ユーザーが FTP 経由で zip ファイルをアップロードすると、php ファイルがそれらを RSS ファイルに追加します。
各 ZIP ファイルをチェックしてファイルを検証し、ファイルが壊れているかどうか、またはアップロードが未完了かどうかを確認する方法を見つけようとしています。それを行う方法はありますか?
からの結果は、最初に評価する必要があるopen
の場合もあります。(int) 1 に等しいcheck がなければ、常に一致します。true
ZipArchive:ER_NOZIP
$zip = new ZipArchive();
$res = $zip->open('test.zip', ZipArchive::CHECKCONS);
if ($res !== TRUE) {
switch($res) {
case ZipArchive::ER_NOZIP:
die('not a zip archive');
case ZipArchive::ER_INCONS :
die('consistency check failed');
case ZipArchive::ER_CRC :
die('checksum failed');
default:
die('error ' . $res);
}
}
ZipArchive
これにはクラスを使用できます。PHP5.2 以降、標準の php ディストリビューションに含まれています。
次のように使用します。
$zip = new ZipArchive();
// ZipArchive::CHECKCONS will enforce additional consistency checks
$res = $zip->open('test.zip', ZipArchive::CHECKCONS);
if(!$res) {
throw Exception('Error opening zip');
}
switch($res) {
case ZipArchive::ER_NOZIP :
die('not a zip archive');
case ZipArchive::ER_INCONS :
die('consistency check failed');
case ZipArchive::ER_CRC :
die('checksum failed');
// ... check for the other types of errors listed in the manual
}
zip アーカイブが不完全であるか、他の方法で破損している場合は$zip->open()
、ZipArchive::ER_NOZIP
CRC が一致しない破損ファイルを検出する方法:
ZipArchive は壊れたファイルを検出できないようです。ZipArchive::CHECKCONS は、それが ZIP ファイルではない場合にのみ役に立ちません。私のテストでは、破損したファイルを喜んで解凍しましたが、データをダウンロードしているクライアントには通知されません。
テスト用に破損したアーカイブを作成するのは簡単です。いくつかのファイルを圧縮し、結果の ZIP ファイル内の 16 進エディターで 1 バイトを変更します。これで、ZIP アプリケーションでファイルをテストして、アーカイブ内のどのファイルが破損しているかを調べることができます。
小さなファイルの場合、サーバー上の CRC を簡単に確認できます。
<?php
$maxsize = 1024*1024;
$z = new ZipArchive;
$r = $z->open("foo.zip", ZipArchive::CHECKCONS);
if($r !== TRUE)
die('ZIP error when trying to open "foo.zip": '.$r);
$stat = $z->statName("mybrokenfile.txt");
if($stat['size'] > $maxsize)
die('File too large, decompression denied');
$s = $z->getStream($file);
$data = stream_get_contents($s, $maxsize);
fclose($s);
if($stat['crc'] != crc32($data))
die('File is corrupt!');
//echo 'File is valid';
//you may send the file to the client now if you didn't output anything before
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="mybrokenfile.txt"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . $stat['size']);
ob_clean();
echo $data;
$z->close();
?>
ファイルがサーバー上で完全に解凍されず、サイズが原因でクライアントへのストリーミング中に解凍される場合、ファイル転送はすでに開始されており、後でエラー メッセージを出力しても機能しません。おそらく最善の方法は、ファイル転送を閉じる前に接続を中断することです。クライアントは、これを破損したダウンロードとして検出できるはずです。サーバー側では、ストリーミングされたデータの CRC32 を段階的に計算できる関数が必要です。