关于如何使用fuelphp文件上传的备注
你好。
我是Mandai,负责Wild 开发团队。
使用 Fuelphp 简单地上传文件非常简单,如果您从文档中复制并粘贴代码,那么它基本上就可以工作。
不过有很多东西不知道怎么做,所以总结了一下。
准备文件上传(HTML + CSS + JS)
在实现文件上传之前,需要准备好HTML等前端材料。
让我们从 HTML 开始。
它是表单标签内的输入标签。
<form id="form" name="form" method="post" enctype="multipart/form-data"><input type="file" name="f" class="hidden" id="f" multiple="multiple"><label for="f"><span class="btn">文件选择</span><span class="selected" id="f_selected">未选择</span></label></form>
接下来,CSS。
input.hidden { /* 显示:无;*/ } 标签 > span.btn { 显示:内联块;边框:1px 实心 #999; 字体:13.333px 行高:21px;左:0.25em;右内边距:0.25em;背景:-webkit-线性渐变(#fcfcfc,#dcdcdc);背景:线性渐变(#fcfcfc,#dcdcdc); span.btn:active { 背景:-webkit-线性渐变(#dcdcdc, #fcfcfc); 背景:线性渐变(#dcdcdc, #fcfcfc); } 标签 > span.btn:hover { 边框: 1px 实心 #666 ; } 标签 > span.selected { 显示:内联块; 字体:13.333px; 行高:21px; } 标签 { -moz-user-select:无; ; -webkit-用户选择:无;
最后但并非最不重要的是 JavaScript。
(function(){ var f = document.getElementById('f'); var label_selected = document.getElementById(f.id + '_selected'); f.addEventListener('change', function(){ if (f.files .length == 0){ label_selected.textContent = '未选择'; } else if (f.files.length == 1){ label_selected.textContent = f.files[0].name } else { label_selected .textContent = f.files.length + '文件' } });
当您在浏览器中显示它时,它看起来如下所示。推荐使用Chrome。
当你看到它的时候,原因就很明显了。
有两个文件上传按钮。
按任一按钮都会起作用。
左边的是实际产品,右边的是使用标签标签的复制品。
我只是想这么做。
表单部分在浏览器之间的显示不同,而且我还想让文件上传按钮本身符合设计,所以这个技巧很有用。
使用 CSS + JS 大致匹配行为和外观,这次我使它类似于 chrome 表单组件。
如果您将“display: none”添加到 CSS 中的输入标记中,它的行为与普通表单没有什么不同。
(已注释掉)
重要的是不要忘记表单标记中的 enctype 属性。
至此,前期准备工作已经完成。
Fuelphp的实现(准备)
在实施之前,我们将进行各种设置并准备模型。
由于 Fuelphp 是配置优先的,因此可以通过配置文件极大地改变其行为。
首先,在上传时,准备一个用于上传的配置文件。
源配置文件位于“fuel/core/config/upload.php”中,因此将其复制到“fuel/app/config”下并更改设置。
需要设置的项目是path。
至于保存目的地,如果将其设置为公共,下载机制会更容易,但如果您知道带有个人信息的PDF的URL,则可以随意下载,因此最好设置它低于公众。
如果需要控制访问,请创建并指定一个目录,例如公共层次结构中的文件。
在这种情况下,将无法从外部访问它,并且您将无法下载它,因此您会担心开销,但您可以通过创建单独的控制器来创建下载 URL 来处理此问题。
这部分和文件上传有点不同,所以我想下次再写。
这次,创建一个与public同级的files目录(直接在项目根目录下)并保存文件。
另外,对于要保存的文件名,我在配置文件中将 randomize 设置为 true 并使用 32 个字符的 MD5 哈希值。
修改后的 config/upload.php 现在如下所示。
return array( 'path' => '/var/www/html/test/files', 'randomize' => true, );
接下来,创建模型。
由于要保存的文件名加上了哈希值,原来的文件名已经不知道了,所以它的主要作用就是保存。
创建上传表进行存储的SQL语句如下。
创建表 `uploads` (`id` int(11) unsigned NOT NULL AUTO_INCRMENT、`origin_name` varchar(256) NOT NULL、`file_name` varchar(256) NOT NULL、`created_at` 时间戳不为 NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `updated_at` 时间戳 NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`), KEY `idx_file_name` (`file_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
执行此 SQL 后,最快的方法是使用 oil 命令创建模型,如下所示。
php /path/to/oil r fromdb:模型上传
另外,由于我们将使用 ORM 包,因此我们需要修改 config.php 中的always_load 项。
如果取消注释包部分,它将自动加载。
Fuelphp(控制器)的实现
我们将在发布数据时实现控制器的行为。
现在控制器中编写的源代码如下。
function post_index() { $data = []; $this->template->title = 'test'; /* * 随机化处理后的文件名如下 * [0-9a-f] { 32}.[ext] * 由于原始文件名将保存在单独的字段中,因此我们将介绍一个在保存之前将文件名更改为仅哈希值的过程 */ Upload::register('before', function( &$ file) { $file['filename'] = substr($file['filename'], 0, 32); $file['path'] .= $file['filename'][0]. '. $file['文件名'][1]. }); if (Upload::is_valid()) { 上传::save(); foreach (Upload::get_files() as $file) { Model_Upload: :add($file); } } foreach (Upload::get_errors() as $file) { // 错误处理 } $this->template->content = View::forge('upload/index', $数据) ; }
如果在config中的upload.php中将“auto_process”设置为true(默认),则不需要显式编写Upload::process()。
文档,如果在 'auto_process' => true 时执行 Upload::process(),Upload::process() 将执行两次。
您可以使用 Upload::process() 覆盖配置,因此如果在多个位置描述文件上传过程,则最好将 auto_process 设置为 false 并每次执行 Upload::process() 。
Upload::register() 方法用于在保存文件之前中断处理。
第一个参数应该是“验证”、“之前”和“之后”之一。
这次我选择之前,因为我想在保存之前更改文件名和保存路径。
如果 config/upload.php 中的 randomize 设置为 true,则文件名将是 32 个字符的哈希值,但具有原始扩展名。
为了完全统一文件名为32个字符,我们添加了一个将文件名更改为哈希值的过程。
另外,关于保存目的地,使用哈希值的第一个和第二个字符创建目录并重置为路径。
如果上传的文件数量较少,这并不是特别必要,但如果上传的文件数量较多,或者存储了数万个文件,则读写响应会明显下降。
作为对此的回应,我们添加了处理以分配一个目录中的文件数量。
$file,它是Upload::register()中闭包中的一个参数,传递的是fuel/vendor/fuelphp/upload/src/File.php中编写的类,并且这个类似乎可以从外部访问。没办法做到这一点。
如果您在“之前”(保存之前)编辑此类,则可以操作保存路径和文件。
如果你转储 $file,它将包含如下内容:
Fuel\Upload\File::__set_state(array( 'container' => array ( 'element' => 'f', 'filename' => 'e9477391cbeefc40e69f7e1bc24868d2', 'name' => 'test.html', 'type' => 'text/html', 'tmp_name' => '/tmp/phpDsDmiL', '错误' => 0, '大小' => 335, '扩展名' => 'html', '基本名称' => '测试', 'mimetype' => 'text/html', 'path' => '/home/vagrant/workspace/test/files/e/9/', ), 'index' => 0, 'errors' => array ( ), 'config' => array ( 'langCallback' => '\\Upload::lang_callback', 'moveCallback' => NULL, 'max_size' => 0, 'max_length' => 0, 'ext_whitelist' = > array ( ), 'ext_blacklist' => 数组 ( ), 'type_whitelist' => 数组 ( ), 'type_blacklist' => 数组 ( ), 'mime_whitelist' => 数组 ( ), 'mime_blacklist' => 数组 ( ), “前缀”=>“”、“后缀”=>“”、“扩展名”=>“”、“随机化”=> true、“标准化”=> false、“normalize_separator”=>“_”、“change_case” =>假,“路径”=>“/var/www/html/test/files”,“create_path”=>真,“path_chmod”=>511,“file_chmod”=>438,“auto_rename”=>真, 'new_name' => false, 'overwrite' => false, ), 'isValidated' => true, 'isValid' => true, 'callbacks' => array ( 'before_validation' => array ( ), 'after_validation' = > array ( ), 'before_save' => array ( 0 => Closure::__set_state(array( )), ), 'after_save' => array ( ), ), ))
有点混乱,但是用Upload::get_files()获取的文件信息只是Fuel\Upload\File的容器部分,而不是上面的类。
另外,即使你改变了Upload::get_files()中的信息,实际的文件信息也无法改变,所以看来改变上传文件信息的唯一方法就是在before事件中。
该区域文档的注册方法部分中有详细介绍
就是这样。