PHP code example of zenstruck / filesystem

1. Go to this page and download the library: Download zenstruck/filesystem library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

zenstruck / filesystem example snippets


/** @var \Zenstruck\Filesystem $filesystem */

// read operations
$filesystem->has('some/path'); // bool
$filesystem->node('some/path'); // Zenstruck\Filesystem\Node\File|Zenstruck\Filesystem\Node\Directory or throws NodeNotFound
$filesystem->file('some/path.txt'); // Zenstruck\Filesystem\Node\File or throws NodeNotFound or NodeTypeMismatch (if exists but not a file)
$filesystem->image('some/path.png'); // Zenstruck\Filesystem\Node\File\Image or throws NodeNotFound or NodeTypeMismatch (if exists but not an image)
$filesystem->directory('some/path'); // Zenstruck\Filesystem\Node\Directory or throws NodeNotFound or NodeTypeMismatch (if exists but not a directory)

// write operations (returns Zenstruck\Filesystem\File)
$filesystem->write('some/path.txt', 'string contents'); // write a string
$filesystem->write('some/path.txt', $resource); // write a resource
$filesystem->write('some/path.txt', new \SplFileInfo('path/to/local/file.txt')); // write a local file
$filesystem->write('some/path.txt', $file); // write a Zenstruck\Filesystem\Node\File

$filesystem->copy('from/file.txt', 'dest/file.txt'); // Zenstruck\Filesystem\Node\File (dest/file.txt)

$filesystem->move('from/file.txt', 'dest/file.txt'); // Zenstruck\Filesystem\Node\File (dest/file.txt)

$filesystem->delete('some/file.txt'); // returns self
$filesystem->delete('some/directory'); // returns self

// mkdir operations (returns Zenstruck\Filesystem\Node\Directory)
$filesystem->mkdir('some/directory'); // create an empty directory
$filesystem->mkdir('some/prefix', $directory); // create directory with files from Zenstruck\Filesystem\Node\Directory
$filesystem->mkdir('some/prefix', new \SplFileInfo('path/to/local/directory')); // create directory with files from local directory

$filesystem->chmod('some/file.txt', 'private'); // Zenstruck\Filesystem\Node (some/file.txt)

// utility methods
$filesystem->name(); // string - human-readable name for the filesystem

/** @var \Zenstruck\Filesystem\Node $node */

$node->path(); // Zenstruck\Filesystem\Node\Path
$node->path()->toString(); // string - the full path
(string) $node->path(); // same as above
$node->path()->name(); // string - filename with extension
$node->path()->basename(); // string - filename without extension
$node->path()->extension(); // string|null - file extension
$node->path()->dirname(); // string|null - the parent directory (or null if there is none)

$node->dsn(); // Zenstruck\Filesystem\Node\Dsn
$node->dsn()->toString(); // string - <filesystem-name>://<full-path>
(string) $node->dsn(); // same as above
$node->dsn()->path(); // Zenstruck\Filesystem\Node\Path
$node->dsn()->filesystem(); // string - name of the filesystem this node belongs to

$node->directory(); // Zenstruck\Filesystem\Node\Directory|null - parent directory object (or null if there is none)

$node->visibility(); // string - ie "public" or "private"
$node->lastModified(); // \DateTimeImmutable (in currently configured timezone)

$node->isDirectory(); // bool
$node->isFile(); // bool
$node->isImage(); // bool

$node->exists(); // bool
$node->ensureExists(); // static or throws NodeNotFound

$node->refresh(); // static and clears any cached metadata

$node->ensureDirectory(); // Zenstruck\Filesystem\Node\Directory or throws NodeTypeMismatch (if not a directory)
$node->ensureFile(); // Zenstruck\Filesystem\Node\File or throws NodeTypeMismatch (if not a file)
$node->ensureImage(); // Zenstruck\Filesystem\Node\Image or throws NodeTypeMismatch (if not an image)

/** @var \Zenstruck\Filesystem\Node\File $file */

$file->contents(); // string - the file's contents

$file->stream(); // \Zenstruck\Stream - wrapper for a resource

$file->read(); // "raw" resource

$file->size(); // int

$file->guessExtension(); // string|null - returns extension if available or attempts to guess from mime-type

