Search by

cloud-castle / file-system

alex-4-17

Безопасная работа с файловой системой для PHP 8.1+: атомарная запись (случайный temp + rename), потоковое и ленивое чтение, символические/жёсткие ссылки, JSON, рекурсивные операции с каталогами, glob, временные пути и лексические операции с путями с защитой от path traversal. Суперсет возможностей S

v1.4.0 2026-09-17 12:31 UTC

README

🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano

CloudCastle FileSystem

CloudCastle FileSystem

Packagist Version PHP Version License Total Downloads Monthly Downloads Stars Dependents Suggesters Security Advisories

Source Release GitVerse Stars Forks Issues Wiki

PHPStan Psalm PHPMD Code Style Coverage Infection MSI OpenSSF Scorecard

Безопасная работа с файловой системой для PHP 8.1+: атомарная запись, потоковое и построчное чтение, символические/жёсткие ссылки, рекурсивные операции с каталогами, JSON, поиск по glob и лексические операции с путями с выявлением path traversal. Зависимости — только php и ext-fileinfo.

Установка

composer require cloud-castle/file-system

Требуется PHP 8.1+ и расширение fileinfo.

Быстрый старт

<?php

use CloudCastle\FileSystem\FileSystem;
use CloudCastle\FileSystem\Path;

// Атомарная запись (временный файл + rename) — без частично записанных файлов.
FileSystem::write('/var/app/config/app.php', '<?php return ["debug" => false];');

$content = FileSystem::read('/var/app/config/app.php');
$sha256 = FileSystem::hash('/var/app/config/app.php');
$mime = FileSystem::mimeType('/var/app/config/app.php');

// Каталоги.
FileSystem::makeDirectory('/var/app/cache');
$files = FileSystem::allFiles('/var/app');       // рекурсивно, отсортировано
FileSystem::deleteDirectory('/var/app/cache');   // рекурсивно

// JSON, ленивое чтение и замена.
FileSystem::writeJson('/var/app/state.json', ['ready' => true]);
$state = FileSystem::readJson('/var/app/state.json');
foreach (FileSystem::lines('/var/log/app.log') as $line) { /* без загрузки в память */ }

// Ссылки, рекурсивное копирование, glob.
FileSystem::symlink('/var/app/current', '/var/app/releases/42');
FileSystem::copyDirectory('/var/app/skel', '/var/app/new');
$logs = FileSystem::glob('/var/log/*.log');

// Пути (без обращения к диску).
$path = Path::join('/var', 'app', 'config');           // «/var/app/config»
$safe = Path::normalize('/var/data/../../etc');        // «/etc» — виден выход за пределы
$inside = Path::isWithin('/var/app', '/var/app/x');    // true — защита от path traversal
$rel = Path::relative('/var/log', '/var/app');         // «../log»
$base = Path::commonBasePath('/var/www/a', '/var/www/b'); // «/var/www»
<?php

use CloudCastle\FileSystem\Directory;
use CloudCastle\FileSystem\Finder;
use CloudCastle\FileSystem\TemporaryDirectory;

// Текучий поиск: PHP-файлы глубже первого уровня, крупнее 1 КБ, отсортированные.
$found = Finder::create()
    ->files()
    ->name('*.php')
    ->notName('*.blade.php')
    ->depth(1)
    ->filter(static fn (\SplFileInfo $f): bool => $f->getSize() > 1024)
    ->sortByName()
    ->from('/var/app/src')
    ->paths();

// Зеркалирование и сравнение деревьев.
Directory::mirror('/var/app/dist', '/var/www/public');   // назначение = источник
$same = Directory::identical('/var/backup', '/var/app'); // структура + хеши

// Временный каталог с гарантированной автоочисткой (даже при исключении).
$tmp = TemporaryDirectory::make()->deleteWhenDestroyed();
FileSystem::write($tmp->path('report/data.json'), '{}'); // подкаталоги создаются
// ...по выходу из области видимости $tmp каталог удаляется автоматически.

// Рекурсивная смена прав по всему дереву.
FileSystem::chmod('/var/app/cache', 0o750, recursive: true);

