LoginSignup
1
1

More than 5 years have passed since last update.

Nginx + php + ZipArchive で 大容量zipファイルを作成・ダウンロード

Last updated at Posted at 2018-10-24

問題

nginx を使ったwebサービスで、メガバイト級のファイル群をzipファイルにまとめてダウンロードする、という機能をつくる際に困った問題が起きました。

phpをつかってるので、ZipArchiveを使ってzipを生成するようにしてます。

zip生成 & zipダウンロードのコード

$filepath = [..., ..., ...];

$zipName = '/var/www/html/example.zip';
if (!file_exists($zipName)) {
  mkdir($zipTmpPath, 0777, TRUE);
}

$zip = new ZipArchive();
$zipResult = $zip->open($zipName, ZipArchive::CREATE | ZipArchive::OVERWRITE);

if ($zipResult !== true) {
  throw new Exception("Zip open is FALSE");
}

try {
    foreach ($files as $filepath) {
        $filename = basename($filepath);
        if ($zip->addFile($filepath, $filename) === FALSE) {
            if (!$zip->close()) {
                throw new Exception("$zip->addFile is FALSE AND $zip->close() is FALSE");
            } else {
                throw new Exception("$zip->addFile is FALSE");
            }
        }
    }
    if (!$zip->close()) {
    throw new Exception("$zip->close() is FALSE");
    }
} catch (Exception $e) {
  throw new Exception("zip exception");
}

if (!file_exists($zipPath)) {
  throw new Exception('Zip does not exist.');
}

header('Content-Type: application/force-download');
header('Content-Length: ' . filesize($zipName));
header('Content-Disposition: attachment; filename="' . basename($zipName) . '"');

while (ob_get_level() > 0) {
  ob_end_clean();
}
ob_start();

if ($realFile = fopen($zipName, 'rb')) {
  while (!feof($realFile) and (connection_status() == 0)) {
    echo fread($realFile, '4096');
    ob_flush();
  }
  ob_flush();
  fclose($realFile);
}
ob_end_clean();

unlink($zipName);

※ 参考コード: https://blog.kuromusubi.com/develop/language/php/20180114-ziparchive

問題の詳細

  • 400メガバイト程度のファイル群をzipにしようとすると、zipArchiveのaddFile部分で処理が止まってしまう。
  • 上記の場合、ブラウザ上では 「404 not found nginx」 と表示されてしまう。

nginxのerror.logには、以下のエラー内容が出力されていた。

upstream timed out (110: Connection timed out) while reading response header from upstream, client: ....
open() "/var/www/html/dev/50x.html" failed (2: No such file or directory),...

処理が止まっていた要因

  • メモリ不足
  • phpのタイムアウト
  • nginxのタイムアウト

対策

メモリ不足の対策

/etc/php.ini
memory_limit = 256M

phpのタイムアウトの対策

/etc/php.ini
max_execution_time = 600

nginxのタイムアウトの対策

/etc/nginx/nginx.conf
fastcgi_read_timeout 1200;
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1