Вход Регистрация
Файл: vendor/symfony/cache/Adapter/PhpFilesAdapter.php
Строк: 295
<?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 SymfonyComponentCacheAdapter;

use 
SymfonyComponentCacheExceptionCacheException;
use 
SymfonyComponentCacheExceptionInvalidArgumentException;
use 
SymfonyComponentCachePruneableInterface;
use 
SymfonyComponentCacheTraitsFilesystemCommonTrait;
use 
SymfonyComponentVarExporterVarExporter;

/**
 * @author Piotr Stankowski <git@trakos.pl>
 * @author Nicolas Grekas <p@tchwork.com>
 * @author Rob Frawley 2nd <rmf@src.run>
 */
class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface
{
    use 
FilesystemCommonTrait {
        
doClear as private doCommonClear;
        
doDelete as private doCommonDelete;
    }

    private 
Closure $includeHandler;
    private 
bool $appendOnly;
    private array 
$values = [];
    private array 
$files = [];

    private static 
int $startTime;
    private static array 
$valuesCache = [];

    
/**
     * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire.
     *                    Doing so is encouraged because it fits perfectly OPcache's memory model.
     *
     * @throws CacheException if OPcache is not enabled
     */
    
public function __construct(string $namespace ''int $defaultLifetime 0, ?string $directory nullbool $appendOnly false)
    {
        
$this->appendOnly $appendOnly;
        
self::$startTime ??= $_SERVER['REQUEST_TIME'] ?? time();
        
parent::__construct(''$defaultLifetime);
        
$this->init($namespace$directory);
        
$this->includeHandler = static function ($type$msg$file$line) {
            throw new 
ErrorException($msg0$type$file$line);
        };
    }

    
/**
     * @return bool
     */
    
public static function isSupported()
    {
        
self::$startTime ??= $_SERVER['REQUEST_TIME'] ?? time();

        return 
function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOL) && (!in_array(PHP_SAPI, ['cli''phpdbg''embed'], true) || filter_var(ini_get('opcache.enable_cli'), FILTER_VALIDATE_BOOL));
    }

    public function 
prune(): bool
    
{
        
$time time();
        
$pruned true;
        
$getExpiry true;

        
set_error_handler($this->includeHandler);
        try {
            foreach (
$this->scanHashDir($this->directory) as $file) {
                try {
                    if (
is_array($expiresAt = include $file)) {
                        
$expiresAt $expiresAt[0];
                    }
                } catch (
ErrorException $e) {
                    
$expiresAt $time;
                }

                if (
$time >= $expiresAt) {
                    
$pruned = ($this->doUnlink($file) || !file_exists($file)) && $pruned;
                }
            }
        } finally {
            
restore_error_handler();
        }

        return 
$pruned;
    }

    protected function 
doFetch(array $ids): iterable
    
{
        if (
$this->appendOnly) {
            
$now 0;
            
$missingIds = [];
        } else {
            
$now time();
            
$missingIds $ids;
            
$ids = [];
        }
        
$values = [];

        
begin:
        
$getExpiry false;

        foreach (
$ids as $id) {
            if (
null === $value $this->values[$id] ?? null) {
                
$missingIds[] = $id;
            } elseif (
'N;' === $value) {
                
$values[$id] = null;
            } elseif (!
is_object($value)) {
                
$values[$id] = $value;
            } elseif (!
$value instanceof LazyValue) {
                
$values[$id] = $value();
            } elseif (
false === $values[$id] = include $value->file) {
                unset(
$values[$id], $this->values[$id]);
                
$missingIds[] = $id;
            }
            if (!
$this->appendOnly) {
                unset(
$this->values[$id]);
            }
        }

        if (!
$missingIds) {
            return 
$values;
        }

        
set_error_handler($this->includeHandler);
        try {
            
$getExpiry true;

            foreach (
$missingIds as $k => $id) {
                try {
                    
$file $this->files[$id] ??= $this->getFile($id);

                    if (isset(
self::$valuesCache[$file])) {
                        [
$expiresAt$this->values[$id]] = self::$valuesCache[$file];
                    } elseif (
is_array($expiresAt = include $file)) {
                        if (
$this->appendOnly) {
                            
self::$valuesCache[$file] = $expiresAt;
                        }

                        [
$expiresAt$this->values[$id]] = $expiresAt;
                    } elseif (
$now $expiresAt) {
                        
$this->values[$id] = new LazyValue($file);
                    }

                    if (
$now >= $expiresAt) {
                        unset(
$this->values[$id], $missingIds[$k], self::$valuesCache[$file]);
                    }
                } catch (
ErrorException $e) {
                    unset(
$missingIds[$k]);
                }
            }
        } finally {
            
restore_error_handler();
        }

        
$ids $missingIds;
        
$missingIds = [];
        goto 
begin;
    }

    protected function 
