PHPでの画像表示の方法について

採用はこちら

目次

PHPで画像を表示する基本的な考え方

PHPで画像を表示する方法には、主に次の2つがあります。

HTMLのimgタグで画像を表示する方法

通常のWebサイトで最もよく使われるのは、HTMLのimgタグで画像を表示する方法です。

<img src="/images/sample.jpg" alt="サンプル画像">

PHPファイルの中でも、画像を表示する基本はHTMLと同じです。

PHPは画像を直接表示するというより、画像のファイル名やパスを動的に出力するために使われることが多いです。

たとえば、次のようにPHPで画像ファイル名を変数に入れて表示できます。

<?php
$image = 'sample.jpg';
?>

<img src="/images/<?= htmlspecialchars($image, ENT_QUOTES, 'UTF-8') ?>" alt="サンプル画像">

このようにすると、PHP側で表示する画像を切り替えられます。

PHPから画像データを直接出力する方法

もうひとつは、PHPファイルから画像データそのものを出力する方法です。

<?php
$file = __DIR__ . '/images/sample.jpg';

if (!is_file($file)) {
    http_response_code(404);
    exit;
}

header('Content-Type: image/jpeg');
readfile($file);
exit;

HTML側では、次のようにPHPファイルを画像URLとして指定します。

<img src="/image.php" alt="PHPから出力した画像">

この方法は、ログインユーザーだけに画像を見せたい場合や、画像へのアクセス権限を確認したい場合に使われます。

ただし、通常の画像表示ではimgタグを使う方法で十分です。

PHPで画像を直接出力する方法は、特別な制御が必要な場合に使うと考えると分かりやすいです。

通常はimgタグで画像を表示する

固定画像を表示する場合

固定の画像を表示するだけであれば、PHPを使わずにimgタグを書くだけで問題ありません。

<img src="/images/logo.png" alt="ロゴ">

たとえば、以下のような構成だとします。

public/
├─ index.php
└─ images/
   └─ logo.png

この場合、ブラウザから画像にアクセスできるパスが/images/logo.pngであれば、次のように表示できます。

<img src="/images/logo.png" alt="ロゴ">

PHPで画像パスを動的に出力する場合

PHPを使うと、条件によって表示する画像を切り替えられます。

<?php
$is_member = true;

if ($is_member) {
    $image = 'member.jpg';
    $alt = '会員向け画像';
} else {
    $image = 'guest.jpg';
    $alt = 'ゲスト向け画像';
}
?>

<img src="/images/<?= htmlspecialchars($image, ENT_QUOTES, 'UTF-8') ?>"
     alt="<?= htmlspecialchars($alt, ENT_QUOTES, 'UTF-8') ?>">

この例では、会員であればmember.jpg、非会員であればguest.jpgを表示します。

PHPを使うことで、ユーザーの状態、商品情報、記事カテゴリなどに応じて表示画像を変えられます。

画像パスを指定するときの注意点

img srcはブラウザから見たURLとして解釈される

画像表示で特に注意したいのが、imgタグのsrcに指定するパスです。

<img src="images/sample.jpg" alt="サンプル画像">

このimages/sample.jpgは、PHPファイルの場所から見たファイルパスではありません。

ブラウザが現在アクセスしているURLから見た相対URLとして解釈されます。

たとえば、現在のURLが次のような場合、

https://example.com/products/detail/123

images/sample.jpgは、次のようなURLとして解釈される可能性があります。

https://example.com/products/detail/images/sample.jpg

そのため、意図した画像が表示されないことがあります。

サイトルートからの絶対パスを使うと分かりやすい

画像パスの混乱を避けるには、サイトルートからの絶対パスを使う方法が分かりやすいです。

<img src="/images/sample.jpg" alt="サンプル画像">

この場合、どのページから読み込んでも、ブラウザは次のURLを見に行きます。

https://example.com/images/sample.jpg

ページの階層が深くなってもパスがずれにくいため、実務ではこの書き方がよく使われます。

PHPで画像名を出力するときはエスケープする

htmlspecialchars()を使う