$file->checksum(); // string - using FilesystemAdapter's default algorithm
$file->checksum('md5'); // string - specify the algorithm

$file->publicUrl(); // string (needs to be configured)
$file->temporaryUrl(new \DateTimeImmutable('+30 minutes')); // string - expiring url (needs to be configured)
$file->temporaryUrl('+30 minutes'); // equivalent to above

$file->tempFile(); // \SplFileInfo - temporary local file that's deleted at the end of the script

use Zenstruck\Filesystem\Node\File\PendingFile;

$file = new PendingFile('/path/to/local/file.txt');
$file->path()->toString(); // "/path/to/local/file.txt"

/** @var \Symfony\Component\HttpFoundation\File\UploadedFile $uploadedFile */

$file = new PendingFile($uploadedFile);
$file->path()->toString(); // $uploadedFile->getClientOriginalName()

/** @var \Zenstruck\Filesystem\Node\File\Image $image */

$image->dimensions(); // Zenstruck\Image\Dimensions
$image->dimensions()->height(); // int
$image->dimensions()->width(); // int
$image->dimensions()->pixels(); // int
$image->dimensions()->aspectRatio(); // float
$image->dimensions()->isSquare(); // bool
$image->dimensions()->isPortrait(); // bool
$image->dimensions()->isLandscape(); // bool

$image->exif(); // array - image exif data if available
$image->iptc(); // array - image iptc data if available

$thumbHash = $image->thumbHash(); // Zenstruck\Image\Hash\ThumbHash (

use Zenstruck\Filesystem\Node\File\Image\PendingImage;

$image = new PendingImage('/path/to/local/file.txt');
$image = new PendingImage($symfonyUploadedFile);

// transform and overwrite
$image->transformInPlace(
    function(ManipulationObject $image) {
        // make manipulations

        return $image;
    }
); // self

/** @var Zenstruck\Filesystem\Node\Directory $directory */

// iterate over nodes (non-recursive)
foreach ($directory as $node) {
    /** @var Zenstruck\Filesystem\Node $node */
}

// iterate over only files (non-recursive)
foreach ($directory->files() as $file) {
    /** @var Zenstruck\Filesystem\Node\File $file */
}

// iterate over only directories (non-recursive)
foreach ($directory->directories() as $dir) {
    /** @var Zenstruck\Filesystem\Node\Directory $dir */
}

// recursively iterate
foreach ($directory->recursive() as $node) {
    /** @var Zenstruck\Filesystem\Node $node */
}

