综述
上一节我们学习了文件的读写操作,这一节我们来看一下文件上传和下载的相关内容。
文件上传
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
1
|
<input type="hidden" name="MAX_FILE_SIZE" value="100000000">
|
4)enctype=”multipart/form-data” 只有文件上传时才使用这个值,用来指定表单编码的数据方式,让服务器知道我们要传递一个文件并带有一些常规的表单信息。如下
1 2
|
<form action="upload.php" method="post" enctype="multipart/form-data"> </form>
|
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
<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 中如下
1 2 3 4 5 6
|
<?php echo "<pre>"; print_r($_POST); print_r($_FILES); echo "</pre>"; ?>
|
一个是输出 POST得到的数据内容,另一个是输出获取到的文件信息。 运行结果如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
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) 不会有任何输出 又比如多文件上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
<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需要不同的名字,那么上面的代码输出结果为
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
|
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设定为一个数组,如
1 2 3
|
shoppic: <input type="file" name="pic[]"> <br> shoppic: <input type="file" name="pic[]"> <br> shoppic: <input type="file" name="pic[]"> <br>
|
则输出会是一个三维数组
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
|
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)将上传后的文件名改名
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
|
<?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,让我们来感受一下吧!
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
|
<?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; } }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
<?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>';
|
1 2 3 4 5
|
<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>
|
1 2 3 4 5 6 7 8
|
<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>
|
利用上面的这个文件上传类,我们便可以轻松地实现文件上传,非常之便捷。
文件下载
对于浏览器无法直接打开的文件,我们一般只需要设置一下超链接就好了。比如
1
|
<a href="a.rar">a.rar</a>
|
点击超链接之后,便会弹出下载的提示框。 可是对于浏览器可以直接打开的文件,例如 1.html,2.php,3.gif 等等文件,如果仍然用这种超链接形式,那就行不通了,浏览器会直接跳转到这个页面。 我们怎样解决这个问题呢?很简单 我们首先要将超链接的文件名改为一个 php 文件,比如上面的链接就可以改为
1
|
<a href="a.php">logo.gif</a>
|
这样浏览器会去访问 a.php 文件,那么我们只需要在 a.php 文件中作相应处理即可,例如我们要下载 logo.gif 文件 我们就需要在 a.php 文件最开始设定头部信息,如下
1 2 3 4 5 6
|
<?php header("Content-Type:image/gif"); header('Content-Disposition: attachment; filename="logo.gif"'); header('Content-Length:300'); readfile("logo.gif"); ?>
|
一般设置三个头部信息就好了 第一个是设置文件传输的类型,第二个是设置传送的内容为附件形式,文件名是 logo.gif,这里的filename 即为我们下载文件时命名的名字,而不是文件名本身。第三个是设置文件传输大小。 最后设置一下下载的是哪个文件就好了。利用 readfile 方法。 以上便是文件下载所需要的方法。 这样,文件上传和文件下载的方法就全部介绍完啦!