/**
  * {@inheritdoc}
  */
 protected function filterInvalidatedKeys(array &$keys)
 {
     $tags = $invalids = array();
     foreach ($keys as $i => $key) {
         CacheItem::validateKey($key);
         foreach ($this->redis->hGetAll($this->namespace . $key . ':tags') as $tag => $version) {
             $tags[$this->namespace . 'tag:' . $tag][$version][$i] = $key;
         }
     }
     if ($tags) {
         $j = 0;
         $versions = $this->redis->mGet(array_keys($tags));
         foreach ($tags as $tag => $version) {
             $version = $versions[$j++];
             unset($tags[$tag][(int) $version]);
             foreach ($tags[$tag] as $version) {
                 foreach ($version as $i => $key) {
                     $invalids[] = $key;
                     unset($keys[$i]);
                 }
             }
         }
     }
     return $invalids;
 }
Example #2
0
 public function __construct($namespace = '', $defaultLifetime = 0, $version = null)
 {
     if (!static::isSupported()) {
         throw new CacheException('APCu is not enabled');
     }
     if ('cli' === PHP_SAPI) {
         ini_set('apc.use_request_time', 0);
     }
     parent::__construct($namespace, $defaultLifetime);
     if (null !== $version) {
         CacheItem::validateKey($version);
         if (!apcu_exists($version . ':' . $namespace)) {
             $this->clear($namespace);
             apcu_add($version . ':' . $namespace, null);
         }
     }
 }
Example #3
0
 private function generateItems(array $keys, $now)
 {
     $f = $this->createCacheItem;
     foreach ($keys as $i => $key) {
         try {
             if (!($isHit = isset($this->expiries[$key]) && ($this->expiries[$key] >= $now || !$this->deleteItem($key)))) {
                 $this->values[$key] = $value = null;
             } elseif (!$this->storeSerialized) {
                 $value = $this->values[$key];
             } elseif ('b:0;' === ($value = $this->values[$key])) {
                 $value = false;
             } elseif (false === ($value = unserialize($value))) {
                 $this->values[$key] = $value = null;
                 $isHit = false;
             }
         } catch (\Exception $e) {
             CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
             $this->values[$key] = $value = null;
             $isHit = false;
         }
         unset($keys[$i]);
         (yield $key => $f($key, $value, $isHit));
     }
     foreach ($keys as $key) {
         (yield $key => $f($key, null, false));
     }
 }
Example #4
0
    /**
     * Store an array of cached values.
     *
     * @param array $values The cached values
     */
    public function warmUp(array $values)
    {
        if (file_exists($this->file)) {
            if (!is_file($this->file)) {
                throw new InvalidArgumentException(sprintf('Cache path exists and is not a file: %s.', $this->file));
            }
            if (!is_writable($this->file)) {
                throw new InvalidArgumentException(sprintf('Cache file is not writable: %s.', $this->file));
            }
        } else {
            $directory = dirname($this->file);
            if (!is_dir($directory) && !@mkdir($directory, 0777, true)) {
                throw new InvalidArgumentException(sprintf('Cache directory does not exist and cannot be created: %s.', $directory));
            }
            if (!is_writable($directory)) {
                throw new InvalidArgumentException(sprintf('Cache directory is not writable: %s.', $directory));
            }
        }
        $dump = <<<'EOF'
<?php

// This file has been auto-generated by the Symfony Cache Component.

return array(


EOF;
        foreach ($values as $key => $value) {
            CacheItem::validateKey(is_int($key) ? (string) $key : $key);
            if (null === $value || is_object($value)) {
                try {
                    $value = serialize($value);
                } catch (\Exception $e) {
                    throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, get_class($value)), 0, $e);
                }
            } elseif (is_array($value)) {
                try {
                    $serialized = serialize($value);
                    $unserialized = unserialize($serialized);
                } catch (\Exception $e) {
                    throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e);
                }
                // Store arrays serialized if they contain any objects or references
                if ($unserialized !== $value || false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized)) {
                    $value = $serialized;
                }
            } elseif (is_string($value)) {
                // Serialize strings if they could be confused with serialized objects or arrays
                if ('N;' === $value || isset($value[2]) && ':' === $value[1]) {
                    $value = serialize($value);
                }
            } elseif (!is_scalar($value)) {
                throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, gettype($value)));
            }
            $dump .= var_export($key, true) . ' => ' . var_export($value, true) . ",\n";
        }
        $dump .= "\n);\n";
        $dump = str_replace("' . \"\\0\" . '", "", $dump);
        $tmpFile = uniqid($this->file);
        file_put_contents($tmpFile, $dump);
        @chmod($tmpFile, 0666);
        unset($serialized, $unserialized, $value, $dump);
        @rename($tmpFile, $this->file);
        $this->values = (include $this->file) ?: array();
    }
