6年以后的变化

我都忘记曾写过这样一篇文章《Google总让我惊喜》,居然被网友翻出来评论了一把。Google Reader 要关闭这件事,的确让人伤心,因为:

From your 189 subscriptions, over the last 30 days you read 258 itemsclicked 7 itemsstarred 13 items, and emailed 0 items.

Since October 30, 2006 you have read a total of 62,661 items.

其实这心,在 Google Reader 中的 Share 按钮被改成 +1 以后,已经伤了一次了。在我这样一个中国用户眼里,Google Reader 曾是 Google 最好的 SNS 产品,就是因为 Note 和 Share。

不太能理解 Google 放弃 Reader 的决策。基于自己的很多优秀产品(Gmail, Reader, Android, Google+),Google 吸引了很多忠实的注册用户,这一点被其它很多公司羡慕——包括百度,除了腾讯。产品推广的时候,吸引用户注册使用往往是一件很困难的事情,这时就能凸显出用户基数大的好处了。好产品越多,用户的忠诚度肯定越高。如果只有单一的产品,产品没落后用户就会轻易地流失,从这个角度看,我觉得保留 Google Reader 看起来不是一件坏事。

无论如何,Google Reader 是快没了,总要寻找其它的替代品。从目前我的探索来看,Feedly 像是一个比较好的选择,但它的连接不是 https 的,可能会被关键词过滤(或者直接被封掉)。鲜果阅读器看起来也还可以,起码比 QQ 阅读看着更像 Google Reader。豆瓣 9 点就不说了,同步的速度是个渣,也没用心做。

Feedburner 订阅数图标显示解决办法

很多人以前都用过 Feedburner 烧制自己的 rss feed,但是由于众所周知的原因,Feedburner 的 rss 输出在中国网,封天下无法访问了(不信您可以点击一下我博客右侧的 Feedburner 图标)。虽然用 Google Reader 订阅 Feedburner 的 feed 仍然不受影响,但是博客订阅数图标无法正常显示,所以很多人好奇我是如何让 Feedburner 订阅数图标仍然显示在博客侧栏的

更新:刚才写完,我想看看 feed 有没有更新,忽然发现 Feedburner 的 rss 可以访问了,试了试订阅数图标,也能正常显示了。GFW 打盹了?我说这几天 Feedburner 订阅数增加那么快呢。总之我这篇文章算是白写了......呜呜呜呜,没有提前重现问题的后果。

又更新:12 月 23 日,我又无法访问 feedburner 的 RSS 了,才一天那!看来我这篇文章还算没有完全白写,不能幻想 GFW 的仁慈。

其实我以前是用的这篇博客里的方法。这个方法要求你有个国外主机空间,碰巧我能使用师兄的空间,把那篇文章中的 feedburner.php 上传到空间里就可以使用了。

但是使用过程中我发现这个方法有个很严重的问题:不支持并发访问。这是由于它的方法太生硬,先读取自己文件的内容,如果文件中写的时间比当前时间早 4 个小时,就下载新的订阅数图标,重写自身文件(修改更新时间那一行),并将订阅数图标附在文件最后。注意到这里,它会重写自身文件,一个 php 文件读取自己,改一行再重新写入自己,那么如果多个用户同时访问该文件,那不就乱套了?

所以我对它进行了修改,改为一个相对干净的方法:抓取订阅数统计图标保存为一个 gif 文件,每次访问 php 文件时,php 去判断当前时间与该 gif 文件最后修改时间的差,如果大于过期时间,就重新抓取订阅数统计图标更新 gif 文件,最后将访问重定向到 gif 文件。点击这里 http://solrex.org/feedburner.php 查看效果。

具体 php 代码如下(其实我本想用 file_get_contents 函数的,但发现不好用,只好还用这个原来的 httpSocketConnection 函数了,显得冗长了些):

<?php
$username = "username"// Feedburner account name.
$expire_time = 3600;   // Expire time(in second, 3600s = 1 hour).

$fb_url = "feeds.feedburner.com";
$gif_path = "/~fc/".$username."?bg=99CCFF&fg=444444&anim=0";
$localfile = "fb_".$username.".gif";

