`

深入浅出PHP下的文件上传

 
阅读更多


来源:http://www.360weboy.com/php/upload.html

 

文件作为一种特殊的表单数据,通过http post请求方式提交至服务器的时候,php会生成一个$_FILES全局数组,相关的文件信息会存放在这个全局数组中。我将在这篇文章中通过一些示例代 码来阐述php下的文件上传,并且深入看下关于文件上传内部的实现机制,最后简单说下如何加强这方面的安全性!

文件上传

为了让客户端的用户能够上传文件,我们必须在用户界面中提供一个表单用于提交上传文件的请求。由于上传的文件是一种特殊数据,不同于其它的post数据,所以我们必须给表单设置一个特殊的编码:

1
<form action="upload.php" method="POST" enctype="multipart/form-data">

 

以上的enctype属性,你可能不太熟悉,因为这常常会被忽略掉。但是,如果http post请求中既有常规数据,又包含文件类数据的话,这个属性就应该显示加上,这样可以提高针对各种浏览器的兼容性。

接下来,我们得向表单中添加一个用于上传文件的字段:

1
<input type="file" name="attachment" />

上述文件字段在各种浏览器中可能表现会有所不同。对于大多数的浏览器,上述字段都会被渲染成一个文本框加上一个浏览按钮。这样,用户既可以自行输入 文件的路径到文本框中,也可以通过浏览按钮从本地硬盘上选择所要上传的文件。但是,在苹果的Safari中,貌似只能使用浏览这种方式。当然,你也可以自 定义这个上传框的样式,使它看起来比默认的样式优雅些。

下面,为了更好的阐述怎么样处理文件上传,举一个完整的例子。比如,以下一个表单允许用户向我的本地服务器上上传附件:

1
2
3
4
5
<p>请上传你的附件:</p>
<form action="upload.php" method="POST" enctype="multipart/form-data">
<input type="file" name="attachment" />
<input type="submit" value="上传附件" />
</form>

提示:可以通过php.ini中的upload_max_filesize来设置允许上传文件的最大值。另外,还有一个 post_max_size也可以用来设置允许上传的最大表单数据,具体意思就是表单中各种数据之和,所以你也可以通过设置这个字段来控制上传文件的最大 值。但是,注意后者的值必须大于前者,因为前者属于后者的一部分表单数据。

图1. 显示在在firefox中的上传表单

当这个表单提交的时候,http请求会被发送到upload.php。为了显示具体哪些信息可以在upload.php中使用,我在upload.php将其打印出来:

1
2
3
4
5
6
<?php

header('Content-Type: text/plain');
print_r($_FILES);

?>

下面来做个试验,假如我通过以上表单上传一个本博客的logo到我的本地服务器www.360weboy.me/upload.php,看看在upload.php中会输出什么信息:

1
2
3
4
5
6
7
8
9
10
11
12
Array
(
    [attachment] => Array
        (
            [name] => boy.jpg
            [type] => image/jpeg
            [tmp_name] => D:\xampp\tmp\php1168.tmp
            [error] => 0
            [size] => 11490
        )

)

以上就是文件上传后,在全局数组中的关于当前上传文件的所有信息。但是,我们是否能够保证这些信息是安全的,假如name或者其它信息被篡改过了呢?我们时刻需要对来自客户端的信息保持警惕!

具体的http请求的各个部分

为了更好的理解文件上传,我们必须核对下客户端发送的http请求中到底包含了那些具体的信息。先前我上传的附件是本博客的logo,因为是图片,不太适合我们做以上实验。所以,我重新上传一个test.text文本文件,其中具体包含了以下内容:

1
2
3
4
5
360weboy

360days

Life Of A Web Boy

Okay。现在我上传这个文本文件,在upload.php中会输出:

1
2
3
4
5
6
7
8
9
10
11
12
Array
(
    [attachment] => Array
        (
            [name] => test.txt
            [type] => text/plain
            [tmp_name] => D:\xampp\tmp\php51C0.tmp
            [error] => 0
            [size] => 40
        )

)

我们再来看下相关的浏览器发送的http post请求(一些可选的头部我省略了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /upload.php HTTP/1.1
Host: www.360weboy.me
Referer: http://www.360weboy.me/
multipart/form-data; boundary=---------------------------24464570528145
Content-Length: 234
 
-----------------------------24464570528145
Content-Disposition: form-data; name="attachment"; filename="test.txt"
Content-Type: text/plain

360weboy

360days

Life Of A Web Boy
-----------------------------24464570528145--

从上面的请求格式中有几个字段我们要关注下的,分别是name, filename以及Content-Type.它们分别表示上传文件框在form表单中的字段名-attachment,用户从本地硬盘中上传的文件名 – test.txt,以及上传的文件格式 – text/plain(代表文本文件)。然后,我们看到一行空行下面的,就是这个上传文件中的具体内容。

安全性的加强

为了加强文件上传中的安全性,我们需要检查下$_FILES全局数组中的tmp_name和size。为了确保tmp_name指向的文件确实是刚 刚用户在客户端上传的文件,而不是指向的类似/etc/passwd,可以使用php中的函数is_uploaded_file()来进行下判断:

1
2
3
4
5
6
7
8
9
<?php
 
$filename = $_FILES['attachment']['tmp_name'];
 
if (is_uploaded_file($filename)) {
    /* 是一个上传的文件. */
}
 
?>

某些情况下,用户上传文件后,可能会将上传成功的文件的内容显示给用户看下,那么上述代码的检查尤其重要。

另外一个需要检查的就是上传文件的mime-type, 也就是上述upload.php中输出数组的type字段。 我在第一个例子中上传的是一个图片,所以$_FILES['attachment']['type']的值为’image/jpeg’。 如果打算在服务器端只接受image/png, image/jpeg, image/gif, image/x-png 以及 image/p-jpeg这些mime-type的图片,可以用类似下面的代码了进行检查(只是举个例子,具体代码,比如报错等,应该遵循你的系统中的机 制):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$allow_mimes = array(
    'image/png',
    'image/x-png',
    'image/gif',
    'image/jpeg',
    'image/pjpeg'
);

$image = $_FILES['attachment'];

if(!in_array($image['type'], $allow_mimes)) {
    die('对不起, 你上传的文件格式不准确;我们只接受图片文件.');
}

// 继续处理上传的图片文件

正如你看到的,我们已经保准了文件的mime-type是符合服务器端的要求的。但是,这样是不是就可以防止恶意用户上传其它有害文件,还是不够 的,因为这个mime-type恶意用户是可以伪装的。 比如用户做了一张jpg图片,在图片的元数据中写入了一些恶意的php代码,然后保存为后缀名为php的文件。当这个恶意文件上传的时候,将顺利通过服务 器端对于mime-type的检查,被认为是一张图片,里面的危险的php代码将会被执行。具体的图片的元数据类似如下:

1
2
3
4
5
File name    : image.jpg
File size    : 182007 bytes
File date    : 2012:11:27 7:45:10
Resolution   : 1197 x 478
Comment      : <?php passthru($_POST['cmd']); __halt_compiler();

我们可以看到,在图片元数据的Comment字段中加入了php代码。所以,很显然,为了防止类似危险情况发生,还必须对上传文件的扩展名进行一次必要的检查。下面的代码对前面的检查Mime-type的代码进行了加强:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$allow_mimes = array(
    'image/png' => '.png',
    'image/x-png' => '.png',
    'image/gif' => '.gif',
    'image/jpeg' => '.jpg',
    'image/pjpeg' => '.jpg'
);

$image = $_FILES['attachment'];

if(!array_key_exists($image['type'], $allow_mimes )) {
    die('对不起, 你上传的文件格式不准确;我们只接受图片文件.');
}

// 获取略去后缀名的文件名:
$filename = substr($image['name'], 0, strrpos($image['name'], '.'));

// 添加后缀名
$filename .= $allow_mimes[$image['type']];

// 继续处理上传的文件

通过上述的代码,我们确保即使上传的图片的元文件中包含了php代码的话,图片文件会被重名为后缀名为图片格式的文件,所以其中的php代码也不会被执行了。上述代码对正常的上传的图片也不会有任何负面影响。

进行了上述的几步提高安全性的检查步骤后,如果你只是要把上传的文件保存到一个指定的目录中,那么就可以使用php的默认函数move_uploaded_file来实现了:

1
2
3
4
5
6
7
8
9
10
<?php
 
$tmp_filename = $_FILES['attachment']['tmp_name'];
$filename = '/path/to/attachment.txt';
 
if (move_uploaded_file(tmp_filename, $filename)) {
    /* $temp_filename 保存在临时目录中的上传文件, 然后成功将其保存到对应目录下的attachment.txt文件中. */
}
 
?>

你也许还要对上传文件的大小进行限制,那么你可以通过filesize函数来获取上传文件的大小,进行判断后做进一步处理,这具体就不在这将了,自己去折腾吧。

 

分享到:
评论

相关推荐

    PHP和MySQL.Web开发(原书第4版).一

    本书将PHP和MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySL的一班概念,而且对PHP和MySQL的Web应用做了比较全面的阐述。 注意:由于文件有198M而我只能上传小于50M大小文件,所以先传了1-...

    PHP动态网站开发实例教程(第2版_钱兆楼+刘万辉)资源48368

    《PHP动态网站开发实例教程(第2版)》是由钱兆楼和刘万辉两位专家共同编著的一本深入浅出的PHP学习书籍。这本书针对Web开发初学者和有一定基础的开发者,旨在通过实例教学,帮助读者掌握PHP动态网站开发的核心技术...

    PHP与MySQL.WEB开发(一)

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和 MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。由于文件过大无法一次上传,所以...

    PHP与MySQL.WEB开发(四)

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和 MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。由于文件过大无法一次上传,所以...

    PHP与MySQL.WEB开发(三)

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和 MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。由于文件过大无法一次上传,所以...

    PHP与MySQL WEB开发(原书第三版)part4

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。 本书是第3版,经过了全面的更新...

    php全 php书籍

    书中深入浅出地介绍了PHP的基础知识、核心概念以及实际应用,旨在为读者构建一个完整的PHP知识体系。 首先,从"第1-2章 初识PHP及环境搭建"开始,读者将了解到PHP的起源、发展及其在Web开发中的地位。这部分内容会...

    PHP与MySQL WEB开发(原书第三版)part3

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。 本书是第3版,经过了全面的更新...

    PHP与MySQL WEB开发(原书第三版)part2

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。 本书是第3版,经过了全面的更新...

    PHP与MySQL WEB开发(原书第三版)part1

    本书将PHP开发与MySQL应用相结合,分别对PHP和MySQL做了深入浅出的分析,不仅介绍PHP和MySQL的一般概念,而且对PHP和MySQL的Web应用做了较全面的阐述,并包括几个经典且实用的例子。 本书是第3版,经过了全面的更新...

    PHP经典实例 第3版_PDF电子书下载 高清 带索引书签目录

    《PHP经典实例 第3版》深入浅出地讲解了这些特性,并通过大量实例来演示如何在实际场景中应用。 书中可能涉及的知识点包括但不限于: 1. PHP基础语法:变量、数据类型、流程控制(如if/else、switch、for、while)...

    《细说PHP》配套源码.zip

    《细说PHP》是一本深入浅出的PHP编程教材,旨在帮助读者全面理解PHP语言,掌握实际开发中的技能。配套源码.zip文件包含了书中各个章节的实例代码,这对于学习者来说是一个宝贵的资源,可以直接运行、调试和研究,以...

    PHP与MySQL动态网站开发(第4版)--源代码

    《PHP与MySQL动态网站开发(第4版)》是一本深入浅出的IT技术书籍,专为想要掌握PHP和MySQL结合构建动态网站的读者而设计。作者Larry Ullman以其丰富的教学经验,详细阐述了如何利用这两种强大的工具来创建功能丰富的...

    PHP网络编程从入门到精通.rar

    本教程通过深入浅出的方式,引领读者探索PHP的奥秘,实现从新手到精通的转变。 首先,入门阶段,你将了解PHP的基础语法,包括变量、数据类型、控制结构(如条件语句和循环)、函数等核心概念。这些是任何编程语言的...

    韩顺平PHP从入门到精通笔记.zip

    韩顺平老师的"PHP从入门到精通笔记"深入浅出地介绍了PHP的基本概念和语法,帮助初学者快速掌握这门语言。 1. PHP安装与配置:学习如何在不同的操作系统上安装PHP环境,如Windows下的XAMPP或Linux下的LAMP套件,以及...

    [PHP开发宝典].刘欣等.扫描版

    以下是根据书名和描述可以推测出的一些...《PHP开发宝典》通过深入浅出的讲解,旨在培养读者的PHP实战能力,使他们能够运用PHP进行高效、安全的Web开发。如果你正在学习或工作中使用PHP,这本书将是你宝贵的参考资料。

    Zend PHP 5 Certification Study Guide

    这本书深入浅出地涵盖了PHP 5的核心概念、语法和技术,旨在帮助读者全面掌握PHP编程并顺利通过认证考试。 在PHP的世界里,Zend认证是衡量一个开发者技能水平的重要标准。它验证了开发者在PHP语言、Web应用开发以及...

    PHP帮助手册(中文版)

    此外,PHP支持面向对象编程,包括类的创建、继承、封装和多态,手册将深入浅出地解析这些概念。 **六、文件与目录操作** PHP提供了丰富的文件系统函数,如`fopen()`、`fwrite()`、`fclose()`用于读写文件,`mkdir()...

    PHP and MySQL Web Development(Fourth Edition)

    这本书深入浅出地介绍了如何利用这两种强大的开源技术来创建高效、安全且用户友好的Web应用程序。 PHP是一种广泛应用于服务器端的脚本语言,特别适合于Web开发。它能够嵌入到HTML中,使得网页具有动态交互性。本书...

Global site tag (gtag.js) - Google Analytics