## Apache Zeta Components Manual :: File Source for apc_array.php

## Source for file apc_array.php

Documentation is available at apc_array.php

1. <?php
2. /**
3. * File containing the ezcCacheStorageFileApcArray class.
4. *
5. * Licensed to the Apache Software Foundation (ASF) under one
6. * or more contributor license agreements. See the NOTICE file
7. * distributed with this work for additional information
8. * regarding copyright ownership. The ASF licenses this file
9. * to you under the Apache License, Version 2.0 (the
10. * "License"); you may not use this file except in compliance
11. * with the License. You may obtain a copy of the License at
12. *
13. * http://www.apache.org/licenses/LICENSE-2.0
14. *
15. * Unless required by applicable law or agreed to in writing,
16. * software distributed under the License is distributed on an
17. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18. * KIND, either express or implied. See the License for the
19. * specific language governing permissions and limitations
20. * under the License.
21. *
22. * @package Cache
23. * @version //autogentag//
24. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
25. * @filesource
26. */
28. /**
29. * This class is a replacement for the {@link ezcCacheStorageFileArray} class. Tries
30. * to serve data from a local APC cache if possible.
31. *
32. * Options for this class are defined in {@link ezcCacheStorageFileApcArrayOptions}.
33. *
34. * @apichange This class might be removed in future versions. Please use
35. * {@link ezcCacheStack} to achieve the desired behaior.
36. * @package Cache
37. * @version //autogentag//
38. */
39. class ezcCacheStorageFileApcArray extends ezcCacheStorageApc
40. {
41. /**
42. * Creates a new cache storage in the given location. The location in case
43. * of this storage class must a valid file system directory.
44. *
45. * Options can contain the 'ttl' (Time-To-Live). This is per default set
46. * to 1 day. The option 'permissions' can be used to define the file
47. * permissions of created cache items.
48. *
49. * For details about the options see {@link ezcCacheStorageFileApcArrayOptions}.
50. *
51. * @throws ezcBasePropertyNotFoundException
52. * If you tried to set a non-existent option value.
53. *
54. * @param string $location Path to the cache location. Must be a valid path
55. * @param array(string=>string) $options Options for the cache storage
56. */
57. public function __construct ( $location, array $options = array() )
58. {
59. parent:: __construct ( $location, array() );
61. // Overwrite parent set options with new ezcCacheStorageFileApcArrayOptions
62. $this-> properties ['options'] = new ezcCacheStorageFileApcArrayOptions ( $options );
63. }
65. /**
66. * Fetches the data from the cache.
67. *
68. * @param string $filename The ID/filename from where to fetch the object
69. * @param bool $useApc Use APC or the file system
70. * @return mixed The fetched data or false on failure
71. */
72. protected function fetchData ( $filename, $useApc = false )
73. {
74. if ( $useApc === true )
75. {
76. $data = $this-> backend ->fetch( $filename );
77. return ( is_object ( $data ) ) ? $data->data : false;
78. }
79. else
80. {
81. return ( include $filename );
82. }
83. }
85. /**
86. * Fetches the object from the cache.
87. *
88. * @param string $filename The ID/filename from where to fetch the data
89. * @return mixed The fetched object or false on failure
90. */
91. protected function fetchObject ( $filename )
92. {
93. $data = $this-> backend ->fetch( $filename );
94. return ( is_object ( $data ) ) ? $data : false;
95. }
97. /**
98. * Wraps the data in order to be stored in APC ($useApc = true) or on the
99. * file system ($useApc = false).
100. *
101. * @throws ezcCacheInvalidDataException
102. * If the data submitted can not be handled by this storage (object,
103. * resource).
104. *
105. * @param mixed $data Simple type or array
106. * @param bool $useApc Use APC or not
107. * @return mixed Prepared data
108. */
109. protected function prepareData ( $data, $useApc = false )
110. {
111. if ( $useApc === true )
112. {
113. if ( is_resource ( $data ) )
114. {
115. throw new ezcCacheInvalidDataException ( gettype ( $data ), array( 'simple', 'array', 'object' ) );
116. }
117. return new ezcCacheStorageFileApcArrayDataStruct ( $data, $this-> properties ['location'] );
118. }
119. else
120. {
121. if ( is_object ( $data )
122. || is_resource ( $data ) )
123. {
124. throw new ezcCacheInvalidDataException ( gettype ( $data ), array( 'simple', 'array' ) );
125. }
126. return "<?php\nreturn " . var_export ( $data, true ) . ";\n?>\n";
127. }
128. }
130. /**
131. * Stores data to the cache storage.
132. *
133. * @throws ezcBaseFilePermissionException
134. * If the directory to store the cache file could not be created.
135. * This exception means most likely that your cache directory
136. * has been corrupted by external influences (file permission
137. * change).
138. * @throws ezcBaseFileIoException
139. * If an error occured while writing the data to the cache. If this
140. * exception occurs, a serious error occured and your storage might
141. * be corruped (e.g. broken network connection, file system broken,
142. * ...).
143. * @throws ezcCacheInvalidDataException
144. * If the data submitted can not be handled by the implementation
145. * of {@link ezcCacheStorageFile}. Most implementations can not
146. * handle objects and resources.
147. * @throws ezcCacheApcException
148. * If the data could not be stored in APC.
149. *
150. * @param string $id Unique identifier
151. * @param mixed $data The data to store
152. * @param array(string=>string) $attributes Attributes describing the cached data
153. * @return string The ID string of the newly cached data
154. */
155. public function store ( $id, $data, $attributes = array() )
156. {
157. // Generates the identifier
158. $filename = $this-> properties ['location'] . $this-> generateIdentifier ( $id, $attributes );
160. // Purges the Registry Cache
161. if ( isset( $this-> registry [$filename] ) )
162. {
163. unset( $this-> registry [$filename] );
164. }
166. // Deletes the files if it already exists on the filesystem
167. if ( file_exists ( $filename ) )
168. {
169. if ( unlink ( $filename ) === false )
170. {
171. throw new ezcBaseFilePermissionException ( $filename, ezcBaseFileException ::WRITE, 'Could not delete existing cache file.' );
172. }
173. }
175. // Deletes the data from APC if it already exists
176. $this-> backend ->delete( $filename );
178. // Prepares the data for filesystem storage
179. $dataStr = $this-> prepareData ( $data );
181. // Tries to create the directory on the filesystem
182. $dirname = dirname ( $filename );
183. if ( ! is_dir ( $dirname )
184. && ! mkdir ( $dirname, 0777, true ) )
185. {
186. throw new ezcBaseFilePermissionException ( $dirname, ezcBaseFileException ::WRITE, 'Could not create directory to store cache file.' );
187. }
189. // Tries to write the file the filesystem
190. if ( @ file_put_contents ( $filename, $dataStr ) !== strlen ( $dataStr ) )
191. {
192. throw new ezcBaseFileIoException ( $filename, ezcBaseFileException ::WRITE, 'Could not write data to cache file.' );
193. }
195. // Tries to set the file permissions
196. if ( ezcBaseFeatures :: os () !== "Windows" )
197. {
198. chmod ( $filename, $this->options->permissions );
199. }
201. // Prepares the data for APC storage
202. $dataObj = $this-> prepareData ( $data, true );
203. $dataObj->mtime = @ filemtime ( $filename );
204. $dataObj->atime = time ();
206. // Stores it in APC
207. $this-> registerIdentifier ( $id, $attributes, $filename );
208. if ( !$this-> backend ->store( $filename, $dataObj, $this-> properties ['options']['ttl'] ) )
209. {
210. throw new ezcCacheApcException ( "APC store failed." );
211. }
213. // Returns the ID for no good reason
214. return $id;
215. }
217. /**
218. * Restores the data from the cache.
219. *
220. * @param string $id The item ID to restore
221. * @param array(string=>string) $attributes Attributes describing the data to restore
222. * @param bool $search Whether to search for items if not found directly
223. * @return mixed The cached data on success, otherwise false
224. */
225. public function restore ( $id, $attributes = array(), $search = false )
226. {
227. // Generates the identifier
228. $filename = $this-> properties ['location'] . $this-> generateIdentifier ( $id, $attributes );
230. // Grabs the data object from the APC
231. $dataObj = $this-> fetchObject ( $filename );
232. $useApc = false;
234. // Checks the APC object exists
235. if ( $dataObj !== false
236. && is_object ( $dataObj )
237. && isset( $dataObj->atime ) )
238. {
239. $useApc = true;
240. }
242. // Checks the APC object is still valid
243. if ( !isset( $this-> registry [$filename] )
244. && $useApc === true
245. && time () === $dataObj->atime )
246. {
247. // Make sure the FileSystem still has the file and that it hasn't changed
248. if ( file_exists ( $filename ) !== false
249. && @ filemtime ( $filename ) === $dataObj->mtime )
250. {
251. $dataObj->atime = time ();
252. $this-> backend ->store( $filename, $dataObj, $this-> properties ['options']['ttl'] );
253. }
254. else
255. {
256. $useApc = false;
257. $this-> backend ->delete( $filename );
258. }
259. }
261. // Searches the filesystem for the file
262. if ( !isset( $this-> registry [$filename] )
263. && $useApc === false
264. && file_exists ( $filename ) === false )
265. {
266. if ( $search === true
267. && count ( $files = $this-> search ( $id, $attributes ) ) === 1 )
268. {
269. $filename = $files[0][2];
270. }
271. else
272. {
273. // There are more elements found during search, so false is returned
274. return false;
275. }
276. }
278. // Returns false if no data is stored anywhere
279. if ( $useApc === false
280. && file_exists ( $filename ) === false )
281. {
282. // Purges APC
283. $this-> backend ->delete( $filename );
285. // Purges Registry Cache
286. if ( isset( $this-> registry [$filename] ) )
287. {
288. unset( $this-> registry [$filename] );
289. }
291. return false;
292. }
294. // Creates a Registry Object -- should only happen once per page load
295. if ( !isset( $this-> registry [$filename] ) )
296. {
297. $this-> registry [$filename] = new stdClass();
298. $this-> registry [$filename]->data = false;
299. $this-> registry [$filename]->mtime = $useApc ? $dataObj->mtime : null;
300. $this-> registry [$filename]->lifetime = $this-> calcLifetime ( $filename, $useApc );
301. }
303. // Purges the data if it is expired
304. if ( $this-> properties ['options']['ttl'] !== false
305. && $this-> calcLifetime ( $filename, $useApc ) > $this-> properties ['options']['ttl'] )
306. {
307. $this-> delete ( $id, $attributes, false ); // don't search
308. return false;
309. }
311. // Returns the data from the Registry Cache
312. if ( $this-> registry [$filename]->data !== false )
313. {
314. return ( $this-> registry [$filename]->data );
315. }
317. // Returns data from APC
318. else if ( $useApc === true
319. && ( isset( $dataObj->data ) || is_null ( $dataObj->data ) ) )
320. {
321. $this-> registry [$filename]->data = $dataObj->data; // primes the Registry cache
322. return ( $dataObj->data );
323. }
325. // Returns data from the filesystem
326. else if ( file_exists ( $filename ) !== false )
327. {
328. // Grabs the data from the filesystem
329. $dataStr = $this-> fetchData ( $filename );
331. // Stores it in the Registry Cache
332. $this-> registry [$filename]->data = $dataStr;
334. // Prepares the data for APC storage
335. $dataObj = $this-> prepareData ( $dataStr, true );
336. $dataObj->mtime = @ filemtime ( $filename );
337. $dataObj->atime = time ();
339. // Stores it in APC
340. $this-> backend ->store( $filename, $dataObj, $this-> properties ['options']['ttl'] );
342. // Returns the data
343. return ( $dataStr );
344. }
345. else
346. {
347. return false;
348. }
349. }
351. /**
352. * Deletes the data associated with $id or $attributes from the cache.
353. *
354. * @throws ezcBaseFilePermissionException
355. * If an already existsing cache file could not be unlinked.
356. * This exception means most likely that your cache directory
357. * has been corrupted by external influences (file permission
358. * change).
359. *
360. * @param string $id The item ID to purge
361. * @param array(string=>string) $attributes Attributes describing the data to restore
362. * @param bool $search Whether to search for items if not found directly
363. */
364. public function delete ( $id = null, $attributes = array(), $search = false )
365. {
366. $location = $this-> properties ['location'];
367. // Generates the identifier
368. $filename = $location . $this-> generateIdentifier ( $id, $attributes );
370. // Initializes the array
371. $delFiles = array();
373. clearstatcache ();
375. // Checks if the file exists on the filesystem
376. if ( file_exists ( $filename ) )
377. {
378. $delFiles[] = array( $id, $attributes, $filename );
379. }
380. else if ( $search === true )
381. {
382. $delFiles = $this-> search ( $id, $attributes );
383. }
385. $deletedIds = array();
386. // Deletes the files
387. foreach ( $delFiles as $count => $filename )
388. {
389. // Deletes from Registry Cache
390. if ( isset( $this-> registry [$filename[2]] ) )
391. {
392. unset( $this-> registry [$filename[2]] );
393. }
395. // Deletes from APC
396. $this-> backend ->delete( $filename[2] );
397. $this-> unRegisterIdentifier ( $filename[0], $filename[1], $filename[2], true );
398. if ( isset( $this-> registry [$location][$filename[0]][$filename[2]] ) )
399. {
400. unset( $this-> registry [$location][$filename[0]][$filename[2]] );
401. }
403. // Deletes from the filesystem
404. if ( @ unlink ( $filename[2] ) === false )
405. {
406. throw new ezcBaseFilePermissionException (
407. $filename,
408. ezcBaseFileException ::WRITE,
409. 'Could not unlink cache file.'
410. );
411. }
412. $deletedIds[] = $filename[0];
413. }
414. $this-> storeSearchRegistry ();
415. return $deletedIds;
416. }
418. /**
419. * Checks the path in the location property exists, and is read-/writable. It
420. * throws an exception if not.
421. *
422. * @throws ezcBaseFileNotFoundException
423. * If the storage location does not exist. This should usually not
424. * happen, since {@link ezcCacheManager::createCache()} already
425. * performs sanity checks for the cache location. In case this
426. * exception is thrown, your cache location has been corrupted
427. * after the cache was configured.
428. * @throws ezcBaseFileNotFoundException
429. * If the storage location is not a directory. This should usually
430. * not happen, since {@link ezcCacheManager::createCache()} already
431. * performs sanity checks for the cache location. In case this
432. * exception is thrown, your cache location has been corrupted
433. * after the cache was configured.
434. * @throws ezcBaseFilePermissionException
435. * If the storage location is not writeable. This should usually not
436. * happen, since {@link ezcCacheManager::createCache()} already
437. * performs sanity checks for the cache location. In case this
438. * exception is thrown, your cache location has been corrupted
439. * after the cache was configured.
440. */
441. protected function validateLocation ()
442. {
443. if ( file_exists ( $this-> properties ['location'] ) === false )
444. {
445. throw new ezcBaseFileNotFoundException ( $this-> properties ['location'], 'cache location' );
446. }
448. if ( is_dir ( $this-> properties ['location'] ) === false )
449. {
450. throw new ezcBaseFileNotFoundException ( $this-> properties ['location'], 'cache location', 'Cache location not a directory.' );
451. }
453. if ( is_writeable ( $this-> properties ['location'] ) === false )
454. {
455. throw new ezcBaseFilePermissionException ( $this-> properties ['location'], ezcBaseFileException ::WRITE, 'Cache location is not a directory.' );
456. }
457. }
459. /**
460. * Calculates the lifetime remaining for a cache object.
461. *
462. * If the TTL option is set to false, this method will always return 1 for
463. * existing items.
464. *
465. * @param string $filename The file to calculate the remaining lifetime for
466. * @param bool $useApc Use APC or not
467. * @return int The remaining lifetime in seconds (0 if no time remaining)
468. */
469. protected function calcLifetime ( $filename, $useApc = false )
470. {
471. $ttl = $this->options->ttl;
472. // Calculate when the APC object was created
473. if ( $useApc === true )
474. {
475. // we've likely already looked this thing up in APC, so we'll grab the local object
476. if ( isset( $this-> registry [$filename] ) )
477. {
478. $dataObj = $this-> registry [$filename];
479. }
480. else // otherwise we'll grab it from APC
481. {
482. $dataObj = $this-> fetchObject ( $filename );
483. }
485. if ( is_object ( $dataObj ) )
486. {
487. if ( $ttl === false )
488. {
489. return 1;
490. }
491. return (
492. ( $lifeTime = ( time () - $dataObj->mtime ) ) > $ttl
493. ? $ttl - $lifeTime
494. : 0
495. );
496. }
497. else
498. {
499. return 0;
500. }
501. }
503. // Calculate when the filesystem file was created
504. else
505. {
506. if ( ( file_exists ( $filename ) !== false )
507. && ( ( $modTime = @ filemtime ( $filename ) ) !== false ) )
508. {
509. if ( $ttl === false )
510. {
511. return 1;
512. }
513. return (
514. ( $lifeTime = ( time () - $modTime ) ) < $ttl
515. ? $ttl - $lifeTime
516. : 0
517. );
518. }
519. else
520. {
521. return 0;
522. }
523. }
524. }
525. }
526. ?>

Documentation generated by phpDocumentor 1.4.3