php

動いた!……でも、そのまま表示して大丈夫? htmlspecialchars()って何?

前回は、

Warning: Undefined array key "name"

という警告について調べました。

そして、

$name = $_POST['name'] ?? '';

とすることで、

「nameが送られていなければ、空の文字を使う」

という処理ができることを知りました。

では、フォームを完成させてみましょう。

<form method="post">
    <input type="text" name="name">
    <button type="submit">送信</button>
</form>

PHP側はこうします。

<?php

$name = $_POST['name'] ?? '';

if ($name !== '') {
    echo 'こんにちは、' . $name . 'さん';
}

名前に、

みのり

と入力して送信すると、

こんにちは、みのりさん

と表示されます。

よし。

今度こそ完成!

……でしょうか?


名前じゃないものを入力してみる

せっかくなので、少し変な文字を入力してみましょう。

名前の代わりに、

<b>みのり</b>

と入力して送信してみます。

普通に考えれば、

こんにちは、<b>みのり</b>さん

と表示されてほしいところです。

ところがブラウザでは、

こんにちは、みのりさん

と、「みのり」の部分が太字になって表示されることがあります。

なぜでしょう?


ブラウザがHTMLとして読んでしまった

今回入力した、

<b>みのり</b>

には、

<b>

と、

</b>

があります。

これはHTMLで、

この間の文字を太字として扱う

という意味を持つタグです。

つまり現在のPHPは、

入力された文字をそのままHTMLの中へ出力している

ため、ブラウザが入力内容までHTMLとして解釈してしまったわけです。


「太字になるだけなら別にいいのでは?」

今回の例だけを見ると、

文字が太字になっただけじゃん。

と思うかもしれません。

でも、ここで少し考えてみましょう。

ユーザーが入力できる文字を、そのままWebページへ出力できる。

ということは、

こちらが想定していないHTMLまで入力される可能性がある

ということです。

そして、Webページで扱われるのはHTMLだけではありません。

JavaScriptもあります。

入力された内容を無条件にHTMLとして扱わせる設計は、場合によっては**クロスサイトスクリプティング(XSS)**と呼ばれる脆弱性につながります。

ここでは、攻撃方法を覚える必要はありません。

今日覚えておきたいのは、

外から入力された文字を、そのままHTMLとして表示するのは危険な場合がある。

これだけです。


今日の合格ライン

今回はここが分かれば合格です。

フォームに入力された文字を、そのままHTMLへ出力しない。

PHPでフォームを作っていると、

echo $name;

のようなコードはよく登場します。

でも、

その $name はどこから来たデータ?

と、一度考える癖をつけましょう。

自分でプログラム内に設定した文字なのか。

ユーザーがフォームに入力した文字なのか。

外部から取得したデータなのか。

データがどこから来たのかを見る。

これは、AIが書いたコードを確認するときにも重要です。


AIに聞いてみよう

今回も、分からなければAIに相談してみます。

たとえば、

PHPでフォームに入力された名前をechoで表示しています。
HTMLタグのような文字を入力すると、ブラウザがHTMLとして解釈してしまいます。
ユーザーが入力した文字を安全に表示する基本的な方法を、初心者向けに教えてください。

すると、おそらくこんな関数が出てきます。

htmlspecialchars()

……長い。

でも大丈夫です。

暗記しなくてOKです。

何をしているのかだけ見てみましょう。


htmlspecialchars() を使ってみる

先ほどのコードを少し変更します。

<?php

$name = $_POST['name'] ?? '';

if ($name !== '') {
    echo 'こんにちは、'
        . htmlspecialchars($name, ENT_QUOTES, 'UTF-8')
        . 'さん';
}

急に難しそうになりました。

今回見るのは、ここだけです。

htmlspecialchars($name, ENT_QUOTES, 'UTF-8')

ものすごく簡単に言えば、

HTMLとして特別な意味を持つ文字を、そのまま文字として表示できる形に変換する

ための処理です。


もう一度 <b>みのり</b> を入力する

先ほどと同じ、

<b>みのり</b>

を送信してみます。

今度はブラウザに、

こんにちは、<b>みのり</b>さん

と表示されます。

太字にはなりません。

<b> という文字そのものが表示されています。

つまりブラウザに、

「これはHTMLタグじゃないよ。普通の文字として表示してね」

と伝えられたわけです。


中では何が起きている?

HTMLには、特別な意味を持つ文字があります。

たとえば、

<
>
&
"
'

などです。

htmlspecialchars() は、こうした文字をHTMLで安全に文字として扱える表現へ変換してくれます。

たとえば、

<

なら、HTML上では、

&lt;

のような形になります。

ブラウザはこれを画面上では、

<

として表示します。

つまり、

見た目は < だけど、HTMLタグを開始する < としては扱われない

というわけです。


ENT_QUOTES と UTF-8 は何?

AIにコードを書いてもらうと、

htmlspecialchars($name, ENT_QUOTES, 'UTF-8')

のように、さらに知らないものが付いてくることがあります。

ここも今はざっくりでOKです。

