Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
cache_storage_default.inc
1 <?php
25 require_once SQ_CORE_PACKAGE_PATH.'/system/cache_storage/cache_storage/cache_storage.inc';
26 
40 {
41 
42 
49  function __construct($assetid=0)
50  {
51  parent::__construct($assetid);
52 
53  }//end constructor
54 
55 
73  function store($cache_key, $perm_key, $url, $assetid, $data, $expiry)
74  {
75  // work out the file path
76  $group = $this->_getAssetHash($cache_key).$this->_getAssetHash($perm_key);
77  $file_name = md5($cache_key.':'.$perm_key.':'.$url);
78  $file_path = $group.'/'.$file_name;
79 
80  // replace/update existing cache entry
81  // warning: will NOT cause duplicate primary key db error
82  $cached = $this->_getCache($cache_key, $perm_key, $url);
83  if (!is_null($cached)) {
84  $this->_updateCache($cache_key, $perm_key, $url, $expiry, $file_path, $data);
85  return TRUE;
86  }
87 
88  // cache the content file
89  $old_umask = umask(0);
90  if (!is_dir(SQ_CACHE_PATH.'/'.$group)) {
91  $status = mkdir(SQ_CACHE_PATH.'/'.$group, 0755);
92  clearstatcache();
93  if (!$status) {
94  trigger_localised_error('CORE0245', E_USER_WARNING, SQ_CACHE_PATH.'/'.$group);
95  return FALSE;
96  }
97  }
98  $status = string_to_file($data, SQ_CACHE_PATH.'/'.$file_path);
99  if (!$status) {
100  trigger_localised_error('CORE0243', E_USER_WARNING, SQ_CACHE_PATH.'/'.$file_path);
101  return FALSE;
102  }
103  umask($old_umask);
104 
105  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
106  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
107 
108  $error = FALSE;
109  // start a transaction to prevent reinsert due to concurrency issues
110  $cached = $this->_getCache($cache_key, $perm_key, $url);
111  if (is_null($cached)) {
112  try {
113  $bind_vars = Array(
114  'cache_key' => $cache_key,
115  'perm_key' => $perm_key,
116  'url' => $url,
117  'assetid' => $assetid,
118  'expires' => ts_iso8601($expiry),
119  'path' => $file_path,
120  );
121  MatrixDAL::executeQuery('cache_manager', 'insertCacheEntry', $bind_vars);
122  } catch (DALException $e) {
123  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
124  // if there is an error, check if it is already cached
125  $cached = $this->_getCache($cache_key, $perm_key, $url);
126  if (is_null($cached)) {
127  throw new Exception('Unable to cache asset ID # '.$assetid.' due to database error: '.$e->getMessage());
128  return FALSE;
129  }
130  }
131  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
132 
133  } else {
134  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
135  }
136  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
137  return TRUE;
138 
139  }//end store()
140 
141 
156  function read($cache_key, $perm_key, $url, $assetid)
157  {
158  // check expiry time if entry already exists
159  $cached = $this->_getCache($cache_key, $perm_key, $url);
160  if (!is_null($cached)) {
161  // expired
162  if (time() > strtotime($cached['expires'])) {
163  $this->_deleteCache($cache_key, $perm_key, $url);
164  return FALSE;
165  } else {
166  if (file_exists(SQ_CACHE_PATH.'/'.$cached['path'])) {
167  $contents = file_to_string(SQ_CACHE_PATH.'/'.$cached['path']);
168  if ($contents === FALSE) {
169  // if we cannot read from the cache file, remove this cache entry
170  $this->_deleteCache($cache_key, $perm_key, $url);
171  trigger_localised_error('CORE0244', E_USER_WARNING, SQ_CACHE_PATH.'/'.$cached['path']);
172  return FALSE;
173  }
174  return $contents;
175  } else {
176  // if we cannot find this cache file, remove this cache entry
177  $this->_deleteCache($cache_key, $perm_key, $url);
178  return FALSE;
179  }
180  }
181  }
182  return FALSE;
183 
184  }//end read()
185 
186 
193  function clearAll()
194  {
195  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
196  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
197 
198  try {
199  MatrixDAL::executeQuery('cache_manager', 'clearAllCache');
200  } catch (DALException $e) {
201  throw new Exception ('Unable to purge cache due to database error: '.$e->getMessage());
202  }
203 
204  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
205  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
206 
207  }//end clearAll()
208 
209 
216  function canClearByAssetid()
217  {
218  return TRUE;
219 
220  }//end canClearByAssetid()
221 
222 
231  function clear($assetids)
232  {
233  if (!empty($assetids)) {
234 
235  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
236  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
237 
238  // break up the assets into chunks of 1000 so that oracle does not complain
239  //$in_clauses = Array();
240  try {
241  $result = Array();
242  foreach (array_chunk($assetids, 999) as $chunk) {
243  $bind_vars = Array('assetids' => &$chunk);
244  MatrixDAL::executeQuery('cache_manager', 'deleteCacheEntriesByAsset', $bind_vars);
245  }
246  } catch (DALException $e) {
247  throw new Exception('Unable to delete cache entries due to database error: '.$e->getMessage());
248  }
249 
250  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
251  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
252  }
253 
254  }//end clear()
255 
256 
273  {
274  $bind_vars = Array('now' => ts_iso8601(time()));
275 
276  try {
277  $paths = MatrixDAL::executeAssoc('cache_storage_default', 'selectExpiredEntryPaths', 0, $bind_vars);
278  } catch (Exception $e) {
279  trigger_error('Unable to select expired cache entry paths due to database error: '.$e->getMessage(), E_USER_WARNING);
280  return FALSE;
281  }
282 
283  foreach ($paths as $k => $path) {
284  $cache_file = SQ_CACHE_PATH.'/'.$path;
285  if (is_file($cache_file) === TRUE) {
286  $result = unlink($cache_file);
287  if ($result !== TRUE) {
288  trigger_error('Unable to remove expired cache file "'.$cache_file.'"', E_USER_WARNING);
289  return FALSE;
290  }
291  }
292  }
293 
294  try {
295  MatrixDAL::executeQuery('cache_storage_default', 'deleteExpiredEntries', $bind_vars);
296  } catch (Exception $e) {
297  trigger_error('Unable to delete expired cache entries due to database error: '.$e->getMessage(), E_USER_WARNING);
298  return FALSE;
299  }
300 
301  return TRUE;
302 
303  }//end cleanExpiredEntries()
304 
305 
314  function getFilePaths($assetids)
315  {
316  if (!empty($assetids)) {
317  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
318 
319  // break up the assets into chunks of 1000 so that oracle does not complain
320  // $in_clauses = Array();
321  $result = Array();
322  foreach (array_chunk($assetids, 999) as $chunk) {
323  $bind_vars = Array('assetids' => &$chunk);
324  $result = array_merge($result, MatrixDAL::executeAll('cache_manager', 'getCacheFilePathsByAsset', $bind_vars));
325  $result = array_unique($result);
326  }
327 
328  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
329  return $result;
330  }
331 
332  }//end getFilePaths()
333 
334 
343  function getAllFilePaths($option='')
344  {
345  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
346 
347  try {
348  if ($option == 'col') {
349  $result = MatrixDAL::executeAssoc('cache_manager', 'getAllCacheFilePaths', 0);
350  } else {
351  $result = MatrixDAL::executeAll('cache_manager', 'getAllCacheFilePaths');
352  }
353  } catch (DALException $e) {
354  throw new Exception ('Unable to get all cache file paths due to database error: '.$e->getMessage());
355  }
356 
357  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
358 
359  return $result;
360 
361  }//end getAllFilePaths()
362 
363 
364 
375  function _getCache($cache_key, $perm_key, $url)
376  {
377  // to get rid of replication lag if the system has multiple db
378  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
379 
380  try {
381  $bind_vars = Array(
382  'cache_key' => $cache_key,
383  'perm_key' => $perm_key,
384  'url' => $url,
385  );
386  $result = MatrixDAL::executeAll('cache_manager', 'getCacheExpiryAndFilePath', $bind_vars);
387  } catch (DALException $e) {
388  throw new Exception('Unable to get cache entries due to database error: '.$e->getMessage());
389  }
390 
391  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
392 
393  return array_shift($result);
394 
395  }//end _getCache()
396 
397 
408  function _deleteCache($cache_key, $perm_key, $url)
409  {
410  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
411  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
412 
413  try {
414  $bind_vars = Array(
415  'cache_key' => $cache_key,
416  'perm_key' => $perm_key,
417  'url' => $url,
418  );
419  MatrixDAL::executeQuery('cache_manager', 'deleteCacheEntry', $bind_vars);
420  } catch (DALException $e) {
421  throw new Exception('Unable to delete cache entries due to database error: '.$e->getMessage());
422  }
423 
424  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
425  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
426 
427  }//end _deleteCache()
428 
429 
443  function _updateCache($cache_key, $perm_key, $url, $expiry, $file_path='', $updated_content='')
444  {
445  // update the expiry time
446  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
447  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
448 
449  try {
450  $bind_vars = Array(
451  'expires' => ts_iso8601($expiry),
452  'cache_key' => $cache_key,
453  'perm_key' => $perm_key,
454  'url' => $url,
455  );
456  MatrixDAL::executeQuery('cache_manager', 'updateCacheExpiry', $bind_vars);
457  } catch (DALException $e) {
458  throw new Exception('Unable to update cache expiry time due to database error: '.$e->getMessage());
459  }
460 
461  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
462  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
463 
464  // update the content file
465  if ($file_path) {
466  $old_umask = umask(0);
467  $status = string_to_file($updated_content, SQ_CACHE_PATH.'/'.$file_path);
468  if (!$status) {
469  trigger_localised_error('CORE0243', E_USER_WARNING, SQ_CACHE_PATH.'/'.$file_path);
470  return FALSE;
471  }
472  umask($old_umask);
473  }
474 
475  }//end _updateCache()
476 
477 
486  function _getAssetHash($assetid=0)
487  {
488  $cache_manager = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('cache_manager');
489 
490  $assetid = trim($assetid);
491  $hash = 0;
492  $bucketsize = $cache_manager->attr('num_cache_dirs');
493  $len = strlen($assetid);
494  for ($i = 0; $i < $len; $i++) {
495  if (!is_numeric($assetid{$i})) {
496  $hash += ord($assetid{$i});
497  } else {
498  $hash += (int) $assetid{$i};
499  }
500  }
501  $hash = $hash % $bucketsize;
502 
503  while (strlen($hash) != strlen($bucketsize)) {
504  $hash = '0'.$hash;
505  }
506  return $hash;
507 
508  }//end getAssetHash()
509 
510 
525  function clearCachedAssetsByUrl($url)
526  {
527  if (empty($url)) {
528  return;
529  }
530 
531  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('dbcache');
532 
533  $bind_vars = Array(
534  'url1' => $url, // exact match for: url.com
535  'url2' => $url.'/', // exact match for: url.com/
536  'url3' => $url.'?%', // like match for: url.com?%
537  'url4' => $url.'/?%', // like match for: url.com/?%
538  );
539  $cached_assets = MatrixDAL::executeAll('cache_manager', 'getCachedAssetByUrl', $bind_vars);
540 
541  if (!empty($cached_assets)) {
542  // Remove the content file for each assetid
543  foreach ($cached_assets as $cached_asset) {
544  if (isset($cached_asset['path'])) {
545  $asset_cache_path = SQ_CACHE_PATH.'/'.$cached_asset['path'];
546  if (is_file($asset_cache_path)) {
547  if (!unlink($asset_cache_path)) {
548  log_dump('Failed to delete cache file: '.$asset_cache_path);
549  }//end if
550  }//end if
551  }//end if
552  }//end foreach
553 
554  // Purge assetids from cache table based on url
555  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
556 
557  try {
558  $delete_bind_vars = Array(
559  'url1' => $url, // exact match for: url.com
560  'url2' => $url.'/', // exact match for: url.com/
561  'url3' => $url.'?%', // like match for: url.com?%
562  'url4' => $url.'/?%', // like match for: url.com/?%
563  );
564  MatrixDAL::executeQuery('cache_manager', 'deleteCachedAssetByUrl', $delete_bind_vars);
565  } catch (DALException $e) {
566  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
567  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
568  throw new Exception('Unable to delete cache entries due to database error: '.$e->getMessage());
569  }
570 
571  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
572  }
573  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
574  }
575 
576 }//end class
577 
578 ?>