/** * SETTING.TXT をダウンロードして、パースして、キャッシュする * * @access public * @return true|null|false 成功|更新なし(キャッシュ)|失敗 */ function downloadSettingTxt() { global $_conf; $perm = $_conf['dl_perm'] ? $_conf['dl_perm'] : 0606; FileCtl::mkdirFor($this->setting_txt); // 板ディレクトリが無ければ作る $modified = null; if (file_exists($this->setting_srd) && file_exists($this->setting_txt)) { // 更新しない場合は、その場で抜けてしまう if (!empty($_GET['norefresh']) || isset($_REQUEST['word'])) { return null; // キャッシュが新しい場合も抜ける } elseif ($this->isSettingSrdCacheFresh()) { return null; } $modified = gmdate('D, d M Y H:i:s', filemtime($this->setting_txt)) . ' GMT'; } // DL /* // PHP5 if (!class_exists('HTTP_Request', false)) { require 'HTTP/Request.php'; } */ require_once 'HTTP/Request.php'; $params = array(); $params['timeout'] = $_conf['fsockopen_time_limit']; if ($_conf['proxy_use']) { $params['proxy_host'] = $_conf['proxy_host']; $params['proxy_port'] = $_conf['proxy_port']; } $req = new HTTP_Request($this->url, $params); $modified && $req->addHeader('If-Modified-Since', $modified); $req->addHeader('User-Agent', 'Monazilla/1.00 (' . $_conf['p2uaname'] . '/' . $_conf['p2version'] . ')'); $response = $req->sendRequest(); $error_msg = null; if (PEAR::isError($response)) { $error_msg = $response->getMessage(); } else { $code = $req->getResponseCode(); if ($code == 302) { // ホストの移転を追跡 require_once P2_LIB_DIR . '/BbsMap.php'; $new_host = BbsMap::getCurrentHost($this->host, $this->bbs); if ($new_host != $this->host) { $aNewSettingTxt = new SettingTxt($new_host, $this->bbs); return $aNewSettingTxt->downloadSettingTxt(); } } if (!($code == 200 || $code == 206 || $code == 304)) { //var_dump($req->getResponseHeader()); $error_msg = $code; } } // DLエラー if (strlen($error_msg)) { P2Util::pushInfoHtml(sprintf('<div>Error: %s<br>p2 info - %s に接続できませんでした。</div>', hs($error_msg), P2View::tagA(P2Util::throughIme($this->url), hs($this->url), array('target' => $_conf['ext_win_target'])))); touch($this->setting_txt); // DL失敗した場合(404)も touch する touch($this->setting_srd); return false; } $body = $req->getResponseBody(); // DL成功して かつ 更新されていたら保存 if ($body && $code != 304) { // したらば or be.2ch.net ならEUCをSJISに変換 if (P2Util::isHostJbbsShitaraba($this->host) || P2Util::isHostBe2chNet($this->host)) { $body = mb_convert_encoding($body, 'SJIS-win', 'eucJP-win'); } if (false === FileCtl::filePutRename($this->setting_txt, $body)) { die('Error: cannot write file'); } chmod($this->setting_txt, $perm); // パースして if (!$this->setSettingArrayFromSettingTxt()) { return false; } // srd保存する if (!$this->saveSettingSrd($this->setting_array)) { return false; } } else { // touchすることで更新インターバルが効くので、しばらく再チェックされなくなる touch($this->setting_txt); // 同時にキャッシュもtouchしないと、setting_txtとsetting_srdで更新時間がずれて、 // 毎回ここまで処理が来る(サーバへのヘッダリクエストが飛ぶ)場合がある。 touch($this->setting_srd); } return true; }
/** * 標準方法で 2ch互換 DAT を差分ダウンロードする * * @access private * @return true|string|false 取得できたか、更新がなかった場合はtrue(または"304 Not Modified")を返す */ function downloadDat2ch($from_bytes) { global $_conf; global $debug; if (!($this->host && $this->bbs && $this->key)) { return false; } $range_bytes = intval($from_bytes); if ($range_bytes == 0) { $zero_read = true; } else { $zero_read = false; $range_bytes = $from_bytes - 1; } //$url = 'http://' . $this->host . '/' . $this->bbs . '/dat/' . $this->key . '.dat'; $url = $this->getDatUrl($this->host, $this->bbs, $this->key); $purl = parse_url($url); $purl['query'] = isset($purl['query']) ? '?' . $purl['query'] : ''; // プロキシ if ($_conf['proxy_use']) { $send_host = $_conf['proxy_host']; $send_port = $_conf['proxy_port']; $send_path = $url; } else { $send_host = $purl['host']; $send_port = isset($purl['port']) ? $purl['port'] : null; $send_path = $purl['path'] . $purl['query']; } !$send_port and $send_port = 80; $request = 'GET ' . $send_path . " HTTP/1.0\r\n"; $request .= "Host: " . $purl['host'] . "\r\n"; $request .= "Accept: */*\r\n"; //$request .= "Accept-Charset: Shift_JIS\r\n"; //$request .= "Accept-Encoding: gzip, deflate\r\n"; $request .= "Accept-Language: ja, en\r\n"; $request .= "User-Agent: " . P2Util::getP2UA($withMonazilla = true) . "\r\n"; if (!$zero_read) { $request .= "Range: bytes={$range_bytes}-\r\n"; } $request .= "Referer: http://{$purl['host']}/{$this->bbs}/\r\n"; if ($this->modified) { $request .= "If-Modified-Since: " . $this->modified . "\r\n"; } // Basic認証用のヘッダ if (isset($purl['user']) && isset($purl['pass'])) { $request .= "Authorization: Basic " . base64_encode($purl['user'] . ":" . $purl['pass']) . "\r\n"; } $request .= "Connection: Close\r\n"; $request .= "\r\n"; // WEBサーバへ接続 $fp = @fsockopen($send_host, $send_port, $errno, $errstr, $_conf['fsockopen_time_limit']); if (!$fp) { P2Util::pushInfoHtml(sprintf('<p>サーバ接続エラー: %s (%s)<br>p2 info - %s に接続できませんでした。</div>', hs($errstr), hs($errno), P2View::tagA(P2Util::throughIme($url), hs($url), array('target' => $_conf['ext_win_target'])))); $this->diedat = true; return false; } // HTTPリクエスト送信 fputs($fp, $request); // HTTPヘッダレスポンスを取得する $h = $this->freadHttpHeader($fp); if ($h === false) { fclose($fp); $this->_pushInfoHtmlFreadHttpHeaderError($url); $this->diedat = true; return false; } // {{{ HTTPコードをチェック $code = $h['code']; // 206 Partial Content if ($code == "200" || $code == "206") { // OK。何もしない // Found } elseif ($code == "302") { // ホストの移転を追跡 require_once P2_LIB_DIR . '/BbsMap.php'; $new_host = BbsMap::getCurrentHost($this->host, $this->bbs); if ($new_host != $this->host) { fclose($fp); $this->old_host = $this->host; $this->host = $new_host; return $this->downloadDat2ch($from_bytes); } else { fclose($fp); // 2007/06/11 302の時に、UAをMonazillaにしないでDATアクセスを試みると203が帰ってきて、 // body中に'過去ログ ★'とあれば、●落ち中とみなすことにする。 // 仕様の確証が取れていないので、このような判断でよいのかはっきりしない。 // 203 Non-Authoritative Information // 過去ログ ★ /* 名無し募集中。。。<><>2007/06/10(日) 13:29:51.68 0<> http://mlb.yahoo.co.jp/headlines/?a=2279 <br> くわわ>>>>>>>>>>>>>>>>>>>>>井川 <>★くわわメジャー昇格おめ 売上議論14001★ 1001, 131428 (総レス数, サイズ)<><>1181480550000000 (最終更新)<><div style="color:navy;font-size:smaller;">|<br />| 中略<br />|</div><> 1001<><>Over 1000 Thread<> このスレッドは1000を超えました。 <br> もう書けないので、新しいスレッドを立ててくださいです。。。 <> 過去ログ ★<><>[過去ログ]<><div style="color:red;text-align:center;">■ このスレッドは過去ログ倉庫に格納されています</div><hr /><br />IE等普通のブラウザで見る場合 http://tubo.80.kg/tubo_and_maru.html<br />専用のブラウザで見る場合 http://www.monazilla.org/<br /><br />2ちゃんねる Viewer を使うと、すぐに読めます。 http://2ch.tora3.net/<br /><div style="color:navy;">この Viewer(通称●) の売上で、2ちゃんねるは設備を増強しています。<br />●が売れたら、新しいサーバを投入できるという事です。</div><br />よくわからない場合はソフトウェア板へGo http://pc11.2ch.net/software/<br /><br />モリタポ ( http://find.2ch.net/faq/faq2.php#c1 ) を持っていれば、50モリタポで表示できます。<br /> こちらから → http://find.2ch.net/index.php?STR=dat:http://ex23.2ch.net/test/read.cgi/morningcoffee/1181449791/<br /><br /><hr /><> */ $params = array(); $params['timeout'] = $_conf['fsockopen_time_limit']; if ($_conf['proxy_use']) { $params['proxy_host'] = $_conf['proxy_host']; $params['proxy_port'] = $_conf['proxy_port']; } $req = new HTTP_Request($url, $params); $req->setMethod('GET'); $err = $req->sendRequest(true); if (PEAR::isError($err)) { //var_dump('error'); } else { // レスポンスコードを検証 if ('203' == $req->getResponseCode()) { $body2 = $req->getResponseBody(); $reason = null; // $body2 "過去ログ ★<><>[過去ログ]<>「隊長! 過去ログ倉庫で、スレッド http://qb5.2ch.net/operate/kako/1103/11034/1103495887.html を発見しました。」<>過去ログ発見![改行]" if (preg_match('/<>過去ログ発見!/', $body2)) { //$reason = 'kakologsoko'; } elseif (preg_match('/過去ログ ★<>/', $body2)) { $reason = 'datochi'; } $this->downloadDat2chNotFound($reason); return false; } } $this->downloadDat2chNotFound(); return false; } // Not Modified } elseif ($code == '304') { fclose($fp); $this->isonline = true; return '304 Not Modified'; // Requested Range Not Satisfiable } elseif ($code == '416') { //echo "あぼーん検出"; fclose($fp); $this->clearOnbytesModified(); return $this->downloadDat2ch(0); // あぼーんを検出したので全部取り直し。 // 予期しないHTTPコード。スレッドがないと判断 } else { fclose($fp); $this->downloadDat2chNotFound(); return false; } // }}} $r = $this->getOnbytesFromHeader($h['headers'], $zero_read); if ($r !== false) { $this->onbytes = $r; } if (isset($h['headers']['Last-Modified'])) { $this->modified = $h['headers']['Last-Modified']; } // bodyを読む $body = ''; while (!feof($fp)) { $body .= fread($fp, 8192); } fclose($fp); // 末尾の改行であぼーんをチェックする if (!$zero_read) { if (substr($body, 0, 1) != "\n") { //echo "あぼーん検出"; $this->clearOnbytesModified(); return $this->downloadDat2ch(0); // あぼーんを検出したので全部取り直し。 } $body = substr($body, 1); } FileCtl::make_datafile($this->keydat, $_conf['dat_perm']); $done = false; if ($fp = fopen($this->keydat, 'rb+')) { flock($fp, LOCK_EX); if (0 === fseek($fp, $from_bytes)) { if (false !== fwrite($fp, $body)) { ftruncate($fp, $from_bytes + strlen($body)); $done = true; } } flock($fp, LOCK_UN); fclose($fp); } if (!$done) { trigger_error('cannot write file (' . $this->keydat . ')', E_USER_WARNING); die('Error: cannot write file. downloadDat2ch()'); return false; } // {{{ 取得後サイズチェック $debug && $GLOBALS['profiler']->enterSection('dat_size_check'); if ($zero_read == false && $this->onbytes) { $this->getDatBytesFromLocalDat(); // $aThread->length をset if ($this->onbytes != $this->length) { $onbytes = $this->onbytes; $this->clearOnbytesModified(); P2Util::pushInfoHtml("p2 info: {$onbytes}/{$this->length} ファイルサイズが変なので、datを再取得しました<br>"); $debug && $GLOBALS['profiler']->leaveSection('dat_size_check'); return $this->downloadDat2ch(0); // datサイズは不正。全部取り直し。 } } $debug && $GLOBALS['profiler']->leaveSection('dat_size_check'); // }}} $this->isonline = true; return true; /* あぼーん検出漏れについて 0. p2が読み込む 1. レスがあぼーんされる 2. (あぼーんされたレス-あぼーんテキスト)と全く同サイズのレスが書き込まれる 3. p2が読み込む 0-1-2-3が、完全に連続した時にあぼーん検出漏れはありうる。 */ }
/** * SETTING.TXT をダウンロードして、パースして、キャッシュする * * @return boolean 実行成否 */ public function downloadSettingTxt() { global $_conf; // まちBBS・したらば は SETTING.TXT が存在しないものとする if (P2Util::isHostMachiBbs($this->_host) || P2Util::isHostJbbsShitaraba($this->_host)) { return false; } FileCtl::mkdirFor($this->_setting_txt); // 板ディレクトリが無ければ作る if (file_exists($this->_setting_srd) && file_exists($this->_setting_txt)) { // 更新しない場合は、その場で抜けてしまう if (!empty($_GET['norefresh']) || isset($_REQUEST['word'])) { return true; // キャッシュが新しい場合も抜ける } elseif ($this->isCacheFresh()) { return true; } $modified = http_date(filemtime($this->_setting_txt)); } else { $modified = false; } // DL $params = array(); $params['timeout'] = $_conf['http_conn_timeout']; $params['readTimeout'] = array($_conf['http_read_timeout'], 0); if ($_conf['proxy_use']) { $params['proxy_host'] = $_conf['proxy_host']; $params['proxy_port'] = $_conf['proxy_port']; } $req = new HTTP_Request($this->_url, $params); $modified && $req->addHeader('If-Modified-Since', $modified); $req->addHeader('User-Agent', "Monazilla/1.00 ({$_conf['p2ua']})"); $response = $req->sendRequest(); if (PEAR::isError($response)) { $error_msg = $response->getMessage(); } else { $code = $req->getResponseCode(); if ($code == 302) { // ホストの移転を追跡 $new_host = BbsMap::getCurrentHost($this->_host, $this->_bbs); if ($new_host != $this->_host) { $aNewSettingTxt = new SettingTxt($new_host, $this->_bbs); $body = $aNewSettingTxt->downloadSettingTxt(); return true; } } if (!($code == 200 || $code == 206 || $code == 304)) { //var_dump($req->getResponseHeader()); $error_msg = $code; } } // DLエラー if (isset($error_msg) && strlen($error_msg) > 0) { $url_t = P2Util::throughIme($this->_url); $info_msg_ht = "<p class=\"info-msg\">Error: {$error_msg}<br>"; $info_msg_ht .= "rep2 info: <a href=\"{$url_t}\"{$_conf['ext_win_target_at']}>{$this->_url}</a> に接続できませんでした。</p>"; P2Util::pushInfoHtml($info_msg_ht); touch($this->_setting_txt); // DL失敗した場合も touch return false; } $body = $req->getResponseBody(); // DL成功して かつ 更新されていたら保存 if ($body && $code != '304') { // したらば or be.2ch.net ならEUCをSJISに変換 if (P2Util::isHostJbbsShitaraba($this->_host) || P2Util::isHostBe2chNet($this->_host)) { $body = mb_convert_encoding($body, 'CP932', 'CP51932'); } if (FileCtl::file_write_contents($this->_setting_txt, $body) === false) { p2die('cannot write file'); } // パースしてキャッシュを保存する if (!$this->cacheParsedSettingTxt()) { return false; } } else { // touchすることで更新インターバルが効くので、しばらく再チェックされなくなる touch($this->_setting_txt); // 同時にキャッシュもtouchしないと、_setting_txtと_setting_srdで更新時間がずれ、 // 毎回ここまで処理が来る(サーバへのヘッダリクエストが飛ぶ)場合がある。 touch($this->_setting_srd); } return true; }
/** * 標準方法で 2ch互換 DAT を差分ダウンロードする * * @return mix 取得できたか、更新がなかった場合はtrueを返す */ protected function _downloadDat2ch($from_bytes) { global $_conf; global $debug; if (!($this->host && $this->bbs && $this->key)) { return false; } $from_bytes = intval($from_bytes); if ($from_bytes == 0) { $zero_read = true; } else { $zero_read = false; $from_bytes = $from_bytes - 1; } $method = 'GET'; $url = "http://{$this->host}/{$this->bbs}/dat/{$this->key}.dat"; //$url="http://news2.2ch.net/test/read.cgi?bbs=newsplus&key=1038486598"; $purl = parse_url($url); // URL分解 if (isset($purl['query'])) { // クエリー $purl['query'] = '?' . $purl['query']; } else { $purl['query'] = ''; } // プロキシ if ($_conf['proxy_use']) { $send_host = $_conf['proxy_host']; $send_port = $_conf['proxy_port']; $send_path = $url; } else { $send_host = $purl['host']; $send_port = isset($purl['port']) ? $purl['port'] : 80; $send_path = $purl['path'] . $purl['query']; } if (!$send_port) { $send_port = 80; // デフォルトを80 } $request = "{$method} {$send_path} HTTP/1.0\r\n"; $request .= "Host: {$purl['host']}\r\n"; $request .= "Accept: */*\r\n"; //$request .= "Accept-Charset: Shift_JIS\r\n"; //$request .= "Accept-Encoding: gzip, deflate\r\n"; $request .= "Accept-Language: ja, en\r\n"; $request .= "User-Agent: Monazilla/1.00 ({$_conf['p2ua']})\r\n"; if (!$zero_read) { $request .= "Range: bytes={$from_bytes}-\r\n"; } $request .= "Referer: http://{$purl['host']}/{$this->bbs}/\r\n"; if ($this->modified) { $request .= "If-Modified-Since: " . $this->modified . "\r\n"; } // Basic認証用のヘッダ if (isset($purl['user']) && isset($purl['pass'])) { $request .= "Authorization: Basic " . base64_encode($purl['user'] . ":" . $purl['pass']) . "\r\n"; } $request .= "Connection: Close\r\n"; $request .= "\r\n"; // WEBサーバへ接続 $fp = @fsockopen($send_host, $send_port, $errno, $errstr, $_conf['http_conn_timeout']); if (!$fp) { self::_pushInfoConnectFailed($url, $errno, $errstr); $this->diedat = true; return false; } stream_set_timeout($fp, $_conf['http_read_timeout'], 0); $wr = ""; fputs($fp, $request); $start_here = false; while (!p2_stream_eof($fp, $timed_out)) { if ($start_here) { if ($code == "200" || $code == "206") { while (!p2_stream_eof($fp, $timed_out)) { $wr .= fread($fp, 4096); } if ($timed_out) { self::_pushInfoReadTimedOut($url); $this->diedat = true; fclose($fp); return false; } // 末尾の改行であぼーんチェック if (!$zero_read) { if (substr($wr, 0, 1) != "\n") { //echo "あぼーん検出"; fclose($fp); unset($this->onbytes); unset($this->modified); return $this->_downloadDat2ch(0); // あぼーん検出。全部取り直し。 } $wr = substr($wr, 1); } FileCtl::make_datafile($this->keydat, $_conf['dat_perm']); $file_append = $zero_read ? 0 : FILE_APPEND; if (FileCtl::file_write_contents($this->keydat, $wr, $file_append) === false) { p2die('cannot write file.'); } //$GLOBALS['debug'] && $GLOBALS['profiler']->enterSection("dat_size_check"); // 取得後サイズチェック if ($zero_read == false && $this->onbytes) { $this->getDatBytesFromLocalDat(); // $aThread->length をset if ($this->onbytes != $this->length) { fclose($fp); unset($this->onbytes); unset($this->modified); P2Util::pushInfoHtml("<p>rep2 info: {$this->onbytes}/{$this->length} ファイルサイズが変なので、datを再取得</p>"); //$GLOBALS['debug'] && $GLOBALS['profiler']->leaveSection("dat_size_check"); return $this->_downloadDat2ch(0); //datサイズは不正。全部取り直し。 // サイズが同じならそのまま } elseif ($this->onbytes == $this->length) { fclose($fp); $this->isonline = true; //$GLOBALS['debug'] && $GLOBALS['profiler']->leaveSection('dat_size_check'); return true; } } //$GLOBALS['debug'] && $GLOBALS['profiler']->leaveSection('dat_size_check'); // スレッドがないと判断 } else { fclose($fp); return $this->_downloadDat2chNotFound(); } } else { $l = fgets($fp, 32800); // ex) HTTP/1.1 304 Not Modified if (preg_match("/^HTTP\\/1\\.\\d (\\d+) (.+)\r\n/", $l, $matches)) { $code = $matches[1]; if ($code == "200" || $code == "206") { // Partial Content } elseif ($code == "302") { // Found // ホストの移転を追跡 $new_host = BbsMap::getCurrentHost($this->host, $this->bbs); if ($new_host != $this->host) { fclose($fp); $this->old_host = $this->host; $this->host = $new_host; return $this->_downloadDat2ch($from_bytes); } else { fclose($fp); return $this->_downloadDat2chNotFound($code); } } elseif ($code == "304") { // Not Modified fclose($fp); $this->isonline = true; return "304 Not Modified"; } elseif ($code == "416") { // Requested Range Not Satisfiable //echo "あぼーん検出"; fclose($fp); unset($this->onbytes); unset($this->modified); return $this->_downloadDat2ch(0); // あぼーん検出。全部取り直し。 } else { fclose($fp); return $this->_downloadDat2chNotFound(); } } if ($zero_read) { if (preg_match("/^Content-Length: ([0-9]+)/", $l, $matches)) { $this->onbytes = $matches[1]; } } else { if (preg_match("/^Content-Range: bytes ([^\\/]+)\\/([0-9]+)/", $l, $matches)) { $this->onbytes = $matches[2]; } } if (preg_match("/^Last-Modified: (.+)\r\n/", $l, $matches)) { //echo $matches[1]."<br>"; //debug $this->modified = $matches[1]; } elseif ($l == "\r\n") { $start_here = true; } } } fclose($fp); if ($timed_out) { self::_pushInfoReadTimedOut($url); $this->diedat = true; return false; } else { $this->isonline = true; return true; } }
/** * subject.txtをダウンロードする * * @return string subject.txt の中身 */ public function downloadSubject() { global $_conf; if ($this->storage === 'file') { FileCtl::mkdirFor($this->subject_file); // 板ディレクトリが無ければ作る if (file_exists($this->subject_file)) { if (!empty($_REQUEST['norefresh']) || empty($_REQUEST['refresh']) && isset($_REQUEST['word'])) { return; // 更新しない場合は、その場で抜けてしまう } elseif (!empty($GLOBALS['expack.subject.multi-threaded-download.done'])) { return; // 並列ダウンロード済の場合も抜ける } elseif (empty($_POST['newthread']) and $this->isSubjectTxtFresh()) { return; // 新規スレ立て時でなく、更新が新しい場合も抜ける } $modified = http_date(filemtime($this->subject_file)); } else { $modified = false; } } // DL $params = array(); $params['timeout'] = $_conf['http_conn_timeout']; $params['readTimeout'] = array($_conf['http_read_timeout'], 0); if ($_conf['proxy_use']) { $params['proxy_host'] = $_conf['proxy_host']; $params['proxy_port'] = $_conf['proxy_port']; } $req = new HTTP_Request($this->subject_url, $params); $modified && $req->addHeader("If-Modified-Since", $modified); $req->addHeader('User-Agent', "Monazilla/1.00 ({$_conf['p2ua']})"); $response = $req->sendRequest(); if (PEAR::isError($response)) { $error_msg = $response->getMessage(); } else { $code = $req->getResponseCode(); if ($code == 302) { // ホストの移転を追跡 $new_host = BbsMap::getCurrentHost($this->host, $this->bbs); if ($new_host != $this->host) { $aNewSubjectTxt = new SubjectTxt($new_host, $this->bbs); $body = $aNewSubjectTxt->downloadSubject(); return $body; } } if (!($code == 200 || $code == 206 || $code == 304)) { //var_dump($req->getResponseHeader()); $error_msg = $code; } } if (isset($error_msg) && strlen($error_msg) > 0) { $url_t = P2Util::throughIme($this->subject_url); $info_msg_ht = "<p class=\"info-msg\">Error: {$error_msg}<br>"; $info_msg_ht .= "rep2 info: <a href=\"{$url_t}\"{$_conf['ext_win_target_at']}>{$this->subject_url}</a> に接続できませんでした。</p>"; P2Util::pushInfoHtml($info_msg_ht); $body = ''; } else { $body = $req->getResponseBody(); } // ■ DL成功して かつ 更新されていたら if ($body && $code != "304") { // したらば or be.2ch.net ならEUCをSJISに変換 if (P2Util::isHostJbbsShitaraba($this->host) || P2Util::isHostBe2chNet($this->host)) { $body = mb_convert_encoding($body, 'CP932', 'CP51932'); } if (FileCtl::file_write_contents($this->subject_file, $body) === false) { p2die('cannot write file'); } } else { // touchすることで更新インターバルが効くので、しばらく再チェックされなくなる // (変更がないのに修正時間を更新するのは、少し気が進まないが、ここでは特に問題ないだろう) if ($this->storage === 'file') { touch($this->subject_file); } } return $body; }
/** * subject.txtをダウンロードする * * @access public * @return array|null|false subject.txtの配列データ(eaccelerator, apc用)、またはnullを返す。 * 失敗した場合はfalseを返す。 */ function downloadSubject() { global $_conf; static $spentDlTime_ = 0; // DL所要合計時間 $perm = isset($_conf['dl_perm']) ? $_conf['dl_perm'] : 0606; $modified = false; if ($this->storage == 'file') { FileCtl::mkdirFor($this->subject_file); // 板ディレクトリが無ければ作る if (file_exists($this->subject_file)) { // ファイルキャッシュがあれば、DL制限時間をかける if (UA::isK()) { $dlSubjectTotalLimitTime = $_conf['dlSubjectTotalLimitTimeM']; } else { $dlSubjectTotalLimitTime = $_conf['dlSubjectTotalLimitTime']; } if ($dlSubjectTotalLimitTime and $spentDlTime_ > $dlSubjectTotalLimitTime) { return null; } // 条件によって、キャッシュを適用する // subject.php でrefresh指定がある時は、キャッシュを適用しない if (!(basename($_SERVER['SCRIPT_NAME']) == $_conf['subject_php'] && !empty($_REQUEST['refresh']))) { // キャッシュ適用指定時は、その場で抜ける if (!empty($_GET['norefresh']) || isset($_REQUEST['word'])) { return null; // 並列ダウンロード済の場合も抜ける } elseif (!empty($GLOBALS['expack.subject.multi-threaded-download.done'])) { return null; // 新規スレ立て時以外で、キャッシュが新鮮な場合も抜ける } elseif (empty($_POST['newthread']) and $this->isSubjectTxtFresh()) { return null; } } $modified = gmdate("D, d M Y H:i:s", filemtime($this->subject_file)) . " GMT"; } } $dlStartTime = $this->microtimeFloat(); // DL require_once 'HTTP/Request.php'; $params = array(); $params['timeout'] = $_conf['fsockopen_time_limit']; if ($_conf['proxy_use']) { $params['proxy_host'] = $_conf['proxy_host']; $params['proxy_port'] = $_conf['proxy_port']; } $req = new HTTP_Request($this->subject_url, $params); $modified && $req->addHeader('If-Modified-Since', $modified); $req->addHeader('User-Agent', sprintf('Monazilla/1.00 (%s/%s)', $_conf['p2uaname'], $_conf['p2version'])); $response = $req->sendRequest(); $error_msg = null; if (PEAR::isError($response)) { $error_msg = $response->getMessage(); } else { $code = $req->getResponseCode(); if ($code == 302) { // ホストの移転を追跡 require_once P2_LIB_DIR . '/BbsMap.php'; $new_host = BbsMap::getCurrentHost($this->host, $this->bbs); if ($new_host != $this->host) { $aNewSubjectTxt = new SubjectTxt($new_host, $this->bbs); return $aNewSubjectTxt->downloadSubject(); } } if (!($code == 200 || $code == 206 || $code == 304)) { //var_dump($req->getResponseHeader()); $error_msg = $code; } } if (!is_null($error_msg) && strlen($error_msg) > 0) { $attrs = array(); if ($_conf['ext_win_target']) { $attrs['target'] = $_conf['ext_win_target']; } $atag = P2View::tagA(P2Util::throughIme($this->subject_url), hs($this->subject_url), $attrs); $msg_ht = sprintf('<div>Error: %s<br>p2 info - %s に接続できませんでした。</div>', hs($error_msg), $atag); P2Util::pushInfoHtml($msg_ht); $body = ''; } else { $body = $req->getResponseBody(); } $dlEndTime = $this->microtimeFloat(); $dlTime = $dlEndTime - $dlStartTime; $spentDlTime_ += $dlTime; // DL成功して かつ 更新されていたら if ($body && $code != '304') { // したらば or be.2ch.net ならEUCをSJISに変換 if (P2Util::isHostJbbsShitaraba($this->host) || P2Util::isHostBe2chNet($this->host)) { $body = mb_convert_encoding($body, 'SJIS-win', 'eucJP-win'); } // eaccelerator or apcに保存する場合 if ($this->storage == 'eaccelerator' || $this->storage == 'apc') { $cache_key = "{$this->host}/{$this->bbs}"; $cont = rtrim($body); $lines = explode("\n", $cont); if ($this->storage == 'eaccelerator') { eaccelerator_lock($cache_key); eaccelerator_put($cache_key, $lines, $_conf['sb_dl_interval']); eaccelerator_unlock($cache_key); } else { apc_store($cache_key, $lines, $_conf['sb_dl_interval']); } return $lines; // ファイルに保存する場合 } else { if (false === FileCtl::filePutRename($this->subject_file, $body)) { // 保存に失敗はしても、既存のキャッシュが読み込めるならよしとしておく if (is_readable($this->subject_file)) { return null; } else { die("Error: cannot write file"); return false; } } chmod($this->subject_file, $perm); } } else { // touchすることで更新インターバルが効くので、しばらく再チェックされなくなる // (変更がないのに修正時間を更新するのは、少し気が進まないが、ここでは特に問題ないだろう) if ($this->storage == 'file') { touch($this->subject_file); } } return null; }