« 上一篇 | 下一篇»

Moodle中文檔名上傳與下載與zip壓縮解壓縮問題
post by Rong-Fang Wu @ 22 九月, 2007 10:52

安裝moodle 1.8.2(OS and Web Server: FreeBSD 6.2 and Apache22, PHP5.1.6)上傳中文檔名的檔案後無法正確顯示中文名問題,先到網路搜尋解決方法,在這幾篇看到修正方法:

1.http://moodle.club.tw/moodle/mod/forum/discuss.php?d=66&parent=163 

2.http://plog.hlps.tcc.edu.tw/plog/post/1/2945

以下是個人的說明與提出一些修正的看法

於config.php加入

$CFG->unicodecleanfilename = true;

即可正常上傳中文檔名

在lib/moodlelib.php下亦有這段說明

/**
 * Cleans a given filename by removing suspicious or troublesome characters
 * Only these are allowed: alphanumeric _ - .
 * Unicode characters can be enabled by setting $CFG->unicodecleanfilename = true in config.php
 *
 * WARNING: unicode characters may not be compatible with zip compression in backup/restore,
 *          because native zip binaries do weird character conversions. Use PHP zipping instead.
 *
 * @param string $string  file name
 * @return string cleaned file name
 */

因此似乎雖解決上傳中文檔名問題但zip壓縮卻無法使用中文檔名,以moodle 內建pclzip也許可解決???

 以下有兩個問題待解決:

  1. 下載中文檔名於IE下有問題,會轉成英文檔名,Firefox可正常下載
  2. 無論在firefox或IE均無法壓縮與解壓縮中文檔名(備份亦然)

產生此問題原因分析:

  1. IE6對於UTF-8中文檔名無法正常下載,IE7則只對zip的中文檔會產生問題其餘對office或wmv,gif,jpg不會產生問題,所以對於若是IE瀏覽器下載時將檔名轉成Big5應可解決。
  2. 壓縮與解壓縮問題,原因在於php的basename() function對於UTF-8對中文檔名會回傳成無中文檔名或不正確之檔名(IE6與IE7不一樣,IE7較接近Frefox),改寫basename function應可解決。不知道其他php版本會不會這樣???沒試過。

文章最底下有一小段程式碼支持上述說法。

==================================

詳細改寫程式碼,請參閱以下說明: 

 1. 下載中文檔名於IE下有問題,Firefox可正常下載

 雖然註解lib/file.php下的這一行
//$filename = $args[count($args)-1];
send_file($pathname, $filename, $lifetime, $CFG->filteruploadedfiles, false, $forcedownload);
 

可解決下載問題,但使用 //$filename = $args[count($args)-1];

則造成下一行程式call send_file(....)的filename參數為null。

trace send_file function(在lib/filelib.php檔案中)以filename無法正確取得mimetype,不知會不會造成隱含的問題?

經過簡化後測試(參閱最下面程式碼)發現應該是以@header('Content-Disposition: attachment; filename='.$filename);
送出UTF-8中文檔名造成IE錯誤(與IE是否設定以UTF-8傳送URL無關)

因此做了以下修改

1. file.php不註解 $filename = $args[count($args)-1];

2. lib/filelib.php加入一小段程式碼: 

header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT');

if (check_browser_version()){
        $filename=iconv("UTF-8","Big5",$filename);
}

if ($forcedownload) {
       @header('Content-Disposition: attachment; filename='.$filename);
} else {
       @header('Content-Disposition: inline; filename='.$filename);   
 }

 紅色部份是加入的程式碼,check_browser_version()是在lib/moodlelib.php內的function用來檢查用戶端使用何種瀏覽器

 

2. php之basename() 內建function無法正確傳回中文檔名,造成壓縮與解壓縮問題
於lib/moodlelib.php加一function 來取代原來的basename

function file_basename($file= null) {
    if($file=== null || strlen($file)<= 0) {
        return null;
    }
  
    $file= explode('?', $file);
    $file= explode('/', $file[0]);
    $basename= $file[count($file)-1];

    return $basename;  
}

因此需修改的程式碼部份說明如下:

A. files/index.php修改如下

在case "paste": 修改
$shortfile = basename($file);->$shortfile = file_basename($file);

在case "unzip": 修改
$file = basename($file);->$file = file_basename($file);

 在case "listzip": 修改
$file = file_basename($file);->$file = file_basename($file);

 約825行處$fileurl改成$filesafe(fileurl為未編碼的檔名,filesafe為編碼的檔名), 則不管IE6或 IE7均能正常取得正確的檔名

