ThinkPHP---TP功能类之上传
【一】概论
(1)上传操作的核心操作:移动临时文件(move_upload_file),在ThinkPHP里封装了上传类Upload.class.php
(2)上传类Upload.class.php代码分析,位置ThinkPHP/Library/Think/Upload.class.php
①上传配置信息
/**
* 默认上传配置
* @var array
*/
private $config = array(
//(text/html,image/jepg,image/png,image/gif,addType/Application.php为PHP文件类型。都相当于指定的文件格式)
'mimes' => array(), //允许上传的文件MiMe类型
//PHP默认2M
'maxSize' => 0, //上传的文件大小限制 (0-不做限制)
//比如文本格式.txt,PHP格式为.php等
'exts' => array(), //允许上传的文件后缀
//一般默认开启子目录,否则随着日期的增加。当前目录会越来越大,影响运行
'autoSub' => true, //自动子目录保存文件
//子目录创建方式--按照日期创建,所以同一天上传的文件会被放到同一个目录下
'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组
//相对于站点的根目录
'rootPath' => './Uploads/', //保存根路径
'savePath' => '', //保存路径
//重命名上传文件,uniqid为PHP内置语法(生成唯一ID)。这里也可以用md5加密
'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组
//一般不指定,保持原后缀。防止文件类型修改
'saveExt' => '', //文件保存后缀,空则使用原后缀
'replace' => false, //存在同名是否覆盖
//hash类似于md2(32位编码,可逆反向编码,所以不大安全了);
//hash(也叫sha1),40位编码
'hash' => true, //是否生成hash编码
'callback' => false, //检测文件是否存在回调,如果存在返回文件信息数组
//上传驱动有很多种:ftp(例如京东、百度等大型网站),网站和图片不在一个服务器,这时便用到了上传驱动
//ThinkPHP下有几类,ThinkPHP\Library\Think\Upload\Driver目录下:BCS、Ftp、Local、Qiniu、Sae、Upyun等
//新浪用的Sae,一般默认Local上传到本机
'driver' => '', // 文件上传驱动
'driverConfig' => array(), // 上传驱动配置
);
拓展:hash编码及应用
hash编码也叫sha1编码,为40位编码
由来:之前的md5编码为32位编码,在部分网站上已经可逆了。所以安全性上有缺陷,于是开发了更加安全的hash(sha1)编码。多了8位,所以在解码可逆步骤增加难度,自然也就更加安全
应用案例:QQ的快传和网盘,PHP的原生方法sha1_file计算文件的sha1散列值,生成的值
QQ快传和网盘快速上传文件的实现原理:
①扫描文件,生成文件编码。可能是sha1也可能是md5编码;
②拿到编码后去数据库找,看之前有没有记录。此时注意,只通过文件名是无法识别的,因为文件名可能有改动。所以只能通过md5编码或者sha1编码去找。若找到文件之前有记录,直接拿到记录文件名,然后将对方文件传上去。相当于复制一份发了过去,然后重命名文件。
因此今后欧判断文件是否一样,不能通过文件名来判断。而要通过文件结构来进行判断
②构造方法:可以在实例化时传递一个配置数组,然后在内部进行合并配置操作;
③GetError方法:获取最后一次的上传错误信息;
语法:$upload->getError();
注意:因为该方法是上传类里的方法,所以应该由实例化的类去执行。而不是$this
④uploadOne方法:上传单个文件,参数是$_FILES中的子元素,返回值是上传的结果。(成功返回具有9个元素一维数组,失败返回false)
/**
* 上传单个文件
* @param array $file 文件数组,通常是$_FILES中的子元素
* @return array 上传成功后的文件信息
*/
public function uploadOne($file){
$info = $this->upload(array($file));
return $info ? $info[0] : $info;
}
⑤upload方法:参数通常是$_FILES整个数组,成功返回值是二维数组,失败返回false
/**
* 上传文件
* @param 文件信息数组 $files ,通常是 $_FILES数组
*/
public function upload($files='') {...}
仔细查看代码后可以发现uploadOne方法其实也是调用了upload方法,完成单文件上传
⑥查看源码后发现上传错误,所以这里总结下上传错误0-7,注意没有5
0--------------没有错误,上传成功
1--------------上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值!
2--------------上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值!
3--------------文件只有部分被上传!
4--------------没有文件被上传!
6--------------找不到临时文件夹!
7--------------文件写入失败,没有写入权限!
⑦至于其他checkSize(检查文件大小)、checkMime(检查文件Mime类型)、checkExt(检查文件后缀)等方法均为私有方法,只能在内部封装调用
总结:分析后得出公开的方法一共有4个---①构造方法实例化、②GetError返回错误、③uploadOne上传单个文件、④upoad上传多个文件
【案例】实现公文里的附件上传
(1)注意:要满足以下几个条件
①表单属性必须有entype属性声明表单上传数据除了字符外,还含有二进制流数据---enctype="multipart/form-data"
②文件域type="file"
③提交方式必须是post
(2)修改add方法中的表单数据处理
为了符合MVC的设计规范,需要自定义一个模型,然后将文件上传和数据保存,在模型里封装一个方法。由这个方法执行数据的保存
(3)创建模型文件Model.class.php
<?php
namespace Admin\Model;
use Think\Model;
class DocModel extends Model{
}
?>
之所以创建模型是由于添加操作无法一步执行,因为需要对文件上传进行处理。而处理的部分最好不要放在控制器里,所以单独拿出来。
控制器里只负责接受数据和判断执行结果,具体的数据保存操作和处理有模型执行
(4)修改控制器方法,改为接收数据和判断执行结果。具体的数据保存造作放到模型里执行
①实例化自定义模型;②保存由模型处理
(5)编写方法实现数据的保存
方法名:saveData
<?php
namespace Admin\Model;
use Think\Model;
class DocModel extends Model{
//saveData方法实现数据保存
public function saveData($post,$file){
//处理提交
dump($file);die;
//补全addtime字段
$post['addtime']=time();
$result = $this->add($post);
}
}
?>
这里我先选择一张图片,点击上传,预览下输出的格式,浏览器输出如下(输出$_FILES['file'])
array(1) {
["filename"] => array(5) {
["name"] => string(6) "03.jpg"
["type"] => string(10) "image/jpeg" //MIME文件类型
["tmp_name"] => string(53) "C:\Users\Administrator\AppData\Local\Temp\phpA567.tmp" //临时文件,请求结束时便销毁了
["error"] => int(0)
["size"] => int(80669)
}
}
注意:
1. 关于路径的说明
定义配置,配置上传路径
①如果地址是给服务器脚本使用的,则可以使用相对于入口文件的相对路径;也可以使用带盘符的绝对路径
②如果地址是给客户端用的,则地址应该写成"/",相对于站点域名后的地址
在上传的案例中整个路径都不会传递给服务器,则路径属于第一种情况。在上传时保存路径建议写成带盘符的形式
2. 保存路径
后期上传的文件都将保存在Upload下,此时本地路径为C:\site\Public\Upload。但是这里要注意,要对路径进行拆分。因为后期项目上线,服务器的盘符和本地不一样,这时地址便会失效。所以必须对路径进行拆分,定义一个常量。
继续分析,上线后变得是前面的路径,即C:\site,而后面路径Public\Upload不会变。所以可以定义成两个常量,前面是工作路径,后面是固定路径。即使后期工作路径发送变化,也可以通过动态获取的方式获取到相关路径。通过魔术常量__DIR__获取,表示获取当前工作目录。
所以可以拆分为
__DIR__\Public\Upload
最后针对路径总结下:后期项目上线后即使使用绝对路径也可以动态获取
3. 常量定义:可以在入口文件定义常量
//定义工作路径。--因为从require开始执行底层代码,后面的不会被执行。所以放到require之前定义常量
define('WORKING_PATH', __DIR__);
//定义上传根目录。注意:名字不能相同,否则会覆盖
define('UPLOAD__ROOT_PATH', '/Public/Upload');
//输出检查下定义的两个常量
echo WORKING_PATH."<br/>".UPLOAD__ROOT_PATH;die;
输出:
C:\site
/Public/Upload------Window下目录分隔符默认反斜杠,所以要替换成正斜杠\
输出后发现有正斜杠也有反斜杠,所以还需要替换斜杠
将上述代码改为
//定义工作路径。--因为从require开始执行底层代码,后面的不会被执行。所以放到require之前定义常量
define('WORKING_PATH', str_replace(('\\'), '/', __DIR__));
//定义上传根目录。注意:名字不能相同,否则会覆盖
define('UPLOAD__ROOT_PATH', '/Public/Upload');
echo WORKING_PATH.UPLOAD__ROOT_PATH;die;
此时输出正常:C:/site/Public/Upload
(6)定义好常量后,输出检查
因为uploadOne方法上传单个文件,参数是$_FILES中的子元素,返回值是上传的结果(成功返回具有9个元素一维数组,失败返回false)
如果成功,这里会返回一维数组
(7)判断是否上传成功,并补全字段
拓展:
特别注意:保存上传路径时,数据表不可以写带盘符法人路径。因为上传的图片一般都要被浏览器使用。如果使用了带盘符的路径,那会导致http协议和file协议冲突
因为图片要展示给客户端,<img src='D:\www\itcast\1006\Public\Upload\17-01-02\01.jpg'/>,src肯定不能写成前面格式。绝对不可以把带盘符的地址输出到浏览器,因为服务器的协议是http协议,只有本地才可以用file协议
①静态资源路径没有盘符形式的,D:www\itcast\01\Public\upload\16-10-01\01.jpg。纯前端访问可以以file:\\协议进行访问
②而且因为服务器的协议都是http协议,所以不能用盘符形式的路径
③只有本地才能用file协议
最终代码:DocModel.class.php
<?php
//声明命名空间
namespace Admin\Model;
//引入父类
use Think\Model;
//声明并且继承父类
class DocModel extends Model{ //saveData
public function saveData($post,$file){
//处理提交
//dump($file);die;
//先判断是否有文件需要处理
if(!$file['error']){
//定义配置
$cfg = array(
//配置上传路径
'rootPath' => WORKING_PATH . UPLOAD_ROOT_PATH
);
//处理上传
$upload = new \Think\Upload($cfg);
//开始上传
$info = $upload -> uploadOne($file);
//判断是否上传成功
if($info){
//补全剩余的三个字段
// 图片路径为相对路径---固定目录+日期+文件名+后缀
//因为后期数据库存的数据是给浏览器看的,所以路径上----不能带盘符,相对于站点根目录形式UPLOAD_ROOT_PATH
$post['filepath'] = UPLOAD_ROOT_PATH . $info['savepath'] . $info['savename'];
$post['filename'] = $info['name'];//文件的原始名
$post['hasfile'] = 1;//是否有文件
}else{
//A方法实例化控制器
A('Doc') -> error($upload -> getError());exit;
}
}
//补全addtime字段
$post['addtime'] = time();
//添加操作
return $this -> add($post);
}
}
本文总结:MVC心得->如果可以直接进行CURD操作的,简单的基本操作可以直接在控制器编写。如果数据需要保存处理等操作,则最好放到模型里,进行数据的CURD操作。
.
ThinkPHP---TP功能类之上传的更多相关文章
- thinkphp杂项功能(主干)
thinkphp杂项功能(主干) 一.总结 1.杂项功能:杂项里面我需要有点印象的是五个:缓存,多语言,图像处理,文件处理,单元测试 二.thinkphp杂项功能(主干) thinkphp扩展杂项功能 ...
- ThinkPHP示例:图片上传
ThinkPHP示例之图片上传,包括图片上传.数据库保存.缩略图生成以及图片水印功能演示.首先需要下载框架核心,然后把示例解压到Web根目录下面,并修改入口文件中的框架入口文件的位置.导入示例目录下面 ...
- 【socket】Socket的三个功能类TCPClient、TCPListener 和 UDPClient
Socket的三个功能类TCPClient.TCPListener 和 UDPClient (转) 应用程序可以通过 TCPClient.TCPListener 和 UDPClient 类使用传输控制 ...
- php之框架增加日志记录功能类
<?php /* 思路:给定文件,写入读取(fopen ,fwrite……) 如果大于1M 则重写备份 传给一个内容, 判断大小,如果大于1M,备份 小于则写入 */ class Log{ // ...
- FTP文件操作之上传文件
上传文件是一个比较常用的功能,前段时间就做了一个上传图片的模块.开始采用的是共享文件夹的方式,后来发现这种方法不太好.于是果断将其毙掉,后来选择采用FTP的方式进行上传.个人感觉FTP的方式还是比较好 ...
- thinkphp框架调用类不存在的方法
thinkphp框架调用类不存在的方法调用类不存在的方法,不会报错,但是也不会执行,这是根据tp框架里面的一个魔术方法,框架里面一共才十几个魔术方法
- 修改ThinkPHP的验证码类
今天用ThinkPHP重新开发一个系统,用到了ThinkPHP的验证码类,由于我希望验证码别太复杂,希望验证码里边只有数字,却发现该Verify类并未提供设置验证码中使用的字符的配置的方法,于是查看源 ...
- 李洪强iOS开发之上传照片时英文改中文
今天在做项目的时候,有一个功能是上传照片选择系统相册的照片,或者拍照上传照片,但是页面上的文字是英文的, 需求想改成中文的,解决方法是在 info.plist里面添加 Localized resour ...
- ThinkPHP登录功能的实现方法
登陆功能是PHP程序设计中常见的功能.本文ThinkPHP实例主要完成注册成功后进入首页,并告诉你是登录用户的功能.具体实现步骤如下: 第一步:在config.php文件中加上: 完整实现代码如下: ...
随机推荐
- windows安装Python模块:requests
个人在windows10安装python模块requests如下过程: 1.下载requests模块:首先打开powershell, cd到你要下载文件的位置(我的是d:\softwareinstal ...
- TypeError: db.addUser is not a function : @(shell):1:1 ——mongoDB创建新用户名密码的方法
不多说,旧版本使用 db.addUser("root","root") 新版本使用这句会出现这个错误提示 TypeError: db.addUser is no ...
- Java千百问_03基本的语法(001)_局部变量、类变量、实例变量有什么差别
点击进入_很多其它_Java千百问 局部变量.类变量.实例变量有什么差别 在聊局部变量.类变量.实例变量有什么差别之前,我们须要了解一下Java变量. 1.Java变量是什么 在数学世界中,我们知道有 ...
- 脱离开发软件启动Tomcat访问项目
作为开发人员平时用的最多的就是通过开发软件启动Tomcat服务,从而访问项目.这样便于开发的bug调试 此处讲的是脱离开发软件启动Tomcat访问项目 链接参考: http://jingyan.bai ...
- [RK3288][Android6.0] 调试笔记 --- Goodix GT9和GT9F区别【转】
本文转载自:http://blog.csdn.net/kris_fei/article/details/78341425 Platform: RK3288 OS: Android 6.0 Kernel ...
- 2014年国内最热门的.NET开源项目TOP25
编者按:在2014年初时,微软宣布成立.NET基金会,全面支持开源项目.如今将过一年的时间,目前国内的开源项目到底如何了?下面我们就来细数一下国内25款比较优秀的.NET开源项目. 作者:acdoma ...
- Hadoop安装—— WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platf
今天在安装hadoop完成测试创建用户目录失败在网上找到了原因记录一下原文地址 http://blog.csdn.net/l1028386804/article/details/51538611 配置 ...
- 【USACO 2008FEB】 旅馆
[题目链接] 点击打开链接 [算法] 线段树 对于一个节点,记录它从左端点延伸的最多的空房间的个数,从右端点延伸的最多的空房间个数,和该区间最多的连续 空房间个数 [代码] #include<b ...
- Python print 输出不换行,只有空格
for x in open("/home/soyo/桌面/中期内容/6.txt"): print x, ,,,]: print x, #print 输出没有换行,只有空格 结果: ...
- bzoj 1626: [Usaco2007 Dec]Building Roads 修建道路【最小生成树】
先把已有的边并查集了,然后MST即可 记得开double #include<iostream> #include<cstdio> #include<algorithm&g ...