Table of Contents
RFC1867
表单提交
接受上传
Home Backend Development PHP Tutorial PHP 文件上传源码分析(RFC1867)_php技巧

PHP 文件上传源码分析(RFC1867)_php技巧

May 17, 2016 am 09:29 AM
php File Upload

你总不至于在用户要上传头像的时候告诉用户”请打开FTP客户端,上传文件到http://www.jb51.net/uploads/中, 并以2dk433423l.jpg命名”吧?

而基于HTTP的上传,相对来说易用性和安全性上就比FTP要增强了很多. 可以应用的上传方式有PUT, WEBDAV, 和RFC1867三种, 本文将分析在PHP中,是如何基于RFC1867实现文件上传的.

RFC1867

RCF1867是Form-based File Upload in HTML标准协议, RFC1867标准对HTML做出了两处修改:
 

1 为input元素的type属性增加了一个file选项。<br>2 input标记可以具有accept属性,该属性能够指定可被上传的文件类型或文件格式列表。<br>
Copy after login

  
另外,本标准还定义了一种新的mime类型:multipart/form-data,以及当处理一个带有enctype=”multipart/form-data” 并且/或含有的标记的表单时所应该采取的行为。
  
举例来说,当HTML想让用户能够上传一个或更多的文件时,他可以这么写:

Copy after login
Copy after login

选择文件:

文件描述:



这个表单, 大家一定不陌生, 而对于PHP来说, 它自己另外定义了一个默认表单元素MAX_FILE_SIZE, 用户可以通过这个隐藏的表单元素来建议PHP最多只容许上传文件的大小, 比如对于上面的例子, 我们希望用户上传的文件不能大于5000(5k)字节, 那么可以如下写:

Copy after login
Copy after login


选择文件:

文件描述:



姑且不说, 这个MAX_FILE_SIZE是多么的不可靠(所以基于浏览器的控制,都是不可靠的), 单纯从实现来讲, 我会慢慢介绍这个MAX_FILE_SIZE是如何起作用的.

当用户选择了一个文件(laruence.txt), 并填写好文件描述(”laruence的个人介绍”), 点击上传后, 发生了什么呢?

表单提交

在用户确定提交以后, 浏览器会发送如下类似格式的数据包到form中action属性指定的页面(在本例中是upload.php):

//请求头<br>POST /upload.php HTTP/1.0\r\n<br>...<br>Host: www.laruence.com\r\n<br>...<br>Content-length: xxxxx\r\n<br>...<br>Content-type: multipart/form-data, boundary=--------------7d51863950254\r\n<br>...\r\n\r\n<br>//开始POST数据内容<br>---------------7d51863950254<br>content-disposition: form-data; name="description"<br>laruence的个人介绍<br>---------------7d51863950254<br>content-disposition: form-data; name="userfile"; filename="laruence.txt"<br>Content-Type: text/plain<br>... laruence.txt 的内容...<br>---------------7d51863950254<br>
Copy after login

接下来, 就是服务器, 是如何处理这些数据了.

接受上传

当Web服务器, 此处假设为Apache(另外假设PHP是以module方式安装在Apache上的), 接受到用户的数据时, 首先它根据HTTP请求头, 通过确定MIME TYPE为PHP类型, 然后经过一些过程以后(这部分,可以参看我之前的PHP Life Cycle ppt), 最终会把控制权交给PHP模块.

这个时候, PHP会调用sapi_activate来初始化一个请求, 在这个过程中, 首先判断请求类型, 此时是POST, 从而去调用sapi_read_post_data, 通过Content-type, 找到rfc1867的处理函数rfc1867_post_handler, 从而调用这个handler, 来分析POST来的数据.

关于rfc1867_post_handler这部分的源代码, 可以在mian/rfc1867.c找到, 另外也可以参看我之前的深入理解PHP之文件上传, 其中也列出的源代码.

然后, PHP通过boundary, 对于每一个分段, 都通过检查, 是否同时定义了:

 name和filename属性(有名文件上传)<br> 没有定义name定义了filename(无名上传)<br> 定义了name没有定义filename(普通数据),<br>
Copy after login

从而进行不同的处理.