PHPで画像ファイル名やalt属性を出力する場合は、htmlspecialchars()を使います。

<?php
$image = 'sample.jpg';
$alt = 'サンプル画像';
?>

<img src="/images/<?= htmlspecialchars($image, ENT_QUOTES, 'UTF-8') ?>"
     alt="<?= htmlspecialchars($alt, ENT_QUOTES, 'UTF-8') ?>">

htmlspecialchars()を使うことで、HTMLとして特別な意味を持つ文字を安全に出力できます。

特に、データベースから取得した値やユーザー入力をHTMLに表示する場合は、エスケープ処理が重要です。

htmlspecialchars()だけではパスの安全性は保証できない

ただし、htmlspecialchars()はHTML出力を安全にするための処理です。

ファイルパスそのものが安全かどうかを保証するものではありません。

たとえば、次のような値が入った場合を考えます。

$image = '../secret.txt';

この値をhtmlspecialchars()しても、パスとして安全になるわけではありません。

そのため、ユーザー入力から画像ファイル名を決める場合は、次のような対策が必要です。

・許可された画像だけを表示する
・画像IDからサーバー側でファイル名を決める
・ファイル名を直接GETパラメータで受け取らない
・拡張子やMIMEタイプを確認する

HTML出力のエスケープと、ファイルパスの安全性チェックは別のものとして考える必要があります。

複数の画像を一覧表示する方法

配列を使って画像を表示する

複数の画像を表示したい場合は、配列とforeachを使います。

<?php
$images = [
    'photo01.jpg',
    'photo02.jpg',
    'photo03.jpg',
];
?>

<?php foreach ($images as $image): ?>
  <img src="/images/<?= htmlspecialchars($image, ENT_QUOTES, 'UTF-8') ?>" alt="画像">
<?php endforeach; ?>

このようにすると、配列に入っている画像を順番に出力できます。

alt属性も画像ごとに設定する

実務では、単にalt="画像"とするよりも、画像の内容に合わせた代替テキストを設定した方がよいです。

<?php
$images = [
    [
        'file' => 'photo01.jpg',
        'alt' => '赤いバッグの商品写真',
    ],
    [
        'file' => 'photo02.jpg',
        'alt' => '青いバッグの商品写真',
    ],
];
?>

<?php foreach ($images as $image): ?>
  <img src="/images/<?= htmlspecialchars($image['file'], ENT_QUOTES, 'UTF-8') ?>"
       alt="<?= htmlspecialchars($image['alt'], ENT_QUOTES, 'UTF-8') ?>">
<?php endforeach; ?>

画像が意味を持つ場合は、内容が分かるaltを設定します。

装飾目的の画像であれば、空のaltを指定することもあります。

<img src="/images/bg.jpg" alt="">

CSSで画像サイズを調整する

縦横比を保ってサイズ調整する

画像の表示サイズは、PHPではなくCSSで調整するのが基本です。

<img src="/images/sample.jpg" alt="サンプル画像" class="photo">
.photo {
  width: 300px;
  height: auto;
}

widthだけを指定し、height: auto;にすることで、画像の縦横比を保ったまま表示できます。

レスポンシブ対応する場合

スマートフォンやタブレットでも見やすくするなら、次のように指定します。

.photo {
  max-width: 100%;
  height: auto;
}

この指定により、画像が親要素の幅を超えてはみ出しにくくなります。

サムネイル表示する場合

画像を同じサイズの枠に収めたい場合は、object-fitを使うことがあります。

.thumbnail {
  width: 300px;
  height: 200px;
  object-fit: cover;
}

object-fit: cover;を指定すると、指定した枠いっぱいに画像を表示できます。

ただし、画像の一部がトリミングされるため、商品画像などでは注意が必要です。

画像が存在するか確認してから表示する

サーバー上のパスとブラウザ用URLを分ける

PHPで画像の存在を確認してから表示したい場合は、サーバー上のファイルパスとブラウザに出力するURLを分けて考える必要があります。

<?php
$image = 'sample.jpg';

