literal-string型
"hello " . "world"
"hello " . Person::DEFAULT_NAME
implode(', ', ["one", "two"])
implode(', ', [1, 2, 3])
"hello " . <another literal-string>
基本的にはXSSやSQLインジェクションのようなインジェクション系の脆弱性を回避するために用いる
静的解析でも検査は可能だが実行時検査できた方が安全だとRFCは主張する
RFCにはPsalmの検出を迂回するための例が掲載されている
Rubyはこれに似たtaintという概念がかつて存在した(過去形)
プログラミング言語が提供するセキュリティ機構としては難しい面がある
セキュアなプログラムを構築するための確実な基盤とはならない
一方で、確実ではなくとも静的な型として表明できると嬉しい場面はある
使いかた
以下のような関数を考えてみる
code:php
/**
* @param literal-string $format
*/
function html_printf(string $format, mixed ...$args): void
{
vprintf($format, array_map(fn(string $s) => htmlspecialchars($s, ENT_QUOTES), $args));
}
呼び出しコード
code:php
<?php declare(strict_types = 1);
// 安全
html_printf('<title>%s</title>', 'test');
// 安全
html_printf('<title>%s</title>', $_GET'name'); // 外部から入力する文字列は % の数が不定で実行時エラーを起こす可能性があるので安全ではない
html_printf((string)$_GET'format', 'test'); この例においてはHTML組み立てに外部入力を用いることだけが危険なのではなく、フォーマット文字列に外部入力を用いると実行時エラーを起こせて危険だということには注意されたい。
外部入力値に関してはhtmlspecialchars()でエスケープされている
同様に、普通のprintf()やpreg_match()に対して外部入力文字列を渡すのも危険