PHP-文件上传

(。・∀・)ノ

 
 

PHP 文件上传

 
 

一. 修改php.ini文件

一般情况需要修改:[可以使用ctrl+f 搜索相关配置项。]

配置项 功能说明
file_uploads on为开启文件上传功能,off为关闭
post_max_size 系统允许的POST传参的最大值
upload_max_filesize 系统允许的上传文件的最大值
memory_limit 内存使用限制
max_execution_time (1)脚本执行时间,参数的单位为秒。
(2)这个参数是设定脚本的最大执行时间。
(3)也可以根据需求做适当的改变。通常不需要来修改,系统默认值即可。超大文件
上传的时候,可能会涉及到这一项参数的修改。
(4)上传时间太长了,会超时。如果你将此项参数设为0,则是不限制超时时间,不建
议使用。

建议尺寸: file_size(文件大小) < upload_max_filesize < post_max_size < memory_limit

&emsp;
&emsp;

三. is_uploaded_file()函数、数组$_FILES

2.1 创建一个文件上传表单

请看下面这个供上传文件的 HTML 表单:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html>
<body>

<form action="upload_file.php" method="post"
enctype="multipart/form-data">
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>

</body>
</html>

&emsp;

请留意如下有关此表单的信息:

  1. <’'form> 标签的 enctype 属性规定了在提交表单时要使用哪种内容类型。在表单需要二进制数据时,比如文件内容,请使用 “multipart/form-data”
  2. <’'input> 标签的 type=”file” 属性规定了应该把输入作为文件来处理。举例来说,当在浏览器中预览时,会看到输入框旁边有一个浏览按钮。

&emsp;

2.2 is_uploaded_file() 函数

[PHP is_uploaded_file() 函数]

功能:检查指定的文件是否是通过 HTTP POST 上传的。如果文件是通过 HTTP POST 上传的,该函数返回 TRUE。

语法: is_uploaded_file(file)

参数 描述
file 必需。规定要检查的文件。

注意:该函数的结果会被缓存。请使用 clearstatcache() 来清除缓存。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$file = "test.txt";
if(is_uploaded_file($file))
{
echo ("$file is uploaded via HTTP POST");
}
else
{
echo ("$file is not uploaded via HTTP POST");
}
?>

上面的代码将输出:

test.txt is not uploaded via HTTP POST

&emsp;

2.3 $_FILES 数组

当客户端上传文件后,我们在action=”xxxx.php”的xxxx.php页面就获得了一个**$_FILES 数组 。**
$_FILES 数组内容如下:

数组元素 描述
$_FILES[“File”][“name”] 上传文件的名称。
$_FILES[“File”][“type”] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如”image/gif”。
$_FILES[“File”][“size”] 已上传文件的大小,单位为字节。
$_FILES[“File’][“tmp_name”] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在ph
p.ini的upload_tmp_dir 指定,但 用 putenv()函数设置是不起作用的。
$_FILES[“File”][“error”] 和该文件上传相关的错误代码。[“error”] 是在 PHP 4.2.0 版本中增加的。
下面是它的说明:(它们在PHP3.0以后成了常量或0123467)

&emsp;
$_FILES数组结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
//var_dump()或print_r()
//打印变量的相关信息,将变量的信息详细的展示出来
var_dump($_FILES);
?>

打印出来的结果的数组结构如下:
array (size=1)
'file' =>
array (size=5)
//文件名
'name' => string 'psu.jpg' (length=7)
//文件的mime类型
'type' => string 'image/jpeg' (length=10)
//缓存文件,上传的图片即保存在这里
'tmp_name' => string 'E:\wamp\tmp\phpC32A.tmp' (length=23)
//错误码,详见上面错误码介绍
'error' => int 0
//上传的文件大小
'size' => int 225824

&emsp;

2.4 move_uploaded_file() 函数

[PHP move_uploaded_file() 函数]

功能:将上传的文件移动到新位置,并命名。

bool move_uploaded_file ( file, newloc)

参数 描述
file 必需。规定要移动的文件。上传后的临时文件名,由系统自动生成。
newloc 必需。规定文件的新位置。包含有路径的新的文件名。

