PHP 7.4 新機能解説 Standard 編

php_release_standard

2019年11月28日、PHP 7.4.0 がリリースされました! 🎉

https://www.php.net/archive/2019.php#2019-11-28-1

公式ドキュメントで発表された新機能のうち、ここでは Standard 部分の機能について詳しくみていきたいとおもいます✨

PHP コア部分については、こちらの記事をご覧ください。

php74_release PHP 7.4 新機能解説 PHP コア編

※ 各コードは公式ドキュメントから引用の上、一部編集しています。

strip_tags() をタグ名の配列とともに使う

strip_tags() 関数は、第一引数に渡した文字列から HTML タグや PHP タグを取り除くことができる関数です。

https://www.php.net/manual/ja/function.strip-tags.php

また、第二引数に許可したいタグ名を渡すことで、そのタグは取り除かずに残すということもできます。

従来の方法でp, aタグ以外のHTMLおよびPHPタグを除外
$text = '<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>';
echo strip_tags($text, '<p><a>');
出力結果(ソース)
<p>Test paragraph.</p> <a href="#fragment">Other text</a>

今までは、この第二引数には文字列のみが指定できましたが、 PHP 7.4 からは配列でも指定可能となりました。

そのため、 PHP 7.4 以降の環境では上記を以下のようにコーディングすることが可能です。

配列を使ってp, aタグ以外のHTMLおよびPHPタグを除外
$text = '<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>';
echo strip_tags($text, ['a', 'p']);
出力結果(ソース)
<p>Test paragraph.</p> <a href="#fragment">Other text</a>

出力結果は文字列で指定した場合と何ら変わりはありません。

配列で指定すると、より簡単に許可タグを後から追加・削除できそうですね!

proc_open() 関数

proc_open() 関数は、 PHP からシェルコマンドを実行し、入出力用のファイルポインタを開くことができる関数です。popen() 関数よりもさらに細かくプログラムの実行を制御できるという特徴があります。

https://www.php.net/manual/ja/function.proc-open.php

proc_open() 関数の使用例
$descriptorspec = array(
   0 => array("pipe", "r"),
   1 => array("pipe", "w"),
   2 => array("file", "/tmp/error-output.txt", "a"),
);

$cwd = null;
$env = null;

$process = proc_open('php -r \'echo "Hello World\n";\'', $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
        fwrite($pipes[0], '<?php echo "proc_open() is running." ?>');
    fclose($pipes[0]);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    $return_value = proc_close($process);
    
    echo "command returned $return_value\n";
}
出力結果
Hello World
command returned 0

proc_open() 関数自体は PHP 4.3 から存在していましたが、 PHP 7.4 で 2 点変更された内容があります。

まず 1 点目は、第一引数であるコマンドを文字列だけでなく配列も受け入れられるようになりました。

つまり、上記コードの proc_open() 部分をこのように書くことが可能です。

コマンドを配列で渡す
proc_open(['php', '-r', 'echo "Hello World\n";'], $descriptorspec, $pipes, $cwd, $env);

この場合、 PHP コードを囲うシングルクオート(またはダブルクオート)にエスケープは必要ありません。

2 つ目の変更点は、 redirect と null ディスクリプタがサポートされるようになったことです。

redirect の例として、よくある標準エラーの出力先を標準出力の出力先にリダイレクトさせる(シェルなら 2>&1 と書く)操作は proc_open() ではこのように書きます。

proc_open() を使った redirect
$descriptorspec = array(
    0 => array("pipe", "r"),
    1 => array("pipe", "w"),
    2 => array("redirect", 1), // 標準エラーの出力先を標準出力の出力先にリダイレクト
);

$cwd = null;
$env = null;

$process = proc_open(['php', '-r', 'echo "Hello World\n"; error_log("error");'], $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
    fwrite($pipes[0], '<?php echo "proc_open() is running." ?>');
    fclose($pipes[0]);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    $return_value = proc_close($process);
    
    echo "command returned $return_value\n";
}
出力結果(標準出力)
Hello World
error
command returned 0

null の例としては、シェルで 2>/dev/null や 2>null と書いていた出力結果を破棄する処理を次のように書くことで実現できます。

proc_open() を使った null
$descriptorspec = array(
    0 => array("pipe", "r"),    
    1 => array("pipe", "w"),
    2 => array("null"), // 出力結果を破棄
);
$cwd = null;
$env = null;

$process = proc_open(['php', '-r', 'echo "Hello World\n"; error_log("error");'], $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
    fwrite($pipes[0], '<?php echo "proc_open() is running." ?>');
    fclose($pipes[0]);

    echo stream_get_contents($pipes[1]);
    fclose($pipes[1]);

    $return_value = proc_close($process);
    
    echo "command returned $return_value\n";
}
出力結果(標準出力)
Hello World
command returned 0

おかげで PHP でもあまり不自由なくコマンド実行ができるようになってきました🙌

libargon なしでの argon2i(d)

argon2i と argon2id は、 password_hash() 関数で使えるアルゴリズムです。 PHP 7.2.0 以降 PHP コアに含まれるようになりましたが、 PHP のビルド時に libargon がない場合は使用できませんでした。

また、 libargon ベースのハッシュメカニズムはしばらくチューニングされていないという問題点もあり、PHP 7.4 からは拡張機能の libsodium ベースで argon2i 及び argon2id を使えるようになりました。

https://www.php.net/manual/ja/function.password-hash.php