综述
上一节我们学习了文件的读写操作,这一节我们来看一下文件上传和下载的相关内容。
文件上传
1.PHP 配置文件
首先,我们文件上传需要设定一下 php.ini 的配置文件。这是最基本的设置,如果这里设置不成功,那么代码写得再正确也没有用。基本的配置项目如下
file_uploads = on #文件上传开启 upload_max_filesize= 200M #文件上传的最大尺寸 upload_tmp_dir = c:/uploads/ #临时文件目录 post_max_size = 250M #POST 时最大尺寸,必须要大于 upload_max_filesize
2. 上传时注意事项
1) 文件上传操作表单提交方法必须为 post 2)文件上传时,input type 必须为 file 类型 3)文件上传的表单中,需要增加一个隐含内容,代码如下,value 的单位是 B
<input type ="hidden" name ="MAX_FILE_SIZE" value ="100000000">
4)enctype=”multipart/form-data” 只有文件上传时才使用这个值,用来指定表单编码的数据方式,让服务器知道我们要传递一个文件并带有一些常规的表单信息。如下
<form action ="upload.php" method ="post" enctype ="multipart/form-data" > </form >
例如
<html > <head > <title > File Uploads </title > </head > <body > <form action ="b.php" method ="post" enctype ="multipart/form-data" > shopname: <input type ="text" name ="shopname" > <br > shopprice: <input type ="text" name ="price" > <br > shopnum : <input type ="text" name ="num" > <br > shoppic: <input type ="file" name ="pic" > <br > <input type ="submit" name ="sub" value ="添加商品" > </form > </body > </html >
文件 a.php 表单提交到了 b.php 文件,在文件 b.php 中如下
<?php echo "<pre>" ; print_r($_POST); print_r($_FILES); echo "</pre>" ; ?>
一个是输出 POST 得到的数据内容,另一个是输出获取到的文件信息。 运行结果如下
Array ( [shopname] => abc [price] => abc [num] => add [sub] => 添加商品 ) Array ( [pic] => Array ( [name] => QPGF.dll [type] => application/qscall-plugin [tmp_name] => D:\wamp\tmp\phpC2C7.tmp [error] => 0 [size] => 199224 ) )
如果不加 enctype=”multipart/form-data” 那么 print_r ($_FILES) 不会有任何输出 又比如多文件上传
<html> <head> <title> File Uploads </title> </head> <body> <form action="b.php" method="post" enctype="multipart/form-data" > shopname: <input type ="text" name="shopname" > <br> shopprice: <input type ="text" name="price" > <br> shopnum : <input type ="text" name="num" > <br> shoppic: <input type ="file" name="pic1" > <br> shoppic: <input type ="file" name="pic2" > <br> shoppic: <input type ="file" name="pic3" > <br> <input type ="submit" name="sub" value="添加商品" > </form> </body> </html>
file 的 name 需要不同的名字,那么上面的代码输出结果为
Array ( [pic1] => Array ( [name] => libtcmalloc.dll [type] => application/qscall-plugin [tmp_name] => D:\wamp\tmp\phpE51E.tmp [error] => 0 [size] => 178232 ) [pic2] => Array ( [name] => libexpatw.dll [type] => application/qscall-plugin [tmp_name] => D:\wamp\tmp\phpE52E.tmp [error] => 0 [size] => 130104 ) [pic3] => Array ( [name] => AsyncTask.dll [type] => application/qscall-plugin [tmp_name] => D:\wamp\tmp\phpE52F.tmp [error] => 0 [size] => 84536 ) )
还可以将 name 设定为一个数组,如
shoppic: <input type ="file" name ="pic[]"> <br> shoppic: <input type ="file" name ="pic[]"> <br> shoppic: <input type ="file" name ="pic[]"> <br>
则输出会是一个三维数组
Array ( [pic] => Array ( [name] => Array ( [0 ] => libtcmalloc.dll [1 ] => libexpatw.dll [2 ] => QQProtect.dll ) [type] => Array ( [0 ] => application/qscall-plugin [1 ] => application/qscall-plugin [2 ] => application/qscall-plugin ) [tmp_name] => Array ( [0 ] => D:\wamp\tmp\phpA17D.tmp [1 ] => D:\wamp\tmp\phpA17E.tmp [2 ] => D:\wamp\tmp\phpA17F.tmp ) [error] => Array ( [0 ] => 0 [1 ] => 0 [2 ] => 0 ) [size] => Array ( [0 ] => 178232 [1 ] => 130104 [2 ] => 387128 ) ) )
3. 文件上传后的检查
加入上传的表单中文件的 name 是 pic,那么检查的四个方法如下: 1)使用 $_FILES [‘file’][‘error’] 检查错误 2)使用 $_FILES [‘file’][‘size’] 限制大小,单位是字节 3)使用 $_FILES [‘pic’][‘type’] 获取文件或站名,限制文件的类型 4)将上传后的文件名改名
<?php //step 1 使用$_FILES ['pic' ]["error" ] 检查错误 if ($_FILES ["pic" ]["error" ] > 0){ switch($_FILES ["pic" ]["error" ]) { case 1: echo "上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值<br>" ; break ; case 2: echo "上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值" ; break ; case 3: echo "文件只有部分被上传" ; break ; case 4: echo "没有文件被上传" ; break ; default: echo "末知错误" ; } exit ; } $maxsize =5000000; //50k //step 2 使用$_FILES ["pic" ]["size" ] 限制大小 单位字节 2M=2000000 if ($_FILES ["pic" ]["size" ] > $maxsize ) { echo "上传的文件太大,不能超过{$maxsize }字节" ; exit ; } //step 3 使用$_FILES ["pic" ]["type" ]或是文件的扩展名 限制类型 MIME image/gif image/png gif png jpg /* list($dl , $xl ) = explode("/" , $_FILES ["pic" ]["type" ]); if ($dl !="image" ){ echo "请上传一个图片,不充许其它类型文件" ; exit ; } */ $allowtype =array("png" , "gif" , "jpg" , "jpeg" ); $arr =explode("." , $_FILES ["pic" ]["name" ]); $hz =$arr [count($arr )-1]; if (!in_array($hz , $allowtype )){ echo "这是不充许的类型" ; exit ; } //step 4 将让传后的文件名改名 $filepath ="./uploads/" ; $randname =date("Y" ).date("m" ).date("d" ).date("H" ).date("i" ).date("s" ).rand(100, 999)."." .$hz ; //将临时位置的文件移动到指定的目录上即可 if (is_uploaded_file($_FILES ["pic" ]["tmp_name" ])){ if (move_uploaded_file($_FILES ["pic" ]["tmp_name" ], $filepath .$randname )){ echo "上传成功" ; }else { echo "上传失败" ; } }else { echo "不是一个上传文件" ; }
以上便实现了文件上传的检测,包括错误检测,文件大小检测,文件类型检测以及文件更名等等。
文件上传类
在上面的介绍中,我们没有将文件的上传做一个封装,不过,将文件上传个功能封装成一个类的确是一个不错的选择。下面便是一个实例 DEMO,让我们来感受一下吧!
<?php class FileUpload { private $filePath; private $allowType=array ('gif' , 'jpg' , 'png' , 'jpeg' ); private $maxSize=1000000 ; private $isRandName=true ; private $originName; private $tmpFileName; private $fileType; private $fileSize; private $newFileName; private $errorNum=0 ; private $errorMess="" ; function __construct ($options=array() ) { foreach ($options as $key=>$val){ if (!in_array($key,get_class_vars(get_class($this )))){ continue ; } $this ->setOption($key, $val); } } private function getError () { $str="上传文件<font color='red'>{$this->originName}</font>时出错:" ; switch ($this ->errorNum){ case 4 : $str .= "没有文件被上传" ; break ; case 3 : $str .= "文件只被部分上传" ; break ; case 2 : $str .= "上传文件超过了HTML表单中MAX_FILE_SIZE选项指定的值" ; break ; case 1 : $str .= "上传文件超过了php.ini 中upload_max_filesize选项的值" ; break ; case -1 : $str .= "不被充许的类型" ; break ; case -2 : $str .= "文件过大,上传文件不能超过{$this->maxSize}个字节" ; break ; case -3 : $str .= "上传失败" ; break ; case -4 : $str .= "建立存放上传文件目录失败,请重新指定上传目录" ; break ; case -5 : $str .= "必须指定上传文件的路径" ; break ; default : $str .= "末知错误" ; } return $str.'<br>' ; } private function checkFilePath () { if (empty ($this ->filePath)) { $this ->setOption('errorNum' , -5 ); return false ; } if (!file_exists($this ->filePath) || !is_writable($this ->filePath)){ if (!@mkdir($this ->filePath, 0755 )){ $this ->setOption('errorNum' , -4 ); return false ; } } return true ; } private function checkFileSize () { if ($this ->fileSize > $this ->maxSize){ $this ->setOPtion('errorNum' , '-2' ); return false ; }else { return true ; } } private function checkFileType () { if (in_array(strtolower($this ->fileType), $this ->allowType)) { return true ; }else { $this ->setOption('errorNum' , -1 ); return false ; } } private function setNewFileName () { if ($this ->isRandName){ $this ->setOption('newFileName' , $this ->proRandName()); } else { $this ->setOption('newFileName' , $this ->originName); } } private function proRandName () { $fileName=date("YmdHis" ).rand(100 ,999 ); return $fileName.'.' .$this ->fileType; } private function setOption ($key, $val) { $this ->$key=$val; } function uploadFile ($fileField) { echo $fileField; $return=true ; if (!$this ->checkFilePath()){ $this ->errorMess=$this ->getError(); return false ; } $name=$_FILES[$fileField]['name' ]; $tmp_name=$_FILES[$fileField]['tmp_name' ]; $size=$_FILES[$fileField]['size' ]; $error=$_FILES[$fileField]['error' ]; if (is_Array($name)){ $errors=array (); for ($i=0 ; $i<count($name); $i++){ if ($this ->setFiles($name[$i], $tmp_name[$i], $size[$i], $error[$i])){ if (!$this ->checkFileSize() || !$this ->checkFileType()){ $errors[]=$this ->getError(); $return=false ; } }else { $error[]=$this ->getError(); $return=false ; } if (!$return) $this ->setFiles(); } if ($return){ $fileNames=array (); for ($i=0 ; $i<count($name); $i++){ if ($this ->setFiles($name[$i], $tmp_name[$i], $size[$i], $error[$i])){ $this ->setNewFileName(); if (!$this ->copyFile()){ $errors=$this ->getError(); $return=false ; }else { $fileNames[]=$this ->newFileName; } } } $this ->newFileName=$fileNames; } $this ->errorMess=$errors; return $return; } else { if ($this ->setFiles($name, $tmp_name, $size, $error)){ if ($this ->checkFileSize() && $this ->checkFileType()){ $this ->setNewFileName(); if ($this ->copyFile()){ return true ; }else { $return=false ; } }else { $return=false ; } }else { $return=false ; } if (!$return) $this ->errorMess=$this ->getError(); return $return; } } private function copyFile () { if (!$this ->errorNum){ $filePath=rtrim($this ->filePath, '/' ).'/' ; $filePath.=$this ->newFileName; if (@move_uploaded_file($this ->tmpFileName, $filePath)) { return true ; }else { $this ->setOption('errorNum' , -3 ); return false ; } }else { return false ; } } private function setFiles ($name="" , $tmp_name='' , $size=0 , $error=0 ) { $this ->setOption('errorNum' , $error); if ($error){ return false ; } $this ->setOption('originName' , $name); $this ->setOption('tmpFileName' , $tmp_name); $arrStr=explode('.' , $name); $this ->setOption('fileType' , strtolower($arrStr[count($arrStr)-1 ])); $this ->setOption('fileSize' , $size); return true ; } function getNewFileName () { return $this ->newFileName; } function getErrorMsg () { return $this ->errorMess; } }
<?php require "FileUpload.class.php" ; $up=new FileUpload(array ('isRandName' =>true ,'allowType' =>array ('txt' , 'doc' , 'php' , 'gif' ),'filePath' =>'./uploads/' , 'maxSize' =>200000 )); echo '<pre>' ; if ($up->uploadFile('upload' )){ print_r($up->getNewFileName()); }else { print_r($up->getErrorMsg()); } echo '</pre>' ;
<form action="upload.php" method ="post" enctype="multipart/form-data"> <input type ="hidden" name ="MAX_FILE_SIZE" value ="100000000"> <input type ="file" name ="upload"> <br> <input type ="submit" name ="sub" value ="upload file"><br> </form>
<form action="upload.php" method ="post" enctype="multipart/form-data"> <input type ="hidden" name ="MAX_FILE_SIZE" value ="100000000"> <input type ="file" name ="upload[]"> <br> <input type ="file" name ="upload[]"> <br> <input type ="file" name ="upload[]"> <br> <input type ="file" name ="upload[]"> <br> <input type ="submit" name ="sub" value ="upload file"><br> </form>
利用上面的这个文件上传类,我们便可以轻松地实现文件上传,非常之便捷。
文件下载
对于浏览器无法直接打开的文件,我们一般只需要设置一下超链接就好了。比如
<a href="a.rar" >a .rar</a >
点击超链接之后,便会弹出下载的提示框。 可是对于浏览器可以直接打开的文件,例如 1.html,2.php,3.gif 等等文件,如果仍然用这种超链接形式,那就行不通了,浏览器会直接跳转到这个页面。 我们怎样解决这个问题呢?很简单 我们首先要将超链接的文件名改为一个 php 文件,比如上面的链接就可以改为
<a href ="a.php" > logo.gif</a >
这样浏览器会去访问 a.php 文件,那么我们只需要在 a.php 文件中作相应处理即可,例如我们要下载 logo.gif 文件 我们就需要在 a.php 文件最开始设定头部信息,如下
<?php header ("Content-Type:image/gif" ); header ('Content-Disposition: attachment; filename="logo.gif"' ); header ('Content-Length:300' ); readfile("logo.gif" ); ?>
一般设置三个头部信息就好了 第一个是设置文件传输的类型,第二个是设置传送的内容为附件形式,文件名是 logo.gif,这里的 filename 即为我们下载文件时命名的名字,而不是文件名本身。第三个是设置文件传输大小。 最后设置一下下载的是哪个文件就好了。利用 readfile 方法。 以上便是文件下载所需要的方法。 这样,文件上传和文件下载的方法就全部介绍完啦!