@ -0,0 +1,3 @@ | |||
/Build export-ignore | |||
/unitTests export-ignore | |||
README.md export-ignore |
@ -0,0 +1,9 @@ | |||
build/PHPExcel.phar | |||
unitTests/codeCoverage | |||
analysis | |||
## IDE support | |||
*.buildpath | |||
*.project | |||
/.settings | |||
/.idea |
@ -0,0 +1,29 @@ | |||
language: php | |||
php: | |||
- 5.4 | |||
- 5.5 | |||
- 5.6 | |||
- 7.0 | |||
- hhvm | |||
matrix: | |||
allow_failures: | |||
- php: hhvm | |||
before_script: | |||
## Packages | |||
- sudo apt-get -qq update > /dev/null | |||
## Composer | |||
- composer self-update | |||
- composer install --prefer-source --dev | |||
- phpenv global "$TRAVIS_PHP_VERSION" | |||
script: | |||
## PHP_CodeSniffer | |||
- ./vendor/bin/phpcs --report-width=200 --report-summary --report-full Classes/ unitTests/ --standard=PSR2 -n | |||
## PHPUnit | |||
- phpunit -c ./unitTests/ | |||
notifications: | |||
email: false |
@ -0,0 +1,289 @@ | |||
<?php | |||
/** PHPExcel root directory */ | |||
if (!defined('PHPEXCEL_ROOT')) { | |||
/** | |||
* @ignore | |||
*/ | |||
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../'); | |||
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); | |||
} | |||
/** | |||
* PHPExcel_IOFactory | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_IOFactory | |||
{ | |||
/** | |||
* Search locations | |||
* | |||
* @var array | |||
* @access private | |||
* @static | |||
*/ | |||
private static $searchLocations = array( | |||
array( 'type' => 'IWriter', 'path' => 'PHPExcel/Writer/{0}.php', 'class' => 'PHPExcel_Writer_{0}' ), | |||
array( 'type' => 'IReader', 'path' => 'PHPExcel/Reader/{0}.php', 'class' => 'PHPExcel_Reader_{0}' ) | |||
); | |||
/** | |||
* Autoresolve classes | |||
* | |||
* @var array | |||
* @access private | |||
* @static | |||
*/ | |||
private static $autoResolveClasses = array( | |||
'Excel2007', | |||
'Excel5', | |||
'Excel2003XML', | |||
'OOCalc', | |||
'SYLK', | |||
'Gnumeric', | |||
'HTML', | |||
'CSV', | |||
); | |||
/** | |||
* Private constructor for PHPExcel_IOFactory | |||
*/ | |||
private function __construct() | |||
{ | |||
} | |||
/** | |||
* Get search locations | |||
* | |||
* @static | |||
* @access public | |||
* @return array | |||
*/ | |||
public static function getSearchLocations() | |||
{ | |||
return self::$searchLocations; | |||
} | |||
/** | |||
* Set search locations | |||
* | |||
* @static | |||
* @access public | |||
* @param array $value | |||
* @throws PHPExcel_Reader_Exception | |||
*/ | |||
public static function setSearchLocations($value) | |||
{ | |||
if (is_array($value)) { | |||
self::$searchLocations = $value; | |||
} else { | |||
throw new PHPExcel_Reader_Exception('Invalid parameter passed.'); | |||
} | |||
} | |||
/** | |||
* Add search location | |||
* | |||
* @static | |||
* @access public | |||
* @param string $type Example: IWriter | |||
* @param string $location Example: PHPExcel/Writer/{0}.php | |||
* @param string $classname Example: PHPExcel_Writer_{0} | |||
*/ | |||
public static function addSearchLocation($type = '', $location = '', $classname = '') | |||
{ | |||
self::$searchLocations[] = array( 'type' => $type, 'path' => $location, 'class' => $classname ); | |||
} | |||
/** | |||
* Create PHPExcel_Writer_IWriter | |||
* | |||
* @static | |||
* @access public | |||
* @param PHPExcel $phpExcel | |||
* @param string $writerType Example: Excel2007 | |||
* @return PHPExcel_Writer_IWriter | |||
* @throws PHPExcel_Reader_Exception | |||
*/ | |||
public static function createWriter(PHPExcel $phpExcel, $writerType = '') | |||
{ | |||
// Search type | |||
$searchType = 'IWriter'; | |||
// Include class | |||
foreach (self::$searchLocations as $searchLocation) { | |||
if ($searchLocation['type'] == $searchType) { | |||
$className = str_replace('{0}', $writerType, $searchLocation['class']); | |||
$instance = new $className($phpExcel); | |||
if ($instance !== null) { | |||
return $instance; | |||
} | |||
} | |||
} | |||
// Nothing found... | |||
throw new PHPExcel_Reader_Exception("No $searchType found for type $writerType"); | |||
} | |||
/** | |||
* Create PHPExcel_Reader_IReader | |||
* | |||
* @static | |||
* @access public | |||
* @param string $readerType Example: Excel2007 | |||
* @return PHPExcel_Reader_IReader | |||
* @throws PHPExcel_Reader_Exception | |||
*/ | |||
public static function createReader($readerType = '') | |||
{ | |||
// Search type | |||
$searchType = 'IReader'; | |||
// Include class | |||
foreach (self::$searchLocations as $searchLocation) { | |||
if ($searchLocation['type'] == $searchType) { | |||
$className = str_replace('{0}', $readerType, $searchLocation['class']); | |||
$instance = new $className(); | |||
if ($instance !== null) { | |||
return $instance; | |||
} | |||
} | |||
} | |||
// Nothing found... | |||
throw new PHPExcel_Reader_Exception("No $searchType found for type $readerType"); | |||
} | |||
/** | |||
* Loads PHPExcel from file using automatic PHPExcel_Reader_IReader resolution | |||
* | |||
* @static | |||
* @access public | |||
* @param string $pFilename The name of the spreadsheet file | |||
* @return PHPExcel | |||
* @throws PHPExcel_Reader_Exception | |||
*/ | |||
public static function load($pFilename) | |||
{ | |||
$reader = self::createReaderForFile($pFilename); | |||
return $reader->load($pFilename); | |||
} | |||
/** | |||
* Identify file type using automatic PHPExcel_Reader_IReader resolution | |||
* | |||
* @static | |||
* @access public | |||
* @param string $pFilename The name of the spreadsheet file to identify | |||
* @return string | |||
* @throws PHPExcel_Reader_Exception | |||
*/ | |||
public static function identify($pFilename) | |||
{ | |||
$reader = self::createReaderForFile($pFilename); | |||
$className = get_class($reader); | |||
$classType = explode('_', $className); | |||
unset($reader); | |||
return array_pop($classType); | |||
} | |||
/** | |||
* Create PHPExcel_Reader_IReader for file using automatic PHPExcel_Reader_IReader resolution | |||
* | |||
* @static | |||
* @access public | |||
* @param string $pFilename The name of the spreadsheet file | |||
* @return PHPExcel_Reader_IReader | |||
* @throws PHPExcel_Reader_Exception | |||
*/ | |||
public static function createReaderForFile($pFilename) | |||
{ | |||
// First, lucky guess by inspecting file extension | |||
$pathinfo = pathinfo($pFilename); | |||
$extensionType = null; | |||
if (isset($pathinfo['extension'])) { | |||
switch (strtolower($pathinfo['extension'])) { | |||
case 'xlsx': // Excel (OfficeOpenXML) Spreadsheet | |||
case 'xlsm': // Excel (OfficeOpenXML) Macro Spreadsheet (macros will be discarded) | |||
case 'xltx': // Excel (OfficeOpenXML) Template | |||
case 'xltm': // Excel (OfficeOpenXML) Macro Template (macros will be discarded) | |||
$extensionType = 'Excel2007'; | |||
break; | |||
case 'xls': // Excel (BIFF) Spreadsheet | |||
case 'xlt': // Excel (BIFF) Template | |||
$extensionType = 'Excel5'; | |||
break; | |||
case 'ods': // Open/Libre Offic Calc | |||
case 'ots': // Open/Libre Offic Calc Template | |||
$extensionType = 'OOCalc'; | |||
break; | |||
case 'slk': | |||
$extensionType = 'SYLK'; | |||
break; | |||
case 'xml': // Excel 2003 SpreadSheetML | |||
$extensionType = 'Excel2003XML'; | |||
break; | |||
case 'gnumeric': | |||
$extensionType = 'Gnumeric'; | |||
break; | |||
case 'htm': | |||
case 'html': | |||
$extensionType = 'HTML'; | |||
break; | |||
case 'csv': | |||
// Do nothing | |||
// We must not try to use CSV reader since it loads | |||
// all files including Excel files etc. | |||
break; | |||
default: | |||
break; | |||
} | |||
if ($extensionType !== null) { | |||
$reader = self::createReader($extensionType); | |||
// Let's see if we are lucky | |||
if (isset($reader) && $reader->canRead($pFilename)) { | |||
return $reader; | |||
} | |||
} | |||
} | |||
// If we reach here then "lucky guess" didn't give any result | |||
// Try walking through all the options in self::$autoResolveClasses | |||
foreach (self::$autoResolveClasses as $autoResolveClass) { | |||
// Ignore our original guess, we know that won't work | |||
if ($autoResolveClass !== $extensionType) { | |||
$reader = self::createReader($autoResolveClass); | |||
if ($reader->canRead($pFilename)) { | |||
return $reader; | |||
} | |||
} | |||
} | |||
throw new PHPExcel_Reader_Exception('Unable to identify a reader for this file'); | |||
} | |||
} |
@ -0,0 +1,81 @@ | |||
<?php | |||
PHPExcel_Autoloader::register(); | |||
// As we always try to run the autoloader before anything else, we can use it to do a few | |||
// simple checks and initialisations | |||
//PHPExcel_Shared_ZipStreamWrapper::register(); | |||
// check mbstring.func_overload | |||
if (ini_get('mbstring.func_overload') & 2) { | |||
throw new PHPExcel_Exception('Multibyte function overloading in PHP must be disabled for string functions (2).'); | |||
} | |||
PHPExcel_Shared_String::buildCharacterSets(); | |||
/** | |||
* PHPExcel | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Autoloader | |||
{ | |||
/** | |||
* Register the Autoloader with SPL | |||
* | |||
*/ | |||
public static function register() | |||
{ | |||
if (function_exists('__autoload')) { | |||
// Register any existing autoloader function with SPL, so we don't get any clashes | |||
spl_autoload_register('__autoload'); | |||
} | |||
// Register ourselves with SPL | |||
if (version_compare(PHP_VERSION, '5.3.0') >= 0) { | |||
return spl_autoload_register(array('PHPExcel_Autoloader', 'load'), true, true); | |||
} else { | |||
return spl_autoload_register(array('PHPExcel_Autoloader', 'load')); | |||
} | |||
} | |||
/** | |||
* Autoload a class identified by name | |||
* | |||
* @param string $pClassName Name of the object to load | |||
*/ | |||
public static function load($pClassName) | |||
{ | |||
if ((class_exists($pClassName, false)) || (strpos($pClassName, 'PHPExcel') !== 0)) { | |||
// Either already loaded, or not a PHPExcel class request | |||
return false; | |||
} | |||
$pClassFilePath = PHPEXCEL_ROOT . | |||
str_replace('_', DIRECTORY_SEPARATOR, $pClassName) . | |||
'.php'; | |||
if ((file_exists($pClassFilePath) === false) || (is_readable($pClassFilePath) === false)) { | |||
// Can't load | |||
return false; | |||
} | |||
require($pClassFilePath); | |||
} | |||
} |
@ -0,0 +1,290 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_APC | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Prefix used to uniquely identify cache data for this worksheet | |||
* | |||
* @access private | |||
* @var string | |||
*/ | |||
private $cachePrefix = null; | |||
/** | |||
* Cache timeout | |||
* | |||
* @access private | |||
* @var integer | |||
*/ | |||
private $cacheTime = 600; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @access private | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
if (!apc_store( | |||
$this->cachePrefix . $this->currentObjectID . '.cache', | |||
serialize($this->currentObject), | |||
$this->cacheTime | |||
)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception('Failed to store cell ' . $this->currentObjectID . ' in APC'); | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @access public | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->cellCache[$pCoord] = true; | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell? | |||
* | |||
* @access public | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @throws PHPExcel_Exception | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord) | |||
{ | |||
// Check if the requested entry is the current object, or exists in the cache | |||
if (parent::isDataSet($pCoord)) { | |||
if ($this->currentObjectID == $pCoord) { | |||
return true; | |||
} | |||
// Check if the requested entry still exists in apc | |||
$success = apc_fetch($this->cachePrefix.$pCoord.'.cache'); | |||
if ($success === false) { | |||
// Entry no longer exists in APC, so clear it from the cache array | |||
parent::deleteCacheData($pCoord); | |||
throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache'); | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @access public | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (parent::isDataSet($pCoord)) { | |||
$obj = apc_fetch($this->cachePrefix . $pCoord . '.cache'); | |||
if ($obj === false) { | |||
// Entry no longer exists in APC, so clear it from the cache array | |||
parent::deleteCacheData($pCoord); | |||
throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache'); | |||
} | |||
} else { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = unserialize($obj); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @access public | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord) | |||
{ | |||
// Delete the entry from APC | |||
apc_delete($this->cachePrefix.$pCoord.'.cache'); | |||
// Delete the entry from our cell address array | |||
parent::deleteCacheData($pCoord); | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @access public | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @throws PHPExcel_Exception | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::copyCellCollection($parent); | |||
// Get a new id for the new file name | |||
$baseUnique = $this->getUniqueID(); | |||
$newCachePrefix = substr(md5($baseUnique), 0, 8) . '.'; | |||
$cacheList = $this->getCellList(); | |||
foreach ($cacheList as $cellID) { | |||
if ($cellID != $this->currentObjectID) { | |||
$obj = apc_fetch($this->cachePrefix . $cellID . '.cache'); | |||
if ($obj === false) { | |||
// Entry no longer exists in APC, so clear it from the cache array | |||
parent::deleteCacheData($cellID); | |||
throw new PHPExcel_Exception('Cell entry ' . $cellID . ' no longer exists in APC'); | |||
} | |||
if (!apc_store($newCachePrefix . $cellID . '.cache', $obj, $this->cacheTime)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception('Failed to store cell ' . $cellID . ' in APC'); | |||
} | |||
} | |||
} | |||
$this->cachePrefix = $newCachePrefix; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if ($this->currentObject !== null) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
// Flush the APC cache | |||
$this->__destruct(); | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
* @param array of mixed $arguments Additional initialisation arguments | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent, $arguments) | |||
{ | |||
$cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600; | |||
if ($this->cachePrefix === null) { | |||
$baseUnique = $this->getUniqueID(); | |||
$this->cachePrefix = substr(md5($baseUnique), 0, 8) . '.'; | |||
$this->cacheTime = $cacheTime; | |||
parent::__construct($parent); | |||
} | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
$cacheList = $this->getCellList(); | |||
foreach ($cacheList as $cellID) { | |||
apc_delete($this->cachePrefix . $cellID . '.cache'); | |||
} | |||
} | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
if (!function_exists('apc_store')) { | |||
return false; | |||
} | |||
if (apc_sma_info() === false) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,368 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_CacheBase | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
abstract class PHPExcel_CachedObjectStorage_CacheBase | |||
{ | |||
/** | |||
* Parent worksheet | |||
* | |||
* @var PHPExcel_Worksheet | |||
*/ | |||
protected $parent; | |||
/** | |||
* The currently active Cell | |||
* | |||
* @var PHPExcel_Cell | |||
*/ | |||
protected $currentObject = null; | |||
/** | |||
* Coordinate address of the currently active Cell | |||
* | |||
* @var string | |||
*/ | |||
protected $currentObjectID = null; | |||
/** | |||
* Flag indicating whether the currently active Cell requires saving | |||
* | |||
* @var boolean | |||
*/ | |||
protected $currentCellIsDirty = true; | |||
/** | |||
* An array of cells or cell pointers for the worksheet cells held in this cache, | |||
* and indexed by their coordinate address within the worksheet | |||
* | |||
* @var array of mixed | |||
*/ | |||
protected $cellCache = array(); | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent) | |||
{ | |||
// Set our parent worksheet. | |||
// This is maintained within the cache controller to facilitate re-attaching it to PHPExcel_Cell objects when | |||
// they are woken from a serialized state | |||
$this->parent = $parent; | |||
} | |||
/** | |||
* Return the parent worksheet for this cell collection | |||
* | |||
* @return PHPExcel_Worksheet | |||
*/ | |||
public function getParent() | |||
{ | |||
return $this->parent; | |||
} | |||
/** | |||
* Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell? | |||
* | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return true; | |||
} | |||
// Check if the requested entry exists in the cache | |||
return isset($this->cellCache[$pCoord]); | |||
} | |||
/** | |||
* Move a cell object from one address to another | |||
* | |||
* @param string $fromAddress Current address of the cell to move | |||
* @param string $toAddress Destination address of the cell to move | |||
* @return boolean | |||
*/ | |||
public function moveCell($fromAddress, $toAddress) | |||
{ | |||
if ($fromAddress === $this->currentObjectID) { | |||
$this->currentObjectID = $toAddress; | |||
} | |||
$this->currentCellIsDirty = true; | |||
if (isset($this->cellCache[$fromAddress])) { | |||
$this->cellCache[$toAddress] = &$this->cellCache[$fromAddress]; | |||
unset($this->cellCache[$fromAddress]); | |||
} | |||
return true; | |||
} | |||
/** | |||
* Add or Update a cell in cache | |||
* | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function updateCacheData(PHPExcel_Cell $cell) | |||
{ | |||
return $this->addCacheData($cell->getCoordinate(), $cell); | |||
} | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID && !is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
if (is_object($this->cellCache[$pCoord])) { | |||
$this->cellCache[$pCoord]->detach(); | |||
unset($this->cellCache[$pCoord]); | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
return array_keys($this->cellCache); | |||
} | |||
/** | |||
* Sort the list of all cell addresses currently held in cache by row and column | |||
* | |||
* @return string[] | |||
*/ | |||
public function getSortedCellList() | |||
{ | |||
$sortKeys = array(); | |||
foreach ($this->getCellList() as $coord) { | |||
sscanf($coord, '%[A-Z]%d', $column, $row); | |||
$sortKeys[sprintf('%09d%3s', $row, $column)] = $coord; | |||
} | |||
ksort($sortKeys); | |||
return array_values($sortKeys); | |||
} | |||
/** | |||
* Get highest worksheet column and highest row that have cell records | |||
* | |||
* @return array Highest column name and highest row number | |||
*/ | |||
public function getHighestRowAndColumn() | |||
{ | |||
// Lookup highest column and highest row | |||
$col = array('A' => '1A'); | |||
$row = array(1); | |||
foreach ($this->getCellList() as $coord) { | |||
sscanf($coord, '%[A-Z]%d', $c, $r); | |||
$row[$r] = $r; | |||
$col[$c] = strlen($c).$c; | |||
} | |||
if (!empty($row)) { | |||
// Determine highest column and row | |||
$highestRow = max($row); | |||
$highestColumn = substr(max($col), 1); | |||
} | |||
return array( | |||
'row' => $highestRow, | |||
'column' => $highestColumn | |||
); | |||
} | |||
/** | |||
* Return the cell address of the currently active cell object | |||
* | |||
* @return string | |||
*/ | |||
public function getCurrentAddress() | |||
{ | |||
return $this->currentObjectID; | |||
} | |||
/** | |||
* Return the column address of the currently active cell object | |||
* | |||
* @return string | |||
*/ | |||
public function getCurrentColumn() | |||
{ | |||
sscanf($this->currentObjectID, '%[A-Z]%d', $column, $row); | |||
return $column; | |||
} | |||
/** | |||
* Return the row address of the currently active cell object | |||
* | |||
* @return integer | |||
*/ | |||
public function getCurrentRow() | |||
{ | |||
sscanf($this->currentObjectID, '%[A-Z]%d', $column, $row); | |||
return (integer) $row; | |||
} | |||
/** | |||
* Get highest worksheet column | |||
* | |||
* @param string $row Return the highest column for the specified row, | |||
* or the highest column of any row if no row number is passed | |||
* @return string Highest column name | |||
*/ | |||
public function getHighestColumn($row = null) | |||
{ | |||
if ($row == null) { | |||
$colRow = $this->getHighestRowAndColumn(); | |||
return $colRow['column']; | |||
} | |||
$columnList = array(1); | |||
foreach ($this->getCellList() as $coord) { | |||
sscanf($coord, '%[A-Z]%d', $c, $r); | |||
if ($r != $row) { | |||
continue; | |||
} | |||
$columnList[] = PHPExcel_Cell::columnIndexFromString($c); | |||
} | |||
return PHPExcel_Cell::stringFromColumnIndex(max($columnList) - 1); | |||
} | |||
/** | |||
* Get highest worksheet row | |||
* | |||
* @param string $column Return the highest row for the specified column, | |||
* or the highest row of any column if no column letter is passed | |||
* @return int Highest row number | |||
*/ | |||
public function getHighestRow($column = null) | |||
{ | |||
if ($column == null) { | |||
$colRow = $this->getHighestRowAndColumn(); | |||
return $colRow['row']; | |||
} | |||
$rowList = array(0); | |||
foreach ($this->getCellList() as $coord) { | |||
sscanf($coord, '%[A-Z]%d', $c, $r); | |||
if ($c != $column) { | |||
continue; | |||
} | |||
$rowList[] = $r; | |||
} | |||
return max($rowList); | |||
} | |||
/** | |||
* Generate a unique ID for cache referencing | |||
* | |||
* @return string Unique Reference | |||
*/ | |||
protected function getUniqueID() | |||
{ | |||
if (function_exists('posix_getpid')) { | |||
$baseUnique = posix_getpid(); | |||
} else { | |||
$baseUnique = mt_rand(); | |||
} | |||
return uniqid($baseUnique, true); | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
$this->currentCellIsDirty; | |||
$this->storeData(); | |||
$this->parent = $parent; | |||
if (($this->currentObject !== null) && (is_object($this->currentObject))) { | |||
$this->currentObject->attach($this); | |||
} | |||
} // function copyCellCollection() | |||
/** | |||
* Remove a row, deleting all cells in that row | |||
* | |||
* @param string $row Row number to remove | |||
* @return void | |||
*/ | |||
public function removeRow($row) | |||
{ | |||
foreach ($this->getCellList() as $coord) { | |||
sscanf($coord, '%[A-Z]%d', $c, $r); | |||
if ($r == $row) { | |||
$this->deleteCacheData($coord); | |||
} | |||
} | |||
} | |||
/** | |||
* Remove a column, deleting all cells in that column | |||
* | |||
* @param string $column Column ID to remove | |||
* @return void | |||
*/ | |||
public function removeColumn($column) | |||
{ | |||
foreach ($this->getCellList() as $coord) { | |||
sscanf($coord, '%[A-Z]%d', $c, $r); | |||
if ($c == $column) { | |||
$this->deleteCacheData($coord); | |||
} | |||
} | |||
} | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
return true; | |||
} | |||
} |
@ -0,0 +1,208 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_DiscISAM | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_DiscISAM extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Name of the file for this cache | |||
* | |||
* @var string | |||
*/ | |||
private $fileName = null; | |||
/** | |||
* File handle for this cache file | |||
* | |||
* @var resource | |||
*/ | |||
private $fileHandle = null; | |||
/** | |||
* Directory/Folder where the cache file is located | |||
* | |||
* @var string | |||
*/ | |||
private $cacheDirectory = null; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
fseek($this->fileHandle, 0, SEEK_END); | |||
$this->cellCache[$this->currentObjectID] = array( | |||
'ptr' => ftell($this->fileHandle), | |||
'sz' => fwrite($this->fileHandle, serialize($this->currentObject)) | |||
); | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (!isset($this->cellCache[$pCoord])) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
fseek($this->fileHandle, $this->cellCache[$pCoord]['ptr']); | |||
$this->currentObject = unserialize(fread($this->fileHandle, $this->cellCache[$pCoord]['sz'])); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::copyCellCollection($parent); | |||
// Get a new id for the new file name | |||
$baseUnique = $this->getUniqueID(); | |||
$newFileName = $this->cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache'; | |||
// Copy the existing cell cache file | |||
copy($this->fileName, $newFileName); | |||
$this->fileName = $newFileName; | |||
// Open the copied cell cache file | |||
$this->fileHandle = fopen($this->fileName, 'a+'); | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
// Close down the temporary cache file | |||
$this->__destruct(); | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
* @param array of mixed $arguments Additional initialisation arguments | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent, $arguments) | |||
{ | |||
$this->cacheDirectory = ((isset($arguments['dir'])) && ($arguments['dir'] !== null)) | |||
? $arguments['dir'] | |||
: PHPExcel_Shared_File::sys_get_temp_dir(); | |||
parent::__construct($parent); | |||
if (is_null($this->fileHandle)) { | |||
$baseUnique = $this->getUniqueID(); | |||
$this->fileName = $this->cacheDirectory.'/PHPExcel.'.$baseUnique.'.cache'; | |||
$this->fileHandle = fopen($this->fileName, 'a+'); | |||
} | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
if (!is_null($this->fileHandle)) { | |||
fclose($this->fileHandle); | |||
unlink($this->fileName); | |||
} | |||
$this->fileHandle = null; | |||
} | |||
} |
@ -0,0 +1,103 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_ICache | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
interface PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell); | |||
/** | |||
* Add or Update a cell in cache | |||
* | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function updateCacheData(PHPExcel_Cell $cell); | |||
/** | |||
* Fetch a cell from cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to retrieve | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function getCacheData($pCoord); | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord); | |||
/** | |||
* Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell? | |||
* | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord); | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList(); | |||
/** | |||
* Get the list of all cell addresses currently held in cache sorted by column and row | |||
* | |||
* @return string[] | |||
*/ | |||
public function getSortedCellList(); | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent); | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable(); | |||
} |
@ -0,0 +1,149 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_Igbinary | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_Igbinary extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
$this->cellCache[$this->currentObjectID] = igbinary_serialize($this->currentObject); | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} // function _storeData() | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} // function addCacheData() | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (!isset($this->cellCache[$pCoord])) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = igbinary_unserialize($this->cellCache[$pCoord]); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} // function getCacheData() | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} // function unsetWorksheetCells() | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
if (!function_exists('igbinary_serialize')) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,308 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_Memcache | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_Memcache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Prefix used to uniquely identify cache data for this worksheet | |||
* | |||
* @var string | |||
*/ | |||
private $cachePrefix = null; | |||
/** | |||
* Cache timeout | |||
* | |||
* @var integer | |||
*/ | |||
private $cacheTime = 600; | |||
/** | |||
* Memcache interface | |||
* | |||
* @var resource | |||
*/ | |||
private $memcache = null; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
$obj = serialize($this->currentObject); | |||
if (!$this->memcache->replace($this->cachePrefix . $this->currentObjectID . '.cache', $obj, null, $this->cacheTime)) { | |||
if (!$this->memcache->add($this->cachePrefix . $this->currentObjectID . '.cache', $obj, null, $this->cacheTime)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception("Failed to store cell {$this->currentObjectID} in MemCache"); | |||
} | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} // function _storeData() | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->cellCache[$pCoord] = true; | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} // function addCacheData() | |||
/** | |||
* Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell? | |||
* | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @return boolean | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord) | |||
{ | |||
// Check if the requested entry is the current object, or exists in the cache | |||
if (parent::isDataSet($pCoord)) { | |||
if ($this->currentObjectID == $pCoord) { | |||
return true; | |||
} | |||
// Check if the requested entry still exists in Memcache | |||
$success = $this->memcache->get($this->cachePrefix.$pCoord.'.cache'); | |||
if ($success === false) { | |||
// Entry no longer exists in Memcache, so clear it from the cache array | |||
parent::deleteCacheData($pCoord); | |||
throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in MemCache'); | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (parent::isDataSet($pCoord)) { | |||
$obj = $this->memcache->get($this->cachePrefix . $pCoord . '.cache'); | |||
if ($obj === false) { | |||
// Entry no longer exists in Memcache, so clear it from the cache array | |||
parent::deleteCacheData($pCoord); | |||
throw new PHPExcel_Exception("Cell entry {$pCoord} no longer exists in MemCache"); | |||
} | |||
} else { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = unserialize($obj); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord) | |||
{ | |||
// Delete the entry from Memcache | |||
$this->memcache->delete($this->cachePrefix . $pCoord . '.cache'); | |||
// Delete the entry from our cell address array | |||
parent::deleteCacheData($pCoord); | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::copyCellCollection($parent); | |||
// Get a new id for the new file name | |||
$baseUnique = $this->getUniqueID(); | |||
$newCachePrefix = substr(md5($baseUnique), 0, 8) . '.'; | |||
$cacheList = $this->getCellList(); | |||
foreach ($cacheList as $cellID) { | |||
if ($cellID != $this->currentObjectID) { | |||
$obj = $this->memcache->get($this->cachePrefix.$cellID.'.cache'); | |||
if ($obj === false) { | |||
// Entry no longer exists in Memcache, so clear it from the cache array | |||
parent::deleteCacheData($cellID); | |||
throw new PHPExcel_Exception("Cell entry {$cellID} no longer exists in MemCache"); | |||
} | |||
if (!$this->memcache->add($newCachePrefix . $cellID . '.cache', $obj, null, $this->cacheTime)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception("Failed to store cell {$cellID} in MemCache"); | |||
} | |||
} | |||
} | |||
$this->cachePrefix = $newCachePrefix; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
// Flush the Memcache cache | |||
$this->__destruct(); | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
* @param array of mixed $arguments Additional initialisation arguments | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent, $arguments) | |||
{ | |||
$memcacheServer = (isset($arguments['memcacheServer'])) ? $arguments['memcacheServer'] : 'localhost'; | |||
$memcachePort = (isset($arguments['memcachePort'])) ? $arguments['memcachePort'] : 11211; | |||
$cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600; | |||
if (is_null($this->cachePrefix)) { | |||
$baseUnique = $this->getUniqueID(); | |||
$this->cachePrefix = substr(md5($baseUnique), 0, 8) . '.'; | |||
// Set a new Memcache object and connect to the Memcache server | |||
$this->memcache = new Memcache(); | |||
if (!$this->memcache->addServer($memcacheServer, $memcachePort, false, 50, 5, 5, true, array($this, 'failureCallback'))) { | |||
throw new PHPExcel_Exception("Could not connect to MemCache server at {$memcacheServer}:{$memcachePort}"); | |||
} | |||
$this->cacheTime = $cacheTime; | |||
parent::__construct($parent); | |||
} | |||
} | |||
/** | |||
* Memcache error handler | |||
* | |||
* @param string $host Memcache server | |||
* @param integer $port Memcache port | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function failureCallback($host, $port) | |||
{ | |||
throw new PHPExcel_Exception("memcache {$host}:{$port} failed"); | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
$cacheList = $this->getCellList(); | |||
foreach ($cacheList as $cellID) { | |||
$this->memcache->delete($this->cachePrefix.$cellID . '.cache'); | |||
} | |||
} | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
if (!function_exists('memcache_add')) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,118 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_Memory | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_Memory extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Dummy method callable from CacheBase, but unused by Memory cache | |||
* | |||
* @return void | |||
*/ | |||
protected function storeData() | |||
{ | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
$this->cellCache[$pCoord] = $cell; | |||
// Set current entry to the new/updated entry | |||
$this->currentObjectID = $pCoord; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
// Check if the entry that has been requested actually exists | |||
if (!isset($this->cellCache[$pCoord])) { | |||
$this->currentObjectID = null; | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
// Return requested entry | |||
return $this->cellCache[$pCoord]; | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::copyCellCollection($parent); | |||
$newCollection = array(); | |||
foreach ($this->cellCache as $k => &$cell) { | |||
$newCollection[$k] = clone $cell; | |||
$newCollection[$k]->attach($this); | |||
} | |||
$this->cellCache = $newCollection; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
// Because cells are all stored as intact objects in memory, we need to detach each one from the parent | |||
foreach ($this->cellCache as $k => &$cell) { | |||
$cell->detach(); | |||
$this->cellCache[$k] = null; | |||
} | |||
unset($cell); | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} | |||
} |
@ -0,0 +1,133 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_MemoryGZip | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_MemoryGZip extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
$this->cellCache[$this->currentObjectID] = gzdeflate(serialize($this->currentObject)); | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (!isset($this->cellCache[$pCoord])) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = unserialize(gzinflate($this->cellCache[$pCoord])); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} | |||
} |
@ -0,0 +1,129 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_MemorySerialized | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_MemorySerialized extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
$this->cellCache[$this->currentObjectID] = serialize($this->currentObject); | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (!isset($this->cellCache[$pCoord])) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = unserialize($this->cellCache[$pCoord]); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} | |||
} |
@ -0,0 +1,200 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_PHPTemp | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_PHPTemp extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Name of the file for this cache | |||
* | |||
* @var string | |||
*/ | |||
private $fileHandle = null; | |||
/** | |||
* Memory limit to use before reverting to file cache | |||
* | |||
* @var integer | |||
*/ | |||
private $memoryCacheSize = null; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
fseek($this->fileHandle, 0, SEEK_END); | |||
$this->cellCache[$this->currentObjectID] = array( | |||
'ptr' => ftell($this->fileHandle), | |||
'sz' => fwrite($this->fileHandle, serialize($this->currentObject)) | |||
); | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
if (!isset($this->cellCache[$pCoord])) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
fseek($this->fileHandle, $this->cellCache[$pCoord]['ptr']); | |||
$this->currentObject = unserialize(fread($this->fileHandle, $this->cellCache[$pCoord]['sz'])); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::copyCellCollection($parent); | |||
// Open a new stream for the cell cache data | |||
$newFileHandle = fopen('php://temp/maxmemory:' . $this->memoryCacheSize, 'a+'); | |||
// Copy the existing cell cache data to the new stream | |||
fseek($this->fileHandle, 0); | |||
while (!feof($this->fileHandle)) { | |||
fwrite($newFileHandle, fread($this->fileHandle, 1024)); | |||
} | |||
$this->fileHandle = $newFileHandle; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
// Close down the php://temp file | |||
$this->__destruct(); | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
* @param array of mixed $arguments Additional initialisation arguments | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent, $arguments) | |||
{ | |||
$this->memoryCacheSize = (isset($arguments['memoryCacheSize'])) ? $arguments['memoryCacheSize'] : '1MB'; | |||
parent::__construct($parent); | |||
if (is_null($this->fileHandle)) { | |||
$this->fileHandle = fopen('php://temp/maxmemory:' . $this->memoryCacheSize, 'a+'); | |||
} | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
if (!is_null($this->fileHandle)) { | |||
fclose($this->fileHandle); | |||
} | |||
$this->fileHandle = null; | |||
} | |||
} |
@ -0,0 +1,307 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_SQLite | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_SQLite extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Database table name | |||
* | |||
* @var string | |||
*/ | |||
private $TableName = null; | |||
/** | |||
* Database handle | |||
* | |||
* @var resource | |||
*/ | |||
private $DBHandle = null; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
if (!$this->DBHandle->queryExec("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES('".$this->currentObjectID."','".sqlite_escape_string(serialize($this->currentObject))."')")) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
$query = "SELECT value FROM kvp_".$this->TableName." WHERE id='".$pCoord."'"; | |||
$cellResultSet = $this->DBHandle->query($query, SQLITE_ASSOC); | |||
if ($cellResultSet === false) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} elseif ($cellResultSet->numRows() == 0) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$cellResult = $cellResultSet->fetchSingle(); | |||
$this->currentObject = unserialize($cellResult); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Is a value set for an indexed cell? | |||
* | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return true; | |||
} | |||
// Check if the requested entry exists in the cache | |||
$query = "SELECT id FROM kvp_".$this->TableName." WHERE id='".$pCoord."'"; | |||
$cellResultSet = $this->DBHandle->query($query, SQLITE_ASSOC); | |||
if ($cellResultSet === false) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} elseif ($cellResultSet->numRows() == 0) { | |||
// Return null if requested entry doesn't exist in cache | |||
return false; | |||
} | |||
return true; | |||
} | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
$this->currentObject->detach(); | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
// Check if the requested entry exists in the cache | |||
$query = "DELETE FROM kvp_".$this->TableName." WHERE id='".$pCoord."'"; | |||
if (!$this->DBHandle->queryExec($query)) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
/** | |||
* Move a cell object from one address to another | |||
* | |||
* @param string $fromAddress Current address of the cell to move | |||
* @param string $toAddress Destination address of the cell to move | |||
* @return boolean | |||
*/ | |||
public function moveCell($fromAddress, $toAddress) | |||
{ | |||
if ($fromAddress === $this->currentObjectID) { | |||
$this->currentObjectID = $toAddress; | |||
} | |||
$query = "DELETE FROM kvp_".$this->TableName." WHERE id='".$toAddress."'"; | |||
$result = $this->DBHandle->exec($query); | |||
if ($result === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$query = "UPDATE kvp_".$this->TableName." SET id='".$toAddress."' WHERE id='".$fromAddress."'"; | |||
$result = $this->DBHandle->exec($query); | |||
if ($result === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
return true; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
$query = "SELECT id FROM kvp_".$this->TableName; | |||
$cellIdsResult = $this->DBHandle->unbufferedQuery($query, SQLITE_ASSOC); | |||
if ($cellIdsResult === false) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} | |||
$cellKeys = array(); | |||
foreach ($cellIdsResult as $row) { | |||
$cellKeys[] = $row['id']; | |||
} | |||
return $cellKeys; | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
$this->currentCellIsDirty; | |||
$this->storeData(); | |||
// Get a new id for the new table name | |||
$tableName = str_replace('.', '_', $this->getUniqueID()); | |||
if (!$this->DBHandle->queryExec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB) | |||
AS SELECT * FROM kvp_'.$this->TableName) | |||
) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} | |||
// Copy the existing cell cache file | |||
$this->TableName = $tableName; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
// Close down the temporary cache file | |||
$this->__destruct(); | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::__construct($parent); | |||
if (is_null($this->DBHandle)) { | |||
$this->TableName = str_replace('.', '_', $this->getUniqueID()); | |||
$_DBName = ':memory:'; | |||
$this->DBHandle = new SQLiteDatabase($_DBName); | |||
if ($this->DBHandle === false) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} | |||
if (!$this->DBHandle->queryExec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) { | |||
throw new PHPExcel_Exception(sqlite_error_string($this->DBHandle->lastError())); | |||
} | |||
} | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
if (!is_null($this->DBHandle)) { | |||
$this->DBHandle->queryExec('DROP TABLE kvp_'.$this->TableName); | |||
} | |||
$this->DBHandle = null; | |||
} | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
if (!function_exists('sqlite_open')) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,346 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_SQLite3 | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_SQLite3 extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Database table name | |||
* | |||
* @var string | |||
*/ | |||
private $TableName = null; | |||
/** | |||
* Database handle | |||
* | |||
* @var resource | |||
*/ | |||
private $DBHandle = null; | |||
/** | |||
* Prepared statement for a SQLite3 select query | |||
* | |||
* @var SQLite3Stmt | |||
*/ | |||
private $selectQuery; | |||
/** | |||
* Prepared statement for a SQLite3 insert query | |||
* | |||
* @var SQLite3Stmt | |||
*/ | |||
private $insertQuery; | |||
/** | |||
* Prepared statement for a SQLite3 update query | |||
* | |||
* @var SQLite3Stmt | |||
*/ | |||
private $updateQuery; | |||
/** | |||
* Prepared statement for a SQLite3 delete query | |||
* | |||
* @var SQLite3Stmt | |||
*/ | |||
private $deleteQuery; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
$this->insertQuery->bindValue('id', $this->currentObjectID, SQLITE3_TEXT); | |||
$this->insertQuery->bindValue('data', serialize($this->currentObject), SQLITE3_BLOB); | |||
$result = $this->insertQuery->execute(); | |||
if ($result === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
$this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT); | |||
$cellResult = $this->selectQuery->execute(); | |||
if ($cellResult === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$cellData = $cellResult->fetchArray(SQLITE3_ASSOC); | |||
if ($cellData === false) { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = unserialize($cellData['value']); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Is a value set for an indexed cell? | |||
* | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return true; | |||
} | |||
// Check if the requested entry exists in the cache | |||
$this->selectQuery->bindValue('id', $pCoord, SQLITE3_TEXT); | |||
$cellResult = $this->selectQuery->execute(); | |||
if ($cellResult === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$cellData = $cellResult->fetchArray(SQLITE3_ASSOC); | |||
return ($cellData === false) ? false : true; | |||
} | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
$this->currentObject->detach(); | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
// Check if the requested entry exists in the cache | |||
$this->deleteQuery->bindValue('id', $pCoord, SQLITE3_TEXT); | |||
$result = $this->deleteQuery->execute(); | |||
if ($result === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
/** | |||
* Move a cell object from one address to another | |||
* | |||
* @param string $fromAddress Current address of the cell to move | |||
* @param string $toAddress Destination address of the cell to move | |||
* @return boolean | |||
*/ | |||
public function moveCell($fromAddress, $toAddress) | |||
{ | |||
if ($fromAddress === $this->currentObjectID) { | |||
$this->currentObjectID = $toAddress; | |||
} | |||
$this->deleteQuery->bindValue('id', $toAddress, SQLITE3_TEXT); | |||
$result = $this->deleteQuery->execute(); | |||
if ($result === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$this->updateQuery->bindValue('toid', $toAddress, SQLITE3_TEXT); | |||
$this->updateQuery->bindValue('fromid', $fromAddress, SQLITE3_TEXT); | |||
$result = $this->updateQuery->execute(); | |||
if ($result === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
return true; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
$query = "SELECT id FROM kvp_".$this->TableName; | |||
$cellIdsResult = $this->DBHandle->query($query); | |||
if ($cellIdsResult === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
$cellKeys = array(); | |||
while ($row = $cellIdsResult->fetchArray(SQLITE3_ASSOC)) { | |||
$cellKeys[] = $row['id']; | |||
} | |||
return $cellKeys; | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
$this->currentCellIsDirty; | |||
$this->storeData(); | |||
// Get a new id for the new table name | |||
$tableName = str_replace('.', '_', $this->getUniqueID()); | |||
if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$tableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB) | |||
AS SELECT * FROM kvp_'.$this->TableName) | |||
) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
// Copy the existing cell cache file | |||
$this->TableName = $tableName; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
// Close down the temporary cache file | |||
$this->__destruct(); | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::__construct($parent); | |||
if (is_null($this->DBHandle)) { | |||
$this->TableName = str_replace('.', '_', $this->getUniqueID()); | |||
$_DBName = ':memory:'; | |||
$this->DBHandle = new SQLite3($_DBName); | |||
if ($this->DBHandle === false) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
if (!$this->DBHandle->exec('CREATE TABLE kvp_'.$this->TableName.' (id VARCHAR(12) PRIMARY KEY, value BLOB)')) { | |||
throw new PHPExcel_Exception($this->DBHandle->lastErrorMsg()); | |||
} | |||
} | |||
$this->selectQuery = $this->DBHandle->prepare("SELECT value FROM kvp_".$this->TableName." WHERE id = :id"); | |||
$this->insertQuery = $this->DBHandle->prepare("INSERT OR REPLACE INTO kvp_".$this->TableName." VALUES(:id,:data)"); | |||
$this->updateQuery = $this->DBHandle->prepare("UPDATE kvp_".$this->TableName." SET id=:toId WHERE id=:fromId"); | |||
$this->deleteQuery = $this->DBHandle->prepare("DELETE FROM kvp_".$this->TableName." WHERE id = :id"); | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
if (!is_null($this->DBHandle)) { | |||
$this->DBHandle->exec('DROP TABLE kvp_'.$this->TableName); | |||
$this->DBHandle->close(); | |||
} | |||
$this->DBHandle = null; | |||
} | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
if (!class_exists('SQLite3', false)) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,289 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorage_Wincache | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorage_Wincache extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache | |||
{ | |||
/** | |||
* Prefix used to uniquely identify cache data for this worksheet | |||
* | |||
* @var string | |||
*/ | |||
private $cachePrefix = null; | |||
/** | |||
* Cache timeout | |||
* | |||
* @var integer | |||
*/ | |||
private $cacheTime = 600; | |||
/** | |||
* Store cell data in cache for the current cell object if it's "dirty", | |||
* and the 'nullify' the current cell object | |||
* | |||
* @return void | |||
* @throws PHPExcel_Exception | |||
*/ | |||
protected function storeData() | |||
{ | |||
if ($this->currentCellIsDirty && !empty($this->currentObjectID)) { | |||
$this->currentObject->detach(); | |||
$obj = serialize($this->currentObject); | |||
if (wincache_ucache_exists($this->cachePrefix.$this->currentObjectID.'.cache')) { | |||
if (!wincache_ucache_set($this->cachePrefix.$this->currentObjectID.'.cache', $obj, $this->cacheTime)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception('Failed to store cell '.$this->currentObjectID.' in WinCache'); | |||
} | |||
} else { | |||
if (!wincache_ucache_add($this->cachePrefix.$this->currentObjectID.'.cache', $obj, $this->cacheTime)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception('Failed to store cell '.$this->currentObjectID.' in WinCache'); | |||
} | |||
} | |||
$this->currentCellIsDirty = false; | |||
} | |||
$this->currentObjectID = $this->currentObject = null; | |||
} | |||
/** | |||
* Add or Update a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to update | |||
* @param PHPExcel_Cell $cell Cell to update | |||
* @return PHPExcel_Cell | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function addCacheData($pCoord, PHPExcel_Cell $cell) | |||
{ | |||
if (($pCoord !== $this->currentObjectID) && ($this->currentObjectID !== null)) { | |||
$this->storeData(); | |||
} | |||
$this->cellCache[$pCoord] = true; | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = $cell; | |||
$this->currentCellIsDirty = true; | |||
return $cell; | |||
} | |||
/** | |||
* Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell? | |||
* | |||
* @param string $pCoord Coordinate address of the cell to check | |||
* @return boolean | |||
*/ | |||
public function isDataSet($pCoord) | |||
{ | |||
// Check if the requested entry is the current object, or exists in the cache | |||
if (parent::isDataSet($pCoord)) { | |||
if ($this->currentObjectID == $pCoord) { | |||
return true; | |||
} | |||
// Check if the requested entry still exists in cache | |||
$success = wincache_ucache_exists($this->cachePrefix.$pCoord.'.cache'); | |||
if ($success === false) { | |||
// Entry no longer exists in Wincache, so clear it from the cache array | |||
parent::deleteCacheData($pCoord); | |||
throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache'); | |||
} | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Get cell at a specific coordinate | |||
* | |||
* @param string $pCoord Coordinate of the cell | |||
* @throws PHPExcel_Exception | |||
* @return PHPExcel_Cell Cell that was found, or null if not found | |||
*/ | |||
public function getCacheData($pCoord) | |||
{ | |||
if ($pCoord === $this->currentObjectID) { | |||
return $this->currentObject; | |||
} | |||
$this->storeData(); | |||
// Check if the entry that has been requested actually exists | |||
$obj = null; | |||
if (parent::isDataSet($pCoord)) { | |||
$success = false; | |||
$obj = wincache_ucache_get($this->cachePrefix.$pCoord.'.cache', $success); | |||
if ($success === false) { | |||
// Entry no longer exists in WinCache, so clear it from the cache array | |||
parent::deleteCacheData($pCoord); | |||
throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in WinCache'); | |||
} | |||
} else { | |||
// Return null if requested entry doesn't exist in cache | |||
return null; | |||
} | |||
// Set current entry to the requested entry | |||
$this->currentObjectID = $pCoord; | |||
$this->currentObject = unserialize($obj); | |||
// Re-attach this as the cell's parent | |||
$this->currentObject->attach($this); | |||
// Return requested entry | |||
return $this->currentObject; | |||
} | |||
/** | |||
* Get a list of all cell addresses currently held in cache | |||
* | |||
* @return string[] | |||
*/ | |||
public function getCellList() | |||
{ | |||
if ($this->currentObjectID !== null) { | |||
$this->storeData(); | |||
} | |||
return parent::getCellList(); | |||
} | |||
/** | |||
* Delete a cell in cache identified by coordinate address | |||
* | |||
* @param string $pCoord Coordinate address of the cell to delete | |||
* @throws PHPExcel_Exception | |||
*/ | |||
public function deleteCacheData($pCoord) | |||
{ | |||
// Delete the entry from Wincache | |||
wincache_ucache_delete($this->cachePrefix.$pCoord.'.cache'); | |||
// Delete the entry from our cell address array | |||
parent::deleteCacheData($pCoord); | |||
} | |||
/** | |||
* Clone the cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The new worksheet | |||
* @return void | |||
*/ | |||
public function copyCellCollection(PHPExcel_Worksheet $parent) | |||
{ | |||
parent::copyCellCollection($parent); | |||
// Get a new id for the new file name | |||
$baseUnique = $this->getUniqueID(); | |||
$newCachePrefix = substr(md5($baseUnique), 0, 8) . '.'; | |||
$cacheList = $this->getCellList(); | |||
foreach ($cacheList as $cellID) { | |||
if ($cellID != $this->currentObjectID) { | |||
$success = false; | |||
$obj = wincache_ucache_get($this->cachePrefix.$cellID.'.cache', $success); | |||
if ($success === false) { | |||
// Entry no longer exists in WinCache, so clear it from the cache array | |||
parent::deleteCacheData($cellID); | |||
throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in Wincache'); | |||
} | |||
if (!wincache_ucache_add($newCachePrefix.$cellID.'.cache', $obj, $this->cacheTime)) { | |||
$this->__destruct(); | |||
throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in Wincache'); | |||
} | |||
} | |||
} | |||
$this->cachePrefix = $newCachePrefix; | |||
} | |||
/** | |||
* Clear the cell collection and disconnect from our parent | |||
* | |||
* @return void | |||
*/ | |||
public function unsetWorksheetCells() | |||
{ | |||
if (!is_null($this->currentObject)) { | |||
$this->currentObject->detach(); | |||
$this->currentObject = $this->currentObjectID = null; | |||
} | |||
// Flush the WinCache cache | |||
$this->__destruct(); | |||
$this->cellCache = array(); | |||
// detach ourself from the worksheet, so that it can then delete this object successfully | |||
$this->parent = null; | |||
} | |||
/** | |||
* Initialise this new cell collection | |||
* | |||
* @param PHPExcel_Worksheet $parent The worksheet for this cell collection | |||
* @param array of mixed $arguments Additional initialisation arguments | |||
*/ | |||
public function __construct(PHPExcel_Worksheet $parent, $arguments) | |||
{ | |||
$cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600; | |||
if (is_null($this->cachePrefix)) { | |||
$baseUnique = $this->getUniqueID(); | |||
$this->cachePrefix = substr(md5($baseUnique), 0, 8).'.'; | |||
$this->cacheTime = $cacheTime; | |||
parent::__construct($parent); | |||
} | |||
} | |||
/** | |||
* Destroy this cell collection | |||
*/ | |||
public function __destruct() | |||
{ | |||
$cacheList = $this->getCellList(); | |||
foreach ($cacheList as $cellID) { | |||
wincache_ucache_delete($this->cachePrefix.$cellID.'.cache'); | |||
} | |||
} | |||
/** | |||
* Identify whether the caching method is currently available | |||
* Some methods are dependent on the availability of certain extensions being enabled in the PHP build | |||
* | |||
* @return boolean | |||
*/ | |||
public static function cacheMethodIsAvailable() | |||
{ | |||
if (!function_exists('wincache_ucache_add')) { | |||
return false; | |||
} | |||
return true; | |||
} | |||
} |
@ -0,0 +1,231 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CachedObjectStorageFactory | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_CachedObjectStorage | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CachedObjectStorageFactory | |||
{ | |||
const cache_in_memory = 'Memory'; | |||
const cache_in_memory_gzip = 'MemoryGZip'; | |||
const cache_in_memory_serialized = 'MemorySerialized'; | |||
const cache_igbinary = 'Igbinary'; | |||
const cache_to_discISAM = 'DiscISAM'; | |||
const cache_to_apc = 'APC'; | |||
const cache_to_memcache = 'Memcache'; | |||
const cache_to_phpTemp = 'PHPTemp'; | |||
const cache_to_wincache = 'Wincache'; | |||
const cache_to_sqlite = 'SQLite'; | |||
const cache_to_sqlite3 = 'SQLite3'; | |||
/** | |||
* Name of the method used for cell cacheing | |||
* | |||
* @var string | |||
*/ | |||
private static $cacheStorageMethod = null; | |||
/** | |||
* Name of the class used for cell cacheing | |||
* | |||
* @var string | |||
*/ | |||
private static $cacheStorageClass = null; | |||
/** | |||
* List of all possible cache storage methods | |||
* | |||
* @var string[] | |||
*/ | |||
private static $storageMethods = array( | |||
self::cache_in_memory, | |||
self::cache_in_memory_gzip, | |||
self::cache_in_memory_serialized, | |||
self::cache_igbinary, | |||
self::cache_to_phpTemp, | |||
self::cache_to_discISAM, | |||
self::cache_to_apc, | |||
self::cache_to_memcache, | |||
self::cache_to_wincache, | |||
self::cache_to_sqlite, | |||
self::cache_to_sqlite3, | |||
); | |||
/** | |||
* Default arguments for each cache storage method | |||
* | |||
* @var array of mixed array | |||
*/ | |||
private static $storageMethodDefaultParameters = array( | |||
self::cache_in_memory => array( | |||
), | |||
self::cache_in_memory_gzip => array( | |||
), | |||
self::cache_in_memory_serialized => array( | |||
), | |||
self::cache_igbinary => array( | |||
), | |||
self::cache_to_phpTemp => array( 'memoryCacheSize' => '1MB' | |||
), | |||
self::cache_to_discISAM => array( 'dir' => null | |||
), | |||
self::cache_to_apc => array( 'cacheTime' => 600 | |||
), | |||
self::cache_to_memcache => array( 'memcacheServer' => 'localhost', | |||
'memcachePort' => 11211, | |||
'cacheTime' => 600 | |||
), | |||
self::cache_to_wincache => array( 'cacheTime' => 600 | |||
), | |||
self::cache_to_sqlite => array( | |||
), | |||
self::cache_to_sqlite3 => array( | |||
), | |||
); | |||
/** | |||
* Arguments for the active cache storage method | |||
* | |||
* @var array of mixed array | |||
*/ | |||
private static $storageMethodParameters = array(); | |||
/** | |||
* Return the current cache storage method | |||
* | |||
* @return string|null | |||
**/ | |||
public static function getCacheStorageMethod() | |||
{ | |||
return self::$cacheStorageMethod; | |||
} | |||
/** | |||
* Return the current cache storage class | |||
* | |||
* @return PHPExcel_CachedObjectStorage_ICache|null | |||
**/ | |||
public static function getCacheStorageClass() | |||
{ | |||
return self::$cacheStorageClass; | |||
} | |||
/** | |||
* Return the list of all possible cache storage methods | |||
* | |||
* @return string[] | |||
**/ | |||
public static function getAllCacheStorageMethods() | |||
{ | |||
return self::$storageMethods; | |||
} | |||
/** | |||
* Return the list of all available cache storage methods | |||
* | |||
* @return string[] | |||
**/ | |||
public static function getCacheStorageMethods() | |||
{ | |||
$activeMethods = array(); | |||
foreach (self::$storageMethods as $storageMethod) { | |||
$cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $storageMethod; | |||
if (call_user_func(array($cacheStorageClass, 'cacheMethodIsAvailable'))) { | |||
$activeMethods[] = $storageMethod; | |||
} | |||
} | |||
return $activeMethods; | |||
} | |||
/** | |||
* Identify the cache storage method to use | |||
* | |||
* @param string $method Name of the method to use for cell cacheing | |||
* @param array of mixed $arguments Additional arguments to pass to the cell caching class | |||
* when instantiating | |||
* @return boolean | |||
**/ | |||
public static function initialize($method = self::cache_in_memory, $arguments = array()) | |||
{ | |||
if (!in_array($method, self::$storageMethods)) { | |||
return false; | |||
} | |||
$cacheStorageClass = 'PHPExcel_CachedObjectStorage_'.$method; | |||
if (!call_user_func(array( $cacheStorageClass, | |||
'cacheMethodIsAvailable'))) { | |||
return false; | |||
} | |||
self::$storageMethodParameters[$method] = self::$storageMethodDefaultParameters[$method]; | |||
foreach ($arguments as $k => $v) { | |||
if (array_key_exists($k, self::$storageMethodParameters[$method])) { | |||
self::$storageMethodParameters[$method][$k] = $v; | |||
} | |||
} | |||
if (self::$cacheStorageMethod === null) { | |||
self::$cacheStorageClass = 'PHPExcel_CachedObjectStorage_' . $method; | |||
self::$cacheStorageMethod = $method; | |||
} | |||
return true; | |||
} | |||
/** | |||
* Initialise the cache storage | |||
* | |||
* @param PHPExcel_Worksheet $parent Enable cell caching for this worksheet | |||
* @return PHPExcel_CachedObjectStorage_ICache | |||
**/ | |||
public static function getInstance(PHPExcel_Worksheet $parent) | |||
{ | |||
$cacheMethodIsAvailable = true; | |||
if (self::$cacheStorageMethod === null) { | |||
$cacheMethodIsAvailable = self::initialize(); | |||
} | |||
if ($cacheMethodIsAvailable) { | |||
$instance = new self::$cacheStorageClass( | |||
$parent, | |||
self::$storageMethodParameters[self::$cacheStorageMethod] | |||
); | |||
if ($instance !== null) { | |||
return $instance; | |||
} | |||
} | |||
return false; | |||
} | |||
/** | |||
* Clear the cache storage | |||
* | |||
**/ | |||
public static function finalize() | |||
{ | |||
self::$cacheStorageMethod = null; | |||
self::$cacheStorageClass = null; | |||
self::$storageMethodParameters = array(); | |||
} | |||
} |
@ -0,0 +1,94 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CalcEngine_CyclicReferenceStack | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CalcEngine_CyclicReferenceStack | |||
{ | |||
/** | |||
* The call stack for calculated cells | |||
* | |||
* @var mixed[] | |||
*/ | |||
private $stack = array(); | |||
/** | |||
* Return the number of entries on the stack | |||
* | |||
* @return integer | |||
*/ | |||
public function count() | |||
{ | |||
return count($this->stack); | |||
} | |||
/** | |||
* Push a new entry onto the stack | |||
* | |||
* @param mixed $value | |||
*/ | |||
public function push($value) | |||
{ | |||
$this->stack[$value] = $value; | |||
} | |||
/** | |||
* Pop the last entry from the stack | |||
* | |||
* @return mixed | |||
*/ | |||
public function pop() | |||
{ | |||
return array_pop($this->stack); | |||
} | |||
/** | |||
* Test to see if a specified entry exists on the stack | |||
* | |||
* @param mixed $value The value to test | |||
*/ | |||
public function onStack($value) | |||
{ | |||
return isset($this->stack[$value]); | |||
} | |||
/** | |||
* Clear the stack | |||
*/ | |||
public function clear() | |||
{ | |||
$this->stack = array(); | |||
} | |||
/** | |||
* Return an array of all entries on the stack | |||
* | |||
* @return mixed[] | |||
*/ | |||
public function showStack() | |||
{ | |||
return $this->stack; | |||
} | |||
} |
@ -0,0 +1,151 @@ | |||
<?php | |||
/** | |||
* PHPExcel_CalcEngine_Logger | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_CalcEngine_Logger | |||
{ | |||
/** | |||
* Flag to determine whether a debug log should be generated by the calculation engine | |||
* If true, then a debug log will be generated | |||
* If false, then a debug log will not be generated | |||
* | |||
* @var boolean | |||
*/ | |||
private $writeDebugLog = false; | |||
/** | |||
* Flag to determine whether a debug log should be echoed by the calculation engine | |||
* If true, then a debug log will be echoed | |||
* If false, then a debug log will not be echoed | |||
* A debug log can only be echoed if it is generated | |||
* | |||
* @var boolean | |||
*/ | |||
private $echoDebugLog = false; | |||
/** | |||
* The debug log generated by the calculation engine | |||
* | |||
* @var string[] | |||
*/ | |||
private $debugLog = array(); | |||
/** | |||
* The calculation engine cell reference stack | |||
* | |||
* @var PHPExcel_CalcEngine_CyclicReferenceStack | |||
*/ | |||
private $cellStack; | |||
/** | |||
* Instantiate a Calculation engine logger | |||
* | |||
* @param PHPExcel_CalcEngine_CyclicReferenceStack $stack | |||
*/ | |||
public function __construct(PHPExcel_CalcEngine_CyclicReferenceStack $stack) | |||
{ | |||
$this->cellStack = $stack; | |||
} | |||
/** | |||
* Enable/Disable Calculation engine logging | |||
* | |||
* @param boolean $pValue | |||
*/ | |||
public function setWriteDebugLog($pValue = false) | |||
{ | |||
$this->writeDebugLog = $pValue; | |||
} | |||
/** | |||
* Return whether calculation engine logging is enabled or disabled | |||
* | |||
* @return boolean | |||
*/ | |||
public function getWriteDebugLog() | |||
{ | |||
return $this->writeDebugLog; | |||
} | |||
/** | |||
* Enable/Disable echoing of debug log information | |||
* | |||
* @param boolean $pValue | |||
*/ | |||
public function setEchoDebugLog($pValue = false) | |||
{ | |||
$this->echoDebugLog = $pValue; | |||
} | |||
/** | |||
* Return whether echoing of debug log information is enabled or disabled | |||
* | |||
* @return boolean | |||
*/ | |||
public function getEchoDebugLog() | |||
{ | |||
return $this->echoDebugLog; | |||
} | |||
/** | |||
* Write an entry to the calculation engine debug log | |||
*/ | |||
public function writeDebugLog() | |||
{ | |||
// Only write the debug log if logging is enabled | |||
if ($this->writeDebugLog) { | |||
$message = implode(func_get_args()); | |||
$cellReference = implode(' -> ', $this->cellStack->showStack()); | |||
if ($this->echoDebugLog) { | |||
echo $cellReference, | |||
($this->cellStack->count() > 0 ? ' => ' : ''), | |||
$message, | |||
PHP_EOL; | |||
} | |||
$this->debugLog[] = $cellReference . | |||
($this->cellStack->count() > 0 ? ' => ' : '') . | |||
$message; | |||
} | |||
} | |||
/** | |||
* Clear the calculation engine debug log | |||
*/ | |||
public function clearLog() | |||
{ | |||
$this->debugLog = array(); | |||
} | |||
/** | |||
* Return the calculation engine debug log | |||
* | |||
* @return string[] | |||
*/ | |||
public function getLog() | |||
{ | |||
return $this->debugLog; | |||
} | |||
} |
@ -0,0 +1,676 @@ | |||
<?php | |||
/** PHPExcel root directory */ | |||
if (!defined('PHPEXCEL_ROOT')) { | |||
/** | |||
* @ignore | |||
*/ | |||
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); | |||
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); | |||
} | |||
/** | |||
* PHPExcel_Calculation_Database | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_Database | |||
{ | |||
/** | |||
* fieldExtract | |||
* | |||
* Extracts the column ID to use for the data field. | |||
* | |||
* @access private | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param mixed $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @return string|NULL | |||
* | |||
*/ | |||
private static function fieldExtract($database, $field) | |||
{ | |||
$field = strtoupper(PHPExcel_Calculation_Functions::flattenSingleValue($field)); | |||
$fieldNames = array_map('strtoupper', array_shift($database)); | |||
if (is_numeric($field)) { | |||
$keys = array_keys($fieldNames); | |||
return $keys[$field-1]; | |||
} | |||
$key = array_search($field, $fieldNames); | |||
return ($key) ? $key : null; | |||
} | |||
/** | |||
* filter | |||
* | |||
* Parses the selection criteria, extracts the database rows that match those criteria, and | |||
* returns that subset of rows. | |||
* | |||
* @access private | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return array of mixed | |||
* | |||
*/ | |||
private static function filter($database, $criteria) | |||
{ | |||
$fieldNames = array_shift($database); | |||
$criteriaNames = array_shift($criteria); | |||
// Convert the criteria into a set of AND/OR conditions with [:placeholders] | |||
$testConditions = $testValues = array(); | |||
$testConditionsCount = 0; | |||
foreach ($criteriaNames as $key => $criteriaName) { | |||
$testCondition = array(); | |||
$testConditionCount = 0; | |||
foreach ($criteria as $row => $criterion) { | |||
if ($criterion[$key] > '') { | |||
$testCondition[] = '[:'.$criteriaName.']'.PHPExcel_Calculation_Functions::ifCondition($criterion[$key]); | |||
$testConditionCount++; | |||
} | |||
} | |||
if ($testConditionCount > 1) { | |||
$testConditions[] = 'OR(' . implode(',', $testCondition) . ')'; | |||
$testConditionsCount++; | |||
} elseif ($testConditionCount == 1) { | |||
$testConditions[] = $testCondition[0]; | |||
$testConditionsCount++; | |||
} | |||
} | |||
if ($testConditionsCount > 1) { | |||
$testConditionSet = 'AND(' . implode(',', $testConditions) . ')'; | |||
} elseif ($testConditionsCount == 1) { | |||
$testConditionSet = $testConditions[0]; | |||
} | |||
// Loop through each row of the database | |||
foreach ($database as $dataRow => $dataValues) { | |||
// Substitute actual values from the database row for our [:placeholders] | |||
$testConditionList = $testConditionSet; | |||
foreach ($criteriaNames as $key => $criteriaName) { | |||
$k = array_search($criteriaName, $fieldNames); | |||
if (isset($dataValues[$k])) { | |||
$dataValue = $dataValues[$k]; | |||
$dataValue = (is_string($dataValue)) ? PHPExcel_Calculation::wrapResult(strtoupper($dataValue)) : $dataValue; | |||
$testConditionList = str_replace('[:' . $criteriaName . ']', $dataValue, $testConditionList); | |||
} | |||
} | |||
// evaluate the criteria against the row data | |||
$result = PHPExcel_Calculation::getInstance()->_calculateFormulaValue('='.$testConditionList); | |||
// If the row failed to meet the criteria, remove it from the database | |||
if (!$result) { | |||
unset($database[$dataRow]); | |||
} | |||
} | |||
return $database; | |||
} | |||
private static function getFilteredColumn($database, $field, $criteria) | |||
{ | |||
// reduce the database to a set of rows that match all the criteria | |||
$database = self::filter($database, $criteria); | |||
// extract an array of values for the requested column | |||
$colData = array(); | |||
foreach ($database as $row) { | |||
$colData[] = $row[$field]; | |||
} | |||
return $colData; | |||
} | |||
/** | |||
* DAVERAGE | |||
* | |||
* Averages the values in a column of a list or database that match conditions you specify. | |||
* | |||
* Excel Function: | |||
* DAVERAGE(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DAVERAGE($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::AVERAGE( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DCOUNT | |||
* | |||
* Counts the cells that contain numbers in a column of a list or database that match conditions | |||
* that you specify. | |||
* | |||
* Excel Function: | |||
* DCOUNT(database,[field],criteria) | |||
* | |||
* Excel Function: | |||
* DAVERAGE(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return integer | |||
* | |||
* @TODO The field argument is optional. If field is omitted, DCOUNT counts all records in the | |||
* database that match the criteria. | |||
* | |||
*/ | |||
public static function DCOUNT($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::COUNT( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DCOUNTA | |||
* | |||
* Counts the nonblank cells in a column of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DCOUNTA(database,[field],criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return integer | |||
* | |||
* @TODO The field argument is optional. If field is omitted, DCOUNTA counts all records in the | |||
* database that match the criteria. | |||
* | |||
*/ | |||
public static function DCOUNTA($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// reduce the database to a set of rows that match all the criteria | |||
$database = self::filter($database, $criteria); | |||
// extract an array of values for the requested column | |||
$colData = array(); | |||
foreach ($database as $row) { | |||
$colData[] = $row[$field]; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::COUNTA( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DGET | |||
* | |||
* Extracts a single value from a column of a list or database that matches conditions that you | |||
* specify. | |||
* | |||
* Excel Function: | |||
* DGET(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return mixed | |||
* | |||
*/ | |||
public static function DGET($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
$colData = self::getFilteredColumn($database, $field, $criteria); | |||
if (count($colData) > 1) { | |||
return PHPExcel_Calculation_Functions::NaN(); | |||
} | |||
return $colData[0]; | |||
} | |||
/** | |||
* DMAX | |||
* | |||
* Returns the largest number in a column of a list or database that matches conditions you that | |||
* specify. | |||
* | |||
* Excel Function: | |||
* DMAX(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DMAX($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::MAX( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DMIN | |||
* | |||
* Returns the smallest number in a column of a list or database that matches conditions you that | |||
* specify. | |||
* | |||
* Excel Function: | |||
* DMIN(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DMIN($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::MIN( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DPRODUCT | |||
* | |||
* Multiplies the values in a column of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DPRODUCT(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DPRODUCT($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_MathTrig::PRODUCT( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DSTDEV | |||
* | |||
* Estimates the standard deviation of a population based on a sample by using the numbers in a | |||
* column of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DSTDEV(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DSTDEV($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::STDEV( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DSTDEVP | |||
* | |||
* Calculates the standard deviation of a population based on the entire population by using the | |||
* numbers in a column of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DSTDEVP(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DSTDEVP($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::STDEVP( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DSUM | |||
* | |||
* Adds the numbers in a column of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DSUM(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DSUM($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_MathTrig::SUM( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DVAR | |||
* | |||
* Estimates the variance of a population based on a sample by using the numbers in a column | |||
* of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DVAR(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DVAR($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::VARFunc( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
/** | |||
* DVARP | |||
* | |||
* Calculates the variance of a population based on the entire population by using the numbers | |||
* in a column of a list or database that match conditions that you specify. | |||
* | |||
* Excel Function: | |||
* DVARP(database,field,criteria) | |||
* | |||
* @access public | |||
* @category Database Functions | |||
* @param mixed[] $database The range of cells that makes up the list or database. | |||
* A database is a list of related data in which rows of related | |||
* information are records, and columns of data are fields. The | |||
* first row of the list contains labels for each column. | |||
* @param string|integer $field Indicates which column is used in the function. Enter the | |||
* column label enclosed between double quotation marks, such as | |||
* "Age" or "Yield," or a number (without quotation marks) that | |||
* represents the position of the column within the list: 1 for | |||
* the first column, 2 for the second column, and so on. | |||
* @param mixed[] $criteria The range of cells that contains the conditions you specify. | |||
* You can use any range for the criteria argument, as long as it | |||
* includes at least one column label and at least one cell below | |||
* the column label in which you specify a condition for the | |||
* column. | |||
* @return float | |||
* | |||
*/ | |||
public static function DVARP($database, $field, $criteria) | |||
{ | |||
$field = self::fieldExtract($database, $field); | |||
if (is_null($field)) { | |||
return null; | |||
} | |||
// Return | |||
return PHPExcel_Calculation_Statistical::VARP( | |||
self::getFilteredColumn($database, $field, $criteria) | |||
); | |||
} | |||
} |
@ -0,0 +1,46 @@ | |||
<?php | |||
/** | |||
* PHPExcel_Calculation_Exception | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_Exception extends PHPExcel_Exception | |||
{ | |||
/** | |||
* Error handler callback | |||
* | |||
* @param mixed $code | |||
* @param mixed $string | |||
* @param mixed $file | |||
* @param mixed $line | |||
* @param mixed $context | |||
*/ | |||
public static function errorHandlerCallback($code, $string, $file, $line, $context) | |||
{ | |||
$e = new self($string, $code); | |||
$e->line = $line; | |||
$e->file = $file; | |||
throw $e; | |||
} | |||
} |
@ -0,0 +1,45 @@ | |||
<?php | |||
/** | |||
* PHPExcel_Calculation_ExceptionHandler | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_ExceptionHandler | |||
{ | |||
/** | |||
* Register errorhandler | |||
*/ | |||
public function __construct() | |||
{ | |||
set_error_handler(array('PHPExcel_Calculation_Exception', 'errorHandlerCallback'), E_ALL); | |||
} | |||
/** | |||
* Unregister errorhandler | |||
*/ | |||
public function __destruct() | |||
{ | |||
restore_error_handler(); | |||
} | |||
} |
@ -0,0 +1,622 @@ | |||
<?php | |||
/* | |||
PARTLY BASED ON: | |||
Copyright (c) 2007 E. W. Bachtal, Inc. | |||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software | |||
and associated documentation files (the "Software"), to deal in the Software without restriction, | |||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, | |||
subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all copies or substantial | |||
portions of the Software. | |||
The software is provided "as is", without warranty of any kind, express or implied, including but not | |||
limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In | |||
no event shall the authors or copyright holders be liable for any claim, damages or other liability, | |||
whether in an action of contract, tort or otherwise, arising from, out of or in connection with the | |||
software or the use or other dealings in the software. | |||
http://ewbi.blogs.com/develops/2007/03/excel_formula_p.html | |||
http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html | |||
*/ | |||
/** | |||
* PHPExcel_Calculation_FormulaParser | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_FormulaParser | |||
{ | |||
/* Character constants */ | |||
const QUOTE_DOUBLE = '"'; | |||
const QUOTE_SINGLE = '\''; | |||
const BRACKET_CLOSE = ']'; | |||
const BRACKET_OPEN = '['; | |||
const BRACE_OPEN = '{'; | |||
const BRACE_CLOSE = '}'; | |||
const PAREN_OPEN = '('; | |||
const PAREN_CLOSE = ')'; | |||
const SEMICOLON = ';'; | |||
const WHITESPACE = ' '; | |||
const COMMA = ','; | |||
const ERROR_START = '#'; | |||
const OPERATORS_SN = "+-"; | |||
const OPERATORS_INFIX = "+-*/^&=><"; | |||
const OPERATORS_POSTFIX = "%"; | |||
/** | |||
* Formula | |||
* | |||
* @var string | |||
*/ | |||
private $formula; | |||
/** | |||
* Tokens | |||
* | |||
* @var PHPExcel_Calculation_FormulaToken[] | |||
*/ | |||
private $tokens = array(); | |||
/** | |||
* Create a new PHPExcel_Calculation_FormulaParser | |||
* | |||
* @param string $pFormula Formula to parse | |||
* @throws PHPExcel_Calculation_Exception | |||
*/ | |||
public function __construct($pFormula = '') | |||
{ | |||
// Check parameters | |||
if (is_null($pFormula)) { | |||
throw new PHPExcel_Calculation_Exception("Invalid parameter passed: formula"); | |||
} | |||
// Initialise values | |||
$this->formula = trim($pFormula); | |||
// Parse! | |||
$this->parseToTokens(); | |||
} | |||
/** | |||
* Get Formula | |||
* | |||
* @return string | |||
*/ | |||
public function getFormula() | |||
{ | |||
return $this->formula; | |||
} | |||
/** | |||
* Get Token | |||
* | |||
* @param int $pId Token id | |||
* @return string | |||
* @throws PHPExcel_Calculation_Exception | |||
*/ | |||
public function getToken($pId = 0) | |||
{ | |||
if (isset($this->tokens[$pId])) { | |||
return $this->tokens[$pId]; | |||
} else { | |||
throw new PHPExcel_Calculation_Exception("Token with id $pId does not exist."); | |||
} | |||
} | |||
/** | |||
* Get Token count | |||
* | |||
* @return string | |||
*/ | |||
public function getTokenCount() | |||
{ | |||
return count($this->tokens); | |||
} | |||
/** | |||
* Get Tokens | |||
* | |||
* @return PHPExcel_Calculation_FormulaToken[] | |||
*/ | |||
public function getTokens() | |||
{ | |||
return $this->tokens; | |||
} | |||
/** | |||
* Parse to tokens | |||
*/ | |||
private function parseToTokens() | |||
{ | |||
// No attempt is made to verify formulas; assumes formulas are derived from Excel, where | |||
// they can only exist if valid; stack overflows/underflows sunk as nulls without exceptions. | |||
// Check if the formula has a valid starting = | |||
$formulaLength = strlen($this->formula); | |||
if ($formulaLength < 2 || $this->formula[0] != '=') { | |||
return; | |||
} | |||
// Helper variables | |||
$tokens1 = $tokens2 = $stack = array(); | |||
$inString = $inPath = $inRange = $inError = false; | |||
$token = $previousToken = $nextToken = null; | |||
$index = 1; | |||
$value = ''; | |||
$ERRORS = array("#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A"); | |||
$COMPARATORS_MULTI = array(">=", "<=", "<>"); | |||
while ($index < $formulaLength) { | |||
// state-dependent character evaluation (order is important) | |||
// double-quoted strings | |||
// embeds are doubled | |||
// end marks token | |||
if ($inString) { | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) { | |||
if ((($index + 2) <= $formulaLength) && ($this->formula[$index + 1] == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE)) { | |||
$value .= PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE; | |||
++$index; | |||
} else { | |||
$inString = false; | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_TEXT); | |||
$value = ""; | |||
} | |||
} else { | |||
$value .= $this->formula[$index]; | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// single-quoted strings (links) | |||
// embeds are double | |||
// end does not mark a token | |||
if ($inPath) { | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) { | |||
if ((($index + 2) <= $formulaLength) && ($this->formula[$index + 1] == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE)) { | |||
$value .= PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE; | |||
++$index; | |||
} else { | |||
$inPath = false; | |||
} | |||
} else { | |||
$value .= $this->formula[$index]; | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// bracked strings (R1C1 range index or linked workbook name) | |||
// no embeds (changed to "()" by Excel) | |||
// end does not mark a token | |||
if ($inRange) { | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::BRACKET_CLOSE) { | |||
$inRange = false; | |||
} | |||
$value .= $this->formula[$index]; | |||
++$index; | |||
continue; | |||
} | |||
// error values | |||
// end marks a token, determined from absolute list of values | |||
if ($inError) { | |||
$value .= $this->formula[$index]; | |||
++$index; | |||
if (in_array($value, $ERRORS)) { | |||
$inError = false; | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_ERROR); | |||
$value = ""; | |||
} | |||
continue; | |||
} | |||
// scientific notation check | |||
if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_SN, $this->formula[$index]) !== false) { | |||
if (strlen($value) > 1) { | |||
if (preg_match("/^[1-9]{1}(\.[0-9]+)?E{1}$/", $this->formula[$index]) != 0) { | |||
$value .= $this->formula[$index]; | |||
++$index; | |||
continue; | |||
} | |||
} | |||
} | |||
// independent character evaluation (order not important) | |||
// establish state-dependent character evaluations | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) { | |||
if (strlen($value > 0)) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$inString = true; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) { | |||
if (strlen($value) > 0) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$inPath = true; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::BRACKET_OPEN) { | |||
$inRange = true; | |||
$value .= PHPExcel_Calculation_FormulaParser::BRACKET_OPEN; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::ERROR_START) { | |||
if (strlen($value) > 0) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$inError = true; | |||
$value .= PHPExcel_Calculation_FormulaParser::ERROR_START; | |||
++$index; | |||
continue; | |||
} | |||
// mark start and end of arrays and array rows | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::BRACE_OPEN) { | |||
if (strlen($value) > 0) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$tmp = new PHPExcel_Calculation_FormulaToken("ARRAY", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
$tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::SEMICOLON) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
$tmp = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT); | |||
$tokens1[] = $tmp; | |||
$tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::BRACE_CLOSE) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
++$index; | |||
continue; | |||
} | |||
// trim white-space | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::WHITESPACE) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE); | |||
++$index; | |||
while (($this->formula[$index] == PHPExcel_Calculation_FormulaParser::WHITESPACE) && ($index < $formulaLength)) { | |||
++$index; | |||
} | |||
continue; | |||
} | |||
// multi-character comparators | |||
if (($index + 2) <= $formulaLength) { | |||
if (in_array(substr($this->formula, $index, 2), $COMPARATORS_MULTI)) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken(substr($this->formula, $index, 2), PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL); | |||
$index += 2; | |||
continue; | |||
} | |||
} | |||
// standard infix operators | |||
if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_INFIX, $this->formula[$index]) !== false) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] =new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula[$index], PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX); | |||
++$index; | |||
continue; | |||
} | |||
// standard postfix operators (only one) | |||
if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_POSTFIX, $this->formula[$index]) !== false) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula[$index], PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX); | |||
++$index; | |||
continue; | |||
} | |||
// start subexpression or function | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::PAREN_OPEN) { | |||
if (strlen($value) > 0) { | |||
$tmp = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
$value = ""; | |||
} else { | |||
$tmp = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// function, subexpression, or array parameters, or operand unions | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::COMMA) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$stack[] = $tmp; | |||
if ($tmp->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_UNION); | |||
} else { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT); | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// stop subexpression | |||
if ($this->formula[$index] == PHPExcel_Calculation_FormulaParser::PAREN_CLOSE) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
++$index; | |||
continue; | |||
} | |||
// token accumulation | |||
$value .= $this->formula[$index]; | |||
++$index; | |||
} | |||
// dump remaining accumulation | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
} | |||
// move tokenList to new set, excluding unnecessary white-space tokens and converting necessary ones to intersections | |||
$tokenCount = count($tokens1); | |||
for ($i = 0; $i < $tokenCount; ++$i) { | |||
$token = $tokens1[$i]; | |||
if (isset($tokens1[$i - 1])) { | |||
$previousToken = $tokens1[$i - 1]; | |||
} else { | |||
$previousToken = null; | |||
} | |||
if (isset($tokens1[$i + 1])) { | |||
$nextToken = $tokens1[$i + 1]; | |||
} else { | |||
$nextToken = null; | |||
} | |||
if (is_null($token)) { | |||
continue; | |||
} | |||
if ($token->getTokenType() != PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE) { | |||
$tokens2[] = $token; | |||
continue; | |||
} | |||
if (is_null($previousToken)) { | |||
continue; | |||
} | |||
if (! ( | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND) | |||
) ) { | |||
continue; | |||
} | |||
if (is_null($nextToken)) { | |||
continue; | |||
} | |||
if (! ( | |||
(($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) || | |||
(($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) || | |||
($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND) | |||
) ) { | |||
continue; | |||
} | |||
$tokens2[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_INTERSECTION); | |||
} | |||
// move tokens to final list, switching infix "-" operators to prefix when appropriate, switching infix "+" operators | |||
// to noop when appropriate, identifying operand and infix-operator subtypes, and pulling "@" from function names | |||
$this->tokens = array(); | |||
$tokenCount = count($tokens2); | |||
for ($i = 0; $i < $tokenCount; ++$i) { | |||
$token = $tokens2[$i]; | |||
if (isset($tokens2[$i - 1])) { | |||
$previousToken = $tokens2[$i - 1]; | |||
} else { | |||
$previousToken = null; | |||
} | |||
if (isset($tokens2[$i + 1])) { | |||
$nextToken = $tokens2[$i + 1]; | |||
} else { | |||
$nextToken = null; | |||
} | |||
if (is_null($token)) { | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "-") { | |||
if ($i == 0) { | |||
$token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX); | |||
} elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH); | |||
} else { | |||
$token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX); | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "+") { | |||
if ($i == 0) { | |||
continue; | |||
} elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH); | |||
} else { | |||
continue; | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && | |||
$token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) { | |||
if (strpos("<>=", substr($token->getValue(), 0, 1)) !== false) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL); | |||
} elseif ($token->getValue() == "&") { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_CONCATENATION); | |||
} else { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH); | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND && | |||
$token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) { | |||
if (!is_numeric($token->getValue())) { | |||
if (strtoupper($token->getValue()) == "TRUE" || strtoupper($token->getValue() == "FALSE")) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL); | |||
} else { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_RANGE); | |||
} | |||
} else { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NUMBER); | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) { | |||
if (strlen($token->getValue() > 0)) { | |||
if (substr($token->getValue(), 0, 1) == "@") { | |||
$token->setValue(substr($token->getValue(), 1)); | |||
} | |||
} | |||
} | |||
$this->tokens[] = $token; | |||
} | |||
} | |||
} |
@ -0,0 +1,622 @@ | |||
<?php | |||
/* | |||
PARTLY BASED ON: | |||
Copyright (c) 2007 E. W. Bachtal, Inc. | |||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software | |||
and associated documentation files (the "Software"), to deal in the Software without restriction, | |||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, | |||
subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all copies or substantial | |||
portions of the Software. | |||
The software is provided "as is", without warranty of any kind, express or implied, including but not | |||
limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In | |||
no event shall the authors or copyright holders be liable for any claim, damages or other liability, | |||
whether in an action of contract, tort or otherwise, arising from, out of or in connection with the | |||
software or the use or other dealings in the software. | |||
http://ewbi.blogs.com/develops/2007/03/excel_formula_p.html | |||
http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html | |||
*/ | |||
/** | |||
* PHPExcel_Calculation_FormulaParser | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_FormulaParser | |||
{ | |||
/* Character constants */ | |||
const QUOTE_DOUBLE = '"'; | |||
const QUOTE_SINGLE = '\''; | |||
const BRACKET_CLOSE = ']'; | |||
const BRACKET_OPEN = '['; | |||
const BRACE_OPEN = '{'; | |||
const BRACE_CLOSE = '}'; | |||
const PAREN_OPEN = '('; | |||
const PAREN_CLOSE = ')'; | |||
const SEMICOLON = ';'; | |||
const WHITESPACE = ' '; | |||
const COMMA = ','; | |||
const ERROR_START = '#'; | |||
const OPERATORS_SN = "+-"; | |||
const OPERATORS_INFIX = "+-*/^&=><"; | |||
const OPERATORS_POSTFIX = "%"; | |||
/** | |||
* Formula | |||
* | |||
* @var string | |||
*/ | |||
private $formula; | |||
/** | |||
* Tokens | |||
* | |||
* @var PHPExcel_Calculation_FormulaToken[] | |||
*/ | |||
private $tokens = array(); | |||
/** | |||
* Create a new PHPExcel_Calculation_FormulaParser | |||
* | |||
* @param string $pFormula Formula to parse | |||
* @throws PHPExcel_Calculation_Exception | |||
*/ | |||
public function __construct($pFormula = '') | |||
{ | |||
// Check parameters | |||
if (is_null($pFormula)) { | |||
throw new PHPExcel_Calculation_Exception("Invalid parameter passed: formula"); | |||
} | |||
// Initialise values | |||
$this->formula = trim($pFormula); | |||
// Parse! | |||
$this->parseToTokens(); | |||
} | |||
/** | |||
* Get Formula | |||
* | |||
* @return string | |||
*/ | |||
public function getFormula() | |||
{ | |||
return $this->formula; | |||
} | |||
/** | |||
* Get Token | |||
* | |||
* @param int $pId Token id | |||
* @return string | |||
* @throws PHPExcel_Calculation_Exception | |||
*/ | |||
public function getToken($pId = 0) | |||
{ | |||
if (isset($this->tokens[$pId])) { | |||
return $this->tokens[$pId]; | |||
} else { | |||
throw new PHPExcel_Calculation_Exception("Token with id $pId does not exist."); | |||
} | |||
} | |||
/** | |||
* Get Token count | |||
* | |||
* @return string | |||
*/ | |||
public function getTokenCount() | |||
{ | |||
return count($this->tokens); | |||
} | |||
/** | |||
* Get Tokens | |||
* | |||
* @return PHPExcel_Calculation_FormulaToken[] | |||
*/ | |||
public function getTokens() | |||
{ | |||
return $this->tokens; | |||
} | |||
/** | |||
* Parse to tokens | |||
*/ | |||
private function parseToTokens() | |||
{ | |||
// No attempt is made to verify formulas; assumes formulas are derived from Excel, where | |||
// they can only exist if valid; stack overflows/underflows sunk as nulls without exceptions. | |||
// Check if the formula has a valid starting = | |||
$formulaLength = strlen($this->formula); | |||
if ($formulaLength < 2 || $this->formula{0} != '=') { | |||
return; | |||
} | |||
// Helper variables | |||
$tokens1 = $tokens2 = $stack = array(); | |||
$inString = $inPath = $inRange = $inError = false; | |||
$token = $previousToken = $nextToken = null; | |||
$index = 1; | |||
$value = ''; | |||
$ERRORS = array("#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A"); | |||
$COMPARATORS_MULTI = array(">=", "<=", "<>"); | |||
while ($index < $formulaLength) { | |||
// state-dependent character evaluation (order is important) | |||
// double-quoted strings | |||
// embeds are doubled | |||
// end marks token | |||
if ($inString) { | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) { | |||
if ((($index + 2) <= $formulaLength) && ($this->formula{$index + 1} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE)) { | |||
$value .= PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE; | |||
++$index; | |||
} else { | |||
$inString = false; | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_TEXT); | |||
$value = ""; | |||
} | |||
} else { | |||
$value .= $this->formula{$index}; | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// single-quoted strings (links) | |||
// embeds are double | |||
// end does not mark a token | |||
if ($inPath) { | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) { | |||
if ((($index + 2) <= $formulaLength) && ($this->formula{$index + 1} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE)) { | |||
$value .= PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE; | |||
++$index; | |||
} else { | |||
$inPath = false; | |||
} | |||
} else { | |||
$value .= $this->formula{$index}; | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// bracked strings (R1C1 range index or linked workbook name) | |||
// no embeds (changed to "()" by Excel) | |||
// end does not mark a token | |||
if ($inRange) { | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACKET_CLOSE) { | |||
$inRange = false; | |||
} | |||
$value .= $this->formula{$index}; | |||
++$index; | |||
continue; | |||
} | |||
// error values | |||
// end marks a token, determined from absolute list of values | |||
if ($inError) { | |||
$value .= $this->formula{$index}; | |||
++$index; | |||
if (in_array($value, $ERRORS)) { | |||
$inError = false; | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_ERROR); | |||
$value = ""; | |||
} | |||
continue; | |||
} | |||
// scientific notation check | |||
if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_SN, $this->formula{$index}) !== false) { | |||
if (strlen($value) > 1) { | |||
if (preg_match("/^[1-9]{1}(\.[0-9]+)?E{1}$/", $this->formula{$index}) != 0) { | |||
$value .= $this->formula{$index}; | |||
++$index; | |||
continue; | |||
} | |||
} | |||
} | |||
// independent character evaluation (order not important) | |||
// establish state-dependent character evaluations | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_DOUBLE) { | |||
if (strlen($value > 0)) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$inString = true; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::QUOTE_SINGLE) { | |||
if (strlen($value) > 0) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$inPath = true; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACKET_OPEN) { | |||
$inRange = true; | |||
$value .= PHPExcel_Calculation_FormulaParser::BRACKET_OPEN; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::ERROR_START) { | |||
if (strlen($value) > 0) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$inError = true; | |||
$value .= PHPExcel_Calculation_FormulaParser::ERROR_START; | |||
++$index; | |||
continue; | |||
} | |||
// mark start and end of arrays and array rows | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACE_OPEN) { | |||
if (strlen($value) > 0) { | |||
// unexpected | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN); | |||
$value = ""; | |||
} | |||
$tmp = new PHPExcel_Calculation_FormulaToken("ARRAY", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
$tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::SEMICOLON) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
$tmp = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT); | |||
$tokens1[] = $tmp; | |||
$tmp = new PHPExcel_Calculation_FormulaToken("ARRAYROW", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
++$index; | |||
continue; | |||
} | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::BRACE_CLOSE) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
++$index; | |||
continue; | |||
} | |||
// trim white-space | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::WHITESPACE) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE); | |||
++$index; | |||
while (($this->formula{$index} == PHPExcel_Calculation_FormulaParser::WHITESPACE) && ($index < $formulaLength)) { | |||
++$index; | |||
} | |||
continue; | |||
} | |||
// multi-character comparators | |||
if (($index + 2) <= $formulaLength) { | |||
if (in_array(substr($this->formula, $index, 2), $COMPARATORS_MULTI)) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken(substr($this->formula, $index, 2), PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL); | |||
$index += 2; | |||
continue; | |||
} | |||
} | |||
// standard infix operators | |||
if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_INFIX, $this->formula{$index}) !== false) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] =new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula{$index}, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX); | |||
++$index; | |||
continue; | |||
} | |||
// standard postfix operators (only one) | |||
if (strpos(PHPExcel_Calculation_FormulaParser::OPERATORS_POSTFIX, $this->formula{$index}) !== false) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($this->formula{$index}, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX); | |||
++$index; | |||
continue; | |||
} | |||
// start subexpression or function | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::PAREN_OPEN) { | |||
if (strlen($value) > 0) { | |||
$tmp = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
$value = ""; | |||
} else { | |||
$tmp = new PHPExcel_Calculation_FormulaToken("", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START); | |||
$tokens1[] = $tmp; | |||
$stack[] = clone $tmp; | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// function, subexpression, or array parameters, or operand unions | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::COMMA) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$stack[] = $tmp; | |||
if ($tmp->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_UNION); | |||
} else { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken(",", PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_ARGUMENT); | |||
} | |||
++$index; | |||
continue; | |||
} | |||
// stop subexpression | |||
if ($this->formula{$index} == PHPExcel_Calculation_FormulaParser::PAREN_CLOSE) { | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
$value = ""; | |||
} | |||
$tmp = array_pop($stack); | |||
$tmp->setValue(""); | |||
$tmp->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP); | |||
$tokens1[] = $tmp; | |||
++$index; | |||
continue; | |||
} | |||
// token accumulation | |||
$value .= $this->formula{$index}; | |||
++$index; | |||
} | |||
// dump remaining accumulation | |||
if (strlen($value) > 0) { | |||
$tokens1[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND); | |||
} | |||
// move tokenList to new set, excluding unnecessary white-space tokens and converting necessary ones to intersections | |||
$tokenCount = count($tokens1); | |||
for ($i = 0; $i < $tokenCount; ++$i) { | |||
$token = $tokens1[$i]; | |||
if (isset($tokens1[$i - 1])) { | |||
$previousToken = $tokens1[$i - 1]; | |||
} else { | |||
$previousToken = null; | |||
} | |||
if (isset($tokens1[$i + 1])) { | |||
$nextToken = $tokens1[$i + 1]; | |||
} else { | |||
$nextToken = null; | |||
} | |||
if (is_null($token)) { | |||
continue; | |||
} | |||
if ($token->getTokenType() != PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_WHITESPACE) { | |||
$tokens2[] = $token; | |||
continue; | |||
} | |||
if (is_null($previousToken)) { | |||
continue; | |||
} | |||
if (! ( | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND) | |||
) ) { | |||
continue; | |||
} | |||
if (is_null($nextToken)) { | |||
continue; | |||
} | |||
if (! ( | |||
(($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) || | |||
(($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && ($nextToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_START)) || | |||
($nextToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND) | |||
) ) { | |||
continue; | |||
} | |||
$tokens2[] = new PHPExcel_Calculation_FormulaToken($value, PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX, PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_INTERSECTION); | |||
} | |||
// move tokens to final list, switching infix "-" operators to prefix when appropriate, switching infix "+" operators | |||
// to noop when appropriate, identifying operand and infix-operator subtypes, and pulling "@" from function names | |||
$this->tokens = array(); | |||
$tokenCount = count($tokens2); | |||
for ($i = 0; $i < $tokenCount; ++$i) { | |||
$token = $tokens2[$i]; | |||
if (isset($tokens2[$i - 1])) { | |||
$previousToken = $tokens2[$i - 1]; | |||
} else { | |||
$previousToken = null; | |||
} | |||
if (isset($tokens2[$i + 1])) { | |||
$nextToken = $tokens2[$i + 1]; | |||
} else { | |||
$nextToken = null; | |||
} | |||
if (is_null($token)) { | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "-") { | |||
if ($i == 0) { | |||
$token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX); | |||
} elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH); | |||
} else { | |||
$token->setTokenType(PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPREFIX); | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && $token->getValue() == "+") { | |||
if ($i == 0) { | |||
continue; | |||
} elseif ((($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
(($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_SUBEXPRESSION) && | |||
($previousToken->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_STOP)) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORPOSTFIX) || | |||
($previousToken->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND)) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH); | |||
} else { | |||
continue; | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERATORINFIX && | |||
$token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) { | |||
if (strpos("<>=", substr($token->getValue(), 0, 1)) !== false) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL); | |||
} elseif ($token->getValue() == "&") { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_CONCATENATION); | |||
} else { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_MATH); | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_OPERAND && | |||
$token->getTokenSubType() == PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) { | |||
if (!is_numeric($token->getValue())) { | |||
if (strtoupper($token->getValue()) == "TRUE" || strtoupper($token->getValue() == "FALSE")) { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_LOGICAL); | |||
} else { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_RANGE); | |||
} | |||
} else { | |||
$token->setTokenSubType(PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NUMBER); | |||
} | |||
$this->tokens[] = $token; | |||
continue; | |||
} | |||
if ($token->getTokenType() == PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_FUNCTION) { | |||
if (strlen($token->getValue() > 0)) { | |||
if (substr($token->getValue(), 0, 1) == "@") { | |||
$token->setValue(substr($token->getValue(), 1)); | |||
} | |||
} | |||
} | |||
$this->tokens[] = $token; | |||
} | |||
} | |||
} |
@ -0,0 +1,176 @@ | |||
<?php | |||
/* | |||
PARTLY BASED ON: | |||
Copyright (c) 2007 E. W. Bachtal, Inc. | |||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software | |||
and associated documentation files (the "Software"), to deal in the Software without restriction, | |||
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, | |||
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, | |||
subject to the following conditions: | |||
The above copyright notice and this permission notice shall be included in all copies or substantial | |||
portions of the Software. | |||
The software is provided "as is", without warranty of any kind, express or implied, including but not | |||
limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In | |||
no event shall the authors or copyright holders be liable for any claim, damages or other liability, | |||
whether in an action of contract, tort or otherwise, arising from, out of or in connection with the | |||
software or the use or other dealings in the software. | |||
http://ewbi.blogs.com/develops/2007/03/excel_formula_p.html | |||
http://ewbi.blogs.com/develops/2004/12/excel_formula_p.html | |||
*/ | |||
/** | |||
* PHPExcel_Calculation_FormulaToken | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_FormulaToken | |||
{ | |||
/* Token types */ | |||
const TOKEN_TYPE_NOOP = 'Noop'; | |||
const TOKEN_TYPE_OPERAND = 'Operand'; | |||
const TOKEN_TYPE_FUNCTION = 'Function'; | |||
const TOKEN_TYPE_SUBEXPRESSION = 'Subexpression'; | |||
const TOKEN_TYPE_ARGUMENT = 'Argument'; | |||
const TOKEN_TYPE_OPERATORPREFIX = 'OperatorPrefix'; | |||
const TOKEN_TYPE_OPERATORINFIX = 'OperatorInfix'; | |||
const TOKEN_TYPE_OPERATORPOSTFIX = 'OperatorPostfix'; | |||
const TOKEN_TYPE_WHITESPACE = 'Whitespace'; | |||
const TOKEN_TYPE_UNKNOWN = 'Unknown'; | |||
/* Token subtypes */ | |||
const TOKEN_SUBTYPE_NOTHING = 'Nothing'; | |||
const TOKEN_SUBTYPE_START = 'Start'; | |||
const TOKEN_SUBTYPE_STOP = 'Stop'; | |||
const TOKEN_SUBTYPE_TEXT = 'Text'; | |||
const TOKEN_SUBTYPE_NUMBER = 'Number'; | |||
const TOKEN_SUBTYPE_LOGICAL = 'Logical'; | |||
const TOKEN_SUBTYPE_ERROR = 'Error'; | |||
const TOKEN_SUBTYPE_RANGE = 'Range'; | |||
const TOKEN_SUBTYPE_MATH = 'Math'; | |||
const TOKEN_SUBTYPE_CONCATENATION = 'Concatenation'; | |||
const TOKEN_SUBTYPE_INTERSECTION = 'Intersection'; | |||
const TOKEN_SUBTYPE_UNION = 'Union'; | |||
/** | |||
* Value | |||
* | |||
* @var string | |||
*/ | |||
private $value; | |||
/** | |||
* Token Type (represented by TOKEN_TYPE_*) | |||
* | |||
* @var string | |||
*/ | |||
private $tokenType; | |||
/** | |||
* Token SubType (represented by TOKEN_SUBTYPE_*) | |||
* | |||
* @var string | |||
*/ | |||
private $tokenSubType; | |||
/** | |||
* Create a new PHPExcel_Calculation_FormulaToken | |||
* | |||
* @param string $pValue | |||
* @param string $pTokenType Token type (represented by TOKEN_TYPE_*) | |||
* @param string $pTokenSubType Token Subtype (represented by TOKEN_SUBTYPE_*) | |||
*/ | |||
public function __construct($pValue, $pTokenType = PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN, $pTokenSubType = PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) | |||
{ | |||
// Initialise values | |||
$this->value = $pValue; | |||
$this->tokenType = $pTokenType; | |||
$this->tokenSubType = $pTokenSubType; | |||
} | |||
/** | |||
* Get Value | |||
* | |||
* @return string | |||
*/ | |||
public function getValue() | |||
{ | |||
return $this->value; | |||
} | |||
/** | |||
* Set Value | |||
* | |||
* @param string $value | |||
*/ | |||
public function setValue($value) | |||
{ | |||
$this->value = $value; | |||
} | |||
/** | |||
* Get Token Type (represented by TOKEN_TYPE_*) | |||
* | |||
* @return string | |||
*/ | |||
public function getTokenType() | |||
{ | |||
return $this->tokenType; | |||
} | |||
/** | |||
* Set Token Type | |||
* | |||
* @param string $value | |||
*/ | |||
public function setTokenType($value = PHPExcel_Calculation_FormulaToken::TOKEN_TYPE_UNKNOWN) | |||
{ | |||
$this->tokenType = $value; | |||
} | |||
/** | |||
* Get Token SubType (represented by TOKEN_SUBTYPE_*) | |||
* | |||
* @return string | |||
*/ | |||
public function getTokenSubType() | |||
{ | |||
return $this->tokenSubType; | |||
} | |||
/** | |||
* Set Token SubType | |||
* | |||
* @param string $value | |||
*/ | |||
public function setTokenSubType($value = PHPExcel_Calculation_FormulaToken::TOKEN_SUBTYPE_NOTHING) | |||
{ | |||
$this->tokenSubType = $value; | |||
} | |||
} |
@ -0,0 +1,148 @@ | |||
<?php | |||
/** | |||
* PHPExcel_Calculation_Function | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_Function | |||
{ | |||
/* Function categories */ | |||
const CATEGORY_CUBE = 'Cube'; | |||
const CATEGORY_DATABASE = 'Database'; | |||
const CATEGORY_DATE_AND_TIME = 'Date and Time'; | |||
const CATEGORY_ENGINEERING = 'Engineering'; | |||
const CATEGORY_FINANCIAL = 'Financial'; | |||
const CATEGORY_INFORMATION = 'Information'; | |||
const CATEGORY_LOGICAL = 'Logical'; | |||
const CATEGORY_LOOKUP_AND_REFERENCE = 'Lookup and Reference'; | |||
const CATEGORY_MATH_AND_TRIG = 'Math and Trig'; | |||
const CATEGORY_STATISTICAL = 'Statistical'; | |||
const CATEGORY_TEXT_AND_DATA = 'Text and Data'; | |||
/** | |||
* Category (represented by CATEGORY_*) | |||
* | |||
* @var string | |||
*/ | |||
private $category; | |||
/** | |||
* Excel name | |||
* | |||
* @var string | |||
*/ | |||
private $excelName; | |||
/** | |||
* PHPExcel name | |||
* | |||
* @var string | |||
*/ | |||
private $phpExcelName; | |||
/** | |||
* Create a new PHPExcel_Calculation_Function | |||
* | |||
* @param string $pCategory Category (represented by CATEGORY_*) | |||
* @param string $pExcelName Excel function name | |||
* @param string $pPHPExcelName PHPExcel function mapping | |||
* @throws PHPExcel_Calculation_Exception | |||
*/ | |||
public function __construct($pCategory = null, $pExcelName = null, $pPHPExcelName = null) | |||
{ | |||
if (($pCategory !== null) && ($pExcelName !== null) && ($pPHPExcelName !== null)) { | |||
// Initialise values | |||
$this->category = $pCategory; | |||
$this->excelName = $pExcelName; | |||
$this->phpExcelName = $pPHPExcelName; | |||
} else { | |||
throw new PHPExcel_Calculation_Exception("Invalid parameters passed."); | |||
} | |||
} | |||
/** | |||
* Get Category (represented by CATEGORY_*) | |||
* | |||
* @return string | |||
*/ | |||
public function getCategory() | |||
{ | |||
return $this->category; | |||
} | |||
/** | |||
* Set Category (represented by CATEGORY_*) | |||
* | |||
* @param string $value | |||
* @throws PHPExcel_Calculation_Exception | |||
*/ | |||
public function setCategory($value = null) | |||
{ | |||
if (!is_null($value)) { | |||
$this->category = $value; | |||
} else { | |||
throw new PHPExcel_Calculation_Exception("Invalid parameter passed."); | |||
} | |||
} | |||
/** | |||
* Get Excel name | |||
* | |||
* @return string | |||
*/ | |||
public function getExcelName() | |||
{ | |||
return $this->excelName; | |||
} | |||
/** | |||
* Set Excel name | |||
* | |||
* @param string $value | |||
*/ | |||
public function setExcelName($value) | |||
{ | |||
$this->excelName = $value; | |||
} | |||
/** | |||
* Get PHPExcel name | |||
* | |||
* @return string | |||
*/ | |||
public function getPHPExcelName() | |||
{ | |||
return $this->phpExcelName; | |||
} | |||
/** | |||
* Set PHPExcel name | |||
* | |||
* @param string $value | |||
*/ | |||
public function setPHPExcelName($value) | |||
{ | |||
$this->phpExcelName = $value; | |||
} | |||
} |
@ -0,0 +1,760 @@ | |||
<?php | |||
/** PHPExcel root directory */ | |||
if (!defined('PHPEXCEL_ROOT')) { | |||
/** | |||
* @ignore | |||
*/ | |||
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); | |||
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); | |||
} | |||
/** MAX_VALUE */ | |||
define('MAX_VALUE', 1.2e308); | |||
/** 2 / PI */ | |||
define('M_2DIVPI', 0.63661977236758134307553505349006); | |||
/** MAX_ITERATIONS */ | |||
define('MAX_ITERATIONS', 256); | |||
/** PRECISION */ | |||
define('PRECISION', 8.88E-016); | |||
/** | |||
* PHPExcel_Calculation_Functions | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_Functions | |||
{ | |||
/** constants */ | |||
const COMPATIBILITY_EXCEL = 'Excel'; | |||
const COMPATIBILITY_GNUMERIC = 'Gnumeric'; | |||
const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc'; | |||
const RETURNDATE_PHP_NUMERIC = 'P'; | |||
const RETURNDATE_PHP_OBJECT = 'O'; | |||
const RETURNDATE_EXCEL = 'E'; | |||
/** | |||
* Compatibility mode to use for error checking and responses | |||
* | |||
* @access private | |||
* @var string | |||
*/ | |||
protected static $compatibilityMode = self::COMPATIBILITY_EXCEL; | |||
/** | |||
* Data Type to use when returning date values | |||
* | |||
* @access private | |||
* @var string | |||
*/ | |||
protected static $returnDateType = self::RETURNDATE_EXCEL; | |||
/** | |||
* List of error codes | |||
* | |||
* @access private | |||
* @var array | |||
*/ | |||
protected static $errorCodes = array( | |||
'null' => '#NULL!', | |||
'divisionbyzero' => '#DIV/0!', | |||
'value' => '#VALUE!', | |||
'reference' => '#REF!', | |||
'name' => '#NAME?', | |||
'num' => '#NUM!', | |||
'na' => '#N/A', | |||
'gettingdata' => '#GETTING_DATA' | |||
); | |||
/** | |||
* Set the Compatibility Mode | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @param string $compatibilityMode Compatibility Mode | |||
* Permitted values are: | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc' | |||
* @return boolean (Success or Failure) | |||
*/ | |||
public static function setCompatibilityMode($compatibilityMode) | |||
{ | |||
if (($compatibilityMode == self::COMPATIBILITY_EXCEL) || | |||
($compatibilityMode == self::COMPATIBILITY_GNUMERIC) || | |||
($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) { | |||
self::$compatibilityMode = $compatibilityMode; | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Return the current Compatibility Mode | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @return string Compatibility Mode | |||
* Possible Return values are: | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc' | |||
*/ | |||
public static function getCompatibilityMode() | |||
{ | |||
return self::$compatibilityMode; | |||
} | |||
/** | |||
* Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object) | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @param string $returnDateType Return Date Format | |||
* Permitted values are: | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E' | |||
* @return boolean Success or failure | |||
*/ | |||
public static function setReturnDateType($returnDateType) | |||
{ | |||
if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) || | |||
($returnDateType == self::RETURNDATE_PHP_OBJECT) || | |||
($returnDateType == self::RETURNDATE_EXCEL)) { | |||
self::$returnDateType = $returnDateType; | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object) | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @return string Return Date Format | |||
* Possible Return values are: | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E' | |||
*/ | |||
public static function getReturnDateType() | |||
{ | |||
return self::$returnDateType; | |||
} | |||
/** | |||
* DUMMY | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #Not Yet Implemented | |||
*/ | |||
public static function DUMMY() | |||
{ | |||
return '#Not Yet Implemented'; | |||
} | |||
/** | |||
* DIV0 | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #Not Yet Implemented | |||
*/ | |||
public static function DIV0() | |||
{ | |||
return self::$errorCodes['divisionbyzero']; | |||
} | |||
/** | |||
* NA | |||
* | |||
* Excel Function: | |||
* =NA() | |||
* | |||
* Returns the error value #N/A | |||
* #N/A is the error value that means "no value is available." | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @return string #N/A! | |||
*/ | |||
public static function NA() | |||
{ | |||
return self::$errorCodes['na']; | |||
} | |||
/** | |||
* NaN | |||
* | |||
* Returns the error value #NUM! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #NUM! | |||
*/ | |||
public static function NaN() | |||
{ | |||
return self::$errorCodes['num']; | |||
} | |||
/** | |||
* NAME | |||
* | |||
* Returns the error value #NAME? | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #NAME? | |||
*/ | |||
public static function NAME() | |||
{ | |||
return self::$errorCodes['name']; | |||
} | |||
/** | |||
* REF | |||
* | |||
* Returns the error value #REF! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #REF! | |||
*/ | |||
public static function REF() | |||
{ | |||
return self::$errorCodes['reference']; | |||
} | |||
/** | |||
* NULL | |||
* | |||
* Returns the error value #NULL! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #NULL! | |||
*/ | |||
public static function NULL() | |||
{ | |||
return self::$errorCodes['null']; | |||
} | |||
/** | |||
* VALUE | |||
* | |||
* Returns the error value #VALUE! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #VALUE! | |||
*/ | |||
public static function VALUE() | |||
{ | |||
return self::$errorCodes['value']; | |||
} | |||
public static function isMatrixValue($idx) | |||
{ | |||
return ((substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0)); | |||
} | |||
public static function isValue($idx) | |||
{ | |||
return (substr_count($idx, '.') == 0); | |||
} | |||
public static function isCellValue($idx) | |||
{ | |||
return (substr_count($idx, '.') > 1); | |||
} | |||
public static function ifCondition($condition) | |||
{ | |||
$condition = PHPExcel_Calculation_Functions::flattenSingleValue($condition); | |||
if (!isset($condition[0])) { | |||
$condition = '=""'; | |||
} | |||
if (!in_array($condition[0], array('>', '<', '='))) { | |||
if (!is_numeric($condition)) { | |||
$condition = PHPExcel_Calculation::wrapResult(strtoupper($condition)); | |||
} | |||
return '=' . $condition; | |||
} else { | |||
preg_match('/([<>=]+)(.*)/', $condition, $matches); | |||
list(, $operator, $operand) = $matches; | |||
if (!is_numeric($operand)) { | |||
$operand = str_replace('"', '""', $operand); | |||
$operand = PHPExcel_Calculation::wrapResult(strtoupper($operand)); | |||
} | |||
return $operator.$operand; | |||
} | |||
} | |||
/** | |||
* ERROR_TYPE | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function ERROR_TYPE($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
$i = 1; | |||
foreach (self::$errorCodes as $errorCode) { | |||
if ($value === $errorCode) { | |||
return $i; | |||
} | |||
++$i; | |||
} | |||
return self::NA(); | |||
} | |||
/** | |||
* IS_BLANK | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_BLANK($value = null) | |||
{ | |||
if (!is_null($value)) { | |||
$value = self::flattenSingleValue($value); | |||
} | |||
return is_null($value); | |||
} | |||
/** | |||
* IS_ERR | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_ERR($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return self::IS_ERROR($value) && (!self::IS_NA($value)); | |||
} | |||
/** | |||
* IS_ERROR | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_ERROR($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if (!is_string($value)) { | |||
return false; | |||
} | |||
return in_array($value, array_values(self::$errorCodes)); | |||
} | |||
/** | |||
* IS_NA | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_NA($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return ($value === self::NA()); | |||
} | |||
/** | |||
* IS_EVEN | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_EVEN($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if ($value === null) { | |||
return self::NAME(); | |||
} elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { | |||
return self::VALUE(); | |||
} | |||
return ($value % 2 == 0); | |||
} | |||
/** | |||
* IS_ODD | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_ODD($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if ($value === null) { | |||
return self::NAME(); | |||
} elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { | |||
return self::VALUE(); | |||
} | |||
return (abs($value) % 2 == 1); | |||
} | |||
/** | |||
* IS_NUMBER | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_NUMBER($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if (is_string($value)) { | |||
return false; | |||
} | |||
return is_numeric($value); | |||
} | |||
/** | |||
* IS_LOGICAL | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_LOGICAL($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return is_bool($value); | |||
} | |||
/** | |||
* IS_TEXT | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_TEXT($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return (is_string($value) && !self::IS_ERROR($value)); | |||
} | |||
/** | |||
* IS_NONTEXT | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_NONTEXT($value = null) | |||
{ | |||
return !self::IS_TEXT($value); | |||
} | |||
/** | |||
* VERSION | |||
* | |||
* @return string Version information | |||
*/ | |||
public static function VERSION() | |||
{ | |||
return 'PHPExcel ##VERSION##, ##DATE##'; | |||
} | |||
/** | |||
* N | |||
* | |||
* Returns a value converted to a number | |||
* | |||
* @param value The value you want converted | |||
* @return number N converts values listed in the following table | |||
* If value is or refers to N returns | |||
* A number That number | |||
* A date The serial number of that date | |||
* TRUE 1 | |||
* FALSE 0 | |||
* An error value The error value | |||
* Anything else 0 | |||
*/ | |||
public static function N($value = null) | |||
{ | |||
while (is_array($value)) { | |||
$value = array_shift($value); | |||
} | |||
switch (gettype($value)) { | |||
case 'double': | |||
case 'float': | |||
case 'integer': | |||
return $value; | |||
case 'boolean': | |||
return (integer) $value; | |||
case 'string': | |||
// Errors | |||
if ((strlen($value) > 0) && ($value[0] == '#')) { | |||
return $value; | |||
} | |||
break; | |||
} | |||
return 0; | |||
} | |||
/** | |||
* TYPE | |||
* | |||
* Returns a number that identifies the type of a value | |||
* | |||
* @param value The value you want tested | |||
* @return number N converts values listed in the following table | |||
* If value is or refers to N returns | |||
* A number 1 | |||
* Text 2 | |||
* Logical Value 4 | |||
* An error value 16 | |||
* Array or Matrix 64 | |||
*/ | |||
public static function TYPE($value = null) | |||
{ | |||
$value = self::flattenArrayIndexed($value); | |||
if (is_array($value) && (count($value) > 1)) { | |||
end($value); | |||
$a = key($value); | |||
// Range of cells is an error | |||
if (self::isCellValue($a)) { | |||
return 16; | |||
// Test for Matrix | |||
} elseif (self::isMatrixValue($a)) { | |||
return 64; | |||
} | |||
} elseif (empty($value)) { | |||
// Empty Cell | |||
return 1; | |||
} | |||
$value = self::flattenSingleValue($value); | |||
if (($value === null) || (is_float($value)) || (is_int($value))) { | |||
return 1; | |||
} elseif (is_bool($value)) { | |||
return 4; | |||
} elseif (is_array($value)) { | |||
return 64; | |||
} elseif (is_string($value)) { | |||
// Errors | |||
if ((strlen($value) > 0) && ($value[0] == '#')) { | |||
return 16; | |||
} | |||
return 2; | |||
} | |||
return 0; | |||
} | |||
/** | |||
* Convert a multi-dimensional array to a simple 1-dimensional array | |||
* | |||
* @param array $array Array to be flattened | |||
* @return array Flattened array | |||
*/ | |||
public static function flattenArray($array) | |||
{ | |||
if (!is_array($array)) { | |||
return (array) $array; | |||
} | |||
$arrayValues = array(); | |||
foreach ($array as $value) { | |||
if (is_array($value)) { | |||
foreach ($value as $val) { | |||
if (is_array($val)) { | |||
foreach ($val as $v) { | |||
$arrayValues[] = $v; | |||
} | |||
} else { | |||
$arrayValues[] = $val; | |||
} | |||
} | |||
} else { | |||
$arrayValues[] = $value; | |||
} | |||
} | |||
return $arrayValues; | |||
} | |||
/** | |||
* Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing | |||
* | |||
* @param array $array Array to be flattened | |||
* @return array Flattened array | |||
*/ | |||
public static function flattenArrayIndexed($array) | |||
{ | |||
if (!is_array($array)) { | |||
return (array) $array; | |||
} | |||
$arrayValues = array(); | |||
foreach ($array as $k1 => $value) { | |||
if (is_array($value)) { | |||
foreach ($value as $k2 => $val) { | |||
if (is_array($val)) { | |||
foreach ($val as $k3 => $v) { | |||
$arrayValues[$k1.'.'.$k2.'.'.$k3] = $v; | |||
} | |||
} else { | |||
$arrayValues[$k1.'.'.$k2] = $val; | |||
} | |||
} | |||
} else { | |||
$arrayValues[$k1] = $value; | |||
} | |||
} | |||
return $arrayValues; | |||
} | |||
/** | |||
* Convert an array to a single scalar value by extracting the first element | |||
* | |||
* @param mixed $value Array or scalar value | |||
* @return mixed | |||
*/ | |||
public static function flattenSingleValue($value = '') | |||
{ | |||
while (is_array($value)) { | |||
$value = array_pop($value); | |||
} | |||
return $value; | |||
} | |||
} | |||
// | |||
// There are a few mathematical functions that aren't available on all versions of PHP for all platforms | |||
// These functions aren't available in Windows implementations of PHP prior to version 5.3.0 | |||
// So we test if they do exist for this version of PHP/operating platform; and if not we create them | |||
// | |||
if (!function_exists('acosh')) { | |||
function acosh($x) | |||
{ | |||
return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2)); | |||
} // function acosh() | |||
} | |||
if (!function_exists('asinh')) { | |||
function asinh($x) | |||
{ | |||
return log($x + sqrt(1 + $x * $x)); | |||
} // function asinh() | |||
} | |||
if (!function_exists('atanh')) { | |||
function atanh($x) | |||
{ | |||
return (log(1 + $x) - log(1 - $x)) / 2; | |||
} // function atanh() | |||
} | |||
// | |||
// Strangely, PHP doesn't have a mb_str_replace multibyte function | |||
// As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set | |||
// | |||
if ((!function_exists('mb_str_replace')) && | |||
(function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) { | |||
function mb_str_replace($search, $replace, $subject) | |||
{ | |||
if (is_array($subject)) { | |||
$ret = array(); | |||
foreach ($subject as $key => $val) { | |||
$ret[$key] = mb_str_replace($search, $replace, $val); | |||
} | |||
return $ret; | |||
} | |||
foreach ((array) $search as $key => $s) { | |||
if ($s == '' && $s !== 0) { | |||
continue; | |||
} | |||
$r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : ''); | |||
$pos = mb_strpos($subject, $s, 0, 'UTF-8'); | |||
while ($pos !== false) { | |||
$subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8'); | |||
$pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8'); | |||
} | |||
} | |||
return $subject; | |||
} | |||
} |
@ -0,0 +1,760 @@ | |||
<?php | |||
/** PHPExcel root directory */ | |||
if (!defined('PHPEXCEL_ROOT')) { | |||
/** | |||
* @ignore | |||
*/ | |||
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); | |||
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); | |||
} | |||
/** MAX_VALUE */ | |||
define('MAX_VALUE', 1.2e308); | |||
/** 2 / PI */ | |||
define('M_2DIVPI', 0.63661977236758134307553505349006); | |||
/** MAX_ITERATIONS */ | |||
define('MAX_ITERATIONS', 256); | |||
/** PRECISION */ | |||
define('PRECISION', 8.88E-016); | |||
/** | |||
* PHPExcel_Calculation_Functions | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_Functions | |||
{ | |||
/** constants */ | |||
const COMPATIBILITY_EXCEL = 'Excel'; | |||
const COMPATIBILITY_GNUMERIC = 'Gnumeric'; | |||
const COMPATIBILITY_OPENOFFICE = 'OpenOfficeCalc'; | |||
const RETURNDATE_PHP_NUMERIC = 'P'; | |||
const RETURNDATE_PHP_OBJECT = 'O'; | |||
const RETURNDATE_EXCEL = 'E'; | |||
/** | |||
* Compatibility mode to use for error checking and responses | |||
* | |||
* @access private | |||
* @var string | |||
*/ | |||
protected static $compatibilityMode = self::COMPATIBILITY_EXCEL; | |||
/** | |||
* Data Type to use when returning date values | |||
* | |||
* @access private | |||
* @var string | |||
*/ | |||
protected static $returnDateType = self::RETURNDATE_EXCEL; | |||
/** | |||
* List of error codes | |||
* | |||
* @access private | |||
* @var array | |||
*/ | |||
protected static $errorCodes = array( | |||
'null' => '#NULL!', | |||
'divisionbyzero' => '#DIV/0!', | |||
'value' => '#VALUE!', | |||
'reference' => '#REF!', | |||
'name' => '#NAME?', | |||
'num' => '#NUM!', | |||
'na' => '#N/A', | |||
'gettingdata' => '#GETTING_DATA' | |||
); | |||
/** | |||
* Set the Compatibility Mode | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @param string $compatibilityMode Compatibility Mode | |||
* Permitted values are: | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc' | |||
* @return boolean (Success or Failure) | |||
*/ | |||
public static function setCompatibilityMode($compatibilityMode) | |||
{ | |||
if (($compatibilityMode == self::COMPATIBILITY_EXCEL) || | |||
($compatibilityMode == self::COMPATIBILITY_GNUMERIC) || | |||
($compatibilityMode == self::COMPATIBILITY_OPENOFFICE)) { | |||
self::$compatibilityMode = $compatibilityMode; | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Return the current Compatibility Mode | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @return string Compatibility Mode | |||
* Possible Return values are: | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_EXCEL 'Excel' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_GNUMERIC 'Gnumeric' | |||
* PHPExcel_Calculation_Functions::COMPATIBILITY_OPENOFFICE 'OpenOfficeCalc' | |||
*/ | |||
public static function getCompatibilityMode() | |||
{ | |||
return self::$compatibilityMode; | |||
} | |||
/** | |||
* Set the Return Date Format used by functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object) | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @param string $returnDateType Return Date Format | |||
* Permitted values are: | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E' | |||
* @return boolean Success or failure | |||
*/ | |||
public static function setReturnDateType($returnDateType) | |||
{ | |||
if (($returnDateType == self::RETURNDATE_PHP_NUMERIC) || | |||
($returnDateType == self::RETURNDATE_PHP_OBJECT) || | |||
($returnDateType == self::RETURNDATE_EXCEL)) { | |||
self::$returnDateType = $returnDateType; | |||
return true; | |||
} | |||
return false; | |||
} | |||
/** | |||
* Return the current Return Date Format for functions that return a date/time (Excel, PHP Serialized Numeric or PHP Object) | |||
* | |||
* @access public | |||
* @category Function Configuration | |||
* @return string Return Date Format | |||
* Possible Return values are: | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_NUMERIC 'P' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_PHP_OBJECT 'O' | |||
* PHPExcel_Calculation_Functions::RETURNDATE_EXCEL 'E' | |||
*/ | |||
public static function getReturnDateType() | |||
{ | |||
return self::$returnDateType; | |||
} | |||
/** | |||
* DUMMY | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #Not Yet Implemented | |||
*/ | |||
public static function DUMMY() | |||
{ | |||
return '#Not Yet Implemented'; | |||
} | |||
/** | |||
* DIV0 | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #Not Yet Implemented | |||
*/ | |||
public static function DIV0() | |||
{ | |||
return self::$errorCodes['divisionbyzero']; | |||
} | |||
/** | |||
* NA | |||
* | |||
* Excel Function: | |||
* =NA() | |||
* | |||
* Returns the error value #N/A | |||
* #N/A is the error value that means "no value is available." | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @return string #N/A! | |||
*/ | |||
public static function NA() | |||
{ | |||
return self::$errorCodes['na']; | |||
} | |||
/** | |||
* NaN | |||
* | |||
* Returns the error value #NUM! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #NUM! | |||
*/ | |||
public static function NaN() | |||
{ | |||
return self::$errorCodes['num']; | |||
} | |||
/** | |||
* NAME | |||
* | |||
* Returns the error value #NAME? | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #NAME? | |||
*/ | |||
public static function NAME() | |||
{ | |||
return self::$errorCodes['name']; | |||
} | |||
/** | |||
* REF | |||
* | |||
* Returns the error value #REF! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #REF! | |||
*/ | |||
public static function REF() | |||
{ | |||
return self::$errorCodes['reference']; | |||
} | |||
/** | |||
* NULL | |||
* | |||
* Returns the error value #NULL! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #NULL! | |||
*/ | |||
public static function NULL() | |||
{ | |||
return self::$errorCodes['null']; | |||
} | |||
/** | |||
* VALUE | |||
* | |||
* Returns the error value #VALUE! | |||
* | |||
* @access public | |||
* @category Error Returns | |||
* @return string #VALUE! | |||
*/ | |||
public static function VALUE() | |||
{ | |||
return self::$errorCodes['value']; | |||
} | |||
public static function isMatrixValue($idx) | |||
{ | |||
return ((substr_count($idx, '.') <= 1) || (preg_match('/\.[A-Z]/', $idx) > 0)); | |||
} | |||
public static function isValue($idx) | |||
{ | |||
return (substr_count($idx, '.') == 0); | |||
} | |||
public static function isCellValue($idx) | |||
{ | |||
return (substr_count($idx, '.') > 1); | |||
} | |||
public static function ifCondition($condition) | |||
{ | |||
$condition = PHPExcel_Calculation_Functions::flattenSingleValue($condition); | |||
if (!isset($condition{0})) { | |||
$condition = '=""'; | |||
} | |||
if (!in_array($condition{0}, array('>', '<', '='))) { | |||
if (!is_numeric($condition)) { | |||
$condition = PHPExcel_Calculation::wrapResult(strtoupper($condition)); | |||
} | |||
return '=' . $condition; | |||
} else { | |||
preg_match('/([<>=]+)(.*)/', $condition, $matches); | |||
list(, $operator, $operand) = $matches; | |||
if (!is_numeric($operand)) { | |||
$operand = str_replace('"', '""', $operand); | |||
$operand = PHPExcel_Calculation::wrapResult(strtoupper($operand)); | |||
} | |||
return $operator.$operand; | |||
} | |||
} | |||
/** | |||
* ERROR_TYPE | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function ERROR_TYPE($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
$i = 1; | |||
foreach (self::$errorCodes as $errorCode) { | |||
if ($value === $errorCode) { | |||
return $i; | |||
} | |||
++$i; | |||
} | |||
return self::NA(); | |||
} | |||
/** | |||
* IS_BLANK | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_BLANK($value = null) | |||
{ | |||
if (!is_null($value)) { | |||
$value = self::flattenSingleValue($value); | |||
} | |||
return is_null($value); | |||
} | |||
/** | |||
* IS_ERR | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_ERR($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return self::IS_ERROR($value) && (!self::IS_NA($value)); | |||
} | |||
/** | |||
* IS_ERROR | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_ERROR($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if (!is_string($value)) { | |||
return false; | |||
} | |||
return in_array($value, array_values(self::$errorCodes)); | |||
} | |||
/** | |||
* IS_NA | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_NA($value = '') | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return ($value === self::NA()); | |||
} | |||
/** | |||
* IS_EVEN | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_EVEN($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if ($value === null) { | |||
return self::NAME(); | |||
} elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { | |||
return self::VALUE(); | |||
} | |||
return ($value % 2 == 0); | |||
} | |||
/** | |||
* IS_ODD | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_ODD($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if ($value === null) { | |||
return self::NAME(); | |||
} elseif ((is_bool($value)) || ((is_string($value)) && (!is_numeric($value)))) { | |||
return self::VALUE(); | |||
} | |||
return (abs($value) % 2 == 1); | |||
} | |||
/** | |||
* IS_NUMBER | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_NUMBER($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
if (is_string($value)) { | |||
return false; | |||
} | |||
return is_numeric($value); | |||
} | |||
/** | |||
* IS_LOGICAL | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_LOGICAL($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return is_bool($value); | |||
} | |||
/** | |||
* IS_TEXT | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_TEXT($value = null) | |||
{ | |||
$value = self::flattenSingleValue($value); | |||
return (is_string($value) && !self::IS_ERROR($value)); | |||
} | |||
/** | |||
* IS_NONTEXT | |||
* | |||
* @param mixed $value Value to check | |||
* @return boolean | |||
*/ | |||
public static function IS_NONTEXT($value = null) | |||
{ | |||
return !self::IS_TEXT($value); | |||
} | |||
/** | |||
* VERSION | |||
* | |||
* @return string Version information | |||
*/ | |||
public static function VERSION() | |||
{ | |||
return 'PHPExcel ##VERSION##, ##DATE##'; | |||
} | |||
/** | |||
* N | |||
* | |||
* Returns a value converted to a number | |||
* | |||
* @param value The value you want converted | |||
* @return number N converts values listed in the following table | |||
* If value is or refers to N returns | |||
* A number That number | |||
* A date The serial number of that date | |||
* TRUE 1 | |||
* FALSE 0 | |||
* An error value The error value | |||
* Anything else 0 | |||
*/ | |||
public static function N($value = null) | |||
{ | |||
while (is_array($value)) { | |||
$value = array_shift($value); | |||
} | |||
switch (gettype($value)) { | |||
case 'double': | |||
case 'float': | |||
case 'integer': | |||
return $value; | |||
case 'boolean': | |||
return (integer) $value; | |||
case 'string': | |||
// Errors | |||
if ((strlen($value) > 0) && ($value{0} == '#')) { | |||
return $value; | |||
} | |||
break; | |||
} | |||
return 0; | |||
} | |||
/** | |||
* TYPE | |||
* | |||
* Returns a number that identifies the type of a value | |||
* | |||
* @param value The value you want tested | |||
* @return number N converts values listed in the following table | |||
* If value is or refers to N returns | |||
* A number 1 | |||
* Text 2 | |||
* Logical Value 4 | |||
* An error value 16 | |||
* Array or Matrix 64 | |||
*/ | |||
public static function TYPE($value = null) | |||
{ | |||
$value = self::flattenArrayIndexed($value); | |||
if (is_array($value) && (count($value) > 1)) { | |||
end($value); | |||
$a = key($value); | |||
// Range of cells is an error | |||
if (self::isCellValue($a)) { | |||
return 16; | |||
// Test for Matrix | |||
} elseif (self::isMatrixValue($a)) { | |||
return 64; | |||
} | |||
} elseif (empty($value)) { | |||
// Empty Cell | |||
return 1; | |||
} | |||
$value = self::flattenSingleValue($value); | |||
if (($value === null) || (is_float($value)) || (is_int($value))) { | |||
return 1; | |||
} elseif (is_bool($value)) { | |||
return 4; | |||
} elseif (is_array($value)) { | |||
return 64; | |||
} elseif (is_string($value)) { | |||
// Errors | |||
if ((strlen($value) > 0) && ($value{0} == '#')) { | |||
return 16; | |||
} | |||
return 2; | |||
} | |||
return 0; | |||
} | |||
/** | |||
* Convert a multi-dimensional array to a simple 1-dimensional array | |||
* | |||
* @param array $array Array to be flattened | |||
* @return array Flattened array | |||
*/ | |||
public static function flattenArray($array) | |||
{ | |||
if (!is_array($array)) { | |||
return (array) $array; | |||
} | |||
$arrayValues = array(); | |||
foreach ($array as $value) { | |||
if (is_array($value)) { | |||
foreach ($value as $val) { | |||
if (is_array($val)) { | |||
foreach ($val as $v) { | |||
$arrayValues[] = $v; | |||
} | |||
} else { | |||
$arrayValues[] = $val; | |||
} | |||
} | |||
} else { | |||
$arrayValues[] = $value; | |||
} | |||
} | |||
return $arrayValues; | |||
} | |||
/** | |||
* Convert a multi-dimensional array to a simple 1-dimensional array, but retain an element of indexing | |||
* | |||
* @param array $array Array to be flattened | |||
* @return array Flattened array | |||
*/ | |||
public static function flattenArrayIndexed($array) | |||
{ | |||
if (!is_array($array)) { | |||
return (array) $array; | |||
} | |||
$arrayValues = array(); | |||
foreach ($array as $k1 => $value) { | |||
if (is_array($value)) { | |||
foreach ($value as $k2 => $val) { | |||
if (is_array($val)) { | |||
foreach ($val as $k3 => $v) { | |||
$arrayValues[$k1.'.'.$k2.'.'.$k3] = $v; | |||
} | |||
} else { | |||
$arrayValues[$k1.'.'.$k2] = $val; | |||
} | |||
} | |||
} else { | |||
$arrayValues[$k1] = $value; | |||
} | |||
} | |||
return $arrayValues; | |||
} | |||
/** | |||
* Convert an array to a single scalar value by extracting the first element | |||
* | |||
* @param mixed $value Array or scalar value | |||
* @return mixed | |||
*/ | |||
public static function flattenSingleValue($value = '') | |||
{ | |||
while (is_array($value)) { | |||
$value = array_pop($value); | |||
} | |||
return $value; | |||
} | |||
} | |||
// | |||
// There are a few mathematical functions that aren't available on all versions of PHP for all platforms | |||
// These functions aren't available in Windows implementations of PHP prior to version 5.3.0 | |||
// So we test if they do exist for this version of PHP/operating platform; and if not we create them | |||
// | |||
if (!function_exists('acosh')) { | |||
function acosh($x) | |||
{ | |||
return 2 * log(sqrt(($x + 1) / 2) + sqrt(($x - 1) / 2)); | |||
} // function acosh() | |||
} | |||
if (!function_exists('asinh')) { | |||
function asinh($x) | |||
{ | |||
return log($x + sqrt(1 + $x * $x)); | |||
} // function asinh() | |||
} | |||
if (!function_exists('atanh')) { | |||
function atanh($x) | |||
{ | |||
return (log(1 + $x) - log(1 - $x)) / 2; | |||
} // function atanh() | |||
} | |||
// | |||
// Strangely, PHP doesn't have a mb_str_replace multibyte function | |||
// As we'll only ever use this function with UTF-8 characters, we can simply "hard-code" the character set | |||
// | |||
if ((!function_exists('mb_str_replace')) && | |||
(function_exists('mb_substr')) && (function_exists('mb_strlen')) && (function_exists('mb_strpos'))) { | |||
function mb_str_replace($search, $replace, $subject) | |||
{ | |||
if (is_array($subject)) { | |||
$ret = array(); | |||
foreach ($subject as $key => $val) { | |||
$ret[$key] = mb_str_replace($search, $replace, $val); | |||
} | |||
return $ret; | |||
} | |||
foreach ((array) $search as $key => $s) { | |||
if ($s == '' && $s !== 0) { | |||
continue; | |||
} | |||
$r = !is_array($replace) ? $replace : (array_key_exists($key, $replace) ? $replace[$key] : ''); | |||
$pos = mb_strpos($subject, $s, 0, 'UTF-8'); | |||
while ($pos !== false) { | |||
$subject = mb_substr($subject, 0, $pos, 'UTF-8') . $r . mb_substr($subject, $pos + mb_strlen($s, 'UTF-8'), 65535, 'UTF-8'); | |||
$pos = mb_strpos($subject, $s, $pos + mb_strlen($r, 'UTF-8'), 'UTF-8'); | |||
} | |||
} | |||
return $subject; | |||
} | |||
} |
@ -0,0 +1,285 @@ | |||
<?php | |||
/** PHPExcel root directory */ | |||
if (!defined('PHPEXCEL_ROOT')) { | |||
/** | |||
* @ignore | |||
*/ | |||
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); | |||
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); | |||
} | |||
/** | |||
* PHPExcel_Calculation_Logical | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_Logical | |||
{ | |||
/** | |||
* TRUE | |||
* | |||
* Returns the boolean TRUE. | |||
* | |||
* Excel Function: | |||
* =TRUE() | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @return boolean True | |||
*/ | |||
public static function TRUE() | |||
{ | |||
return true; | |||
} | |||
/** | |||
* FALSE | |||
* | |||
* Returns the boolean FALSE. | |||
* | |||
* Excel Function: | |||
* =FALSE() | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @return boolean False | |||
*/ | |||
public static function FALSE() | |||
{ | |||
return false; | |||
} | |||
/** | |||
* LOGICAL_AND | |||
* | |||
* Returns boolean TRUE if all its arguments are TRUE; returns FALSE if one or more argument is FALSE. | |||
* | |||
* Excel Function: | |||
* =AND(logical1[,logical2[, ...]]) | |||
* | |||
* The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays | |||
* or references that contain logical values. | |||
* | |||
* Boolean arguments are treated as True or False as appropriate | |||
* Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False | |||
* If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds | |||
* the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @param mixed $arg,... Data values | |||
* @return boolean The logical AND of the arguments. | |||
*/ | |||
public static function LOGICAL_AND() | |||
{ | |||
// Return value | |||
$returnValue = true; | |||
// Loop through the arguments | |||
$aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); | |||
$argCount = -1; | |||
foreach ($aArgs as $argCount => $arg) { | |||
// Is it a boolean value? | |||
if (is_bool($arg)) { | |||
$returnValue = $returnValue && $arg; | |||
} elseif ((is_numeric($arg)) && (!is_string($arg))) { | |||
$returnValue = $returnValue && ($arg != 0); | |||
} elseif (is_string($arg)) { | |||
$arg = strtoupper($arg); | |||
if (($arg == 'TRUE') || ($arg == PHPExcel_Calculation::getTRUE())) { | |||
$arg = true; | |||
} elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) { | |||
$arg = false; | |||
} else { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
$returnValue = $returnValue && ($arg != 0); | |||
} | |||
} | |||
// Return | |||
if ($argCount < 0) { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
return $returnValue; | |||
} | |||
/** | |||
* LOGICAL_OR | |||
* | |||
* Returns boolean TRUE if any argument is TRUE; returns FALSE if all arguments are FALSE. | |||
* | |||
* Excel Function: | |||
* =OR(logical1[,logical2[, ...]]) | |||
* | |||
* The arguments must evaluate to logical values such as TRUE or FALSE, or the arguments must be arrays | |||
* or references that contain logical values. | |||
* | |||
* Boolean arguments are treated as True or False as appropriate | |||
* Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False | |||
* If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds | |||
* the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @param mixed $arg,... Data values | |||
* @return boolean The logical OR of the arguments. | |||
*/ | |||
public static function LOGICAL_OR() | |||
{ | |||
// Return value | |||
$returnValue = false; | |||
// Loop through the arguments | |||
$aArgs = PHPExcel_Calculation_Functions::flattenArray(func_get_args()); | |||
$argCount = -1; | |||
foreach ($aArgs as $argCount => $arg) { | |||
// Is it a boolean value? | |||
if (is_bool($arg)) { | |||
$returnValue = $returnValue || $arg; | |||
} elseif ((is_numeric($arg)) && (!is_string($arg))) { | |||
$returnValue = $returnValue || ($arg != 0); | |||
} elseif (is_string($arg)) { | |||
$arg = strtoupper($arg); | |||
if (($arg == 'TRUE') || ($arg == PHPExcel_Calculation::getTRUE())) { | |||
$arg = true; | |||
} elseif (($arg == 'FALSE') || ($arg == PHPExcel_Calculation::getFALSE())) { | |||
$arg = false; | |||
} else { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
$returnValue = $returnValue || ($arg != 0); | |||
} | |||
} | |||
// Return | |||
if ($argCount < 0) { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
return $returnValue; | |||
} | |||
/** | |||
* NOT | |||
* | |||
* Returns the boolean inverse of the argument. | |||
* | |||
* Excel Function: | |||
* =NOT(logical) | |||
* | |||
* The argument must evaluate to a logical value such as TRUE or FALSE | |||
* | |||
* Boolean arguments are treated as True or False as appropriate | |||
* Integer or floating point arguments are treated as True, except for 0 or 0.0 which are False | |||
* If any argument value is a string, or a Null, the function returns a #VALUE! error, unless the string holds | |||
* the value TRUE or FALSE, in which case it is evaluated as the corresponding boolean value | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @param mixed $logical A value or expression that can be evaluated to TRUE or FALSE | |||
* @return boolean The boolean inverse of the argument. | |||
*/ | |||
public static function NOT($logical = false) | |||
{ | |||
$logical = PHPExcel_Calculation_Functions::flattenSingleValue($logical); | |||
if (is_string($logical)) { | |||
$logical = strtoupper($logical); | |||
if (($logical == 'TRUE') || ($logical == PHPExcel_Calculation::getTRUE())) { | |||
return false; | |||
} elseif (($logical == 'FALSE') || ($logical == PHPExcel_Calculation::getFALSE())) { | |||
return true; | |||
} else { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
} | |||
return !$logical; | |||
} | |||
/** | |||
* STATEMENT_IF | |||
* | |||
* Returns one value if a condition you specify evaluates to TRUE and another value if it evaluates to FALSE. | |||
* | |||
* Excel Function: | |||
* =IF(condition[,returnIfTrue[,returnIfFalse]]) | |||
* | |||
* Condition is any value or expression that can be evaluated to TRUE or FALSE. | |||
* For example, A10=100 is a logical expression; if the value in cell A10 is equal to 100, | |||
* the expression evaluates to TRUE. Otherwise, the expression evaluates to FALSE. | |||
* This argument can use any comparison calculation operator. | |||
* ReturnIfTrue is the value that is returned if condition evaluates to TRUE. | |||
* For example, if this argument is the text string "Within budget" and the condition argument evaluates to TRUE, | |||
* then the IF function returns the text "Within budget" | |||
* If condition is TRUE and ReturnIfTrue is blank, this argument returns 0 (zero). To display the word TRUE, use | |||
* the logical value TRUE for this argument. | |||
* ReturnIfTrue can be another formula. | |||
* ReturnIfFalse is the value that is returned if condition evaluates to FALSE. | |||
* For example, if this argument is the text string "Over budget" and the condition argument evaluates to FALSE, | |||
* then the IF function returns the text "Over budget". | |||
* If condition is FALSE and ReturnIfFalse is omitted, then the logical value FALSE is returned. | |||
* If condition is FALSE and ReturnIfFalse is blank, then the value 0 (zero) is returned. | |||
* ReturnIfFalse can be another formula. | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @param mixed $condition Condition to evaluate | |||
* @param mixed $returnIfTrue Value to return when condition is true | |||
* @param mixed $returnIfFalse Optional value to return when condition is false | |||
* @return mixed The value of returnIfTrue or returnIfFalse determined by condition | |||
*/ | |||
public static function STATEMENT_IF($condition = true, $returnIfTrue = 0, $returnIfFalse = false) | |||
{ | |||
$condition = (is_null($condition)) ? true : (boolean) PHPExcel_Calculation_Functions::flattenSingleValue($condition); | |||
$returnIfTrue = (is_null($returnIfTrue)) ? 0 : PHPExcel_Calculation_Functions::flattenSingleValue($returnIfTrue); | |||
$returnIfFalse = (is_null($returnIfFalse)) ? false : PHPExcel_Calculation_Functions::flattenSingleValue($returnIfFalse); | |||
return ($condition) ? $returnIfTrue : $returnIfFalse; | |||
} | |||
/** | |||
* IFERROR | |||
* | |||
* Excel Function: | |||
* =IFERROR(testValue,errorpart) | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @param mixed $testValue Value to check, is also the value returned when no error | |||
* @param mixed $errorpart Value to return when testValue is an error condition | |||
* @return mixed The value of errorpart or testValue determined by error condition | |||
*/ | |||
public static function IFERROR($testValue = '', $errorpart = '') | |||
{ | |||
$testValue = (is_null($testValue)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($testValue); | |||
$errorpart = (is_null($errorpart)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($errorpart); | |||
return self::STATEMENT_IF(PHPExcel_Calculation_Functions::IS_ERROR($testValue), $errorpart, $testValue); | |||
} | |||
} |
@ -0,0 +1,879 @@ | |||
<?php | |||
/** PHPExcel root directory */ | |||
if (!defined('PHPEXCEL_ROOT')) { | |||
/** | |||
* @ignore | |||
*/ | |||
define('PHPEXCEL_ROOT', dirname(__FILE__) . '/../../'); | |||
require(PHPEXCEL_ROOT . 'PHPExcel/Autoloader.php'); | |||
} | |||
/** | |||
* PHPExcel_Calculation_LookupRef | |||
* | |||
* Copyright (c) 2006 - 2015 PHPExcel | |||
* | |||
* This library is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 2.1 of the License, or (at your option) any later version. | |||
* | |||
* This library is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
* | |||
* @category PHPExcel | |||
* @package PHPExcel_Calculation | |||
* @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel) | |||
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL | |||
* @version ##VERSION##, ##DATE## | |||
*/ | |||
class PHPExcel_Calculation_LookupRef | |||
{ | |||
/** | |||
* CELL_ADDRESS | |||
* | |||
* Creates a cell address as text, given specified row and column numbers. | |||
* | |||
* Excel Function: | |||
* =ADDRESS(row, column, [relativity], [referenceStyle], [sheetText]) | |||
* | |||
* @param row Row number to use in the cell reference | |||
* @param column Column number to use in the cell reference | |||
* @param relativity Flag indicating the type of reference to return | |||
* 1 or omitted Absolute | |||
* 2 Absolute row; relative column | |||
* 3 Relative row; absolute column | |||
* 4 Relative | |||
* @param referenceStyle A logical value that specifies the A1 or R1C1 reference style. | |||
* TRUE or omitted CELL_ADDRESS returns an A1-style reference | |||
* FALSE CELL_ADDRESS returns an R1C1-style reference | |||
* @param sheetText Optional Name of worksheet to use | |||
* @return string | |||
*/ | |||
public static function CELL_ADDRESS($row, $column, $relativity = 1, $referenceStyle = true, $sheetText = '') | |||
{ | |||
$row = PHPExcel_Calculation_Functions::flattenSingleValue($row); | |||
$column = PHPExcel_Calculation_Functions::flattenSingleValue($column); | |||
$relativity = PHPExcel_Calculation_Functions::flattenSingleValue($relativity); | |||
$sheetText = PHPExcel_Calculation_Functions::flattenSingleValue($sheetText); | |||
if (($row < 1) || ($column < 1)) { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
if ($sheetText > '') { | |||
if (strpos($sheetText, ' ') !== false) { | |||
$sheetText = "'".$sheetText."'"; | |||
} | |||
$sheetText .='!'; | |||
} | |||
if ((!is_bool($referenceStyle)) || $referenceStyle) { | |||
$rowRelative = $columnRelative = '$'; | |||
$column = PHPExcel_Cell::stringFromColumnIndex($column-1); | |||
if (($relativity == 2) || ($relativity == 4)) { | |||
$columnRelative = ''; | |||
} | |||
if (($relativity == 3) || ($relativity == 4)) { | |||
$rowRelative = ''; | |||
} | |||
return $sheetText.$columnRelative.$column.$rowRelative.$row; | |||
} else { | |||
if (($relativity == 2) || ($relativity == 4)) { | |||
$column = '['.$column.']'; | |||
} | |||
if (($relativity == 3) || ($relativity == 4)) { | |||
$row = '['.$row.']'; | |||
} | |||
return $sheetText.'R'.$row.'C'.$column; | |||
} | |||
} | |||
/** | |||
* COLUMN | |||
* | |||
* Returns the column number of the given cell reference | |||
* If the cell reference is a range of cells, COLUMN returns the column numbers of each column in the reference as a horizontal array. | |||
* If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the | |||
* reference of the cell in which the COLUMN function appears; otherwise this function returns 0. | |||
* | |||
* Excel Function: | |||
* =COLUMN([cellAddress]) | |||
* | |||
* @param cellAddress A reference to a range of cells for which you want the column numbers | |||
* @return integer or array of integer | |||
*/ | |||
public static function COLUMN($cellAddress = null) | |||
{ | |||
if (is_null($cellAddress) || trim($cellAddress) === '') { | |||
return 0; | |||
} | |||
if (is_array($cellAddress)) { | |||
foreach ($cellAddress as $columnKey => $value) { | |||
$columnKey = preg_replace('/[^a-z]/i', '', $columnKey); | |||
return (integer) PHPExcel_Cell::columnIndexFromString($columnKey); | |||
} | |||
} else { | |||
if (strpos($cellAddress, '!') !== false) { | |||
list($sheet, $cellAddress) = explode('!', $cellAddress); | |||
} | |||
if (strpos($cellAddress, ':') !== false) { | |||
list($startAddress, $endAddress) = explode(':', $cellAddress); | |||
$startAddress = preg_replace('/[^a-z]/i', '', $startAddress); | |||
$endAddress = preg_replace('/[^a-z]/i', '', $endAddress); | |||
$returnValue = array(); | |||
do { | |||
$returnValue[] = (integer) PHPExcel_Cell::columnIndexFromString($startAddress); | |||
} while ($startAddress++ != $endAddress); | |||
return $returnValue; | |||
} else { | |||
$cellAddress = preg_replace('/[^a-z]/i', '', $cellAddress); | |||
return (integer) PHPExcel_Cell::columnIndexFromString($cellAddress); | |||
} | |||
} | |||
} | |||
/** | |||
* COLUMNS | |||
* | |||
* Returns the number of columns in an array or reference. | |||
* | |||
* Excel Function: | |||
* =COLUMNS(cellAddress) | |||
* | |||
* @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of columns | |||
* @return integer The number of columns in cellAddress | |||
*/ | |||
public static function COLUMNS($cellAddress = null) | |||
{ | |||
if (is_null($cellAddress) || $cellAddress === '') { | |||
return 1; | |||
} elseif (!is_array($cellAddress)) { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
reset($cellAddress); | |||
$isMatrix = (is_numeric(key($cellAddress))); | |||
list($columns, $rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress); | |||
if ($isMatrix) { | |||
return $rows; | |||
} else { | |||
return $columns; | |||
} | |||
} | |||
/** | |||
* ROW | |||
* | |||
* Returns the row number of the given cell reference | |||
* If the cell reference is a range of cells, ROW returns the row numbers of each row in the reference as a vertical array. | |||
* If cell reference is omitted, and the function is being called through the calculation engine, then it is assumed to be the | |||
* reference of the cell in which the ROW function appears; otherwise this function returns 0. | |||
* | |||
* Excel Function: | |||
* =ROW([cellAddress]) | |||
* | |||
* @param cellAddress A reference to a range of cells for which you want the row numbers | |||
* @return integer or array of integer | |||
*/ | |||
public static function ROW($cellAddress = null) | |||
{ | |||
if (is_null($cellAddress) || trim($cellAddress) === '') { | |||
return 0; | |||
} | |||
if (is_array($cellAddress)) { | |||
foreach ($cellAddress as $columnKey => $rowValue) { | |||
foreach ($rowValue as $rowKey => $cellValue) { | |||
return (integer) preg_replace('/[^0-9]/i', '', $rowKey); | |||
} | |||
} | |||
} else { | |||
if (strpos($cellAddress, '!') !== false) { | |||
list($sheet, $cellAddress) = explode('!', $cellAddress); | |||
} | |||
if (strpos($cellAddress, ':') !== false) { | |||
list($startAddress, $endAddress) = explode(':', $cellAddress); | |||
$startAddress = preg_replace('/[^0-9]/', '', $startAddress); | |||
$endAddress = preg_replace('/[^0-9]/', '', $endAddress); | |||
$returnValue = array(); | |||
do { | |||
$returnValue[][] = (integer) $startAddress; | |||
} while ($startAddress++ != $endAddress); | |||
return $returnValue; | |||
} else { | |||
list($cellAddress) = explode(':', $cellAddress); | |||
return (integer) preg_replace('/[^0-9]/', '', $cellAddress); | |||
} | |||
} | |||
} | |||
/** | |||
* ROWS | |||
* | |||
* Returns the number of rows in an array or reference. | |||
* | |||
* Excel Function: | |||
* =ROWS(cellAddress) | |||
* | |||
* @param cellAddress An array or array formula, or a reference to a range of cells for which you want the number of rows | |||
* @return integer The number of rows in cellAddress | |||
*/ | |||
public static function ROWS($cellAddress = null) | |||
{ | |||
if (is_null($cellAddress) || $cellAddress === '') { | |||
return 1; | |||
} elseif (!is_array($cellAddress)) { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
reset($cellAddress); | |||
$isMatrix = (is_numeric(key($cellAddress))); | |||
list($columns, $rows) = PHPExcel_Calculation::_getMatrixDimensions($cellAddress); | |||
if ($isMatrix) { | |||
return $columns; | |||
} else { | |||
return $rows; | |||
} | |||
} | |||
/** | |||
* HYPERLINK | |||
* | |||
* Excel Function: | |||
* =HYPERLINK(linkURL,displayName) | |||
* | |||
* @access public | |||
* @category Logical Functions | |||
* @param string $linkURL Value to check, is also the value returned when no error | |||
* @param string $displayName Value to return when testValue is an error condition | |||
* @param PHPExcel_Cell $pCell The cell to set the hyperlink in | |||
* @return mixed The value of $displayName (or $linkURL if $displayName was blank) | |||
*/ | |||
public static function HYPERLINK($linkURL = '', $displayName = null, PHPExcel_Cell $pCell = null) | |||
{ | |||
$args = func_get_args(); | |||
$pCell = array_pop($args); | |||
$linkURL = (is_null($linkURL)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($linkURL); | |||
$displayName = (is_null($displayName)) ? '' : PHPExcel_Calculation_Functions::flattenSingleValue($displayName); | |||
if ((!is_object($pCell)) || (trim($linkURL) == '')) { | |||
return PHPExcel_Calculation_Functions::REF(); | |||
} | |||
if ((is_object($displayName)) || trim($displayName) == '') { | |||
$displayName = $linkURL; | |||
} | |||
$pCell->getHyperlink()->setUrl($linkURL); | |||
$pCell->getHyperlink()->setTooltip($displayName); | |||
return $displayName; | |||
} | |||
/** | |||
* INDIRECT | |||
* | |||
* Returns the reference specified by a text string. | |||
* References are immediately evaluated to display their contents. | |||
* | |||
* Excel Function: | |||
* =INDIRECT(cellAddress) | |||
* | |||
* NOTE - INDIRECT() does not yet support the optional a1 parameter introduced in Excel 2010 | |||
* | |||
* @param cellAddress $cellAddress The cell address of the current cell (containing this formula) | |||
* @param PHPExcel_Cell $pCell The current cell (containing this formula) | |||
* @return mixed The cells referenced by cellAddress | |||
* | |||
* @todo Support for the optional a1 parameter introduced in Excel 2010 | |||
* | |||
*/ | |||
public static function INDIRECT($cellAddress = null, PHPExcel_Cell $pCell = null) | |||
{ | |||
$cellAddress = PHPExcel_Calculation_Functions::flattenSingleValue($cellAddress); | |||
if (is_null($cellAddress) || $cellAddress === '') { | |||
return PHPExcel_Calculation_Functions::REF(); | |||
} | |||
$cellAddress1 = $cellAddress; | |||
$cellAddress2 = null; | |||
if (strpos($cellAddress, ':') !== false) { | |||
list($cellAddress1, $cellAddress2) = explode(':', $cellAddress); | |||
} | |||
if ((!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress1, $matches)) || | |||
((!is_null($cellAddress2)) && (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_CELLREF.'$/i', $cellAddress2, $matches)))) { | |||
if (!preg_match('/^'.PHPExcel_Calculation::CALCULATION_REGEXP_NAMEDRANGE.'$/i', $cellAddress1, $matches)) { | |||
return PHPExcel_Calculation_Functions::REF(); | |||
} | |||
if (strpos($cellAddress, '!') !== false) { | |||
list($sheetName, $cellAddress) = explode('!', $cellAddress); | |||
$sheetName = trim($sheetName, "'"); | |||
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName); | |||
} else { | |||
$pSheet = $pCell->getWorksheet(); | |||
} | |||
return PHPExcel_Calculation::getInstance()->extractNamedRange($cellAddress, $pSheet, false); | |||
} | |||
if (strpos($cellAddress, '!') !== false) { | |||
list($sheetName, $cellAddress) = explode('!', $cellAddress); | |||
$sheetName = trim($sheetName, "'"); | |||
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName); | |||
} else { | |||
$pSheet = $pCell->getWorksheet(); | |||
} | |||
return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false); | |||
} | |||
/** | |||
* OFFSET | |||
* | |||
* Returns a reference to a range that is a specified number of rows and columns from a cell or range of cells. | |||
* The reference that is returned can be a single cell or a range of cells. You can specify the number of rows and | |||
* the number of columns to be returned. | |||
* | |||
* Excel Function: | |||
* =OFFSET(cellAddress, rows, cols, [height], [width]) | |||
* | |||
* @param cellAddress The reference from which you want to base the offset. Reference must refer to a cell or | |||
* range of adjacent cells; otherwise, OFFSET returns the #VALUE! error value. | |||
* @param rows The number of rows, up or down, that you want the upper-left cell to refer to. | |||
* Using 5 as the rows argument specifies that the upper-left cell in the reference is | |||
* five rows below reference. Rows can be positive (which means below the starting reference) | |||
* or negative (which means above the starting reference). | |||
* @param cols The number of columns, to the left or right, that you want the upper-left cell of the result | |||
* to refer to. Using 5 as the cols argument specifies that the upper-left cell in the | |||
* reference is five columns to the right of reference. Cols can be positive (which means | |||
* to the right of the starting reference) or negative (which means to the left of the | |||
* starting reference). | |||
* @param height The height, in number of rows, that you want the returned reference to be. Height must be a positive number. | |||
* @param width The width, in number of columns, that you want the returned reference to be. Width must be a positive number. | |||
* @return string A reference to a cell or range of cells | |||
*/ | |||
public static function OFFSET($cellAddress = null, $rows = 0, $columns = 0, $height = null, $width = null) | |||
{ | |||
$rows = PHPExcel_Calculation_Functions::flattenSingleValue($rows); | |||
$columns = PHPExcel_Calculation_Functions::flattenSingleValue($columns); | |||
$height = PHPExcel_Calculation_Functions::flattenSingleValue($height); | |||
$width = PHPExcel_Calculation_Functions::flattenSingleValue($width); | |||
if ($cellAddress == null) { | |||
return 0; | |||
} | |||
$args = func_get_args(); | |||
$pCell = array_pop($args); | |||
if (!is_object($pCell)) { | |||
return PHPExcel_Calculation_Functions::REF(); | |||
} | |||
$sheetName = null; | |||
if (strpos($cellAddress, "!")) { | |||
list($sheetName, $cellAddress) = explode("!", $cellAddress); | |||
$sheetName = trim($sheetName, "'"); | |||
} | |||
if (strpos($cellAddress, ":")) { | |||
list($startCell, $endCell) = explode(":", $cellAddress); | |||
} else { | |||
$startCell = $endCell = $cellAddress; | |||
} | |||
list($startCellColumn, $startCellRow) = PHPExcel_Cell::coordinateFromString($startCell); | |||
list($endCellColumn, $endCellRow) = PHPExcel_Cell::coordinateFromString($endCell); | |||
$startCellRow += $rows; | |||
$startCellColumn = PHPExcel_Cell::columnIndexFromString($startCellColumn) - 1; | |||
$startCellColumn += $columns; | |||
if (($startCellRow <= 0) || ($startCellColumn < 0)) { | |||
return PHPExcel_Calculation_Functions::REF(); | |||
} | |||
$endCellColumn = PHPExcel_Cell::columnIndexFromString($endCellColumn) - 1; | |||
if (($width != null) && (!is_object($width))) { | |||
$endCellColumn = $startCellColumn + $width - 1; | |||
} else { | |||
$endCellColumn += $columns; | |||
} | |||
$startCellColumn = PHPExcel_Cell::stringFromColumnIndex($startCellColumn); | |||
if (($height != null) && (!is_object($height))) { | |||
$endCellRow = $startCellRow + $height - 1; | |||
} else { | |||
$endCellRow += $rows; | |||
} | |||
if (($endCellRow <= 0) || ($endCellColumn < 0)) { | |||
return PHPExcel_Calculation_Functions::REF(); | |||
} | |||
$endCellColumn = PHPExcel_Cell::stringFromColumnIndex($endCellColumn); | |||
$cellAddress = $startCellColumn.$startCellRow; | |||
if (($startCellColumn != $endCellColumn) || ($startCellRow != $endCellRow)) { | |||
$cellAddress .= ':'.$endCellColumn.$endCellRow; | |||
} | |||
if ($sheetName !== null) { | |||
$pSheet = $pCell->getWorksheet()->getParent()->getSheetByName($sheetName); | |||
} else { | |||
$pSheet = $pCell->getWorksheet(); | |||
} | |||
return PHPExcel_Calculation::getInstance()->extractCellRange($cellAddress, $pSheet, false); | |||
} | |||
/** | |||
* CHOOSE | |||
* | |||
* Uses lookup_value to return a value from the list of value arguments. | |||
* Use CHOOSE to select one of up to 254 values based on the lookup_value. | |||
* | |||
* Excel Function: | |||
* =CHOOSE(index_num, value1, [value2], ...) | |||
* | |||
* @param index_num Specifies which value argument is selected. | |||
* Index_num must be a number between 1 and 254, or a formula or reference to a cell containing a number | |||
* between 1 and 254. | |||
* @param value1... Value1 is required, subsequent values are optional. | |||
* Between 1 to 254 value arguments from which CHOOSE selects a value or an action to perform based on | |||
* index_num. The arguments can be numbers, cell references, defined names, formulas, functions, or | |||
* text. | |||
* @return mixed The selected value | |||
*/ | |||
public static function CHOOSE() | |||
{ | |||
$chooseArgs = func_get_args(); | |||
$chosenEntry = PHPExcel_Calculation_Functions::flattenArray(array_shift($chooseArgs)); | |||
$entryCount = count($chooseArgs) - 1; | |||
if (is_array($chosenEntry)) { | |||
$chosenEntry = array_shift($chosenEntry); | |||
} | |||
if ((is_numeric($chosenEntry)) && (!is_bool($chosenEntry))) { | |||
--$chosenEntry; | |||
} else { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
$chosenEntry = floor($chosenEntry); | |||
if (($chosenEntry < 0) || ($chosenEntry > $entryCount)) { | |||
return PHPExcel_Calculation_Functions::VALUE(); | |||
} | |||
if (is_array($chooseArgs[$chosenEntry])) { | |||
return PHPExcel_Calculation_Functions::flattenArray($chooseArgs[$chosenEntry]); | |||
} else { | |||
return $chooseArgs[$chosenEntry]; | |||
} | |||
} | |||
/** | |||
* MATCH | |||
* | |||
* The MATCH function searches for a specified item in a range of cells | |||
* | |||
* Excel Function: | |||
* =MATCH(lookup_value, lookup_array, [match_type]) | |||
* | |||
* @param lookup_value The value that you want to match in lookup_array | |||
* @param lookup_array The range of cells being searched | |||
* @param match_type The number -1, 0, or 1. -1 means above, 0 means exact match, 1 means below. If match_type is 1 or -1, the list has to be ordered. | |||
* @return integer The relative position of the found item | |||
*/ | |||
public static function MATCH($lookup_value, $lookup_array, $match_type = 1) | |||
{ | |||
$lookup_array = PHPExcel_Calculation_Functions::flattenArray($lookup_array); | |||
$lookup_value = PHPExcel_Calculation_Functions::flattenSingleValue($lookup_value); | |||
$match_type = (is_null($match_type)) ? 1 : (int) PHPExcel_Calculation_Functions::flattenSingleValue($match_type); | |||
// MATCH is not case sensitive | |||
$lookup_value = strtolower($lookup_value); | |||
// lookup_value type has to be number, text, or logical values | |||
if ((!is_numeric($lookup_value)) && (!is_string($lookup_value)) && (!is_bool($lookup_value))) { | |||
return PHPExcel_Calculation_Functions::NA(); | |||
} | |||
// match_type is 0, 1 or -1 | |||
if (($match_type !== 0) && ($match_type !== -1) && ($match_type !== 1)) { | |||
return PHPExcel_Calculation_Functions::NA(); | |||
} | |||
// lookup_array should not be empty | |||
$lookupArraySize = count($lookup_array); | |||
if ($lookupArraySize <= 0) { | |||
return PHPExcel_Calculation_Functions::NA(); | |||
} | |||
// lookup_array should contain only number, text, or logical values, or empty (null) cells | |||
foreach ($lookup_array as $i => $lookupArrayValue) { | |||
// check the type of the value | |||
if ((!is_numeric($lookupArrayValue)) && (!is_string($lookupArrayValue)) && | |||
(!is_bool($lookupArrayValue)) && (!is_null($lookupArrayValue))) { | |||
return PHPExcel_Calculation_Functions::NA(); | |||
} | |||
// convert strings to lowercase for case-insensitive testing | |||
if (is_string($lookupArrayValue)) { | |||
$lookup_array[$i] = strtolower($lookupArrayValue); | |||
} | |||
if ((is_null($lookupArrayValue)) && (($match_type == 1) || ($match_type == -1))) { | |||
$lookup_array = array_slice($lookup_array, 0, $i-1); | |||
} | |||
} | |||
// if match_type is 1 or -1, the list has to be ordered | |||
if ($match_type == 1) { | |||
asort($lookup_array); | |||
$keySet = array_keys($lookup_array); | |||
} elseif ($match_type == -1) { | |||
arsort($lookup_array); | |||
$keySet = array_keys($lookup_array); | |||
} | |||
// ** | |||
// find the match | |||
// ** | |||
foreach ($lookup_array as $i => $lookupArrayValue) { | |||
if (($match_type == 0) && ($lookupArrayValue == $lookup_value)) { | |||
// exact match | |||
return ++$i; | |||
} elseif (($match_type == -1) && ($lookupArrayValue <= $lookup_value)) { | |||