首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 文件上傳後端處理進階技巧:臨時儲存、二次提交優化與定時清理策略

     編輯:PHP 相關知識

解決大文件、多文件、分批上傳的工程化方案

文件上傳看似簡單,但面對「多文件即時驗證」、「大文件分片上傳」、「重複上傳浪費頻寬」等場景時,傳統「表單一次性提交」模式勢必力不從心。本文系統梳理三大業務場景與對應的後端優化策略。

場景對比

場景特徵痛點核心策略
單文件無即時驗證表單一次性提交無直傳處理
多文件需即時驗證/預覽選擇後立即上傳,提交時再傳一次重複上傳浪費時間與頻寬首次上傳存臨時目錄,提交時移動
大文件分片/分批上傳多次上傳累積超過單次限制單次上傳大小限制分片暫存,最終合併或僅提交元數據

核心實作:臨時文件落地 + 表單提交時移動

前端 JS(jQuery Form Plugin)

$('.upload-real-file').on('change', function(){
  if(!$(this).val()) return false;
  var responseObj = $('#' + $(this).attr('response-id'));
  
  $('#Form').ajaxSubmit({
    url: '/aa/bb/uploadTmpApkTool',
    dataType: 'json',
    beforeSubmit: function(){ window.loading = layer.load(2); },
    success: function(data){
      layer.close(window.loading);
      if(data.status == 1){
        responseObj.html(data.apkInfoHtml);
        responseObj.find('.file-tmp').html(data.fileInfo); // 隱藏域存臨時文件信息
        $(submitId).removeAttr('disabled');
      }else{ layer.alert(data.info); }
    },
    error: function(){ layer.close(window.loading); layer.alert('未知錯誤'); }
  });
  return false;
});

後端 PHP 處理流程

<?php
// 1. 接收文件
$subFile = $_FILES['apkToolFiles'];
// 2. 驗證:大小、副檔名、內容解析(如 APK 包名/版本/UMENG_CHANNEL)
$fileData = $this->_getFileData($subFile, $subKey);
$checkResult = $this->_checkFileData($fileData, [
  'maxSize' => $config['FILE_MAX_SIZE'],
  'savePath' => $config['TMP_CHILD_PATH'],
  'extArr' => ['apk'],
  'releaseName' => str_replace('.apk', '', $fileData['fileName'])
]);
// 3. 移動到臨時目錄(加隨機後綴避免衝突)
$filePath = $checkData['savePath'] . '/' . $fileData['fileName'] . '.tmp' . genRandStr(6);
$this->_moveUploadedFile($fileData['tmpName'], $filePath);
// 4. 業務驗證(如解析 APK 校驗渠道號)
$apkInfo = $this->_apkParser($filePath);
if($apkInfo['UMENG_CHANNEL'] != 'UMENG_CHANNEL_VALUE') {
  @unlink($filePath); return ajaxReturn(['status'=>0, 'info'=>'渠道號不符']);
}
// 5. 構造臨時文件元數據回傳前端(隱藏域)
$tmpFileArr['file_info'] = [
  'name'=>$subFile['name'][$subKey], 'type'=>$subFile['type'][$subKey],
  'tmp_name'=>str_replace($config['TMP_CHILD_PATH'].'/', '', $filePath),
  'error'=>$subFile['error'][$subKey], 'size'=>$subFile['size'][$subKey]
];
$fileInfo = htmlspecialchars(json_encode($tmpFileArr['file_info']));
$fileInfoHtml = "<input name='apkToolFileTmp[]' value='{$fileInfo}' type='hidden'/>";
// 6. 返回前端所需預覽信息
ajaxReturn(['status'=>1, 'apkInfoHtml'=>$apkInfoHtml, 'fileInfo'=>$fileInfoHtml, ...]);
?>

最終表單提交時

// 前端:禁用 file input,避免重複提交文件二進制
$('.upload-file-real').attr('disabled', 'disabled');

// 後端:僅處理隱藏域中的臨時文件元數據
// 讀取 apkToolFileTmp[] 陣列 -> 解析 tmp_name -> rename() 移動到正式目錄
// 完成業務邏輯入庫

配套機制:定時清理臨時目錄

用戶可能中途取消操作,導致臨時文件殘留。需部署 Crontab 定時腳本:

# 每天凌晨 3 點清理 24 小時前的臨時文件
0 3 * * * /usr/bin/php /path/to/clean_tmp.php >/dev/null 2>&1
<?php
$dir = '/path/to/tmp';
$expire = 86400; // 24h
foreach (new DirectoryIterator($dir) as $file) {
  if ($file->isFile() && (time() - $file->getMTime() > $expire)) @unlink($file->getPathname());
}
?>

關鍵經驗總結

  1. 日誌至關重要:上傳、移動、刪除、解析失敗全記錄,排查極其依賴日誌
  2. htmlspecialchars 雙重編碼:隱藏域 JSON 必須 htmlspecialchars(json_encode(...)),否則引號截斷導致解析失敗
  3. 權限控制:臨時目錄需可寫,但不可直接 Web 訪問(防止惡意腳本執行)
  4. 併發命名:genRandStr(6) 或 uniqid() 避免同名覆蓋

這套「臨時落地 + 元數據傳遞 + 定時清理」模式,已在多個百萬級日活專案穩定運行,有效解決了大文件、多文件、分批上傳的工程難題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved