PHP/Ajax PDF 生成超时

Posted

技术标签:

【中文标题】PHP/Ajax PDF 生成超时【英文标题】:PHP/Ajax PDF generation timeout 【发布时间】:2015-03-16 13:56:24 【问题描述】:

我在 php/ajax/jquery 中有一个代码,可以使用数据库中的值创建文档。但是当用户想要生成大量的 pdf 和 word 文件时,我遇到了生成大量文件所需的时间问题。

对于数组中的每个元素,我想创建一个 pdf 或 word,其中包含来自 mysql 数据库的该行 ID 的数据。 文件生成效果很好,我使用了:http://phpword.codeplex.com/ 和 mPDF。

1 个文件的生成时间约为 2-3 秒。当用户想要生成 500 条记录并将其打包为 .zip 时,我遇到了问题。

我的代码如下所示:

在客户端我创建了数组并通过 ajax 调用发送它:

function() 
    var ids = new Array();

    $.ajax(
        type: 'POST',
        url: 'ajax/generate_pdf.php',
        data: 
            'filename': $("#filename").val(),
            'idPDF': ids.toString()
        
    )
    .done(function (data) 
        $("#filename").val("");
        $("#message").append("Loading.<br/>");
        $("#message").append(data);
    )
    .fail(function () 
        alert("Error..");
    );

我的 generate_pdf.php 文件如下所示:

<?php 
// pdf library
include_once 'pdf/mpdf.php';

// name of zip
$filename=htmlspecialchars($_POST['filename']);

// open a zip
$zip = new ZipArchive();
$zip->open('../documents/'.$filename.'.zip', ZipArchive::CREATE);
header('Content-type: text/plain; charset=utf-8'); 

// get id's of rows sent by ajax
if(isset($_POST['idPDF']))

    $setid=$_POST['idPDF'];
    $rows=explode(',',$setid);

$count=count($rows);

for($i=0;$i<$count;$i++)

    // id of every row
    $id=$rows[$i]; 

    // query to read data for file creation
    $upit = "SELECT * FROM table WHERE id=?";

    // here i read everything from database using PDO functions

    // then i create html that will be written to pdf
    $html .=' test  ';

    // mpdf
    $mpdf=new mPDF(); 
    // define paper
    $mpdf=new mPDF('utf-8', array(176,250));
    // some css
    $style = '<style>
    @page 
        margin-left: 10mm; 
        margin-bottom: 0mm;
    
    </style>
    ';
    // writting to pdf
    $mpdf->WriteHTML($style);
    $mpdf->WriteHTML($html);

    // defining a name of pdf
    $filenameID = $somevaluefromdatabaseUNIQUE.'-'.$filename;
    $filenameID=preg_replace('/\s+/', '', $filenameID);
    $filenameID=str_replace('/', '-', $filenameID);

    // creating pdf
    $mpdf->Output('../documents/'.$filenameID.'.pdf','F');

    // add pdf to zip
    $zip->addFile('../documents/'.$$filenameID.'.pdf', ''.$filenameID.'.pdf');


// close the zip
$zip->close();

// returned message via ajax
echo '<a href="documents/'.$filename.'.zip">Download generated pdf's.</a><br/>';

?>

【问题讨论】:

您可能必须将最初的文件请求与文件的实际送达分开。一种方法是使用作业队列。初始请求将向队列中添加一个条目并返回一个 ID 或令牌。在后台,cron 每隔几分钟就会运行一次,并检查作业队列中的新项目。当它找到一个时,它会生成该作业的所有文档并标记该作业已准备就绪。在客户端,在您的初始请求之后,您会定期查询作业状态,完成后通知用户他们的文档已准备好(光滑:电子邮件)。 Paypal 使用这种方法。 【参考方案1】:

您遇到请求超时的问题。你可以:

    通过将 0 传递给以下函数,告诉您的 php 没有运行脚本的最长时间:

        set_time_limit(0);
    

    http://php.net/manual/en/function.set-time-limit.php

    重构您的代码,以便客户端每隔几秒发送 1 个 ajax 请求,而服务器始终为每个请求生成 1 个 PDF。

    以上两个选项都会让客户端等待很长时间。你对此无能为力,事情需要时间。您可以做的是改善用户体验,就像 Google Drive 在您尝试上传非常大的文件时所做的那样,它会在完成该过程时通知您(例如通过电子邮件)。您可以将您的呼叫队列中要生成的 PDF 文档的 ID,例如在数据库中,然后一个 cron 作业在队列中运行并实际生成它,这样用户就可以从“加载”屏幕中解放出来。当您的(异步)流程结束时,通过电子邮件(如果有)或适合您的用户案例的任何其他选项通知客户。

【讨论】:

是的,我知道 set_time_limit 并且我使用它。使用 cron 作业是个好主意,但由于客户需求,我不能使用它。感谢您的想法;)

以上是关于PHP/Ajax PDF 生成超时的主要内容,如果未能解决你的问题,请参考以下文章

无法呈现网址。无法从 url 获取图像。导航超时

亚马逊RDS超时与PHP pdf

如何在由于库函数而挂起的函数上实现超时? [复制]

AWS Lambda 上的 PhantomJS 总是超时

C Windows:生成子进程以停止和重新启动(超时后)父进程

springcloud openFeign 请求超时问题解决