解决WordPress中文附件attachment以及tag URL导致的404找不到页面问题

!本文可能 超过1年没有更新,今后内容也许不会被维护或者支持,部分内容可能具有时效性,涉及技术细节或者软件使用方面,本人不保证相应的兼容和可操作性。

之前从Typecho转换到WordPress的,结果使用网上的转换程序勉强转换成功,没想到却带来了一堆后遗症,其中比较明显的就是中文url导致的404找不到页面的问题。

其实搜索“Wordpress 中文 tag 404”关键字词就可以找到大量关于这类问题以及解决方案的信息,这些解决方案无非是要求修改WordPress的wp-include/classes.php(3.1之前版本)或wp-include/class-wp.php(3.1+之后版本)的源代码,增加UTF-8与GBK的一个转换;或是修改rewrite.php改变重写规则。这些我没有去尝试,我感觉修改官方代码的做法不是很妥当的,即使修改了,以后升级什么的,原先修改的内容仍然会被替换,或者修改有可能会导致新的问题等等,所以我不建议修改官方源代码。

如果默认官方表前缀wp_的话,导致这个问题的中文tag在MySQL的位置为表wp_terms的列slug,中文附件attachment所在MySQL的位置为表wp_posts的列post_name。这次转换前我尝试着发布了一篇带有中文tag或者attachment中文名称的文章,并且访问这个tag或者附件正常,然后再查看MySQL数据库。发现其中attachment的post_name以及tag所在的slug均被改写成类似%E8%A7%A3%E6%9E%90这样的字符串,其实这类字符串是符合URL编码标准的,一般我们的输入的字符串在提交URL前均会被编码成形如这样的编码;再看看出问题的编码形式,直接是中文未经过任何编码,所以需要访问这类资源需要进行编码转换才能正常访问,否则就会出现404找不到页面的问题。

其实我们可以通过PHP内置的urlencode对attachment的post_name以及tag所在的slug进行一次编码然后再写入数据库,以避免出现这类问题,这里我对所有附件attachment的post_name进行了一次urlenocde编码,代码如下(测试前请备份数据库)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
 
// Author: wangye
// For more information please visit http://wangye.org/
define('MYSQL_HOSTNAME', 'localhost');
define('MYSQL_USERNAME', 'mysqluser');
define('MYSQL_PASSWORD', 'mysqlpassword');
define('MYSQL_DATABASE', 'db1');
define('MYSQL_TABLEPRE', 'wp_'); // 表前缀
 
error_reporting(E_ALL);
ini_set('display_errors','On');
 
$link = mysql_connect(MYSQL_HOSTNAME, MYSQL_USERNAME, MYSQL_PASSWORD);
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
echo 'Connected successfully<br />';
 
mysql_select_db(MYSQL_DATABASE, $link);
 
// 下面三句的作用是设置当前连接编码为UTF-8标准。
// 所以请确保你的WordPress数据库是符合UTF-8编码标准,
// 否则请自行将下面的UTF-8改成相应的字符集。
mysql_set_charset('utf8',$link);
mysql_query('SET NAMES UTF8');
mysql_query("SET character_set_results = 'utf8', " . 
  "character_set_client = 'utf8', " .
  "character_set_connection = 'utf8', " .
  "character_set_database = 'utf8', " .
  "character_set_server = 'utf8'", $link);
// 字符设置结束
echo '<br />';
 
// 下面为encode编码附件attachment中的中文post_name
$res = mysql_query("SELECT `ID`,`post_name` ' .
 'FROM `{$MYSQL_TABLEPRE}posts` WHERE `post_type`='attachment'");
 
while($row=mysql_fetch_array($res)) {
       echo 'id=' . $row[0] . ' - ' . 'name=' . urlencode($row[1]) . ' --- ';
    if (mysql_query('UPDATE `' . MYSQL_TABLEPRE . 'posts` SET `post_name`=\''. 
        urlencode($row[1]) .'\' WHERE `ID` ='. $row[0] . 
        ' AND `post_type`=\'attachment\'')) {
      echo 'UPDATED!<br />';
    }
}
// 编码结束
 
mysql_close($link);
 
echo 'Closed<br />';
exit;

同样的,对于中文tag,只需要将上面代码的编码部分改写成下面这样就可以了:

35
36
37
38
39
40
41
42
43
44
45
46
// 下面为encode编码tag中的中文slug
$res = mysql_query("SELECT `term_id`,`slug` ' .
 'FROM `{$MYSQL_TABLEPRE}terms`");
 
while($row=mysql_fetch_array($res)) {
       echo 'id=' . $row[0] . ' - ' . 'name=' . urlencode($row[1]) . ' --- ';
    if (mysql_query('UPDATE `' . MYSQL_TABLEPRE . 'terms` SET `slug`=\''. 
        urlencode($row[1]) .'\' WHERE `term_id` ='. $row[0])) {
      echo 'UPDATED!<br />';
    }
}
// 编码结束

限于条件,上面这段代码我就不测试了,如果有什么bug记得提醒我一下,另外再说一下,测试上述代码前记得备份你的数据库

若无特别说明,本网站文章均为原创,原则上这些文章不允许转载,但是如果阁下是出于研究学习目的可以转载到阁下的个人博客或者主页,转载遵循创作共同性“署名-非商业性使用-相同方式共享”原则,请转载时注明作者出处谢绝商业性、非署名、采集站、垃圾站或者纯粹为了流量的转载。谢谢合作!
请稍后...

发表评论

电子邮件地址不会被公开。 必填项已用*标注