PHPExcel库挂起了相对的"大"文件

时间:2015-05-08 07:42:30

标签: php mysql phpexcel

我试图将一些记录从我的MySQL(网络服务器)导出到excel,当查询返回> 4k记录时,脚本会挂起网络浏览器,暂时挂起网络托管。

我的PHP_version是5.2.13-pl1-gentoo,而memory_limit中配置的php.ini是128M

结果excel只有一列和N行。有了100或200行,php脚本运行正常。

这是php脚本

<? session_start();
ini_set('memory_limit', '1024M');
set_time_limit(0);
include("include/conexion.php");    
require_once 'include/PHPExcel/Classes/PHPExcel.php';
require_once 'include/PHPExcel/Classes/PHPExcel/IOFactory.php';
$objPHPExcel = new PHPExcel();

$objPHPExcel->getProperties()->setCreator("Name")
->setLastModifiedBy("Name")
->setTitle("Listado")
->setSubject("Listado")
->setDescription("Listado.")
->setKeywords("Listado")
->setCategory("Listado");


    $query = explode("|",stripcslashes($_POST['query']));
$objPHPExcel->getActiveSheet()->setTitle('List');

  $resEmp = mysql_query ($query, $conexion ) or die(mysql_error());
  $tot = mysql_num_rows($resEmp);
  $num_fields = mysql_num_fields($resEmp);

  $fistIndex = $objPHPExcel->getActiveSheet()->getCellByColumnAndRow(0, 1)->getColumn();
  $lastIndex = $objPHPExcel->getActiveSheet()->getCellByColumnAndRow($num_campos - 1, 1)->getColumn();


  //tittles
  for ($e=0;$e < $num_fields;$e++){     
    $objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($e, 2, utf8_decode(ucwords(mysql_field_name($resEmp,$e))));
    $objPHPExcel->getActiveSheet()->getColumnDimension($objPHPExcel->getActiveSheet()->getCellByColumnAndRow($e, 2)->getColumn())->setAutoSize(true);
  }
  //color tittles
  $objPHPExcel->getActiveSheet()->getStyle( $fistIndex.'1:'.$lastIndex.'2' )->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setRGB('c5c5c7');
  $objPHPExcel->getActiveSheet()->getStyle( $fistIndex.'1:'.$lastIndex.'2' )->getFont()->setBold(true);


    if(isset ( $_POST ['mail'] )){

    $objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow(0, 2, "Email");
    $emails = array();
    for ($row = 0; $row < $totEmp; $row++) {
        //more than one mail in field separated by ";"
        $aux = explode(";", mysql_result($resEmp,$row,$col));

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

            $cleaned = utf8_encode(strtolower(trim($aux[$i])));
            //filter repeated mails
            if(!in_array($cleaned, $emails) && $aux[$i] != ""){ 
                $num_rows = $objPHPExcel->getActiveSheet()->getHighestRow();
                $objPHPExcel->getActiveSheet()->insertNewRowBefore($num_rows + 1, 1);
                array_push($emails, $cleaned);                  
                $objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow(0, $num_rows + 1, $cleaned);
            }

        }

    }

  }


  $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');

  header('Content-type: application/vnd.ms-excel');
  header("Content-Disposition: attachment; filename=".$nom_archivo.".xlsx");

  // Write file to the browser
  $objWriter->save('php://output');
  exit();


?>

当输入脚本运行mysql查询然后,迭代结果以获取邮件字段,如果获取的邮件不存在于数组中,则此邮件将插入excel中

我试图设置

ini_set('memory_limit', '1024M');
set_time_limit(0);

但问题仍然存在。

有什么想法解决问题吗?

非常感谢

编辑1

