PHP文件上传
要想顺利实现上传功能,首先要在php.ini中开启文件上传,并对其中一些参数作出合理的设置,找到 File Upload 项 可以看到下面有三个属性,表示含义如下。
file_upload :如果值为 on ,说明服务器支持文件上传。否则反之
upload_tmp_dir : 上传文件临时目录。在文件被成功上传之前,文件首先存放到服务器的临时目录。如果想要知道位置,可以在后面设置存放路径,否则,使用系统默认目录
upload_max_filesize :服务器允许上传的文件的最大值,以MB为单位。系统默认为2MB,用户可自行设置
★ 如果使用集成化的安装包来配置PHP 的开发环境,上面介绍的这些配置信息按默认已经配置好了。
文件上传步骤
为了更好的学习PHP,我们将复杂的PHP的文件上传归纳总结成为了6个步骤。
在实际使用过程中,按照这6个步骤就能够很好的完成PHP的文件上传:
一.判断是否有错误码
系统返回的错误码详解:
错误码 | 说明 |
0 | 无误,可以继续进行文件上传的后续操作。 |
1 | 超出上传文件的最大限制,upload_max_filesize = 2M php.ini中设置,一般默认为2M。可根据项目中的实际需要来修改 |
2 | 超出了指定的文件大小,根据项目的业务需求指定上传文件的大小限制 |
3 | 只有部分文件被上传 |
4 | 文件没有被上传 |
6 | 找不到临时文件夹,可能目录不存在或没权限 |
7 | 文件写入失败,可能磁盘满了或没有权限 |
注★:错误码中没有5
二.自定义判断是否超出文件大小范围
在开发上传功能时。我们作为开发人员,除了php.ini中规定的上传的最大值外。
我们通常还会设定一个值,是业务规定的上传大小限制。
例如:
新浪微博或者QQ空间只准单张头像图片2M。而在上传图册的时候又可以超过2M来上传。
所以说,它的系统是支持更大文件上传的。
此处的判断文件大小,我们用于限制实际业务中我们想要规定的上传的文件大小。
三.判断后缀名和MIME类型是否符合
MIME(Multipurpose Internet Mail Extensions)是多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时
候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
在判断后缀和MIME类型的时候,我们会用到PHP的一个函数in_array(),该函数传入两个参数。
第一个参数是要判断的值;
第二个参数是范围数组。
我们用这个函数来判断文件的后缀名和mime类型是否在允许的范围内。
四.生成文件名
我们的文件上传成功了,不会让它保存原名。
因为,有些人在原名中有敏感关键词会违反我国的相关法律和法规。
我们可以采用date()、mt_rand()或者unique()生成随机的文件名。
五.判断是否是上传文件。
我们的文件上传成功了,不会让它保存原名。
因为,有些人在原名中有敏感关键词会违反我国的相关法律和法规。
我们可以采用date()、mt_rand()或者unique()生成随机的文件名。文件上传成功时,系统会将上传的临时文件上传到系统的临时目录中。产生一个临时文件。
同时会产生临时文件名。我们需要做的事情是将临时文件移动到系统的指定目录中。
而移动前不能瞎移动,或者移动错了都是不科学的。移动前我们需要使用相关函数判断上传的文件是不是临时文件。
is_uploaded_file()传入一个参数($_FILES中的缓存文件名),判断传入的名称是不是上传文件。
六.移动临时文件到指定目录
临时文件是真实的临时文件,我们需要将其移动到我们的网站目录下面了。
让我们网站目录的数据,其他人可以访问到。
我们使用:move_uploaded_file()。
这个函数是将上传文件移动到指定位置,并命名。
传入两个参数:
第一个参数是指定移动的上传文件;
第二个参数是指定的文件夹和名称拼接的字符串。
上传文件必须在网页中准备好一个form表单。就像下面这样
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>PHP中文网</title> </head> <body> <form action="file.php" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上传"> </form> </body> </html>
注意事项:
1. form 表单中的参数method 必须为post。若为get是无法进行文件上传的
2. enctype须为multipart/form-dat
3. 当选择 的 type=file 时,默认为上传文件内容。
上面的form表单提交的文件内容指向了file.php。
我们在file.php中,通过PHP代码,来处理上传文件。
我们选择一个名为图片进行上传。假设图片的名字为:.jpg,点击上传。
PHP为文件类数据准备了一个专用的系统函数$_FILES,上传文件的所有相关数据,都保存在这个系统函数中。
在PHP文件中,我们打印 $_FILES ,来观察这个数组的结构:
<?php //var_dump()或print_r() //打印变量的相关信息,将变量的信息详细的展示出来 var_dump($_FILES); ?>
程序运行结果:
array(1) {
["file"]=>
array(5) {
["name"]=>
string(7) "psu.jpg"
["type"]=>
string(10) "image/jpeg"
["tmp_name"]=>
string(22) "C:\Windows\phpE2F1.tmp"
["error"]=>
int(0)
["size"]=>
int(488929)
}
}
打印出来的结果的数组结构如下:
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
得到了上面的数组结构。
我们就可以开始文件的处理过程了。
第一步,判断错误码
<?php header("Content-type:text/html;charset=utf-8"); 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{ echo "上传成功";//错误码为0,即上传成功,可以进行后续处理,处理流程见下文 } ?>
上面的代码详细的介绍了错误码和对应的错误,我们可以根据错误码,来生成准确的错误提示。
第二步,判断文件是否超出大小。
在实际项目中,由于系统硬件的限制,以及存储设备的限制,不可能让用户无限制的上传文件,所以我们要对用户上传的文件大小进行限制。定义一个合适的限制大小,能让
我们的应用更稳定的运行。
<?php header("Content-type:text/html;charset=utf-8"); 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及以下的文件。
第三步,判断文件的mime类型是否正确。
更多的时候,我们的文件上传功能,都需要判断用户上传的文件,是否符合要求,不可用的文件上传以后,对于线上应用的整体展示效果,会造成恶劣的影响。所以我们需通
过mime类型和后缀名,来判断用户上传的文件是否符合要求。
下面的示例代码中,我们假设当前的项目需求为指定上传图片,要求上传后缀名为GIF或者jpg的文件,当用户上传不符合要求的文件时,返回错误提示。
/*判断后缀名和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('文件格式不正确,请检查');
//如果不在允许范围内,退出上传并返回错误信息
}
第四步,生成指定的路径和文件名。
按照项目的文件安排,生成文件存储路径,为了避免文件名重复而产生的错误,按照一定的格式,生成一个随机文件名。
按照项目的文件安排,生成文件存储路径,为了避免文件名重复而产生的错误,按照一定的格式,生成一个随机文件名。
//指定上传文件夹
$path = "upload/images/";
/*
根据当前时间生成随机文件名,本行代码是使用当前时间 + 随机一个0-9的数字组合成文件名,后缀即为前面取到的文件后缀名
*/
$name = date('Y').date('m').date("d").date('H').date('i').date('s').rand(0,9).'.'.$myImgSuffix;
第五步,判断是否是上传文件。
is_uploaded_file()函数是专用的函数,来判断目标文件是否是上传文件。
<?php
//使用is_uploaded_file()判断是否是上传文件,函数介绍见上文
if(is_uploaded_file($_FILEs['file']['tmp_name'])){
}
?>
第六步,移动文件到指定位置。
使用move_uploaded_file()函数,将文件移动到指定的位置,并命名。需要注意的是,Linux系统中对目标目录是否有权限及磁盘空间是否足够,否则会导致上传操作失败。
/*
使用move_uploaded_file()移动上传文件至指定位置,第一个参数为上传文件,第二个参数为我们在前面指定的上传路径和名称。
*/
if(move_uploaded_file($_FILEs['file']['tmp_name'], $path.$name)){
//提示文件上传成功
echo "上传成功";
}else{
/*
文件移动失败,检查磁盘是否有足够的空间, */
echo '上传失败';
}
}else{
echo '不是上传文件';
}
}
?>
我们将这个文件片段整理成一整个文件:一个简单的上传图片的程序
详情见示例1
多文件上传
介绍了PHP上传单个文件的过程。但是有些时候,为了使用方便,我们需要满足同时上传多个文件的需求。多文件上传原理相同,不过在处理数据时,需要对上传数据进行特殊处理。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>PHP中文网</title> </head> <body> <html> <body> <form action="morefile.php" method="post" enctype="multipart/form-data"> <input type="file" name="file[]"> <input type="file" name="file[]"> <input type="submit" value="上传"> </form> </body> </html> </body> </html>
这里是一个简易的上传页面,form表单同时提交了两个文件。我们 可以通过这个页面提交内容。
注意:
1. input type="file" name="file[]"与之前相比file后多加了一个中括号
2. 写了2个或者多个input type="file" name="file[]"
数组结构如下
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
我们可以看到,两个文件被存储在一个数组中,键名和上传单文件是相同。所以,需要我们用for()循环,来分别取出两个文件的需要用到的数据。
在$_FILES中同时保存了两个文件的数据,我们需要使用一个简单的循环,来读取单个文件的信息,并将文件移动到我们想要放的位置。
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 '上传失败';
}
}
详细的判断过程,参见单文件上传,这里只做了基本的判断,并没有对文件的大小及格式提醒。
实例1
上传图片程序
程序1 html 页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>PHP中文网</title> </head> <body> <form action="file-upload.php" enctype="multipart/form-data" method="post" name="uploadfile"> 上传文件:<input type="file" name="upfile" /><br> <input type="submit" value="上传" /></form> </form> </body> </html>
程序2 提交到 php 页面
<?php header("Content-type:text/html;charset=utf-8"); //print_r($_FILES["upfile"]); if(is_uploaded_file($_FILES['upfile']['tmp_name'])){ $upfile=$_FILES["upfile"]; //获取数组里面的值 $name=$upfile["name"];//上传文件的文件名 $type=$upfile["type"];//上传文件的类型 $size=$upfile["size"];//上传文件的大小 $tmp_name=$upfile["tmp_name"];//上传文件的临时存放路径 //判断是否为图片 switch ($type){ case 'image/pjpeg':$okType=true; break; case 'image/jpeg':$okType=true; break; case 'image/gif':$okType=true; break; case 'image/png':$okType=true; break; } if($okType){ /** * 0:文件上传成功<br/> * 1:超过了文件大小,在php.ini文件中设置<br/> * 2:超过了文件的大小MAX_FILE_SIZE选项指定的值<br/> * 3:文件只有部分被上传<br/> * 4:没有文件被上传<br/> * 5:上传文件大小为0 */ $error=$upfile["error"];//上传后系统返回的值 echo "上传文件名称是:".$name."<br/>"; echo "上传文件类型是:".$type."<br/>"; echo "上传文件大小是:".$size."<br/>"; echo "上传后系统返回的值是:".$error."<br/>"; echo "上传文件的临时存放路径是:".$tmp_name."<br/>"; echo "开始移动上传文件<br/>"; //把上传的临时文件移动到指定目录下面 move_uploaded_file($tmp_name,'D:\\upload/images/'.$name); $destination="D:\\upload/images/".$name; echo "上传信息:<br/>"; if($error==0){ echo "文件上传成功啦!"; }elseif ($error==1){ echo "超过了文件大小,在php.ini文件中设置"; }elseif ($error==2){ echo "超过了文件的大小MAX_FILE_SIZE选项指定的值"; }elseif ($error==3){ echo "文件只有部分被上传"; }elseif ($error==4){ echo "没有文件被上传"; }else{ echo "上传文件大小为0"; } }else{ echo "请上传jpg,gif,png等格式的图片!"; } } ?>
找一个图片上传,看看程序运行结果
实例2
本例有4个文件上传域,文件域的名字为 u_file[] ,提交后上传的文件信息都被保存到$_FILES[u_file]中,生成多维数组。读取数组信息,并上传文件。
程序1 html 页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>PHP中文网</title> </head> <body> <html> <body> <p>请选择要上传的文件</p> <form action="morefile.php" method="post" enctype="multipart/form-data"> <table border="1" bgcolor="f0f0f0"> <tr> <td>上传文件</td> <td><input type="file" name="u_file[]"></td> </tr> <tr> <td>上传文件</td> <td><input type="file" name="u_file[]"></td> </tr> <tr> <td>上传文件</td> <td><input type="file" name="u_file[]"></td> </tr> <tr> <td>上传文件</td> <td><input type="file" name="u_file[]"></td> </tr> <tr> <td colspan="2"><input type="submit" value="上传"></td> </tr> </table> </form> </body> </html> </body> </html>
程序2 提交到 php 页面
<?php header("Content-type:text/html;charset=utf-8"); if(!empty($_FILES[u_file][name])){ //判断遍历$_FILES是否为空 $file_name=$_FILES[u_file][name]; //将上传文件名另存为数组 $file_tmp_name=$_FILES[u_file][tmp_name]; //将上传的临时文件名另存为数组 for($i=0;$i<count($file_name);$i++){ //循环上传文件 if($file_name[$i]!=""){ //判断上传文件名是否为空 move_uploaded_file($file_tmp_name[$i],$i.$file_name[$i]); echo "文件" .$file_name[$i] ."上传成功。更名为"."$file_name[$i]"."<br>"; } } } ?>
运行你的程序看看吧
实例3
本例上传一个表单,允许上传大小为1MB 以下的文件
<from action="" method="POST" enctype="multipart/form-data"> <input type="file" name="file"> <input type="submit" value="上传"> </from> <?php if(!empty($_FILES[file][name])){ //判断是否有文件上传 $fileinfo=$_FILES[file]; //将文件信息赋给变量$fileinfo if($fileinfo['size']<1000000 && $fileinfo['size']>0){ //判断文件大小 echo "上传成功"; }else{ echo "上传文件太大或未知"; } } ?>
运行你的程序。