博客列表 >PHP基础-文件上传

PHP基础-文件上传

岂几岂几
岂几岂几原创
2020年05月13日 01:08:04568浏览

文件上传实战案例

1. 页面

  1. 单文件上传页面
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>单个文件上传</title>
  7. <style>
  8. @import url("style/style.css");
  9. </style>
  10. </head>
  11. <body>
  12. <form action="doBusiness.php" method="post" enctype="multipart/form-data">
  13. <section class="upload-box">
  14. <div class="upload-title">
  15. <span>请选择需要上传的文件</span>
  16. </div>
  17. <div class="upload-content">
  18. <div class="upload-item">
  19. <!-- 隐藏域限制文件大小为约256K -->
  20. <input type="hidden" name="MAX_FILE_SIZE" value="256000">
  21. <input type="file" name="single" id="single" />
  22. </div>
  23. <div class="upload-item">
  24. <p>文件大小限制: 256KB</p>
  25. </div>
  26. <div class="upload-item">
  27. <button type="submit">上传</button>
  28. </div>
  29. </div>
  30. </section>
  31. </form>
  32. </body>
  33. </html>

效果图:

  1. 多文件上传(文件域name属性值不同)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>多文件上传(一)</title>
  7. <style>
  8. @import url("style/style.css");
  9. </style>
  10. </head>
  11. <body>
  12. <form action="doBusiness.php" method="post" enctype="multipart/form-data">
  13. <section class="upload-box">
  14. <div class="upload-title">
  15. <span>请选择需要上传的文件</span>
  16. </div>
  17. <div class="upload-content">
  18. <!-- 隐藏域限制文件大小为约256K -->
  19. <input type="hidden" name="MAX_FILE_SIZE" value="256000">
  20. <div class="upload-item">
  21. <input type="file" name="file1" id="file1" />
  22. </div>
  23. <div class="upload-item">
  24. <input type="file" name="file2" id="file2" />
  25. </div>
  26. <div class="upload-item">
  27. <input type="file" name="file3" id="file3" />
  28. </div>
  29. <div class="upload-item">
  30. <input type="file" name="file4" id="file4" />
  31. </div>
  32. <div class="upload-item">
  33. <p>文件大小限制: 256KB</p>
  34. </div>
  35. <div class="upload-item">
  36. <button type="submit">上传</button>
  37. </div>
  38. </div>
  39. </section>
  40. </form>
  41. </body>
  42. </html>

效果图:

  1. 多文件上传(文件域的name属性值相同)
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>单个文件上传(二)</title>
  7. <style>
  8. @import url("style/style.css");
  9. </style>
  10. </head>
  11. <body>
  12. <form action="doBusiness.php" method="post" enctype="multipart/form-data">
  13. <section class="upload-box">
  14. <div class="upload-title">
  15. <span>请选择需要上传的文件</span>
  16. </div>
  17. <div class="upload-content">
  18. <!-- 隐藏域限制文件大小为约256K -->
  19. <input type="hidden" name="MAX_FILE_SIZE" value="256000">
  20. <div class="upload-item">
  21. <input type="file" name="file[]" />
  22. </div>
  23. <div class="upload-item">
  24. <input type="file" name="file[]" />
  25. </div>
  26. <div class="upload-item">
  27. <input type="file" name="file[]" />
  28. </div>
  29. <div class="upload-item">
  30. <input type="file" name="file[]" />
  31. </div>
  32. <div class="upload-item">
  33. <p>文件大小限制: 256KB</p>
  34. </div>
  35. <div class="upload-item">
  36. <button type="submit">上传</button>
  37. </div>
  38. </div>
  39. </section>
  40. </form>
  41. </body>
  42. </html>

效果图:

  1. 文件批量上传
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6. <title>文件批量上传</title>
  7. <style>
  8. @import url("style/style.css");
  9. </style>
  10. </head>
  11. <body>
  12. <form action="doBusiness.php" method="post" enctype="multipart/form-data">
  13. <section class="upload-box">
  14. <div class="upload-title">
  15. <span>请选择需要上传的文件</span>
  16. </div>
  17. <div class="upload-content">
  18. <div class="upload-item">
  19. <!-- 隐藏域限制文件大小为约256K -->
  20. <input type="hidden" name="MAX_FILE_SIZE" value="256000">
  21. <input type="file" name="single[]" multiple />
  22. </div>
  23. <div class="upload-item">
  24. <p>文件大小限制: 256KB</p>
  25. </div>
  26. <div class="upload-item">
  27. <button type="submit">上传</button>
  28. </div>
  29. </div>
  30. </section>
  31. </form>
  32. </body>
  33. </html>

