ZipArchiveでZipファイル…                            
                            [2018-01-14 10:13:40][
ブログ記事へ]
                                                            
                                    
                                        rel="nofollow">肌年齢が若くなる!?【厳選された植物原料100%】納得の無添加 化粧水 
問題
ZipArchiveを使用してzipファイルを作成し、ダウンロードさせるWebページを作成していたが、
アカウントによってダウンロードできていない人がいた
コード
    // Zipフォルダにコピーするファイル
    $files = array("/atxt","/btxt","/ctxt");
    // Zip作成用一時フォルダを作る
    $tmp = "\\tmp";
    if(!file_exists($tmp))
        if (!mkdir($tmp, 0777, true)){
            echo "{$tmp}の作成に失敗しました\n";
            exit();
        }
    // zipフォルダを作る
    $zipfile = "{$tmp}\\zip1zip");
    // すでにファイルがある場合削除
    if(file_exists($zipfile))
        unlink ($zipfile);
    // Zipを作成
    $zip = new ZipArchive;
    if ($zip>open($zipfile, ZipArchiveCREATE) === FALSE) {
        echo "zipの作成に失敗しました\n";
        exit();
    }
    // ファイルをコピーする
    foreach($files as $file){
        if($zip>addFile("{$file}",basename($file)) === FALSE){
            echo "{$file}のコピーに失敗しました\n";
            $zip>close();
            exit();
        }
    }
    $zip>close();
    // ダウンロードさせる
    header('ContentType application/forcedownload');
    header('ContentLength 'filesize($zipfile));
    header('Contentdisposition attachment; filename="'basename($zipfile)'"');
    // readfile()だと大容量のときに時間がかかりすぎるので分割する
    // out of memoryエラーが出る場合に出力バッファリングを無効
    while (ob_get_level() > 0) {
      ob_end_clean();
    }
    ob_start();
    // ファイル出力
    if ($file = fopen($zipfile, 'rb')) {
        while(!feof($file) and (connection_status() == 0)) {
            echo fread($file, '4096'); //指定したバイト数ずつ出力
            ob_flush();
        }
        ob_flush();
        fclose($file);
    }
    ob_end_clean();
    // 一時ファイルを削除する
    unlink ($zipfile);
期待する動作
ダウンロードボタンがクリックされたらzipの生成を開始
zipの生成が完了したらダウンロード
現象
PHPのエラーログには
  [09Jan2018 095935 Asia/Seoul] PHP Warning  fopen(zip1zip) failed to open stream No such file or directory in 該当ページphp on line  
zipを作成する一時フォルダには、zip1zipa06572といった、zipになりきれなかったファイルが残っている
ファイルサイズはあるため、ファイルのコピーは成功しているっぽい
zip>close()に失敗している?
ただし、zip>close()の戻り値を見てみても、trueを返してきている
原因
zipを生成する一時フォルダに、現象発生ユーザーの”変更”の権限がついていなかった
ファイルの作成、コピーは「書き込み」の権限でできるが、zip>close()は「変更」の権限が必要?
権限がなくclose()に失敗している場合でもTrueが返ってきてしまうらしい
解決策
該当ユーザーに、「書き込み」「読み込み」だけでなく、「変更」 の権限も付ける
ついでにzip>close()にもエラー処理を追加
<?php
    // Zipフォルダにコピーするファイル
    $files = array("/atxt","/btxt","/ctxt");
    // Zip作成用一時フォルダを作る
    $tmp = "\\tmp";
    if(!file_exists($tmp))
        if (!mkdir($tmp, 0777, true)){
            echo "{$tmp}の作成に失敗しました\n";
            exit();
        }
    try {
        // zipフォルダを作る
        $zipfile = "{$tmp}\\zip1zip");
        if(!file_exists($zipfile)){
            $zip = new ZipArchive;
            $res = $zip>open($zipfile, ZipArchiveCREATE);
            if ($res != TRUE) {
                throw new Exception("open FALSE code{$res}");
            }
            // ファイルをコピーする
            foreach($files as $file){
                if($zip>addFile("{$file}",basename($file)) === FALSE){
                    if(!$zip>close())
                        throw new Exception("addFile FALSE AND close FALSE");
                    else
                        throw new Exception("addFile FALSE");
                }
            }
            if(!$zip>close()){
                throw new Exception("close False");
            }
        }
    } catch (Exception $e) {
        echo "zipの作成に失敗しました\n";
        error_log(date("Y/m/d His")"\t"$e>getFile()""$e>getLine()" "$e>getMessage() "("$e>getCode()")["get_class($e)"]\t{$zipfile}\r\n", 3, "errorlog");
        exit();
    }
    if(!file_exists($zipfile)){
        echo "zipが存在しません\n";
        error_log(date("Y/m/d His")"\t{$zipfile}が存在しません\r\n", 3, "errorlog");
        exit();
    }
    // ダウンロードさせる
    header('ContentType application/forcedownload');
    header('ContentLength 'filesize($zipfile));
    header('Contentdisposition attachment; filename="'basename($zipfile)'"');
    // readfile()だと大容量のときに時間がかかりすぎるので分割する
    // out of memoryエラーが出る場合に出力バッファリングを無効
    while (ob_get_level() > 0) {
      ob_end_clean();
    }
    ob_start();
    // ファイル出力
    if ($file = fopen($zipfile, 'rb')) {
        while(!feof($file) and (connection_status() == 0)) {
            echo fread($file, '4096'); //指定したバイト数ずつ出力
            ob_flush();
        }
        ob_flush();
        fclose($file);
    }
    ob_end_clean();
?>
ZipArchive自体はエラーになっていないので、上記で正しくエラーログが出力できるかはわかりません(´⊙ω⊙`)                                    
                                                                                    
                                                続きを見る