PageRenderTime 230ms CodeModel.GetById 111ms app.highlight 62ms RepoModel.GetById 49ms app.codeStats 0ms

/PHPExcel/Cell.php

https://bitbucket.org/nfredricks/wp-employee-time
PHP | 972 lines | 447 code | 114 blank | 411 comment | 68 complexity | 16fd9ae93014177891ffe3965b00ca30 MD5 | raw file
  1<?php
  2/**
  3 *	PHPExcel
  4 *
  5 *	Copyright (c) 2006 - 2012 PHPExcel
  6 *
  7 *	This library is free software; you can redistribute it and/or
  8 *	modify it under the terms of the GNU Lesser General Public
  9 *	License as published by the Free Software Foundation; either
 10 *	version 2.1 of the License, or (at your option) any later version.
 11 *
 12 *	This library is distributed in the hope that it will be useful,
 13 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15 *	Lesser General Public License for more details.
 16 *
 17 *	You should have received a copy of the GNU Lesser General Public
 18 *	License along with this library; if not, write to the Free Software
 19 *	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 20 *
 21 *	@category	PHPExcel
 22 *	@package	PHPExcel_Cell
 23 *	@copyright	Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
 24 *	@license	http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt	LGPL
 25 *	@version	1.7.8, 2012-10-12
 26 */
 27
 28
 29/**
 30 *	PHPExcel_Cell
 31 *
 32 *	@category   PHPExcel
 33 *	@package	PHPExcel_Cell
 34 *	@copyright  Copyright (c) 2006 - 2012 PHPExcel (http://www.codeplex.com/PHPExcel)
 35 */
 36class PHPExcel_Cell
 37{
 38
 39	/**
 40	 *  Default range variable constant
 41	 *
 42	 *  @var  string
 43	 */
 44	const DEFAULT_RANGE = 'A1:A1';
 45
 46	/**
 47	 *	Value binder to use
 48	 *
 49	 *	@var	PHPExcel_Cell_IValueBinder
 50	 */
 51	private static $_valueBinder = NULL;
 52
 53	/**
 54	 *	Column of the cell
 55	 *
 56	 *	@var	string
 57	 */
 58	private $_column;
 59
 60	/**
 61	 *	Row of the cell
 62	 *
 63	 *	@var	int
 64	 */
 65	private $_row;
 66
 67	/**
 68	 *	Value of the cell
 69	 *
 70	 *	@var	mixed
 71	 */
 72	private $_value;
 73
 74	/**
 75	 *	Calculated value of the cell (used for caching)
 76	 *	This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
 77	 *		create the original spreadsheet file.
 78	 *	Note that this value is not guaranteed to reflect the actual calculated value because it is
 79	 *		possible that auto-calculation was disabled in the original spreadsheet, and underlying data
 80	 *		values used by the formula have changed since it was last calculated.
 81	 *
 82	 *	@var mixed
 83	 */
 84	private $_calculatedValue = NULL;
 85
 86	/**
 87	 *	Type of the cell data
 88	 *
 89	 *	@var	string
 90	 */
 91	private $_dataType;
 92
 93	/**
 94	 *	Parent worksheet
 95	 *
 96	 *	@var	PHPExcel_Worksheet
 97	 */
 98	private $_parent;
 99
100	/**
101	 *	Index to cellXf
102	 *
103	 *	@var	int
104	 */
105	private $_xfIndex;
106
107	/**
108	 *	Attributes of the formula
109	 *
110	 */
111	private $_formulaAttributes;
112
113
114	/**
115	 *	Send notification to the cache controller
116	 *
117	 *	@return void
118	 **/
119	public function notifyCacheController() {
120		$this->_parent->getCellCacheController()->updateCacheData($this);
121		return $this;
122	}
123
124	public function detach() {
125		$this->_parent = NULL;
126	}
127
128	public function attach($parent) {
129		$this->_parent = $parent;
130	}
131
132
133	/**
134	 *	Create a new Cell
135	 *
136	 *	@param	string				$pColumn
137	 *	@param	int					$pRow
138	 *	@param	mixed				$pValue
139	 *	@param	string				$pDataType
140	 *	@param	PHPExcel_Worksheet	$pSheet
141	 *	@throws	PHPExcel_Exception
142	 */
143	public function __construct($pColumn = 'A', $pRow = 1, $pValue = NULL, $pDataType = NULL, PHPExcel_Worksheet $pSheet = NULL)
144	{
145		// Initialise cell coordinate
146		$this->_column = strtoupper($pColumn);
147		$this->_row = $pRow;
148
149		// Initialise cell value
150		$this->_value = $pValue;
151
152		// Set worksheet
153		$this->_parent = $pSheet;
154
155		// Set datatype?
156		if ($pDataType !== NULL) {
157			if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2)
158				$pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
159			$this->_dataType = $pDataType;
160		} else {
161			if (!self::getValueBinder()->bindValue($this, $pValue)) {
162				throw new PHPExcel_Exception("Value could not be bound to cell.");
163			}
164		}
165
166		// set default index to cellXf
167		$this->_xfIndex = 0;
168	}
169
170	/**
171	 *	Get cell coordinate column
172	 *
173	 *	@return	string
174	 */
175	public function getColumn()
176	{
177		return $this->_column;
178	}
179
180	/**
181	 *	Get cell coordinate row
182	 *
183	 *	@return	int
184	 */
185	public function getRow()
186	{
187		return $this->_row;
188	}
189
190	/**
191	 *	Get cell coordinate
192	 *
193	 *	@return	string
194	 */
195	public function getCoordinate()
196	{
197		return $this->_column . $this->_row;
198	}
199
200	/**
201	 *	Get cell value
202	 *
203	 *	@return	mixed
204	 */
205	public function getValue()
206	{
207		return $this->_value;
208	}
209
210	/**
211	 *	Get cell value with formatting
212	 *
213	 *	@return	string
214	 */
215	public function getFormattedValue()
216	{
217		return (string) PHPExcel_Style_NumberFormat::toFormattedString(
218				$this->getCalculatedValue(),
219				$this->_parent->getParent()->getCellXfByIndex($this->getXfIndex())
220					->getNumberFormat()->getFormatCode()
221			);
222	}
223
224	/**
225	 *	Set cell value
226	 *
227	 *	Sets the value for a cell, automatically determining the datatype using the value binder
228	 *
229	 *	@param	mixed	$pValue					Value
230	 *	@return	PHPExcel_Cell
231	 *	@throws	PHPExcel_Exception
232	 */
233	public function setValue($pValue = NULL)
234	{
235		if (!self::getValueBinder()->bindValue($this, $pValue)) {
236			throw new PHPExcel_Exception("Value could not be bound to cell.");
237		}
238		return $this;
239	}
240
241	/**
242	 *	Set the value for a cell, with the explicit data type passed to the method (bypassing any use of the value binder)
243	 *
244	 *	@param	mixed	$pValue			Value
245	 *	@param	string	$pDataType		Explicit data type
246	 *	@return	PHPExcel_Cell
247	 *	@throws	PHPExcel_Exception
248	 */
249	public function setValueExplicit($pValue = NULL, $pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
250	{
251		// set the value according to data type
252		switch ($pDataType) {
253			case PHPExcel_Cell_DataType::TYPE_STRING2:
254				$pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
255			case PHPExcel_Cell_DataType::TYPE_STRING:
256			case PHPExcel_Cell_DataType::TYPE_NULL:
257			case PHPExcel_Cell_DataType::TYPE_INLINE:
258				$this->_value = PHPExcel_Cell_DataType::checkString($pValue);
259				break;
260			case PHPExcel_Cell_DataType::TYPE_NUMERIC:
261				$this->_value = (float)$pValue;
262				break;
263			case PHPExcel_Cell_DataType::TYPE_FORMULA:
264				$this->_value = (string)$pValue;
265				break;
266			case PHPExcel_Cell_DataType::TYPE_BOOL:
267				$this->_value = (bool)$pValue;
268				break;
269			case PHPExcel_Cell_DataType::TYPE_ERROR:
270				$this->_value = PHPExcel_Cell_DataType::checkErrorCode($pValue);
271				break;
272			default:
273				throw new PHPExcel_Exception('Invalid datatype: ' . $pDataType);
274				break;
275		}
276
277		// set the datatype
278		$this->_dataType = $pDataType;
279
280		return $this->notifyCacheController();
281	}
282
283	/**
284	 *	Get calculated cell value
285	 *
286	 *	@deprecated		Since version 1.7.8 for planned changes to cell for array formula handling
287	 *
288	 *	@return	mixed
289	 *	@throws	PHPExcel_Exception
290	 */
291	public function getCalculatedValue($resetLog = TRUE)
292	{
293//		echo 'Cell '.$this->getCoordinate().' value is a '.$this->_dataType.' with a value of '.$this->getValue().'<br />';
294		if ($this->_dataType == PHPExcel_Cell_DataType::TYPE_FORMULA) {
295			try {
296//				echo 'Cell value for '.$this->getCoordinate().' is a formula: Calculating value<br />';
297				$result = PHPExcel_Calculation::getInstance()->calculateCellValue($this,$resetLog);
298//				echo $this->getCoordinate().' calculation result is '.$result.'<br />';
299			} catch ( Exception $ex ) {
300				if (($ex->getMessage() === 'Unable to access External Workbook') && ($this->_calculatedValue !== NULL)) {
301//					echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().'<br />';
302					return $this->_calculatedValue; // Fallback for calculations referencing external files.
303				}
304//				echo 'Calculation Exception: '.$ex->getMessage().'<br />';
305				$result = '#N/A';
306				throw(
307					new PHPExcel_Exception(
308						$this->getParent()->getTitle().'!'.$this->getCoordinate().' -> '.$ex->getMessage()
309					)
310				);
311			}
312
313			if ($result === '#Not Yet Implemented') {
314//				echo 'Returning fallback value of '.$this->_calculatedValue.' for cell '.$this->getCoordinate().'<br />';
315				return $this->_calculatedValue; // Fallback if calculation engine does not support the formula.
316			}
317//			echo 'Returning calculated value of '.$result.' for cell '.$this->getCoordinate().'<br />';
318			return $result;
319		}
320
321//		if ($this->_value === NULL) {
322//			echo 'Cell '.$this->getCoordinate().' has no value, formula or otherwise<br />';
323//			return NULL;
324//		}
325//		echo 'Cell value for '.$this->getCoordinate().' is not a formula: Returning data value of '.$this->_value.'<br />';
326		return $this->_value;
327	}
328
329	/**
330	 *	Set old calculated value (cached)
331	 *
332	 *	@param	mixed $pValue	Value
333	 *	@return	PHPExcel_Cell
334	 */
335	public function setCalculatedValue($pValue = NULL)
336	{
337		if ($pValue !== NULL) {
338			$this->_calculatedValue = (is_numeric($pValue)) ? (float) $pValue : $pValue;
339		}
340
341		return $this->notifyCacheController();
342	}
343
344	/**
345	 *	Get old calculated value (cached)
346	 *	This returns the value last calculated by MS Excel or whichever spreadsheet program was used to
347	 *		create the original spreadsheet file.
348	 *	Note that this value is not guaranteed to refelect the actual calculated value because it is
349	 *		possible that auto-calculation was disabled in the original spreadsheet, and underlying data
350	 *		values used by the formula have changed since it was last calculated.
351	 *
352	 *	@return	mixed
353	 */
354	public function getOldCalculatedValue()
355	{
356		return $this->_calculatedValue;
357	}
358
359	/**
360	 *	Get cell data type
361	 *
362	 *	@return string
363	 */
364	public function getDataType()
365	{
366		return $this->_dataType;
367	}
368
369	/**
370	 *	Set cell data type
371	 *
372	 *	@param	string $pDataType
373	 *	@return	PHPExcel_Cell
374	 */
375	public function setDataType($pDataType = PHPExcel_Cell_DataType::TYPE_STRING)
376	{
377		if ($pDataType == PHPExcel_Cell_DataType::TYPE_STRING2)
378			$pDataType = PHPExcel_Cell_DataType::TYPE_STRING;
379
380		$this->_dataType = $pDataType;
381
382		return $this->notifyCacheController();
383	}
384
385	/**
386	 *	Does this cell contain Data validation rules?
387	 *
388	 *	@return	boolean
389	 *	@throws	PHPExcel_Exception
390	 */
391	public function hasDataValidation()
392	{
393		if (!isset($this->_parent)) {
394			throw new PHPExcel_Exception('Cannot check for data validation when cell is not bound to a worksheet');
395		}
396
397		return $this->_parent->dataValidationExists($this->getCoordinate());
398	}
399
400	/**
401	 *	Get Data validation rules
402	 *
403	 *	@return	PHPExcel_Cell_DataValidation
404	 *	@throws	PHPExcel_Exception
405	 */
406	public function getDataValidation()
407	{
408		if (!isset($this->_parent)) {
409			throw new PHPExcel_Exception('Cannot get data validation for cell that is not bound to a worksheet');
410		}
411
412		return $this->_parent->getDataValidation($this->getCoordinate());
413	}
414
415	/**
416	 *	Set Data validation rules
417	 *
418	 *	@param	PHPExcel_Cell_DataValidation	$pDataValidation
419	 *	@return	PHPExcel_Cell
420	 *	@throws	PHPExcel_Exception
421	 */
422	public function setDataValidation(PHPExcel_Cell_DataValidation $pDataValidation = NULL)
423	{
424		if (!isset($this->_parent)) {
425			throw new PHPExcel_Exception('Cannot set data validation for cell that is not bound to a worksheet');
426		}
427
428		$this->_parent->setDataValidation($this->getCoordinate(), $pDataValidation);
429
430		return $this->notifyCacheController();
431	}
432
433	/**
434	 *	Does this cell contain a Hyperlink?
435	 *
436	 *	@return boolean
437	 *	@throws	PHPExcel_Exception
438	 */
439	public function hasHyperlink()
440	{
441		if (!isset($this->_parent)) {
442			throw new PHPExcel_Exception('Cannot check for hyperlink when cell is not bound to a worksheet');
443		}
444
445		return $this->_parent->hyperlinkExists($this->getCoordinate());
446	}
447
448	/**
449	 *	Get Hyperlink
450	 *
451	 *	@return	PHPExcel_Cell_Hyperlink
452	 *	@throws	PHPExcel_Exception
453	 */
454	public function getHyperlink()
455	{
456		if (!isset($this->_parent)) {
457			throw new PHPExcel_Exception('Cannot get hyperlink for cell that is not bound to a worksheet');
458		}
459
460		return $this->_parent->getHyperlink($this->getCoordinate());
461	}
462
463	/**
464	 *	Set Hyperlink
465	 *
466	 *	@param	PHPExcel_Cell_Hyperlink	$pHyperlink
467	 *	@return	PHPExcel_Cell
468	 *	@throws	PHPExcel_Exception
469	 */
470	public function setHyperlink(PHPExcel_Cell_Hyperlink $pHyperlink = NULL)
471	{
472		if (!isset($this->_parent)) {
473			throw new PHPExcel_Exception('Cannot set hyperlink for cell that is not bound to a worksheet');
474		}
475
476		$this->_parent->setHyperlink($this->getCoordinate(), $pHyperlink);
477
478		return $this->notifyCacheController();
479	}
480
481	/**
482	 *	Get parent worksheet
483	 *
484	 *	@return PHPExcel_Worksheet
485	 */
486	public function getParent() {
487		return $this->_parent;
488	}
489
490	/**
491	 *	Re-bind parent
492	 *
493	 *	@param	PHPExcel_Worksheet $parent
494	 *	@return	PHPExcel_Cell
495	 */
496	public function rebindParent(PHPExcel_Worksheet $parent) {
497		$this->_parent = $parent;
498
499		return $this->notifyCacheController();
500	}
501
502	/**
503	 *	Is cell in a specific range?
504	 *
505	 *	@param	string	$pRange		Cell range (e.g. A1:A1)
506	 *	@return	boolean
507	 */
508	public function isInRange($pRange = 'A1:A1')
509	{
510		list($rangeStart,$rangeEnd) = self::rangeBoundaries($pRange);
511
512		// Translate properties
513		$myColumn	= self::columnIndexFromString($this->getColumn());
514		$myRow		= $this->getRow();
515
516		// Verify if cell is in range
517		return (($rangeStart[0] <= $myColumn) && ($rangeEnd[0] >= $myColumn) &&
518				($rangeStart[1] <= $myRow) && ($rangeEnd[1] >= $myRow)
519			   );
520	}
521
522	/**
523	 *	Coordinate from string
524	 *
525	 *	@param	string	$pCoordinateString
526	 *	@return	array	Array containing column and row (indexes 0 and 1)
527	 *	@throws	PHPExcel_Exception
528	 */
529	public static function coordinateFromString($pCoordinateString = 'A1')
530	{
531		if (preg_match("/^([$]?[A-Z]{1,3})([$]?\d{1,7})$/", $pCoordinateString, $matches)) {
532			return array($matches[1],$matches[2]);
533		} elseif ((strpos($pCoordinateString,':') !== FALSE) || (strpos($pCoordinateString,',') !== FALSE)) {
534			throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
535		} elseif ($pCoordinateString == '') {
536			throw new PHPExcel_Exception('Cell coordinate can not be zero-length string');
537		}
538
539		throw new PHPExcel_Exception('Invalid cell coordinate '.$pCoordinateString);
540	}
541
542	/**
543	 *	Make string row, column or cell coordinate absolute
544	 *
545	 *	@param	string	$pCoordinateString		e.g. 'A' or '1' or 'A1'
546	 *					Note that this value can be a row or column reference as well as a cell reference
547	 *	@return	string	Absolute coordinate		e.g. '$A' or '$1' or '$A$1'
548	 *	@throws	PHPExcel_Exception
549	 */
550	public static function absoluteReference($pCoordinateString = 'A1')
551	{
552		if (strpos($pCoordinateString,':') === FALSE && strpos($pCoordinateString,',') === FALSE) {
553			// Split out any worksheet name from the reference
554			$worksheet = '';
555			$cellAddress = explode('!',$pCoordinateString);
556			if (count($cellAddress) > 1) {
557				list($worksheet,$pCoordinateString) = $cellAddress;
558			}
559			if ($worksheet > '')	$worksheet .= '!';
560
561			// Create absolute coordinate
562			if (ctype_digit($pCoordinateString)) {
563				return $worksheet . '$' . $pCoordinateString;
564			} elseif (ctype_alpha($pCoordinateString)) {
565				return $worksheet . '$' . strtoupper($pCoordinateString);
566			}
567			return $worksheet . self::absoluteCoordinate($pCoordinateString);
568		}
569
570		throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
571	}
572
573	/**
574	 *	Make string coordinate absolute
575	 *
576	 *	@param	string	$pCoordinateString		e.g. 'A1'
577	 *	@return	string	Absolute coordinate		e.g. '$A$1'
578	 *	@throws	PHPExcel_Exception
579	 */
580	public static function absoluteCoordinate($pCoordinateString = 'A1')
581	{
582		if (strpos($pCoordinateString,':') === FALSE && strpos($pCoordinateString,',') === FALSE) {
583			// Split out any worksheet name from the coordinate
584			$worksheet = '';
585			$cellAddress = explode('!',$pCoordinateString);
586			if (count($cellAddress) > 1) {
587				list($worksheet,$pCoordinateString) = $cellAddress;
588			}
589			if ($worksheet > '')	$worksheet .= '!';
590
591			// Create absolute coordinate
592			list($column, $row) = self::coordinateFromString($pCoordinateString);
593			$column = ltrim($column,'$');
594			$row = ltrim($row,'$');
595			return $worksheet . '$' . $column . '$' . $row;
596		}
597
598		throw new PHPExcel_Exception('Cell coordinate string can not be a range of cells');
599	}
600
601	/**
602	 *	Split range into coordinate strings
603	 *
604	 *	@param	string	$pRange		e.g. 'B4:D9' or 'B4:D9,H2:O11' or 'B4'
605	 *	@return	array	Array containg one or more arrays containing one or two coordinate strings
606	 *								e.g. array('B4','D9') or array(array('B4','D9'),array('H2','O11'))
607	 *										or array('B4')
608	 */
609	public static function splitRange($pRange = 'A1:A1')
610	{
611		// Ensure $pRange is a valid range
612		if(empty($pRange)) {
613			$pRange = self::DEFAULT_RANGE;
614		}
615
616		$exploded = explode(',', $pRange);
617		$counter = count($exploded);
618		for ($i = 0; $i < $counter; ++$i) {
619			$exploded[$i] = explode(':', $exploded[$i]);
620		}
621		return $exploded;
622	}
623
624	/**
625	 *	Build range from coordinate strings
626	 *
627	 *	@param	array	$pRange	Array containg one or more arrays containing one or two coordinate strings
628	 *	@return	string	String representation of $pRange
629	 *	@throws	PHPExcel_Exception
630	 */
631	public static function buildRange($pRange)
632	{
633		// Verify range
634		if (!is_array($pRange) || empty($pRange) || !is_array($pRange[0])) {
635			throw new PHPExcel_Exception('Range does not contain any information');
636		}
637
638		// Build range
639		$imploded = array();
640		$counter = count($pRange);
641		for ($i = 0; $i < $counter; ++$i) {
642			$pRange[$i] = implode(':', $pRange[$i]);
643		}
644		$imploded = implode(',', $pRange);
645
646		return $imploded;
647	}
648
649	/**
650	 *	Calculate range boundaries
651	 *
652	 *	@param	string	$pRange		Cell range (e.g. A1:A1)
653	 *	@return	array	Range coordinates array(Start Cell, End Cell)
654	 *					where Start Cell and End Cell are arrays (Column Number, Row Number)
655	 */
656	public static function rangeBoundaries($pRange = 'A1:A1')
657	{
658		// Ensure $pRange is a valid range
659		if(empty($pRange)) {
660			$pRange = self::DEFAULT_RANGE;
661		}
662
663		// Uppercase coordinate
664		$pRange = strtoupper($pRange);
665
666		// Extract range
667		if (strpos($pRange, ':') === FALSE) {
668			$rangeA = $rangeB = $pRange;
669		} else {
670			list($rangeA, $rangeB) = explode(':', $pRange);
671		}
672
673		// Calculate range outer borders
674		$rangeStart = self::coordinateFromString($rangeA);
675		$rangeEnd	= self::coordinateFromString($rangeB);
676
677		// Translate column into index
678		$rangeStart[0]	= self::columnIndexFromString($rangeStart[0]);
679		$rangeEnd[0]	= self::columnIndexFromString($rangeEnd[0]);
680
681		return array($rangeStart, $rangeEnd);
682	}
683
684	/**
685	 *	Calculate range dimension
686	 *
687	 *	@param	string	$pRange		Cell range (e.g. A1:A1)
688	 *	@return	array	Range dimension (width, height)
689	 */
690	public static function rangeDimension($pRange = 'A1:A1')
691	{
692		// Calculate range outer borders
693		list($rangeStart,$rangeEnd) = self::rangeBoundaries($pRange);
694
695		return array( ($rangeEnd[0] - $rangeStart[0] + 1), ($rangeEnd[1] - $rangeStart[1] + 1) );
696	}
697
698	/**
699	 *	Calculate range boundaries
700	 *
701	 *	@param	string	$pRange		Cell range (e.g. A1:A1)
702	 *	@return	array	Range coordinates array(Start Cell, End Cell)
703	 *					where Start Cell and End Cell are arrays (Column ID, Row Number)
704	 */
705	public static function getRangeBoundaries($pRange = 'A1:A1')
706	{
707		// Ensure $pRange is a valid range
708		if(empty($pRange)) {
709			$pRange = self::DEFAULT_RANGE;
710		}
711
712		// Uppercase coordinate
713		$pRange = strtoupper($pRange);
714
715		// Extract range
716		if (strpos($pRange, ':') === FALSE) {
717			$rangeA = $rangeB = $pRange;
718		} else {
719			list($rangeA, $rangeB) = explode(':', $pRange);
720		}
721
722		return array( self::coordinateFromString($rangeA), self::coordinateFromString($rangeB));
723	}
724
725	/**
726	 *	Column index from string
727	 *
728	 *	@param	string $pString
729	 *	@return	int Column index (base 1 !!!)
730	 *	@throws	Exception
731	 */
732	public static function columnIndexFromString($pString = 'A')
733	{
734		//	Using a lookup cache adds a slight memory overhead, but boosts speed
735		//	caching using a static within the method is faster than a class static,
736		//		though it's additional memory overhead
737		static $_indexCache = array();
738
739		if (isset($_indexCache[$pString]))
740			return $_indexCache[$pString];
741
742		//	It's surprising how costly the strtoupper() and ord() calls actually are, so we use a lookup array rather than use ord()
743		//		and make it case insensitive to get rid of the strtoupper() as well. Because it's a static, there's no significant
744		//		memory overhead either
745		static $_columnLookup = array(
746			'A' => 1, 'B' => 2, 'C' => 3, 'D' => 4, 'E' => 5, 'F' => 6, 'G' => 7, 'H' => 8, 'I' => 9, 'J' => 10, 'K' => 11, 'L' => 12, 'M' => 13,
747			'N' => 14, 'O' => 15, 'P' => 16, 'Q' => 17, 'R' => 18, 'S' => 19, 'T' => 20, 'U' => 21, 'V' => 22, 'W' => 23, 'X' => 24, 'Y' => 25, 'Z' => 26,
748			'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5, 'f' => 6, 'g' => 7, 'h' => 8, 'i' => 9, 'j' => 10, 'k' => 11, 'l' => 12, 'm' => 13,
749			'n' => 14, 'o' => 15, 'p' => 16, 'q' => 17, 'r' => 18, 's' => 19, 't' => 20, 'u' => 21, 'v' => 22, 'w' => 23, 'x' => 24, 'y' => 25, 'z' => 26
750		);
751
752		//	We also use the language construct isset() rather than the more costly strlen() function to match the length of $pString
753		//		for improved performance
754		if (isset($pString{0})) {
755			if (!isset($pString{1})) {
756				$_indexCache[$pString] = $_columnLookup[$pString];
757				return $_indexCache[$pString];
758			} elseif(!isset($pString{2})) {
759				$_indexCache[$pString] = $_columnLookup[$pString{0}] * 26 + $_columnLookup[$pString{1}];
760				return $_indexCache[$pString];
761			} elseif(!isset($pString{3})) {
762				$_indexCache[$pString] = $_columnLookup[$pString{0}] * 676 + $_columnLookup[$pString{1}] * 26 + $_columnLookup[$pString{2}];
763				return $_indexCache[$pString];
764			}
765		}
766		throw new PHPExcel_Exception("Column string index can not be " . ((isset($pString{0})) ? "longer than 3 characters" : "empty"));
767	}
768
769	/**
770	 *	String from columnindex
771	 *
772	 *	@param	int $pColumnIndex Column index (base 0 !!!)
773	 *	@return	string
774	 */
775	public static function stringFromColumnIndex($pColumnIndex = 0)
776	{
777		//	Using a lookup cache adds a slight memory overhead, but boosts speed
778		//	caching using a static within the method is faster than a class static,
779		//		though it's additional memory overhead
780		static $_indexCache = array();
781
782		if (!isset($_indexCache[$pColumnIndex])) {
783			// Determine column string
784			if ($pColumnIndex < 26) {
785				$_indexCache[$pColumnIndex] = chr(65 + $pColumnIndex);
786			} elseif ($pColumnIndex < 702) {
787				$_indexCache[$pColumnIndex] = chr(64 + ($pColumnIndex / 26)) .
788											  chr(65 + $pColumnIndex % 26);
789			} else {
790				$_indexCache[$pColumnIndex] = chr(64 + (($pColumnIndex - 26) / 676)) .
791											  chr(65 + ((($pColumnIndex - 26) % 676) / 26)) .
792											  chr(65 + $pColumnIndex % 26);
793			}
794		}
795		return $_indexCache[$pColumnIndex];
796	}
797
798	/**
799	 *	Extract all cell references in range
800	 *
801	 *	@param	string	$pRange		Range (e.g. A1 or A1:C10 or A1:E10 A20:E25)
802	 *	@return	array	Array containing single cell references
803	 */
804	public static function extractAllCellReferencesInRange($pRange = 'A1') {
805		// Returnvalue
806		$returnValue = array();
807
808		// Explode spaces
809		$cellBlocks = explode(' ', str_replace('$', '', strtoupper($pRange)));
810		foreach ($cellBlocks as $cellBlock) {
811			// Single cell?
812			if (strpos($cellBlock,':') === FALSE && strpos($cellBlock,',') === FALSE) {
813				$returnValue[] = $cellBlock;
814				continue;
815			}
816
817			// Range...
818			$ranges = self::splitRange($cellBlock);
819			foreach($ranges as $range) {
820				// Single cell?
821				if (!isset($range[1])) {
822					$returnValue[] = $range[0];
823					continue;
824				}
825
826				// Range...
827				list($rangeStart, $rangeEnd)	= $range;
828				list($startCol, $startRow)	= sscanf($rangeStart,'%[A-Z]%d');
829				list($endCol, $endRow)		= sscanf($rangeEnd,'%[A-Z]%d');
830				$endCol++;
831
832				// Current data
833				$currentCol	= $startCol;
834				$currentRow	= $startRow;
835
836				// Loop cells
837				while ($currentCol != $endCol) {
838					while ($currentRow <= $endRow) {
839						$returnValue[] = $currentCol.$currentRow;
840						++$currentRow;
841					}
842					++$currentCol;
843					$currentRow = $startRow;
844				}
845			}
846		}
847
848		//	Sort the result by column and row
849		$sortKeys = array();
850		foreach (array_unique($returnValue) as $coord) {
851			list($column,$row) = sscanf($coord,'%[A-Z]%d');
852			$sortKeys[sprintf('%3s%09d',$column,$row)] = $coord;
853		}
854		ksort($sortKeys);
855
856		// Return value
857		return array_values($sortKeys);
858	}
859
860	/**
861	 * Compare 2 cells
862	 *
863	 * @param	PHPExcel_Cell	$a	Cell a
864	 * @param	PHPExcel_Cell	$a	Cell b
865	 * @return	int		Result of comparison (always -1 or 1, never zero!)
866	 */
867	public static function compareCells(PHPExcel_Cell $a, PHPExcel_Cell $b)
868	{
869		if ($a->_row < $b->_row) {
870			return -1;
871		} elseif ($a->_row > $b->_row) {
872			return 1;
873		} elseif (self::columnIndexFromString($a->_column) < self::columnIndexFromString($b->_column)) {
874			return -1;
875		} else {
876			return 1;
877		}
878	}
879
880	/**
881	 * Get value binder to use
882	 *
883	 * @return PHPExcel_Cell_IValueBinder
884	 */
885	public static function getValueBinder() {
886		if (self::$_valueBinder === NULL) {
887			self::$_valueBinder = new PHPExcel_Cell_DefaultValueBinder();
888		}
889
890		return self::$_valueBinder;
891	}
892
893	/**
894	 * Set value binder to use
895	 *
896	 * @param PHPExcel_Cell_IValueBinder $binder
897	 * @throws Exception
898	 */
899	public static function setValueBinder(PHPExcel_Cell_IValueBinder $binder = NULL) {
900		if ($binder === NULL) {
901			throw new Exception("A PHPExcel_Cell_IValueBinder is required for PHPExcel to function correctly.");
902		}
903
904		self::$_valueBinder = $binder;
905	}
906
907	/**
908	 * Implement PHP __clone to create a deep clone, not just a shallow copy.
909	 */
910	public function __clone() {
911		$vars = get_object_vars($this);
912		foreach ($vars as $key => $value) {
913			if ((is_object($value)) && ($key != '_parent')) {
914				$this->$key = clone $value;
915			} else {
916				$this->$key = $value;
917			}
918		}
919	}
920
921	/**
922	 * Get index to cellXf
923	 *
924	 * @return int
925	 */
926	public function getXfIndex()
927	{
928		return $this->_xfIndex;
929	}
930
931	/**
932	 * Set index to cellXf
933	 *
934	 * @param int $pValue
935	 * @return PHPExcel_Cell
936	 */
937	public function setXfIndex($pValue = 0)
938	{
939		$this->_xfIndex = $pValue;
940
941		return $this->notifyCacheController();
942	}
943
944	/**
945	 *	@deprecated		Since version 1.7.8 for planned changes to cell for array formula handling
946	 */
947	public function setFormulaAttributes($pAttributes)
948	{
949		$this->_formulaAttributes = $pAttributes;
950		return $this;
951	}
952
953	/**
954	 *	@deprecated		Since version 1.7.8 for planned changes to cell for array formula handling
955	 */
956	public function getFormulaAttributes()
957	{
958		return $this->_formulaAttributes;
959	}
960
961    /**
962     * Convert to string
963     *
964     * @return string
965     */
966	public function __toString()
967	{
968		return (string) $this->getValue();
969	}
970
971}
972