本文就來說說,php檔案上傳後端處理都有些什麼技巧吧!
業務場景一、我們只會選擇單一的檔案上傳,而且不需要做一些即時的驗證工作。那麼,也許並沒有什麼優化可言了,因為,最後你要做的,只是將這個文件放在表單裡最後一起提交,直接處理即可!
業務場景二、需要上傳多個文件,而且需要時時驗證文件內部內容,並時行對應頁面顯示。對於這種況,在用戶選擇了上傳文件之後,我們需要立即將文件上傳,因為我們需要讀取文件裡的信息,在最後提交的時候,我們也需要提交一次文件。很明顯,這裡是存在一個重複上傳的工作的,一個耗費用戶時間,二個是耗費伺服器頻寬資源!優化,能夠想得到的方法也很簡單,能不能在第一次上傳完文件之後,就將文件保留在伺服器,真正提交表單的時候,去讀取這個已經被上傳的臨時文件即可。是的,這就是我們的處理想法!
業務場景三、與場景二類似,需要上傳多個文件,但是多個文件可能是分開上傳的。即我們可能第一次上傳了10M,第二次上傳了10M,總共上傳了10次,那麼,在伺服器端來說的話,一次性提交肯定是超出了上傳大小的限制了,但是如果,我們是分每一次的上傳,這是可以的,而最後提交的時候,我們只需要將簡短的文字訊息傳上去即可!
思路的確是簡單的,看起來,也是沒什麼問題,但是,也許我是能力有限,當時著實花了我不少時間去處理這個什麼鬼!下面,我將給出一些範例程式碼,以供參考:
檔案上傳技巧(將單次上傳的檔案作為臨時檔案存在在伺服器端)範例程式碼:
1. 頁面js處理
//点击选择完成文件后,触发上传文件操作,将文件上传至服务器临时目录 $('.upload-real-file').off().on('change', function(){ if(!$(this).val()){ return false; } var responseObjId = $(this).attr('response-id'); var responseObj = $('#' + responseObjId); $('#Form').ajaxSubmit({ url:'/aa/bb/uploadTmpApkTool', resetForm: false, dataType: 'json', beforeSubmit: function(option){ window.loading = layer.load(2); }, success: function(data, statusText){ layer.close(window.loading); if(data.status == 1){ responseObj.html(data.apkInfoHtml); var parentContainer = responseObj.parent().parent(), nameContainer = parentContainer.find('.file-name-container'); nameContainer.html(data.apkName); nameContainer.attr('title', data.apkName); responseObj.find('.file-tmp').html(data.fileInfo); //将文件信息存放于隐藏域中,以便在提交时能找到 $(submitId).removeAttr('disabled'); }else{ layer.alert(data.info); } }, error: function(data){ layer.close(window.loading); layer.alert('未知错误,请稍后再试!'); } }); return false;//防止dialog 自动关闭 });
2. 很明顯,頁裡面需要取得檔案訊息,後台處理程式碼(PHP)
$apkConfig = $this->_getApkConfig(); $params = $this->getFilteredParam('get'); $subFile = $_FILES['apkToolFiles']; $apkName = $apkInfoHtml = ""; if(empty($subFile)) { $this->ajaxReturn(array('status' => -4, 'info' => '请选择要上传的文件')); } foreach ($subFile['name'] as $subKey => $subVal) { if ($subFile['name'][$subKey]) { $fileData = $this->_getFileData($subFile, $subKey); $checkData = array( 'maxSize' => $apkConfig['FILE_MAX_SIZE'], 'savePath' => $apkConfig['TMP_CHILD_PATH'], 'extArr' => array('apk'), 'releaseName' => str_replace('.apk', '', $fileData['fileName']), //特有 ); $checkResult = $this->_checkFileData($fileData, $checkData); if ($checkResult['status'] != 1) { $this->ajaxReturn($checkResult); } //移动文件 $filePath = $checkData['savePath'] . '/' . $fileData['fileName'] . '.tmp' . genRandStr(6);; $this->_moveUploadedFile($fileData['tmpName'], $filePath); $apkInfo = $this->_apkParser($filePath); //解析 if($apkInfo['UMENG_CHANNEL'] != 'UMENG_CHANNEL_VALUE') { @unlink($filePath); //删除无效文件 $this->ajaxReturn(array('status' => 0, 'info' => "UMENG_CHANNEL的值要是 UMENG_CHANNEL_VALUE才行")); } $tmpFileArr['file_info'] = array( 'name' => $subFile['name'][$subKey], 'type' => $subFile['type'][$subKey], 'tmp_name' => str_replace($apkConfig['TMP_CHILD_PATH'] . '/', '', $filePath), 'error' => $subFile['error'][$subKey], 'size' => $subFile['size'][$subKey], ); //转存该值,不再重复上传文件 } else { $this->ajaxReturn(array('status' => 0, 'info' => "文件不能为空")); } foreach ($apkInfo as $key => $val) { $apkInfoHtml .= "{$key}:{$val} \r\n"; } $apkName = $fileData['fileName']; $version = $apkInfo['versionName']; } $fileInfo = htmlspecialchars(json_encode($tmpFileArr['file_info'])); $fileInfoHtml = "<input name=\"apkToolFileTmp[]\" value='{$fileInfo}' type=\"hidden\"/>"; //一定要输出前使用htmlspecialchars, 否则不能正确显示页面值和获取至正确的文件信息 $this->ajaxReturn(array('status' => 1, 'info' => "上传成功", 'version' => $version, 'item' => $item, 'apkName' => $apkName, 'apkInfoHtml' => $apkInfoHtml, 'fileInfo' => $fileInfoHtml)); }
3. 透過以兩部分程式碼的配合,我們在頁面上已經有正確的資訊了,只需要在最後提交表單的時候,不要將檔案提交到伺服器,在伺服器端處理時,只需將之前上傳的臨時檔案移動一下位置即可,這樣就算大功告成了!
$('.upload-file-real').attr('disabled', 'disabled'); //提交表单前,禁用上传文件
4. 後續工作
將臨時檔案上傳到伺服器後,是沒辦法判斷使用者是否取消目前操作的,如果取消了,則臨時檔案將一直存在於伺服器,所以,我們需要一個定時清理臨時目錄的腳本。當然,這個很簡單,就只需要找到這個目錄,比較一下時間,例如超過一天前的檔案就給刪除。注意控制清理頻率即可!
5. 題外話
日誌真的很重要,哪裡出錯了,哪裡刪除檔案了,哪裡清理資料庫了,一定要做好紀錄!
以上是php上傳處理文件小技巧總結的詳細內容。更多資訊請關注PHP中文網其他相關文章!