效果图:

  1. 文件上传结果页
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>上传结果</title>
  7. <style>
  8. @import url('style/result.css');
  9. </style>
  10. </head>
  11. <body>
  12. <?php if (!empty($success)) : ?>
  13. <table border="1" cellspacing="0" cellpadding="10" width="800" align="center">
  14. <caption style="font-size: 1.5rem; margin-bottom: 30px;">上传成功的文件</caption>
  15. <thead style="background-color: lightblue;">
  16. <tr>
  17. <th>文件序号</th>
  18. <th>文件名</th>
  19. <th>缩略图</th>
  20. <th>扩展名</th>
  21. </tr>
  22. </thead>
  23. <tbody>
  24. <?php foreach ($success as $item) : ?>
  25. <tr>
  26. <td><?php echo $item['filenumber'] ?></td>
  27. <td><?php echo $item['filename'] ?></td>
  28. <td><img src="<?php echo $item['filepath'] ?>"></td>
  29. <td><?php echo $item['extName'] ?></td>
  30. </tr>
  31. <?php endforeach; ?>
  32. </tbody>
  33. </table>
  34. <hr>
  35. <?php endif; ?>
  36. <?php if (!empty($failure)) : ?>
  37. <table border="1" cellspacing="0" cellpadding="10" width="800" align="center">
  38. <caption style="font-size: 1.5rem; margin-bottom: 30px;">上传失败的文件</caption>
  39. <thead style="background:orangered">
  40. <tr>
  41. <th>文件序号</th>
  42. <th>文件名</th>
  43. <th>错误码</th>
  44. <th>错误信息</th>
  45. </tr>
  46. </thead>
  47. <tbody>
  48. <?php foreach ($failure as $item) : ?>
  49. <tr>
  50. <td><?php echo $item['filenumber'] ?></td>
  51. <td><?php echo $item['filename'] ?></td>
  52. <td><?php echo $item['errorCode'] ?></td>
  53. <td><?php echo $item['message'] ?></td>
  54. </tr>
  55. <?php endforeach; ?>
  56. </tbody>
  57. </table>
  58. <?php endif; ?>
  59. </body>
  60. </html>

效果图:

