Php 导出到Excel时,将公式视为任何其他文本值
我构建了一个报告解决方案,可以将数据导出为Excel。使用PHPExcel,这项工作非常漂亮。但是,我们需要构建仪表板样式的模板表,并在运行时将它们插入到输出中,包括公式。我的问题是,有时候这些仪表板模板相当复杂,PHPExcel在尝试输出时会阻塞公式 我花了相当多的时间寻找解决方法,甚至添加了一种禁用计算的方法,试图阻止公式被处理,但无法使其工作。我还尝试禁用计算缓存 @MarkBaker在这个库中做了非常出色的工作,我多次看到他提到这个库不是为修改文件而设计的,但是如果做得非常仔细,它似乎可以工作 我的问题是,如何让PHPExcel停止尝试计算公式?我希望它像对待任何其他文本值一样对待它们,并让Excel自己处理验证。这可能吗 例如,PHPExcel似乎不喜欢以下公式:Php 导出到Excel时,将公式视为任何其他文本值,php,excel,phpexcel,Php,Excel,Phpexcel,我构建了一个报告解决方案,可以将数据导出为Excel。使用PHPExcel,这项工作非常漂亮。但是,我们需要构建仪表板样式的模板表,并在运行时将它们插入到输出中,包括公式。我的问题是,有时候这些仪表板模板相当复杂,PHPExcel在尝试输出时会阻塞公式 我花了相当多的时间寻找解决方法,甚至添加了一种禁用计算的方法,试图阻止公式被处理,但无法使其工作。我还尝试禁用计算缓存 @MarkBaker在这个库中做了非常出色的工作,我多次看到他提到这个库不是为修改文件而设计的,但是如果做得非常仔细,它似乎可
=IFERROR(IF($L$3="UNITS",COUNTIF('K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5)+COUNTIF('K1_Current_Available'!$M$2:$M$10000,'Snapshot Summary'!H5),IF($L$3="Cost Basis",SUMIF('K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5,'K1_Current_Accounts'!$E$2:$E$10000)+SUMIF('K1_Current_Available'!$M$2:$M$10000,'Snapshot Summary'!H5,'K1_Current_Available'!$E$2:$E$10000),IF($L$3="Notes",SUMIFS('K1_Current_Accounts'!$AA$2:$AA$10000,'K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5,'K1_Current_Accounts'!$R$2:$R$10000,'Snapshot Summary'!$A$7)+SUMIFS('K1_Current_Accounts'!$AA$2:$AA$10000,'K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5,'K1_Current_Accounts'!$R$2:$R$10000,'Snapshot Summary'!$A$8)+SUMIFS('K1_Current_Accounts'!$AA$2:$AA$10000,'K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5,'K1_Current_Accounts'!$R$2:$R$10000,'Snapshot Summary'!$A$9),IF($L$3="Cash",SUMIFS('K1_Historical_Accounts'!$AC$2:$AC$10000,'K1_Historical_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5,'K1_Historical_Accounts'!$R$2:$R$10000,'Snapshot Summary'!$A$10))))),"")
我读到SUMIFS
可能会导致问题,但我不知道如何按照建议将其重构为SUMPRODUCT
(这些仪表盘由业务开发团队构建)。此外,我们的列范围达到10000,因为像A:A这样的范围也不起作用。它们在Excel中工作得很好,所以如果我能让PHPExcel停止尝试验证一切,让它通过,我的生活将是美好的
编辑
进一步查看堆栈跟踪,它似乎在尝试编写图表时开始出现:
编辑2
将图表生成视为此问题的根源,只有一个图表,它的数据源是
='Sales History'$Y$4:$CR$5
,我可以看到它确实尝试处理,但这不应该引起问题,因为它是一个相对简单的引用。您可以通过使用将编写器的preCalculateFormulas
标记设置为false来防止PHPExcel在编写时计算公式
$objWriter->setPreCalculateFormulas(false);
编辑
我对Excel2007 Writer进行了一些实验性更改,以禁用图表的单元格计算:
在/PHPExcel/Writer/Excel2007/Chart.php
中,我添加了一个新属性
protected $calculateCellValues;
并修改了writeChart()
方法以接受附加参数:
public function writeChart(PHPExcel_Chart $pChart = null, $calculateCellValues = true)
{
$this->calculateCellValues = $calculateCellValues;
并修改了对$pChart->refresh()的后续调用
在/PHPExcel/Writer/Excel2007.php的save()
方法中,我将第300行附近对writeChart()的调用修改为:
$objZip->addFromString(
'xl/charts/chart' . ($chartCount + 1) . '.xml',
$this->getWriterPart('Chart')
->writeChart($chart, $this->preCalculateFormulas)
);
(即,我已将$this->preCalculateFormulas
注入图表编写器。)
临时测试表明,当结果xlsx文件被打开时,MS Excel将触发重新计算。。。。但这还不是一个完整的测试您可以通过使用将编写器的preCalculateFormulas
标记设置为false来防止PHPExcel在编写时计算公式
$objWriter->setPreCalculateFormulas(false);
编辑
我对Excel2007 Writer进行了一些实验性更改,以禁用图表的单元格计算:
在/PHPExcel/Writer/Excel2007/Chart.php
中,我添加了一个新属性
protected $calculateCellValues;
并修改了writeChart()
方法以接受附加参数:
public function writeChart(PHPExcel_Chart $pChart = null, $calculateCellValues = true)
{
$this->calculateCellValues = $calculateCellValues;
并修改了对$pChart->refresh()的后续调用
在/PHPExcel/Writer/Excel2007.php的save()
方法中,我将第300行附近对writeChart()的调用修改为:
$objZip->addFromString(
'xl/charts/chart' . ($chartCount + 1) . '.xml',
$this->getWriterPart('Chart')
->writeChart($chart, $this->preCalculateFormulas)
);
(即,我已将$this->preCalculateFormulas
注入图表编写器。)
临时测试表明,当结果xlsx文件被打开时,MS Excel将触发重新计算。。。。但这还不是一个完整的测试我从未使用过PHPExcel,但我可以将该公式从SUMIF/S()重新表述为SUMPRODUCTS。您可以使用Alt+Enter使这些庞大的公式具有一定的可读性
为了让您了解sumproduct,当应用任何数学运算时,Excel将TRUE/FALSE视为1/0,因此您可以{TRUE,TRUE,FALSE}x{FALSE,TRUE,TRUE}来获得{0,1,0}。然后SUMPRODUCT取{0,1,0}并将其乘以您尝试筛选的行/列总数,然后对值求和
=IFERROR(
IF($L$3="UNITS",
COUNTIF('K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5)
+COUNTIF('K1_Current_Available'!$M$2:$M$10000,'Snapshot Summary'!H5),
IF($L$3="Cost Basis",
SUMPRODUCT(--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),'K1_Current_Accounts'!$E$2:$E$10000)
+SUMPRODUCT(--('K1_Current_Available'!$M$2:$M$10000='Snapshot Summary'!H5),'K1_Current_Available'!$E$2:$E$10000),
IF($L$3="Notes",
SUMPRODUCT('K1_Current_Accounts'!$AA$2:$AA$10000,--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Current_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$7))
+SUMPRODUCT('K1_Current_Accounts'!$AA$2:$AA$10000,--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Current_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$8))
+SUMPRODUCT('K1_Current_Accounts'!$AA$2:$AA$10000,--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Current_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$9)),
IF($L$3="Cash",
SUMPRODUCT('K1_Historical_Accounts'!$AC$2:$AC$10000,--('K1_Historical_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Historical_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$10))))))
,"")
我从未使用过PHPExcel,但我可以将该公式从SUMIF/S()重新表述为SUMPRODUCTS。您可以使用Alt+Enter使这些庞大的公式具有一定的可读性
为了让您了解sumproduct,当应用任何数学运算时,Excel将TRUE/FALSE视为1/0,因此您可以{TRUE,TRUE,FALSE}x{FALSE,TRUE,TRUE}来获得{0,1,0}。然后SUMPRODUCT取{0,1,0}并将其乘以您尝试筛选的行/列总数,然后对值求和
=IFERROR(
IF($L$3="UNITS",
COUNTIF('K1_Current_Accounts'!$M$2:$M$10000,'Snapshot Summary'!H5)
+COUNTIF('K1_Current_Available'!$M$2:$M$10000,'Snapshot Summary'!H5),
IF($L$3="Cost Basis",
SUMPRODUCT(--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),'K1_Current_Accounts'!$E$2:$E$10000)
+SUMPRODUCT(--('K1_Current_Available'!$M$2:$M$10000='Snapshot Summary'!H5),'K1_Current_Available'!$E$2:$E$10000),
IF($L$3="Notes",
SUMPRODUCT('K1_Current_Accounts'!$AA$2:$AA$10000,--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Current_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$7))
+SUMPRODUCT('K1_Current_Accounts'!$AA$2:$AA$10000,--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Current_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$8))
+SUMPRODUCT('K1_Current_Accounts'!$AA$2:$AA$10000,--('K1_Current_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Current_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$9)),
IF($L$3="Cash",
SUMPRODUCT('K1_Historical_Accounts'!$AC$2:$AC$10000,--('K1_Historical_Accounts'!$M$2:$M$10000='Snapshot Summary'!H5),--('K1_Historical_Accounts'!$R$2:$R$10000='Snapshot Summary'!$A$10))))))
,"")
我试过了。在PHPExcel\Writer\Excel2007
第39行中,它也默认为false
。在那个特定的编写器(我需要的编写器)中,它将该值传递到工作表的第290行,但仍然尝试验证公式的正确性。我正在尽我所能避免写我自己的库来处理这些东西,因为它非常复杂(如你所知),但我没有取得多大进展。让我看看是否可以在这里找到代码路径,它仍在运行公式计算。该函数是否停止图表中的计算?是否使用列自动调整大小?这应该是唯一可以覆盖预计算公式falseNo的公式计算触发器,但我使用的是自动过滤。我发布了一个编辑我的问题与屏幕截图进一步向下的堆栈跟踪。似乎是图表生成触发了导致公式计算的一系列事件。虽然自动筛选不使用计算IIRC,但