An english version of this post can be found here .
把站台從 wordpress 1.5 升上 wordpress 2.0 的人們,可能發現不能 Trackback了。我,也中標了。
Ah Knight’s Blog提供了一個蠻暴力的解法變通的方法:把資料庫中的 to_ping欄位給清光光,並提及可能的原因是:
this problem is because of to_ping field contain some char ( including space, tab which represent by \n\r )
正好在 IRC 上,我跟 ijliao、priv也在討論這個問題,既然問題可能出在 to_ping這個欄位,於是乾脆進source裡翻翻看,看問題到底出在哪裡。
不翻則已,一翻嚇出一聲冷汗。
WordPress 1.5以前發表文章要送出時,使用者得先等 trackback/ping 別人的動作完成。當有許多的URL要trackback時,一個個tackback的結果是換來使用者的漫長等待。因此,在 WordPress 2.0以後,改用了另外一種方式以減少文章按下「發表」之後的等待。其作法是另外用fsockopen呼叫另一個 script來作trackback的動作:wp-admin/execute-pings.php
問題就出在這個 wp-admin/execute-pings.php 裡。
在 wp-admin/execute-pings.php 中,trackback的部份是這樣子實作的:
// Do Trackbacks
while ($trackback = $wpdb->get_row("SELECT ID FROM $wpdb->posts WHERE TRIM(to_ping) != '' AND post_status != 'draft' LIMIT 1")) {
echo "Trackback : $trackback->ID";
do_trackbacks($trackback->ID);
} ?>
正常情況下,程式去讀出資料庫中第一筆需要trackback 的post,做完 do_trackbacks,然後以此類推,直到最後一筆做完為止。但是有沒有發現到,萬一第一筆(or第 n筆)沒有trackback成功,仍然留在資料庫中時,會發生什麼事?
是的,用 while這個寫法會使得程式一直嘗試對第一筆符合的資料做 trackback 動作,永遠不會停下來。(這就是我討厭 while的地方)
於是程式永遠在跑第一筆,當然不可能跑到最後一筆(就是要送出 trackback 的那一筆),於是乎,trackback就沒有送出去。
那麼,又是什麼原因為讓之前沒送成功的trackback再次失敗呢?
第一種情況:對方的網頁根本就關掉 trackback了,或是要trackback的網址已經不存在了。那麼trackback當然會失敗。
第二種情況:在 wp-includes/function-post.php 的 do_trackbacks()裡,要先呼叫 wp-includes/function-post.php 的 get_to_ping() 把當要trackback的網址(to_ping)切成array,但是當 to_ping 只剩下一些怪怪的值,如 “\n”(換行)符號,會被下面這一行濾掉:
$to_ping = preg_split('/\s/', $to_ping, -1, PREG_SPLIT_NO_EMPTY);
於是傳回的array變empty array,再碰上 do_trackbacks()裡的這一行:
if ( empty($to_ping) )
return;
噹噹! 就什麼也不做地走掉了,然後回去又碰到 while,就是永無止盡的無窮迴圈了。
解決辦法:在 WP 出新版/新patch解決這個問題之前,可以試試自己改source:
PS. 這只是頭痛醫頭,pingback 也有同樣的問題,不過我不管他了。XD
wp-includes/function-post.php line 700:
if ( empty($to_ping) )
return;
改成
if ( empty($to_ping) ) {
$wpdb->query("UPDATE $wpdb->posts SET to_ping = '' WHERE ID ='$post_id'");
return;
}
wp-admin/execute-pings.php line 21:
// Do Trackbacks
while ($trackback = $wpdb->get_row("SELECT ID FROM $wpdb->posts WHERE TRIM(to_ping) != '' AND post_status != 'draft' LIMIT 1")) {
echo "Trackback : $trackback->ID";
do_trackbacks($trackback->ID);
}
改成
// Do Trackbacks
// The old code will cause infinite loop when trackback failed.
//
$trackbacks = $wpdb->get_results("SELECT ID FROM $wpdb->posts WHERE TRIM(to_ping) != '' AND post_status != 'draft'");
if (is_array($trackbacks) && count($trackbacks)) {
foreach ($trackbacks AS $trackback ) {
echo "Trackback : $trackback->ID";
do_trackbacks($trackback->ID);
} // end foreach
}
或是直接下載 patch檔 解開後,放到要patch的檔案目錄下。在命令列下用 patch 指令(如果有的話):
patch functions-post.php functions-post.php.diff
patch execute-pings.php execute-pings.php.diff
好樣 ..! 可是我滿反對改source …
還有堅決反對把我的方法叫做 ‘暴力的解法’
我覺得我的方式是用來過濾to_ping~~~~~
Knight:
我也不喜歡改source 🙂
用清欄位的方法過陣子還是會出問題。
可惜不能用plugin實作。
最好的方式還是讓官方release修正版本。
我放了一些其他的格式,包括 zip 檔/patch好的檔案等,要的人可以到英文版那邊下載。
我的tb不行,但是pb是好的,真奇怪。而且有相当一部分人tb是好的。
剛剛去 svn update,發現這份 patch 已經加到官方 codebase 裡了。
william:
看到了,感謝你的通知。
唉,不知利用了多少方法,都不成功。有谁可以来一个详细的教程。
把資料庫中的 to_ping欄位給清光光?这是说把里面的内容清光光还是把该表删掉。两种方法我都试了,内容清光光,那之前发的贴子出现一个框框,里面全是代码。将该表删掉,不能发贴。。。。。。。
有谁解决了这个问题,请给我一个方法,可以吗?
用 PipperL 這篇文章介紹的改 WordPress 程式碼的方法比較安全吧,資料庫的內容最好不要隨便亂碰,可能會有意想不到的副作用。
PipperL 所提的修改方法,已經被 WordPress 官方採納,列入 changeset #3384。如果你不熟悉 patch 的使用法,不妨去上述地點下載更正過的 wp-includes/functions-post.php 及 wp-admin/execute-pings.php 檔。
如您所说的修改了,不过看似还无法正常trackback
就能ping通您的,其他的好像都不通
TB的字符集很是麻烦啊。。
[…] 讓 WP2.0 可以正常trackback (終極邊疆BLOG) […]
看来碰到类似问题的可不止我一个啊