Возможности

  • Атомарная запись через временный файл со случайным именем + rename — исключает частично записанные файлы при сбое или гонке.
  • Файлы: чтение — обычное и под разделяемой блокировкой (read(shared: true), согласованный снимок при параллельной дозаписи под LOCK_EX), построчное и ленивое (генератор) чтение, запись, запись массива строк (writeLines), атомарное преобразование (atomicUpdate), дозапись в начало/конец, замена подстрок, копирование, перемещение, удаление, touch, chmod; предикаты missing, isReadable, isWritable, isExecutable, type.
  • Потоки: readStream/writeStream — обработка больших файлов без загрузки в память; запись из потока атомарна.
  • JSON: readJson/writeJson с контролем ошибок кодирования.
  • Ссылки: символические и жёсткие ссылки (symlink, hardlink, readlink).
  • Метаданные и права: размер, directorySize, время модификации, хеш (sha256 и др.), checksumEquals (timing-safe), MIME-тип, guessExtension, humanSize, видимость visibility/setVisibility; права chmod/chown/chgrp с рекурсивным применением по дереву (recursive: true); разрешение реального пути через readlink(canonicalize: true) (аналог realpath).
  • Каталоги: создание (рекурсивно), гарантированное существование файла и каталога (ensureFileExists/ensureDirectoryExists), рекурсивные копирование/перемещение/удаление/очистка, листинг файлов и подкаталогов (в т.ч. рекурсивный), поиск по glob и рекурсивный find, isDirectoryEmpty, deleteDirectories.
  • Текучий поиск (Finder): декларативный обход дерева с фильтрами по типу, маскам имени (name/notName), глубине (depth), произвольным предикатам (filter) и сортировкой; результаты — SplFileInfo со всеми метаданными.
  • Операции над деревом (Directory): зеркалирование каталога (mirror — приведение назначения к источнику с удалением лишнего) и сравнение двух деревьев на идентичность структуры и содержимого (identical).
  • Реестр MIME ↔ расширение (MimeTypes): разрешение расширения по MIME-типу и обратно из встроенной таблицы распространённых типов, без внешних зависимостей.
  • Временные ресурсы с автоочисткой (TemporaryDirectory, TemporaryFile): RAII-объекты, гарантированно удаляющие ресурс при разрушении (deleteWhenDestroyed) — даже при исключении; поддержка явного имени и пересоздания (force).
  • Пути: join, normalize, canonicalize, resolve, relative, isWithin (защита от path traversal), makeAbsolute, getRoot, commonBasePath, getHomeDirectory, expandUser (раскрытие ~), segments, unixSlashes, extension, filename, removeExtension, changeExtension, hasExtension, isAbsolute.
  • Безопасность: отклонение байта NUL в путях, случайное имя temp-файла, атомарность, лексическое выявление выхода за каталог, контрактные исключения вместо предупреждений PHP.

Сравнение с аналогами

Все таблицы ниже сгенерированы автоматически из честных сравнительных тестов (benchmarks/compare.php) на ОДИНАКОВОЙ операции для всех аналогов, PHP 8.3.32, без Xdebug.

1. Функциональность

Возможность🏆 CloudCastlesymfonyleagueilluminatenettespatienative¹
Атомарная запись (temp + rename)
Дозапись в начало и конец файла
Чтение под разделяемой блокировкой (LOCK_SH)
Хеш и MIME-тип из коробки
Ленивое построчное чтение (генератор)
Потоковая обработка (readStream/writeStream)
JSON: чтение и запись
Символические и жёсткие ссылки
Рекурсивное копирование каталога
Поиск по glob-шаблону
Лексические операции с путями (relative, isWithin)
Временные файлы и каталоги
Рекурсивный листинг файлов
Управление видимостью (visibility)
Нулевые внешние зависимости (кроме ext-fileinfo)
Текучий поиск с фильтрами (Finder)
Зеркалирование каталога (mirror)
Сравнение деревьев на идентичность
RAII-объекты временных ресурсов (автоочистка)
Рекурсивные права (chmod/chown/chgrp по дереву)
Реестр MIME ↔ расширение из коробки
Разрешение реального пути (realpath)
Утилиты путей: корень, общий базовый, домашний каталог
Всего🏆 231049533

2. Безопасность и корректность

Свойство🏆 CloudCastlesymfonyleagueilluminatenettespatienative¹
Атомарная запись (нет частичных файлов при сбое)
Случайное имя временного файла (защита от symlink-атаки)
Отклонение байта NUL в пути
Лексическое выявление path traversal (isWithin)
Дозапись под блокировкой (LOCK_EX)
Timing-safe проверка целостности (checksumEquals)
Контрактные исключения (маркер-интерфейс)
Гарантированная очистка временных ресурсов (RAII)
Всего🏆 8410120

2.1. Соответствие стандартам безопасности

СтандартCloudCastlesymfonyleagueilluminatenettespatienative¹🏆 Победители
Политика раскрытия уязвимостей (SECURITY.md)CloudCastle, symfony, league, illuminate, nette, spatie
Мониторинг уязвимостей (Packagist Security Advisories)CloudCastle, symfony, league, illuminate, nette, spatie
OpenSSF Scorecard (автоскан практик; доступен только GitHub-репозиториям)symfony, league, illuminate, nette, spatie
OpenSSF Best Practices (бейдж CII)
Статический анализ в CI пакета (PHPStan/Psalm)CloudCastle, symfony, league, nette, spatie
Мутационное тестирование в CI (Infection, MSI 100%)CloudCastle
Защита от path traversal — CWE-22CloudCastle, symfony, league
Timing-safe сравнение секретов и хешей — CWE-208CloudCastle
Атомарная запись против гонок и частичных файлов — CWE-362/CWE-367CloudCastle, symfony
Безопасное создание временных файлов — CWE-377CloudCastle, symfony
Всего🏆 8753440🏆 CloudCastle

3. Производительность

Рекурсивный листинг 80 файлов дерева, 3 000 раз (минимум из 4).

РешениеВремя (мс)Итог
🏆 CloudCastle3 536,3быстрейшее среди библиотек
native¹3 540,3базовый уровень (не библиотека)
league4 818,1аналог
symfony4 923,1аналог
nette5 318,6аналог
illuminate6 618,6аналог

4. Потребление памяти

_Рабочая память операции: пик рабочего набора на 3 000 листингов после прогрева классов (memory_reset_peakusage, PHP 8.2+) — только аллокации операции, не вес загруженного кода.

РешениеПиковая память (KB)Итог
🏆 league14легчайшее среди библиотек
symfony17аналог
CloudCastle18аналог
native¹18базовый уровень (не библиотека)
nette26аналог
illuminate83аналог

¹ Базовый уровень (нативные вызовы/примитивы без полноты решения) показан для контекста и не претендует на победу среди библиотек-аналогов.

Производительность и память измеряются на рекурсивном листинге дерева (частая операция обхода проекта). Все аналоги приведены к ЭКВИВАЛЕНТНОЙ работе — материализации одного и того же отсортированного списка путей, который allFiles даёт из коробки. Каждая библиотека замеряется в отдельном процессе; память — это пик рабочего набора самой операции после прогрева классов (не вес загруженного кода). league легче по рабочей памяти за счёт ленивого генератора, уступая по функционалу (4 из 22) — осознанный компромисс: детерминированный материализованный список против ленивого потока.

Вывод: CloudCastle FileSystem объединяет возможности пяти популярных пакетов (суперсет по функционалу — 23 из 23), лидирует по безопасности, качеству кода и по скорости обхода дерева среди библиотек, при нулевых внешних зависимостях (кроме ext-fileinfo).

Плюсы и минусы

Плюсы:

  • Самый широкий набор операций из коробки — суперсет (23 из 23 возможностей) Symfony Filesystem, Flysystem, Laravel, Nette и Spatie вместе взятых: атомарная запись, чтение под разделяемой блокировкой, ссылки, JSON, glob, рекурсивные операции и права, ленивое чтение, потоки, текучий поиск (Finder), зеркалирование и сравнение деревьев (Directory), временные ресурсы с автоочисткой (TemporaryDirectory/TemporaryFile), реестр MIME (MimeTypes), богатые лексические операции с путями.
  • Безопасность по умолчанию: атомарность, случайное имя temp-файла, отклонение байта NUL, лексическое выявление path traversal (isWithin), timing-safe проверка целостности, RAII-очистка временных ресурсов, контрактные исключения с маркер-интерфейсом.
  • Нулевые внешние зависимости (только php и ext-fileinfo) — без транзитивного веса и конфликтов версий.
  • 100 % покрытие строк на каждый файл и 100 % Infection MSI; строгий статанализ (PHPStan max, Psalm errorLevel 1, PHPMD, Deptrac, Rector, PSR-12).
  • Быстрее аналогов на обходе дерева за счёт прямого итератора без оверхеда абстракций.

Минусы:

  • Пакет моложе и менее распространён, чем Symfony/Laravel/Flysystem — меньше сторонних материалов и время на нём в проде.
  • Рабочая память рекурсивного листинга выше, чем у ленивого генератора league: материализованный детерминированный список против ленивого потока — осознанный компромисс в пользу функциональности и скорости (см. таблицу памяти ниже).

Примечание: API — статический фасад (удобно и без DI-настройки); если в тестах приложения нужно мокать ввод-вывод, абстрагируйте вызовы за собственный интерфейс. Пакет осознанно ограничен локальной файловой системой — единый API поверх облачных бэкендов не входит в его задачу (см. «Когда лучше взять другое»).

Когда применять

  • Конфигурация, кэш, сессии, генерация файлов — там, где критична атомарная запись без частично записанных файлов (деплой, сборка артефактов).
  • Финтех и обработка ПД — благодаря защите от path traversal (isWithin), отклонению NUL и случайным именам temp-файлов при загрузке/выгрузке файлов.
  • CLI-инструменты и скрипты сборки — быстрый рекурсивный обход дерева, хеширование, glob, операции с путями без тяжёлых зависимостей.
  • Библиотеки и пакеты — когда нужен богатый файловый API без навязывания пользователю транзитивных зависимостей.
  • Когда лучше взять другое: для работы с облачными хранилищами или единого API поверх нескольких бэкендов — Flysystem; если проект уже целиком на Symfony или Laravel и хватает их файловых компонентов — их и достаточно.

Разработка

composer install
composer check    # линтеры + статический анализ + тесты
composer fix      # автоисправления (Rector, PHP CS Fixer, PHPCBF)
composer ci       # полный CI-пайплайн локально

Полный список команд с описаниями: composer run-script --list.

Документация

Лицензия

MIT © CloudCastle (alex-4-17@yandex.ru)

🇷🇺 Русский · 🇬🇧 English · 🇩🇪 Deutsch · 🇫🇷 Français · 🇪🇸 Español · 🇮🇹 Italiano