Php 导出到Excel时,将公式视为任何其他文本值

Php 导出到Excel时,将公式视为任何其他文本值,php,excel,phpexcel,Php,Excel,Phpexcel,我构建了一个报告解决方案,可以将数据导出为Excel。使用PHPExcel,这项工作非常漂亮。但是,我们需要构建仪表板样式的模板表,并在运行时将它们插入到输出中,包括公式。我的问题是,有时候这些仪表板模板相当复杂,PHPExcel在尝试输出时会阻塞公式 我花了相当多的时间寻找解决方法,甚至添加了一种禁用计算的方法,试图阻止公式被处理,但无法使其工作。我还尝试禁用计算缓存 @MarkBaker在这个库中做了非常出色的工作,我多次看到他提到这个库不是为修改文件而设计的,但是如果做得非常仔细,它似乎可

我构建了一个报告解决方案,可以将数据导出为Excel。使用PHPExcel,这项工作非常漂亮。但是,我们需要构建仪表板样式的模板表,并在运行时将它们插入到输出中,包括公式。我的问题是,有时候这些仪表板模板相当复杂,PHPExcel在尝试输出时会阻塞公式

我花了相当多的时间寻找解决方法,甚至添加了一种禁用计算的方法,试图阻止公式被处理,但无法使其工作。我还尝试禁用计算缓存

@MarkBaker在这个库中做了非常出色的工作,我多次看到他提到这个库不是为修改文件而设计的,但是如果做得非常仔细,它似乎可以工作

我的问题是,如何让PHPExcel停止尝试计算公式?我希望它像对待任何其他文本值一样对待它们,并让Excel自己处理验证。这可能吗

例如,PHPExcel似乎不喜欢以下公式:

=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,但