为什么有时候会 出现 "上传文件保存错误"?
public function save($file, $replace=true){
/* 移动文件 */
if (!move_uploaded_file($file['tmp_name'], $filename)) {
$this->error = '文件上传保存错误!'; // 比如写权限, 或文件本身的一些问题, 或者 网络关闭/网速慢等的一些问题等
return false; // 都有可能 引起上传文件的 保存错误!
}
}
说明报 这个错的 原因是: 因为在 将 $file['tmp_name'] 临时文件 移动/剪切到 指定的 保存路径时, 发生了错误.
可以将这个时候的 $file['tmp_name'] 打印出来看看.
也有可能是 move_uploaded_file() 函数有特殊的要求??
===========================
当文件上传成功时, 为什么在 $file你是看不到 tmp_name和 error的?
因为在 public function upload()函数中,调用了 $this ->uploader 的 save() 方法:
$this->uploader->save()
而且在 save成功的时候, 就把 这两个 元素给unset了:在upload上传时, 你要获取错误, 既可以用 Upload类 的 $this->getError(), 也可以用 $this->uploader->getError( 或 $up -> getError() ). 两者其实是一样的, 因为: 在 Upload类的 方法中:
public function getError(){
return $this->error;
}
而在 upload方法中,
if($this->uploader->save($file, $this->replace)){ // 上传成功时 就把$file中的 tmp_name和 error这两个索引给删除了的, 所以后来就看不到了....
unset($file['tmp_name'], $file['error'];
$info[$key] =
$file // 二维数组的索引名称 就等于当前遍历的文件名
}else{
$this->error = $this -> uploader-> getError(); // Upload类的私有成员error 就是由 上传类实例的getError来的. 所以两者是一样的.
}
- 实在 要在 上传错误时, 查看 临时文件名称, 可以在 upload()方法中, 开始就
dump ($files) 或 dump($_FILES). 或者, 在 uploader的save()方法中, 甚至在 调用了$this->uploader->save()方法后, unset之前 都可以用 $file['tmp_name']去查看 上传文件的临时 文件名....
上传时, 明明选择了文件, 却提示" 没有上传的文件"?
这是因为: 当上传的文件超过了 php.ini 设置中的 Post_max_size(默认=8M )时, 表单将不会上传任何信息, 此时的 $_POST & $_FILES 将为 空值.
因此, 正好在 upload方法中, 有: if(empty($file)) { $this->error = '没有上传的文件'; return false; }
在上传的时候, 首先是生成了 $_FILES 数组, 从其名字 就可以看出, 这个是关于 多个上传文件的信息 组成的 二维数组. 这个 $_FILES 时php原生的东西, 跟任何框架, 任何函数方法都没有关系的.
所谓的 upload类等 ,只是对 上传的 原生方法进行了加工和封装, 主要是增加了一些 内部判断 语句, 比如 它的private function check($file) { if(!$this->checkSize($file[
size'))...; if(!$this->checkExt($file['ext']))...; if(!$this->checkMime($file['mime'])).....}tp 上传类中, $files就等于 $_FILES了, 其中的每一个元素(文件)就是 $file. 最后生成的 信息 时$info. 不能搞混了.
这个数组中 的索引名称就是 上传表单的input的那个name. 然后 元素的值就是关于这个上传到 临时目录的文件的信息组成的数组$file
原生的 $_FILES 中, 每个文件的原数据 其实只有 5个: 即 name, type , tmp_name, error(错误代号, 默认为0, 出错为1) ,size 跟$info记录的不同
上传文件的tmp_name其实是在 c:/wamp/tmp目录中, 默认的临时文件名称是 php(当前上传文件的序号, 按16进制的方式进行 编排的. ).tmp 比如: php10.tmp, c:/wamp/tmp/php10.tmp, php16.tmp php1A.tmp(超过16后就是A开始的了)....等等.
array (size=1)
'upfile' =>
array (size=5)
'name' => string 'foobar.exe' (length=15)
'type' => string 'application/octet-stream' (length=24)
'tmp_name' => string 'C:\wamp\tmp\php17.tmp' (length=21)
'error' => int 0
'size' => int 3463680
为什么c:/wamp/tmp目录中 没有 上传临时文件? 即使有临时文件, 也不能再使用了?
如果要手动处理 上传文件的话, 步骤是: 原始文件 -> 中间临时 上传到 临时目录 c:/wamp/tmp -> 再由用户来自己按照需要处理
临时目录中的文件通常被 move走了的, 所以没有了.
如果不是move, 而是copy的话, 那么 临时上传文件就一直存在, 当这个脚本执行完毕后(即退出上传过程后), 这个临时文件虽然还存在, 但是不能再被处理了, 因为它
已经不是一个 is_uploaded_file() 了, 所以, 你用 move_uploaded_file() 来处理的话, 就会报错了.
所以在 上传 封装方法中, 由判断:
/* 检查是否合法上传 */
if (!is_uploaded_file($file['tmp_name'])) {
$this->error = '非法上传文件!';
return false;
}
move_uploaded_file()方法的过程?
- 如同这个函数的名字一样, 它有几个检查的地方, 首先这个文件必须是:经过httppost的方法和机制上传的文件,也就是 is_uploaded_file() 要返回真,
其次, 这个文件, 会 去 上传文件的临时目录c:/wamp/tmp/ 目录中 去查找 $file, 如果找到了 就 "move" 到 新的位置, 注意是move, 所以 临时文件就没有了.
但是 , 并不是 每一次 move_uploaded_file都会成功, 可能会因为 一些原因, 比如: 权限, 比如 文件本身的一些 特殊原因 等等, 可能会使得 这个move 函数 失败, 从而返回false.
最后, 就是 如果 要 避免 上传 保存的文件名, 出现 中文乱码的情况, 上传保存文件最好 就不要使用 中文 名称. 而是使用 纯数字 来命名, 比如:
$cfg = array(
'rootPath' => './Public/',
'savePath' => 'Uploads/',
'saveName' => time().mt_rand(), // 这里就是使用 的 直接 "字符串"的方式, 是 用函数拼接字符串.
);
即使这里的保存文件名是数字或 其他什么的 数字和字母 任意拼接, 都没有关系! 因为最后,都 要把这个 $info的 信息中的 savename 和原始name 以及其他一些信息都要保持到 数据库中去的.