phpを利用して、ファイルをzipで一括ダウンロードするためのプログラムをメモします。これは「jqueryで一括でチェックボックスを全選択する」で紹介したjsと組み合わせます。
また、「phpでcsvデータの内容を検索する」で紹介したプログラム及びcsvデータをベースとして利用します。
csvデータの内容
「phpでcsvデータの内容を検索する」で使用したcsvデータの末尾にファイルのパスを追加します。
contact.csv
登録年月日,会員氏名,メールアドレス,都道府県,ファイル, 20211001,山田太郎,taro@sample.com,東京都,https://www.sample.com/sample1.pdf, 20211010,山田花子,hanako@sample.com,東京都,https://www.sample.com/sample2.pdf, 20211020,日本太郎,n.taro@sample.com,神奈川県,https://www.sample.com/sample3.pdf, 20211101,日本花子,n.hanako@sample.com,千葉県,https://www.sample.com/sample4.pdf,
プログラムの内容
「phpでcsvデータの内容を検索する」の内容にファイルを追加し、さらに「jqueryで一括でチェックボックスを全選択する」のjsを記述してファイルの一括ダウンロード設定をします。
file.php
<?php $start = $_GET['start']; $end = $_GET['end']; $csv_file="csv/contact.csv"; $openfile = file_get_contents($csv_file); $csv_gyo = explode("\n", $openfile); $data_download_link=<<<END start=$start&end=$end END; ?> <!DOCTYPE html> <html lang="ja"><head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>テスト</title> <meta name="viewport" content="initial-scale=1"> </head> <body> <form method="post" name="zip" action="zip.php?<?php print $data_download_link;?>"> <table id="formfiled"> <tr> <th>登録年月日</th> <th>会員氏名</th> <th>メールアドレス</th> <th>都道府県</th> <th>ファイル</th> <th><label><input type="checkbox" name="allChecked" id="allcheck">全選択</label></th> </tr> <?php foreach($csv_gyo as $value) { list($ymd_data,$name,$mail,$pref,$file) = explode(",", $value); $ymd_data = mb_convert_encoding($ymd_data, "UTF-8", "SJIS"); $name = mb_convert_encoding($name, "UTF-8", "SJIS"); $mail = mb_convert_encoding($mail, "UTF-8", "SJIS"); $pref = mb_convert_encoding($pref, "UTF-8", "SJIS"); $file = mb_convert_encoding($file, "UTF-8", "SJIS"); $table_list=<<<END <tr> <td>$ymd_data</td> <td>$name</td> <td>$mail</td> <td>$pref</td> <td><a href="$file" download>ファイルをダウンロード</a></td> <td><label><input type="checkbox" name="pdf[]" value="$file"/>ファイル</label></td> </tr> END; if($ymd_data =="登録年月日" || $ymd_data ==""){ print <<<EOF EOF; } elseif(($end>=$ymd_data) && ($start<=$ymd_data)){ print <<<EOF $table_list EOF; } } ?> </table> <input type="submit" name="send" value="ファイル一括ダウンロード" /> </form> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script> $(function() { // 1. 「全選択」する $('#allcheck').on('click', function() { $("input[name='pdf[]']").prop('checked', this.checked); }); // 2. 「全選択」以外のチェックボックスがクリックされたら、 $("input[name='pdf[]']").on('click', function() { if ($('#box :checked').length == $('#formfiled :input').length) { // 全てのチェックボックスにチェックが入っていたら、「全選択」 = checked $('#allcheck').prop('checked', true); } else { // 1つでもチェックが入っていたら、「全選択」 = checked $('#allcheck').prop('checked', false); } }); }); </script> </body> </html>
index.phpはGETを使用してcsvの内容を検索し表示します。加えて、jsを使用してダウンロード該当ファイルを一括でチェックできるギミックを設定しています。そのデータをzipを生成する後述のzip.phpに送信する役割を果たします。
ポイントとしてcheckboxのpdfは複数生成されるので配列にしておきます。
<input type="checkbox" name="pdf[]" value="$file"/>
ではzip生成のプログラムを記述します。
zip.php
<?php $start = $_GET['start']; $end = $_GET['end']; $data_download_link=<<<END start=$start&end=$end END; $datename=date("Ymdhis"); $download_file=$start."_".$end."_".$datename; if (!empty($_POST["pdf"])){ // ダウンロードさせたいファイル $pdf= $_POST['pdf']; $pathAry = array(); for($i=0; $i<sizeof($pdf); $i++){ $pathAry[] = $pdf[$i]; } // zipのインスタンス作成 $objzip = new zipArchive($pathAry); // 一時ファイル(zip)の名前とPath $zipName = $download_file.'.zip'; $zipPath = 'tmpzip/' . $zipName; // 一時ファイル(zipファイル)を作成 $result = $objzip->open($zipPath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE); if ($result !== true) { echo "err - open zip-file"; exit; } set_time_limit(0); // zipに追加 foreach ($pathAry as $filepath) { $filename = basename($filepath); $objzip->addFromString($filename, file_get_contents($filepath)); } $objzip->close(); // 出力(ダウンロード) header('Content-Type: application/zip; name="' . $zipName . '"'); header('Content-Disposition: attachment; filename="' . $zipName . '"'); header('Content-Length: '.filesize($zipPath)); echo file_get_contents($zipPath); // 一時ファイル(zipファイル)の削除 unlink($zipPath); exit(); }else{ header("Location:index.php?$data_download_link"); } ?>
zipのファイル名
ファイル名はgetで得た情報にdate関数で生成したデータを追加します。
$data_download_link=<<<END start=$start&end=$end END; $datename=date("Ymdhis"); $download_file=$start."_".$end."_".$datename;
一時ファイルの生成
以下の部分で一時ファイルを生成します。
// zipのインスタンス作成 $objzip = new zipArchive($pathAry); // 一時ファイル(zip)の名前とPath $zipName = $download_file.'.zip'; $zipPath = 'tmpzip/' . $zipName; // 一時ファイル(zipファイル)を作成 $result = $objzip->open($zipPath, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE); if ($result !== true) { echo "err - open zip-file"; exit; }
zipの生成とダウンロード
ダウンロード用のzipを生成し、強制的にダウンロードします。同時に一時ファイルを削除します。
// zipに追加 foreach ($pathAry as $filepath) { $filename = basename($filepath); $objzip->addFromString($filename, file_get_contents($filepath)); } $objzip->close(); // 出力(ダウンロード) header('Content-Type: application/zip; name="' . $zipName . '"'); header('Content-Disposition: attachment; filename="' . $zipName . '"'); header('Content-Length: '.filesize($zipPath)); echo file_get_contents($zipPath); // 一時ファイル(zipファイル)の削除 unlink($zipPath); exit();
元のページに戻す
処理後file.phpに戻します。
header("Location:file.php?$data_download_link");
大容量のzipデータダウンロードの対応
大量にファイルをダウンロードする場合、php.iniで上限を上げるとある程度は対応できますが、複数人同時にダウンロードされるとサーバー負荷が大きくなります。そこでfile_get_contentsではなくfread関数で少しずつ読み込んで出力させる方法があります。
// 出力(ダウンロード) header('Content-Type: application/zip; name="' . $zipName . '"'); header('Content-Disposition: attachment; filename="' . $zipName . '"'); header('Content-Length: '.filesize($zipPath)); // out of memoryエラー対応 while (ob_get_level() > 0) { ob_end_clean(); } ob_start(); // ファイル出力 if ($file = fopen($zipPath, 'rb')) { while(!feof($file) and (connection_status() == 0)) { echo fread($file, '4096'); //指定したバイト数ずつ出力 ob_flush(); } ob_flush(); fclose($file); } ob_end_clean(); // out of memoryエラー対応
以上です。
デモを用意しました。デモではfread関数を使用しています。
検索結果をcsvでダウンロードできるようにしてますが、その辺は「phpでcsvデータの内容を検索した結果だけをcsvでダウンロードする」を参照してください。