BILIBIBI

hitokoto 本地缓存方案

hitokoto.us 是一个一句话分享网站,现在已经收录了数千条的一言。官方提供了完善的API供各站点调用,不过由于机房位置的原因,官方的服务器在国内时常被墙,导致页面加载卡住。

要解决这种问题,最好的方法就是把数据都缓存到自己的服务器上。经过长时间的抓取,我已经抓取了官方大部分的一言(有几条始终抓不到,可能是官方隐藏了):

注:如果你用的是Discuz!X论坛的话请到应用中心下载我写好的插件:http://addon.discuz.com/?@cv_hitokoto.plugin
附件:cv_hitokoto.zip(旧版本)

系统收录:http://hitokoto.api.bilibibi.me/hitokoto.json
个人收录:http://hitokoto.api.bilibibi.me/hitokotouid.json
(个人收录因为没经官方审核,可能会有一些广告,我会定期检查并删除里面的广告,但不保证能全部删除)

数据采用JSON+UrlEncode(一开始没用UrlEncode结果全是乱码)格式,更新的时候可以用file_get_contents或Curl获取。(注意:根据官方手册,PHP的UrlEncode采用旧标准编码,如果直接用JS解码的话会出现空格变加号的问题)

数据结构:

Array(
  [0] => Array(
    ['catname'] => '分类',
    ['author'] => '投稿人',
    ['date'] => '投稿时间',
    ['id'] => 'ID(可用<a rel="nofollow" href="http://hitokoto.us/view/'.$hiko['id'].'.html">链接到官方页面)',
    ['text'] => '一言内容',
    ['source'] => '来源(可能为空)',
  ),
  [1] => Array(
    ...
  ),
  ...
  ['num'] => '总数',
)

一个简易的更新页面:

<?php
  function curl_get_contents($url) { 
    $curlHandle = curl_init(); 
    curl_setopt($curlHandle,CURLOPT_URL,$url); 
    curl_setopt($curlHandle,CURLOPT_RETURNTRANSFER,1); 
    curl_setopt($curlHandle,CURLOPT_TIMEOUT,5); 
    $result = curl_exec($curlHandle); 
    curl_close($curlHandle); 
    return $result; 
  }
  
  if(function_exists('curl_init') && function_exists('curl_setopt') && function_exists('curl_exec') && function_exists('curl_close')) {
    $contents = 'curl_get_contents';
  }else{
    $contents = 'file_get_contents';
  }
  
  stream_context_set_default(array('http' => array('method' => 'HEAD')));
  
  $hitokototime = get_headers('http://hitokoto.api.bilibibi.me/hitokoto.json',1);
  $hitokototime = strtotime($hitokototime['Last-Modified']);
  $hitokotouidtime = get_headers('http://hitokoto.api.bilibibi.me/hitokotouid.json',1);
  $hitokotouidtime = strtotime($hitokotouidtime['Last-Modified']);
  
  if(isset($_POST['update'])){
    $hitokoto = call_user_func($contents,'http://hitokoto.api.bilibibi.me/hitokoto.json');
    $hitokoto = json_decode($hitokoto,1);
    $hitokotouid = call_user_func($contents,'http://hitokoto.api.bilibibi.me/hitokotouid.json');
    $hitokotouid = json_decode($hitokotouid,1);
    
    if(!$hitokoto || !$hitokotouid){
      die('数据获取失败');
    }
    
    foreach($hitokoto as &$value){
      foreach($value as $k => $v){
        $value[$k] = urldecode($v);
        //$value[$k] = iconv('UTF-8', 'GBK//IGNORE',urldecode($v)); //页面编码不是UTF-8时
      }
    }
    
    foreach($hitokotouid as &$value){
      foreach($value as $k => $v){
        $value[$k] = urldecode($v);
        //$value[$k] = iconv('UTF-8', 'GBK//IGNORE',urldecode($v)); //页面编码不是UTF-8时
      }
    }
    
    $hitokoto['time'] = $hitokototime;
    $hitokotouid['time'] = $hitokotouidtime;
    
    $hitokoto = '<?php return '.var_export($hitokoto,1).";\n";
    file_put_contents('./cache_hitokoto.php',$hitokoto);
    
    $hitokotouid = '<?php return '.var_export($hitokotouid,1).";\n";
    file_put_contents('./cache_hitokotouid.php',$hitokotouid);
  }
  
  $cache = @include './cache_hitokoto.php';
  $cacheuid = @include './cache_hitokotouid.php';
  
  echo 'hitokoto系统收录:';echo '<br>';
  echo '本地缓存时间:',$cache['time']?date('Y-m-d H:i:s',$cache['time']):'无缓存';echo '<br>';
  echo '条数:',$cache['num'];echo '<br>';
  echo '云端缓存时间:',date('Y-m-d H:i:s',$hitokototime);echo '<br>';
  echo ($cache['time']>=$hitokototime)?'<font color="#009900">无更新</font>':'<font color="#0000CC">有更新</font>';echo '<br><br>';
  
  echo 'hitokoto个人收录:';echo '<br>';
  echo '本地缓存时间:',$cache['time']?date('Y-m-d H:i:s',$cacheuid['time']):'无缓存';echo '<br>';
  echo '条数:',$cacheuid['num'];echo '<br>';
  echo '云端缓存时间:',date('Y-m-d H:i:s',$hitokototime);echo '<br>';
  echo ($cacheuid['time']>=$hitokotouidtime)?'<font color="#009900">无更新</font>':'<font color="#0000CC">有更新</font>';echo '<br><br>';
  
  echo '<form method="POST"><input type="submit" value="更新" name="update" /></form>';
