上传原理
将客户端文件上传到服务器端,再将服务器端的文件(临时文件)移动到指定目录即可。
通过学习文件上传,你将透过使用的现象看到文件上传的本质!
1. 上传的实现
1. 1 客户端配置
选择文件上传页面(表单页面)
下面两个 条件 缺一不可:
( 1 ) 发送方式为POST
( 2 ) 添加enctype="multipart/form-data"属性
index.php代码如下:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no" />
<title>文件上传</title>
<meta charset="utf-8" />
</head>
<body>
<form action="upload.php" method="post" enctype="multipart/form-data" >
请选择您要上传的文件:<br/>
<input type="file" name="myFile" /><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
注:关键就是form的属性;另外就是input 中用到了type="file"这一点
1.2服务 端配置
处理 上传文件
处理 流程如下
1 ) 获得上传页面传递的$FILES
2 ) 将服务器的临时文件移动到指定位置
方法一:move_upload_file($tmp_name,$destination)
方法二:copy($src,$des)
注意:move相当于剪切;而copy则临时文件还在
3 ) 根据$error的值,提示不同信息 , 进行相应处理
upload.php代码如下:
<?php
header("Content-type:text/html;charset=utf-8");
//文件上传处理程序
//$_FILES:文件上传变量
$filename=$_FILES['myFile']['name'];
$type=$_FILES['myFile']['type'];
$tmp_name=$_FILES['myFile']['tmp_name'];
$size=$_FILES['myFile']['size'];
$error=$_FILES['myFile']['error'];
//将服务器上的临时文件移动到指定位置
//方法一move_upload_file($tmp_name,$destination)
//move_uploaded_file($tmp_name, "uploads/".$filename);//文件夹应提前建立好,不然报错
//方法二copy($src,$des)
//以上两个函数都是成功返回真,否则返回false
//copy($tmp_name, "copies/".$filename);
//注意,不能两个方法都对临时文件进行操作,临时文件似乎操作完就没了,我们试试反过来
copy($tmp_name, "copies/".$filename);
move_uploaded_file($tmp_name, "uploads/".$filename);
//能够实现,说明move那个函数基本上相当于剪切;copy就是copy,临时文件还在
//另外,错误信息也是不一样的,遇到错误可以查看或者直接报告给用户
if ($error===0) {
echo "上传成功!";
}else{
switch ($error){
case 1:
echo "超过了上传文件的最大值,请上传2M以下文件";
break;
case 2:
echo "上传文件过多,请一次上传20个及以下文件!";
break;
case 3:
echo "文件并未完全上传,请再次尝试!";
break;
case 4:
echo "未选择上传文件!";
break;
case 5:
echo "上传文件为0";
break;
}
}
?>
注:需要在upload.php的同级目录里新建一个uploads文件夹用于存放上传的图片,不然会报错 ; 上面的var_dump($_FILES);可以在测试时候对文件上传成功与否进行判断,如果成功上传,返回文件信息数组 , 如 :
array(1){
["myflie"]=>
array(5){
["name"]=>string(37)"xxxxxxxx.jpg"
["type"]=>string(10)"image/jpeg"
["tmp_name"]=>string(44)"C:\Users\win7\xxxxxx\xxxx\xxx\xxx.tmp
["error"]=>int(0)
["size"]=>int(13767)
}
}
得到是一个二维数组,关键有两个:tmp_name临时文件名;error报错信息(代号,后面可以利用);
报错原因
基本上都是超过或者不符合服务器关于上传文件的配置,那么服务器端配置有哪些呢?
先考虑上传我们用了什么?POST,upload
所以在php.ini中找这么几项:
file_upload:On
upload_tmp_dir=——临时文件保存目录;
upload_max_filesize=2M
max_file_uploads=20——允许一次上传的最大文件数量
post_max_size=8M——post方式发送数据的最大值
其他相关配置
max_exectuion_time=-1——最大执行时间,避免程序不好占用服务器资源;
max_input_time=60
max_input_nesting_level=64——输入嵌套深度;
memory_limit=128M——最大单线程的独立内存使用量
总之都是有关资源的配置
错误号
UPLOAD_ERR_OK 值:0; 没有错误发生,文件上传成功。
UPLOAD_ERR_INI_SIZE 值:1; 上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值。
UPLOAD_ERR_FORM_SIZE 值:2; 上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。
UPLOAD_ERR_PARTIAL 值:3; 文件只有部分被上传。
UPLOAD_ERR_NO_FILE 值:4; 没有文件被上传。
注:这个错误信息是第一步上传的信息,也就是上传到临时文件夹的情况,而不是move或者copy的情况。
下面从客户端和服务器端实现两个限制
客户端限制
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no" />
<title>文件上传(客户端限制)</title>
<meta charset="utf-8" />
</head>
<body>
<form action="upload2.php" method="post" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="101321" />
请选择您要上传的文件:
<input type="file" name="myFile" accept="image/jpeg,image/gif,text/html"/><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
这里用input的属性对上传文件的大小和类型进行了限制,但是个人感觉
1.html代码是“可见的”
2.常不起作用。
服务器端限制
<?php
header('content-type:text/html;charset=utf-8');
//接受文件,临时文件信息
$fileinfo=$_FILES["myFile"];//降维操作
$filename=$fileinfo["name"];
$tmp_name=$fileinfo["tmp_name"];
$size=$fileinfo["size"];
$error=$fileinfo["error"];
$type=$fileinfo["type"];
//服务器端设定限制
$maxsize=10485760;//10M,10*1024*1024
$allowExt=array('jpeg','jpg','png','tif');//允许上传的文件类型(拓展名
$ext=pathinfo($filename,PATHINFO_EXTENSION);//提取上传文件的拓展名
//目标存放文件夹
$path="uploads";
if (!file_exists($path)) { //当目录不存在,就创建目录
mkdir($path,0777,true);//创建目录
chmod($path, 0777);//改变文件模式,所有人都有执行权限、写权限、度权限
}
//得到唯一的文件名!防止因为文件名相同而产生覆盖
$uniName=md5(uniqid(microtime(true),true)).".$ext";//md5加密,uniqid产生唯一id,microtime做前缀
//目标存放文件地址
$destination=$path."/".$uniName;
//当文件上传成功,存入临时文件夹,服务器端开始判断
if ($error===0) {
if ($size>$maxsize) {
exit("上传文件过大!");
}
if (!in_array($ext, $allowExt)) {
exit("非法文件类型");
}
if (!is_uploaded_file($tmp_name)) {
exit("上传方式有误,请使用post方式");
}
//判断是否为真实图片(防止伪装成图片的病毒一类的
if (!getimagesize($tmp_name)) {//getimagesize真实返回数组,否则返回false
exit("不是真正的图片类型");
}
//move_uploaded_file($tmp_name, "uploads/".$filename);
if (@move_uploaded_file($tmp_name, $destination)) {//@错误抑制符,不让用户看到警告
echo "文件".$filename."上传成功!";
}else{
echo "文件".$filename."上传失败!";
}
}else{
switch ($error){
case 1:
echo "超过了上传文件的最大值,请上传2M以下文件";
break;
case 2:
echo "上传文件过多,请一次上传20个及以下文件!";
break;
case 3:
echo "文件并未完全上传,请再次尝试!";
break;
case 4:
echo "未选择上传文件!";
break;
case 7:
echo "没有临时文件夹";
break;
}
}
1.3 封装上传函数
<?php
//定义一个uploadFile函数
function uploadFile($fileInfo,$path,$allowExt,$maxSize){
//取出$_FILES中的数据
$filename=$fileInfo["name"];
$tmp_name=$fileInfo["tmp_name"];
$size=$fileInfo["size"];
$error=$fileInfo["error"];
$type=$fileInfo["type"];
//取出文件路径中文件的类型的部分
$ext=pathinfo($filename,PATHINFO_EXTENSION);
//确定是否存在存放图片的文件夹,没有则新建一个
if (!file_exists($path)) { //当目录不存在,就创建目录
mkdir($path,0777,true);//创建目录
chmod($path, 0777);//改变文件模式,所有人都有执行权限、写权限、度权限
}
//得到唯一的文件名!防止因为文件名相同而产生覆盖
$uniName=md5(uniqid(microtime(true),true)).'.'.$ext;
//目标存放文件地址
$destination=$path."/".$uniName;
//当文件上传成功,存入临时文件夹,服务器端开始判断
if ($error==0) {
if ($size>$maxSize) {
exit("上传文件过大!");
}
if (!in_array($ext, $allowExt)) {
exit("非法文件类型");
}
if (!is_uploaded_file($tmp_name)) {
exit("上传方式有误,请使用post方式");
}
//判断是否为真实图片(防止伪装成图片的病毒一类的
if (!getimagesize($tmp_name)) {//getimagesize真实返回数组,否则返回false
exit("不是真正的图片类型");
}
if (@move_uploaded_file($tmp_name, $destination)) {//@错误抑制符,不让用户看到警告
echo "文件".$filename."上传成功!";
}else{
echo "文件".$filename."上传失败!";
}
}else{
switch ($error){
case 1:
echo "超过了上传文件的最大值,请上传2M以下文件";
break;
case 2:
echo "上传文件过多,请一次上传20个及以下文件!";
break;
case 3:
echo "文件并未完全上传,请再次尝试!";
break;
case 4:
echo "未选择上传文件!";
break;
case 7:
echo "没有临时文件夹";
break;
}
}
return $destination;
}
表单采取之前的 , 然后提交处理文件如下
<?php
header('content-type:text/html;charset=utf-8');
//初始化相关变量
$fileInfo=$_FILES["myFile"];
$maxSize=10485760;//10M,10*1024*1024
$allowExt=array('jpeg','jpg','png','tif');
$path="uploads";
//引入前面封装了的上传函数fun_upload.php
include_once 'fun_upload.php';
uploadFile($fileInfo, $path, $allowExt, $maxSize);
?>
这样我们就能够通过引用函数文件使用这个函数,这个函数会返回文件的路径
所以我们可以
$url=uploadFile($fileInfo, $path, $allowExt, $maxSize);
1.4 实现多文件上传
表单如下
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no" />
<meta charset="utf-8" />
<title>多文件上传</title>
</head>
<body>
<form action="upload4.php" method="post" enctype="multipart/form-data">
请选择您要上传的文件:<input type="file" name="myFile1" /><br/>
请选择您要上传的文件:<input type="file" name="myFile2" /><br/>
请选择您要上传的文件:<input type="file" name="myFile3" /><br/>
请选择您要上传的文件:<input type="file" name="myFile4" /><br/>
<input type="submit" value="上传"/>
</form>
</body>
</html>
上传处理代码
<?php
//echo "<pre>";
//print_r($_FILES);
//echo "</pre>";
//exit;
header('content-type:text/html;charset=utf-8');
include_once 'fun_upload.php';
foreach ($_FILES as $fileInfo){
$file[]=uploadFile($fileInfo);
}
?>
将$_FILES打印出来,打印出来看到是个二维数组,很简单,遍历去用就好了!
封装好的上传函数需要修改一下,给一些默认值
function uploadFile($fileInfo,$path="uploads",$allowExt=
array('jpeg','jpg','png','tif'),$maxSize=10485760){.....}
具体封装代码如下
<?php
function uploadFile( $fileInfo,$path="uploads",$allowExt=array('jpeg','jpg','png','tif'),$maxSize=10485760
){
$filename=$fileInfo["name"];
$tmp_name=$fileInfo["tmp_name"];
$size=$fileInfo["size"];
$error=$fileInfo["error"];
$type=$fileInfo["type"];
//服务器端设定限制
$ext=pathinfo($filename,PATHINFO_EXTENSION);
//目的信息
if (!file_exists($path)) {
mkdir($path,0777,true);
chmod($path, 0777);
}
$uniName=md5(uniqid(microtime(true),true)).'.'.$ext;
$destination=$path."/".$uniName;
if ($error==0) {
if ($size>$maxSize) {
exit("上传文件过大!");
}
if (!in_array($ext, $allowExt)) {
exit("非法文件类型");
}
if (!is_uploaded_file($tmp_name)) {
exit("上传方式有误,请使用post方式");
}
//判断是否为真实图片(防止伪装成图片的病毒一类的
if (!getimagesize($tmp_name)) {//getimagesize真实返回数组,否则返回false
exit("不是真正的图片类型");
}
if (@move_uploaded_file($tmp_name, $destination)) {//@错误抑制符,不让用户看到警告
echo "文件".$filename."上传成功!";
}else{
echo "文件".$filename."上传失败!";
}
}else{
switch ($error){
case 1:
echo "超过了上传文件的最大值,请上传2M以下文件";
break;
case 2:
echo "上传文件过多,请一次上传20个及以下文件!";
break;
case 3:
echo "文件并未完全上传,请再次尝试!";
break;
case 4:
echo "未选择上传文件!";
break;
case 7:
echo "没有临时文件夹";
break;
}
}
return $destination;
}
?>
1.5 文件的下载
<?php
//获取传递过来的路径信息
$filename=$_GET['filename'];
//判断是否有值,没有则不执行下面的php语句
if($filename){
header("Content-Disposition:attachment;filename=download_$filename");
//Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。
//格式:content-disposition = "Content-Disposition" ":" disposition-type *( ";" disposition-parm
//Content-Disposition为属性名
//disposition-type是以什么方式下载,如attachment为以附件方式下载
//disposition-parm为默认保存时的文件名
readfile($filename);
exit;
}
?>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no" />
<title>文件下载</title>
<meta charset="utf-8" />
</head>
<body>
<a href="1.rar">下载1.rar</a>
<br />
<a href="1.jpg">下载1.jpg</a>
<br />
<a href="download.php?filename=1.jpg">通过程序下载1.jpg</a>
</body>
</html>
注:测试的时候,文件的同级目录下,必须存在1.rar、1.jpg,也可以通过修改路径,
改变到自己的文件想要的文件夹下面
代码解 读
有三个下载连接
一个对应图片(浏览器可以识别)
一个对应压缩文件(浏览器不可以识别)
最后一个还是图片,我们通过传递路径给当前页面,在页面顶端的php代码中实现当成一个附件打开或者保存