简体   繁体   English

如何使用PHP和ZipArchive创建ZIP文件而不将其发送到浏览器?

[英]How to create a ZIP file using PHP and ZipArchive without sending it to the browser?

My PHP/MySQL web application has a function that combines a set of images for each user into a single PDF using ImageMagick. 我的PHP / MySQL Web应用程序具有使用ImageMagick将每个用户的一组图像组合到单个PDF中的功能。 Each PDF is then placed into a ZIP file. 然后将每个PDF放入一个ZIP文件中。 Each image can be up to 5 MB in size. 每个图像的最大大小为5 MB。 My problem is that the browser times out before the user can download the document. 我的问题是浏览器在用户可以下载文档之前超时。

Any ideas on how to best do this? 关于如何最好地做到这一点的任何想法?

I was thinking I could create the ZIP file without sending it to the browser (ie remove the "headers" at the end of my code) and then email a link to the file; 我以为我可以创建ZIP文件而不将其发送到浏览器(即,删除代码末尾的“标题”),然后通过电子邮件将链接发送到该文件; however, it still requires that the user wait a long time for the ZIP file to be created (it appears as if the browser is just hanging). 但是,它仍然需要用户等待很长时间才能创建ZIP文件(看起来好像浏览器刚刚挂起一样)。 Could this be done with AJAX behind the scenes or directly on the server somehow? 可以使用AJAX在后台还是直接在服务器上以某种方式完成此操作?

$tmp_path = sys_get_temp_dir().'/';
$archive_name = "myarchive.zip";

$zip = new ZipArchive();

if($zip->open($archive_name,1 ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE) !== true) {
    return false;
}

foreach ($rows AS $row) {

    $irows = get_images($row['user_id']);

    $images = array();

    foreach($irows AS $irow){
        $doc = fetch_document_path($irow['id']);
        $output_file_name = $tmp_path.$irow['id'].'.jpg';  
        exec ('convert '.$doc.' '.$output_file_name);
        $images[] = $irow['id'].'.jpg'; 
    }    

    $images = implode(' ', $images);   
    $output_file_name = $tmp_path.$row['name'].'.pdf';  
    exec ('convert '.$images.' "'.$output_file_name.'"');       
    $zip->addFile($output_file_name,basename($output_file_name));

}

$zip->close();

header('Content-type: application/zip');
header('Content-Disposition: attachment; filename="output.zip"');
readfile($archive_name);

IMO you should run some background task that will do the job. IMO,您应该运行一些后台任务来完成这项工作。 Background worker can for example save URL to result file in DB after it'll finished (can also save some more information like current status and job progress), meantime webpage can periodically ask server using AJAX if job is already done or not and finally display link when it'll be available. 例如,后台工作人员可以在完成后将URL保存到数据库中的结果文件中(还可以保存一些其他信息,例如当前状态和作业进度),与此同时,网页可以定期使用AJAX询问服务器是否已完成作业并最终显示链接何时可用。

Simplest way to achieve that is to run your script as background process: 最简单的方法是将脚本作为后台进程运行:

  $arg1 = escapeshellarg($somearg1);
  $arg2 = escapeshellarg($somearg1);
  exec(sprintf('/usr/bin/php archiver.php %s %s > /dev/null 2>&1 & echo $!', $arg1, $arg2));

archiver.php should begin with following lines: archiver.php应该以以下几行开头:

 <?php
 ignore_user_abort(true);
 set_time_limit(0);

it'll prevent script from being stopped when parent script will finish working. 这样可以防止父脚本完成工作后停止脚本。

Second idea I have is more complex - you can write a daemon that will run in background waiting for jobs. 第二个想法比较复杂-您可以编写一个守护程序,该守护程序将在后台运行以等待作业。 To communicate with it you can use queues (like AMQP) or just database. 要与之通信,您可以使用队列(例如AMQP)或仅使用数据库。 With daemon you'll have more control on what is happening and when - in first approach it can happen that your application will fire too many processes. 使用守护程序,您可以更好地控制发生的时间和时间-在第一种方法中,您的应用程序可能会触发过多的进程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM