文件上传一直都是PHP津津乐道的特色之一,相同的功能在ASP或JSP中实现,要手工编写很复杂的COM组件或JavaBeans(我们不得不一个字节一个字节的读取请求,然后将它们按照分隔符“&”和“=”解析成一个个变量,而这一切对于普通的查询参数来讲,都是由解释器代劳的),但在PHP中,这一切像接受普通的请求参数一样简单。提起上传,多数人最先想到的可能就是FTP,但事实上,无论是上传还是下载,HTTP都可以实现,只不过FTP的特色是像管理本地文件一样管理远程文件,而HTTP则侧重于超文本文件的直接显示。
要使用文件上传功能,还要关心一下php.ini文件中的几个选项设置,它们是:
file_uploads:布尔值,定义是否允许文件上传;
post_max_size:整数值,定义允许POST数据最大的字节数,由于文件数据是通过POST方法上传的,因此必须确保上传文件与其同一表单内的其它数据的总大小控制在该选项之内;
upload_max_filesize:整数值,定义允许上传文件最大的字节数;
upload_tmp_dir:字符串,定义存储上传文件的临时文件夹;
HTTP上传支持是使用HTML中的 <input type="file"> 表单元素实现的,符合RFC-1867标准的浏览器会将它解析成一个带有“浏览...”按钮的
路径输入文本框,点击“浏览...”按钮,将显示一个可以浏览本地文件的对话框。要想提供文件上传功能,首先要将 <form> 标签中的
enctype属性定义为“multipart/form-data”,还要将method属性定义为“post”(HTTP/1.1还提供了一种PUT方法来实现文件上传,不过该方法并不被IE等主流WEB浏览器所支持),否则,上传的将只是文件名字符串。
下面是一个典型的文件上传表单:
<form enctype="multipart/form-data" action="URL" method="post">
<input type="hidden" name="MAX_FILE_SIZE" value="1000">
上传这个文件:<input name="userfile" type="file">
<input type="submit" value="上传">
</form>
请注意代码中的几点细节,action属性的值“URL”只是个站位符,请将它替换成接收请求的文件名。另一个隐藏元素 <inputtype="hidden" name="MAX_FILE_SIZE" value="1000"> 限定了上传文件的大小(就好像 <input type="text" maxlength="20"> 中的maxLength属性限定了输入的长度),符合RFC-1867标准的浏览器应该能识别该选项并在文件尺寸溢出时给予提示,但由于是在客户端验证,所以其结果是不受信任的,换句话说,用户完全可以自己编写一个上传文件的客户端来跳过该验证。作为一个健壮的系统,应该使用服务器端验证。代码的最后,是一个名为userfile的文件上传控件。
当上述含有文件上传元素的表单被提交,文件将会一个字节一个字节的发送到服务器端,PHP解释器会自动将文件保存在php.ini文件中定义的临时目录下,如果出现命名冲突,PHP会自作主张的将其改成一个不会出现冲突的新名字,不过这个新名字会反馈给脚本的。
PHP中的文件上传支持被封装在了$_FILES数组中,当上面表单中的文件上传成功后,会自动生成以下变量(请注意,userfile是在上面的表单中定义的标识符):
$_FILES['userfile']['name']:客户端文件的原文件名;
$_FILES['userfile']['type']:文件的MIME类型,如:image/gif、text/paint等;
$_FILES['userfile']['size']:文件的尺寸(字节数);
$_FILES['userfile']['tmp_name']:服务器端文件的临时文件名,当读取文件时,应该使用该名称;
$_FILES['userfile']['error']:上传文件的错误码,从PHP2.0开始引入,0代表没有错误,1代表文件尺寸超过了php.ini文件中
upload_max_filesize选项的值,2代表文件尺寸超过了HTML代码中MAX_FILE_SIZE选项的值,3表示文件只有部分上传,4表示文件没有上传。
文件上传在WEB开发中具有很大的用途,例如,一些免费主机提供商(如国外的Brinkster)不支持FTP方式上传文件,则提供了HTTP上传的接口。这个接口如果使用PHP来开发,工作将变得非常轻松。另外,一些论坛贴图功能也使用了文件上传,这样,就可以让用户将本地文件贴到文章中了。不过一般来说,对于需要持久化保存的文件,为了方便管理及查询,一般将它们保存在数据库中的BLOB类型的字段中,至于怎样将文件保存在数据库中,以及怎样从数据库中输出,我将在以后详细论述。而对于PUT方法,由于其通用性较差(“通用性”这个概念代表不被微软帝国所支持),我就不再赘述了