Blogger Information
Blog 26
fans 0
comment 0
visits 21893
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
细说文件上传原理与实战
溪边小树
Original
1334 people have browsed it

文件上传

1. 文件上传配置

文件上传项目项在php.ini中设置,常用的配置项有:

序号 配置项 默认值 描述
1 file_uploads On 使 PHP 支持文件上传
2 upload_tmp_dir /tmp 指示应该临时把上传的文件存储在什么位置
3 max_file_uploads 20 单次请求时允许上传的最大文件数量
4 max_execution_time 30 设置 PHP 最长执行时间(秒)
5 max_input_time 60 设置 PHP 通过 POST/GET/PUT 接收数据的时长(秒)
6 memory_limit 128M 系统分配给当前脚本执行可用的最大内存容量
7 post_max_size 8M 允许的 POST 数据的总大小(以字节为单位)
8 upload_max_filesize 32M 允许的尽可能最大的文件上传(以字节为单位)

$_FILES

  • 上传文件的描述信息,全部保存在系统全局变量$_FILES
  • $_FILES以二维数组形式保存: $_FILES['form_file_name']['key']
  • 'form_file_name': 对应着表单中<input type="file" name="my_pic">name属性值
  • 'key': 共有 5 个键名, 描述如下:
序号 键名 描述
1 name 文件在客户端的原始文件名(即存在用户电脑上的文件名)
2 type 文件的 MIME 类型, 由浏览器提供, PHP 并不检查它
3 tmp_name 文件被上传到服务器上之后,在临时目录中临时文件名
4 error 和该文件上传相关的错误代码
5 size 已上传文件的大小(单位为字节)
  • 文件上传错误信息描述
序号 常量 描述
1 UPLOAD_ERR_OK 0 没有错误发生,文件上传成功
2 UPLOAD_ERR_INI_SIZE 1 文件超过php.iniupload_max_filesize
3 UPLOAD_ERR_FORM_SIZE 2 文件大小超过表单中MAX_FILE_SIZE指定的值
4 UPLOAD_ERR_PARTIAL 3 文件只有部分被上传
5 UPLOAD_ERR_NO_FILE 4 没有文件被上传
6 UPLOAD_ERR_NO_TMP_DIR 6 找不到临时文件夹
7 UPLOAD_ERR_CANT_WRITE 7 文件写入失败
  • 支持文件上传的前端表单设置
序号 属性设置 描述
1 <form method="POST"> 请求类型必须是POST
2 <form enctype="multipart/form-data"> 设置表单提交数据的编码类型
3 <input type="file" name="uploads"> 设置表单控件类型与名称以支持上传
4 <input type="hidden" name="MAX_FILE_SIZE" value="..."> 设置隐藏域限制上传文件大小(可选)
  • [扩展] enctype属性说明

enctype: 设置表单数据,在发送到服务器之前的编码规则

序号 属性值 描述
1 application/x-www-form-urlencoded 默认值, 发送前进行编码,空格转+,非空字符转 16 进制
2 multipart/form-data 不对字符编码,以二进制发送,适合文件上传
3 text/plain 纯文本发送,仅对空格编码(转为+)

4. MIME 类型

4.1 概述

  • MIME: (Multipurpose Internet Mail Extensions)的简写,中文意思”多功能因特网邮件扩展”
  • MIME: 最初用来表示 Email 附件格式的字符串, 后来演变成为网络文档或应用程序的文档格式规范
  • MIME: 由一个媒体类型一个子类组成, 中间用斜线/分隔,例如text/css

4.2 类型

