2.

PHP を HTML に埋め込む方法|短縮タグ・代替構文・エスケープの基本

編集
この記事の要点
  • PHP は <?php ... ?> の外側をそのまま HTML として出力する
  • 値を書き出すだけなら <?= $name ?>(short echo tag。常に使える)
  • PHP だけのファイルには終了タグ ?> を書かない。後ろの改行が出力されて事故になる
  • HTML の中では if: / endif;代替構文のほうが対応関係を追いやすい
  • 変数を出すときは必ず htmlspecialchars() を通す。素で出すと XSS になる

基本の書き方

<!DOCTYPE html>
<html lang="ja">
<body>
  <h1><?php echo "こんにちは"; ?></h1>

  <?php $name = "田中"; ?>
  <p><?= $name ?> さん</p>
</body>
</html>

PHP タグの外側は解釈されずにそのまま出力されます。つまり PHP ファイルは「HTML の中に、必要なところだけ PHP を差し込む」形で書けます。

タグの種類

書き方意味使ってよいか
<?php ... ?>標準これを使う
<?= $x ?><?php echo $x; ?> の短縮使える(PHP 5.4 以降つねに有効)
<? ... ?>短縮開始タグ使わない(short_open_tag 依存・XML と衝突)
<% ... %>ASP 風タグPHP 7 で廃止済み

終了タグを書かない

<?php
// functions.php — PHP コードだけのファイル

function greet(string $name): string
{
    return "こんにちは {$name} さん";
}

// ここに ?> を書かない

終了タグの後ろにある改行や空白まで出力されます。それが原因で次のエラーが出ます。

Warning: Cannot modify header information - headers already sent by
(output started at /path/functions.php:12) in /path/index.php on line 3

header()setcookie()、セッション開始は出力が 1 バイトでも始まる前に呼ぶ必要があります。詳細は Warning: Cannot modify header information を参照してください。

HTML の中で分岐・繰り返しをする

<?php $tasks = ['買い物', '掃除']; ?>

<?php if ($tasks): ?>
  <ul>
    <?php foreach ($tasks as $i => $task): ?>
      <li><?= $i + 1 ?>. <?= htmlspecialchars($task, ENT_QUOTES, 'UTF-8') ?></li>
    <?php endforeach; ?>
  </ul>
<?php else: ?>
  <p>タスクはありません</p>
<?php endif; ?>

この :endif; の書き方を代替構文といいます。波かっこだと HTML の中で } が散らばり、どのブロックの終わりか分からなくなるため、テンプレートでは代替構文を使うのが定石です。

通常の構文代替構文
if (...) { }if (...): ... endif;
foreach (...) { }foreach (...): ... endforeach;
for (...) { }for (...): ... endfor;
while (...) { }while (...): ... endwhile;
switch (...) { }switch (...): ... endswitch;

出力するときは必ずエスケープする

<?php
$comment = '<script>alert(1)</script>';   // 利用者が入力した値
?>

<!-- 危険: スクリプトがそのまま動く -->
<p><?= $comment ?></p>

<!-- 安全: 文字として表示される -->
<p><?= htmlspecialchars($comment, ENT_QUOTES, 'UTF-8') ?></p>

短く書くためにヘルパー関数を用意しておくと、書き忘れが減ります。

function e(?string $s): string
{
    return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}

// テンプレート側
<p><?= e($comment) ?></p>
出力先使うもの
HTML の本文・属性値htmlspecialchars($s, ENT_QUOTES, 'UTF-8')
URL のパラメータurlencode() / http_build_query()
JavaScript に渡す値json_encode($v, JSON_HEX_TAG | JSON_HEX_AMP)
SQLプレースホルダ(PDO)。文字列連結しない

ロジックと表示を分ける

<?php
// index.php — ここで必要なデータを揃える
require __DIR__ . '/lib/db.php';

$tasks = fetchTasks($pdo);      // DB アクセスや計算はここまで

require __DIR__ . '/views/tasks.php';   // 表示は別ファイルへ
<!-- views/tasks.php — ここでは表示だけ -->
<ul>
  <?php foreach ($tasks as $task): ?>
    <li><?= e($task['title']) ?></li>
  <?php endforeach; ?>
</ul>

表示用のファイルには echo と分岐・繰り返しだけを置きます。DB アクセスや条件計算がテンプレートに混ざると、画面を直すたびにロジックを壊す危険が出ます。フレームワークを使う場合は Bladeテンプレート のような専用の仕組みがこれを担当します。

共通部分をまとめる

<!-- views/layout/header.php -->
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title><?= e($title ?? 'サイト名') ?></title>
</head>
<body>
<?php
$title = 'タスク一覧';
require __DIR__ . '/views/layout/header.php';
?>

<h1><?= e($title) ?></h1>

<?php require __DIR__ . '/views/layout/footer.php'; ?>

読み込んだファイルからは読み込み元の変数がそのまま見えます$title のように渡したい値を、読み込む直前で用意しておくのが素朴なやり方です。

出力バッファリング

function render(string $file, array $data = []): string
{
    extract($data, EXTR_SKIP);
    ob_start();                    // ここから先の出力をためる
    require $file;
    return ob_get_clean();         // ためた内容を文字列で受け取る
}

$html = render(__DIR__ . '/views/tasks.php', ['tasks' => $tasks]);
echo $html;                        // 加工してから出力できる

テンプレートの結果を文字列として受け取れるので、メール本文を組み立てたり、キャッシュに保存したりできます。ob_start()ob_get_clean() は必ず対にしてください。

フォームの値を表示する

<form method="post" action="">
  <input type="text" name="title"
         value="<?= e($_POST['title'] ?? '') ?>">

  <select name="status">
    <?php foreach (['open' => '未着手', 'done' => '完了'] as $v => $label): ?>
      <option value="<?= e($v) ?>"
        <?= (($_POST['status'] ?? '') === $v) ? 'selected' : '' ?>>
        <?= e($label) ?>
      </option>
    <?php endforeach; ?>
  </select>
</form>

入力エラーで戻したときに値を保つには、value$_POST の値を入れ直します。属性値の中でも必ずエスケープしてください。" がエスケープされないと、属性を抜け出して任意の属性を差し込まれます。

よくあるつまずき

症状原因
PHP のコードがそのまま画面に出る拡張子が .html/Web サーバー経由でなくファイルを直接開いている
headers already sent終了タグの後ろの改行、または BOM 付きで保存している
画面が真っ白致命的エラー。display_errors ではなくエラーログを見る
文字化けするファイルを UTF-8(BOM なし)で保存し、<meta charset="utf-8"> を出す
変数が出ないスコープ違い。関数の中から外の変数は見えない(スコープ

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本事項
  2. HTMLへの埋め込み
  3. 変数
  4. 可変変数
  5. 定数
  6. データ型
  7. キャスト
  8. エスケープ文字
  9. 配列
  10. 演算子
  11. 代入の際の注意点
  12. 条件分岐
  13. 繰り返し処理
  14. クラスとインスタンス
  15. コンストラクタ
  16. 関数
  17. スーパーグローバル変数
  18. スコープ
  19. staticについて
  20. yieldについて
  21. ファイルのアップロード方法
  22. DB接続方法
  23. SQL実行方法
  24. カプセル化の具体例
  25. 継承の構文
  26. オーバーライド
  27. ポリモーフィズム(多様性)の具体例
  28. 抽象クラス・メソッドの構文と具体例
  29. GET通信
  30. try catchで全てのエラーを拾う方法

最近更新/作成されたページ