详解PHP文件上传

zxh5566  2016-08-26 19:56   Hits: 

在WEB开发中,经常需要将本地文件上传到web服务器上,也可以从web服务器上下载一些文件到本地磁盘,文件的上传和下载应用十分广泛,在PHP中可以接受来自几乎所有类型浏览器上传的文件,PHP还允许对服务器的下载进行控制。

为了满足传递文件信息的需要,HTTP协议实现了文件上传机制,从而可以将客户端的文件通过自己的浏览器上传到服务器上的指定目录存放。上传文件时,需要在客户端选择本地磁盘文件,而在服务器端需要接收并处理来自客户端上传的文件。所以客户端和web服务器都需要设置。

1、客户端上传设置

文件上传的最基本方法,是使用html表单选择本地文件进行提交,在form表单中可以通过<input type='file'>标记选择本地文件,如果支持文件上传操作,必须在<form>标签中将enctype和method两个属性指明相应的值。

enctype="multipart/form-data"用来指定表单编码数据方式,让服务器知道,我们要传递一个文件,并带有常规的表单信息

method="POST"用来指明发送数据的方法。

另外,还需要在form表单中设置一个hidden类型的input,其中name值为MAX_FILE_SIZE的隐藏值域,并通过设置其value的值限制上传文件的大小。但这个值不能超过PHP的配置文件中upload_max_filesize值设置的大小,文件上传表单的示例代码如下

<html>
<head><title>文件上传</title></head>
<body>
<form action="upload.php" method='post' enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="1000000"/>
选择文件:<input type="file" name="myfile"/>
<input type="submit" value="上传文件"/>
</form>
</body>
</html>

其中隐藏表单MAX_FILE_SIZE的值是对浏览器的一个建议,实际上可以被简单的攻击,我们不要对浏览器端的限制寄托什么希望,在表单上使用,是因为对于善意的错误我们可以帮助纠正,避免用户花费很长时间等待大文件上传,传了很久,才发现无法上传。

2、在服务器端通过PHP上传

客户端的上传只能提供本地文件选择,以及提供将文件发送给服务器的标准化方式,但并没有提供相关功能来确定文件到达目的地后发生了什么,所以上传文件的接收后后续处理就要通过PHP脚本来处理,要想通过PHP成功的管理文件上传,需要通过以下三方面信息。

设置PHP配置文件的指令,用于精细的调节PHP的文件上传功能
$_FILE多维数组:用于存储各种与上传文件有关的信息
PHP的文件上传处理函数,用于上传文件的后续处理

文件上传与PHP配置文件的设置有关,首先,应该设置php.ini文件中的一些指令,精细调节PHP的文件上传功能。

file_uploads  on  确定服务器上的PHP脚本是否可以接受HTTP文件上传
memory_limit  8M  设置脚本可以分配的最大内存量,防止失控的脚本独占服务器内存
upload_max_filesize  2M 限制PHP处理上传文件大小的最大值,此值必须小于post_max_size
post_max_size  8M 限制通过post方法可以接受信息的最大值,此值应当大于配置指令upload_max_file的值,因为除了上传的文件之外,还可能传递其他的表单域。
upload_tmp_dir  null  上传文件存放的临时路径,可以是一个绝对路径,这个目录对于拥有此服务进程用户必须是可写的,上传的文件在处理之前必须成功传输到服务器,所以必须指定一个位置,可以临时放置这些文件,直到文件移动到最终目录。

通过POST方法上传的文件有关信息都被存储在多维数组$_FILES中,这些信息对于通过PHP脚本上传到服务器的文件至关重要,因为文件上传后,首先存储于服务器的临时目录中,同时在PHP脚本中就会获取一个$_FILES全局数组。

$_FILES['myfile']['name'] 客户端机器文件的原名称,包含扩展名
$_FILES['myfile']['size'] 已上传文件大小
$_FILES['myfile']['tmp_name'] 文件上传后在服务器端的临时文件名
$_FILES['myfile']['error'] 文件上传产生的错误信息
$_FILES['myfile']['type'] 获取从客户端上传文件的MIME类型

上传文件时,除了可以应用PHP中所提供的文件系统函数外,PHP还提供了专门用于文件上传所使用is_uploaded_file()和move_uploaded_file()两个函数。

函数is_uploaded_file()

该函数判断指定的文件是否通过HTTPPOST上传的,如果是则返回true,用于防止潜在的攻击者对原本不能通过脚本交互的文件进行非法管理,这可以用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件,例如/etc/passwd,为了能使此函数正常工作,唯一的参数必须指定类似于$_FILES['myfile']['tmp_name']的变量,才能判断指定的文件确实是上传文件。

函数move_uploaded_file()

文件上传后,首先会存储在服务器的临时目录中,可以使用该函数将上传的文件移动到新位置,虽然函数copy()和函数move()也同样好用,但函数move_uploaded_file()还提供了一种额外的功能,检测并确保由第一个参数指定的文件,是否是合法的上传文件,如果合法,将其移动为由第二个参数指定的文件,如果不是合法的上传文件,不会出现任何操作,将返回false,成功返回true。

既然对上传文件有了基本的概念,就可以实现文件上传了,下面示例中,限制用户不能上传文件类型的文件,并将用户上传的文件从临时文件移动到指定目录,并改名。

<?php

if($_FILES['myfile']['error']>0){
switch($_FILES['myfile']['error']){
case 1:
echo "上传文件大小超过PHP配置文件中的约定值:upload_max_filesize";
break;
case 2:
echo "上传文件大小超过表单中的约定值:MAX_FILE_SIZE";
break;
case 3:
echo "文件只有部分上传";
break;
case 4:
echo "没有上传任何文件";
break;
}
exit;
}

list($maintype,$subtype) = explode('/',$_FILES['myfile']['name']);
if(is_uploaded_file($_FILES['myfile']['tmp_name'])){
if(!move_uploaded_file($_FILES['myfile']['tmp_name'],$upfile)){
echo "不能移动到指定目录";
exit;
}else{
echo "上传文件不合法";
echo $_FILES['myfile']['name']
exit;
}
}
echo "文件上传成功";

执行上例时,需要在当前目录创建一个upload目录,并且该目录必须具有web服务器进程用户可写的权限,还可以通过设置PHP配置文件中的指令调整上传文件的大小限制,以及通过上传文件的MIME类型或文件扩展名,控制上传文件的类型。

上一篇:文件指针ftell()、fseek()、rewind()
下一篇:PHP中cookie的设置与读取