diff --git a/Classes/PHPExcel/Calculation.php b/Classes/PHPExcel/Calculation.php index 788ee71..40fcaa3 100644 --- a/Classes/PHPExcel/Calculation.php +++ b/Classes/PHPExcel/Calculation.php @@ -114,6 +114,15 @@ class PHPExcel_Calculation { private static $_calculationCacheEnabled = true; + /** + * Calculation cache expiration time + * + * @access private + * @var float + */ + private static $_calculationCacheExpirationTime = 15; + + /** * List of operators that can be used within formulae * The true/false value indicates whether it is a binary operator or a unary operator @@ -1832,6 +1841,28 @@ class PHPExcel_Calculation { } // function clearCalculationCache() + /** + * Get calculation cache expiration time + * + * @return float + */ + public function getCalculationCacheExpirationTime() { + return self::$_calculationCacheExpirationTime; + } // getCalculationCacheExpirationTime() + + + /** + * Set calculation cache expiration time + * + * @param float $pValue + */ + public function setCalculationCacheExpirationTime($pValue = 15) { + self::$_calculationCacheExpirationTime = $pValue; + } // function setCalculationCacheExpirationTime() + + + + /** * Get the currently defined locale code * @@ -2249,20 +2280,32 @@ class PHPExcel_Calculation { } } // Is calculation cacheing enabled? - if (($cellID !== NULL) && (self::$_calculationCacheEnabled)) { - // Is the value present in calculation cache? - $this->_writeDebug('Testing cache for cell ', $cellID); - if (isset(self::$_calculationCache[$wsTitle][$cellID])) { -// echo 'Value is in cache
'; - $this->_writeDebug('Retrieving value for ', $cellID, ' from cache'); - // Return the cached result - $returnValue = self::$_calculationCache[$wsTitle][$cellID]; -// echo 'Retrieving data value of '.$returnValue.' for '.$cellID.' from cache
'; - if (is_array($returnValue)) { - $returnValue = PHPExcel_Calculation_Functions::flattenArray($returnValue); - return array_shift($returnValue); + if ($cellID !== NULL) { + if (self::$_calculationCacheEnabled) { + // Is the value present in calculation cache? +// echo 'Testing cache value
'; + if (isset(self::$_calculationCache[$wsTitle][$cellID])) { +// echo 'Value is in cache
'; + $this->_writeDebug('Testing cache value for cell '.$cellID); + // Is cache still valid? + if ((microtime(true) - self::$_calculationCache[$wsTitle][$cellID]['time']) < self::$_calculationCacheExpirationTime) { +// echo 'Cache time is still valid
'; + $this->_writeDebug('Retrieving value for '.$cellID.' from cache'); + // Return the cached result + $returnValue = self::$_calculationCache[$wsTitle][$cellID]['data']; +// echo 'Retrieving data value of '.$returnValue.' for '.$cellID.' from cache
'; + if (is_array($returnValue)) { + $returnValue = PHPExcel_Calculation_Functions::flattenArray($returnValue); + return array_shift($returnValue); + } + return $returnValue; + } else { +// echo 'Cache has expired
'; + $this->_writeDebug('Cache value for '.$cellID.' has expired'); + // Clear the cache if it's no longer valid + unset(self::$_calculationCache[$wsTitle][$cellID]); + } } - return $returnValue; } } @@ -2290,8 +2333,11 @@ class PHPExcel_Calculation { array_pop($this->debugLogStack); // Save to calculation cache - if (($cellID !== NULL) && (self::$_calculationCacheEnabled)) { - self::$_calculationCache[$wsTitle][$cellID] = $cellValue; + if ($cellID !== NULL) { + if (self::$_calculationCacheEnabled) { + self::$_calculationCache[$wsTitle][$cellID]['time'] = microtime(true); + self::$_calculationCache[$wsTitle][$cellID]['data'] = $cellValue; + } } // Return the calculated value @@ -2986,9 +3032,9 @@ class PHPExcel_Calculation { // Log what we're doing if ($token == ':') { - $this->_writeDebug('Evaluating Range ', $this->_showValue($operand1Data['reference']), $token, $this->_showValue($operand2Data['reference'])); + $this->_writeDebug('Evaluating Range '.$this->_showValue($operand1Data['reference']).$token.$this->_showValue($operand2Data['reference'])); } else { - $this->_writeDebug('Evaluating ', $this->_showValue($operand1), ' ', $token, ' ', $this->_showValue($operand2)); + $this->_writeDebug('Evaluating '.$this->_showValue($operand1).' '.$token.' '.$this->_showValue($operand2)); } // Process the operation in the appropriate manner @@ -3089,13 +3135,13 @@ class PHPExcel_Calculation { $matrixResult = $matrix->concat($operand2); $result = $matrixResult->getArray(); } catch (PHPExcel_Exception $ex) { - $this->_writeDebug('JAMA Matrix Exception: ', $ex->getMessage()); + $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage()); $result = '#VALUE!'; } } else { $result = '"'.str_replace('""','"',self::_unwrapResult($operand1,'"').self::_unwrapResult($operand2,'"')).'"'; } - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); $stack->push('Value',$result); break; case '|' : // Intersect @@ -3109,7 +3155,7 @@ class PHPExcel_Calculation { } } $cellRef = PHPExcel_Cell::stringFromColumnIndex(min($oCol)).min($oRow).':'.PHPExcel_Cell::stringFromColumnIndex(max($oCol)).max($oRow); - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($cellIntersect)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($cellIntersect)); $stack->push('Value',$cellIntersect,$cellRef); break; } @@ -3121,11 +3167,11 @@ class PHPExcel_Calculation { $arg = $arg['value']; if ($token === '~') { // echo 'Token is a negation operator
'; - $this->_writeDebug('Evaluating Negation of ', $this->_showValue($arg)); + $this->_writeDebug('Evaluating Negation of '.$this->_showValue($arg)); $multiplier = -1; } else { // echo 'Token is a percentile operator
'; - $this->_writeDebug('Evaluating Percentile of ', $this->_showValue($arg)); + $this->_writeDebug('Evaluating Percentile of '.$this->_showValue($arg)); $multiplier = 0.01; } if (is_array($arg)) { @@ -3135,10 +3181,10 @@ class PHPExcel_Calculation { $matrixResult = $matrix1->arrayTimesEquals($multiplier); $result = $matrixResult->getArray(); } catch (PHPExcel_Exception $ex) { - $this->_writeDebug('JAMA Matrix Exception: ', $ex->getMessage()); + $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage()); $result = '#VALUE!'; } - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); $stack->push('Value',$result); } else { $this->_executeNumericBinaryOperation($cellID,$multiplier,$arg,'*','arrayTimesEquals',$stack); @@ -3162,23 +3208,23 @@ class PHPExcel_Calculation { } $matches[2] = trim($matches[2],"\"'"); // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'
'; - $this->_writeDebug('Evaluating Cell Range ', $cellRef, ' in worksheet ', $matches[2]); + $this->_writeDebug('Evaluating Cell Range '.$cellRef.' in worksheet '.$matches[2]); if ($pCellParent !== NULL) { $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false); } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cells ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cells '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue)); // $cellRef = $matches[2].'!'.$cellRef; } else { // echo '$cellRef='.$cellRef.' in current worksheet
'; - $this->_writeDebug('Evaluating Cell Range ', $cellRef, ' in current worksheet'); + $this->_writeDebug('Evaluating Cell Range '.$cellRef.' in current worksheet'); if ($pCellParent !== NULL) { $cellValue = $this->extractCellRange($cellRef, $pCellParent, false); } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cells ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cells '.$cellRef.' is '.$this->_showTypeDetails($cellValue)); } } } else { @@ -3195,7 +3241,7 @@ class PHPExcel_Calculation { return $this->_raiseFormulaError('Unable to access External Workbook'); } // echo '$cellRef='.$cellRef.' in worksheet '.$matches[2].'
'; - $this->_writeDebug('Evaluating Cell ', $cellRef, ' in worksheet ', $matches[2]); + $this->_writeDebug('Evaluating Cell '.$cellRef.' in worksheet '.$matches[2]); if ($pCellParent !== NULL) { if ($pCellParent->getParent()->getSheetByName($matches[2])->cellExists($cellRef)) { $cellValue = $this->extractCellRange($cellRef, $pCellParent->getParent()->getSheetByName($matches[2]), false); @@ -3206,18 +3252,18 @@ class PHPExcel_Calculation { } else { return $this->_raiseFormulaError('Unable to access Cell Reference'); } - $this->_writeDebug('Evaluation Result for cell ', $cellRef, ' in worksheet ', $matches[2], ' is ', $this->_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cell '.$cellRef.' in worksheet '.$matches[2].' is '.$this->_showTypeDetails($cellValue)); // $cellRef = $matches[2].'!'.$cellRef; } else { // echo '$cellRef='.$cellRef.' in current worksheet
'; - $this->_writeDebug('Evaluating Cell ', $cellRef, ' in current worksheet'); + $this->_writeDebug('Evaluating Cell '.$cellRef.' in current worksheet'); if ($pCellParent->cellExists($cellRef)) { $cellValue = $this->extractCellRange($cellRef, $pCellParent, false); $pCell->attach($pCellParent); } else { $cellValue = null; } - $this->_writeDebug('Evaluation Result for cell ', $cellRef, ' is ', $this->_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for cell '.$cellRef.' is '.$this->_showTypeDetails($cellValue)); } } } @@ -3230,7 +3276,7 @@ class PHPExcel_Calculation { $argCount = $stack->pop(); $argCount = $argCount['value']; if ($functionName != 'MKMATRIX') { - $this->_writeDebug('Evaluating Function ', self::_localeFunc($functionName), '() with ', (($argCount == 0) ? 'no' : $argCount), ' argument', (($argCount == 1) ? '' : 's')); + $this->_writeDebug('Evaluating Function '.self::_localeFunc($functionName).'() with '.(($argCount == 0) ? 'no' : $argCount).' argument'.(($argCount == 1) ? '' : 's')); } if ((isset(self::$_PHPExcelFunctions[$functionName])) || (isset(self::$_controlFunctions[$functionName]))) { // function if (isset(self::$_PHPExcelFunctions[$functionName])) { @@ -3275,28 +3321,28 @@ class PHPExcel_Calculation { if ($functionName != 'MKMATRIX') { if ($this->writeDebugLog) { krsort($argArrayVals); - $this->_writeDebug('Evaluating ', self::_localeFunc($functionName), '( '.implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)).' )'); + $this->_writeDebug('Evaluating '. self::_localeFunc($functionName).'( '.implode(self::$_localeArgumentSeparator.' ',PHPExcel_Calculation_Functions::flattenArray($argArrayVals)).' )'); } } // Process each argument in turn, building the return value as an array // if (($argCount == 1) && (is_array($args[1])) && ($functionName != 'MKMATRIX')) { // $operand1 = $args[1]; -// $this->_writeDebug('Argument is a matrix: ', $this->_showValue($operand1)); +// $this->_writeDebug('Argument is a matrix: '.$this->_showValue($operand1)); // $result = array(); // $row = 0; // foreach($operand1 as $args) { // if (is_array($args)) { // foreach($args as $arg) { -// $this->_writeDebug('Evaluating ', self::_localeFunc($functionName), '( '.$this->_showValue($arg), ' )'); +// $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($arg).' )'); // $r = call_user_func_array($functionCall,$arg); -// $this->_writeDebug('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); +// $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r)); // $result[$row][] = $r; // } // ++$row; // } else { -// $this->_writeDebug('Evaluating ', self::_localeFunc($functionName), '( '.$this->_showValue($args), ' )'); +// $this->_writeDebug('Evaluating '.self::_localeFunc($functionName).'( '.$this->_showValue($args).' )'); // $r = call_user_func_array($functionCall,$args); -// $this->_writeDebug('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($r)); +// $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($r)); // $result[] = $r; // } // } @@ -3316,7 +3362,7 @@ class PHPExcel_Calculation { } // } if ($functionName != 'MKMATRIX') { - $this->_writeDebug('Evaluation Result for ', self::_localeFunc($functionName), '() function call is ', $this->_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result for '.self::_localeFunc($functionName).'() function call is '.$this->_showTypeDetails($result)); } $stack->push('Value',self::_wrapResult($result)); } @@ -3327,7 +3373,7 @@ class PHPExcel_Calculation { $excelConstant = strtoupper($token); // echo 'Token is a PHPExcel constant: '.$excelConstant.'
'; $stack->push('Constant Value',self::$_ExcelConstants[$excelConstant]); - $this->_writeDebug('Evaluating Constant ', $excelConstant, ' as ', $this->_showTypeDetails(self::$_ExcelConstants[$excelConstant])); + $this->_writeDebug('Evaluating Constant '.$excelConstant.' as '.$this->_showTypeDetails(self::$_ExcelConstants[$excelConstant])); } elseif ((is_numeric($token)) || ($token === NULL) || (is_bool($token)) || ($token == '') || ($token{0} == '"') || ($token{0} == '#')) { // echo 'Token is a number, boolean, string, null or an Excel error
'; $stack->push('Value',$token); @@ -3336,10 +3382,10 @@ class PHPExcel_Calculation { // echo 'Token is a named range
'; $namedRange = $matches[6]; // echo 'Named Range is '.$namedRange.'
'; - $this->_writeDebug('Evaluating Named Range ', $namedRange); + $this->_writeDebug('Evaluating Named Range '.$namedRange); $cellValue = $this->extractNamedRange($namedRange, ((null !== $pCell) ? $pCellParent : null), false); $pCell->attach($pCellParent); - $this->_writeDebug('Evaluation Result for named range ', $namedRange, ' is ', $this->_showTypeDetails($cellValue)); + $this->_writeDebug('Evaluation Result for named range '.$namedRange.' is '.$this->_showTypeDetails($cellValue)); $stack->push('Named Range',$cellValue,$namedRange); } else { return $this->_raiseFormulaError("undefined variable '$token'"); @@ -3369,12 +3415,12 @@ class PHPExcel_Calculation { // If not a numeric, test to see if the value is an Excel error, and so can't be used in normal binary operations if ($operand > '' && $operand{0} == '#') { $stack->push('Value', $operand); - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($operand)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($operand)); return false; } elseif (!PHPExcel_Shared_String::convertToNumberIfFraction($operand)) { // If not a numeric or a fraction, then it's a text string, and so can't be used in mathematical binary operations $stack->push('Value', '#VALUE!'); - $this->_writeDebug('Evaluation Result is a ', $this->_showTypeDetails('#VALUE!')); + $this->_writeDebug('Evaluation Result is a '.$this->_showTypeDetails('#VALUE!')); return false; } } @@ -3391,14 +3437,14 @@ class PHPExcel_Calculation { $result = array(); if ((is_array($operand1)) && (!is_array($operand2))) { foreach($operand1 as $x => $operandData) { - $this->_writeDebug('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2)); + $this->_writeDebug('Evaluating Comparison '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2)); $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2,$operation,$stack); $r = $stack->pop(); $result[$x] = $r['value']; } } elseif ((!is_array($operand1)) && (is_array($operand2))) { foreach($operand2 as $x => $operandData) { - $this->_writeDebug('Evaluating Comparison ', $this->_showValue($operand1), ' ', $operation, ' ', $this->_showValue($operandData)); + $this->_writeDebug('Evaluating Comparison '.$this->_showValue($operand1).' '.$operation.' '.$this->_showValue($operandData)); $this->_executeBinaryComparisonOperation($cellID,$operand1,$operandData,$operation,$stack); $r = $stack->pop(); $result[$x] = $r['value']; @@ -3406,14 +3452,14 @@ class PHPExcel_Calculation { } else { if (!$recursingArrays) { self::_checkMatrixOperands($operand1,$operand2,2); } foreach($operand1 as $x => $operandData) { - $this->_writeDebug('Evaluating Comparison ', $this->_showValue($operandData), ' ', $operation, ' ', $this->_showValue($operand2[$x])); + $this->_writeDebug('Evaluating Comparison '.$this->_showValue($operandData).' '.$operation.' '.$this->_showValue($operand2[$x])); $this->_executeBinaryComparisonOperation($cellID,$operandData,$operand2[$x],$operation,$stack,true); $r = $stack->pop(); $result[$x] = $r['value']; } } // Log the result details - $this->_writeDebug('Comparison Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_writeDebug('Comparison Evaluation Result is '.$this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Array',$result); return true; @@ -3452,7 +3498,7 @@ class PHPExcel_Calculation { } // Log the result details - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Value',$result); return true; @@ -3490,7 +3536,7 @@ class PHPExcel_Calculation { $matrixResult = $matrix->$matrixFunction($operand2); $result = $matrixResult->getArray(); } catch (PHPExcel_Exception $ex) { - $this->_writeDebug('JAMA Matrix Exception: ', $ex->getMessage()); + $this->_writeDebug('JAMA Matrix Exception: '.$ex->getMessage()); $result = '#VALUE!'; } } else { @@ -3517,7 +3563,7 @@ class PHPExcel_Calculation { if ($operand2 == 0) { // Trap for Divide by Zero error $stack->push('Value','#DIV/0!'); - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails('#DIV/0!')); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails('#DIV/0!')); return false; } else { $result = $operand1/$operand2; @@ -3532,21 +3578,20 @@ class PHPExcel_Calculation { } // Log the result details - $this->_writeDebug('Evaluation Result is ', $this->_showTypeDetails($result)); + $this->_writeDebug('Evaluation Result is '.$this->_showTypeDetails($result)); // And push the result onto the stack $stack->push('Value',$result); return true; } // function _executeNumericBinaryOperation() - private function _writeDebug() { + private function _writeDebug($message) { // Only write the debug log if logging is enabled if ($this->writeDebugLog) { - $message = implode('', func_get_args()); if ($this->echoDebugLog) { - echo implode(' -> ', $this->debugLogStack) . ' -> ' . $message , PHP_EOL; + echo implode(' -> ',$this->debugLogStack).' -> '.$message,'
'; } - $this->debugLog[] = implode(' -> ', $this->debugLogStack) . ' -> ' . $message; + $this->debugLog[] = implode(' -> ',$this->debugLogStack).' -> '.$message; } } // function _writeDebug() diff --git a/Classes/PHPExcel/Cell.php b/Classes/PHPExcel/Cell.php index e0e0f92..2e9cd32 100644 --- a/Classes/PHPExcel/Cell.php +++ b/Classes/PHPExcel/Cell.php @@ -133,10 +133,10 @@ class PHPExcel_Cell * @param PHPExcel_Worksheet $pSheet * @throws PHPExcel_Exception */ - public function __construct($pColumn = 'A', $pRow = 1, $pValue = NULL, $pDataType = NULL, PHPExcel_Worksheet $pSheet = NULL) + public function __construct($pCoordinate = 'A1', $pValue = NULL, $pDataType = NULL, PHPExcel_Worksheet $pSheet = NULL) { // Initialise cell coordinate - $this->_coordinate = strtoupper($pColumn) . $pRow; + $this->_coordinate = strtoupper($pCoordinate); // Initialise cell value $this->_value = $pValue; diff --git a/Classes/PHPExcel/Style/NumberFormat.php b/Classes/PHPExcel/Style/NumberFormat.php index 4b899f9..ed6ace9 100644 --- a/Classes/PHPExcel/Style/NumberFormat.php +++ b/Classes/PHPExcel/Style/NumberFormat.php @@ -390,8 +390,11 @@ class PHPExcel_Style_NumberFormat extends PHPExcel_Style_Supervisor implements P 'mmmm' => 'F', // short month name 'mmm' => 'M', - // mm is minutes if time or month w/leading zero + // mm is minutes if time, but can also be month w/leading zero + // so we try to identify times be the inclusion of a : separator in the mask + // It isn't perfect, but the best way I know how ':mm' => ':i', + 'mm:' => 'i:', // month leading zero 'mm' => 'm', // month no leading zero diff --git a/Classes/PHPExcel/Worksheet.php b/Classes/PHPExcel/Worksheet.php index d017327..ec201ab 100644 --- a/Classes/PHPExcel/Worksheet.php +++ b/Classes/PHPExcel/Worksheet.php @@ -1118,7 +1118,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable // Coordinates $aCoordinates = PHPExcel_Cell::coordinateFromString($pCoordinate); - $cell = $this->_cellCollection->addCacheData($pCoordinate,new PHPExcel_Cell($aCoordinates[0], $aCoordinates[1], null, PHPExcel_Cell_DataType::TYPE_NULL, $this)); + $cell = $this->_cellCollection->addCacheData($pCoordinate,new PHPExcel_Cell($pCoordinate, NULL, PHPExcel_Cell_DataType::TYPE_NULL, $this)); $this->_cellCollectionIsSorted = false; if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < PHPExcel_Cell::columnIndexFromString($aCoordinates[0])) @@ -1158,7 +1158,7 @@ class PHPExcel_Worksheet implements PHPExcel_IComparable $coordinate = $columnLetter . $pRow; if (!$this->_cellCollection->isDataSet($coordinate)) { - $cell = $this->_cellCollection->addCacheData($coordinate, new PHPExcel_Cell($columnLetter, $pRow, null, PHPExcel_Cell_DataType::TYPE_NULL, $this)); + $cell = $this->_cellCollection->addCacheData($coordinate, new PHPExcel_Cell($coordinate, NULL, PHPExcel_Cell_DataType::TYPE_NULL, $this)); $this->_cellCollectionIsSorted = false; if (PHPExcel_Cell::columnIndexFromString($this->_cachedHighestColumn) < $pColumn)