ZAPAnet総合情報局 > ZAPAブログ2.0 > PHPのリネーム関数は上書きする

PHPのリネーム関数は上書きする

2020年06月25日 プログラミングTIPS
先日の「ブログのデザインとシステムをリニューアルしました」の時に、「iPhone(iOS6以上)対応画像アップロードプログラム」も自分用に改良したことを書きました。スマホから複数枚の画像をアップロードできるように改良し、画像を削除できる機能も付けました。その後、画像ファイルの名前をリネームできる機能も付けました。この「リネーム」の処理が少し危なかったので、メモとして残しておきます。
アップローダー

PHPの関数では、アップロードされたファイルを移動するときは「move_uploaded_file」関数を使います。一方、既存のファイルを移動するときは「rename」関数を使います。move_uploaded_file()とrename()、この統一感のない関数名がPHPの面白いところだななどと思っていたら、ちょっとした罠が。
rename ( string $oldname , string $newname [, resource $context ] ) : bool

oldname を newname にリネームし、必要ならディレクトリを移動しようと試みます。 ファイル名の変更かつ newname が存在する場合、上書きされます。 ディレクトリ名の変更かつ newname が存在する場合、 この関数は警告を発します。
「ファイル名の変更かつ newname が存在する場合、上書きされます」という仕様です。特に警告もなく、いきなり上書きしちゃうんですね。以下のページでも話題になっていました。

自分でファイルのリネーム処理を実装したとき、当初は「自分で名前を変更するわけだから、同じ名前を付けてしまうことはないだろう」などと考えていました。実際に画像ファイルのリネームをやってみたところ、変更後の名前をコピペで貼り付け、そのあと連番を付けようとしていたのに、コピペの段階でリターンキーを押してしまいそうになりました。そのままリターンキーを押していたら、画像を上書きして、元の画像ファイルが上書きされて消失していたというわけです。実際に上書きしてしまったわけではありませんが、このままでは危ないので、確認処理を追加しました。以下のような感じです。
//同じ名前のファイルがあるかチェック
if( file_exists($newname) ){
  //存在する場合
  echo "同じ名前のファイルがあります!リネームできません!";
}else{
  //リネーム処理
}
file_exists関数を使って、もし変更後の名前と同じ名前のファイルがすでに存在するなら、リネームできないような処理を追加しました。これにより、誤った操作でファイルを上書きして消えてしまう心配がなくなりました。このプログラムは自分しか使っていないのでこの処理で問題ありませんが、「もし同時に同じ名前のリネーム処理が走ったら?」という部分は考慮していません。たくさんの人が同時にリネームするような環境では、もう一手間の改良が必要だと思います。