我已经使用建议更新了代码,现在工作正常。 无论如何,如果在挂起之前发生任何错误或内存使用,我怎么能得到? 如何使用ini_set('memory_limit', '2048M');设置max memory_limit?

 <? session_start();
    ini_set('memory_limit', '2048M');
    set_time_limit(0);
    include("include/conexion.php");    
    require_once 'include/PHPExcel/Classes/PHPExcel.php';
    require_once 'include/PHPExcel/Classes/PHPExcel/IOFactory.php';
    $objPHPExcel = new PHPExcel();

    $objPHPExcel->getProperties()->setCreator("Name")
    ->setLastModifiedBy("Name")
    ->setTitle("Listado")
    ->setSubject("Listado")
    ->setDescription("Listado.")
    ->setKeywords("Listado")
    ->setCategory("Listado");

    $activeSheet = $objPHPExcel->getActiveSheet();
        $query = explode("|",stripcslashes($_POST['query']));
    $activeSheet->setTitle('List');

      $resEmp = mysql_query ($query, $conexion ) or die(mysql_error());
      $tot = mysql_num_rows($resEmp);
      $num_fields = mysql_num_fields($resEmp);

      $fistIndex = $activeSheet->getCellByColumnAndRow(0, 1)->getColumn();
      $lastIndex = $activeSheet->getCellByColumnAndRow($num_campos - 1, 1)->getColumn();


      //tittles
      for ($e=0;$e < $num_fields;$e++){     
        $activeSheet->setCellValueByColumnAndRow($e, 2, utf8_decode(ucwords(mysql_field_name($resEmp,$e))));
        $activeSheet->getColumnDimension($activeSheet->getCellByColumnAndRow($e, 2)->getColumn())->setAutoSize(true);
      }
      //color tittles
      $activeSheet->getStyle( $fistIndex.'1:'.$lastIndex.'2' )->getFill()->setFillType(PHPExcel_Style_Fill::FILL_SOLID)->getStartColor()->setRGB('c5c5c7');
      $activeSheet->getStyle( $fistIndex.'1:'.$lastIndex.'2' )->getFont()->setBold(true);


        if(isset ( $_POST ['mail'] )){

        $activeSheet->setCellValueByColumnAndRow(0, 2, "Email");
        $emails = array();
        for ($row = 0; $row < $totEmp; $row++) {
            //more than one mail in field separated by ";"
            $aux = explode(";", mysql_result($resEmp,$row,$col));

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

                $cleaned = utf8_encode(strtolower(trim($aux[$i])));
                //filter repeated mails
                if(!in_array($cleaned, $emails) && $aux[$i] != ""){ 
                    array_push($emails, $cleaned);                                      
                }

            }

        }
    for ($row = 0; $row < count($emails); $row++) {
        $activeSheet->setCellValueByColumnAndRow(0, $row + 3, $emails[$row]);
    }

      }


      $objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');

      header('Content-type: application/vnd.ms-excel');
      header("Content-Disposition: attachment; filename=".$nom_archivo.".xlsx");

      // Write file to the browser
      $objWriter->save('php://output');
      exit();


    ?>

2 个答案:

答案 0 :(得分:0)

似乎这个库在解析大型excel电子表格方面存在严重问题,我已经发现了这个问题。我找不到合适的解决方案。我想这是正常的行为,因为这个库完全用PHP编写,导致大量的解析开销 我强烈建议您使用excel解析PHP扩展,如Jersey documentation - Defining Custom Injection Annotation 作为另一个可以想象的解决方案[如果可能],你可以将你的大文件分解为几个较小的文件(例如通过表格),否则我猜你应该使用更快的CPU或使用另一个库或编程语言来解析你的exel文件(例如java中的this one,可能带有apache-poi)。

答案 1 :(得分:0)

不幸的是,PHPExcel不适合使用大数据执行,因为PHP实际上并不是一个好的二进制文件处理语言。

有些人将他们的数据导出为ex​​cel(http://en.wikipedia.org/wiki/Microsoft_Office_XML_formats)的XML格式,并且它可以很好地运行。但是,xml格式没有excel二进制文件的完整功能,当然它的文件大小也会更大。

为了处理大数据(导入/导出到二进制excel文件),我们的系统现在使用libxl,这将花费199美元的许可证,php_excel是libxl的包装器。实际上,我们的系统现在使用libxl在大约几秒钟内导出一个行数超过5k的excel文件,我认为它是迄今为止使用二进制excel的唯一解决方案。

P / s:$ objPHPExcel-&gt; getActiveSheet()也有成本,因此您可以将其值存储到变量中以便稍后重用,这将有助于您加快代码的速度。