bocharsky-bw / file-naming-resolver
一个轻量级的库,用于通过各种命名策略解决上传文件的文件/目录命名。
Requires
- php: >=5.3
Requires (Dev)
- phpunit/phpunit: ~4.8
README
一个轻量级的库,用于通过各种命名策略解决上传文件的文件/目录命名。
此库仅解决命名问题,不会直接处理任何文件或目录。如果您正在寻找一些文件系统抽象层,则更接近于 Gaufrette、symfony/filesystem 或 Flysystem 库。
内容
需求
此库是独立的,没有依赖。要在项目中使用它,请确保符合以下要求
- PHP
5.3或更高版本
安装
安装此包的首选方法是使用 Composer
$ composer require bocharsky-bw/file-naming-resolver
如果您不使用 Composer - 请根据 PSR-4 自动加载标准手动注册此包,或者简单地下载此库并在脚本中直接 require 必要的文件
require_once __DIR__ . '/path/to/library/src/FileNamingResolver.php'; // and other files you intend to use...
使用
首先,在使用文件命名解析器之前,您应该确定要使用哪种命名策略。您可以使用不同的策略,也可以通过实现 NamingStrategyInterface 接口或扩展已为您实现它的 AbstractNamingStrategy 类来轻松创建自己的策略。
// don't forget to use namespaces use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\HashNamingStrategy; // First of all, upload new file or use any uploaded file on the your server // Create source FileInfo object from FQFN of uploaded file $srcFileInfo = new FileInfo(__DIR__.'/uploads/image.jpg'); // Create at least one naming strategy object $hashStrategy = new HashNamingStrategy(); // Create file naming resolver and pass naming strategy to it $namingResolver = new FileNamingResolver($hashStrategy); // Resolve new name using specified naming strategy $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/4e/d3/a51a07c8e89ff8f228075b7fc76b.jpg // Use rename() / move_uploaded_file() built-in functions, Gaufrette or any other filesystem // abstraction library to move uploaded file to the directory according to suggested pathname.
注意:以下所有示例中
__DIR__等于/var/www/html/web。
文件信息
FileNamingResolver\FileInfo 类扩展了 \SplFileInfo 对象。有关更多信息,请查看 SplFileInfo。以下列出了此类常用的获取器
$fileInfo = new FileInfo('/var/www/html/web/uploads/products/image.jpg'); echo $fileInfo->toString(); // '/var/www/html/web/uploads/products/image.jpg' echo $fileInfo->getPathname(); // '/var/www/html/web/uploads/products/image.jpg' echo $fileInfo->getPath(); // '/var/www/html/web/uploads/products' echo $fileInfo->getFilename(); // 'image.jpg' echo $fileInfo->getBasename(); // 'image' echo $fileInfo->getExtension(); // 'jpg' echo $fileInfo->getPathRelativeTo('/var/www/html/web'); // 'uploads/products' echo $fileInfo->getPathnameRelativeTo('/var/www/html/web'); // 'uploads/products/image.jpg'
策略列表
聚合命名策略
此命名策略允许同时使用任意数量的命名策略。它会聚合结果。每个新结果路径基于上一个路径。
use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\AggregateNamingStrategy; use FileNamingResolver\NamingStrategy\DatetimeNamingStrategy; use FileNamingResolver\NamingStrategy\HashNamingStrategy; $srcFileInfo = new FileInfo(__DIR__.'/uploads/image.jpg'); $datetimeStrategy = new DatetimeNamingStrategy(); $hashStrategy = new HashNamingStrategy(); // Create an aggregate naming strategy object $strategies = [ $datetimeStrategy, $hashStrategy, // and so on as many as you need... ]; $aggregateStrategy = new AggregateNamingStrategy($strategies); $namingResolver = new FileNamingResolver($aggregateStrategy); $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/2015/12/9c/98/87cbf44f53c9f6fa08f44ce705c8.jpg
要将策略的适用顺序反转,请将 true 作为 AggregateNamingStrategy 类构造函数的第二个参数传递
$aggregateStrategy = new AggregateNamingStrategy($strategies, AggregateNamingStrategy::MODE_REVERSE); $namingResolver = new FileNamingResolver($aggregateStrategy); $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/a0/cb/2015/12/11-23-35-039900.jpg
回调命名策略
此命名策略允许使用自定义回调创建自定义命名逻辑。
use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\CallbackNamingStrategy; $srcFileInfo = new FileInfo(__DIR__.'/uploads/image.jpg'); // Create a custom callback naming strategy object $callbackStrategy = new CallbackNamingStrategy(function (FileInfo $srcFileInfo) { $dstFileInfo = $srcFileInfo // Add 'products' suffix to the path ->changePath($srcFileInfo->getPath().FileInfo::SEPARATOR_DIRECTORY.'products') // Generate custom basename of the file without extension ->changeBasename(time().'-'.uniqid()) // comment this line to keep original basename // or do whatever custom naming logic you want here... ; return $dstFileInfo; }); $namingResolver = new FileNamingResolver($callbackStrategy); $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/products/1450004778-566d512a32d2c.jpg
内容哈希命名策略
哈希命名策略的命名行为类似于 Twig 缓存文件的命名。
use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\ContentHashNamingStrategy; $srcFileInfo = new FileInfo(__DIR__.'/uploads/image.jpg'); // Create a hash naming strategy object $contentHashStrategy = new ContentHashNamingStrategy( // Hashing algorithm, by default: 'md5' ContentHashNamingStrategy::ALGORITHM_SHA1, // 'sha1' // Count of parts for explode, by default: 2 3, // Length of each exploded part, by default: 2 3, // Keep full filename for easy searching true ); $namingResolver = new FileNamingResolver($contentHashStrategy); $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/4ed/3a5/1a0/4ed3a51a07c8e89ff8f228075b7fc76b.jpg
注意:在使用
ContentHashNamingStrategy之前,请确保源文件确实存在,否则将抛出InvalidArgumentException。您可能需要使用FileInfo对象上的isFile()方法来确保文件存在。这是必要的,因为此命名策略尝试对实际的文件内容进行哈希处理。
日期时间命名策略
日期时间命名策略的命名行为类似于 WordPress 上传媒体文件的命名。
use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\DatetimeNamingStrategy; $srcFileInfo = new FileInfo(__DIR__.'/uploads/image.jpg'); // Create a datetime naming strategy object $datetimeStrategy = new DatetimeNamingStrategy( // DateTime format for directories, by default: 'Y/m' DateTimeNamingStrategy::FORMAT_DIR_YEAR_MONTH_DAY, // 'Y/m/d' // DateTime format for files, by default: 'H-i-s-u' DateTimeNamingStrategy::FORMAT_FILE_TIMESTAMP_MICROSECONDS // 'U-u' ); $namingResolver = new FileNamingResolver($datetimeStrategy); $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/2015/12/13/1450004392-907500.jpg
哈希命名策略
哈希命名策略的命名行为类似于 Twig 缓存文件的命名。
use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\HashNamingStrategy; $srcFileInfo = new FileInfo(__DIR__.'/uploads/image.jpg'); // Create a hash naming strategy object $hashStrategy = new HashNamingStrategy( // Hashing algorithm, by default: 'md5' HashNamingStrategy::ALGORITHM_SHA1, // 'sha1' // Count of parts for explode, by default: 2 3, // Length of each exploded part, by default: 2 3, // Keep full filename for easy searching true ); $namingResolver = new FileNamingResolver($hashStrategy); $dstFileInfo = $namingResolver->resolve($srcFileInfo); echo $dstFileInfo->toString(); // /var/www/html/web/uploads/4ed/3a5/1a0/4ed3a51a07c8e89ff8f228075b7fc76b.jpg
示例
以下是一个完整的工作示例,演示如何使用 FileNamingResolver 库和简单的 HTML 表单以及内置的 PHP 函数上传文件。
<?php require_once __DIR__.'/vendor/autoload.php'; use FileNamingResolver\FileInfo; use FileNamingResolver\FileNamingResolver; use FileNamingResolver\NamingStrategy\HashNamingStrategy; // Define a few constants for convenience define('WEB_ROOT_DIR', __DIR__); define('UPLOAD_ROOT_DIR', WEB_ROOT_DIR.'/uploads'); // Check whether form was submitted... if (isset($_POST['upload'])) { // and file was attached - process file uploading if ($_FILES['attachment']['tmp_name']) { $strategy = new HashNamingStrategy(); // or create any other strategy you need here $namingResolver = new FileNamingResolver($strategy); // use created naming strategy in resolver $dstFileInfo = new FileInfo(UPLOAD_ROOT_DIR.'/'.$_FILES['attachment']['name']); // build destination pathname $dstFileInfo = $namingResolver->resolve($dstFileInfo); // apply specified naming strategy to the destination file // Change extension based on mime type of uploaded file // WARNING: Could be skipped if you want to base on original extension in $_FILES['attachment']['name'] but it could cause some security issues! switch ($_FILES['attachment']['type']) { case 'image/jpeg': $extension = 'jpg'; break; case 'image/png': $extension = 'png'; break; default: $extension = 'bin'; } // The FileInfo object is immutable so changeExtension() creates a new object. // Don't forget to override previous variable $dstFileInfo = $dstFileInfo->changeExtension($extension); // create non-existent directories for the destination file if (false === is_dir($dstFileInfo->getPath())) { if (false === mkdir($dstFileInfo->getPath(), 0777, true)) { throw new RuntimeException('Unable to create a directory for the destination file.'); } } // move uploaded file according to the destination pathname if (false === move_uploaded_file($_FILES['attachment']['tmp_name'], $dstFileInfo->toString())) { throw new RuntimeException('Unable to move an uploaded file to the specified directory.'); } // Do whatever you want after successful uploading (i.e redirect user after success uploading) echo sprintf( 'File "<b>%s</b>" successfully uploaded to the "<b>%s</b>" web directory! :)', $dstFileInfo->getFilename(), $dstFileInfo->getPathRelativeTo(WEB_ROOT_DIR) // get path relative to the web directory ); } } ?> <form action="" method="POST" enctype="multipart/form-data"> <input type="file" name="attachment"> <input type="submit" name="upload" value="Upload file"> </form>
贡献
如果您发现任何错误或希望提出改进建议,请随时提交一个问题或创建一个拉取请求。
为了提出一个新功能,最佳的方式是首先提交一个问题并对其进行讨论。