2. 处理脚本

  1. 请求处理脚本(doBusiness.php)
  1. <?php
  2. // 加载文件上传处理类
  3. require('FileUpload.php');
  4. // 执行文件上传
  5. $res = (new FileUpload())->doFileUpload();
  6. // 若没有处理结果, 则表示$_FILES中的数据格式暂时无法处理
  7. if (count($res) === 0) {
  8. printf('<script>alert("暂不支持的文件上传形式");window.history.go(-1);</script>');
  9. exit;
  10. }
  11. // printfpre($res);
  12. // 上传成功的文件信息数组
  13. $success = $res['success'];
  14. // 上传失败的文件信息数组
  15. $failure = $res['failure'];
  16. // 加载上传结果页, 显示上传结果数据
  17. require('upload_result.php');
  1. 文件上传处理类(FileUpload.php)
  1. <?php
  2. require('../../out.php');
  3. class FileUpload
  4. {
  5. /* 文件保存路径 */
  6. private static $fileMovePath = 'uploads/';
  7. /* 保存处理结果的数组 */
  8. private $res = null;
  9. /* 合法的文件MIME类型 */
  10. private $allowMine = ['image'];
  11. /* 上传处理方法 */
  12. public function doFileUpload()
  13. {
  14. $this->res = [];
  15. // 批量上传的情况(三维数组,第一维数组只有一个元素)
  16. if (COUNT($_FILES) === 1 && is_array(current($_FILES)['error'])) {
  17. // 获取第一维数组的第一个元素
  18. $batch_files = current($_FILES);
  19. // 便利第二维数组中key=error的值数组
  20. for ($index = 0; $index < count($batch_files['error']); $index++) {
  21. // 把上传文件的信息保存为一维数组
  22. $fileInfo = [
  23. 'name' => $batch_files['name'][$index],
  24. 'type' => $batch_files['type'][$index],
  25. 'tmp_name' => $batch_files['tmp_name'][$index],
  26. 'error' => $batch_files['error'][$index],
  27. 'size' => $batch_files['size'][$index],
  28. ];
  29. // 执行验证和移动
  30. // printf('开始处理第%d个文件<br/>', ($index + 1));
  31. $this->doUpload($fileInfo, $index + 1);
  32. // printf('第%d个文件处理完成<hr/>', ($index + 1));
  33. }
  34. }
  35. // 简单处理,如果不是三维数组,则认定其为单文件上传或文件域name属性值不相同的多文件上传
  36. else if (!is_array(current($_FILES)['error'])) {
  37. $index = 1;
  38. // 便利一维数组,执行验证和移动
  39. foreach ($_FILES as $file) {
  40. // printf('开始处理第%d个文件<br/>', $index);
  41. $this->doUpload($file, $index);
  42. // printf('第%d个文件处理完成<hr/>', $index);
  43. }
  44. }
  45. return $this->res;
  46. }
  47. /**
  48. * 执行文件上传的方法
  49. * $file : 文件信息
  50. * $index : 对应前端文件域的序号
  51. */
  52. private function doUpload(array $file, $index)
  53. {
  54. // 上传出错的代码
  55. $errorCode = $file['error'];
  56. // 大于0的错误码为上传失败
  57. if ($errorCode > UPLOAD_ERR_OK) {
  58. // 异常信息
  59. $message = '';
  60. switch ($errorCode) {
  61. case UPLOAD_ERR_INI_SIZE:
  62. $message = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值';
  63. break;
  64. case UPLOAD_ERR_FORM_SIZE:
  65. $message = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值';
  66. break;
  67. case UPLOAD_ERR_PARTIAL:
  68. $message = '文件只有部分被上传';
  69. break;
  70. case UPLOAD_ERR_NO_FILE:
  71. $message = '没有文件被上传';
  72. break;
  73. case UPLOAD_ERR_NO_TMP_DIR:
  74. $message = '找不到临时文件夹';
  75. break;
  76. case UPLOAD_ERR_CANT_WRITE:
  77. $message = '文件写入失败';
  78. break;
  79. default:
  80. // 测试时建议关掉default: 避免误报影响
  81. $message = '未知类型错误';
  82. }
  83. $this->res['failure'][] = [
  84. 'filename' => $file['name'] ?? '',
  85. 'errorCode' => $errorCode,
  86. 'message' => $message,
  87. 'filenumber' => $index,
  88. ];
  89. return;
  90. }
  91. // 判断文件MIME类型
  92. $fileMine = strstr($file['type'], '/', true);
  93. if (!in_array($fileMine, $this->allowMine)) {
  94. $this->res['failure'][] = [
  95. 'filename' => $file['name'] ?? '',
  96. 'errorCode' => 8,
  97. 'message' => '文件MIME不允许上传',
  98. 'filenumber' => $index,
  99. ];
  100. return;
  101. }
  102. // 临时文件
  103. $tmpFileName = $file['tmp_name'];
  104. /* 非法请求, 当处理失败处理 */
  105. if (!is_uploaded_file($tmpFileName)) {
  106. $this->res['failure'][] = [
  107. 'filename' => $file['name'] ?? '',
  108. 'errorCode' => 9,
  109. 'message' => '不是合法的文件上传请求,劝你善良',
  110. 'filenumber' => $index,
  111. ];
  112. return;
  113. }
  114. // 准备移动
  115. // 原文件名
  116. $oriFileName = $file['name'];
  117. // 文件扩展名
  118. $extName = strstr($oriFileName, '.') ?? '';
  119. // 目标文件名(包括路径)
  120. $targetFileName = self::$fileMovePath . md5(time() . rand(1, 1000)) . $extName;
  121. // 执行移动
  122. if (move_uploaded_file($tmpFileName, $targetFileName)) {
  123. $this->res['success'][] = [
  124. 'filename' => $oriFileName,
  125. 'filepath' => $targetFileName,
  126. 'filenumber' => $index,
  127. 'extName' => $extName,
  128. ];
  129. } else {
  130. $this->res['failure'][] = [
  131. 'filename' => $oriFileName,
  132. 'errorCode' => 10,
  133. 'filenumber' => $index,
  134. 'message' => '移动文件失败',
  135. ];
  136. }
  137. }
  138. }

学习心得

文件上传是比较过程化的流程. 而4种文件上传提交的数据, 在$_FILES上以不同的数据结构存放. 因此只要把不同的数据结构转成相同的结构来处理, 就可以统一操作了.

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议