PHP 5.4.16からPHP 8.1.7にバージョンアップをしようとしたときのこと。
<input type="file" name="file" ~
に値が指定されていないときに
fopen($_FILES['file']['tmp_name'], 'r');
したとき、例外が発生するようになってしまったので調査。同じPHP 5.x系ということで、php56を使い、php56とphp81での比較とする。
そもそものコードは以下のような感じ。
Main1.php
<?php $filename = $argv[1]; $fp = fopen($filename, "r"); if (!$fp) { print "{$filename}: Cannot open file.\n"; exit(1); } print "{$filename}: OK\n"; // ・・・ fclose($fp);
php56での実行結果。
$ php56 Main1.php Main1.php Main1.php: OK $ php56 Main1.php a.txt PHP Warning: fopen(a.txt): failed to open stream: No such file or directory in /home/hhelibex/blog/2022-0705-01/Main1.php on line 5 a.txt: Cannot open file. $ php56 Main1.php "" PHP Warning: fopen(): Filename cannot be empty in /home/hhelibex/blog/2022-0705-01/Main1.php on line 5 : Cannot open file. $
php81での実行結果。
$ php81 Main1.php Main1.php Main1.php: OK $ php81 Main1.php a.txt PHP Warning: fopen(a.txt): Failed to open stream: No such file or directory in /home/hhelibex/blog/2022-0705-01/Main1.php on line 5 a.txt: Cannot open file. $ php81 Main1.php "" PHP Fatal error: Uncaught ValueError: Path cannot be empty in /home/hhelibex/blog/2022-0705-01/Main1.php:5 Stack trace: #0 /home/hhelibex/blog/2022-0705-01/Main1.php(5): fopen() #1 {main} thrown in /home/hhelibex/blog/2022-0705-01/Main1.php on line 5 $
ファイル名が空でなく存在しないファイルの場合の挙動はWarningのまま変わらないが、ファイル名が空文字列の場合に、PHP 8.1ではValueErrorが発生するようになってしまった。
対症療法をするなら、以下のような感じだろうか。
Main2.php
<?php $filename = $argv[1]; if (empty($filename)) { print "Filename cannot be empty.\n"; exit(1); } $fp = fopen($filename, "r"); if (!$fp) { print "{$filename}: Cannot open file.\n"; exit(1); } print "{$filename}: OK\n"; // ・・・ fclose($fp);
しかし、ファイルが存在しない場合のWarningが気持ち悪い。
これは、C言語でプログラムを書いていた頃の癖でfopen()の実行結果しかチェックしないのが問題なのだろう。
ということで、PHPでの最適解は以下になるのではないか。
Main3.php
<?php $filename = $argv[1]; if (!file_exists($filename) || !($fp = fopen($filename, "r"))) { print "{$filename}: Cannot open file.\n"; exit(1); } print "{$filename}: OK\n"; // ・・・ fclose($fp);
php81での実行結果。
$ php81 Main3.php Main3.php Main3.php: OK $ php81 Main3.php a.txt a.txt: Cannot open file. $ php81 Main3.php "" : Cannot open file. $
厳密には、file_exists()とfopen()の間にファイルが存在しなくなった場合のエラーを考えなければならないが、それはイレギュラーケースとしてログに記録されてもいいのではないだろうか。