Example #5
0
 /**
  * {@inheritdoc}
  */
 public function commit()
 {
     $ok = true;
     $byLifetime = $this->mergeByLifetime;
     $byLifetime = $byLifetime($this->deferred, $this->namespace);
     $retry = $this->deferred = array();
     foreach ($byLifetime as $lifetime => $values) {
         try {
             $e = $this->doSave($values, $lifetime);
         } catch (\Exception $e) {
         }
         if (true === $e || array() === $e) {
             continue;
         }
         if (is_array($e) || 1 === count($values)) {
             foreach (is_array($e) ? $e : array_keys($values) as $id) {
                 $ok = false;
                 $v = $values[$id];
                 $type = is_object($v) ? get_class($v) : gettype($v);
                 CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => substr($id, strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
             }
         } else {
             foreach ($values as $id => $v) {
                 $retry[$lifetime][] = $id;
             }
         }
     }
     // When bulk-save failed, retry each item individually
     foreach ($retry as $lifetime => $ids) {
         foreach ($ids as $id) {
             try {
                 $v = $byLifetime[$lifetime][$id];
                 $e = $this->doSave(array($id => $v), $lifetime);
             } catch (\Exception $e) {
             }
             if (true === $e || array() === $e) {
                 continue;
             }
             $ok = false;
             $type = is_object($v) ? get_class($v) : gettype($v);
             CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => substr($id, strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
         }
     }
     $this->deferred = array();
     return $ok;
 }
Example #6
0
 private function getId($key)
 {
     CacheItem::validateKey($key);
     return $this->namespace . $key;
 }
Example #7
0
 private function generateItems($items, &$keys)
 {
     $f = $this->createCacheItem;
     try {
         foreach ($items as $id => $value) {
             $key = $keys[$id];
             unset($keys[$id]);
             (yield $key => $f($key, $value, true));
         }
     } catch (\Exception $e) {
         CacheItem::log($this->logger, 'Failed to fetch requested items', array('keys' => array_values($keys), 'exception' => $e));
     }
     foreach ($keys as $key) {
         (yield $key => $f($key, null, false));
     }
 }
Example #8
0
 /**
  * {@inheritdoc}
  */
 public function save(CacheItemInterface $item)
 {
     if (!$item instanceof CacheItem) {
         return false;
     }
     $item = (array) $item;
     $key = $item[CacheItem::CAST_PREFIX . 'key'];
     $value = $item[CacheItem::CAST_PREFIX . 'value'];
     $expiry = $item[CacheItem::CAST_PREFIX . 'expiry'];
     if (null !== $expiry && $expiry <= time()) {
         $this->deleteItem($key);
         return true;
     }
     if ($this->storeSerialized) {
         try {
             $value = serialize($value);
         } catch (\Exception $e) {
             $type = is_object($value) ? get_class($value) : gettype($value);
             CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
             return false;
         }
     }
     $this->values[$key] = $value;
     $this->expiries[$key] = null !== $expiry ? $expiry : PHP_INT_MAX;
     return true;
 }
Example #9
0
 /**
  * @dataProvider provideInvalidKey
  * @expectedException Symfony\Component\Cache\Exception\InvalidArgumentException
  * @expectedExceptionMessage Cache key
  */
 public function testInvalidKey($key)
 {
     CacheItem::validateKey($key);
 }
Example #10
0
 /**
  * @dataProvider provideInvalidKey
  * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
  * @expectedExceptionMessage Cache tag
  */
 public function testInvalidTag($tag)
 {
     $item = new CacheItem();
     $item->tag($tag);
 }
Example #11
0
 /**
  * {@inheritdoc}
  */
 public function commit()
 {
     $f = $this->mergeByLifetime;
     $ko = array();
     foreach ($f($this->deferred, $this->namespace) as $lifetime => $values) {
         try {
             if (true === ($ok = $this->doSave($values, $lifetime))) {
                 continue;
             }
         } catch (\Exception $e) {
             $ok = false;
         }
         if (false === $ok) {
             $ok = array_keys($values);
         }
         foreach ($ok as $id) {
             $ko[$lifetime][] = array($id => $values[$id]);
         }
     }
     $this->deferred = array();
     $ok = true;
     // When bulk-save failed, retry each item individually
     foreach ($ko as $lifetime => $values) {
         foreach ($values as $v) {
             try {
                 $e = $this->doSave($v, $lifetime);
             } catch (\Exception $e) {
             }
             if (true !== $e && array() !== $e) {
                 $ok = false;
                 foreach ($v as $key => $value) {
                     $type = is_object($value) ? get_class($value) : gettype($value);
                     CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null));
                 }
             }
         }
     }
     return $ok;
 }
Example #12
0
 /**
  * {@inheritdoc}
  */
 public function save(CacheItemInterface $item)
 {
     if (!$item instanceof CacheItem) {
         return false;
     }
     $item = (array) $item;
     $key = $item[CacheItem::CAST_PREFIX . 'key'];
     $value = $item[CacheItem::CAST_PREFIX . 'value'];
     $lifetime = $item[CacheItem::CAST_PREFIX . 'lifetime'];
     if (0 > $lifetime) {
         return true;
     }
     if (is_object($value)) {
         try {
             $value = clone $value;
         } catch (\Exception $e) {
             $type = is_object($value) ? get_class($value) : gettype($value);
             CacheItem::log($this->logger, 'Failed to clone key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
             return false;
         }
     }
     $this->values[$key] = $value;
     $this->expiries[$key] = $lifetime ? $lifetime + time() : PHP_INT_MAX;
     return true;
 }