Php 下载带有StreamdResponse的CSV在几行之后停止

Php 下载带有StreamdResponse的CSV在几行之后停止,php,symfony,doctrine-orm,doctrine-odm,Php,Symfony,Doctrine Orm,Doctrine Odm,我有一个MongoDB集合,其中有几千个条目,我想作为CSV文件下载 我有一些代码,基本上做了以下工作;控制器方法使用ODM查询数据库中的所有记录。然后将返回的光标馈送到StreamdResponse。在StreamdResponse中,我在光标上循环,并将每条记录作为CSV中的一行输出 下面的代码起作用,并下载一个文件。仅包含不超过60行。当光标计数指示有2670个结果时,它在该点停止流式处理的原因可能是什么 // Get all available bookings $cursor = $t

我有一个MongoDB集合,其中有几千个条目,我想作为CSV文件下载

我有一些代码,基本上做了以下工作;控制器方法使用ODM查询数据库中的所有记录。然后将返回的光标馈送到StreamdResponse。在StreamdResponse中,我在光标上循环,并将每条记录作为CSV中的一行输出

下面的代码起作用,并下载一个文件。仅包含不超过60行。当光标计数指示有2670个结果时,它在该点停止流式处理的原因可能是什么

// Get all available bookings
$cursor = $this
        ->get('doctrine_mongodb')
        ->getRepository('FooBundle:Booking')
        ->getQueryBuilder()
        ->getQuery()
        ->execute();

$response = new StreamedResponse(function () use ($cursor) {

    $handle = fopen('php://output', 'r+');

    $headerPrinted = false;

    // Calling $cursor->count() here returns 2670

    foreach ($cursor as $result) {
        // Transform the Booking object to a flat array.
        $data = $this->constructRow($result);

        // Print CSV header
        if (!$headerPrinted) {
            fputcsv($handle, array_keys($data), ';', '"');
            $headerPrinted = true;
        }

        // Add a line in the csv file.
        fputcsv($handle, $data, ';', '"');
    }

    fclose($handle);
});

$response->headers->set('Content-Type', 'application/force-download');
$response->headers->set('Content-Disposition', 'attachment; filename="bookings.csv"');

return $response;

就我所见,没有代码在流式传输时在内存中积累数据。我使用Symfony 2.7、Doctrine MongoDB ODM 1.0.3和PHP5.5.9,内存限制为256M。

听起来似乎与PHP.ini中的内存限制有关

ini_集('memory_limit','16M')


把它放大,看看你能得到多少行。听起来这和你在php.ini中的内存限制有关

ini_集('memory_limit','16M')


将其放大,查看得到的行数

如注释中所述,问题与光标结果上的不可iDatable对象有关。 为了捕获异常并写入正确的数据,您可以捕获异常。需要重写循环以捕获异常。例如,您可以按如下方式执行do while循环:

do {
        try 
        {
            // this could rise an exception
            $result = $cursor->getNext()
            // Transform the Booking object to a flat array.
            $data = $this->constructRow($result);

            // Print CSV header
            if (!$headerPrinted) {
                fputcsv($handle, array_keys($data), ';', '"');
                $headerPrinted = true;
            }

            // Add a line in the csv file.
            fputcsv($handle, $data, ';', '"');
        } catch (\Exception $e) 
        {
          // do nothing and process next element
        } 
 }
while($cursor->hasNext())
我还建议使用库来管理CSV编写,例如:


希望获得此帮助

如注释中所述,问题与光标结果上的不可识别对象有关。 为了捕获异常并写入正确的数据,您可以捕获异常。需要重写循环以捕获异常。例如,您可以按如下方式执行do while循环:

do {
        try 
        {
            // this could rise an exception
            $result = $cursor->getNext()
            // Transform the Booking object to a flat array.
            $data = $this->constructRow($result);

            // Print CSV header
            if (!$headerPrinted) {
                fputcsv($handle, array_keys($data), ';', '"');
                $headerPrinted = true;
            }

            // Add a line in the csv file.
            fputcsv($handle, $data, ';', '"');
        } catch (\Exception $e) 
        {
          // do nothing and process next element
        } 
 }
while($cursor->hasNext())
我还建议使用库来管理CSV编写,例如:


希望这有帮助

日志中有错误吗?symfony日志或apache/nginx?@Matteo,日志中没有添加任何内容,这让人觉得非常可疑。结果发现我有一个配置错误的日志处理程序。修复此问题后,我得到了一个
原则\ODM\MongoDB\DocumentNotFoundException
。显然,已删除引用的文档,但未从Booking对象中删除引用。我认为解决这个问题会解决我的问题因此,您只需解决捕获异常的问题,对吗?要捕获异常,您需要重新设计循环(现在在循环条件中引发异常)并使用curson的
hasNext
nethod设置循环条件,然后您可以在循环体中捕获异常,在该循环体中调用对象的
getNext
方法(请参见soruce代码)@Matteo,我正在考虑围绕游标创建包装器类,该类实现迭代器接口,并在下一个方法中包含
try{}catch(){}
。但你的想法要简单得多。我喜欢!日志中有错误吗?symfony日志或apache/nginx?@Matteo,日志中没有添加任何内容,这让人觉得非常可疑。结果发现我有一个配置错误的日志处理程序。修复此问题后,我得到了一个
原则\ODM\MongoDB\DocumentNotFoundException
。显然,已删除引用的文档,但未从Booking对象中删除引用。我认为解决这个问题会解决我的问题因此,您只需解决捕获异常的问题,对吗?要捕获异常,您需要重新设计循环(现在在循环条件中引发异常)并使用curson的
hasNext
nethod设置循环条件,然后您可以在循环体中捕获异常,在该循环体中调用对象的
getNext
方法(请参见soruce代码)@Matteo,我正在考虑围绕游标创建包装器类,该类实现迭代器接口,并在下一个方法中包含
try{}catch(){}
。但你的想法要简单得多。我喜欢!我已经编辑了我的帖子,添加了一些关于内存设置的信息。我有相当多的可用内存,使用StreamdResponse的全部目的不是将发送的数据保留在内存中。我编辑了我的帖子,添加了一些有关内存设置的信息。我有相当多的可用内存,使用StreamdResponse的全部目的不是将发送的数据保存在内存中。