$filePath = __DIR__ . '/images/' . $image;
$imageUrl = '/images/' . $image;

if (is_file($filePath)) :
?>
  <img src="<?= htmlspecialchars($imageUrl, ENT_QUOTES, 'UTF-8') ?>" alt="サンプル画像">
<?php else : ?>
  <p>画像が見つかりません。</p>
<?php endif; ?>

ここで重要なのは、次の2つを分けることです。

$filePath = __DIR__ . '/images/' . $image;
$imageUrl = '/images/' . $image;

$filePathは、PHPがサーバー上でファイルの存在を確認するためのパスです。

一方、$imageUrlは、ブラウザが画像を読み込むためのURLです。

file_exists()よりis_file()が分かりやすい

ファイルの存在確認にはfile_exists()も使えます。

file_exists($filePath)

ただし、file_exists()はディレクトリに対してもtrueを返します。

画像ファイルが存在するかを確認したい場合は、is_file()の方が意図が明確です。

is_file($filePath)

画像ファイルとして存在するかを確認したい場合は、is_file()を使うとよいでしょう。

データベースの画像情報を表示する

画像本体ではなくファイル名やURLを保存する

実務では、画像そのものをデータベースに保存するよりも、画像ファイルはサーバーやストレージに保存し、データベースにはファイル名やURLを保存することが多いです。

たとえば、商品情報として次のようなデータを取得したとします。

<?php
$product = [
    'name' => 'サンプル商品',
    'image' => 'product01.jpg',
];
?>

この場合、次のように商品名と画像を表示できます。

<h3><?= htmlspecialchars($product['name'], ENT_QUOTES, 'UTF-8') ?></h3>

<img src="/uploads/products/<?= htmlspecialchars($product['image'], ENT_QUOTES, 'UTF-8') ?>"
     alt="<?= htmlspecialchars($product['name'], ENT_QUOTES, 'UTF-8') ?>">

画像の保存先には複数の選択肢がある

画像ファイルの保存先には、次のような選択肢があります。

・Webサーバー内のuploadsディレクトリ
・別サーバー
・CDN
・Amazon S3などのオブジェクトストレージ
・Google Cloud Storage
・Cloudflare R2

小規模サイトであれば、uploads/ディレクトリに保存する方法でも十分です。

一方、画像数が多いサイトやアクセス数が多いサイトでは、CDNやオブジェクトストレージを使うこともあります。

アップロード画像を表示する場合の注意点

ユーザーがアップロードした画像は慎重に扱う

ユーザーや管理者がアップロードした画像を表示する場合は、セキュリティに注意が必要です。

単純に次のように表示すること自体はできます。

<img src="/uploads/user_photo.jpg" alt="ユーザー画像">

しかし、アップロード機能では、不正なファイルがアップロードされるリスクがあります。

アップロード画像で確認すべきこと

アップロード画像を扱う場合は、少なくとも次のような点を確認します。

・拡張子だけで判断しない
・MIMEタイプを確認する
・画像として読み込めるか確認する
・ファイル名をそのまま使わない
・保存ファイル名はランダムな文字列にする
・ファイルサイズの上限を設ける
・画像のピクセル数にも上限を設ける
・アップロード先でPHPを実行できないようにする
・必要に応じて画像を再エンコードする

特に、アップロードされた元のファイル名をそのまま使うのは避けた方が安全です。

// よくない例
<img src="/uploads/<?= $_GET['image'] ?>" alt="画像">

ユーザー入力をそのまま画像パスに使うと、不正なファイル参照やXSSなどの原因になる可能性があります。

SVGの扱いには注意する

SVGは画像形式のひとつですが、扱いには注意が必要です。

SVGにはスクリプトを含められる場合があるため、JPEG、PNG、WebPなどと同じ感覚で許可すると危険なケースがあります。

初心者向けには、まず次のような画像形式だけを許可するのが分かりやすいです。

・JPEG
・PNG
・WebP
・GIF

SVGを許可する場合は、サニタイズや配信方法を慎重に検討する必要があります。

PHPで画像を直接出力する方法

基本的な画像出力のコード

