PHP强化之13 - 文件上传与下载

一、文件上传

将客户端文件上传到服务器端,再将服务器端的文件(临时文件)移动到指定目录即可。

1、form表单

文件的上传一般都是经过form表单来实现的。

1)标签enctype属性
表单中enctype="multipart/form-data"是用于设置表单的MIME编码。

默认情况,这个编码格式是application/x-www-form-urlencoded,不能用于文件上传;只有使用了multipart/form-data且提交方式为POST都能完整的传递文件数据。

2)MAX_FILE_SIZE 隐藏字段
MAX_FILE_SIZE 隐藏字段(单位为字节)必须放在文件输入字段之前,其值为接收文件的最大尺寸。这是对浏览器的一个建议,PHP 也会检查此项。
如:<input type="hidden" name="MAX_FILE_SIZE" value="101321" />

在浏览器端可以简单绕过此设置,不可信,因此不要指望用此特性来阻挡大文件。(不过鉴于友好性最好还是在表单中加上此项目,因为它可以避免用户在花时间等待上传大文件之后才发现文件过大上传失败的麻烦。)

3)通过accept属性限制上传文件类型
<input type='file' name='myfile' accept='文件的MIME类型' />
如:accept="image/gif, image/jpeg",如果不限制图像的格式,可以写为:accept="image/*"

accept 属性只能与<input type="file">配合使用。它规定能够通过文件上传进行提交的文件类型。(提示:请避免使用该属性,应该在服务器端验证文件上传。)

4)例子

<form action="upload.php" method="post" enctype="multipart/form-data">
  <input type="hidden" name="MAX_FILE_SIZE" value="101321" />
  请选择您要上传的文件:
  <input type="file" name="myfile" accept="image/*" /><br/>
  <input type="submit" value="上传"/>

5)一次选择多个文件

<input type="file" name="filename" multiple="multiple" />

2、全局变量 $_FILES

通过form表单上传文件后,在服务器端则需要使用全局数组$_FILES来获取文件信息。

1)$_FILES字段说明

  • $_FILES['myfile']['name']  为上传文件的原文件名
  • $_FILES['myfile']['type']  为上传文件的 MIME 类型
  • $_FILES['myfile']['size']  已上传文件的大小,单位为字节
  • $_FILES['myfile']['tmp_name']  文件被上传后在服务端储存的临时文件名
  • $_FILES['myfile']['error']  文件上传的错误代码

2)error字段说明

  • 0(UPLOAD_ERR_OK):没有错误发生,文件上传成功。
  • 1(UPLOAD_ERR_INI_SIZE):上传的文件超过了 php.ini 中upload_max_filesize 选项限制的值。
  • 2(UPLOAD_ERR_FORM_SIZE):上传文件的大小超过了 HTML 表单中MAX_FILE_SIZE 选项指定的值。
  • 3(UPLOAD_ERR_PARTIAL):文件只有部分被上传。
  • 4(UPLOAD_ERR_NO_FILE):没有文件被上传。
  • 5:上传文件大小为0。

3、服务器配置

在php.ini中可以对文件上传进行如下的配置:

file_uploads = On    ; Whether to allow HTTP file uploads.
;upload_tmp_dir =    ; Temporary directory for HTTP uploaded files (will use system default if not
upload_max_filesize = 2M   ; Maximum allowed size for uploaded files.
max_file_uploads = 20   ; Maximum number of files that can be uploaded via a single request
post_max_size = 8M   ; Maximum size of POST data that PHP will accept.

max_execution_time = 30   ; Maximum execution time of each script, in seconds
max_input_time = 60   ; Maximum amount of time each script may spend parsing request data. 
memory_limit = 128M   ; Maximum amount of memory a script may consume (128MB)

4、相关函数

1)is_uploaded_file
bool is_uploaded_file ( string $filename )
如果 filename 所给出的文件是通过 HTTP POST 上传的则返回 TRUE。这可以用来确保恶意的用户无法欺骗脚本去访问本不能访问的文件。
为了能使 is_uploaded_file() 函数正常工作,必段指定类似于 $_FILES['userfile']['tmp_name'] 的变量,而在从客户端上传的文件名 $_FILES['userfile']['name'] 不能正常运作。
is_uploaded_file ($_FILES['userfile']['tmp_name'] )