序号 类型 描述 示例
1 text 文本 text/plain,text/html,text/css,text/javascript
2 image 图像 1 image/jpeg,image/gif,image/png,image/bmp,image/ webp,
2 image 图像 2 image/x-icon, image/vnd.microsoft.icon
3 audio 音频 audio/midi, audio/mpeg, audio/webm, audio/ogg, audio/wav
4 video 视频 video/mp4,video/mpeg,video/webm, video/ogg,video/x-msvideo
5 application 二进制 1 application/octet-stream, application/javascript, application/ecmascript
5 application 二进制 2 application/json,application/pkcs12, application/vnd.mspowerpoint
5 application 二进制 3 application/xhtml+xml, application/xml, application/pdf,application/x-gzip
  • 表中,以x-为前缀的是还没有成为国际标准的格式
  • 如果某个文档不在该列表中,会识别为: applicaton/octet-stream, 如.md文档, 尽管它是纯文本

示例演示

前期准备基本代码:

  1. <?php
  2. // 查看与文件上传相关的配置项
  3. phpinfo();
  4. //了解各配置项的基本信息
  5. -------------
  6. <?php
  7. // $_FILES
  8. printf('<pre>%s</pre>', print_r($_FILES, true));
  9. // 二维数组: 只有一个元素
  10. ?>
  11. <!DOCTYPE html>
  12. <html lang="en">
  13. <head>
  14. <meta charset="UTF-8">
  15. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  16. <title>文件上传变量$_FILES</title>
  17. </head>
  18. <body>
  19. <form action="" method="POST" enctype="multipart/form-data">
  20. <fieldset>
  21. <legend>单文件上传</legend>
  22. <input type="hidden" name="MAX_FILE_SIZE" value="500000">
  23. <input type="file" name="my_pic">
  24. <button>上传</button>
  25. </fieldset>
  26. </form>
  27. </body>
  28. </html>
  29. ---------------
  30. <?php
  31. // $_FILES
  32. printf('<pre>%s</pre>', print_r($_FILES, true));
  33. $errorCode = $_FILES['my_pic']['error'];
  34. if (UPLOAD_ERR_NO_FILE === $errorCode) echo '<p>没有文件被上传</p>';
  35. // if (empty($_FILES['my_pic']['name'])) echo '<p>没有文件被上传</p>'
  36. ?>
  37. <!DOCTYPE html>
  38. <html lang="en">
  39. <head>
  40. <meta charset="UTF-8">
  41. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  42. <title>文件上传变量$_FILES</title>
  43. </head>
  44. <body>
  45. <form action="" method="POST" enctype="multipart/form-data">
  46. <fieldset>
  47. <legend>单文件上传: 检查是否有文件被上传</legend>
  48. <input type="hidden" name="MAX_FILE_SIZE" value="500000">
  49. <input type="file" name="my_pic">
  50. <button>上传</button>
  51. </fieldset>
  52. </form>
  53. </body>
  54. </html>
  55. -----------
  56. <?php
  57. // $_FILES
  58. printf('<pre>%s</pre>', print_r($_FILES, true));
  59. // 检测当前文件是否是通过 HTTP POST 方式上传的
  60. $tmpFileName = $_FILES['my_pic']['tmp_name'];
  61. $originalFileName = $_FILES['my_pic']['name'];
  62. if (is_uploaded_file($tmpFileName)) echo "{$orginalFileName}: 上传方式合法";
  63. ?>
  64. <!DOCTYPE html>
  65. <html lang="en">
  66. <head>
  67. <meta charset="UTF-8">
  68. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  69. <title>文件上传变量$_FILES</title>
  70. </head>
  71. <body>
  72. <form action="" method="POST" enctype="multipart/form-data">
  73. <fieldset>
  74. <legend>单文件上传: 检查是否是通过POST上传?</legend>
  75. <input type="hidden" name="MAX_FILE_SIZE" value="500000">
  76. <input type="file" name="my_pic">
  77. <button>上传</button>
  78. </fieldset>
  79. </form>
  80. </body>
  81. </html>
  82. ----------------------
  83. <?php
  84. // $_FILES
  85. printf('<pre>%s</pre>', print_r($_FILES, true));
  86. // 获取文件类型
  87. $fileType = $_FILES['my_pic']['type'];
  88. // echo $fileType, '<br>';
  89. // print_r(explode('/',$fileType)[0]);
  90. // echo strstr($fileType, '/', true);
  91. // $allow = ['jpg', 'png', 'gif'];
  92. // $extension = pathinfo($_FILES['my_pic']['name'])['extension'];
  93. // echo $extension;
  94. // if (!in_array($extension, $allow)) echo '<p>文件类型错误</p>';
  95. if (strstr($fileType, '/', true) !== 'image') echo '<p>文件类型错误</p>';
  96. ?>
  97. <!DOCTYPE html>
  98. <html lang="en">
  99. <head>
  100. <meta charset="UTF-8">
  101. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  102. <title>文件上传变量$_FILES</title>
  103. </head>
  104. <body>
  105. <hr>
  106. <form action="" method="POST" enctype="multipart/form-data">
  107. <fieldset>
  108. <legend>单文件上传: 检测文件类型</legend>
  109. <input type="hidden" name="MAX_FILE_SIZE" value="500000">
  110. <input type="file" name="my_pic">
  111. <button>上传</button>
  112. </fieldset>
  113. </form>
  114. </body>
  115. </html>
  116. ------------
  117. <?php
  118. // $_FILES
  119. printf('<pre>%s</pre>', print_r($_FILES, true));
  120. // php.ini
  121. echo ini_get('upload_max_filesize');
  122. ini_set('upload_max_filesize', '10M');
  123. $errorCode = $_FILES['my_pic']['error'] ?? 'null';
  124. switch ($errorCode) {
  125. case 1:
  126. echo '文件超过`php.ini`中`upload_max_filesize`值';
  127. break;
  128. case 2:
  129. echo '文件大小超过表单隐藏域中`MAX_FILE_SIZE`指定的值 ';
  130. }
  131. ?>
  132. <!DOCTYPE html>
  133. <html lang="en">
  134. <head>
  135. <meta charset="UTF-8">
  136. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  137. <title>文件上传变量$_FILES</title>
  138. </head>
  139. <body>
  140. <hr>
  141. <form action="" method="POST" enctype="multipart/form-data">
  142. >
  143. <fieldset>
  144. <legend>单文件上传: 检测文件大小</legend>
  145. <input type="hidden" name="MAX_FILE_SIZE" value="3000000">
  146. <input type="file" name="my_pic">
  147. <button>上传</button>
  148. </fieldset>
  149. </form>
  150. </body>
  151. </html>