PHPから画像データを直接返す場合は、Content-Typeを指定してから画像ファイルを出力します。

<?php
$file = __DIR__ . '/images/sample.jpg';

if (!is_file($file)) {
    http_response_code(404);
    exit;
}

header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($file));

readfile($file);
exit;

このPHPファイルをimage.phpとして保存した場合、HTML側では次のように指定します。

<img src="/image.php" alt="PHPから出力した画像">

PHPで画像を返すときの注意点

PHPで画像を直接出力する場合は、以下の点に注意します。

・header()より前に文字や空白を出力しない
・画像形式に合ったContent-Typeを返す
・存在しない画像には404を返す
・余計なHTMLを出力しない
・必要に応じてContent-Lengthを指定する
・必要に応じてX-Content-Type-Options: nosniffを付ける

画像出力専用のPHPでは、最後のPHP終了タグ?>を書かないこともあります。

終了タグの後に不要な空白や改行が入るのを防ぐためです。

ログインユーザーだけに画像を表示する

PHP経由でアクセス制御する

ログインしているユーザーだけに画像を見せたい場合は、画像ファイルへ直接アクセスさせず、PHPを経由して配信します。

<?php
session_start();

if (empty($_SESSION['user_id'])) {
    http_response_code(403);
    exit;
}

$file = __DIR__ . '/../storage/private/sample.jpg';

if (!is_file($file)) {
    http_response_code(404);
    exit;
}

header('Content-Type: image/jpeg');
header('Content-Length: ' . filesize($file));
header('X-Content-Type-Options: nosniff');

readfile($file);
exit;

このようにすると、ログイン確認をした上で画像を返せます。

HTML側では次のように読み込みます。

<img src="/private-image.php" alt="限定画像">

非公開画像は公開ディレクトリ外に置く

アクセス制限が必要な画像は、Web公開ディレクトリの外に置くと安全性が高まります。

たとえば、次のような構成です。

project/
├─ public/
│  ├─ index.php
│  └─ private-image.php
└─ storage/
   └─ private/
      └─ sample.jpg

この構成では、storage/private/sample.jpgへブラウザから直接アクセスしにくくなります。

PHP側でログイン状態や権限を確認した上で、画像を出力できます。

GETパラメータで画像を指定する方法

ファイル名ではなく画像IDを受け取る

画像を動的に切り替えたい場合、GETパラメータで画像IDを指定する方法があります。

HTML側は次のようにします。

<img src="/image.php?id=1" alt="サンプル画像">

PHP側では、受け取ったIDから安全なファイル名に変換します。

<?php
$images = [
    1 => 'sample01.jpg',
    2 => 'sample02.jpg',
    3 => 'sample03.jpg',
];

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

if ($id === false || $id === null || !isset($images[$id])) {
    http_response_code(404);
    exit;
}

$file = __DIR__ . '/images/' . $images[$id];

if (!is_file($file)) {
    http_response_code(404);
    exit;
}

header('Content-Type: image/jpeg');
readfile($file);
exit;

この方法では、ユーザーが直接ファイル名を指定できません。

そのため、想定外のファイルを参照されるリスクを下げられます。

if (!$id)のような判定は避ける

IDを判定するときに、次のような書き方をすることがあります。

if (!$id) {
    // エラー処理
}

しかし、この書き方では0falseとして扱われます。

IDとして0を使う可能性がある場合、不具合の原因になります。

そのため、filter_input()の結果は厳密に比較した方が安全です。

if ($id === false || $id === null) {
    http_response_code(404);
    exit;
}

画像形式に応じてMIMEタイプを変える

finfoでMIMEタイプを判定する

JPEG、PNG、GIF、WebPなど複数の画像形式を扱う場合は、画像ファイルのMIMEタイプを判定して、適切なContent-Typeを返します。

<?php
$file = __DIR__ . '/images/sample.png';

if (!is_file($file)) {
    http_response_code(404);
    exit;
}

$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($file);

$allowedTypes = [
    'image/jpeg',
    'image/png',
    'image/gif',
    'image/webp',
];