if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {<br> char *pair=NULL;<br> int end=0;<br><br> while (isspace(*cd)) {<br> ++cd;<br> }<br><br> while (*cd && (pair = php_ap_getword(&cd, ';')))<br> {<br> char *key=NULL, *word = pair;<br><br> while (isspace(*cd)) {<br> ++cd;<br> }<br><br> if (strchr(pair, '=')) {<br> key = php_ap_getword(&pair, '=');<br><br> if (!strcasecmp(key, "name")) {<br> //获取name字段<br> if (param) {<br> efree(param);<br> }<br> param = php_ap_getword_conf(&pair TSRMLS_CC);<br> } else if (!strcasecmp(key, "filename")) {<br> //获取filename字段<br> if (filename) {<br> efree(filename);<br> }<br> filename = php_ap_getword_conf(&pair TSRMLS_CC);<br> }<br> }<br> if (key) {<br> efree(key);<br> }<br> efree(word);<br> }<br>
Copy after login

在这个过程中, PHP会去检查普通数据中,是否有MAX_FILE_SIZE.

 /* Normal form variable, safe to read all data into memory */<br>if (!filename && param) {<br> unsigned int value_len;<br> char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);<br> unsigned int new_val_len; /* Dummy variable */<br> ......<br><br> if (!strcasecmp(param, "MAX_FILE_SIZE")) {<br> max_file_size = atol(value);<br> }<br><br> efree(param);<br> efree(value);<br> continue;<br>}<br>
Copy after login

有的话, 就会按照它的值来检查文件大小是否超出.

if (PG(upload_max_filesize) > 0 && total_bytes > PG(upload_max_filesize)) {<br> cancel_upload = UPLOAD_ERROR_A;<br>} else if (max_file_size && (total_bytes > max_file_size)) {<br>#if DEBUG_FILE_UPLOAD<br> sapi_module.sapi_error(E_NOTICE,<br> "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved",<br> max_file_size, param, filename);<br>#endif<br> cancel_upload = UPLOAD_ERROR_B;<br>}<br>
Copy after login

通过上面的代码,我们也可以看到, 判断分为俩部, 第一部分是检查PHP默认的上传上限. 第二部分才是检查用户自定义的MAX_FILE_SIZE, 所以表单中定义的MAX_FILE_SIZE并不能超过PHP中设置的最大上传文件大小.

通过对name和filename的判断, 如果是文件上传, 会根据php的设置, 在文件上传目录中创建一个随机名字的临时文件:

 if (!skip_upload) {<br> /* Handle file */<br> fd = php_open_temporary_fd_ex(PG(upload_tmp_dir),<br> "php", &temp_filename, 1 TSRMLS_CC);<br> if (fd==-1) {<br> sapi_module.sapi_error(E_WARNING,<br> "File upload error - unable to create a temporary file");<br> cancel_upload = UPLOAD_ERROR_E;<br> }<br>}<br>
Copy after login

返回文件句柄, 和临时随机文件名.

之后, 还会有一些验证,比如文件名合法, name合法等.

如果这些验证都通过, 那么就把内容读入, 写入到这个临时文件中.

.....<br>else if (blen > 0) {<br> wlen = write(fd, buff, blen); //写入临时文件.<br> if (wlen == -1) {<br> /* write failed */<br>#if DEBUG_FILE_UPLOAD<br> sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));<br>#endif<br> cancel_upload = UPLOAD_ERROR_F;<br> }<br>}<br>....<br>
Copy after login

当循环读入完成后, 关闭临时文件句柄. 记录临时变量名:

zend_hash_add(SG(rfc1867_uploaded_files), temp_filename,<br> strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);<br>
Copy after login

并且生成FILE变量, 这个时候, 如果是有名上传, 那么就会设置:

$_FILES['userfile'] //name="userfile"<br>
Copy after login

如果是无名上传, 则会使用tmp_name来设置:

$_FILES['tmp_name'] //无名上传<br>
Copy after login

最终交给用户编写的upload.php处理.

这时在upload.php中, 用户就可以通过move_uploaded_file来操作刚才生成的文件了~

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1664
14
PHP Tutorial
1269
29
C# Tutorial
1248
24
Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

PHP Program to Count Vowels in a String PHP Program to Count Vowels in a String Feb 07, 2025 pm 12:12 PM

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

Explain late static binding in PHP (static::). Explain late static binding in PHP (static::). Apr 03, 2025 am 12:04 AM

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are PHP magic methods (__construct, __destruct, __call, __get, __set, etc.) and provide use cases? What are PHP magic methods (__construct, __destruct, __call, __get, __set, etc.) and provide use cases? Apr 03, 2025 am 12:03 AM

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.

PHP and Python: Comparing Two Popular Programming Languages PHP and Python: Comparing Two Popular Programming Languages Apr 14, 2025 am 12:13 AM

PHP and Python each have their own advantages, and choose according to project requirements. 1.PHP is suitable for web development, especially for rapid development and maintenance of websites. 2. Python is suitable for data science, machine learning and artificial intelligence, with concise syntax and suitable for beginners.

PHP in Action: Real-World Examples and Applications PHP in Action: Real-World Examples and Applications Apr 14, 2025 am 12:19 AM

PHP is widely used in e-commerce, content management systems and API development. 1) E-commerce: used for shopping cart function and payment processing. 2) Content management system: used for dynamic content generation and user management. 3) API development: used for RESTful API development and API security. Through performance optimization and best practices, the efficiency and maintainability of PHP applications are improved.

PHP: A Key Language for Web Development PHP: A Key Language for Web Development Apr 13, 2025 am 12:08 AM

PHP is a scripting language widely used on the server side, especially suitable for web development. 1.PHP can embed HTML, process HTTP requests and responses, and supports a variety of databases. 2.PHP is used to generate dynamic web content, process form data, access databases, etc., with strong community support and open source resources. 3. PHP is an interpreted language, and the execution process includes lexical analysis, grammatical analysis, compilation and execution. 4.PHP can be combined with MySQL for advanced applications such as user registration systems. 5. When debugging PHP, you can use functions such as error_reporting() and var_dump(). 6. Optimize PHP code to use caching mechanisms, optimize database queries and use built-in functions. 7

The Enduring Relevance of PHP: Is It Still Alive? The Enduring Relevance of PHP: Is It Still Alive? Apr 14, 2025 am 12:12 AM

PHP is still dynamic and still occupies an important position in the field of modern programming. 1) PHP's simplicity and powerful community support make it widely used in web development; 2) Its flexibility and stability make it outstanding in handling web forms, database operations and file processing; 3) PHP is constantly evolving and optimizing, suitable for beginners and experienced developers.

See all articles