PHP - 文件上传 | 缩略图

文件上传


表单的enctype属性:

  • application/x-www-fomr-urlencoded :表示表单先服务器传输的文件数据。这是默认格式。(将表单的数据转成XML格式向服务器传输)
  • multipart/form-data :符合数据,告知浏览器表单中是符合数据(字符串,二进制文件)
  • text/plain:用于向服务器传输大量文本,效率高,但时安全性低,用于发送邮件
    表示表单传输的数据类型

表单文件域

1
2
3
4
<form method="post" action="" enctype="multipart/form-data">
<input type="file" name="">
<input type="submit" name="button" value="上传">
</form>

超全局变量

$_FILES
$_FILES[]['name'] :上传文件名
$_FILES[]['size'] :文件上传的大小

$_FILES[]['error'] :文件上传的错误号 0,1,2,3,4,6,7

UPLOAD_ERR_OK:值为 0,没有错误发生,文件上传成功。
UPLOAD_ERR_INI_SIZE : 值为 1,上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
UPLOAD_ERR_FORM_SIZE:值为 2,上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。<input type='hidden' name='MAX_FILE_SIZE' value='2'>,隐藏域必须在文件域前面才起作用。
UPLOAD_ERR_PARTIAL:值为 3,文件只有部分被上传。
UPLOAD_ERR_NO_FILE:值为 4,没有文件被上传。
UPLOAD_ERR_NO_TMP_DIR:值为 6,找不到临时文件夹。PHP 4.3.10 和 PHP 5.0.3 引进。
UPLOAD_ERR_CANT_WRITE:值为 7,文件写入失败。PHP 5.1.0 引进。

补充:

表单允许POST传输的最大值:
post_max_size = 8M

$_FILES[]['type'] :上传文件格式,返回MIMIE格式 语法:类型/格式
$_FILES[]['tmp'] :文件上传的临时目录

upload_tmp_dir='F:\wamp\tmp' 临时目录地址

php.ini 配置文件
file_uploads = On 是否允许文件上传
max_file_uploads = 20 同时最多允许上传20个文件

move_uploaded_file()移动上传文件

bool move_uploaded_file ( string $filename , string $destination )
$filename:上传的文件的文件名。
$destination:移动文件到这个位置。

常用函数
bool is_uploaded_file ( string $filename ) — 判断文件是否是通过 HTTP POST 上传的
is_uploaded_file($_FILES['userfile']['tmp_name']):用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件,例如 /etc/passwd

文件名截取
方法一:strrchr($filename,'.'); 从最后出现的点截取到末尾
方法二:pathinfo($filename); 通过文件路径返回文件信息

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$path_parts = pathinfo('/www/htdocs/inc/lib.inc.php');

echo $path_parts['dirname'], "\n";
echo $path_parts['basename'], "\n";
echo $path_parts['extension'], "\n";
echo $path_parts['filename'], "\n"; // since PHP 5.2.0
?>
/www/htdocs/inc
lib.inc.php
php
lib.inc

以上两种方法方法可以被伪装(强制修改文件扩展名)

方法三:开启fileinfo扩展extension_fileinfo.dll

1
2
3
$finfo = finfo_open(FILEINFO_MIME); //创建finfo对象,用来匹配文件
$info = finfo_file($finfo,'F:/image.jpg');//通过对象匹配文件
var_dump($info);//显示文件信息

文件上传注意事项:

上传文件的大小限制(文件上传upload_max_filesize、post大小post_max_size、表单隐藏域<input type='hidden' name='MAX_FILE_SIZE' value='2'>,文件域之前)
文件格式验证的三种方法:
路径截取、pathinfo、fileinfo

生成唯一文件名

time().rand(100,999).strrchr($path,’.’);

uniqid().strrchar($path,’.’);