注意:

  1. 参数file一般为$_FILES[“File’][“tmp_name”],是一个文件完整的临时路径和文件名;
  2. 参数newloc为新的路径,并且还要加上相应的重新命名文件的的格式。
  3. 本函数仅用于通过 HTTP POST 上传的文件。
  4. 本函数检查并确保由 file 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 newloc 指定的文件。
  5. 返回值:如果 file 不是合法的上传文件,不会出现任何操作,move_uploaded_file() 将返回 false。
    如果 file 是合法的上传文件,但出于某些原因无法移动,不会出现任何操作,move_uploaded_file() 将返回 false,此外还会发出一条警告。
    这种检查显得格外重要,如果上传的文件有可能会造成对用户或本系统的其他用户显示其内容的话。
  6. move_uploaded_file()基本上与函数rename()相同,但是它只能用于通过PHP的上传机制上传的文件。这是一项安全功能,可防止用户欺骗您的脚本,向他们显示与安全相关的数据。

&emsp;
&emsp;

三. 文件上传的步骤

3.1 判断是否有错误码

使用数组元素:$_FILES[‘file’][‘error’]
即判断$_FILES[‘file’][‘error’]返回值!!
注:错误码中没有5。

错误码
对应常量
说明
0
UPLOAD_ERR_OK
无误,可以继续进行文件上传的后续操作。
1
UPLOAD_ERR_INI_SIZE
超出上传文件的最大限制,upload_max_filesize = 2M php.ini中设置,一
般默认为2M。可根据项目中的实际需要来修改
2
UPLOAD_ERR_FORM_SIZE
超出了指定的文件大小,根据项目的业务需求指定上传文件的大小限制
3
UPLOAD_ERR_PARTIAL
只有部分文件被上传
4
UPLOAD_ERR_NO_FILE
文件没有被上传
6 找不到临时文件夹,可能目录不存在或没权限
7 文件写入失败,可能磁盘满了或没有权限

&emsp;
示例:

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
<?php
if($_FILES['file']['error'] > 0){
switch ($_FILES['file']['error']) { //错误码不为0,即文件上传过程中出现了错误
case '1':
echo '文件过大';
break;
case '2':
echo '文件超出指定大小';
break;
case '3':
echo '只有部分文件被上传';
break;
case '4':
echo '文件没有被上传';
break;
case '6':
echo '找不到指定文件夹';
break;
case '7':
echo '文件写入失败';
break;
default:
echo "上传出错<br/>";
}
}else{
//错误码为0,即上传成功,可以进行后续处理,处理流程见下文
}
?>

&emsp;
&emsp;

3.2 判断是否超出文件大小范围

使用数组元素:$_FILES[“File’][“size”]

&emsp;
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
//判断错误
if ($_FILES['file']['error'] > 0) {
//有错误可停止执行
} else {
//当前上传文件无误,运行本段代码
//判断文件是否超出了指定的大小
//单位为byte
$MAX_FILE_SIZE = 100000;
if ($_FILES['file']['size'] > $MAX_FILE_SIZE) {
//判断,如果上传的文件,大小超出了我们给的限制范围,退上传并产生错误提示
exit("文件超出指定大小");
}
}
?>

将我们指定的文件大小,定义为$MAX_FILE_SIZE,该变量的计数单位为byte,对应上传文件的 $_FILES[‘file’][‘size’]大小。
示例代码中,限制大小约为100K及以下的文件。

&emsp;
&emsp;

3.3 判断后缀名和mime类型是否符合

使用数组元素:$_FILES[“File”][“type”]

  1. MIME(Multipurpose Internet Mail Extensions)是多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
  2. 在判断后缀和MIME类型的时候,我们会用到PHP的一个函数in_array(),该函数传入两个参数。
    第一个参数是要判断的值;
    第二个参数是范围数组。
    我们用这个函数来判断文件的后缀名和mime类型是否在允许的范围内。

&emsp;
示例:

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
<?php
/*判断后缀名和MIME类型是否符合指定需求
例如:
当前项目指定上传后缀为.jpg或.gif的图片,则$allowSuffix = array('jpg','gif');
*/
//定义允许的后缀名数组
$myImg = explode('.', $_FILES['file']['name']);
/*
explode() 将一个字符串用指定的字符切割,并返回一个数组,这里我们将文件名用'.''切割,结果存在$myImg
中,文件的后缀名即为数组的最后一个值
*/
$myImgSuffix = array_pop($myImg);
/*
根据上传文件名获取文件的后缀名
使用in_array()函数,判断上传文件是否符合要求
当文件后缀名不在我们允许的范围内时退出上传并返回错误信息
*/
if(!in_array($myImgSuffix, $allowSuffix)){
exit("文件后缀名不符");
}
/*
mime类型和文件后缀名的对应关系,我们可以通过很多途径查询到,为了避免用户自主修改文件后缀名造成文件无
法使用。
mime类型也必须做出限制检查mime类型,是为了防止上传者直接修改文件后缀名
导致文件不可用或上传的文件不符合要求。
*/
//数组内容为允许上传的mime类型
$allowMime = array(
"image/jpg",
"image/jpeg",
"image/pjpeg",
"image/gif"
);
if(!in_array($_FILES['file']['type'], $allowMime)){
//判断上传文件的mime类型是否在允许的范围内
exit('文件格式不正确,请检查');
//如果不在允许范围内,退出上传并返回错误信息
}
?>

&emsp;
&emsp;

3.4 生成指定的路径和文件名

我们的文件上传成功了,不会让它保存原名。
因为,有些人在原名中有敏感关键词会违反我国的相关法律和法规。
我们可以采用date()、mt_rand()或者unique()生成随机的文件名。

  1. $_FILES[“file”][“tmp_name”]:文件被上传结束后,默认地被存储在了临时目录中,这时您必须将它从临时目录中删除或移动到其它地方,如果没有,则会被删除。也就是不管是否上传成功,脚本执行完后临时目录里的文件肯定会被删除。所以在删除之前要用PHP的 copy() 函数将它复制到其它位置,此时,才算完成了上传文件过程。
  2. 按照项目的文件安排,生成文件存储路径,为了避免文件名重复而产生的错误,按照一定的格式,生成一个随机文件名。

&emsp;
示例:

1
2
3
4
5
6
7
8
<?php
//指定上传文件夹
$path = "upload/images/";
/*
根据当前时间生成随机文件名,本行代码是使用当前时间 + 随机一个0-9的数字组合成文件名,后缀即为前面取到的文件后缀名
*/
$name = date('Y').date('m').date("d").date('H').date('i').date('s').rand(0,9).'.'.$myImgSuffix;
?>

&emsp;
&emsp;

3.5 判断是否是上传文件

使用函数:is_uploaded_file()

  1. 文件上传成功时,系统会将上传的临时文件上传到系统的临时目录中。产生一个临时文件。
  2. 同时会产生临时文件名。我们需要做的事情是将临时文件移动到系统的指定目录中。
  3. 而移动前不能瞎移动,或者移动错了都是不科学的。移动前我们需要使用相关函数判断上传的文件是不是临时文件。
  4. is_uploaded_file()传入一个参数($_FILES中的缓存文件名),判断传入的名称是不是上传文件。

&emsp;
is_uploaded_file()函数是专用的函数,来判断目标文件是否是上传文件。

1
2
3
4
5
6
7
<?php

//使用is_uploaded_file()判断是否是上传文件,函数介绍见上文
if(is_uploaded_file($_FILEs['file']['tmp_name'])){

}
?>

&emsp;
&emsp;

3.6 移动临时文件到指定位置

使用函数:move_uploaded_file()和数组元素:$_FILES[“file”][“tmp_name”]

  1. 临时文件是真实的临时文件,我们需要将其移动到我们的网站目录下面,让我们网站目录的数据,其他人可以访问到。
  2. 我们使用:move_uploaded_file()
    这个函数是**将上传文件移动到指定位置,并命名**。
    传入两个参数:
    第一个参数是指定移动的上传文件;
    第二个参数是指定的文件夹和名称拼接的字符串。
  3. 需要注意的是,Linux系统中对目标目录是否有权限及磁盘空间是否足够,否则会导致上传操作失败。

&emsp;
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
/*
使用move_uploaded_file()移动上传文件至指定位置,第一个参数为上传文件,第二个参数为我们在前面指定的上传路径和名称。
*/
if(move_uploaded_file($_FILEs['file']['tmp_name'], $path.$name)){
//提示文件上传成功
echo "上传成功";
}else{
/*
文件移动失败,检查磁盘是否有足够的空间,或者linux类系统中文件夹是否有足够的操作权限
*/
echo '上传失败';
}
}else{
echo '不是上传文件';
}

}
?>

&emsp;
&emsp;

四. 多文件上传

