/** * 2ch公式メニューをパースし、板-ホストの対応表を作成する * * @return array site/bbs/(host,itaj) の多次元連想配列 * ダウンロードに失敗したときは false */ private static function _getMapping() { global $_conf; // {{{ 設定 $bbsmenu_url = 'http://menu.2ch.net/bbsmenu.html'; // 公式メニューの URL $altmenu_url = 'http://www.2ch.se/bbsmenu.html'; // 代替メニューの URL $map_cache_path = $_conf['cache_dir'] . '/host_bbs_map.txt'; $map_cache_lifetime = 600; // TTLは少し短めに $err_fmt = '<p>rep2 error: BbsMap: %s - %s をダウンロードできませんでした。</p>'; $use_alt = false; // }}} // {{{ キャッシュ確認 if (!is_null(self::$_map)) { return self::$_map; } elseif (file_exists($map_cache_path)) { $mtime = filemtime($map_cache_path); $expires = $mtime + $map_cache_lifetime; if (time() < $expires) { $map_cahce = file_get_contents($map_cache_path); self::$_map = unserialize($map_cahce); return self::$_map; } } else { FileCtl::mkdirFor($map_cache_path); } touch($map_cache_path); clearstatcache(); // }}} // {{{ メニューをダウンロード if (!class_exists('HTTP_Request', false)) { require 'HTTP/Request.php'; } $params = array(); $params['timeout'] = $_conf['http_conn_timeout']; $params['readTimeout'] = array($_conf['http_read_timeout'], 0); if (isset($mtime)) { $params['requestHeaders'] = array('If-Modified-Since' => http_date($mtime)); } if ($_conf['proxy_use']) { $params['proxy_host'] = $_conf['proxy_host']; $params['proxy_port'] = $_conf['proxy_port']; } $req = new HTTP_Request($bbsmenu_url, $params); $req->setMethod('GET'); $err = $req->sendRequest(true); // エラーのとき、代わりのメニューを使ってみる if (PEAR::isError($err) && $use_alt) { P2Util::pushInfoHtml(sprintf($err_fmt, htmlspecialchars($err->getMessage(), ENT_QUOTES), htmlspecialchars($bbsmenu_url, ENT_QUOTES))); P2Util::pushInfoHtml(sprintf("<p>代わりに %s をダウンロードします。</p>", htmlspecialchars($altmenu_url, ENT_QUOTES))); $bbsmenu_url = $altmenu_url; unset($req, $err); $req = new HTTP_Request($bbsmenu_url, $params); $req->setMethod('GET'); $err = $req->sendRequest(true); } // エラーを検証 if (PEAR::isError($err)) { P2Util::pushInfoHtml(sprintf($err_fmt, htmlspecialchars($err->getMessage(), ENT_QUOTES), htmlspecialchars($bbsmenu_url, ENT_QUOTES))); if (file_exists($map_cache_path)) { return unserialize(file_get_contents($map_cache_path)); } else { return false; } } // レスポンスコードを検証 $code = $req->getResponseCode(); if ($code == 304) { $map_cahce = file_get_contents($map_cache_path); self::$_map = unserialize($map_cahce); return self::$_map; } elseif ($code != 200) { P2Util::pushInfoHtml(sprintf($err_fmt, htmlspecialchars(strval($code), ENT_QUOTES), htmlspecialchars($bbsmenu_url, ENT_QUOTES))); if (file_exists($map_cache_path)) { return unserialize(file_get_contents($map_cache_path)); } else { return false; } } $res_body = $req->getResponseBody(); // }}} // {{{ パース $regex = '!<A HREF=http://(\\w+\\.(?:2ch\\.net|bbspink\\.com|machi\\.to|mathibbs\\.com))/(\\w+)/(?: TARGET=_blank)?>(.+?)</A>!'; preg_match_all($regex, $res_body, $matches, PREG_SET_ORDER); $map = array(); foreach ($matches as $match) { $host = $match[1]; $bbs = $match[2]; $itaj = $match[3]; $type = self::_detectHostType($host); if (!isset($map[$type])) { $map[$type] = array(); } $map[$type][$bbs] = array('host' => $host, 'itaj' => $itaj); } // }}} // {{{ キャッシュする $map_cache = serialize($map); if (FileCtl::file_write_contents($map_cache_path, $map_cache) === false) { p2die("cannot write file. ({$map_cache_path})"); } // }}} return self::$_map = $map; }