// advanced filter
$directories = $directory
    ->recursive()
    ->files()
    ->largerThan('10M')
    ->smallerThan('1G')
    ->olderThan('30 days ago')
    ->newerThan('20 days ago')
    ->matchingFilename('*.twig')
    ->notMatchingFilename('*.txt.twig')
    ->matchingPath('/files/')
    ->notMatchingPath('/exclude/')
    ->filter(function(File $file) { // custom filter
        if ($someCondition) {
            return false; // exclude
        }

        return true; // 

use Zenstruck\Filesystem\FlysystemFilesystem;

/** @var \League\Flysystem\FilesystemOperator $operator */
/** @var \League\Flysystem\FilesystemAdapter $adapter */

// create from an already configured Flysystem Filesystem Operator
$filesystem = new FlysystemFilesystem($operator);

// create from an already configured Flysystem Filesystem Adapter
$filesystem = new FlysystemFilesystem($operator);

// create for local directory
$filesystem = new FlysystemFilesystem('/path/to/local/dir');

// create for dsn (see available DSNs below)
$filesystem = new FlysystemFilesystem('flysystem+ftp://user:[email protected]:21/root');

use Zenstruck\Filesystem\ScopedFilesystem;

/** @var \Zenstruck\Filesystem $primaryFilesystem */

$scopedFilesystem = new ScopedFilesystem($primaryFilesystem, 'some/prefix');

// paths are prefixed
$scopedFilesystem
    ->write('file.txt', 'content')
    ->path()->toString(); // "some/prefix/file.txt"
;

// prefix is stripped from path
$scopedFilesystem
    ->write('some/prefix/file.txt', 'content')
    ->path()->toString(); // "some/prefix/file.txt"
;

use Zenstruck\Filesystem\MultiFilesystem;

/** @var \Zenstruck\Filesystem $filesystem1 */
/** @var \Zenstruck\Filesystem $filesystem2 */

$filesystem = new MultiFilesystem([
    'filesystem1' => $filesystem1,
    'filesystem2' => $filesystem2,
]);

// prefix paths with a "scheme" as the filesystem's name
$filesystem->file('filesystem1://some/file.txt'); // File from "filesystem1"
$filesystem->file('filesystem2://another/file.txt'); // File from "filesystem2"

// can copy and move across filesystems
$filesystem->copy('filesystem1://file.txt', 'filesystem2://file.txt');
$filesystem->move('filesystem1://file.txt', 'filesystem2://file.txt');

// set a default filesystem for when no scheme is set
$filesystem = new MultiFilesystem(
    [
        'filesystem1' => $filesystem1,
        'filesystem2' => $filesystem2,
    ],
    default: 'filesystem2'
);

$filesystem->file('another/file.txt'); // File from "filesystem2"

use Zenstruck\Filesystem\CacheFilesystem;
use Zenstruck\Filesystem\Node\Mapping;

/** @var \Zenstruck\Filesystem $inner */
/** @var \Psr\Cache\CacheItemPoolInterface $cache */

$filesystem = new CacheFilesystem(
    inner: $inner,
    cache: $cache,
    metadata: [ // array of metadata to cache (see Zenstruck\Filesystem\Node\Mapping)
        Mapping::LAST_MODIFIED,
        Mapping::SIZE,
    ],
    ttl: 3600, // or null for no TTL
);

$filesystem->write('file.txt', 'content'); // caches metadata

$file = $filesystem->file('file.txt');
$file->lastModified(); // cached value
$file->size(); // cached value
$file->checksum(); // real value (as this wasn't configured to be cached)
$file->contents(); // actually reads the file (contents cannot be cached)

use Zenstruck\Filesystem\LoggableFilesystem;
use Zenstruck\Filesystem\Operation;
use Psr\Log\LogLevel;

/** @var \Zenstruck\Filesystem $inner */
/** @var \Psr\Log\LoggerInterface $logger */

$filesystem = new LoggableFilesystem($inner, $logger);

// operations are logged
$filesystem->write('file.txt', 'content'); // logged as '[info] Writing "string" to "file.txt" on filesystem "<filesystem-name>"'

// customize the log levels for each operation
$filesystem = new LoggableFilesystem($inner, $logger, [
    Operation::READ => false, // disable logging read operations
    Operation::WRITE => LogLevel::DEBUG,
    Operation::MOVE => LogLevel::ALERT,
    Operation::COPY => LogLevel::CRITICAL,
    Operation::DELETE => LogLevel::EMERGENCY,
    Operation::CHMOD => LogLevel::ERROR,
    Operation::MKDIR => LogLevel::NOTICE,
]);

use Zenstruck\Filesystem\Event\EventDispatcherFilesystem;
use Zenstruck\Filesystem\Operation;

/** @var \Zenstruck\Filesystem $inner */
/** @var \Psr\EventDispatcher\EventDispatcherInterface $dispatcher */

$filesystem = new EventDispatcherFilesystem($inner, $dispatcher, [
    // set these to false or exclude to disable dispatching operation's event
    Operation::WRITE => true,
    Operation::COPY => true,
    Operation::MOVE => true,
    Operation::DELETE => true,
    Operation::CHMOD => true,
    Operation::MKDIR => true,
]);

$filesystem->write('foo', 'bar'); // PreWriteEvent/PostWriteEvent dispatched
$filesystem->mkdir('bar'); // PreMkdirEvent/PostMkdirEvent dispatched
$filesystem->chmod('foo', 'public'); // PreChmodEvent/PostChmodEvent dispatched
$filesystem->copy('foo', 'file.png'); // PreCopyEvent/PostCopyEvent dispatched
$filesystem->delete('foo'); // PreDeleteEvent/PostDeleteEvent dispatched
$filesystem->move('file.png', 'file2.png'); // PreMoveEvent/PostMoveEvent dispatched
;

use Zenstruck\Filesystem\Archive\ZipFile;

$archive = new ZipFile('/local/path/to/archive.zip');
$archive->file('some/file.txt');
$archive->write('another/file.txt', 'content');

(string) $archive; // /local/path/to/archive.zip

use Zenstruck\Filesystem\Archive\ZipFile;

$archive = new ZipFile();

$archive->write('some/file.txt', 'content');
$archive->write('another/file.txt', 'content');

(string) $archive; // /tmp/...

use Zenstruck\Filesystem\Archive\ZipFile;

$archive = new ZipFile();

$archive->beginTransaction(); // start the transaction
$archive->write('some/file.txt', 'content');
$archive->write('another/file.txt', 'content');
$archive->commit(); // actually writes the above files

// optionally pass a progress callback to commit
$archive->commit(function() use ($progress) { // callback is called at most, 100 times
    $progress->advance();
});

use Zenstruck\Filesystem\Archive\ZipFile;

// compress a local file
$zipFile = ZipFile::compress(new \SplFileInfo('/some/local/file.txt')); // ZipFile (temp file deleted on script end)

// compress a local directory (all files (recursive) in "some/local/directory" are added to archive)
$zipFile = ZipFile::compress(new \SplFileInfo('some/local/directory'));

/** @var \Zenstruck\Filesystem\Node\File $file */

// compress a filesystem file
$zipFile = ZipFile::compress($file);

/** @var \Zenstruck\Filesystem\Node\Directory $directory */

// compress a filesystem directory
$zipFile = ZipFile::compress($directory);

// compress several local/filesystem files
$zipFile = ZipFile::compress([
    new \SplFileInfo('/some/local/file.txt'),
    $file,
    'customize/path.txt' => $file, // use a string array key to set the path for the file
]);

// customize the output filename (will not be deleted at end of script)
$zipFile = ZipFile::compress(..., filename: 'path/to/archive.zip');

use Zenstruck\Filesystem\Archive\TarFile;

$archive = new TarFile('/local/path/to/archive.tar');
$archive = new TarFile('/local/path/to/archive.tar.gz');
$archive = new TarFile('/local/path/to/archive.tar.bz2');

$archive->file('some/file.txt'); // \Zenstruck\Filesystem\Node\File

use Zenstruck\Filesystem\Test\TestFilesystem;
use Zenstruck\Filesystem\Test\Node\TestDirectory;
use Zenstruck\Filesystem\Test\Node\TestFile
use Zenstruck\Filesystem\Test\Node\TestImage;

/** @var \Zenstruck\Filesystem $filesystem */

$filesystem = new TestFilesystem($filesystem);

$filesystem
    ->assertExists('foo')
    ->assertNotExists('invalid')
    ->assertFileExists('file1.txt')
    ->assertDirectoryExists('foo')
    ->assertImageExists('symfony.png')
    ->assertSame('symfony.png', 'fixture://symfony.png')
    ->assertNotSame('file1.txt', 'fixture://symfony.png')
    ->assertDirectoryExists('foo', function(TestDirectory $dir) {
        $dir
            ->assertCount(4)
            ->files()->assertCount(2)
        ;

        $dir
            ->recursive()
            ->assertCount(5)
            ->files()->assertCount(3)
        ;
    })
    ->assertFileExists('file1.txt', function(TestFile $file) {
        $file
            ->assertVisibilityIs('public')
            ->assertChecksum($file->checksum()->toString())
            ->assertContentIs('contents1')
            ->assertContentIsNot('foo')
            ->assertContentContains('1')
            ->assertContentDoesNotContain('foo')
            ->assertMimeTypeIs('text/plain')
            ->assertMimeTypeIsNot('foo')
            ->assertLastModified('2023-01-01 08:54')
            ->assertLastModified(function(\DateTimeInterface $actual) {
                // ...
            })
            ->assertSize(9)
        ;
    })
    ->assertImageExists('symfony.png', function(TestImage $image) {
        $image
            ->assertHeight(678)
            ->assertWidth(563)
        ;
    })
;

$file = $filesystem->realFile('symfony.png'); // \SplFileInfo('/tmp/symfony.png') - deleted at the end of the script

use PHPUnit\Framework\TestCase;
use Zenstruck\Filesystem\Test\InteractsWithFilesystem;

class MyTest extends TestCase
{
    use InteractsWithFilesystem;

    public function test_1(): void
    {
        $filesystem = $this->filesystem(); // instance of TestFilesystem wrapping an in-memory filesystem
        $filesystem->write('file.txt', 'content');
        $filesystem->assertExists('file.txt');
    }
}

use PHPUnit\Framework\TestCase;
use Zenstruck\Filesystem;
use Zenstruck\Filesystem\Test\InteractsWithFilesystem;
use Zenstruck\Filesystem\Test\FilesystemProvider;

class MyTest extends TestCase implements FilesystemProvider
{
    use InteractsWithFilesystem;

    public function test_1(): void
    {
        $filesystem = $this->filesystem(); // instance of TestFilesystem wrapping the AdapterFilesystem defined below
        $filesystem->write('file.txt', 'content');
        $filesystem->assertExists('file.txt');
    }

    public function createFilesystem(): Filesystem|FilesystemAdapter|string
    {
        return '/some/temp/dir';
    }
}

use PHPUnit\Framework\TestCase;
use Zenstruck\Filesystem;
use Zenstruck\Filesystem\Test\InteractsWithFilesystem;
use Zenstruck\Filesystem\Test\FixtureFilesystemProvider;

class MyTest extends TestCase implements FixtureFilesystemProvider
{
    use InteractsWithFilesystem;

    public function test_1(): void
    {
        $filesystem = $this->filesystem(); // instance of TestFilesystem wrapping a MultiFilesystem

        $filesystem->write('file.txt', 'content'); // accesses your test filesystem
        $filesystem->assertExists('file.txt');
        $filesystem->copy('fixture://some/file.txt', 'file.txt'); // copy a fixture to your test filesystem
    }

    public function createFixtureFilesystem(): Filesystem|FilesystemAdapter|string;
    {
        return __DIR__.'/../fixtures';
    }
}

use PHPUnit\Framework\TestCase;
use Zenstruck\Filesystem;
use Zenstruck\Filesystem\Test\ResetFilesystem
use Zenstruck\Filesystem\Test\InteractsWithFilesystem;
use Zenstruck\Filesystem\Test\FilesystemProvider;

class MyTest extends TestCase implements FilesystemProvider
{
    use InteractsWithFilesystem, ResetFilesystem;

    public function test_1(): void
    {
        $this->filesystem()->write('file.txt', 'content')
        $this->filesystem()->assertExists('file.txt')
    }

    public function test_2(): void
    {
        $this->filesystem()->assertNotExists('file.txt'); // file created in test_1 was deleted before this test
    }

    public function createFilesystem(): Filesystem|FilesystemAdapter|string;
    {
        return '/some/temp/dir';
    }
}

use Zenstruck\Filesystem\Symfony\HttpFoundation\FileResponse;

/** @var \Zenstruck\Filesystem\File $file */

$response = new FileResponse($file); // auto-adds content-type/last-modified headers

// create inline/attachment responses
$response = FileResponse::attachment($file); // auto names by the filename (file.txt)
$response = FileResponse::inline($file); // auto names by the filename (file.txt)

// customize the filename used for the content-disposition header
$response = FileResponse::attachment($file, 'different-name.txt');
$response = FileResponse::inline($file, 'different-name.txt');

use Zenstruck\Filesystem\Symfony\HttpFoundation\ArchiveResponse;

/** @var \SplFileInfo|\Zenstruck\Filesystem\Node\File|\Zenstruck\Filesystem\Node\Directory $what */

$response = ArchiveResponse::zip($what);
$response = ArchiveResponse::zip($what, 'data.zip'); // customize the content-disposition name (defaults to archive.zip)

use Zenstruck\Filesystem\Symfony\Validator\PendingFileConstraint;
use Zenstruck\Filesystem\Symfony\Validator\PendingImageConstraint;

/** @var \Symfony\Component\Validator\Validator\ValidatorInterface $validator */
/** @var \Zenstruck\Filesystem\Node\File $file */
/** @var \Zenstruck\Filesystem\Node\File\Image $image */

$validator->validate($file, new PendingFileConstraint(maxSize: '1M')));

$validator->validate($image, new PendingImageConstraint(maxWidth: 200, maxHeight: 200)));