if (!in_array($mime, $allowedTypes, true)) {
    http_response_code(400);
    exit;
}

header('Content-Type: ' . $mime);
header('Content-Length: ' . filesize($file));
header('X-Content-Type-Options: nosniff');

readfile($file);
exit;

このようにすると、画像形式に合わせて正しいContent-Typeを返せます。

mime_content_type()も使える

MIMEタイプの判定には、mime_content_type()を使うこともできます。

$mime = mime_content_type($file);

ただし、環境によってはfinfoを使った方が扱いやすい場合があります。

実務ではfinfoによる判定もよく使われます。

Base64で画像を表示する方法

Data URIとして画像を埋め込む

画像をBase64に変換して、HTML内に直接埋め込むこともできます。

<?php
$file = __DIR__ . '/images/sample.jpg';

$finfo = new finfo(FILEINFO_MIME_TYPE);
$type = $finfo->file($file);

$data = base64_encode(file_get_contents($file));
?>

<img src="data:<?= htmlspecialchars($type, ENT_QUOTES, 'UTF-8') ?>;base64,<?= $data ?>" alt="Base64画像">

この方法では、画像ファイルへのリクエストを別途行わず、HTML内に画像データを埋め込めます。

Base64画像は通常のWebページでは多用しない

Base64画像は便利な場面もありますが、通常のWebページでは多用しない方がよいです。

理由は、HTMLのサイズが大きくなりやすく、画像単体のブラウザキャッシュも効きにくくなるためです。

Base64画像が向いているのは、次のようなケースです。

・小さなアイコンを埋め込みたい場合
・単一ファイルで完結させたい場合
・外部ファイルを読み込めない特殊な環境

メールHTMLでも使われることがありますが、メールクライアントによって対応に差があります。

そのため、Base64画像は万能ではありません。

GDライブラリで画像を生成して表示する

PHPで動的に画像を作る

PHPでは、GDライブラリを使って画像を生成できます。

<?php
header('Content-Type: image/png');

$image = imagecreatetruecolor(400, 200);

$background = imagecolorallocate($image, 255, 255, 255);
$textColor = imagecolorallocate($image, 0, 0, 0);

imagefilledrectangle($image, 0, 0, 400, 200, $background);
imagestring($image, 5, 120, 90, 'Hello PHP', $textColor);

imagepng($image);
imagedestroy($image);
exit;

HTML側では、次のように呼び出します。

<img src="/generate.php" alt="PHPで生成した画像">

この方法を使うと、PHPで動的に画像を作成して表示できます。

GDライブラリを使う場面

GDライブラリは、次のような用途で使われます。

・簡単な画像生成
・サムネイル作成
・画像への文字入れ
・簡易的なグラフ画像の生成
・認証画像の作成

ただし、GD拡張がサーバーで有効になっていないと使えません。

また、日本語テキストを画像に入れたい場合、imagestring()では不向きです。

日本語を描画する場合は、TrueTypeフォントを使えるimagettftext()などを使う必要があります。

本格的な画像加工を行う場合は、Imagickなどのライブラリを使うこともあります。

画像が表示されないときのよくある原因

画像パスが間違っている

画像が表示されない原因として最も多いのは、画像パスの間違いです。

<img src="images/sample.jpg" alt="サンプル画像">

この相対パスは、現在のURLを基準に解釈されます。

ページのURL構造によっては、意図しない場所を参照してしまいます。

確実に指定したい場合は、サイトルートからのパスを使います。

<img src="/images/sample.jpg" alt="サンプル画像">

ファイルは存在するが、ブラウザからアクセスできない

サーバー上に画像ファイルが存在していても、ブラウザからアクセスできる場所にあるとは限りません。

たとえば、PHPから見て次のファイルが存在していても、

__DIR__ . '/../storage/private/sample.jpg'

ブラウザから次のように直接アクセスできるとは限りません。

<img src="/storage/private/sample.jpg" alt="画像">

サーバー上のファイルパスと、ブラウザから見えるURLは別物です。

header()より前に出力している

