dokuwiki是一款免数据库基于文件的wiki系统,原本其保存文件的命名方式是,对于非ASCII字符的字符用其UTF-8编码按URL编码方式保存。比如一个中文的条目,你看到它保存的文件名可能是 「%E5%A4%9A%E9%87%8D%E5%AF%B9%E6%95%B0%E5%87%BD%E6%95%B0.txt」。 这么一大串实际上只有6个汉字,让人好生不爽呀。

近日整理博客的时候发现,dokuwiki有了新版本「Anteater」,立马换上去。而后,在EasyBoxLite建站dokuwiki新版本发布 - 2010-11-07 「Anteater」上发现,新版的dokuwiki支持用utf-8编码命名文件了,相当给力!这样在FTP上面就可以正确显示出中文文件名,友好多了。在配置管理器页面的非 ASCII 文件名的编码方法(fnencode)可以做更改,默认的还是原来URL编码,还一个选项是「安全」,这个没有试验过估计dokuwiki用自己的方式对utf8字符再编码,据说比URL编码更短,比UTF8安全,但人不可读的。这也是在说UTF8编码不是安全的,在一些服务器上面可能不能正常工作,比如说我的Win7——文件名是Unicode-16LE编码的;还有我的SSH服务器(CentOS)——没有中文字符集或者说所有非ASCII字符的会变成问号 :?: ,这些服务器都可能会出问题。

还有一点,将文件名的编码设置成utf-8的格式,那些之前用URL编码保存的文件dokuwiki是不会帮你重命名的,也就说之前的写好的wiki条目都访问不了,是很郁闷的一件事啊!于是乎趁php还未手生写了个批量重命名的php脚本。脚本如下:

<?php 
/*  
*  fixfn.php  
*  !!!注意,转换前千万个一定要备份原数据!!!!  
*  跟要修改的data文件夹放在同目录,一般是dokuwiki的根目录。  
*  也可以放在任意位置,但要自己修改dokuwiki的data文件夹位置,在最下面的$ds变量指定  
*  访问执行一次便可。  
*  对文件名里有"%"符号的文件才会有影响  
*  重复运行虽无影响,但运行完还是删了好  
*  如果文件名中"%"出现在不应该出现的地方,那文件名肯定会错乱滴  
*  !!!注意,转换前千万个一定要备份原数据!!!!  
*/
function simpleHexToNum($s){
    $s=strtoupper($s);
    $x = ord($s);

    if($x>=ord("0") && $x<=ord("9")){
       return $x-ord('0');
    }
    if($x>=ord('A')&&$x<=ord('F')){
       return $x-ord('A')+10;
    }
    return -1;
}
function toUTF8($str){  //文件名中百分号(%)后面必须跟着两位16进制数才能正常工作  
    $len = strlen($str);
    $result ='';
    $i=0;
    while($i<$len){
        if($str[$i] == "%"){
            $i++;
            $d = simpleHexToNum($str[$i++])*16+simpleHexToNum($str[$i++]); //DIG
            $result =$result . chr($d);
        }else{
            $result =$result . $str[$i++];
        }

    }
    return $result;
}
function rename_data($path){
        if(is_dir($path)){
                echo $path . "<br />";
                $dp=dir($path);
                while($file=$dp->read())
                        if($file!='.'&&$file!='..'){
                            //  $nfile = toUTF8($file); //亲测可用  
                                $nfile = urldecode($file);   //php自带urldeconde,这个健壮性会好很多吧 ...汗  
                                echo "rename <strong>" . $file."</strong> to <strong>" .$nfile . "</strong><br />";
                                echo  rename($path."/".$file , $path."/".$nfile)?"<font color=\"#00FF00\">success</font>":"<font color=\"#FF0000\">fail</font>" ;
                                echo "<br />";
                                rename_data($path.'/'.$nfile);
                        }
                $dp->close();
        }

}
echo "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"></head>";

//可能要动手修改的地方  
$ds =dirname(__FILE__) . "/data";  //默认同目录下的data文件夹  
//$ds = "/xxxx/dourok.info/wiki/data";  //自己指定data文件夹  
rename_data($ds); 


echo "<font color=\"#FF0000\">if everything running fine,delete this php file</font></html>";
?>

对跟我一样只有FTP权限的童鞋应该有帮助,将上面的代码复制下来,保存成php文件如fixfn.php,最好UTF8编码的,上传到服务器,位置见代码注释,访问一下搞定。再次提醒一定得备份原数据啊!php菜鸟一个,你们懂的。

突然想来一段FML: 今天,本来是想把dokuwiki的老数据拉到本地系统上来改名的,用Java写好了代码才想起windows文件名不是utf-8,于是乎再将数据跟代码传到我的ssh服务器上,上面有java环境,运行下才发现服务器不支持非ASCII字符,我一早知道又给忘了,无奈只能用php重写,实现了url解码成功改完名后,才发现php有urldecode…FML