多文件上传原理相同,不过在处理数据时,需要对上传数据进行特殊处理

&emsp;
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
<html> 
<head>
<meta charset="utf-8" />
<title>单文件上传</title>
</head>
<body>
<form action="morefile.php" method="post" enctype="multipart/form-data">
<input type="file" name="file[]"> //name比单文件上传时多了[]
<input type="file" name="file[]"> //name比单文件上传时多了[]
<input type="submit" value="上传">
</form>
</body>
</html>

这里是一个简易的上传页面,form表单同时提交了两个文件。我们 可以通过这个页面提交内容。
注意:

  1. input type=”file” name=”file[]”与之前相比file后多加了一个中括号
  2. 写了2个或者多个input type=”file” name=”file[]”
    我们使用 $_FILES 来接收文件信息,打印并查看数组:

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
<?php 
var_dump($_FILES); //打印$_FILES查看数组结构
?>

输出如下:
array (size=1)
'file' =>
array (size=5)
'name' =>
array (size=2)
//文件名
0 => string 'psu.jpg' (length=7)
1 => string 'qwe.jpg' (length=7)
//文件mime类型
'type' => array (size=2)
0 => string 'image/jpeg' (length=10)
1 => string 'image/jpeg' (length=10)
//缓存文件
'tmp_name' =>
array (size=2)
0 => string 'E:\wamp\tmp\phpF6D5.tmp' (length=23)
1 => string 'E:\wamp\tmp\phpF6F5.tmp' (length=23)
//文件错误信息
'error' =>
array (size=2)
0 => int 0
1 => int 0
//文件大小
'size' =>
array (size=2)
0 => int 225824
1 => int 151651
  1. 我们可以看到,两个文件被存储在一个数组中,键名和上传单文件是相同。所以,需要我们for()循环,来分别取出两个文件的需要用到的数据。
  2. 在$_FILES中同时保存了两个文件的数据,我们需要使用一个简单的循环,来读取单个文件的信息,并将文件移动到我们想要放的位置。

&emsp;

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
<?php
for ($i=0; $i < count($_FILE['file']['name']); $i++) {

/*
用is_uploaded_file()函数判断是上传文件
并且没有出现错
*/

if(is_uploaded_file($_FILEs['file']['tmp_name'][$i]) && $_FILEs['file']['error'][$i] == 0){
if(move_uploaded_file($_FILEs['file']['tmp_name'][$i],'upload/'.$_FILE['file']['name'][$i])){
//用move_uploaded_file()函数移动文件到指定的位置并使用文件原名
echo "上传成功";

}else{

echo '上传失败';

}

}else{

echo '上传失败';

}

}
?>

&emsp;
&emsp;

五. 单文件上传完整代码

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
<?php
if ($_FILES['file']['error'] > 0) {
switch ($_FILES['file']['error']) {
//错误码不为0,即文件上传过程中出现了错误
case '1':
echo '文件过大';
break;
case '2':
echo '文件超出指定大小';
break;
case '3':
echo '只有部分文件被上传';
break;
case '4':
echo '文件没有被上传';
break;
case '6':
echo '找不到指定文件夹';
break;
case '7':
echo '文件写入失败';
break;
default:
echo "上传出错<br/>";
}
} else {

$MAX_FILE_SIZE = 100000;
if ($_FILES['file']['size'] > $MAX_FILE_SIZE) {
exit("文件超出指定大小");

}

$allowSuffix = array(
'jpg',
'gif',
);

$myImg = explode('.', $_FILES['file']['name']);

$myImgSuffix = array_pop($myImg);

if (!in_array($myImgSuffix, $allowSuffix)) {
exit("文件后缀名不符");
}

$allowMime = array(
"image/jpg",
"image/jpeg",
"image/pjpeg",
"image/gif",
);

if (!in_array($_FILES['file']['type'], $allowMime)) {
exit('文件格式不正确,请检查');
}

$path = "upload/images/";
$name = date('Y') . date('m') . date("d") . date('H') . date('i') . date('s') . rand(0, 9) . '.' . $myImgSuffix;

if (is_uploaded_file($_FILEs['file']['tmp_name'])) {

if (move_uploaded_file($_FILEs['file']['tmp_name'], $path . $name)) {
echo "上传成功";
} else {
echo '上传失败';
}

} else {
echo '不是上传文件';
}

}
?>