PHP の renameは、mv(move)コマンドの代用ではない件
phpには、rename という関数があります。
Linuxおよび UNIXライクな環境をご存じの方であれば、renameコマンドの php版 かなぁと思われることでしょう。
あるいは、ウェブには、mv コマンドの php版 みたいな記述もあります。
しかし、その実は、まったく別物で、php独自の処理を行っています。
32bit OS では、旧ファイル名、新ファイル名が、それぞれ異なるパーティション間で renameを実行すると
4GiBまでしかファイルを転送できない・・・という変な問題が存在します。
今回は、その問題について簡単に解説してみます。
ここで使用したPHPのバージョンは、以下のとおりです。OSは、Ubuntu 14.04 LTS です。
$ php -v
PHP 5.5.9-1ubuntu4.9 (cli) (built: Apr 17 2015 11:45:45)
Copyright (c) 1997-2014 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2014 Zend Technologies
with Zend OPcache v7.0.3, Copyright (c) 1999-2014, by Zend Technologies
|
PHP の renameの問題点
既知の問題
そもそも PHP の rename は、問題も多く、つい最近まで マルチプラットフォームに対応しきれていませんでした。
PHPの公式マニュアル(http://php.net/manual/ja/function.rename.php)には、以下のような記載があります。
- 5.3.1 rename() は Windows で別のドライブにリネームできるようになりました。
- 5.0.0 rename() は いくつかの URL ラッパーを併用することができるようになりました。 rename() をサポートしているラッパーの一覧については、 サポートするプロトコル/ラッパー を参照ください。
- 4.3.3 rename() は *nix ベースシステムで パーティション越しにファイル名を変更できるようになりました。 適切なパーミッションが保持されます。 移動先のファイルシステムで chown() あるいは chmod() といったシステムコールが実行できない場合 (移動先のファイルシステムが FAT である場合など) は警告が発生します。
また、”https://bugs.php.net/” サイトには、rename 関連のバグが案外多いことがわかるかと思います。
(基本的に解決済になっているかと思います。)
ざっくりとしたものですが、renameを使うには、少なくとも 5.3.1 以上ですし、
問題に関しては、
正しく動いているのに警告メッセージが出力されたり、
正しく動作していないのにエラーが出力されなかったり、
名前を変更してもタイムスタンプが更新されなかったりと
ちょっと、つじつまが合わないような動作になっているのが伺い知ることができるかと思います。
このように、そもそも、ちょっと問題の多い関数であることを頭にいれておいてください。
今回の問題
さて、今回の問題は、先にも書いたように
32bit OS では、旧ファイル名、新ファイル名が、それぞれ異なるパーティション間で renameを実行すると
4GiBまでしかファイルを転送できない・・・という問題です。
この問題を確認するために簡単なテスト用のphpスクリプトを書いてみました。
このphpファイル( ここではファイル名を mv_test.php とします) を用いて、PHP の rename を使用しファイルの移動をしてみます。
( ここでは、移行に出てくるディレクトリ /tmp と /var2 は、異なるパーティションとします。 )
1
2
3
4
5
6
7
8
9
| <?php
error_reporting(E_ALL);
$time_start = microtime(true);
$mv_ret= rename('/tmp/aaa.mp4','/var2/aaa.mp4');
var_dump($mv_ret);
$time_end = microtime(true);
$time = $time_end - $time_start;
echo $time ." (s)";
?>
|
ここで作成したテスト用のphpファイル( ここではファイル名を mv_test.php とします) を実行してみます。
$ ls -l /tmp/aaa.mp4
-rw-r--r-- 1 root root 4728099044 6月 11 18:54 aaa.mp4
$ php mv_test.php
PHP Warning: rename(/tmp/aaa.mp4,/var2/aaa.mp4): No such file or directory in mv_test.php on line 4
bool(false)
34.926637172699 (s)
$ ls -l /tmp/aaa.mp4
-rw-r--r-- 1 root root 4728099044 6月 11 18:54 aaa.mp4
$ ls -l /var2/aaa.mp4
-rw-r--r-- 1 root root 4294967296 6月 11 18:58 aaa.mp4
|
この結果でわかるように、rename は、異なるパーティションでは、以下のような動作をします。
- ターゲットファイルをコピーする。
- 正しくコピーできた場合は、コピー元ファイルを削除する。
ここでは、コピーに失敗していますから、
コピー元もコピー先もファイルは、そのまま残っています。
さらに、コピー元(/tmp/aaa.mp4)のファイルサイズとコピー先(/var2/aaa.mp4)のファイルサイズは異なり、
コピー先(/var2/aaa.mp4)のファイルサイズについては、4GiB ( = 4 x 230 = 4,294,967,296 )となっているのがわかるかと思います。
この問題は、少なくとも 32bit 版 OS での問題であり、Ubuntuだけの問題かもしれません。
詳しく調べていませんが、
ソースコードは、たぶん、stream.c の phar_wrapper_rename になるのかな?と思いますが、
ざっくりと見てみると、多少、64bit対応処理が抜けているような?感じもしますから、そうなのかもしれません。(すみません、勘(カン)です)
また、この問題の回避策は、system関数を使って mv(move) コマンドを実行すれば良いだけです。
今回は、phpの問題を取り上げてみました。
phpは非常に便利なスクリプトで、Wordpressなどの有名なCMSなどに用いられていることでも有名です。
(随分、改善されていますが)便利になった反面、機能も多く、多少の問題があるのも事実でしょう。
ただ、このような問題は、phpに限らず人気のスクリプト言語には、よくあることかなぁとも思います。
また、よくある問題なら、回避策もそれなりにありますので、もし、そのような問題に当たってしまったなら、Googleさんで確認すると良いかもしれません。
ご利用のブラウザは、広告ブロック(AdBlockなど) が適用となっていませんか?
このサイトでは、コンテンツの一部が非表示、あるいは、コメント、お問い合わせの投稿ができない、検索ができないことがあります。
関連記事 :
コメントを投稿 :