| @ -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)) { | |||