else if ($icon == "zip.gif") {
                $edittext .= "<a href=\"index.php?id=$id&wdir=$wdir&file=
$filesafe&action=unzip&sesskey=$USER->sesskey&choose=$choose\">$strunzip</a> ";
                //
                $edittext .= "<a href=\"index.php?id=$id&wdir=$wdir&file=
$filesafe&action=listzip&sesskey=$USER->sesskey&choose=$choose\">$strlist</a> ";

B. 修改lib/moodlelib.php

在lib/moodlelib.php

修改function zip_files(..)

//$destfilename = $path_parts["basename"];  //The name of the zip file
    $destfilename = file_basename($destination);

//$filestozip .= escapeshellarg(basename($filetozip));
$filestozip .= escapeshellarg(file_basename($filetozip)); 

修改 function unzip_file(...)

//$zipfilename = $path_parts["basename"];  //The name of the zip file
    $zipfilename = file_basename($zipfile);

經過以上修改無論在Firefox, IE6 or IE7均能正常使用中文檔名了。 

簡化測試程式碼
--------------------------------------------

<?
//echo basename("/usr/local/test/中文測試檔.zip");

$filename=iconv("UTF-8","Big5","中文測試檔.zip");
//$filename="中文測試檔.zip";
@header('Content-Disposition: attachment; filename='.$filename);
@header('Content-Type: application/zip');
readfile_chunked("中文測試檔.zip");


//readfile_chunked 為lib/filelib.php內的function
function readfile_chunked($filename, $retbytes=true) {
    $chunksize = 1*(1024*1024); // 1MB chunks - must be less than 2MB!
    $buffer = '';
    $cnt =0;// $handle = fopen($filename, 'rb');
    $handle = fopen($filename, 'rb');
    if ($handle === false) {
        return false;
    }

    while (!feof($handle)) {
        @set_time_limit(60*60); //reset time limit to 60 min - should be enough for 1 MB chunk
        $buffer = fread($handle, $chunksize);
        echo $buffer;
        flush();
        if ($retbytes) {
            $cnt += strlen($buffer);
        }
    }
    $status = fclose($handle);
    if ($retbytes && $status) {
        return $cnt; // return num. bytes delivered like readfile() does.
    }
    return $status;
}
?>

發表迴響
暱稱:
標題:
個人網頁:
電子郵件:

 authimage

發表迴響

  

commons icon [18] [ 回覆 ]

謝謝你的資訊,我試用過沒問題喔。
太感激了!

commons icon [17] 更新系統亦可解決 [ 回覆 ]
  1. 測試PHP 5.2.4以上版本basename已可正常處理中文,因此只要系統PHP版本更新至5.2.4以上,則以上所有basename函式無須取代。
  2. IE7處理UTF8中文問題似乎已解決,只要把IE6升級至IE7上述問題無須修改程式碼亦可解決。
  3. zip壓縮問題:在moodle壓縮中文檔名的zip檔無法在windows下正常解壓縮 ; 反之在windows下壓縮的zip檔,在moodle下解壓縮中文檔名出現亂碼(其實是Big5碼) 因為在moodle下之中文檔名為UTF-8而在windows下為Big5碼。
commons icon [16] [ 回覆 ]

更新1.8.4後發現lib/filelib.php增加程式片斷
if (check_browser_version('MSIE')){
$filename=urlencode($filename);
}

因此本文章原加入
if (check_browser_version()){
$filename=iconv("UTF-8","Big5",$filename);
}
不用再加入

commons icon [15] 請問一下 [ 回覆 ]

我現在是Apache 2.2.4 +php5.2.5+MySQL 5.0.45
有加
$CFG->unicodecleanfilename = true;
還有哪邊需要改的嗎
約825行處$fileurl改成$filesafe(fileurl為未編碼的檔名,filesafe為編碼的檔名), 則不管IE6或 IE7均能正常取得正確的檔名

else if ($icon == "zip.gif") {
$edittext .= "sesskey&choose=$choose\">$strunzip ";
//
$edittext .= "sesskey&choose=$choose\">$strlist ";
這裡有需要改嗎
謝謝

commons icon [14] RE:請問一下 [ 回覆 ]

針對用戶端是IE6
約825行處$fileurl仍需改成$filesafe

因為:
$fileurl與$filesafe的關係為
$filesafe=urlencode($fileurl);

commons icon [13] 缺乏檔案 - 您確定選擇了上傳檔案了嗎? [ 回覆 ]

你好我加了$CFG->unicodecleanfilename = true;
上傳中文時會出現
缺乏檔案 - 您確定選擇了上傳檔案了嗎?

備份檔案亦出現
PCLZIP_ERR_READ_OPEN_FAIL (-2) : Unable to open archive 'C:/AppServ/moodledata/temp/backup/1203645681/備份檔-cf101_1-20080222- 1001.zip' in wb mode

commons icon [12] 缺乏檔案 [ 回覆 ]

請教
缺乏檔案 - 您確定選擇了上傳檔案了嗎
也無法壓縮中文檔
謝謝

commons icon [11] Re:缺乏檔案 [ 回覆 ]
一, 我以Windows XP, Xampp, Moodle1.8.2測試,會出現同樣無法上傳中文檔名問題即使已設定$CFG->unicodecleanfilename = true;
我想應該是Windows XP系統儲存中文檔名仍是以Big5存檔(Windows 2003與vista是否也是這樣沒試過),我修改一下lib/uploadlib.php第233行:
原來是:
if (move_uploaded_file($this->files[$i]['tmp_name'], $destination.'/'.$this->files[$i]['name'])) {
修改為 if (move_uploaded_file($this->files[$i]['tmp_name'], iconv("UTF-8","Big5",$destination.'/'.$this->files[$i]['name']))) { 把輸入的檔名改成Big5編碼則能順利上傳,當然瀏覽器編碼需改成Big5就能正確顯示中文檔名。
二, 另一種驗證的方法直接把中文檔案複製到moodledata下,然後進入moodle看該檔案顯示出亂碼,當然瀏覽器編碼改成Big5就能正確顯示中文檔名。
三, 建議將 OS 改成 unix 系統。
四, 是否有辦法將Windows系統設成同時認得Big5與UTF-8編碼的檔名?尚未得到答案!!!
commons icon [10] 請教 [ 回覆 ]

老師
這樣的確能上傳
但如你所說編碼還是...
且要下載時會出現
抱歉,指定的檔案找不到
 
在課程備份時會出現
備份檔案亦出現
PCLZIP_ERR_READ_OPEN_FAIL (-2) : Unable to open archive 'C:/AppServ/moodledata/temp/backup/1203645681/備份檔-cf101_1-20080222- 1001.zip' in wb mode

無法完成

commons icon [9] 中文編碼 [ 回覆 ]

吳老師你好:
我是在XP下測試
主系統在CENTOS上
依你作法中文檔案可上傳
編碼還是.....

備份資料使用中文亦會有問題
是我在安裝SERVER 哪有設定錯嗎?

謝謝

commons icon [8] RE:中文編碼 [ 回覆 ]
PCLZIP_ERR_READ_OPEN_FAIL (-2) : Unable to open archive 'C:/AppServ/moodledata/temp/backup/1203645681/備份檔-cf101_1-20080222- 1001.zip' in wb mode 從上述的錯誤訊息看,moodle似乎是安裝在Windows平台上,若是安裝在Windows平台因檔名編碼問題,似乎無解。 試試將moodle安裝在unix OS 上(FreeBSD, Linux CentOS),只要moodle1.8.4 且PHP版本是5.2.4以上,只加$CFG->unicodecleanfilename = true; 其他則不需再作任何修訂IE7與firefox均能正常運作 針對IE6需修正部分參閱本篇回響部份(RE:請問一下)與http://plog.ptes.tp.edu.tw/97/609 PS:CentOS 5.1 PHP的版本似乎仍為5.1.6,因為未安裝CentOS環境,不肯定。
commons icon [7] 感謝你的指導 [ 回覆 ]

CentOS版板的確稍舊
再CENTOS上 依你步驟尚未發現大問題
感謝你的指導
老師可否提供聯絡方式
日後請益交流之用

commons icon [6] 匯入課程 [ 回覆 ]
老師你好 我在匯入課程時卡住 匯入課程系統會複製一份備份檔(有中文檔名) 在會到要匯入課程 請問老師要在哪修改 謝謝
commons icon [5] [ 回覆 ]
匯入功能是先將要匯入的課程先備份後再還原到要匯入的課程,根據你描述應是在匯入還原階段無法順利完成,參閱下列文章,也許可解決。
http://plog.ptes.tp.edu.tw/post/97/716
在上列文章迴響內容對新版1.8.4修正說明,只提高memory_limit即可。
commons icon [4] 匯入功能 [ 回覆 ]
老師你好 我的檔案1.8MB而已 匯入的課程可以備份 還原到要匯入的課程 是有問題的(會是中文檔名的問題嗎) restore.php有basename函式 自做主張把它改成file_basename 亦不見效果 一直重複循環 如附件:http://moodle.club.tw/moodle/file.php/1/moddata/forum/30/1834/課程匯入.doc
commons icon [3] [ 回覆 ]
請確認一下版本:Moodle 1.8.4, PHP 5.2.4以上,OS 為Unix base。 在我的環境測試沒有問題,我想在上述環境下應無中文檔名問題,若要試驗是否中文檔名問題可以下利兩種方式試驗: 1.將moodle系統語系暫時改成英文。2.瀏覽器使用Firefox試試。

將php.ini 中memory_limit調高到128M以上試試。
commons icon [2] firefox ok [ 回覆 ]
我的PHP 5.16 匯入課程 firefox 似乎可以
commons icon [1] [ 回覆 ]
建議將PHP升級到5.2.4版以後,該版以後處理中文問題已獲改善,例如basename()已能處理中文檔名。
Power by LifeType. Template design by JamesHuang. Valid XHTML and CSS