185 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			PHP
		
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			PHP
		
	
	
<?php
 | 
						|
 | 
						|
/*
 | 
						|
 * This file is part of the Symfony package.
 | 
						|
 *
 | 
						|
 * (c) Fabien Potencier <fabien@symfony.com>
 | 
						|
 *
 | 
						|
 * For the full copyright and license information, please view the LICENSE
 | 
						|
 * file that was distributed with this source code.
 | 
						|
 */
 | 
						|
 | 
						|
namespace Symfony\Component\Cache\Traits;
 | 
						|
 | 
						|
use Psr\Log\LoggerAwareTrait;
 | 
						|
use Symfony\Component\Cache\CacheItem;
 | 
						|
 | 
						|
/**
 | 
						|
 * @author Nicolas Grekas <p@tchwork.com>
 | 
						|
 *
 | 
						|
 * @internal
 | 
						|
 */
 | 
						|
trait ArrayTrait
 | 
						|
{
 | 
						|
    use LoggerAwareTrait;
 | 
						|
 | 
						|
    private $storeSerialized;
 | 
						|
    private $values = [];
 | 
						|
    private $expiries = [];
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns all cached values, with cache miss as null.
 | 
						|
     *
 | 
						|
     * @return array
 | 
						|
     */
 | 
						|
    public function getValues()
 | 
						|
    {
 | 
						|
        if (!$this->storeSerialized) {
 | 
						|
            return $this->values;
 | 
						|
        }
 | 
						|
 | 
						|
        $values = $this->values;
 | 
						|
        foreach ($values as $k => $v) {
 | 
						|
            if (null === $v || 'N;' === $v) {
 | 
						|
                continue;
 | 
						|
            }
 | 
						|
            if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) {
 | 
						|
                $values[$k] = serialize($v);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $values;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * {@inheritdoc}
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function hasItem($key)
 | 
						|
    {
 | 
						|
        if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        CacheItem::validateKey($key);
 | 
						|
 | 
						|
        return isset($this->expiries[$key]) && !$this->deleteItem($key);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * {@inheritdoc}
 | 
						|
     *
 | 
						|
     * @param string $prefix
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function clear(/*string $prefix = ''*/)
 | 
						|
    {
 | 
						|
        $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : '';
 | 
						|
 | 
						|
        if ('' !== $prefix) {
 | 
						|
            foreach ($this->values as $key => $value) {
 | 
						|
                if (0 === strpos($key, $prefix)) {
 | 
						|
                    unset($this->values[$key], $this->expiries[$key]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $this->values = $this->expiries = [];
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * {@inheritdoc}
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function deleteItem($key)
 | 
						|
    {
 | 
						|
        if (!\is_string($key) || !isset($this->expiries[$key])) {
 | 
						|
            CacheItem::validateKey($key);
 | 
						|
        }
 | 
						|
        unset($this->values[$key], $this->expiries[$key]);
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * {@inheritdoc}
 | 
						|
     */
 | 
						|
    public function reset()
 | 
						|
    {
 | 
						|
        $this->clear();
 | 
						|
    }
 | 
						|
 | 
						|
    private function generateItems(array $keys, float $now, callable $f): iterable
 | 
						|
    {
 | 
						|
        foreach ($keys as $i => $key) {
 | 
						|
            if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) {
 | 
						|
                $this->values[$key] = $value = null;
 | 
						|
            } else {
 | 
						|
                $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key];
 | 
						|
            }
 | 
						|
            unset($keys[$i]);
 | 
						|
 | 
						|
            yield $key => $f($key, $value, $isHit);
 | 
						|
        }
 | 
						|
 | 
						|
        foreach ($keys as $key) {
 | 
						|
            yield $key => $f($key, null, false);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private function freeze($value, $key)
 | 
						|
    {
 | 
						|
        if (null === $value) {
 | 
						|
            return 'N;';
 | 
						|
        }
 | 
						|
        if (\is_string($value)) {
 | 
						|
            // Serialize strings if they could be confused with serialized objects or arrays
 | 
						|
            if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
 | 
						|
                return serialize($value);
 | 
						|
            }
 | 
						|
        } elseif (!is_scalar($value)) {
 | 
						|
            try {
 | 
						|
                $serialized = serialize($value);
 | 
						|
            } catch (\Exception $e) {
 | 
						|
                unset($this->values[$key]);
 | 
						|
                $type = \is_object($value) ? \get_class($value) : \gettype($value);
 | 
						|
                $message = sprintf('Failed to save key "{key}" of type %s: ', $type).$e->getMessage();
 | 
						|
                CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]);
 | 
						|
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
            // Keep value serialized if it contains any objects or any internal references
 | 
						|
            if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
 | 
						|
                return $serialized;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $value;
 | 
						|
    }
 | 
						|
 | 
						|
    private function unfreeze(string $key, bool &$isHit)
 | 
						|
    {
 | 
						|
        if ('N;' === $value = $this->values[$key]) {
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
        if (\is_string($value) && isset($value[2]) && ':' === $value[1]) {
 | 
						|
            try {
 | 
						|
                $value = unserialize($value);
 | 
						|
            } catch (\Exception $e) {
 | 
						|
                CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]);
 | 
						|
                $value = false;
 | 
						|
            }
 | 
						|
            if (false === $value) {
 | 
						|
                $this->values[$key] = $value = null;
 | 
						|
                $isHit = false;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return $value;
 | 
						|
    }
 | 
						|
}
 |