PHP Tips | 文字列処理:ログ・表示向け - 表示安全文字列生成

PHP PHP
スポンサーリンク

「表示安全文字列生成」とは何をするものか

ここで言う「表示安全文字列」は、ざっくり言うとこういう文字列です。

画面に出してもレイアウトが壊れない。
ログに出してもビューアが変にならない。
HTML やターミナルで「意図しない意味」を持たない。

つまり、「人間が読むために安全で、扱いやすい形に整えた文字列」です。
元の文字列をそのまま出すのではなく、ログ・画面向けに「前処理」をまとめてやるユーティリティがあると、実務ではかなり便利です。


どんな問題から守りたいのか

HTML 表示での問題

ブラウザにそのまま文字列を出すと、<> をタグとして解釈されてしまいます。

<script>alert(1)</script>

これをそのまま出すと、XSS(スクリプト実行)の原因になります。
なので、画面表示用には必ず htmlspecialchars でエスケープする必要があります。

ログ表示での問題

ログに「制御文字」や「極端に長い文字列」が混ざると、こうなります。

ログビューアが崩れる。
grep しづらい。
1 行が長すぎて、他の情報が見えなくなる。

なので、ログ用には「制御文字を落とす」「長さを制限する」といった前処理が欲しくなります。


コアとなる「表示安全文字列」ユーティリティの設計

やりたいことを分解する

表示安全文字列を作るとき、よくやる処理はだいたい次のようなものです。

前後の余計な空白を削る(trim)。
制御文字を除去する。
必要なら改行を残すか、スペースに変える。
長すぎる場合は、一定の長さで切って「…」を付ける。
HTML に出すなら htmlspecialchars でエスケープする。

これを毎回バラバラに書くのではなく、「1 本の関数にまとめる」のがユーティリティの発想です。


実装例① ログ向けの表示安全文字列

改行は残さず、1 行に収めたい場合

ログの 1 行メッセージとして使うことを想定して、
「改行も含めて制御文字を全部落とし、長さを制限する」関数を作ります。

/**
 * ログ向けの表示安全文字列を生成する
 *
 * - 前後の空白をトリム
 * - 制御文字(改行含む)を削除
 * - 長すぎる場合は末尾を「...」で省略
 */
function to_safe_log_string(string $value, int $maxLength = 200): string
{
    // 前後の空白を削る
    $value = trim($value);

    // 制御文字(0x00-0x1F, 0x7F)をすべて削除
    $value = preg_replace('/[\x00-\x1F\x7F]/', '', $value) ?? '';

    // 長さ制限(マルチバイト対応)
    if (mb_strlen($value, 'UTF-8') > $maxLength) {
        $value = mb_substr($value, 0, $maxLength, 'UTF-8') . '...';
    }

    return $value;
}
PHP

使い方の例です。

$raw = $_POST['comment'] ?? '';

$logMessage = to_safe_log_string($raw);

error_log('comment=' . $logMessage);
PHP

ここでの重要ポイントは、「ログに出す前に必ずこの関数を通す」と決めてしまうことです。
そうすると、「変な制御文字」「異常に長い文字列」がログを壊すリスクをかなり減らせます。


実装例② 画面表示向けの表示安全文字列

改行は残して、HTML として安全に出したい場合

画面に出すときは、「改行は残したい」「HTML として安全にしたい」というニーズが多いです。
その場合は、こういう関数にします。

/**
 * 画面表示向けの表示安全文字列を生成する
 *
 * - 前後の空白をトリム
 * - 改行以外の制御文字を削除
 * - 長すぎる場合は末尾を「...」で省略
 * - HTML エスケープした上で、改行を <br> に変換
 */
function to_safe_html_string(string $value, int $maxLength = 200): string
{
    $value = trim($value);

    // 改行(LF, CR)は残し、それ以外の制御文字を削除
    $value = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $value) ?? '';

    // 長さ制限
    if (mb_strlen($value, 'UTF-8') > $maxLength) {
        $value = mb_substr($value, 0, $maxLength, 'UTF-8') . '...';
    }

    // HTML エスケープ
    $escaped = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');

    // 改行を <br> に
    return nl2br($escaped);
}
PHP

使い方の例です。

$raw = $_POST['comment'] ?? '';

echo to_safe_html_string($raw, 500);
PHP

ここでの重要ポイントは、「エスケープと整形の順番」です。

テキスト整形(制御文字除去・長さ制限)
→ HTML エスケープ(htmlspecialchars
→ 改行を <br> に変換(nl2br

この順番を守ることで、「XSS を防ぎつつ、見た目も整った表示」ができます。


どこに組み込むかで安全性が変わる

「呼び出し側で毎回やる」は危険

毎回 trim して、preg_replace して、htmlspecialchars して…と書いていると、
どこかで「やり忘れ」が必ず出ます。

ログ出力の一部だけ生文字列。
画面の一部だけエスケープ漏れ。

こういう「穴」を防ぐために、「表示用に文字列を出すときは必ずこの関数を通す」と決めてしまうのが大事です。

例えば、ビュー層で共通のヘルパーとして使う、
ロガーのラッパーの中で必ず to_safe_log_string を通す、などです。


まとめ:今日からの「表示安全文字列生成」ユーティリティ

表示安全文字列生成の本質は、「人間が読む場所に出す前に、文字列を“安全で扱いやすい形”に整える」ことです。

ログ向けには、制御文字除去+長さ制限。
画面向けには、制御文字除去+長さ制限+HTML エスケープ+改行処理。

これらをユーティリティ関数にまとめておけば、「毎回バラバラに気をつける」必要がなくなります。

最後に、ログ用と画面用の 2 本をもう一度並べておきます。

function to_safe_log_string(string $value, int $maxLength = 200): string
{
    $value = trim($value);
    $value = preg_replace('/[\x00-\x1F\x7F]/', '', $value) ?? '';

    if (mb_strlen($value, 'UTF-8') > $maxLength) {
        $value = mb_substr($value, 0, $maxLength, 'UTF-8') . '...';
    }

    return $value;
}

function to_safe_html_string(string $value, int $maxLength = 200): string
{
    $value = trim($value);
    $value = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $value) ?? '';

    if (mb_strlen($value, 'UTF-8') > $maxLength) {
        $value = mb_substr($value, 0, $maxLength, 'UTF-8') . '...';
    }

    $escaped = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');

    return nl2br($escaped);
}
PHP

もし、あなたのプロジェクトで「ログにそのまま生文字列を突っ込んでいる」「ビューで直接 $_POST を echo している」ような箇所があれば、そこがこのユーティリティを差し込むベストポイントです。
その 1 ステップを挟むだけで、「表示まわりの事故」はかなり減らせます。

タイトルとURLをコピーしました