doHave(string $id): bool
    
{
        if (
$this->appendOnly && isset($this->values[$id])) {
            return 
true;
        }

        
set_error_handler($this->includeHandler);
        try {
            
$file $this->files[$id] ??= $this->getFile($id);
            
$getExpiry true;

            if (isset(
self::$valuesCache[$file])) {
                [
$expiresAt$value] = self::$valuesCache[$file];
            } elseif (
is_array($expiresAt = include $file)) {
                if (
$this->appendOnly) {
                    
self::$valuesCache[$file] = $expiresAt;
                }

                [
$expiresAt$value] = $expiresAt;
            } elseif (
$this->appendOnly) {
                
$value = new LazyValue($file);
            }
        } catch (
ErrorException) {
            return 
false;
        } finally {
            
restore_error_handler();
        }
        if (
$this->appendOnly) {
            
$now 0;
            
$this->values[$id] = $value;
        } else {
            
$now time();
        }

        return 
$now $expiresAt;
    }

    protected function 
doSave(array $valuesint $lifetime): array|bool
    
{
        
$ok true;
        
$expiry $lifetime time() + $lifetime 'PHP_INT_MAX';
        
$allowCompile self::isSupported();

        foreach (
$values as $key => $value) {
            unset(
$this->values[$key]);
            
$isStaticValue true;
            if (
null === $value) {
                
$value "'N;'";
            } elseif (
is_object($value) || is_array($value)) {
                try {
                    
$value VarExporter::export($value$isStaticValue);
                } catch (
Exception $e) {
                    throw new 
InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.'$keyget_debug_type($value)), 0$e);
                }
            } elseif (
is_string($value)) {
                
// Wrap "N;" in a closure to not confuse it with an encoded `null`
                
if ('N;' === $value) {
                    
$isStaticValue false;
                }
                
$value var_export($valuetrue);
            } elseif (!
is_scalar($value)) {
                throw new 
InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.'$keyget_debug_type($value)));
            } else {
                
$value var_export($valuetrue);
            }

            
$encodedKey rawurlencode($key);

            if (
$isStaticValue) {
                
$value "return [{$expiry}{$value}];";
            } elseif (
$this->appendOnly) {
                
$value "return [{$expiry}, static fn () => {$value}];";
            } else {
                
// We cannot use a closure here because of https://bugs.php.net/76982
                
$value str_replace('SymfonyComponentVarExporterInternal\', '', $value);
                $value = "namespace SymfonyComponentVarExporterInternal;nnreturn $getExpiry ? {$expiry} : {$value};";
            }

            $file = $this->files[$key] = $this->getFile($key, true);
            // Since OPcache only compiles files older than the script execution start, set the file'
s mtime in the past
            $ok 
$this->write($file"<?php //{$encodedKey}nn{$value}n"self::$startTime 10) && $ok;

            if (
$allowCompile) {
                @
opcache_invalidate($filetrue);
                @
opcache_compile_file($file);
            }
            unset(
self::$valuesCache[$file]);
        }

        if (!
$ok && !is_writable($this->directory)) {
            throw new 
CacheException(sprintf('Cache directory is not writable (%s).'$this->directory));
        }

        return 
$ok;
    }

    protected function 
doClear(string $namespace): bool
    
{
        
$this->values = [];

        return 
$this->doCommonClear($namespace);
    }

    protected function 
doDelete(array $ids): bool
    
{
        foreach (
$ids as $id) {
            unset(
$this->values[$id]);
        }

        return 
$this->doCommonDelete($ids);
    }

    
/**
     * @return bool
     */
    
protected function doUnlink(string $file)
    {
        unset(
self::$valuesCache[$file]);

        if (
self::isSupported()) {
            @
opcache_invalidate($filetrue);
        }

        return @
unlink($file);
    }

    private function 
getFileKey(string $file): string
    
{
        if (!
$h = @fopen($file'r')) {
            return 
'';
        }

        
$encodedKey substr(fgets($h), 8);
        
fclose($h);

        return 
rawurldecode(rtrim($encodedKey));
    }
}

/**
 * @internal
 */
class LazyValue
{
    public 
string $file;

    public function 
__construct(string $file)
    {
        
$this->file $file;
    }
}
Онлайн: 2
Реклама