1: <?php
2: /**
3: * PHPExcel
4: *
5: * Copyright (c) 2006 - 2014 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_CachedObjectStorage
23: * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
24: * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
25: * @version 1.8.0, 2014-03-02
26: */
27:
28:
29: /**
30: * PHPExcel_CachedObjectStorage_APC
31: *
32: * @category PHPExcel
33: * @package PHPExcel_CachedObjectStorage
34: * @copyright Copyright (c) 2006 - 2014 PHPExcel (http://www.codeplex.com/PHPExcel)
35: */
36: class PHPExcel_CachedObjectStorage_APC extends PHPExcel_CachedObjectStorage_CacheBase implements PHPExcel_CachedObjectStorage_ICache {
37:
38: /**
39: * Prefix used to uniquely identify cache data for this worksheet
40: *
41: * @access private
42: * @var string
43: */
44: private $_cachePrefix = null;
45:
46: /**
47: * Cache timeout
48: *
49: * @access private
50: * @var integer
51: */
52: private $_cacheTime = 600;
53:
54:
55: /**
56: * Store cell data in cache for the current cell object if it's "dirty",
57: * and the 'nullify' the current cell object
58: *
59: * @access private
60: * @return void
61: * @throws PHPExcel_Exception
62: */
63: protected function _storeData() {
64: if ($this->_currentCellIsDirty && !empty($this->_currentObjectID)) {
65: $this->_currentObject->detach();
66:
67: if (!apc_store($this->_cachePrefix.$this->_currentObjectID.'.cache',serialize($this->_currentObject),$this->_cacheTime)) {
68: $this->__destruct();
69: throw new PHPExcel_Exception('Failed to store cell '.$this->_currentObjectID.' in APC');
70: }
71: $this->_currentCellIsDirty = false;
72: }
73: $this->_currentObjectID = $this->_currentObject = null;
74: } // function _storeData()
75:
76:
77: /**
78: * Add or Update a cell in cache identified by coordinate address
79: *
80: * @access public
81: * @param string $pCoord Coordinate address of the cell to update
82: * @param PHPExcel_Cell $cell Cell to update
83: * @return void
84: * @throws PHPExcel_Exception
85: */
86: public function addCacheData($pCoord, PHPExcel_Cell $cell) {
87: if (($pCoord !== $this->_currentObjectID) && ($this->_currentObjectID !== null)) {
88: $this->_storeData();
89: }
90: $this->_cellCache[$pCoord] = true;
91:
92: $this->_currentObjectID = $pCoord;
93: $this->_currentObject = $cell;
94: $this->_currentCellIsDirty = true;
95:
96: return $cell;
97: } // function addCacheData()
98:
99:
100: /**
101: * Is a value set in the current PHPExcel_CachedObjectStorage_ICache for an indexed cell?
102: *
103: * @access public
104: * @param string $pCoord Coordinate address of the cell to check
105: * @return void
106: * @return boolean
107: */
108: public function isDataSet($pCoord) {
109: // Check if the requested entry is the current object, or exists in the cache
110: if (parent::isDataSet($pCoord)) {
111: if ($this->_currentObjectID == $pCoord) {
112: return true;
113: }
114: // Check if the requested entry still exists in apc
115: $success = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
116: if ($success === FALSE) {
117: // Entry no longer exists in APC, so clear it from the cache array
118: parent::deleteCacheData($pCoord);
119: throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
120: }
121: return true;
122: }
123: return false;
124: } // function isDataSet()
125:
126:
127: /**
128: * Get cell at a specific coordinate
129: *
130: * @access public
131: * @param string $pCoord Coordinate of the cell
132: * @throws PHPExcel_Exception
133: * @return PHPExcel_Cell Cell that was found, or null if not found
134: */
135: public function getCacheData($pCoord) {
136: if ($pCoord === $this->_currentObjectID) {
137: return $this->_currentObject;
138: }
139: $this->_storeData();
140:
141: // Check if the entry that has been requested actually exists
142: if (parent::isDataSet($pCoord)) {
143: $obj = apc_fetch($this->_cachePrefix.$pCoord.'.cache');
144: if ($obj === FALSE) {
145: // Entry no longer exists in APC, so clear it from the cache array
146: parent::deleteCacheData($pCoord);
147: throw new PHPExcel_Exception('Cell entry '.$pCoord.' no longer exists in APC cache');
148: }
149: } else {
150: // Return null if requested entry doesn't exist in cache
151: return null;
152: }
153:
154: // Set current entry to the requested entry
155: $this->_currentObjectID = $pCoord;
156: $this->_currentObject = unserialize($obj);
157: // Re-attach this as the cell's parent
158: $this->_currentObject->attach($this);
159:
160: // Return requested entry
161: return $this->_currentObject;
162: } // function getCacheData()
163:
164:
165: /**
166: * Get a list of all cell addresses currently held in cache
167: *
168: * @return array of string
169: */
170: public function getCellList() {
171: if ($this->_currentObjectID !== null) {
172: $this->_storeData();
173: }
174:
175: return parent::getCellList();
176: }
177:
178:
179: /**
180: * Delete a cell in cache identified by coordinate address
181: *
182: * @access public
183: * @param string $pCoord Coordinate address of the cell to delete
184: * @throws PHPExcel_Exception
185: */
186: public function deleteCacheData($pCoord) {
187: // Delete the entry from APC
188: apc_delete($this->_cachePrefix.$pCoord.'.cache');
189:
190: // Delete the entry from our cell address array
191: parent::deleteCacheData($pCoord);
192: } // function deleteCacheData()
193:
194:
195: /**
196: * Clone the cell collection
197: *
198: * @access public
199: * @param PHPExcel_Worksheet $parent The new worksheet
200: * @throws PHPExcel_Exception
201: * @return void
202: */
203: public function copyCellCollection(PHPExcel_Worksheet $parent) {
204: parent::copyCellCollection($parent);
205: // Get a new id for the new file name
206: $baseUnique = $this->_getUniqueID();
207: $newCachePrefix = substr(md5($baseUnique),0,8).'.';
208: $cacheList = $this->getCellList();
209: foreach($cacheList as $cellID) {
210: if ($cellID != $this->_currentObjectID) {
211: $obj = apc_fetch($this->_cachePrefix.$cellID.'.cache');
212: if ($obj === FALSE) {
213: // Entry no longer exists in APC, so clear it from the cache array
214: parent::deleteCacheData($cellID);
215: throw new PHPExcel_Exception('Cell entry '.$cellID.' no longer exists in APC');
216: }
217: if (!apc_store($newCachePrefix.$cellID.'.cache',$obj,$this->_cacheTime)) {
218: $this->__destruct();
219: throw new PHPExcel_Exception('Failed to store cell '.$cellID.' in APC');
220: }
221: }
222: }
223: $this->_cachePrefix = $newCachePrefix;
224: } // function copyCellCollection()
225:
226:
227: /**
228: * Clear the cell collection and disconnect from our parent
229: *
230: * @return void
231: */
232: public function unsetWorksheetCells() {
233: if ($this->_currentObject !== NULL) {
234: $this->_currentObject->detach();
235: $this->_currentObject = $this->_currentObjectID = null;
236: }
237:
238: // Flush the APC cache
239: $this->__destruct();
240:
241: $this->_cellCache = array();
242:
243: // detach ourself from the worksheet, so that it can then delete this object successfully
244: $this->_parent = null;
245: } // function unsetWorksheetCells()
246:
247:
248: /**
249: * Initialise this new cell collection
250: *
251: * @param PHPExcel_Worksheet $parent The worksheet for this cell collection
252: * @param array of mixed $arguments Additional initialisation arguments
253: */
254: public function __construct(PHPExcel_Worksheet $parent, $arguments) {
255: $cacheTime = (isset($arguments['cacheTime'])) ? $arguments['cacheTime'] : 600;
256:
257: if ($this->_cachePrefix === NULL) {
258: $baseUnique = $this->_getUniqueID();
259: $this->_cachePrefix = substr(md5($baseUnique),0,8).'.';
260: $this->_cacheTime = $cacheTime;
261:
262: parent::__construct($parent);
263: }
264: } // function __construct()
265:
266:
267: /**
268: * Destroy this cell collection
269: */
270: public function __destruct() {
271: $cacheList = $this->getCellList();
272: foreach($cacheList as $cellID) {
273: apc_delete($this->_cachePrefix.$cellID.'.cache');
274: }
275: } // function __destruct()
276:
277:
278: /**
279: * Identify whether the caching method is currently available
280: * Some methods are dependent on the availability of certain extensions being enabled in the PHP build
281: *
282: * @return boolean
283: */
284: public static function cacheMethodIsAvailable() {
285: if (!function_exists('apc_store')) {
286: return FALSE;
287: }
288: if (apc_sma_info() === FALSE) {
289: return FALSE;
290: }
291:
292: return TRUE;
293: }
294:
295: }
296: