simkimsia / file_storage
Requires
- composer/installers: ~1.0
- knplabs/gaufrette: 0.1.*
This package is not auto-updated.
Last update: 2024-09-24 03:13:12 UTC
README
此插件允许您将文件存储在虚拟的后端存储中。此插件将 Gaufrette 库(https://github.com/KnpLabs/Gaufrette)封装在 CakePHP 风格中,并提供了一种简单的方法通过 StorageManager 类使用存储适配器。
存储适配器是一个统一的接口,允许您将文件数据存储到本地文件系统、内存、数据库、zip 文件或远程系统中。有一个数据库表跟踪您存储了什么。
Gaufrette 官方库包含的存储适配器有
- 本地文件系统
- Amazon S3
- ACL 意识的 Amazon S3
- Mogile FS
- Rackspace Cloudfiles
- Zip 文件
- Ftp
- Sftp
- 内存
- Grid FS
- Apc
- Doctrine DBAL
您始终可以编写自己的适配器或扩展并重载现有的适配器。
需求
- CakePHP 2.x
- PHP 5.3+
- Gaufrette 库(作为 git 子模块包含,只需初始化它)
- 如果您想处理和存储图片,则需要 CakeDC Imagine 图像处理插件 https://github.com/cakedc/imagine
安装
要简单地自动加载 Gaufrette,请启用引导程序加载插件。引导程序文件将注册 SPL 类加载器。
CakePlugin::load('FileStorage', array('bootstrap' => true));
您还需要设置插件数据库
cake schema create --plugin FileStorage
此插件依赖于 Gaufrette 库(《https://github.com/KnpLabs/Gaufrette》),初始化子模块,插件依赖于它。
git submodule update --init
如果您想使用 S3 上传,Gaufrette 也有子模块需要初始化。以下是初始化所有内容的完整过程
cd YOUR-APP-FOLDER
git submodule add git://github.com/burzum/FileStorage.git Plugin/FileStorage
git submodule update --init --recursive
如果您不想将其作为子模块添加,则只需克隆它而不是执行子模块添加,然后按照其余步骤进行
git clone git://github.com/burzum/FileStorage.git
进行操作
用法
StorageManager
要配置适配器,请使用 StorageManager::config 方法。第一个参数是配置名称,第二个是该适配器的选项数组
StorageManager::config('Local', array(
'adapterOptions' => array(TMP, true),
'adapterClass' => '\Gaufrette\Adapter\Local',
'class' => '\Gaufrette\Filesystem'));
要使用先前设置的配置调用新实例,请
$Adapter = StorageManager::adapter('Local');
您也可以这样调用适配器实例的方法
StorageManager::adapter('Local')->write($key, $data);
或者,您可以将配置数组作为第一个参数传递,以使用这些设置获取实例,这些设置不在配置中。
要删除配置以及由此产生的 StorageManager 中的实例,请调用
StorageManager::flush('Local');
如果您想清除 所有 适配器配置和实例,只需不带第一个参数调用它。
如何存储上传的文件
此插件的基本思想是文件始终作为独立的实体处理,并与其他模型相关联。
例如,假设您有一个 Report 模型,并希望保存一个 pdf,您将创建一个类似这样的关联
public $hasOne = array(
'PdfFile' => array(
'className' => 'FileStorage.FileStorage',
'foreignKey' => 'foreign_key'));
在添加/编辑报告时,您将拥有类似的内容
echo $this->Form->input('Report.title');
echo $this->Form->input('PdfFile.file');
echo $this->Form->input('Report.description');
现在,整个实现的要点来了
由于存在太多的不同需求和个人偏好,该插件 不会 自动存储文件。您需要稍作自定义,但这只需要几行代码。
让我们以 report 模型中的此场景为例,假设有一个 add() 方法
$this->create();
if ($this->save($data)) {
$key = 'your-file-name';
if (StorageManager::adapter('Local')->write($key, file_get_contents($this->data['PdfFile']['file']['tmp_name']))) {
$this->data['PdfFile']['foreign_key'] = $this->getLastInsertId();
$this->data['PdfFile']['model'] = 'Report';
$this->data['PdfFile']['path'] = $key;
$this->data['PdfFile']['adapter'] = 'Local';
}
}
稍后,当您想要删除文件时,例如在Report模型的beforeDelete()或afterDelete()回调中,您将知道您所使用的适配器来存储附加的PdfFile,并可以使用StorageManager获取此适配器配置的实例。通过拥有路径或密钥,您可以简单地调用
StorageManager::adapter($data['PdfFile']['adapter'])->delete($data['PdfFile']['path']);
您也可以直接扩展插件中的FileStorage模型,并在那里添加您的存储逻辑,然后使用该模型进行关联,而不是在具有文件关联的模型中进行所有这些操作。
如何存储上传的文件 II - 使用事件
该插件包含一个类,充当该插件中一些事件的监听器。请参阅Filestorage/Event/LocalImageProcessingLister.php
此类将监听所有ImageStorage事件,保存上传的图像,然后为该图像和存储适配器创建版本。
理解这一点很重要,每个存储适配器都需要不同的处理。您不能将本地文件和存储在云服务中的文件同等对待。此插件和Gaufrette提供的接口是相同的,但内部结构不同。
因此,如果您想使用Amazon S3存储文件,您必须在本地存储该文件的所有版本,然后上传每个版本,最后删除本地临时文件。
当您创建一个新的监听器时,您需要检查模型字段和事件主题对象,看它是否与您预期的相符。使用事件系统,您可以在不继承或修改模型代码的情况下创建任何类型的存储和上传行为。只需编写一个监听器类并将其附加到全局CakeEventManager。
事件列表
- ImageVersion.createVersion
- ImageVersion.removeVersion
- ImageStorage.beforeSave
- ImageStorage.afterSave
- ImageStorage.beforeDelete
- ImageStorage.afterDelete
- FileStorage.beforeSave
- FileStorage.afterSave
- FileStorage.afterDelete
为什么这样做?
因为每个开发人员可能希望在文件存储的不同点进行存储或在其存储前后对文件执行其他操作。根据不同的环境,您可能希望在将记录附加到记录之前就保存关联的文件,在诸如本说明中的其他场景中,您可能希望在之后进行操作。
这里的$key也是一个关键方面:不同的适配器可能期望不同的密钥。Gaufrette的本地适配器的密钥通常是存储数据下的路径和文件名。这也是为什么您使用file_get_contents()而不是简单地传递临时路径的原因。
如何生成密钥和构建路径取决于您。
我建议您阅读Gaufrette文档中的适配器的read()和write()方法。
图像版本化
您可以设置FileStorage.Image模型的自动图像处理。要使魔法发生,您必须使用Image模型(它扩展了FileStorage模型)来保存图像文件。
您需要做的只是基本上使用图像模型并在每个模型的基础上配置版本。当您保存Image模型记录时,重要的是要填写'model'字段,以便脚本可以找到该模型的正确版本。
Configure::write('Media', array(
'imageSizes' => array(
'GalleryImage' => array(
'c50' => array(
'crop' => array(
'width' => 50, 'height' => 50)),
't120' => array(
'thumbnail' => array(
'width' => 120, 'height' => 120)),
't800' => array(
'thumbnail' => array(
'width' => 800, 'height' => 600))),
'User' => array(
'c50' => array(
'crop' => array(
'width' => 50, 'height' => 50)),
't150' => array(
'crop' => array(
'width' => 150, 'height' => 150))),
)
)
);
App::uses('ClassRegistry', 'Utility');
ClassRegistry::init('FileStorage.Image')->generateHashes();
调用generateHashes很重要,它将为每个版本化图像创建哈希值,并将它们存储在配置中的Media.imageHashes中。
如果您不希望在每次脚本执行时都生成哈希值,那么您可以选择持久化存储它。此插件只是提供了工具。
图像文件将存储在您配置的基本路径中
/ModelName/51/21/63/4c0f128f91fc48749662761d407888cc/4c0f128f91fc48749662761d407888cc.jpg
版本化的图像文件将位于与原始图像相同的文件夹中,该文件夹是记录的id,版本哈希截断附加在扩展名之前。
/ModelName/51/21/63/4c0f128f91fc48749662761d407888cc/4c0f128f91fc48749662761d407888cc.f91fsc.jpg
您应该将图像根文件夹smylink到APP/webroot/images,例如,以避免图像通过php直接发送。
扩展和更改图像版本化
可以完全改变创建图像版本的方式。
支持
有关支持和功能请求,请访问FileStorage问题页面
https://github.com/burzum/FileStorage/issues
贡献
请向devevelop分支发送pull请求。
许可证
版权所有2012,Florian Krämer
许可协议为MIT许可证。文件分发必须保留上述版权声明。
致谢
感谢Larry Masters和CakeDC给我与优秀团队合作的机会,以及Jitka Koukalová在编程相关问题上的卓越建议,几年前她给我提供了一些建议。你们让我成为了一名更好的程序员! :)