ENT_QUOTES は、

シングルクォートやダブルクォートも変換対象にする

ための指定。

UTF-8 は、

この文字列をUTF-8として扱う

という指定です。

日本語のWebサイトではUTF-8が広く使われています。

今の段階では、

htmlspecialchars($name, ENT_QUOTES, 'UTF-8')

を見て、

「あ、画面に安全に文字を出すための処理かな」

と気付ければ十分です。


「入力するとき」に変換するの?

ここは少し重要です。

たとえば名前を受け取った直後に、

$name = htmlspecialchars($_POST['name'] ?? '', ENT_QUOTES, 'UTF-8');

としてしまうコードを見かけることもあります。

小さなサンプルでは動きます。

ただ、

「受け取った瞬間に何でもHTML用に変換すればいい」

と覚えるのはおすすめしません。

htmlspecialchars() は基本的に、

HTMLへ出力するとき

に必要になる処理だからです。

同じデータをメールに使うかもしれない。

データベースへ保存するかもしれない。

CSVへ出力するかもしれない。

使う場所によって、必要な安全対策は変わります。

なので今は、

HTMLへ表示するときは、HTMLへ表示するための安全対策をする。

と覚えておきましょう。


AIが書いたコードでも、安全とは限らない

ここが今回、一番大切なところかもしれません。

AIに、

「PHPで名前を入力して表示するフォームを作って」

とお願いすれば、数秒でコードを書いてくれます。

しかも、ちゃんと動くことも多いです。

でも、

動くコード=安全なコード

とは限りません。

だからAIが出したコードを見るとき、

この入力値はどこから来ている?

そのまま画面に出していない?

ユーザーが変な文字を入力したらどうなる?

と考えられるだけでも、大きな違いがあります。

コードを全部自分で書けなくても構いません。

「ここ、大丈夫?」とAIに質問できること。

それも立派なWeb制作の力です。


AIへの質問を一段階進めてみる

最初なら、

このPHPフォームを作って。

だけでもOKです。

でも今回のことを知ったなら、次はこう聞けます。

PHPで名前を入力して表示するフォームを作ってください。
ユーザーからの入力値をHTMLへ表示するときの安全対策も入れてください。
また、なぜその処理が必要なのか初心者向けに説明してください。

さらに、すでにAIがコードを書いてくれたなら、

このコードで、ユーザーから受け取った値をそのままHTMLへ出力している箇所はありますか?
XSSなどの問題につながる可能性がないか確認してください。

と聞くこともできます。

知識が一つ増えると、AIへの質問も一つ良くなる。

これを積み重ねていけばOKです。


ワンポイント:htmlspecialchars() を使えば全部安全?

ここも大切です。

いいえ。

htmlspecialchars() はとても重要ですが、

これを付ければ、あらゆるセキュリティ問題が解決する魔法の関数

ではありません。

HTMLのどこへ値を出すのか。

JavaScriptで使うのか。

URLとして使うのか。

データベースへ保存するのか。

用途によって対策は変わります。

今回はあくまで、

ユーザーから受け取った文字列をHTML本文へ文字として表示する

という場面を扱っています。

セキュリティは一気に全部覚えなくて大丈夫です。

必要になった場面で、一つずつ覚えていきましょう。


3話で、ここまで読めるようになった

最初に見たコードを、もう一度見てみます。

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = $_POST['name'] ?? '';

    if ($name !== '') {
        echo 'こんにちは、'
            . htmlspecialchars($name, ENT_QUOTES, 'UTF-8')
            . 'さん';
    }
}

第1話の時点では、

「何これ?」

だったかもしれません。

でも、今ならどうでしょう。

if ($_SERVER['REQUEST_METHOD'] === 'POST') {

POSTされたときだけ動かしている。

$name = $_POST['name'] ?? '';

送られてきた name を受け取って、なければ空にする。

if ($name !== '') {

名前が空じゃなければ、

htmlspecialchars($name, ENT_QUOTES, 'UTF-8')

HTMLへ安全に文字として表示できるようにして、

echo

画面へ表示する。

なんとなく読める。

それで十分です。

最初から全部書けなくてもいい。

AIに書かせてもいい。

検索してもいい。

コピペしてもいい。

でも、

「このコード、だいたい何をやっているんだろう?」

が少しずつ分かるようになっていく。

それが今回の合格です。


次は「送信したらページが真っ白」?

フォームについて少し分かってきました。

では次は、WordPressでもPHPでもかなり遭遇する、

「変更したら画面が真っ白になった」

を扱ってみましょう。

500エラーとは何が違うのか。

なぜ何も表示されないのか。

そして、何も表示されていない状態から、どうやって原因を探すのか。

次回は、

何も表示されない!PHPの「真っ白な画面」はどう調べる?

です。

☆ この授業をあとで見返す

学生登録(無料)すると、お気に入りに保存できます。授業は登録しなくても読めます。

☆ この授業をあとで見返す

学生登録(無料)すると、お気に入りに保存できます。授業は登録しなくても読めます。