Magento 2 Documentation  2.3
Documentation for Magento 2 CMS v2.3 (December 2018)
File.php
Go to the documentation of this file.
1 <?php
26 #require_once 'Zend/Cache/Backend/ExtendedInterface.php';
27 
31 #require_once 'Zend/Cache/Backend.php';
32 
33 
41 {
98  protected $_options = array(
99  'cache_dir' => null,
100  'file_locking' => true,
101  'read_control' => true,
102  'read_control_type' => 'crc32',
103  'hashed_directory_level' => 0,
104  'hashed_directory_perm' => 0700,
105  'file_name_prefix' => 'zend_cache',
106  'cache_file_perm' => 0600,
107  'metadatas_array_max_size' => 100
108  );
109 
115  protected $_metadatasArray = array();
116 
117 
124  public function __construct(array $options = array())
125  {
126  parent::__construct($options);
127  if ($this->_options['cache_dir'] !== null) { // particular case for this option
128  $this->setCacheDir($this->_options['cache_dir']);
129  } else {
130  $this->setCacheDir(self::getTmpDir() . DIRECTORY_SEPARATOR, false);
131  }
132  if (isset($this->_options['file_name_prefix'])) { // particular case for this option
133  if (!preg_match('~^[a-zA-Z0-9_]+$~D', $this->_options['file_name_prefix'])) {
134  Zend_Cache::throwException('Invalid file_name_prefix : must use only [a-zA-Z0-9_]');
135  }
136  }
137  if ($this->_options['metadatas_array_max_size'] < 10) {
138  Zend_Cache::throwException('Invalid metadatas_array_max_size, must be > 10');
139  }
140 
141  if (isset($options['hashed_directory_umask'])) {
142  // See #ZF-12047
143  trigger_error("'hashed_directory_umask' is deprecated -> please use 'hashed_directory_perm' instead", E_USER_NOTICE);
144  if (!isset($options['hashed_directory_perm'])) {
145  $options['hashed_directory_perm'] = $options['hashed_directory_umask'];
146  }
147  }
148  if (isset($options['hashed_directory_perm']) && is_string($options['hashed_directory_perm'])) {
149  // See #ZF-4422
150  $this->_options['hashed_directory_perm'] = octdec($this->_options['hashed_directory_perm']);
151  }
152 
153  if (isset($options['cache_file_umask'])) {
154  // See #ZF-12047
155  trigger_error("'cache_file_umask' is deprecated -> please use 'cache_file_perm' instead", E_USER_NOTICE);
156  if (!isset($options['cache_file_perm'])) {
157  $options['cache_file_perm'] = $options['cache_file_umask'];
158  }
159  }
160  if (isset($options['cache_file_perm']) && is_string($options['cache_file_perm'])) {
161  // See #ZF-4422
162  $this->_options['cache_file_perm'] = octdec($this->_options['cache_file_perm']);
163  }
164  }
165 
174  public function setCacheDir($value, $trailingSeparator = true)
175  {
176  if (!is_dir($value)) {
177  Zend_Cache::throwException(sprintf('cache_dir "%s" must be a directory', $value));
178  }
179  if (!is_writable($value)) {
180  Zend_Cache::throwException(sprintf('cache_dir "%s" is not writable', $value));
181  }
182  if ($trailingSeparator) {
183  // add a trailing DIRECTORY_SEPARATOR if necessary
184  $value = rtrim(realpath($value), '\\/') . DIRECTORY_SEPARATOR;
185  }
186  $this->_options['cache_dir'] = $value;
187  }
188 
196  public function load($id, $doNotTestCacheValidity = false)
197  {
198  if (!($this->_test($id, $doNotTestCacheValidity))) {
199  // The cache is not hit !
200  return false;
201  }
202  $metadatas = $this->_getMetadatas($id);
203  $file = $this->_file($id);
204  $data = $this->_fileGetContents($file);
205  if ($this->_options['read_control']) {
206  $hashData = $this->_hash($data, $this->_options['read_control_type']);
207  $hashControl = $metadatas['hash'];
208  if ($hashData != $hashControl) {
209  // Problem detected by the read control !
210  $this->_log('Zend_Cache_Backend_File::load() / read_control : stored hash and computed hash do not match');
211  $this->remove($id);
212  return false;
213  }
214  }
215  return $data;
216  }
217 
224  public function test($id)
225  {
226  clearstatcache();
227  return $this->_test($id, false);
228  }
229 
242  public function save($data, $id, $tags = array(), $specificLifetime = false)
243  {
244  clearstatcache();
245  $file = $this->_file($id);
246  $path = $this->_path($id);
247  if ($this->_options['hashed_directory_level'] > 0) {
248  if (!is_writable($path)) {
249  // maybe, we just have to build the directory structure
251  }
252  if (!is_writable($path)) {
253  return false;
254  }
255  }
256  if ($this->_options['read_control']) {
257  $hash = $this->_hash($data, $this->_options['read_control_type']);
258  } else {
259  $hash = '';
260  }
261  $metadatas = array(
262  'hash' => $hash,
263  'mtime' => time(),
264  'expire' => $this->_expireTime($this->getLifetime($specificLifetime)),
265  'tags' => $tags
266  );
267  $res = $this->_setMetadatas($id, $metadatas);
268  if (!$res) {
269  $this->_log('Zend_Cache_Backend_File::save() / error on saving metadata');
270  return false;
271  }
272  $res = $this->_filePutContents($file, $data);
273  return $res;
274  }
275 
282  public function remove($id)
283  {
284  $file = $this->_file($id);
285  $boolRemove = $this->_remove($file);
286  $boolMetadata = $this->_delMetadatas($id);
287  return $boolMetadata && $boolRemove;
288  }
289 
308  public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
309  {
310  // We use this protected method to hide the recursive stuff
311  clearstatcache();
312  return $this->_clean($this->_options['cache_dir'], $mode, $tags);
313  }
314 
320  public function getIds()
321  {
322  return $this->_get($this->_options['cache_dir'], 'ids', array());
323  }
324 
330  public function getTags()
331  {
332  return $this->_get($this->_options['cache_dir'], 'tags', array());
333  }
334 
343  public function getIdsMatchingTags($tags = array())
344  {
345  return $this->_get($this->_options['cache_dir'], 'matching', $tags);
346  }
347 
356  public function getIdsNotMatchingTags($tags = array())
357  {
358  return $this->_get($this->_options['cache_dir'], 'notMatching', $tags);
359  }
360 
369  public function getIdsMatchingAnyTags($tags = array())
370  {
371  return $this->_get($this->_options['cache_dir'], 'matchingAny', $tags);
372  }
373 
380  public function getFillingPercentage()
381  {
382  $free = disk_free_space($this->_options['cache_dir']);
383  $total = disk_total_space($this->_options['cache_dir']);
384  if ($total == 0) {
385  Zend_Cache::throwException('can\'t get disk_total_space');
386  } else {
387  if ($free >= $total) {
388  return 100;
389  }
390  return ((int) (100. * ($total - $free) / $total));
391  }
392  }
393 
405  public function getMetadatas($id)
406  {
407  $metadatas = $this->_getMetadatas($id);
408  if (!$metadatas) {
409  return false;
410  }
411  if (time() > $metadatas['expire']) {
412  return false;
413  }
414  return array(
415  'expire' => $metadatas['expire'],
416  'tags' => $metadatas['tags'],
417  'mtime' => $metadatas['mtime']
418  );
419  }
420 
428  public function touch($id, $extraLifetime)
429  {
430  $metadatas = $this->_getMetadatas($id);
431  if (!$metadatas) {
432  return false;
433  }
434  if (time() > $metadatas['expire']) {
435  return false;
436  }
437  $newMetadatas = array(
438  'hash' => $metadatas['hash'],
439  'mtime' => time(),
440  'expire' => $metadatas['expire'] + $extraLifetime,
441  'tags' => $metadatas['tags']
442  );
443  $res = $this->_setMetadatas($id, $newMetadatas);
444  if (!$res) {
445  return false;
446  }
447  return true;
448  }
449 
464  public function getCapabilities()
465  {
466  return array(
467  'automatic_cleaning' => true,
468  'tags' => true,
469  'expired_read' => true,
470  'priority' => false,
471  'infinite_lifetime' => true,
472  'get_list' => true
473  );
474  }
475 
483  public function ___expire($id)
484  {
485  $metadatas = $this->_getMetadatas($id);
486  if ($metadatas) {
487  $metadatas['expire'] = 1;
488  $this->_setMetadatas($id, $metadatas);
489  }
490  }
491 
498  protected function _getMetadatas($id)
499  {
500  if (isset($this->_metadatasArray[$id])) {
501  return $this->_metadatasArray[$id];
502  } else {
503  $metadatas = $this->_loadMetadatas($id);
504  if (!$metadatas) {
505  return false;
506  }
507  $this->_setMetadatas($id, $metadatas, false);
508  return $metadatas;
509  }
510  }
511 
520  protected function _setMetadatas($id, $metadatas, $save = true)
521  {
522  if (count($this->_metadatasArray) >= $this->_options['metadatas_array_max_size']) {
523  $n = (int) ($this->_options['metadatas_array_max_size'] / 10);
524  $this->_metadatasArray = array_slice($this->_metadatasArray, $n);
525  }
526  if ($save) {
527  $result = $this->_saveMetadatas($id, $metadatas);
528  if (!$result) {
529  return false;
530  }
531  }
532  $this->_metadatasArray[$id] = $metadatas;
533  return true;
534  }
535 
542  protected function _delMetadatas($id)
543  {
544  if (isset($this->_metadatasArray[$id])) {
545  unset($this->_metadatasArray[$id]);
546  }
547  $file = $this->_metadatasFile($id);
548  return $this->_remove($file);
549  }
550 
556  protected function _cleanMetadatas()
557  {
558  $this->_metadatasArray = array();
559  }
560 
567  protected function _loadMetadatas($id)
568  {
569  $file = $this->_metadatasFile($id);
570  $result = $this->_fileGetContents($file);
571  if (!$result) {
572  return false;
573  }
574  $tmp = @unserialize($result);
575  return $tmp;
576  }
577 
585  protected function _saveMetadatas($id, $metadatas)
586  {
587  $file = $this->_metadatasFile($id);
588  $result = $this->_filePutContents($file, serialize($metadatas));
589  if (!$result) {
590  return false;
591  }
592  return true;
593  }
594 
601  protected function _metadatasFile($id)
602  {
603  $path = $this->_path($id);
604  $fileName = $this->_idToFileName('internal-metadatas---' . $id);
605  return $path . $fileName;
606  }
607 
614  protected function _isMetadatasFile($fileName)
615  {
616  $id = $this->_fileNameToId($fileName);
617  if (substr($id, 0, 21) == 'internal-metadatas---') {
618  return true;
619  } else {
620  return false;
621  }
622  }
623 
633  protected function _remove($file)
634  {
635  if (!is_file($file)) {
636  return false;
637  }
638  if (!@unlink($file)) {
639  # we can't remove the file (because of locks or any problem)
640  $this->_log("Zend_Cache_Backend_File::_remove() : we can't remove $file");
641  return false;
642  }
643  return true;
644  }
645 
665  protected function _clean($dir, $mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
666  {
667  if (!is_dir($dir)) {
668  return false;
669  }
670  $result = true;
671  $prefix = $this->_options['file_name_prefix'];
672  $glob = @glob($dir . $prefix . '--*');
673  if ($glob === false) {
674  // On some systems it is impossible to distinguish between empty match and an error.
675  return true;
676  }
677  $metadataFiles = array();
678  foreach ($glob as $file) {
679  if (is_file($file)) {
680  $fileName = basename($file);
681  if ($this->_isMetadatasFile($fileName)) {
682  // In CLEANING_MODE_ALL, we drop anything, even remainings old metadatas files.
683  // To do that, we need to save the list of the metadata files first.
685  $metadataFiles[] = $file;
686  }
687  continue;
688  }
689  $id = $this->_fileNameToId($fileName);
690  $metadatas = $this->_getMetadatas($id);
691  if ($metadatas === FALSE) {
692  $metadatas = array('expire' => 1, 'tags' => array());
693  }
694  switch ($mode) {
696  $result = $result && $this->remove($id);
697  break;
699  if (time() > $metadatas['expire']) {
700  $result = $this->remove($id) && $result;
701  }
702  break;
704  $matching = true;
705  foreach ($tags as $tag) {
706  if (!in_array($tag, $metadatas['tags'])) {
707  $matching = false;
708  break;
709  }
710  }
711  if ($matching) {
712  $result = $this->remove($id) && $result;
713  }
714  break;
716  $matching = false;
717  foreach ($tags as $tag) {
718  if (in_array($tag, $metadatas['tags'])) {
719  $matching = true;
720  break;
721  }
722  }
723  if (!$matching) {
724  $result = $this->remove($id) && $result;
725  }
726  break;
728  $matching = false;
729  foreach ($tags as $tag) {
730  if (in_array($tag, $metadatas['tags'])) {
731  $matching = true;
732  break;
733  }
734  }
735  if ($matching) {
736  $result = $this->remove($id) && $result;
737  }
738  break;
739  default:
740  Zend_Cache::throwException('Invalid mode for clean() method');
741  break;
742  }
743  }
744  if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
745  // Recursive call
746  $result = $this->_clean($file . DIRECTORY_SEPARATOR, $mode, $tags) && $result;
748  // we try to drop the structure too
749  @rmdir($file);
750  }
751  }
752  }
753 
754  // cycle through metadataFiles and delete orphaned ones
755  foreach ($metadataFiles as $file) {
756  if (file_exists($file)) {
757  $result = $this->_remove($file) && $result;
758  }
759  }
760 
761  return $result;
762  }
763 
764  protected function _get($dir, $mode, $tags = array())
765  {
766  if (!is_dir($dir)) {
767  return false;
768  }
769  $result = array();
770  $prefix = $this->_options['file_name_prefix'];
771  $glob = @glob($dir . $prefix . '--*');
772  if ($glob === false) {
773  // On some systems it is impossible to distinguish between empty match and an error.
774  return array();
775  }
776  foreach ($glob as $file) {
777  if (is_file($file)) {
778  $fileName = basename($file);
779  $id = $this->_fileNameToId($fileName);
780  $metadatas = $this->_getMetadatas($id);
781  if ($metadatas === FALSE) {
782  continue;
783  }
784  if (time() > $metadatas['expire']) {
785  continue;
786  }
787  switch ($mode) {
788  case 'ids':
789  $result[] = $id;
790  break;
791  case 'tags':
792  $result = array_unique(array_merge($result, $metadatas['tags']));
793  break;
794  case 'matching':
795  $matching = true;
796  foreach ($tags as $tag) {
797  if (!in_array($tag, $metadatas['tags'])) {
798  $matching = false;
799  break;
800  }
801  }
802  if ($matching) {
803  $result[] = $id;
804  }
805  break;
806  case 'notMatching':
807  $matching = false;
808  foreach ($tags as $tag) {
809  if (in_array($tag, $metadatas['tags'])) {
810  $matching = true;
811  break;
812  }
813  }
814  if (!$matching) {
815  $result[] = $id;
816  }
817  break;
818  case 'matchingAny':
819  $matching = false;
820  foreach ($tags as $tag) {
821  if (in_array($tag, $metadatas['tags'])) {
822  $matching = true;
823  break;
824  }
825  }
826  if ($matching) {
827  $result[] = $id;
828  }
829  break;
830  default:
831  Zend_Cache::throwException('Invalid mode for _get() method');
832  break;
833  }
834  }
835  if ((is_dir($file)) and ($this->_options['hashed_directory_level']>0)) {
836  // Recursive call
837  $recursiveRs = $this->_get($file . DIRECTORY_SEPARATOR, $mode, $tags);
838  if ($recursiveRs === false) {
839  $this->_log('Zend_Cache_Backend_File::_get() / recursive call : can\'t list entries of "'.$file.'"');
840  } else {
841  $result = array_unique(array_merge($result, $recursiveRs));
842  }
843  }
844  }
845  return array_unique($result);
846  }
847 
854  protected function _expireTime($lifetime)
855  {
856  if ($lifetime === null) {
857  return 9999999999;
858  }
859  return time() + $lifetime;
860  }
861 
870  protected function _hash($data, $controlType)
871  {
872  switch ($controlType) {
873  case 'md5':
874  return md5($data);
875  case 'crc32':
876  return crc32($data);
877  case 'strlen':
878  return strlen($data);
879  case 'adler32':
880  return hash('adler32', $data);
881  default:
882  Zend_Cache::throwException("Incorrect hash function : $controlType");
883  }
884  }
885 
892  protected function _idToFileName($id)
893  {
894  $prefix = $this->_options['file_name_prefix'];
895  $result = $prefix . '---' . $id;
896  return $result;
897  }
898 
905  protected function _file($id)
906  {
907  $path = $this->_path($id);
908  $fileName = $this->_idToFileName($id);
909  return $path . $fileName;
910  }
911 
919  protected function _path($id, $parts = false)
920  {
921  $partsArray = array();
922  $root = $this->_options['cache_dir'];
923  $prefix = $this->_options['file_name_prefix'];
924  if ($this->_options['hashed_directory_level']>0) {
925  $hash = hash('adler32', $id);
926  for ($i=0 ; $i < $this->_options['hashed_directory_level'] ; $i++) {
927  $root = $root . $prefix . '--' . substr($hash, 0, $i + 1) . DIRECTORY_SEPARATOR;
928  $partsArray[] = $root;
929  }
930  }
931  if ($parts) {
932  return $partsArray;
933  } else {
934  return $root;
935  }
936  }
937 
944  protected function _recursiveMkdirAndChmod($id)
945  {
946  if ($this->_options['hashed_directory_level'] <=0) {
947  return true;
948  }
949  $partsArray = $this->_path($id, true);
950  foreach ($partsArray as $part) {
951  if (!is_dir($part)) {
952  @mkdir($part, $this->_options['hashed_directory_perm']);
953  @chmod($part, $this->_options['hashed_directory_perm']); // see #ZF-320 (this line is required in some configurations)
954  }
955  }
956  return true;
957  }
958 
966  protected function _test($id, $doNotTestCacheValidity)
967  {
968  $metadatas = $this->_getMetadatas($id);
969  if (!$metadatas) {
970  return false;
971  }
972  if ($doNotTestCacheValidity || (time() <= $metadatas['expire'])) {
973  return $metadatas['mtime'];
974  }
975  return false;
976  }
977 
984  protected function _fileGetContents($file)
985  {
986  $result = false;
987  if (!is_file($file)) {
988  return false;
989  }
990  $f = @fopen($file, 'rb');
991  if ($f) {
992  if ($this->_options['file_locking']) @flock($f, LOCK_SH);
993  $result = stream_get_contents($f);
994  if ($this->_options['file_locking']) @flock($f, LOCK_UN);
995  @fclose($f);
996  }
997  return $result;
998  }
999 
1007  protected function _filePutContents($file, $string)
1008  {
1009  $result = false;
1010  $f = @fopen($file, 'ab+');
1011  if ($f) {
1012  if ($this->_options['file_locking']) @flock($f, LOCK_EX);
1013  fseek($f, 0);
1014  ftruncate($f, 0);
1015  $tmp = @fwrite($f, $string);
1016  if (!($tmp === FALSE)) {
1017  $result = true;
1018  }
1019  @fclose($f);
1020  }
1021  @chmod($file, $this->_options['cache_file_perm']);
1022  return $result;
1023  }
1024 
1031  protected function _fileNameToId($fileName)
1032  {
1033  $prefix = $this->_options['file_name_prefix'];
1034  return preg_replace('~^' . $prefix . '---(.*)$~', '$1', $fileName);
1035  }
1036 
1037 }
clean($mode=Zend_Cache::CLEANING_MODE_ALL, $tags=array())
Definition: File.php:308
_fileGetContents($file)
Definition: File.php:984
getIdsNotMatchingTags($tags=array())
Definition: File.php:356
_expireTime($lifetime)
Definition: File.php:854
setCacheDir($value, $trailingSeparator=true)
Definition: File.php:174
_get($dir, $mode, $tags=array())
Definition: File.php:764
$id
Definition: fieldset.phtml:14
_clean($dir, $mode=Zend_Cache::CLEANING_MODE_ALL, $tags=array())
Definition: File.php:665
const CLEANING_MODE_OLD
Definition: Cache.php:73
touch($id, $extraLifetime)
Definition: File.php:428
_log($message, $priority=4)
Definition: Backend.php:273
_test($id, $doNotTestCacheValidity)
Definition: File.php:966
_filePutContents($file, $string)
Definition: File.php:1007
$fileName
Definition: translate.phtml:15
$prefix
Definition: name.phtml:25
_isMetadatasFile($fileName)
Definition: File.php:614
_fileNameToId($fileName)
Definition: File.php:1031
$value
Definition: gender.phtml:16
const CLEANING_MODE_NOT_MATCHING_TAG
Definition: Cache.php:75
_saveMetadatas($id, $metadatas)
Definition: File.php:585
if($exist=($block->getProductCollection() && $block->getProductCollection() ->getSize())) $mode
Definition: grid.phtml:15
__construct(array $options=array())
Definition: File.php:124
disk_free_space($path)
Definition: io.php:36
const CLEANING_MODE_ALL
Definition: Cache.php:72
static throwException($msg, Exception $e=null)
Definition: Cache.php:205
is_writable($path)
Definition: io.php:25
getIdsMatchingTags($tags=array())
Definition: File.php:343
mkdir($pathname, $mode=0777, $recursive=false, $context=null)
Definition: ioMock.php:25
const CLEANING_MODE_MATCHING_ANY_TAG
Definition: Cache.php:76
save($data, $id, $tags=array(), $specificLifetime=false)
Definition: File.php:242
_recursiveMkdirAndChmod($id)
Definition: File.php:944
_setMetadatas($id, $metadatas, $save=true)
Definition: File.php:520
const CLEANING_MODE_MATCHING_TAG
Definition: Cache.php:74
getIdsMatchingAnyTags($tags=array())
Definition: File.php:369
load($id, $doNotTestCacheValidity=false)
Definition: File.php:196
getLifetime($specificLifetime)
Definition: Backend.php:143
$i
Definition: gallery.phtml:31
_path($id, $parts=false)
Definition: File.php:919
_hash($data, $controlType)
Definition: File.php:870