if(!function_exists('httpSocketConnection')){
  function httpSocketConnection($host, $method, $path, $data)
  {
    $method = strtoupper($method);
    if ($method == "GET") {
      $path.= '?'.$data;
    }
    $filePointer = fsockopen($host, 80, $errorNumber, $errorString);
    if (!$filePointer) {
      return false;
    }
    $requestHeader = $method." ".$path."  HTTP/1.1\r\n";
    $requestHeader.= "Host: ".$host."\r\n";
    $requestHeader.= "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0\r\n";
    $requestHeader.= "Content-Type: application/x-www-form-urlencoded\r\n";
    if ($method == "POST") {
      $requestHeader.= "Content-Length: ".strlen($data)."\r\n";
    }
    $requestHeader.= "Connection: close\r\n\r\n";
    if ($method == "POST") {
      $requestHeader.= $data;
    }          
    fwrite($filePointer, $requestHeader);
    $responseHeader = '';
    $responseContent = '';
    do {
      $responseHeader.= fread($filePointer, 1);
    }
    while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));
    if (!strstr($responseHeader, "Transfer-Encoding: chunked")) {
      while (!feof($filePointer)) {
        $responseContent.= fgets($filePointer, 128);
      }
    } else {
      while ($chunk_length = hexdec(fgets($filePointer))) {
        $responseContentChunk = '';
        $read_length = 0;
        while ($read_length < $chunk_length) {
          $responseContentChunk .= fread($filePointer, $chunk_length - $read_length);
          $read_length = strlen($responseContentChunk);
        }
        $responseContent.= $responseContentChunk;
    &nb
sp;   fgets($filePointer);
      }
    }
    return chop($responseContent);
  }
}

function get_fbcount($host, $path, $file)
{
  $content = httpSocketConnection($host, 'GET', $path, NULL);
  $fp = fopen( $file,"w" );
  fwrite($fp, $content);
  fclose($fp);
}

if (file_exists($localfile)) {
  $last_modified = filemtime($localfile);
  if ( date('U') - $last_modified > $expire_time) {
    get_fbcount($fb_url, $gif_path, $localfile);
  }
} else {
  get_fbcount($fb_url, $gif_path, $localfile);
}
Header("Location: $localfile");
?>

将上述代码保存为一个 php 文件,比如 fb_username.php,修改用户名和过期时间,上载到国外或者港台能正常访问 Feedburner 的主机空间中,您就可以在网页中用:

<img src="http://your.host.domain/fb_username.php" style="border: 0pt none ;" alt="Feedburner">

来引用 Feedburner 订阅计数图标了。由于这个 php 脚本按照用户名保存 gif 图标,您可以在一个服务器上为多人提供引用,只需修改 php 文件的 usrname 一项,并上传为另一个 php 文件,您也可以将这两个变量改为 php 文件的参数(不建议这样做,因为会被别人利用)。

您也可以在这里下载到 feedburner.txt,要记得将其后缀改为 php 哦。

Google Reader 的一点问题

Google Reader 是我非常喜欢的在线博客订阅器,自从发现这个服务之后我就结束了尝试 N 个离线博客订阅软件的历史。用 Google Reader 看别人的博客好像看邮件一样,而且可以抓取一些国内无法访问的国外博客系统的 feed,很方便。

自从使用以来它就一直很稳定,不过这两天我发现 GR 貌似出现了一些小问题:一个是抓取我的博客 feed 有错,订阅的 http://feeds.feedburner.com/solrex 的条目中忽然多出了十条和我同一服务器的某个博客条目,而 feedburner 的原始连接中并没有这十条内容;二是抓取 feed 的时候没有通知订阅用户数,所以我的 feedburner 和 feedsky 显示的订阅用户一下子少了一大半,本来就只有一百多人订阅,现在显示的订阅数就更可怜了。

本来我以为这可能是个别问题,可是著名博客和菜头也在文章中说某些用户的订阅在 GR 中显示为乱码。这就叫人奇怪了,为什么 GR 在这几天发生那么多问题?难道是 GR 在测试新功能?

虽然 GR 这两天出了那么多问题,我仍然要推荐它,下面简单介绍一下我觉得比较好的特色:

1. 共享阅读。一种方法是把共享阅读块放在自己的主页上(看我的博客右侧栏),另一种是在 GR 的阅读视图里与 Google 好友共享阅读条目,还有一种方法就是把条目直接 email 给别人。

2. 快捷键操作。GR 有很多键盘快捷键,比如:j 阅读下一条,k 阅读上一条,n 移到下一条,p 移到上一条,o 打开列表项,这样操作起来非常方便。

3. 使用安全连接(https)的 GR,避免连接被重置。在中国国内某些网络条件下,明文传输的网页是会被过滤的,如果订阅的博客文章中有敏感词条,路由器就会重置网络连接,比如经常看到的浏览器提示“与服务器的连接被重置”就是由于这个原因。使用安全连接的 GR https://www.google.com/reader/view/ 能避免此类状况的发生。(此方法同样适用于 Gmail 的连接不稳定现象)

4. feed 阅读趋势。GR 可以统计你的阅读情况,并提供一些阅读趋势排行榜,以供你了解自己的阅读习惯。