string uniqid ([ string $prefix = "" [, bool $more_entropy = false ]] ),可选前缀prefix、基于当前时间微秒数的唯一ID。设置第二个参数more_entropyTRUE,返回唯一ID更具唯一性。

优化文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
/*
** +-------------------------------------------
** | Author: uiste [ JUST DO IT ]
** +-------------------------------------------
** | Date: 2015/10/8 Time: 19:50
** +-------------------------------------------
** | Connection: <blog.uiste.com>
** +-------------------------------------------
*/

/**
* Class UploadLib 文件上传类
*/
class UploadLib{
//保存操作获取的错误信息
private $error;
//外部调用文件上传的错误信息
public function getError(){
return $this->error;
}
/**
* 文件上传优化类
* @param array $file 文件上传获取的数组信息
* @return string 上传文件的路径
*/
public function upload($file){
/**
* 验证错误信息,保存到私有属性中
*/
if ($file['error']!==0) {
switch ($file['error']) {
case 1:
$this->error = "上传文件超过了配置文件中允许的最大值";
break;
case 2:
$this->error = "上传文件超过了表单允许的最大值";
break;
case 3:
$this->error = "只有部分文件上传,没有完全上传";
break;
case 4:
$this->error = "没有文件被上传";
break;
case 6:
$this->error = "找不到临时文件";
break;
case 7:
$this->error = "文件写入失败";
break;
default:
$this->error = "其它未知错误";
break;
}
return false;
}
/**
* 验证文件类型
* @param array $allow_types 允许上传的文件类型
* @param resource $finfo MIME资源,用于finfo_file匹配需求
* @param string $info 文件类型与编码信息的字符串
* @param array $type_mime 截取mime文件类型
*/
$allow_types = array("image/jpeg","image/png","image/gif");
$finfo = finfo_open(FILEINFO_MIME);
$info = finfo_file($finfo, $file['tmp_name']);
$info_array = explode(';',$info);
$type_mime = $info_array[0];
if (!in_array($type_mime,$allow_types)) {
$this->error = "文件类型错误,不能上传".$type_mime."类型的文件";
return false;
}
/**
* 验证文件类型
* @param byte $file['size'] 上传文件的大小
* @param byte $GLOBALS['config']['file']['allow_size'] 网站允许上传的文件大小
*/
if ($file['size']>$GLOBALS['config']['file']['allow_size']) {
$this->error = "上传文件大小是:".number_format($file['size']/1024/1024,2)."M;超过了网站允许的最大值:".number_format($GLOBALS['config']['file']['allow_size']/1024/1024,2)."M";
return false;
}
/**
* 验证文件是否通过HTTP POST上传
*/
if (!is_uploaded_file($file['tmp_name'])) {
$this->error = "非法上传文件,必须通过HTTP上传";
return false;
}
/**
* 创建上传文件夹
* @param array $type 拆分MIME类型文件类型与文件格式
* @param string $folder_set 定义级联文件夹
* @param string $folder_path 网站配置上传文件路径与级联路径后的全路径
* @param string $file_name 上传文件重新生成的唯一文件名
* @param string $file_path 文件全路径,包含文件名
*/
$type = explode('/', $type_mime);//获取的文件类型与文件格式两个值
$folder_set = $type[0].DS.$type[1].DS.date('Ym').DS;
$folder_path = $GLOBALS['config']['file']['upload_path'].DS.$folder_set;
$file_name = uniqid('',true).'.'.$type[1];
$file_path = $folder_path.$file_name;
if (!file_exists($folder_path)) {
if (!mkdir($folder_path,0777,true)) {
$this->error = "上传文件夹创建失败";
return false;
}

}
//上传文件
if (move_uploaded_file($file['tmp_name'], $file_path)) {
return $folder_set.$file_name;
}else{
$this->error = "文件上传失败";
}
}
}
?>

多文件上传

表单命名以数组的形式,接收到的数据,按相同的属性组成一个索引数组

缩略图


bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
重采样拷贝部分图像并调整大小

dst_image:目标图象连接资源。
src_image:源图象连接资源。
dst_x:目标 X 坐标点。
dst_y:目标 Y 坐标点。
src_x:源的 X 坐标点。
src_y:源的 Y 坐标点。
dst_w:目标宽度。
dst_h:目标高度。
src_w:源图象的宽度。
src_h:源图象的高度

等比缩略图


思想:按图的长宽比例进行比较,源图的比例大的为标准,短边进行等比压缩。

压缩目标图边的长度=源图缩放边的长度*目标图标准边长度/源图标准边的长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php
/*
** +-------------------------------------------
** | Author: uiste [ JUST DO IT ]
** +-------------------------------------------
** | Date: 2015/10/8 Time: 19:50
** +-------------------------------------------
** | Connection: <blog.uiste.com>
** +-------------------------------------------
*/

/**
* Class ThumbLib 生成缩略图
*/
class ThumbLib{
//保存操作获取的错误信息
private $error;
//外部调用文件上传的错误信息
public function getError(){
return $this->error;
}
/**
* 生成缩略图
* @param string $src_path 源图路径资源
* @param int $max_w 缩略图的最大宽度,若调用时不传递就直接使用配置文件的大小
* @param int $max_h 缩略图的最大高度,同上
* @param bool $is_ration 是否等比缩放
* @param string $prefix 缩略图文件名前缀
* @return string 返回缩略图路径
*/
public function thumb($src_path,$max_w='',$max_h='',$is_ratio=true,$prefix='small_'){
$max_w = $max_w!='' ? $max_w : $GLOBALS['config']['file']['thumb_w'] ;
$max_h = $max_h!='' ? $max_h : $GLOBALS['config']['file']['thumb_h'] ;
$ext = strtolower(strrchr($src_path,'.'));//获取文件的后缀
$type = '';
switch ($ext) {
case '.jpg':
$type = 'jpeg';
break;
case '.jpeg':
$type = 'jpeg';
break;
case '.png':
$type = 'png';
break;
case '.gif':
$type = 'gif';
break;
default:
$this->error = "不支持该文件类型".$ext;
return false;
}
$open_fn = 'imagecreatefrom'.$type; //拼接函数名
// 创建缩略图画布
$dst_img = imagecreatetruecolor($max_w, $max_h);
// 打开源图片资源
$src_path_all = $GLOBALS['config']['file']['upload_path'].DS.$src_path;
if(!$src_img = $open_fn($src_path_all)){
$this->error = "源图路径错误或者不全";
return false;
}
$src_w = imagesx($src_img);
$src_h = imagesy($src_img);
if ($is_ratio) {
if ($src_w/$src_h>$max_w/$max_h) {
#若源图的宽度较长,则等比缩放高度
$dst_w = $max_w;
$dst_h = $dst_w*$src_h/$src_w;
}else{
#如源图的高度较长,则等比缩放宽度
$dst_h = $max_h;
$dst_w = $dst_h*$src_w/$src_h;
}
}
// 求目标图的坐标
$dst_x = (int)(($max_w-$dst_w)/2);
$dst_y = (int)(($max_h-$dst_h)/2);
// 生成缩略图
imagecopyresampled($dst_img, $src_img, $dst_x, $dst_y, 0, 0, $dst_w, $dst_h, $src_w, $src_h);
// 保存缩略图
$folderpath = dirname($src_path);//获取目录地址
$filename = basename($src_path); //获取文件名
$small_path = $GLOBALS['config']['file']['upload_path'].DS.$folderpath.DS.$prefix.$filename; //缩略图的全路径
$save_fn = 'image'.$type;
$save_fn($dst_img,$small_path);
// 关闭资源
imagedestroy($src_img);
imagedestroy($dst_img);
// 返回缩略图保存路径
return $folderpath.DS.$prefix.$filename;
}
}
?>