单文件上传示例:

文件上传正常:

文件上传异常:

  1. <?php
  2. // $_FILES
  3. printf('<pre>%s</pre>', print_r($_FILES, true));
  4. // 自定义上传异常类
  5. class UploadException extends Exception
  6. {
  7. // 在异常子类中,可以访问并重写Exception中的四个属性,通过__toString()格式化异常输出信息
  8. public function __toString()
  9. {
  10. return <<< UPLOAD
  11. <style>
  12. table {border-collapse: collapse;border:1px solid black;text-align: center;}
  13. td {border:1px solid black;padding: 5px;}
  14. tr:first-of-type {background-color:#eee;}
  15. tr:last-of-type td {color: coral;}
  16. </style>
  17. <table>
  18. <tr><td>代码</td><td>信息</td><td>文件</td><td>行号</td></tr>
  19. <tr><td>$this->code</td><td>$this->message</td><td>$this->file</td><td>$this->line</td></tr>
  20. </table>
  21. UPLOAD;
  22. }
  23. }
  24. ///////////////////////////////////////////////////////////////////////
  25. try {
  26. // 上传出错的代码
  27. $errorCode = $_FILES['my_pic']['error'];
  28. if ($errorCode > UPLOAD_ERR_OK) {
  29. switch ($errorCode) {
  30. case UPLOAD_ERR_INI_SIZE:
  31. throw new UploadException('上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值', 1);
  32. break;
  33. case UPLOAD_ERR_FORM_SIZE:
  34. throw new UploadException('上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值', 2);
  35. break;
  36. case UPLOAD_ERR_PARTIAL:
  37. throw new UploadException('文件只有部分被上传', 3);
  38. break;
  39. case UPLOAD_ERR_NO_FILE:
  40. throw new UploadException('没有文件被上传', 4);
  41. break;
  42. case UPLOAD_ERR_NO_TMP_DIR:
  43. throw new UploadException('找不到临时文件夹', 6);
  44. break;
  45. case UPLOAD_ERR_CANT_WRITE:
  46. throw new UploadException('文件写入失败', 7);
  47. break;
  48. default:
  49. // 测试时建议关掉default: 避免误报影响
  50. throw new UploadException('未知类型错误', 8);
  51. }
  52. }
  53. // 判断文件类型
  54. $fileType = $_FILES['my_pic']['type'];
  55. if (strstr($fileType, '/', true) !== 'image') throw new UploadException('文件类型错误',9);
  56. // 将文件从临时目录 移动到用户自定义的目标目录中
  57. // 临时文件名
  58. $tempFileName = $_FILES['my_pic']['tmp_name'];
  59. if (is_uploaded_file($tempFileName)) {
  60. // 原始文件名
  61. $originalFileName = $_FILES['my_pic']['name'];
  62. // 目录文件名
  63. $destFileName = 'uploads/'.md5(time().mt_rand(1,1000)).strstr($originalFileName, '.');
  64. // 移动文件到目标目录使用的函数
  65. if (move_uploaded_file($tempFileName, $destFileName)) {
  66. echo "<p>$originalFileName: 上传成功~~</p>";
  67. // 预览
  68. echo "<img src='{$destFileName}' width='200'>";
  69. }
  70. }
  71. } catch (UploadException $e) {
  72. echo $e;
  73. }
  74. ?>
  75. <!DOCTYPE html>
  76. <html lang="en">
  77. <head>
  78. <meta charset="UTF-8">
  79. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  80. <title>文件上传变量$_FILES</title>
  81. </head>
  82. <body>
  83. <hr>
  84. <form action="" method="POST" enctype="multipart/form-data">
  85. <fieldset>
  86. <legend>单文件上传: 异常处理</legend>
  87. <input type="hidden" name="MAX_FILE_SIZE" value="3000000">
  88. <input type="file" name="my_pic">
  89. <button>上传</button>
  90. </fieldset>
  91. </form>
  92. </body>
  93. </html>

多文件上传示例一:

  1. <?php
  2. // $_FILES
  3. printf('<pre>%s</pre>', print_r($_FILES, true));
  4. // 将异常处理先省略,只演示关键代码
  5. foreach ($_FILES as $file) {
  6. // 只要判断 error === 0
  7. if ($file['error'] === 0) {
  8. $destFile = 'uploads/' . $file['name'];
  9. move_uploaded_file($file['tmp_name'], $destFile);
  10. echo "<img src='{$destFile}' width='200'>";
  11. }
  12. }
  13. ?>
  14. <!DOCTYPE html>
  15. <html lang="en">
  16. <head>
  17. <meta charset="UTF-8">
  18. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  19. <title>文件上传变量$_FILES</title>
  20. </head>
  21. <body>
  22. <hr>
  23. <form action="" method="POST" enctype="multipart/form-data">
  24. <fieldset>
  25. <legend>多文件上传: 逐个上传(一)</legend>
  26. <input type="hidden" name="MAX_FILE_SIZE" value="3000000">
  27. <input type="file" name="my_pic1">
  28. <input type="file" name="my_pic2">
  29. <input type="file" name="my_pic3">
  30. <button>上传</button>
  31. </fieldset>
  32. </form>
  33. </body>
  34. </html>

多文件上传示例二:

  1. <?php
  2. // $_FILES
  3. printf('<pre>%s</pre>', print_r($_FILES, true));
  4. // 将异常处理先省略,只演示关键代码
  5. if ($_FILES['my_pic'])
  6. foreach ($_FILES['my_pic']['error'] as $key => $error) {
  7. // 只要判断 error === 0
  8. if ($error === UPLOAD_ERR_OK) {
  9. // 临时文件名
  10. $tmpFileName = $_FILES['my_pic']['tmp_name'][$key];
  11. // 原始文件名
  12. $originalFileName = $_FILES['my_pic']['name'][$key];
  13. // 目标文件名
  14. $destFileName = 'uploads/'. $originalFileName;
  15. // 移动文件
  16. move_uploaded_file($tmpFileName, $destFileName);
  17. // 预览
  18. echo "<img src='{$destFileName}' width='200'>";
  19. }
  20. }
  21. ?>
  22. <!DOCTYPE html>
  23. <html lang="en">
  24. <head>
  25. <meta charset="UTF-8">
  26. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  27. <title>文件上传变量$_FILES</title>
  28. </head>
  29. <body>
  30. <hr>
  31. <form action="" method="POST" enctype="multipart/form-data">
  32. <fieldset>
  33. <legend>多文件上传: 逐个上传(二)</legend>
  34. <input type="hidden" name="MAX_FILE_SIZE" value="3000000">
  35. <!-- 将name属性值能数组的形式提供 -->
  36. <input type="file" name="my_pic[]">
  37. <input type="file" name="my_pic[]">
  38. <input type="file" name="my_pic[]">
  39. <button>上传</button>
  40. </fieldset>
  41. </form>
  42. </body>
  43. </html>

批量文件上传示例:

  1. <?php
  2. // $_FILES
  3. printf('<pre>%s</pre>', print_r($_FILES, true));
  4. // 将异常处理先省略,只演示关键代码
  5. if ($_FILES['my_pic'])
  6. foreach ($_FILES['my_pic']['error'] as $key => $error) {
  7. // 只要判断 error === 0
  8. if ($error === UPLOAD_ERR_OK) {
  9. // 临时文件名
  10. $tmpFileName = $_FILES['my_pic']['tmp_name'][$key];
  11. // 原始文件名
  12. $originalFileName = $_FILES['my_pic']['name'][$key];
  13. // 目标文件名
  14. $destFileName = 'uploads/'. $originalFileName;
  15. // 移动文件
  16. move_uploaded_file($tmpFileName, $destFileName);
  17. // 预览
  18. echo "<img src='{$destFileName}' width='200'>";
  19. }
  20. }
  21. ?>
  22. <!DOCTYPE html>
  23. <html lang="en">
  24. <head>
  25. <meta charset="UTF-8">
  26. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  27. <title>文件上传变量$_FILES</title>
  28. </head>
  29. <body>
  30. <hr>
  31. <form action="" method="POST" enctype="multipart/form-data">
  32. <fieldset>
  33. <legend>多文件上传: 批量上传</legend>
  34. <input type="hidden" name="MAX_FILE_SIZE" value="3000000">
  35. <!-- 将name属性值能数组的形式提供 -->
  36. <input type="file" name="my_pic[]" multiple>
  37. <button>上传</button>
  38. </fieldset>
  39. </form>
  40. </body>
  41. </html>

课程学习小结

本次课程老师讲解非常细致,在老师的直播讲解之后,又通过回看视频进行理解消化,在案例实操方面,老师由浅入深,从基本必备知识开始演示,通过单个文件上传、多个文件上传(列举了两种不同的实现方式)到批量文件上传,涵盖了几乎所有日常可能使用到的情况,并且融入了文件类型检查,异常处理等实现方式,使得代码更加健壮,通过对各个示例代码的认真理解及部分修改实践,加深对本次课程内容的理解。在实际应用系统中,文件上传是非常重要的功能,必须熟练掌握。

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:因为太重要了, 所以讲解的非常细致.... 因为不少项目就靠上传就可以完成许多功能, 例如开发一个在线网盘项目, 基本上就靠这个了
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post