2)move_uploaded_file
bool move_uploaded_file ( string $filename , string $destination )
本函数检查并确保由 filename 指定的文件是合法的上传文件(即通过 PHP 的 HTTP POST 上传机制所上传的)。如果文件合法,则将其移动为由 destination 指定的文件。
Warning:如果目标文件已经存在,将会被覆盖!!

3)file_exists  检查文件或目录是否存在
4)is_writable   判断给定的文件名是否可写
5)iconv  字符编码互转
6)getimagesize  检查是否为图片文件(其他类型的文件就算后缀名改了也能被检测到)

5、服务器代码示例

header('content-type:text/html;charset=utf-8');
$fileinfo=$_FILES["myfile"];
$ext = pathinfo($fileinfo["name"],PATHINFO_EXTENSION);  //提取上传文件的拓展名

//服务器端设定限制
$max_size = 10485760;  //10M,10*1024*1024
$allow_ext = array('jpeg','jpg','png','gif');  //允许上传的文件类型(拓展名)
$path = "uploads";  //上传目录
if (!file_exists($path)) {   //当目录不存在,就创建目录
    mkdir($path,0777,true);
}

//得到唯一的文件名!防止因为文件名相同而产生覆盖
$uni_name=md5(uniqid(microtime(true),true)).$ext;  //md5加密,uniqid产生唯一id,microtime做前缀
$destination = "uploads/".$uni_name;


if ($fileinfo["error"] == 0) {
    if ($fileinfo["size"] > $maxsize) {
        exit("上传文件过大!");
    }
    if (!in_array($ext, $allow_ext )) {
        exit("非法文件类型");
    }
    if (!is_uploaded_file($fileinfo["tmp_name"])) {
        exit("上传方式有误,请使用post方式");
    }
    if (@move_uploaded_file($fileinfo["tmp_name"], $destination)) {
        echo "文件".$fileinfo["name"]."上传成功!";
    }else{
        echo "文件".$fileinfo["name"]."上传失败!";
    }
    //判断是否为真实图片(防止伪装成图片的病毒一类的
    if (!getimagesize($fileinfo["tmp_name"])) {  //getimagesize真实返回数组,否则返回false
        exit("不是真正的图片类型");
    }

}else{
    exit("文件上传失败$fileinfo['error']");
}

二、文件下载

通常文件下载过程是十分简单的,建立一个链接指向到目标文件就可以了。

1、触发下载

方法一:点击

<a href="download.php?filename=test.jpg">下载test.jpg</a>

方法二:重定向

Header("Location: http://www.xxx.com/xxx.rar");    

2、后端代码

$file_name = $_GET['filename'];     //下载文件名    
$file_dir = "uploads/";        //下载文件存放目录   
if (! file_exists ( $file_dir . $file_name )) {    
  exit ("文件找不到");  
}else{
  //打开文件    
  $file = fopen ( $file_dir . $file_name, "r" );

  Header ( "Content-type: application/octet-stream" );   //代表文件MIME类型是文件流格式。
  Header ( "Accept-Ranges: bytes" );    
  Header ( "Accept-Length: " . filesize ( $file_dir . $file_name ) );   
  //attachment是用来告诉浏览器,文件是可以当做附件被下载,下载后的文件名称为$file_name
  Header ( "Content-Disposition: attachment; filename=" . $file_name );  
  
  //读取文件内容并直接输出到浏览器    
  echo fread ( $file, filesize ( $file_dir . $file_name ) );    
  fclose ( $file );    
  exit();   
}

注意:在文件下载的页面要为纯php代码,除了需要下载的文件,不可以再有其它内容输出。否则会数据大小不一致,导致下载失败。

或者可以直接使用readfile函数:

header('content-disposition:attachment;filename='.basename($filename));
header('content-length:'.filesize($filename));
readfile($filename);

《THE END》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,029评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,238评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,576评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,214评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,324评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,392评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,416评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,196评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,631评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,919评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,090评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,767评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,410评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,090评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,328评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,952评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,979评论 2 351

推荐阅读更多精彩内容