發帖時經常使用 flash 批次上傳附件,來粗略的瞭解一下 flash 上傳附件的過程。

在帖子中,當點選編輯器上傳按紐 程式讀取 ./template/default/forum/editor_menu_forum.htm 模板檔案
從編輯模板原始檔裡面可以看到程式輸出了一程式碼,其中的 js

  1. <script type="text/javascript">
  2.         $('{$editorid}_multiimg').innerHTML = AC_FL_RunContent(
  3.                 'width', '470', 'height', '268',
  4.                 'src',
    '{IMGDIR}/upload.swf?site={$_G[siteroot]}misc.php%3fmod=swfupload%26type=image%26fid=$_G[fid]&type=image&random=<!--{echo
    random(4)}-->',
  5.                 'quality', 'high',
  6.                 'id', 'swfupload',
  7.                 'menu', 'false',
  8.                 'allowScriptAccess', 'always',
  9.                 'wmode', 'transparent'
  10.         );
  11. </script>

輸出 flash

使用 AC_FL_RunContent 函式 (此函式在 common.js) 來輸出 flash

在此函式中 使用 AC_GetArgs 函式來處理 AC_FL_RunContent   所傳進來的變數以構造 flash 輸出相關的資訊

從以上程式碼的

  1. 'src',
    '{IMGDIR}/upload.swf?site={$_G[siteroot]}misc.php%3fmod=swfupload%26type=image%26fid=$_G[fid]&type=image&random=<!--{echo
    random(4)}-->',

可以看出 此 flash 的 src 為 論壇後臺設定的 IMGDIR 目錄下的 upload.swf 輸出的 flash 還傳進了一段引數

這裡面要注意 {IMGDIR} 為後臺設定圖片目錄 有些站長把該值設定了遠端的一個地址 於是程式請求得是遠端的  upload.swf ,當檔案上傳完成後 upload.swf   會請求相同目錄下的 misc.php 檔案 這樣設定可能就會上傳失敗

  1. site={$_G[siteroot]}misc.php%3fmod=swfupload%26type=image%26fid=$_G[fid]&type=image&random=<!--{echo random(4)}-->

flash 會根據該引數 請求類似 misc.php?mod=swfupload&fid=2&action=swfupload&operation=config 的地址

根據該地址我們很容易找到 misc_swfupload.php 檔案,&operation=config 初始化處理後將會輸出一個
xml 給 flash 。此 xml   裡麵包括 flash 上傳介面的提示文字、上傳大小限制、上傳檔案的限制型別等等,很多時候點上傳 flash 按紐空白 沒有顯示中檔案都是因為 xml 輸出出錯導致

到這裡 一切正常 xml 也沒出錯 我們就可以看到 flash 上傳的介面 (終於可以開始上傳了....)

1.jpg

點選瀏覽器按紐,選擇需要上傳的檔案點上傳後 flash 會請求到 misc_swfupload.php 此時檔案就被 php 傳到 php 所配置的上傳的臨時路徑下

所以,在上傳失敗時可能的一條原因是 php.ini 中 upload_tmp_dir 所指定的臨時上傳目錄或硬碟是否滿了,是否有許可權

  1. } elseif($_G['gp_operation'] == 'upload') {
  2.         require_once libfile('class/forumupload');
  3.         if(empty($_G['gp_simple'])) {
  4.                 $_FILES['Filedata']['name'] = addslashes(diconv(urldecode($_FILES['Filedata']['name']), 'UTF-8'));
  5.                 $_FILES['Filedata']['type'] = $_G['gp_filetype'];
  6.         }
  7.         $upload = new forum_upload();
  8. }

在此例項化了一個 forum_upload 類 ( class_forumupload.php ) 在這個類裡面使用了 discuz_upload 類 ( class_upload.php ) 對檔案進行移動處理

程式首先 呼叫 discuz_upload 裡面的 init 方法處理 $_FILES 來得到上傳檔案的目標路徑、檔名、大小等等資訊,存在其屬性 $attach 陣列中

init 方法會呼叫到 is_image_ext 來判斷檔案是否屬於圖片 (該方法判斷字尾有 'jpg', 'jpeg', 'gif', 'png', 'bmp');

出於安全的考慮 init 中呼叫到 get_target_extension 方法處理非法的檔案字尾 (將非 'attach', 'jpg',
'jpeg', 'gif', 'png', 'swf', 'bmp', 'txt', 'zip', 'rar',
'mp3'副檔名名的附件副檔名改成 attach)

然後根據 $attach 裡面的各項值 來判斷相關的 所上傳檔案尺寸、大小、型別、當前使用者所屬使用者組上傳限制等合法性

當程式判斷該附件 「合法」,則呼叫 discuz_upload 類的 save 方法 對圖片進行移動,從 php 的臨時上傳目錄移到程式附件相對應的目錄

save 方法所呼叫的 save_to_local 相容使用了 copy 、 move_uploaded_file 、 fread/fwrite 等三種移動方法

在此我們可以發現需要 data 目錄及子目錄需要可讀寫執行許可權。

在這裡如果有產生錯誤,

  1. 'file_upload_error_-101' => '上傳失敗!上傳檔案不存在或不合法,請返回。',
  2. 'file_upload_error_-102' => '上傳失敗!非圖片型別檔案,請返回。',
  3. 'file_upload_error_-103' => '上傳失敗!無法寫入檔案或寫入失敗,請返回。',
  4. 'file_upload_error_-104' => '上傳失敗!無法識別的影像檔案格式,請返回。',

根據文字所對應的數字程式碼,可以在 class_upload.php 中找到其相對應的判斷所進入的判斷程式碼行。

  1. '-1' : '內部伺服器錯誤',
  2. '0' : '上傳成功',
  3. '1' : '不支援此類副檔名',
  4. '2' : '伺服器限制無法上傳那麼大的附件',
  5. '3' : '使用者組限制無法上傳那麼大的附件',
  6. '4' : '不支援此類副檔名',
  7. '5' : '檔案型別限制無法上傳那麼大的附件',
  8. '6' : '今日你已無法上傳更多的附件',
  9. '7' : '請選擇圖片檔案 (' + imgexts + ')',
  10. '8' : '附件檔案無法儲存',
  11. '9' : '沒有合法的檔案被上傳',
  12. '10' : '非法操作',
  13. '11' : '今日你已無法上傳那麼大的附件'

上傳失敗所示提的程式碼也可以在 class_forumupload.php 裡面找到相對應的判斷。這樣就能很方便的找到問題出錯在哪裡。

save 成功後 如果所上傳檔案是圖片附件,並且後臺開啟了生成縮圖,程式會根據上傳後的圖片進行處理生成縮圖

上傳成功,forum_upload 類 使用 getattachnewaid 函式 向 forum_attachment 插入一條記錄返回新附件的 aid

並插入一條記錄到 forum_attachment_unused 表的中

點確定後返回到附件列表,程式根據 aid 向
forum.php?mod=ajax&action=attachlist&aids=|7|6|5&fid=2&inajax=1&ajaxtarget=attachlist
地址請求

該地址處理程序 forum_ajax.php 使用 getattach 函式從資料庫中讀出附件等資訊並將附件展示出來

至此附件上傳成功