PhpArrayTrait.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Cache\Traits;
  11. use Symfony\Component\Cache\CacheItem;
  12. use Symfony\Component\Cache\Exception\InvalidArgumentException;
  13. /**
  14. * @author Titouan Galopin <galopintitouan@gmail.com>
  15. * @author Nicolas Grekas <p@tchwork.com>
  16. *
  17. * @internal
  18. */
  19. trait PhpArrayTrait
  20. {
  21. use ProxyTrait;
  22. private $file;
  23. private $values;
  24. private $zendDetectUnicode;
  25. /**
  26. * Store an array of cached values.
  27. *
  28. * @param array $values The cached values
  29. */
  30. public function warmUp(array $values)
  31. {
  32. if (file_exists($this->file)) {
  33. if (!is_file($this->file)) {
  34. throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
  35. }
  36. if (!is_writable($this->file)) {
  37. throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
  38. }
  39. } else {
  40. $directory = \dirname($this->file);
  41. if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
  42. throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
  43. }
  44. if (!is_writable($directory)) {
  45. throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
  46. }
  47. }
  48. $dump = <<<'EOF'
  49. <?php
  50. // This file has been auto-generated by the Symfony Cache Component.
  51. return [
  52. EOF;
  53. foreach ($values as $key => $value) {
  54. CacheItem::validateKey(\is_int($key) ? (string) $key : $key);
  55. if (null === $value || \is_object($value)) {
  56. try {
  57. $value = serialize($value);
  58. } catch (\Exception $e) {
  59. throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \get_class($value)), 0, $e);
  60. }
  61. } elseif (\is_array($value)) {
  62. try {
  63. $serialized = serialize($value);
  64. $unserialized = unserialize($serialized);
  65. } catch (\Exception $e) {
  66. throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
  67. }
  68. // Store arrays serialized if they contain any objects or references
  69. if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) {
  70. $value = $serialized;
  71. }
  72. } elseif (\is_string($value)) {
  73. // Serialize strings if they could be confused with serialized objects or arrays
  74. if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
  75. $value = serialize($value);
  76. }
  77. } elseif (!\is_scalar($value)) {
  78. throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value)));
  79. }
  80. $dump .= var_export($key, true).' => '.var_export($value, true).",\n";
  81. }
  82. $dump .= "\n];\n";
  83. $dump = str_replace("' . \"\\0\" . '", "\0", $dump);
  84. $tmpFile = uniqid($this->file, true);
  85. file_put_contents($tmpFile, $dump);
  86. @chmod($tmpFile, 0666 & ~umask());
  87. unset($serialized, $unserialized, $value, $dump);
  88. @rename($tmpFile, $this->file);
  89. $this->initialize();
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function clear()
  95. {
  96. $this->values = [];
  97. $cleared = @unlink($this->file) || !file_exists($this->file);
  98. return $this->pool->clear() && $cleared;
  99. }
  100. /**
  101. * Load the cache file.
  102. */
  103. private function initialize()
  104. {
  105. if ($this->zendDetectUnicode) {
  106. $zmb = ini_set('zend.detect_unicode', 0);
  107. }
  108. try {
  109. $this->values = file_exists($this->file) ? (include $this->file ?: []) : [];
  110. } finally {
  111. if ($this->zendDetectUnicode) {
  112. ini_set('zend.detect_unicode', $zmb);
  113. }
  114. }
  115. }
  116. }