?>

可以这样获取:

<?php
  $hitokoto = @include './cache_hitokoto.php';
  $hitokotouid = @include './cache_hitokotouid.php';

  $c = rand(0,1);//从系统收录和随机收录中随机选择

  if($c){
    $max = $hitokotouid['num'];
    $num = mt_rand(0,$max);
    $hiko = $hitokotouid[$num];
  }else{
    $max = $hitokoto['num'];
    $num = mt_rand(0,$max);
    $hiko = $hitokoto[$num];
  }
  
  if($hiko['source']){
    $add = '&#10出自:'.$hiko['source'];
  }

  echo '<span title="分类:',$hiko['catname'],$add,'&#10投稿:',$hiko['author'],' @ ',$hiko['date'].'"><a rel="nofollow" href="http://hitokoto.us/view/',$hiko['id'],'.html" target="_blank">',$hiko['text'],'</a></span>';
?>

也可以像这样做成API:

<?php
  header("Content-type: application/x-javascript");

  $hitokoto = @include './cache_hitokoto.php';
  $hitokotouid = @include './cache_hitokotouid.php';

  $c = rand(0,1);//从系统收录和随机收录中随机选择

  if($c){
    $max = $hitokotouid['num'];
    $num = mt_rand(0,$max);
    $hiko = $hitokotouid[$num];
  }else{
    $max = $hitokoto['num'];
    $num = mt_rand(0,$max);
    $hiko = $hitokoto[$num];
  }

  if($hiko['source']){
    $add = '&#10出自:'.$hiko['source'];
  }

  echo 'document.write(\'<span title="分类:',$hiko['catname'],$add,'&#10投稿:',$hiko['author'],' @ ',$hiko['date'],'"><a rel="nofollow" href="http://hitokoto.us/view/',$hiko['id'],'.html" target="_blank">',$hiko['text'],'</a></span>\');';
?>

本文介绍的是较简单的文件方式,此方式更新比较容易但效率较低,若你的网站访问量较大还是推荐采用数据库方式(Discuz!的插件采用的是数据库方式,更新脚本是update.inc.php,获取脚本是hook.class.php或ca.inc.php)

标签: none

已有 4 条评论

  1. 你知道 Discuz 函数文档在哪么,找不到完整的 QAQ

    1. 已经抽了

      找下网上有没有别人提取的镜像吧

    2. 我保存的早就没了

      1.  我在读别人的插件代码,有的只能查到函数解析

添加新评论