PHPで画像を直接出力する場合、header()より前に文字や空白が出力されていると、画像が壊れたり、headers already sentのエラーが出たりします。

よくない例です。

echo 'test';

header('Content-Type: image/jpeg');
readfile(__DIR__ . '/images/sample.jpg');

画像出力用のPHPでは、余計なHTML、文字、空白を出力しないようにします。

実務でおすすめのディレクトリ構成

公開画像を扱う場合

ロゴや商品画像など、誰でも見られる画像は、公開ディレクトリ内に置くことが多いです。

public/
├─ index.php
├─ assets/
│  └─ images/
│     └─ logo.png
└─ uploads/
   └─ products/
      └─ product01.jpg

この場合、HTMLでは次のように表示できます。

<img src="/assets/images/logo.png" alt="ロゴ">
<img src="/uploads/products/product01.jpg" alt="商品画像">

非公開画像を扱う場合

ログインユーザーだけに表示したい画像や、権限チェックが必要な画像は、公開ディレクトリの外に置くと安全です。

project/
├─ public/
│  ├─ index.php
│  └─ private-image.php
└─ storage/
   └─ private/
      └─ sample.jpg

この場合、ブラウザから画像ファイルへ直接アクセスさせず、private-image.phpを通して画像を返します。

目的別のおすすめ方法

固定画像を表示したい場合

固定画像を表示するだけなら、imgタグで十分です。

<img src="/images/sample.jpg" alt="サンプル画像">

PHPで特別な処理をする必要はありません。

商品画像や記事画像を表示したい場合

データベースに保存された画像ファイル名を使って表示します。

<img src="/uploads/products/<?= htmlspecialchars($product['image'], ENT_QUOTES, 'UTF-8') ?>"
     alt="<?= htmlspecialchars($product['name'], ENT_QUOTES, 'UTF-8') ?>">

この場合、画像本体はサーバーやストレージに置き、データベースにはファイル名やURLを保存するのが一般的です。

ログインユーザーだけに画像を見せたい場合

PHP経由で画像を返します。

<img src="/private-image.php?id=123" alt="限定画像">

private-image.php側でログイン状態や権限を確認してから、画像データを出力します。

画像を動的に生成したい場合

GDやImagickなどを使って、PHPで画像を生成します。

<img src="/generate.php" alt="生成画像">

グラフ、サムネイル、文字入り画像などを動的に作りたい場合に使えます。

PHPで画像表示するときのまとめ

PHPで画像を表示する基本は、imgタグを使うことです。

<img src="/images/sample.jpg" alt="サンプル画像">

PHPは、画像そのものを表示するというより、画像のファイル名やURLを動的に決める役割で使われます。

実務では、次のように考えると分かりやすいです。

・通常の画像表示はimgタグを使う
・画像パスはブラウザから見たURLとして考える
・PHPで出力する値はhtmlspecialchars()でエスケープする
・画像の存在確認ではサーバー上のパスとURLを分ける
・アクセス制限が必要な画像はPHP経由で返す
・アップロード画像はMIMEタイプや保存方法に注意する

通常の画像であれば、以下の形が基本です。

<?php
$image = 'sample.jpg';
$imageUrl = '/images/' . $image;
?>

<img src="<?= htmlspecialchars($imageUrl, ENT_QUOTES, 'UTF-8') ?>" alt="サンプル画像">

画像の存在確認まで行うなら、次のようにします。

<?php
$image = 'sample.jpg';

$filePath = __DIR__ . '/images/' . $image;
$imageUrl = '/images/' . $image;
?>

<?php if (is_file($filePath)) : ?>
  <img src="<?= htmlspecialchars($imageUrl, ENT_QUOTES, 'UTF-8') ?>" alt="サンプル画像">
<?php else : ?>
  <p>画像が見つかりません。</p>
<?php endif; ?>

アクセス制限やログ記録が不要な画像は、imgタグで表示するのが基本です。

一方、ログインユーザーだけに見せたい画像や、権限チェックが必要な画像は、PHPで画像データを直接返す方法を使います。

以上、PHPでの画像表示の方法についてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次