简体   繁体   中英

Computing output of an excel formula with PHPExcel

I have an excel spreadsheet that contains a formula. I am wondering what the best way would be to use the formula and compute outputs based on a given input.

My first inclination would be to load the spread into PHPExcel object and set the values of each cell involved in the formula to a given input and then finally read the result.

EDIT: I have attempted getting the computed value of the formula with:

getCalculatedValue()

I run this method on the cell that should contain the computed value of the spread 'as is' but it's spitting out undefined offset errors for Excel5.php and MathTrig.php and an incorrect result:

Notice: Undefined offset: 437 in /Applications/MAMP/htdocs/bang/Classes/PHPExcel/Reader/Excel5.php on line 5679

Notice: Undefined offset: 438 in /Applications/MAMP/htdocs/bang/Classes/PHPExcel/Reader/Excel5.php on line 5679

Notice: Undefined offset: 439 in /Applications/MAMP/htdocs/bang/Classes/PHPExcel/Reader/Excel5.php on line 5679

Notice: Undefined offset: 9 in /Applications/MAMP/htdocs/bang/Classes/PHPExcel/Calculation/MathTrig.php on line 1171

Formula and stack trace of it from the debug in PHPExcel is:

Value is =SUMIF(Sheet3!A1:H530,"=212410000",Sheet3!H1:H530)
Parser Stack :-
Array
(
    [0] => Array
        (
            [type] => Cell Reference
            [value] => Sheet3!A1
            [reference] => Sheet3!A1
        )

    [1] => Array
        (
            [type] => Cell Reference
            [value] => Sheet3!H530
            [reference] => Sheet3!H530
        )

    [2] => Array
        (
            [type] => Binary Operator
            [value] => :
            [reference] => 
        )

    [3] => Array
        (
            [type] => Value
            [value] => "=212410000"
            [reference] => 
        )

    [4] => Array
        (
            [type] => Cell Reference
            [value] => Sheet3!H1
            [reference] => Sheet3!H1
        )

    [5] => Array
        (
            [type] => Cell Reference
            [value] => Sheet3!H530
            [reference] => Sheet3!H530
        )

    [6] => Array
        (
            [type] => Binary Operator
            [value] => :
            [reference] => 
        )

    [7] => Array
        (
            [type] => Operand Count for Function SUMIF()
            [value] => 3
            [reference] => 
        )

    [8] => Array
        (
            [type] => Function
            [value] => SUMIF(
            [reference] => 
        )

)

The line from Excel5.php that is triggering the error is:

    // offset: 1; size: 2; one-based index to definedname record
                $definedNameIndex = self::_GetInt2d($formulaData, 1) - 1;
                // offset: 2; size: 2; not used
                $data = $this->_definedname[$definedNameIndex]['name']; // errors here

You can run the calculation engine in debug mode to get a lot more detail about what it is doing to help diagnose such problems:

$cell = 'C3';
//  enable debugging
PHPExcel_Calculation::getInstance()->writeDebugLog = true;

$sheet = $objPHPExcel->getActiveSheet();
$formulaValue = $sheet->getCell($cell)->getValue();
echo '<b>'.$cell.' Value is </b>'.$formulaValue."<br />\n";

$calculate = false;
try {
    $tokens = PHPExcel_Calculation::getInstance()->parseFormula($formulaValue,$sheet->getCell($cell));
    echo '<b>Parser Stack :-</b><pre>';
    print_r($tokens);
    echo '</pre>';
    $calculate = true;
} catch (Exception $e) {
    echo "PARSER ERROR: ".$e->getMessage()."<br />\n";

    echo '<b>Parser Stack :-</b><pre>';
    print_r($tokens);
    echo '</pre>';
}

if ($calculate) {
    //  calculate
    try {
        $cellValue = $sheet->getCell($cell)->getCalculatedValue();
    } catch (Exception $e) {
        echo "CALCULATION ENGINE ERROR: ".$e->getMessage()."<br />\n";

        echo '<h3>Evaluation Log:</h3><pre>';
        print_r(PHPExcel_Calculation::getInstance()->debugLog);
        echo '</pre>';
    }
}

EDIT

No guarantees, because I'll need to test it a bit more, but modify line 1171 in the Classes/PHPExcel/Calculation/MathTrig.php file

This line currently reads

$returnValue += $sumArgs[$key];

change it to

$returnValue += $sumArgs[$key % count($sumArgs)];

It's assuming that the number of cells in the criteria range (Sheet3!A1:H530 in your case) matches the number of cells in the summed range (Sheet3!H1:H530) which clearly isn't the case when the criteria references 8 columns and 530 rows while the summed range only references 530 rows in a single column.

EDIT #2

While above Edit suggestion will fix the error, it'll return the wrong result. If you specify A1:H530 as your criteria, but only H1:H530 as your summed values in MS Excel, it only tests the first column (to match the potential number of summed results) and ignores columns BH in the criteria.

A quick fix might be to modify lines 1161 which read:

if (empty($sumArgs)) {
    $sumArgs = $aArgs;
}

to

if (empty($sumArgs)) {
    $sumArgs = $aArgs;
} elseif (count($aArgs) > count($sumArgs)) {
    $aArgs = array_slice($aArgs,0,count($sumArgs));
}

and revert line 1171 (now 1173) back to

$returnValue += $sumArgs[$key];

I still need to check if flattenArray orders the cells correctly, but that's going to be a closer fix

EDIT #3

It'll take longer to fix PHPExcel's calc engine to handle mismatched criteria/summed arrays (my fix above won't work because PHPExcel flattens by row, while this need sto be flattened by column) - but as a temporary fix change your formula to use just one column in the criteria range

if you do toArray you can:

$objWorksheet = $objPHPExcel->setActiveSheetIndex($index);
$arrExcelObject = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true);

The toArray function is documented in the code:

public function toArray($nullValue = null, $calculateFormulas = true, $formatData = true, $returnColumnRef = false)

So second arg to indicate you want to calc from the formula, by default is set to true.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM