Вход Регистрация
Файл: vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php
Строк: 217
<?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 
SymfonyComponentCacheMarshallerMarshallerInterface;
use 
SymfonyComponentCacheMarshallerTagAwareMarshaller;
use 
SymfonyComponentCachePruneableInterface;
use 
SymfonyComponentCacheTraitsFilesystemTrait;

/**
 * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls.
 *
 * @author Nicolas Grekas <p@tchwork.com>
 * @author André Rømcke <andre.romcke+symfony@gmail.com>
 */
class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface
{
    use 
FilesystemTrait {
        
prune as private doPrune;
        
doClear as private doClearCache;
        
doSave as private doSaveCache;
    }

    
/**
     * Folder used for tag symlinks.
     */
    
private const TAG_FOLDER 'tags';

    public function 
__construct(string $namespace ''int $defaultLifetime 0, ?string $directory null, ?MarshallerInterface $marshaller null)
    {
        
$this->marshaller = new TagAwareMarshaller($marshaller);
        
parent::__construct(''$defaultLifetime);
        
$this->init($namespace$directory);
    }

    public function 
prune(): bool
    
{
        
$ok $this->doPrune();

        
set_error_handler(static function () {});
        
$chars '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

        try {
            foreach (
$this->scanHashDir($this->directory.self::TAG_FOLDER.DIRECTORY_SEPARATOR) as $dir) {
                
$dir .= DIRECTORY_SEPARATOR;
                
$keepDir false;
                for (
$i 0$i 38; ++$i) {
                    if (!
is_dir($dir.$chars[$i])) {
                        continue;
                    }
                    for (
$j 0$j 38; ++$j) {
                        if (!
is_dir($d $dir.$chars[$i].DIRECTORY_SEPARATOR.$chars[$j])) {
                            continue;
                        }
                        foreach (
scandir($dSCANDIR_SORT_NONE) ?: [] as $link) {
                            if (
'.' === $link || '..' === $link) {
                                continue;
                            }
                            if (
'_' !== $dir[-2] && realpath($d.DIRECTORY_SEPARATOR.$link)) {
                                
$keepDir true;
                            } else {
                                
unlink($d.DIRECTORY_SEPARATOR.$link);
                            }
                        }
                        
$keepDir ?: rmdir($d);
                    }
                    
$keepDir ?: rmdir($dir.$chars[$i]);
                }
                
$keepDir ?: rmdir($dir);
            }
        } finally {
            
restore_error_handler();
        }

        return 
$ok;
    }

    protected function 
doClear(string $namespace): bool
    
{
        
$ok $this->doClearCache($namespace);

        if (
'' !== $namespace) {
            return 
$ok;
        }

        
set_error_handler(static function () {});
        
$chars '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

        
$this->tmpSuffix ??= str_replace('/''-'base64_encode(random_bytes(6)));

        try {
            foreach (
$this->scanHashDir($this->directory.self::TAG_FOLDER.DIRECTORY_SEPARATOR) as $dir) {
                if (
rename($dir$renamed substr_replace($dir$this->tmpSuffix.'_', -9))) {
                    
$dir $renamed.DIRECTORY_SEPARATOR;
                } else {
                    
$dir .= DIRECTORY_SEPARATOR;
                    
$renamed null;
                }

                for (
$i 0$i 38; ++$i) {
                    if (!
is_dir($dir.$chars[$i])) {
                        continue;
                    }
                    for (
$j 0$j 38; ++$j) {
                        if (!
is_dir($d $dir.$chars[$i].DIRECTORY_SEPARATOR.$chars[$j])) {
                            continue;
                        }
                        foreach (
scandir($dSCANDIR_SORT_NONE) ?: [] as $link) {
                            if (
'.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.DIRECTORY_SEPARATOR.$link))) {
                                
unlink($d.DIRECTORY_SEPARATOR.$link);
                            }
                        }
                        
null === $renamed ?: rmdir($d);
                    }
                    
null === $renamed ?: rmdir($dir.$chars[$i]);
                }
                
null === $renamed ?: rmdir($renamed);
            }
        } finally {
            
restore_error_handler();
        }

        return 
$ok;
    }

    protected function 
doSave(array $valuesint $lifetime, array $addTagData = [], array $removeTagData = []): array
    {
        
$failed $this->doSaveCache($values$lifetime);

        
// Add Tags as symlinks
        
foreach ($addTagData as $tagId => $ids) {
            
$tagFolder $this->getTagFolder($tagId);
            foreach (
$ids as $id) {
                if (
$failed && in_array($id$failedtrue)) {
                    continue;
                }

                
$file $this->getFile($id);

                if (!@
symlink($file$tagLink $this->getFile($idtrue$tagFolder)) && !is_link($tagLink)) {
                    @
unlink($file);
                    
$failed[] = $id;
                }
            }
        }

        
// Unlink removed Tags
        
foreach ($removeTagData as $tagId => $ids) {
            
$tagFolder $this->getTagFolder($tagId);
            foreach (
$ids as $id) {
                if (
$failed && in_array($id$failedtrue)) {
                    continue;
                }

                @
unlink($this->getFile($idfalse$tagFolder));
            }
        }

        return 
$failed;
    }

    protected function 
doDeleteYieldTags(array $ids): iterable
    
{
        foreach (
$ids as $id) {
            
$file $this->getFile($id);
            if (!
is_file($file) || !$h = @fopen($file'r')) {
                continue;
            }

            if (!@
unlink($file)) {
                
fclose($h);
                continue;
            }

            
$meta explode("n"fread($h4096), 3)[2] ?? '';

            
// detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F
            
if (13 strlen($meta) && "x9D" === $meta[0] && "" === $meta[5] && "x5F" === $meta[9]) {
                
$meta[9] = "";
                
$tagLen unpack('Nlen'$meta9)['len'];
                
$meta substr($meta13$tagLen);

                if (
$tagLen -= strlen($meta)) {
                    
$meta .= fread($h$tagLen);
                }

                try {
                    yield 
$id => '' === $meta ? [] : $this->marshaller->unmarshall($meta);
                } catch (
Exception) {
                    yield 
$id => [];
                }
            }

            
fclose($h);
        }
    }

    protected function 
doDeleteTagRelations(array $tagData): bool
    
{
        foreach (
$tagData as $tagId => $idList) {
            
$tagFolder $this->getTagFolder($tagId);
            foreach (
$idList as $id) {
                @
unlink($this->getFile($idfalse$tagFolder));
            }
        }

        return 
true;
    }

    protected function 
doInvalidate(array $tagIds): bool
    
{
        foreach (
$tagIds as $tagId) {
            if (!
is_dir($tagFolder $this->getTagFolder($tagId))) {
                continue;
            }

            
$this->tmpSuffix ??= str_replace('/''-'base64_encode(random_bytes(6)));

            
set_error_handler(static function () {});

            try {
                if (
rename($tagFolder$renamed substr_replace($tagFolder$this->tmpSuffix.'_', -10))) {
                    
$tagFolder $renamed.DIRECTORY_SEPARATOR;
                } else {
                    
$renamed null;
                }

                foreach (
$this->scanHashDir($tagFolder) as $itemLink) {
                    
unlink(realpath($itemLink) ?: $itemLink);
                    
unlink($itemLink);
                }

                if (
null === $renamed) {
                    continue;
                }

                
$chars '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';

                for (
$i 0$i 38; ++$i) {
                    for (
$j 0$j 38; ++$j) {
                        
rmdir($tagFolder.$chars[$i].DIRECTORY_SEPARATOR.$chars[$j]);
                    }
                    
rmdir($tagFolder.$chars[$i]);
                }
                
rmdir($renamed);
            } finally {
                
restore_error_handler();
            }
        }

        return 
true;
    }

    private function 
getTagFolder(string $tagId): string
    
{
        return 
$this->getFile($tagIdfalse$this->directory.self::TAG_FOLDER.DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
    }
}
Онлайн: 2
Реклама