Advertisement
Guest User

rep2 expackで2ch APIを使うパッチ 差分取得出来るよう修正 rsky氏のrep2-expackに対応

a guest
Feb 27th, 2015
1,128
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 13.67 KB | None | 0 0
  1.  conf/conf.inc.php      |   1 +
  2.  lib/ThreadRead.php     | 247 +++++++++++++++++++++++++++++++++++++++++++++++++
  3.  lib/auth2chapi.inc.php |  74 +++++++++++++++
  4.  3 files changed, 322 insertions(+)
  5.  
  6. diff --git a/conf/conf.inc.php b/conf/conf.inc.php
  7. index 62ff466..feec1bd 100644
  8. --- a/conf/conf.inc.php
  9. +++ b/conf/conf.inc.php
  10. @@ -261,6 +261,7 @@ function p2_init()
  11.          'auth_user_file'    => 'p2_auth_user.php',      // 認証ユーザ設定ファイル(データPHP)
  12.          'login_log_file'    => 'p2_login.log.php',      // ログイン履歴 (データPHP)
  13.          'login_failed_log_file' => 'p2_login_failed.dat.php',   // ログイン失敗履歴 (データPHP)
  14. +        'sid2chapi_php'        => 'p2_sid2chapi.php',         // 2ch APIセッションID記録ファイル (データPHP)
  15.      );
  16.      foreach ($preferences as $k => $v) {
  17.          $_conf[$k] = $_conf['pref_dir'] . '/' . $v;
  18. diff --git a/lib/ThreadRead.php b/lib/ThreadRead.php
  19. index 1d76626..52d200b 100644
  20. --- a/lib/ThreadRead.php
  21. +++ b/lib/ThreadRead.php
  22. @@ -110,6 +110,26 @@ class ThreadRead extends Thread
  23.                  }
  24.                  $this->_downloadDat2chKako($_GET['kakolog'], $ext);
  25.  
  26. +            //2ch はAPI経由で落とす
  27. +            } elseif (P2Util::isHost2chs($this->host)) {
  28. +                $AppKey = 'xxfvFQcOzpTBvwuwPMwwzLZxiCSaGb';
  29. +                $HMKey = 'DgQ3aNpoluV1cl3GFJAqitBg5xKiXZ';
  30. +                // ログインしてなければ or ログイン後、55分以上経過していたら自動再ログイン
  31. +                if (!file_exists($_conf['sid2chapi_php']) ||
  32. +                    (filemtime($_conf['sid2chapi_php']) < time() - 60*55))
  33. +                {
  34. +                    if (!function_exists('authenticate_2chapi')) {
  35. +                        include P2_LIB_DIR . '/auth2chapi.inc.php';
  36. +                    }
  37. +                    if (!authenticate_2chapi($AppKey,$HMKey)) {
  38. +                        $this->getdat_error_msg_ht .= $this->get2chDatError();
  39. +                        $this->diedat = true;
  40. +                        return false;
  41. +                    }
  42. +               }
  43. +
  44. +                include $_conf['sid2chapi_php'];
  45. +                $this->_downloadDat2chAPI($AppKey,$HMKey,$SID2chAPI,$this->length);
  46.              // 2ch or 2ch互換
  47.              } else {
  48.                  // DATを差分DLする
  49. @@ -120,6 +140,233 @@ class ThreadRead extends Thread
  50.      }
  51.  
  52.      // }}}
  53. +    // {{{ _downloadDat2chAPI()
  54. +    
  55. +    /**
  56. +     * 2chAPIで DAT を差分ダウンロードする
  57. +     *
  58. +     * @return mix 取得できたか、更新がなかった場合はtrueを返す
  59. +     */
  60. +    protected function _downloadDat2chAPI($AppKey,$HMKey,$sid,$from_bytes)
  61. +    {
  62. +        global $_conf;
  63. +        global $debug;
  64. +
  65. +        if (!($this->host && $this->bbs && $this->key)) {
  66. +            return false;
  67. +        }
  68. +        
  69. +        if ($sid == '') {
  70. +            return false;
  71. +        }
  72. +
  73. +        $from_bytes = intval($from_bytes);
  74. +
  75. +        if ($from_bytes == 0) {
  76. +            $zero_read = true;
  77. +        } else {
  78. +            $zero_read = false;
  79. +            $from_bytes = $from_bytes - 1;
  80. +        }
  81. +
  82. +        $serverName = explode('.', $this->host);
  83. +        //$url = "http://{$this->host}/{$this->bbs}/dat/{$this->key}.dat";
  84. +        //$url="http://news2.2ch.net/test/read.cgi?bbs=newsplus&key=1038486598";
  85. +        $url = 'https://api.2ch.net/v1/'.$serverName[0].'/'.$this->bbs.'/'.$this->key;
  86. +        $message = '/v1/'.$serverName[0].'/'.$this->bbs.'/'.$this->key.$sid.$AppKey;
  87. +        $HB = hash_hmac("sha256", $message, $HMKey);
  88. +
  89. +        $headers = "User-Agent: Mozilla/3.0 (compatible; JaneStyle/3.80..)\r\n";
  90. +        $headers .= "Connection: close\r\n";
  91. +        $headers .= "Content-Type: application/x-www-form-urlencoded\r\n";
  92. +        
  93. +        $purl = parse_url($url); // URL分解
  94. +
  95. +        if (!$zero_read) {
  96. +            $headers .= "Range: bytes={$from_bytes}-\r\n";
  97. +        }
  98. +
  99. +        if ($this->modified) {
  100. +            $headers .= "If-Modified-Since: {$this->modified}\r\n";
  101. +        }
  102. +
  103. +        // Basic認証用のヘッダ
  104. +        if (isset($purl['user']) && isset($purl['pass'])) {
  105. +            $headers .= "Authorization: Basic ".base64_encode($purl['user'].":".$purl['pass'])."\r\n";
  106. +        }
  107. +        
  108. +        $post_values = array(
  109. +            'sid' => $sid,
  110. +            'hobo' => $HB,
  111. +            'appkey' => $AppKey,
  112. +        );
  113. +        
  114. +        $http = array(
  115. +            'method' => 'POST',
  116. +            'header' => $headers,
  117. +            'content' => http_build_query($post_values),
  118. +        );
  119. +        
  120. +        // プロキシ
  121. +        if ($_conf['proxy_use']) {
  122. +            $http += array('proxy' => 'tcp://'.$_conf['proxy_host'].":".$_conf['proxy_port']);
  123. +            $http += array('request_fulluri' => true);
  124. +        }
  125. +
  126. +        $options = array('http' => $http);
  127. +        
  128. +        // WEBサーバへ接続
  129. +        $fp = @fopen($url, 'r', false, stream_context_create($options));
  130. +        if (!$fp) {
  131. +            self::_pushInfoConnectFailed($url, $errno, $errstr);
  132. +            $this->diedat = true;
  133. +            return false;
  134. +        }
  135. +        stream_set_timeout($fp, $_conf['http_read_timeout'], 0);
  136. +
  137. +        $body = '';
  138. +        $code = null;
  139. +        $start_here = false;
  140. +
  141. +        while (!p2_stream_eof($fp, $timed_out)) {
  142. +
  143. +            if ($start_here) {
  144. +
  145. +                if ($code == '200' || $code == '206') {
  146. +
  147. +                    while (!p2_stream_eof($fp, $timed_out)) {
  148. +                        $body .= fread($fp, 4096);
  149. +                    }
  150. +
  151. +                    if ($timed_out) {
  152. +                        self::_pushInfoReadTimedOut($url);
  153. +                        $this->diedat = true;
  154. +                        fclose($fp);
  155. +                        return false;
  156. +                    }
  157. +
  158. +                    // 末尾の改行であぼーんチェック
  159. +                    if (!$zero_read) {
  160. +                        if (substr($body, 0, 1) != "\n") {
  161. +                            //echo "あぼーん検出";
  162. +                            fclose($fp);
  163. +                            $this->onbytes = 0;
  164. +                            $this->modified = null;
  165. +                            return $this->_downloadDat2chAPI($AppKey,$HMKey,$sid,0); // あぼーん検出。全部取り直し。
  166. +                        }
  167. +                        $body = substr($body, 1);
  168. +                    }
  169. +
  170. +                    $file_append = ($zero_read) ? 0 : FILE_APPEND;
  171. +
  172. +                    if (FileCtl::file_write_contents($this->keydat, $body, $file_append) === false) {
  173. +                        p2die('cannot write file.');
  174. +                    }
  175. +
  176. +                    //$GLOBALS['debug'] && $GLOBALS['profiler']->enterSection("dat_size_check");
  177. +                    // 取得後サイズチェック
  178. +                    if ($zero_read == false && $this->onbytes) {
  179. +                        $this->getDatBytesFromLocalDat(); // $aThread->length をset
  180. +                        if ($this->onbytes != $this->length) {
  181. +                            fclose($fp);
  182. +                            $this->onbytes = 0;
  183. +                            $this->modified = null;
  184. +                            P2Util::pushInfoHtml("<p>rep2 info: {$this->onbytes}/{$this->length} ファイルサイズが変なので、datを再取得</p>");
  185. +                            //$GLOBALS['debug'] && $GLOBALS['profiler']->leaveSection("dat_size_check");
  186. +                            return $this->_downloadDat2chAPI($AppKey,$HMKey,$sid,0); //datサイズは不正。全部取り直し。
  187. +
  188. +                        // サイズが同じならそのまま
  189. +                        } elseif ($this->onbytes == $this->length) {
  190. +                            fclose($fp);
  191. +                            $this->isonline = true;
  192. +                            //$GLOBALS['debug'] && $GLOBALS['profiler']->leaveSection('dat_size_check');
  193. +                            return true;
  194. +                        }
  195. +                    }
  196. +                    //$GLOBALS['debug'] && $GLOBALS['profiler']->leaveSection('dat_size_check');
  197. +
  198. +                // スレッドがないと判断
  199. +                } else {
  200. +                    fclose($fp);
  201. +                    return $this->_downloadDat2chNotFound($code);
  202. +                }
  203. +
  204. +            } else {
  205. +                $meta = stream_get_meta_data($fp);
  206. +                foreach($meta['wrapper_data'] as $l)
  207. +                {
  208. +                    // ex) HTTP/1.1 304 Not Modified
  209. +                    if (preg_match('@^HTTP/1\\.\\d (\\d+) (.+)@i', $l, $matches)) {
  210. +                        $code = $matches[1];
  211. +
  212. +                        if ($code == '200' || $code == '206') { // Partial Content
  213. +                            ;
  214. +
  215. +                        } elseif ($code == '302') { // Found
  216. +
  217. +                            // ホストの移転を追跡
  218. +                            $new_host = BbsMap::getCurrentHost($this->host, $this->bbs);
  219. +                            if ($new_host != $this->host) {
  220. +                                fclose($fp);
  221. +                                $this->old_host = $this->host;
  222. +                                $this->host = $new_host;
  223. +                                return $this->_downloadDat2chAPI($AppKey,$HMKey,$sid,$from_bytes);
  224. +                            } else {
  225. +                                fclose($fp);
  226. +                                return $this->_downloadDat2chNotFound($code);
  227. +                            }
  228. +
  229. +                        } elseif ($code == '304') { // Not Modified
  230. +                            fclose($fp);
  231. +                            $this->isonline = true;
  232. +                            return '304 Not Modified';
  233. +
  234. +                        } elseif ($code == '416') { // Requested Range Not Satisfiable
  235. +                            //echo "あぼーん検出";
  236. +                            fclose($fp);
  237. +                            $this->onbytes = 0;
  238. +                            $this->modified = null;
  239. +                            return $this->_downloadDat2chAPI($AppKey,$HMKey,$sid,0); // あぼーん検出。全部取り直し。
  240. +
  241. +                        } else {
  242. +                            fclose($fp);
  243. +                            return $this->_downloadDat2chNotFound($code);
  244. +                        }
  245. +                    }
  246. +
  247. +                    if ($zero_read) {
  248. +                        if (preg_match('/^Content-Length: ([0-9]+)/i', $l, $matches)) {
  249. +                            $this->onbytes = intval($matches[1]);
  250. +                        }
  251. +                    } else {
  252. +
  253. +                        if (preg_match('@^Content-Range: bytes ([^/]+)/([0-9]+)@i', $l, $matches)) {
  254. +                            $this->onbytes = intval($matches[2]);
  255. +                        }
  256. +
  257. +                    }
  258. +
  259. +                    if (preg_match('/^Last-Modified: (.+)/i', $l, $matches)) {
  260. +                        //echo $matches[1] . '<br />'; //debug
  261. +                        $this->modified = $matches[1];
  262. +                    }
  263. +                }
  264. +                $start_here = true;
  265. +            }
  266. +        }
  267. +
  268. +        fclose($fp);
  269. +        if ($timed_out) {
  270. +            self::_pushInfoReadTimedOut($url);
  271. +            $this->diedat = true;
  272. +            return false;
  273. +        } else {
  274. +            $this->isonline = true;
  275. +            return true;
  276. +        }
  277. +    }
  278. +
  279. +    // }}}
  280.      // {{{ _downloadDat2ch()
  281.  
  282.      /**
  283. diff --git a/lib/auth2chapi.inc.php b/lib/auth2chapi.inc.php
  284. new file mode 100644
  285. index 0000000..cf342f4
  286. --- /dev/null
  287. +++ b/lib/auth2chapi.inc.php
  288. @@ -0,0 +1,74 @@
  289. +<?php
  290. +/**
  291. + * rep2 - 2chログイン
  292. + */
  293. +
  294. +// {{{ authenticate_2chapi()
  295. +
  296. +/**
  297. + * 2ch IDにログインする
  298. + *
  299. + * @return  string|false  成功したら2chAPI SIDを返す
  300. + */
  301. +
  302. +
  303. +/**
  304. +     * 2chAPIの SID を取得する
  305. +     *
  306. +     * @return mix 取得できた場合はSIDを返す
  307. +     */
  308. +    function authenticate_2chapi($AppKey, $HMKey)
  309. +    {
  310. +       global $_conf;
  311. +        $url = 'https://api.2ch.net/v1/auth/';
  312. +        $CT = time();
  313. +        $message = $AppKey.$CT;
  314. +        $HB = hash_hmac("sha256", $message, $HMKey);
  315. +        $values = array(
  316. +            'ID' => '',
  317. +            'PW' => '',
  318. +            'KY' => $AppKey,
  319. +            'CT' => $CT,
  320. +            'HB' => $HB,
  321. +        );
  322. +        $options = array('http' => array(
  323. +            'ignore_errors' => true,
  324. +            'method' => 'POST',
  325. +            'header' => implode("\r\n", array(
  326. +                'User-Agent: ',
  327. +                'X-2ch-UA: JaneStyle/3.80',
  328. +                'Content-Type: application/x-www-form-urlencoded',
  329. +            )),
  330. +            'content' => http_build_query($values),
  331. +        ));
  332. +        
  333. +        $response = '';
  334. +        $response = file_get_contents($url, false, stream_context_create($options));
  335. +        
  336. +        if (strpos($response, ':') != false)
  337. +        {
  338. +            $sid = explode(':', $response);
  339. +            
  340. +            $cont = sprintf('<?php $SID2chAPI = %s;', var_export($sid[1], true));
  341. +           if (false === file_put_contents($_conf['sid2chapi_php'], $cont, LOCK_EX)) {
  342. +               P2Util::pushInfoHtml("<p>p2 Error: {$_conf['sid2chapi_php']} を保存できませんでした。ログイン登録失敗。</p>");
  343. +               return '';
  344. +           }
  345. +            
  346. +            return $sid[1];
  347. +        }
  348. +        
  349. +        return '';
  350. +    }
  351. +// }}}
  352. +
  353. +/*
  354. + * Local Variables:
  355. + * mode: php
  356. + * coding: cp932
  357. + * tab-width: 4
  358. + * c-basic-offset: 4
  359. + * indent-tabs-mode: nil
  360. + * End:
  361. + */
  362. +// vim: set syn=php fenc=cp932 ai et ts=4 sw=4 sts=4 fdm=marker:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement