【问题标题】:PHP/Ajax PDF generation timeoutPHP/Ajax PDF 生成超时
【发布时间】: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 使用这种方法。

标签: php jquery ajax json mpdf


【解决方案1】:

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

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

        set_time_limit(0);
    

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

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

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

【讨论】:

  • 是的,我知道 set_time_limit 并且我使用它。使用 cron 作业是个好主意,但由于客户需求,我不能使用它。感谢您的想法;)
猜你喜欢
  • 1970-01-01
  • 2011-04-04
  • 2019-02-11
  • 1970-01-01
  • 2013-10-13
  • 1970-01-01
  • 2015-08-05
  • 1970-01-01
  • 2011-12-31
相关资源
最近更新 更多