WordPress上传中文文件名文件乱码之解决办法 » 荒野无灯weblog

Keep It Simple, Stupid.

荒野无灯weblog

WordPress上传中文文件名文件乱码之解决办法

WP中文论坛一坛友“晓风东来”发mail来问我WP上传中文文件有无解决办法,这问题以前还真没有细究。今天正好有时间,研究了下。这篇文章也算是给广大中文WP博友做个参考。



说明:

目前此方法适用于WP 3.x版。
适用服务器为windows 2003/2008 中文版操作系统( cp 936 ),不符合此条件的不要乱修改。
由此修改造成的任何问题与本人无关。
最后,说一点废话:
中文名是比较直观,不过个人建议大家最好还是上传英文的。这是保存100%不出问题的办法。
如果你只是想上传中文名的文件上去,然后能以中文名下载下来,而不在乎文件保存在服务器上是否是中文名,那么推荐你用这个插件:Hacklog-DownloadManager



wp-includes\functions.php line 2298 function wp_unique_filename
此函数系用PHP的basename取文件名,据我所知,此basename函数是不能获取中文文件名名称的,若文件名是中文的,返回的结果只剩下后缀了。
此处我给出一个支持中文的basename函数:

/**
 * @author 荒野无灯
 * 2010 0506修正,可取得网址文件名
 * 2011-09-21 fixed,make the function perform like  PHP origenal basename function
 * @param string $file_name
 * @param string $suffix
 * @return string 
 */
function ihacklog_basename($file_name, $suffix    = '') 
{
    $file_name = str_replace("\\", '/', $file_name);
    if (false !== strpos($file_name, '/')) 
    {
        $basename  = substr($file_name, strrpos($file_name, '/') + 1);
    }
    else
    {
        $basename  = $file_name;
    }
    if (!empty($suffix)) 
    {
        $basename  = substr($basename, 0, strlen($basename) - strlen($suffix));
    }
    return $basename;
}

此函数需丢入当前主题 functions.php 或者作为插件载入

2011-09-22T12:08:01+00:00补记:
后来仔细看了下php文档,发现也可以让basename支持中文,方法是在调用它之前要调用setlocale() 函数设置一个能处理多字节字符的
locale.

setlocale() 函数设置地区信息(地域信息)。

地区信息是针对一个地理区域的语言、货币、时间以及其他信息。

该函数返回当前的地区设置,若失败则返回 false。
注释:setlocale() 函数仅针对当前脚本改变地区信息。

提示:可以通过 setlocale(LC_ALL,NULL) 把地区信息设置为系统默认。

由于此函数只在当前脚本有作用,因此在WP里面要想它全局生效的话,此设置需要加入load或者加入wp-config.php中,如:

setlocale(LC_ALL, 'en_US.UTF8');
// 或者:
setlocale(LC_ALL, 'zh_CN.UTF8');

这样以后再调用basename即能正确获取中文名文件的basename.

wp_unique_filename 之line 2305

$name = basename($filename, $ext);

修改为

$name = ihacklog_basename($filename, $ext);

WP上传图片是通过此页面:
wp-admin/media-upload.php?post_id=日志ID&type=image&TB_iframe=1
flash=0参数是可选的。表示不用flash方式上传。
因上传图片比上传音乐等多一些处理,比如生成缩略图等,因此这里拿它开刀。

在日志发布页面以thickbox载入时是非inline方式上传,而通过媒体 –> 添加 上传时是通过inline方式上传的。
inline方式上传动作处理是:

        $id = media_handle_upload('async-upload', $_REQUEST['post_id']);

非inline方式上传处理是:

    do_action("media_upload_$type");

我们再看
media_upload_image() ,此函数位于wp-admin/includes/media.php line 519.
当上传按钮点击时,处理是:

    $id = media_handle_upload('async-upload', $_REQUEST['post_id']);

再看wp-admin/includes/media.php line 191 media_handle_upload()
调用  wp_handle_upload 开始上传文件了:

    $file = wp_handle_upload($_FILES[$file_id], $overrides, $time);

wp-admin/includes/file.php line 324

$filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback );

wp_unique_filename获取name是调用的basename,因此 wp_unique_filename函数得修改。
wp-includes/functions.php line 2298 wp_unique_filename()
line 2305

$name = basename($filename, $ext);

修改为:

$name = ihacklog_basename($filename, $ext);

wp-admin/includes/file.php 其下 line 327 后加一句

$new_file = iconv('UTF-8','GBK', $new_file);

,即变为:

    
        // Move the file to the uploads dir
    $new_file = $uploads['path'] . "/$filename";
    //windows服务器文件系统文件名默认是GBK编码
    $new_file = iconv('UTF-8','GBK', $new_file);

现在在回到wp-admin/inclues/media.php function media_handle_upload()
line 238 更新meta信息,调用 wp_generate_attachment_metadata():

    wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );

wp-admin/inclues/image.php line 89 wp_generate_attachment_metadata():
line 101

$metadata['file'] = _wp_relative_upload_path($file);

此处由于文件名是从wp_handle_upload传递过来的,因此得转回UTF-8,在其下加一句:

    $metadata['file'] = iconv('GBK','UTF-8', $metadata['file'] );

line 126-127:

            if ( $resized )
                $metadata['sizes'][$size] = $resized;

修改为:

    
        if ( $resized )
        {
            $resized['file'] = iconv('GBK','UTF-8', $resized['file'] );
            $metadata['sizes'][$size] = $resized;
        }

另外此函数内部调用了image_make_intermediate_size() ,而image_make_intermediate_size又调用了wp_basename
看wp-includes/media.php line 490
此处调用wp_basename :

    'file' => wp_basename( $resized_file ),

再看wp-includes/formatting.php line 2888 wp_basename()
这里要对wp_basename做修改

return urldecode( ihacklog_basename( str_replace( '%2F', '/', urlencode( $path ) ), $suffix ) );

wp-admin/includes/media.php line 582 function media_sideload_image()
line 590

$file_array['name'] = basename($matches[0]);

修改为:

$file_array['name'] = ihacklog_basename($matches[0]);

此函数内部调用 media_handle_sideload().
wp-admin/includes/media.php line 256 function media_handle_sideload
line 266

$title = preg_replace('/\.[^.]+$/', '', basename($file));

修改为:

$title = preg_replace('/\.[^.]+$/', '', ihacklog_basename($file));

其后又调用wp_generate_attachment_metadata().

最后:
wp-admin/includes/media.php line 1199 function get_media_item()
line 1217 原来的basename修改为wp_basename

$filename = esc_html( basename( $post->guid ) )

修改为:

$filename = esc_html( wp_basename( $post->guid ) ); 

不然返回结果也是只剩下后缀的。

其它修改:

wp-admin/includes/media.php line 46 function wp_crop_image()
line 70 basename ---->  ihacklog_basename 
wp-admin/includes/media.php line 625 function media_upload_audio()
line 647 basename ---->  ihacklog_basename 
wp-admin/includes/media.php line 684 function media_upload_video()
line 706 basename ---->  ihacklog_basename 
wp-admin/includes/media.php line 743 function media_upload_file()
line 765 basename ---->  ihacklog_basename 
wp-admin/includes/media.php line 1026 function image_attachment_fields_to_save
line 1029 basename ---->  ihacklog_basename 

最后,上一张图:

Tagged in : wp问题

All Comments (0)
Gravatar image
No Comments