發帖時經常使用 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 函數從數據庫中讀出附件等信息並將附件展示出來

至此附件上傳成功