ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 文件上传 本篇主要介绍如何使用`ThinkPHP5`进行文件上传及验证。 - - [控制器定义](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/179236#u63A7u5236u5668u5B9Au4E49) - [上传文件验证](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/179236#u4E0Au4F20u6587u4EF6u9A8Cu8BC1) - [文件保存规则](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/179236#u6587u4EF6u4FDDu5B58u89C4u5219) - [多文件上传](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/179236#u591Au6587u4EF6u4E0Au4F20) - [后续文件操作](http://ihavenolimitations.xyz/thinkphp/thinkphp5_quickstart/179236#u540Eu7EEDu6587u4EF6u64CDu4F5C) ## 控制器定义 > 文件上传使用ThinkPHP5内置的`think\File`类库,该类库可以轻松实现文件上传到本地服务器,如果需要上传到其它服务器或者平台,则需要后续调用其它类库或者接口。 首先来创建一个Upload控制器如下: ``` <pre class="calibre18"> ``` <span class="hljs-operator"><span class="hljs-number"><?php</span><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\<span class="hljs-title">index</span>\<span class="hljs-title">controller</span>; <span class="hljs-keyword">use</span> <span class="hljs-title">think</span>\<span class="hljs-title">Request</span>; <span class="hljs-operator"><span class="hljs-keyword">class</span> <span class="hljs-title">Upload</span> <span class="hljs-keyword">extends</span> \<span class="hljs-title">think</span>\<span class="hljs-title">Controller</span></span>{ <span class="hljs-comment">// 文件上传表单</span><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-number">()</span></span>{ <span class="hljs-keyword">return</span> <span class="hljs-regexp">$this</span>->fetch(); } <span class="hljs-comment">// 文件上传提交</span><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-number">(Request <span class="hljs-regexp">$request</span>)</span></span>{ <span class="hljs-comment">// 获取表单上传文件</span><span class="hljs-regexp">$file</span> = <span class="hljs-regexp">$request</span>->file(<span class="hljs-string">'file'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>(<span class="hljs-regexp">$file</span>)) { <span class="hljs-regexp">$this</span>->error(<span class="hljs-string">'请选择上传文件'</span>); } <span class="hljs-comment">// 移动到框架应用根目录/public/uploads/ 目录下</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-regexp">$info</span>) { <span class="hljs-regexp">$this</span>->success(<span class="hljs-string">'文件上传成功:'</span> . <span class="hljs-regexp">$info</span>->getRealPath()); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 上传失败获取错误信息</span><span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } } }</span> ``` ``` 然后创建模板文件(`application/index/view/upload/index.html`): ``` <pre class="calibre18"> ``` <span class="hljs-regexp"><!doctype html></span><span class="hljs-regexp"><<span class="hljs-operator">html</span>></span><span class="hljs-regexp"><<span class="hljs-operator">head</span>></span><span class="hljs-regexp"><<span class="hljs-operator">meta</span> <span class="hljs-operator">charset</span>=<span class="hljs-string">"UTF-8"</span>></span><span class="hljs-regexp"><<span class="hljs-operator">title</span>></span>文件上传示例<span class="hljs-regexp"></<span class="hljs-operator">title</span>></span><span class="hljs-regexp"><<span class="hljs-operator">style</span>></span><span class="css"><span class="hljs-regexp">body</span> <span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">font-family</span>:<span class="hljs-string"><span class="hljs-operator">"Microsoft Yahei"</span>,<span class="hljs-operator">"Helvetica Neue"</span>,Helvetica,Arial,sans-serif</span></span>; <span class="hljs-operator"><span class="hljs-title1">font-size</span>:<span class="hljs-string"><span class="hljs-number">16px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"><span class="hljs-number">5px</span></span></span>; }</span><span class="hljs-regexp">.form</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">15px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">font-size</span>:<span class="hljs-string"> <span class="hljs-number">16px</span></span></span>; }</span><span class="hljs-regexp">.form</span> <span class="hljs-regexp">.text</span> <span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">3px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">margin</span>:<span class="hljs-string"><span class="hljs-number">2px</span> <span class="hljs-number">10px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">width</span>:<span class="hljs-string"> <span class="hljs-number">240px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">height</span>:<span class="hljs-string"> <span class="hljs-number">24px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">line-height</span>:<span class="hljs-string"> <span class="hljs-number">28px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">border</span>:<span class="hljs-string"> <span class="hljs-number">1px</span> solid <span class="hljs-title">#D4D4D4</span></span></span>; }</span><span class="hljs-regexp">.form</span> <span class="hljs-regexp">.btn</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">margin</span>:<span class="hljs-string"><span class="hljs-number">6px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">6px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">width</span>:<span class="hljs-string"> <span class="hljs-number">120px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">font-size</span>:<span class="hljs-string"> <span class="hljs-number">16px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">border</span>:<span class="hljs-string"> <span class="hljs-number">1px</span> solid <span class="hljs-title">#D4D4D4</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">cursor</span>:<span class="hljs-string"> pointer</span></span>; <span class="hljs-operator"><span class="hljs-title1">background</span>:<span class="hljs-string"><span class="hljs-title">#eee</span></span></span>; }</span><span class="hljs-regexp">.form</span> <span class="hljs-regexp">.file</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">margin</span>:<span class="hljs-string"><span class="hljs-number">6px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">6px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">width</span>:<span class="hljs-string"> <span class="hljs-number">220px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">font-size</span>:<span class="hljs-string"> <span class="hljs-number">16px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">border</span>:<span class="hljs-string"> <span class="hljs-number">1px</span> solid <span class="hljs-title">#D4D4D4</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">cursor</span>:<span class="hljs-string"> pointer</span></span>; <span class="hljs-operator"><span class="hljs-title1">background</span>:<span class="hljs-string"><span class="hljs-title">#eee</span></span></span>; }</span><span class="hljs-regexp">a</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">color</span>:<span class="hljs-string"> <span class="hljs-title">#868686</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">cursor</span>:<span class="hljs-string"> pointer</span></span>; }</span><span class="hljs-operator"><span class="hljs-title1">a</span>:<span class="hljs-string">hover{ text-decoration: underline</span></span>; } <span class="hljs-regexp">h2</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">color</span>:<span class="hljs-string"> <span class="hljs-title">#4288ce</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">font-weight</span>:<span class="hljs-string"> <span class="hljs-number">400</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">6px</span> <span class="hljs-number">0</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">margin</span>:<span class="hljs-string"> <span class="hljs-number">6px</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">font-size</span>:<span class="hljs-string"> <span class="hljs-number">28px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">border-bottom</span>:<span class="hljs-string"> <span class="hljs-number">1px</span> solid <span class="hljs-title">#eee</span></span></span>; }</span><span class="hljs-regexp">div</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">margin</span>:<span class="hljs-string"><span class="hljs-number">8px</span></span></span>; }</span><span class="hljs-regexp">.info</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">12px</span> <span class="hljs-number">0</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">border-bottom</span>:<span class="hljs-string"> <span class="hljs-number">1px</span> solid <span class="hljs-title">#eee</span></span></span>; }</span><span class="hljs-regexp">.copyright</span><span class="hljs-operator">{ <span class="hljs-operator"><span class="hljs-title1">margin-top</span>:<span class="hljs-string"> <span class="hljs-number">24px</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">padding</span>:<span class="hljs-string"> <span class="hljs-number">12px</span> <span class="hljs-number">0</span></span></span>; <span class="hljs-operator"><span class="hljs-title1">border-top</span>:<span class="hljs-string"> <span class="hljs-number">1px</span> solid <span class="hljs-title">#eee</span></span></span>; }</span></span><span class="hljs-regexp"></<span class="hljs-operator">style</span>></span><span class="hljs-regexp"></<span class="hljs-operator">head</span>></span><span class="hljs-regexp"><<span class="hljs-operator">body</span>></span><span class="hljs-regexp"><<span class="hljs-operator">h2</span>></span>文件上传示例<span class="hljs-regexp"></<span class="hljs-operator">h2</span>></span><span class="hljs-regexp"><<span class="hljs-operator">FORM</span> <span class="hljs-operator">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-operator">enctype</span>=<span class="hljs-string">"multipart/form-data"</span> <span class="hljs-operator">class</span>=<span class="hljs-string">"form"</span> <span class="hljs-operator">action</span>=<span class="hljs-string">"{:url('up')}"</span>></span> 选择文件:<span class="hljs-regexp"><<span class="hljs-operator">INPUT</span> <span class="hljs-operator">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-operator">class</span>=<span class="hljs-string">"file"</span> <span class="hljs-operator">name</span>=<span class="hljs-string">"file"</span>></span><span class="hljs-regexp"><<span class="hljs-operator">br</span>/></span><span class="hljs-regexp"><<span class="hljs-operator">INPUT</span> <span class="hljs-operator">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-operator">class</span>=<span class="hljs-string">"btn"</span> <span class="hljs-operator">value</span>=<span class="hljs-string">" 提交 "</span>></span><span class="hljs-regexp"></<span class="hljs-operator">FORM</span>></span><span class="hljs-regexp"><<span class="hljs-operator">div</span> <span class="hljs-operator">class</span>=<span class="hljs-string">"copyright"</span>></span><span class="hljs-regexp"><<span class="hljs-operator">a</span> <span class="hljs-operator">title</span>=<span class="hljs-string">"官方网站"</span> <span class="hljs-operator">href</span>=<span class="hljs-string">"http://www.thinkphp.cn"</span>></span>ThinkPHP<span class="hljs-regexp"></<span class="hljs-operator">a</span>></span><span class="hljs-regexp"><<span class="hljs-operator">span</span>></span>V5<span class="hljs-regexp"></<span class="hljs-operator">span</span>></span><span class="hljs-regexp"><<span class="hljs-operator">span</span>></span>{ 十年磨一剑-为API开发设计的高性能框架 }<span class="hljs-regexp"></<span class="hljs-operator">span</span>></span><span class="hljs-regexp"></<span class="hljs-operator">div</span>></span><span class="hljs-regexp"></<span class="hljs-operator">body</span>></span><span class="hljs-regexp"></<span class="hljs-operator">html</span>></span> ``` ``` 访问下面的URL地址: ``` <pre class="calibre18"> ``` <span class="hljs-string">http:</span> <span class="hljs-comment">//tp5.com/index/upload</span> ``` ``` ![](https://img.kancloud.cn/ce/31/ce3161d1487d32532cff6af5505f3e1e_766x368.png) 如果没有选择任何文件点击提交的话,会显示: ![](https://img.kancloud.cn/23/fc/23fcea7b9f7a8b6fa836daebd8d36fc8_652x344.png) 选择文件后点击提交: ![](https://img.kancloud.cn/ed/82/ed82d381fdac150a1ca1710849d9777c_755x368.png) ![](https://img.kancloud.cn/0c/5d/0c5d787b74b375a9ee5e4a2d55e9e247_2110x443.png) 默认的上传文件会按照当前的日期自动保存 ## 上传文件验证 可以在上传之前调用`validate`方法设置验证规则,例如: ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 文件上传提交</span><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-number">(Request <span class="hljs-regexp">$request</span>)</span></span>{ <span class="hljs-comment">// 获取表单上传文件</span><span class="hljs-regexp">$file</span> = <span class="hljs-regexp">$request</span>->file(<span class="hljs-string">'file'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>(<span class="hljs-regexp">$file</span>)) { <span class="hljs-regexp">$this</span>->error(<span class="hljs-string">'请选择上传文件'</span>); } <span class="hljs-comment">// 移动到框架应用根目录/public/uploads/ 目录下</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->validate([<span class="hljs-string">'ext'</span> => <span class="hljs-string">'jpg,png'</span>])->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-regexp">$info</span>) { <span class="hljs-regexp">$this</span>->success(<span class="hljs-string">'文件上传成功:'</span> . <span class="hljs-regexp">$info</span>->getRealPath()); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 上传失败获取错误信息</span><span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } } ``` ``` `validate`方法设置了允许上传的文件后缀是jpg和png,当我们选择一个gif格式的文件后,会提示: ![](https://img.kancloud.cn/71/fd/71fdbee2d76ecc099f509da23f5cb479_664x346.png) `validate`方法支持的验证规则包括: 验证规则 说明 参数类型 size 上传文件最大字节大小 integer ext 允许上传的文件后缀 数组或者字符串 type 允许上传的文件类型 数组或者字符串如果上传的文件后缀是图像格式的话,系统会自动检测是否为合法的图像文件,例如,我们创建一个hello.jpg文件,并且写入下列文本内容 ``` <pre class="calibre18"> ``` Hello,ThinkPHP5! ``` ``` 当我们上传该文件并且提交后显示: ![](https://img.kancloud.cn/e4/2c/e42c1280e5428ae518a6a487133632b7_687x336.png) > 注意:文件上传验证用到了`exif`扩展,如果没有开启请自行开启。 如果你统一使用验证类`think\Validate`对表单进行验证,也可以直接使用控制器类`think\Controller`的`validate`方法进行上传文件验证,修改控制器up方法的代码为: ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 文件上传提交</span><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-number">(Request <span class="hljs-regexp">$request</span>)</span></span>{ <span class="hljs-comment">// 获取表单上传文件</span><span class="hljs-regexp">$file</span> = <span class="hljs-regexp">$request</span>->file(<span class="hljs-string">'file'</span>); <span class="hljs-comment">// 上传文件验证</span><span class="hljs-regexp">$result</span> = <span class="hljs-regexp">$this</span>->validate([<span class="hljs-string">'file'</span> => <span class="hljs-regexp">$file</span>], [<span class="hljs-string">'file'</span>=><span class="hljs-string">'require|image'</span>],[<span class="hljs-string">'file.require'</span> => <span class="hljs-string">'请选择上传文件'</span>, <span class="hljs-string">'file.image'</span> => <span class="hljs-string">'非法图像文件'</span>]); <span class="hljs-keyword">if</span>(<span class="hljs-keyword">true</span> !== <span class="hljs-regexp">$result</span>){ <span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$result</span>); } <span class="hljs-comment">// 移动到框架应用根目录/public/uploads/ 目录下</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-regexp">$info</span>) { <span class="hljs-regexp">$this</span>->success(<span class="hljs-string">'文件上传成功:'</span> . <span class="hljs-regexp">$info</span>->getRealPath()); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 上传失败获取错误信息</span><span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } } ``` ``` 关键的代码是这行: ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 上传文件验证</span><span class="hljs-regexp">$result</span> = <span class="hljs-regexp">$this</span>->validate([<span class="hljs-string">'file'</span> => <span class="hljs-regexp">$file</span>], [<span class="hljs-string">'file'</span>=><span class="hljs-string">'require|image'</span>],[<span class="hljs-string">'file.require'</span> => <span class="hljs-string">'请选择上传文件'</span>, <span class="hljs-string">'file.image'</span> => <span class="hljs-string">'非法图像文件'</span>]); ``` ``` 由于设置了`require`验证规则(表示必须上传文件),所以如果没有选择任何文件直接提交的话,页面会提示: ![](https://img.kancloud.cn/23/fc/23fcea7b9f7a8b6fa836daebd8d36fc8_652x344.png) `image`验证规则表示上传的必须是一个图像文件,如果选择上传了一个文本文件,页面会提示: ![](https://img.kancloud.cn/e4/2c/e42c1280e5428ae518a6a487133632b7_687x336.png) 如果需要上传一个100\*100的`PNG`图像文件,可以这样进行验证: ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 上传文件验证</span><span class="hljs-regexp">$result</span> = <span class="hljs-regexp">$this</span>->validate([<span class="hljs-string">'file'</span> => <span class="hljs-regexp">$file</span>], [<span class="hljs-string">'file'</span>=><span class="hljs-string">'require|image:100,100,png'</span>],[<span class="hljs-string">'file.require'</span> => <span class="hljs-string">'请选择上传文件'</span>, <span class="hljs-string">'file.image'</span> => <span class="hljs-string">'必须是100*100的PNG格式文件'</span>]); ``` ``` 更多的上传文件验证规则还包括: 验证规则 说明 file 验证是否为File对象 image 验证是否为图像File对象 image:width,height\[,type\] 验证图像文件的类型和宽高 fileExt:zip,doc,... 验证文件后缀 fileMime:image/png,... 验证文件类型 fileSize:1024 验证文件大小## 文件保存规则 可以在上传之前调用`rule`方法设置上传文件的保存规则。 ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 文件上传提交</span><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-number">(Request <span class="hljs-regexp">$request</span>)</span></span>{ <span class="hljs-comment">// 获取表单上传文件</span><span class="hljs-regexp">$file</span> = <span class="hljs-regexp">$request</span>->file(<span class="hljs-string">'file'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-keyword">empty</span>(<span class="hljs-regexp">$file</span>)) { <span class="hljs-regexp">$this</span>->error(<span class="hljs-string">'请选择上传文件'</span>); } <span class="hljs-comment">// 移动到框架应用根目录/public/uploads/ 目录下</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->rule(<span class="hljs-string">'md5'</span>)->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-regexp">$info</span>) { <span class="hljs-regexp">$this</span>->success(<span class="hljs-string">'文件上传成功:'</span> . <span class="hljs-regexp">$info</span>->getRealPath()); } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 上传失败获取错误信息</span><span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } } ``` ``` ![](https://img.kancloud.cn/d7/73/d773392e52c76e74a8f84c496c9bf00b_1878x449.png) 系统默认提供了几种上传命名规则,包括: 规则 描述 date 根据日期和微秒数生成(默认规则) md5 对文件使用md5\_file散列生成 sha1 对文件使用sha1\_file散列生成> 其中md5和sha1规则会自动以散列值的前两个字符作为子目录,后面的散列值作为文件名。 如果需要自定义上传文件的保存规则,可以使用: ``` <pre class="calibre18"> ``` /<span class="hljs-regexp">/ 移动到框架应用根目录/public</span><span class="hljs-regexp">/uploads/</span> 目录下 <span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->rule(<span class="hljs-string">'uniqid'</span>)->move(<span class="hljs-number">ROOT_PATH </span>. <span class="hljs-string">'public'</span> . <span class="hljs-number">DS </span>. <span class="hljs-string">'uploads'</span>); ``` ``` 这里使用了`uniqid`函数来生成唯一的ID命名上传文件,如果必要,还可以支持使用闭包定义规则,例如: ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 移动到框架应用根目录/public/uploads/ 目录下</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->rule(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-number">(<span class="hljs-regexp">$file</span>)</span> </span>{ <span class="hljs-comment">// 使用自定义的文件保存规则</span><span class="hljs-keyword">return</span> <span class="hljs-regexp">$file</span>->getInfo(<span class="hljs-string">'type'</span>) . uniqid(); })->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); ``` ``` ![](https://img.kancloud.cn/2c/03/2c0365dfb97675352192f3bd8c583e54_1966x346.png) 如果希望指定某个文件的保存文件名,还可以直接使用: ``` <pre class="calibre18"> ``` /<span class="hljs-regexp">/ 移动到框架应用根目录/public</span><span class="hljs-regexp">/uploads/</span> 目录下 <span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->move(<span class="hljs-number">ROOT_PATH </span>. <span class="hljs-string">'public'</span> . <span class="hljs-number">DS </span>. <span class="hljs-string">'uploads'</span>,<span class="hljs-string">'test'</span>); ``` ``` ![](https://img.kancloud.cn/79/da/79daee05a518766867466711b9c4f5e9_1369x353.png) 如果希望保持上传文件的原文件名保存,则可以使用 ``` <pre class="calibre18"> ``` /<span class="hljs-regexp">/ 移动到框架应用根目录/public</span><span class="hljs-regexp">/uploads/</span> 目录下 <span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->move(<span class="hljs-number">ROOT_PATH </span>. <span class="hljs-string">'public'</span> . <span class="hljs-number">DS </span>. <span class="hljs-string">'uploads'</span>,<span class="hljs-string">''</span>); ``` ``` 默认情况下,会覆盖服务器上传目录下的同名文件,如果不希望覆盖,可以使用: ``` <pre class="calibre18"> ``` <span class="hljs-comment">// 移动到服务器的上传目录 并且设置不覆盖</span><span class="hljs-regexp">$file</span>->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>,<span class="hljs-keyword">true</span>,<span class="hljs-keyword">false</span>); ``` ``` 如果要获取上传的保存文件名,可以调用返回对象的`getSaveName`方法: ``` <pre class="calibre18"> ``` <span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->rule(<span class="hljs-string">'md5'</span>)->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-regexp">$info</span>) { <span class="hljs-keyword">echo</span> <span class="hljs-regexp">$info</span>->getSaveName(); } <span class="hljs-keyword">else</span> { <span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } ``` ``` ## 多文件上传 如果你使用的是多文件上传表单,例如: ``` <pre class="calibre18"> ``` <<span class="hljs-operator">FORM</span> method=<span class="hljs-string">"post"</span> enctype=<span class="hljs-string">"multipart/form-data"</span> <span class="hljs-operator"><span class="hljs-keyword">class</span>=</span><span class="hljs-string">"form"</span> action=<span class="hljs-string">"{:url('up')}"</span>> <input <span class="hljs-operator"><span class="hljs-keyword">type</span>=</span><span class="hljs-string">"file"</span> name=<span class="hljs-string">"image[]"</span> /> <br> <input <span class="hljs-operator"><span class="hljs-keyword">type</span>=</span><span class="hljs-string">"file"</span> name=<span class="hljs-string">"image[]"</span> /> <br> <input <span class="hljs-operator"><span class="hljs-keyword">type</span>=</span><span class="hljs-string">"file"</span> name=<span class="hljs-string">"image[]"</span> /> <br> <<span class="hljs-operator">INPUT</span> <span class="hljs-operator"><span class="hljs-keyword">type</span>=</span><span class="hljs-string">"submit"</span> <span class="hljs-operator"><span class="hljs-keyword">class</span>=</span><span class="hljs-string">"btn"</span> value=<span class="hljs-string">" 提交 "</span>> </<span class="hljs-operator">FORM</span>> ``` ``` 控制器代码可以改成: ``` <pre class="calibre18"> ``` <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-number">(Request <span class="hljs-regexp">$request</span>)</span></span>{ <span class="hljs-comment">// 获取表单上传文件</span><span class="hljs-regexp">$files</span> = <span class="hljs-regexp">$request</span>->file(<span class="hljs-string">'image'</span>); <span class="hljs-regexp">$item</span> = []; <span class="hljs-keyword">foreach</span>(<span class="hljs-regexp">$files</span> <span class="hljs-keyword">as</span> <span class="hljs-regexp">$file</span>){ <span class="hljs-comment">// 移动到框架应用根目录/public/uploads/ 目录下</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span>(<span class="hljs-regexp">$info</span>){ <span class="hljs-regexp">$item</span>[] = <span class="hljs-regexp">$info</span>->getRealPath(); }<span class="hljs-keyword">else</span>{ <span class="hljs-comment">// 上传失败获取错误信息</span><span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } } <span class="hljs-regexp">$this</span>->success(<span class="hljs-string">'文件上传成功'</span>.implode(<span class="hljs-string">'<br/>'</span>,<span class="hljs-regexp">$item</span>)); } ``` ``` ## 后续文件操作 上传成功后返回的是`File`对象,除了可以使用`SplFileObject`的属性和方法之外,还可以使用File类自身提供的下列方法,便于进行后续的文件处理(例如对图像文件进行剪裁处理或者移动到远程服务器)。 方法 描述 getSaveName 获取保存的文件名(包含动态生成的目录) getInfo 获取上传文件信息 getMime 获取文件的MIME信息 md5 获取文件的md5散列值 sha1 获取文件的sha1散列值下面是一个简单的FTP文件移动的处理例子。 ``` <pre class="calibre18"> ``` <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">up</span><span class="hljs-number">(Request <span class="hljs-regexp">$request</span>)</span></span>{ <span class="hljs-comment">// 获取表单上传文件</span><span class="hljs-regexp">$file</span> = <span class="hljs-regexp">$request</span>->file(<span class="hljs-string">'file'</span>); <span class="hljs-comment">// 上传文件</span><span class="hljs-regexp">$info</span> = <span class="hljs-regexp">$file</span>->move(ROOT_PATH . <span class="hljs-string">'public'</span> . DS . <span class="hljs-string">'uploads'</span>); <span class="hljs-keyword">if</span> (<span class="hljs-regexp">$info</span>) { <span class="hljs-comment">// 移动文件到FTP服务器</span><span class="hljs-regexp">$link</span> = ftp_connect(<span class="hljs-string">'212.45.5.78'</span>); ftp_login(<span class="hljs-regexp">$link</span>, <span class="hljs-string">'root'</span>, <span class="hljs-string">'password'</span>); <span class="hljs-comment">/* 移动文件 */</span><span class="hljs-regexp">$path</span> = ftp_pwd(<span class="hljs-regexp">$link</span>) . <span class="hljs-string">'/uploads/'</span>; <span class="hljs-keyword">if</span> (!ftp_put(<span class="hljs-regexp">$link</span>, <span class="hljs-regexp">$path</span>.<span class="hljs-regexp">$info</span>->getFilename(), <span class="hljs-regexp">$info</span>->getRealPath(), FTP_BINARY)) { <span class="hljs-regexp">$this</span>->error(<span class="hljs-string">'文件上传保存错误!'</span>); } } <span class="hljs-keyword">else</span> { <span class="hljs-comment">// 上传失败获取错误信息</span><span class="hljs-regexp">$this</span>->error(<span class="hljs-regexp">$file</span>->getError()); } } ``` ``` 还可以对上传的文件进行处理,后面我们还会讲到对上传图像文件进行额外的图像处理。