/** * チャットちゃんねる cha2.net の dat を読んで保存する関数 * (差分取得には未対応) * ※2ch互換として読み込んでいるので現在この関数は利用はしていない。@see TreadRead->downloadDat() * * @access public * @return boolean */ function downloadDatCha2(&$ThreadRead) { // {{{ 既得datの取得レス数が適性かどうかを念のためチェック if (file_exists($ThreadRead->keydat)) { $dls = file($ThreadRead->keydat); if (sizeof($dls) != $ThreadRead->gotnum) { // echo 'bad size!<br>'; unlink($ThreadRead->keydat); $ThreadRead->gotnum = 0; } } else { $ThreadRead->gotnum = 0; } // }}} if ($ThreadRead->gotnum == 0) { $file_append = false; $START = 1; } else { $file_append = true; $START = $ThreadRead->gotnum + 1; } // チャットちゃんねる $cha2url = "http://{$ThreadRead->host}/cgi-bin/{$ThreadRead->bbs}/dat/{$ThreadRead->key}.dat"; $datfile = $ThreadRead->keydat; FileCtl::mkdirFor($datfile); $cha2url_res = P2Util::fileDownload($cha2url, $datfile); if (!$cha2url_res or !$cha2url_res->is_success()) { $ThreadRead->diedat = true; return false; } $ThreadRead->isonline = true; return true; }
/** * コンストラクタ * * @param string $name ロック名(≒排他処理したいファイル名) * @param bool $remove ロックファイルを自動で削除するかどうか * @param string $suffix ロックファイル名の接尾辞 */ public function __construct($name, $remove = true, $suffix = '.lck') { $this->_filename = p2_realpath($name . $suffix); $this->_remove = $remove; FileCtl::mkdirFor($this->_filename); $this->_fh = fopen($this->_filename, 'wb'); if (!$this->_fh) { p2die("cannot create lockfile ({$this->_filename})."); } if (!flock($this->_fh, LOCK_EX)) { p2die("cannot get lock ({$this->_filename})."); } }
/** * データを保存するP2KeyValueStoreオブジェクトを取得する * * @param string $databasePath * @param string $codec * @param string $tableName * @return P2KeyValueStore */ protected static function _getKVS($databasePath, $codec = P2KeyValueStore::CODEC_SERIALIZING, $tableName = null) { global $_conf; $id = $codec . ':' . $databasePath; if (array_key_exists($id, self::$_kvs)) { return self::$_kvs[$id]; } if (!file_exists($databasePath) && !is_dir(dirname($databasePath))) { FileCtl::mkdirFor($databasePath); } try { $kvs = P2KeyValueStore::getStore($databasePath, $codec, $tableName); self::$_kvs[$id] = $kvs; } catch (Exception $e) { p2die(get_class($e) . ': ' . $e->getMessage()); } return $kvs; }
/** * cachedGetHostByAddr/cachedGetHostByName のキャッシュエンジン */ private static function _cachedGetHost($remote, $function) { global $_conf; $lifeTime = (int) $GLOBALS['_HOSTCHKCONF']['gethostby_lifetime']; if ($lifeTime <= 0) { return $function($remote); } if (!file_exists($_conf['hostcheck_db_path'])) { FileCtl::mkdirFor($_conf['hostcheck_db_path']); } $kvs = P2KeyValueStore::getStore($_conf['hostcheck_db_path']); $result = $kvs->get($remote, $lifeTime); if ($result !== null) { return $result; } $result = $function($remote); $kvs->set($remote, $result); return $result; }
/** * ファイルがなければ生成し、書き込み権限がなければパーミッションを調整する * (既にファイルがあり、書き込み権限もある場合は、何もしない。※modifiedの更新もしない) * * @static * @access public * * @param boolean $die true なら、エラーでただちに終了する * @return boolean 問題がなければtrue */ function make_datafile($file, $perm = 0606, $die = true) { $me = __CLASS__ . "::" . __FUNCTION__ . "()"; // 引数チェック if (strlen($file) == 0) { trigger_error("{$me}, file is null", E_USER_WARNING); return false; } if (empty($perm)) { trigger_error("{$me}, empty perm. ( {$file} )", E_USER_WARNING); $die and die("Error: {$me}, empty perm"); return false; } // ファイルがなければ if (!file_exists($file)) { if (!FileCtl::mkdirFor($file)) { $die and die("Error: {$me} -> FileCtl::mkdirFor() failed."); return false; } if (!touch($file)) { $die and die("Error: {$me} -> touch() failed."); return false; } chmod($file, $perm); // ファイルがあれば } else { if (!is_writable($file)) { if (false === ($cont = file_get_contents($file))) { $die and die("Error: {$me} -> file_get_contents() failed."); return false; } unlink($file); if (false === file_put_contents($file, $cont, LOCK_EX)) { // 備忘メモ: $file が nullの時、file_put_contents() はfalseを返すがwaringは出さないので注意 // ここでは $file は約束されているが… $die and die("Error: {$me} -> file_put_contents() failed."); return false; } chmod($file, $perm); } } return true; }
/** * オンライン上のrep2-expack最新版をチェックする * * @return string HTML */ function checkUpdatan() { global $_conf, $p2web_url_r, $expack_url_r, $expack_dl_url_r, $expack_hist_url_r; $no_p2status_dl_flag = false; $ver_txt_url = $_conf['expack.web_url'] . 'version.txt'; $cachefile = P2Util::cacheFileForDL($ver_txt_url); FileCtl::mkdirFor($cachefile); if (file_exists($cachefile)) { // キャッシュの更新が指定時間以内なら if (filemtime($cachefile) > time() - $_conf['p2status_dl_interval'] * 86400) { $no_p2status_dl_flag = true; } } if (empty($no_p2status_dl_flag)) { P2Util::fileDownload($ver_txt_url, $cachefile); } $ver_txt = FileCtl::file_read_lines($cachefile, FILE_IGNORE_NEW_LINES); $update_ver = $ver_txt[0]; $kita = 'キタ━━━━(゚∀゚)━━━━!!!!!!'; //$kita = 'キタ*・゚゚・*:.。..。.:*・゚(゚∀゚)゚・*:.。. .。.:*・゚゚・*!!!!!'; $newversion_found_html = ''; if ($update_ver && version_compare($update_ver, $_conf['p2version'], '>')) { $newversion_found_html = <<<EOP <div class="kakomi"> {$kita}<br> オンライン上に 拡張パック の最新バージョンを見つけますた。<br> rep2-expack rev.{$update_ver} → <a href="{$expack_dl_url_r}"{$_conf['ext_win_target_at']}>ダウンロード</a> / <a href="{$expack_hist_url_r}"{$_conf['ext_win_target_at']}>更新記録</a> </div> <hr class="invisible"> EOP; } return $newversion_found_html; }
/** * すべてのお気にスレ・お気に板を読み込む * * @param bool $force * @return void */ public static function loadAllFavSet($force = false) { global $_conf; static $done = false; if ($done && !$force) { return; } // キャッシュの有無をチェック $cache_file = $_conf['cache_dir'] . DIRECTORY_SEPARATOR . 'favset_cache.txt'; if ($force || !file_exists($cache_file)) { $use_cache = false; } else { $cache_mtime = filemtime($cache_file); if (filemtime(__FILE__) > $cache_mtime) { $use_cache = false; } else { $use_cache = true; } } // キャッシュが有効かどうかをチェック if ($use_cache && file_exists($_conf['orig_favlist_idx']) && filemtime($_conf['orig_favlist_idx']) > $cache_mtime) { $use_cache = false; } if ($use_cache && file_exists($_conf['orig_favita_brd']) && filemtime($_conf['orig_favita_brd']) > $cache_mtime) { $use_cache = false; } // 読み込み対象ファイルのリストを作成すると同時にキャッシュが有効かどうかをチェック $favlist_idxes = array($_conf['orig_favlist_idx']); $favita_brds = array($_conf['orig_favita_brd']); for ($i = 1; $i <= $_conf['expack.misc.favset_num']; $i++) { $favlist_idx = $_conf['pref_dir'] . DIRECTORY_SEPARATOR . sprintf('p2_favlist%d.idx', $i); if ($use_cache && file_exists($favlist_idx) && filemtime($favlist_idx) > $cache_mtime) { $use_cache = false; } $favlist_idxes[$i] = $favlist_idx; $favita_brd = $_conf['pref_dir'] . DIRECTORY_SEPARATOR . sprintf('p2_favita%d.brd', $i); if ($use_cache && file_exists($favita_brd) && filemtime($favita_brd) > $cache_mtime) { $use_cache = false; } $favita_brds[$i] = $favita_brd; } // キャッシュが有効なら、それを使う if ($use_cache) { $cache = unserialize(file_get_contents($cache_file)); if (is_array($cache)) { list($_conf['favlists'], $_conf['favitas']) = $cache; $done = true; return; } } // すべてのお気にスレを読み込む $_conf['favlists'] = array(); foreach ($favlist_idxes as $i => $favlist_idx) { $_conf['favlists'][$i] = array(); if ($favlines = FileCtl::file_read_lines($favlist_idx, FILE_IGNORE_NEW_LINES)) { foreach ($favlines as $l) { $lar = explode('<>', $l); // bbsのないものは不正データなのでスキップ if (!isset($lar[11])) { continue; } $key = $lar[1]; $host = $lar[10]; $bbs = $lar[11]; $group = P2Util::getHostGroupName($host); $_conf['favlists'][$i][] = array('group' => $group, 'host' => $host, 'bbs' => $bbs, 'key' => $key); } } } // すべてのお気に板を読み込む $_conf['favitas'] = array(); foreach ($favita_brds as $i => $favita_brd) { $_conf['favitas'][$i] = array(); if ($favlines = FileCtl::file_read_lines($favita_brd, FILE_IGNORE_NEW_LINES)) { foreach ($favlines as $l) { $lar = explode("\t", $l); $host = $lar[1]; $bbs = $lar[2]; $itaj = $lar[3]; $group = P2Util::getHostGroupName($host); $_conf['favitas'][$i][] = array('group' => $group, 'host' => $host, 'bbs' => $bbs, 'itaj' => $itaj); } } } //キャッシュに保存する if (!is_dir($_conf['pref_dir'])) { FileCtl::mkdirFor($cache_file); } file_put_contents($cache_file, serialize(array($_conf['favlists'], $_conf['favitas']))); $done = true; }
/** * 2chの過去ログ倉庫からdat.gzをダウンロード&解凍する * * @access private * @return true|string|false 取得できたか、更新がなかった場合はtrue(または"304 Not Modified")を返す */ function downloadDat2chKako($uri, $ext) { global $_conf; $url = $uri . $ext; $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']; } // デフォルトを80 if (!$send_port) { $send_port = 80; } $request = 'GET ' . $send_path . " HTTP/1.0\r\n"; $request .= "Host: " . $purl['host'] . "\r\n"; $request .= "User-Agent: " . P2Util::getP2UA($withMonazilla = true) . "\r\n"; $request .= "Connection: Close\r\n"; //$request .= "Accept-Encoding: gzip\r\n"; /* if ($modified) { $request .= "If-Modified-Since: $modified\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']; // Partial Content if ($code == "200") { // OK。何もしない // Not Modified } elseif ($code == "304") { fclose($fp); //$this->isonline = true; return "304 Not Modified"; // 予期しないHTTPコード。なかったと判断 } else { fclose($fp); $this->downloadDat2chKakoNotFound($uri, $ext); return false; } // }}} if (isset($h['headers']['Last-Modified'])) { $lastmodified = $h['headers']['Last-Modified']; } if (isset($h['headers']['Content-Length'])) { if (preg_match("/^([0-9]+)/", $h['headers']['Content-Length'], $matches)) { $onbytes = $h['headers']['Content-Length']; } } $isGzip = false; if (isset($h['headers']['Content-Encoding'])) { if (preg_match("/^(x-)?gzip/", $h['headers']['Content-Encoding'], $matches)) { $isGzip = true; } } // bodyを読む $body = ''; while (!feof($fp)) { $body .= fread($fp, 8192); } fclose($fp); $done_gunzip = false; if ($isGzip) { $gztempfile = $this->keydat . '.gz'; FileCtl::mkdirFor($gztempfile); if (file_put_contents($gztempfile, $body, LOCK_EX) === false) { die("Error: cannot write file. downloadDat2chKako()"); return false; } if (extension_loaded('zlib')) { $body = FileCtl::getGzFileContents($gztempfile); } else { // 既に存在するなら一時バックアップ退避 $keydat_bak = $this->keydat . '.bak'; if (file_exists($this->keydat)) { if (file_exists($keydat_bak)) { unlink($keydat_bak); } rename($this->keydat, $keydat_bak); } $rcode = 1; // 解凍 system("gzip -d {$gztempfile}", $rcode); if ($rcode != 0) { if (file_exists($keydat_bak)) { if (file_exists($this->keydat)) { unlink($this->keydat); } // 失敗ならバックアップ戻す rename($keydat_bak, $this->keydat); } $this->pushDownloadDatErrorMsgHtml("<p>p2 info - 2ちゃんねる過去ログ倉庫からのスレッド取り込みは、PHPの<a href=\"http://www.php.net/manual/ja/ref.zlib.php\">zlib拡張モジュール</a>がないか、systemでgzipコマンドが使用可能\でなければできません。</p>"); // gztempファイルを捨てる file_exists($gztempfile) and unlink($gztempfile); $this->diedat = true; return false; } else { if (file_exists($keydat_bak)) { unlink($keydat_bak); } $done_gunzip = true; } } // tempファイルを捨てる file_exists($gztempfile) and unlink($gztempfile); } if (!$done_gunzip) { FileCtl::make_datafile($this->keydat, $_conf['dat_perm']); if (false === file_put_contents($this->keydat, $body, LOCK_EX)) { die("Error: cannot write file. downloadDat2chKako()"); return false; } } //$this->isonline = true; return true; }
/** * 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; }
/** * ダウンロードURLからキャッシュファイルパスを返す * * @access public * @return string|false */ function cacheFileForDL($url) { global $_conf; if (!($parsed = parse_url($url))) { return false; } $save_uri = $parsed['host']; $save_uri .= isset($parsed['port']) ? ':' . $parsed['port'] : ''; $save_uri .= $parsed['path'] ? $parsed['path'] : ''; $save_uri .= isset($parsed['query']) ? '?' . $parsed['query'] : ''; $save_uri = str_replace('%2F', '/', rawurlencode($save_uri)); $save_uri = preg_replace('|\\.+/|', '', $save_uri); $save_uri = rtrim($save_uri, '/'); $cachefile = $_conf['cache_dir'] . '/' . $save_uri; FileCtl::mkdirFor($cachefile); return $cachefile; }
/** * 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; }
/** * ホスト名からクッキーファイルパスを返す * * @access public * @return string */ function cachePathForCookie($host) { global $_conf; $cachefile = $_conf['cookie_dir'] . "/{$host}/" . $_conf['cookie_file_name']; FileCtl::mkdirFor($cachefile); return $cachefile; }
/** * @return void */ function _prepareFileSession() { global $_conf; // セッションデータ保存ディレクトリを設定 if ($_conf['session_save'] == 'p2' and session_module_name() == 'files') { // $_conf['data_dir'] を絶対パスに変換する define('P2_DATA_DIR_REAL_PATH', File_Util::realPath($_conf['data_dir'])); $_conf['session_dir'] = P2_DATA_DIR_REAL_PATH . DIRECTORY_SEPARATOR . 'session'; } if (!is_dir($_conf['session_dir'])) { require_once P2_LIB_DIR . '/FileCtl.php'; FileCtl::mkdirFor($_conf['session_dir'] . '/dummy_filename'); } if (!is_writable($_conf['session_dir'])) { die(sprintf('p2 error: セッションデータ保存ディレクトリ (%s) に書き込み権限がありません。', hs($_conf['session_dir']))); } session_save_path($_conf['session_dir']); // session.save_path のパスの深さが2より大きいとガーベッジコレクションが行われないので // 自前でガーベッジコレクションする P2Util::session_gc(); }
/** * 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; }
$aThread = new ThreadRead(); } // lsのセット if (!empty($ls)) { $aThread->ls = mb_convert_kana($ls, 'a'); } //========================================================== // idxの読み込み //========================================================== // hostを分解してidxファイルのパスを求める if (!isset($aThread->keyidx)) { $aThread->setThreadPathInfo($host, $bbs, $key); } // 板ディレクトリが無ければ作る FileCtl::mkdirFor($aThread->keyidx); FileCtl::mkdirFor($aThread->keydat); $aThread->itaj = P2Util::getItaName($host, $bbs); if (!$aThread->itaj) { $aThread->itaj = $aThread->bbs; } // idxファイルがあれば読み込む if ($lines = FileCtl::file_read_lines($aThread->keyidx, FILE_IGNORE_NEW_LINES)) { $idx_data = explode('<>', $lines[0]); } else { $idx_data = array_fill(0, 12, ''); } $aThread->getThreadInfoFromIdx(); //========================================================== // preview >>1 //========================================================== //if (!empty($_GET['onlyone'])) {
/** * コンストラクタ * * @param string $url * @param string $destination * @param array $options * @param P2HttpCallback $onSuccess * @param P2HttpCallback $onFailure */ public function __construct($url, $destination, array $options = null, P2HttpCallback $onSuccess = null, P2HttpCallback $onFailure = null) { global $_conf; if ($options === null) { $options = array(); } if (!isset($options['connecttimeout'])) { $options['connecttimeout'] = $_conf['http_conn_timeout']; } if (!isset($options['timeout'])) { $options['timeout'] = $_conf['http_read_timeout']; } if (!isset($options['compress'])) { $options['compress'] = true; } if (!isset($options['useragent'])) { $options['useragent'] = "Monazilla/1.00 ({$_conf['p2ua']})"; } if ($_conf['proxy_use'] && !isset($options['proxyhost']) && !empty($_conf['proxy_host'])) { $options['proxyhost'] = $_conf['proxy_host']; if (!empty($_conf['proxy_port']) && is_numeric($_conf['proxy_port'])) { $options['proxyport'] = (int) $_conf['proxy_port']; } elseif (strpos($_conf['proxy_host'], ':') === false) { $options['proxyport'] = 80; } /* $options['proxytype'] = HTTP_PROXY_HTTP; if (isset($_conf['proxy_type'])) { switch ($_conf['proxy_type']) { case 'http': $options['proxytype'] = HTTP_PROXY_HTTP; break; case 'socks4': $options['proxytype'] = HTTP_PROXY_SOCKS4; break; case 'socks5': $options['proxytype'] = HTTP_PROXY_SOCKS5; break; default: if (is_numeric($options['proxytype'])) { $options['proxytype'] = (int)$_conf['proxy_type']; } } } if (!empty($_conf['proxy_auth'])) { $options['proxy_auth'] = $_conf['proxy_auth']; $options['proxyauthtype'] = HTTP_AUTH_BASIC; if (isset($_conf['proxy_auth_type'])) { switch ($_conf['proxy_auth_type']) { case 'basic': $options['proxyauthtype'] = HTTP_AUTH_BASIC; break; case 'digest': $options['proxyauthtype'] = HTTP_AUTH_DIGEST; break; case 'ntlm': $options['proxyauthtype'] = HTTP_AUTH_NTLM; break; case 'gssneg': $options['proxyauthtype'] = HTTP_AUTH_GSSNEG; break; case 'any': $options['proxyauthtype'] = HTTP_AUTH_ANY; break; default: if (is_numeric($options['proxytype'])) { $options['proxyauthtype'] = (int)$_conf['proxy_auth_type']; } } } } */ } if (!isset($options['lastmodified']) && file_exists($destination)) { $options['lastmodified'] = filemtime($destination); } else { FileCtl::mkdirFor($destination); } $this->_destination = $destination; $this->_errorCode = self::E_NONE; $this->_errorInfo = ''; $this->_onSuccess = $onSuccess; $this->_onFailure = $onFailure; $this->_next = null; parent::__construct($url, HttpRequest::METH_GET, $options); }
/** * 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; }
/** * オンライン上のrep2最新版をチェックする * * @return string HTML */ function _checkUpdatan() { global $_conf, $p2web_url_r; $no_p2status_dl_flag = false; $ver_txt_url = $_conf['p2web_url'] . 'p2status.txt'; $cachefile = P2Util::cacheFileForDL($ver_txt_url); FileCtl::mkdirFor($cachefile); if (file_exists($cachefile)) { // キャッシュの更新が指定時間以内なら if (filemtime($cachefile) > time() - $_conf['p2status_dl_interval'] * 60) { $no_p2status_dl_flag = true; } } if (empty($no_p2status_dl_flag)) { P2Util::fileDownload($ver_txt_url, $cachefile); } $ver_txt = file($cachefile); $update_ver = $ver_txt[0]; $kita = 'キタ━━━━(゚∀゚)━━━━!!!!!!'; //$kita = 'キタ*・゚゚・*:.。..。.:*・゚(゚∀゚)゚・*:.。. .。.:*・゚゚・*!!!!!'; $newversion_found_html = ''; if ($update_ver && version_compare($update_ver, $_conf['p2version'], '>')) { $update_ver_hs = hs($update_ver); $p2web_url_r_hs = hs($p2web_url_r); $newversion_found_html = <<<EOP <div class="kakomi"> {$kita}<br> オンライン上に rep2 の最新バージョンを見つけますた。<br> rep2<!-- version {$update_ver_hs}--> → <a href="{$p2web_url_r_hs}cgi/dl/dl.php?dl=p2">ダウンロード</a> / <a href="{$p2web_url_r_hs}p2/doc/ChangeLog.txt"{$_conf['ext_win_target_at']}>更新記録</a> </div> <hr class="invisible"> EOP; } return $newversion_found_html; }
/** * ディレクトリに(アクセス拒否のための) .htaccess がなければ、自動で生成する */ function makeDenyHtaccess($dir) { $hta = $dir . '/.htaccess'; if (!file_exists($hta)) { if (!is_dir($dir)) { FileCtl::mkdirFor($hta); } $data = 'Order allow,deny' . "\n" . 'Deny from all' . "\n"; FileCtl::file_write_contents($hta, $data); } }
/** * ホスト名からクッキーファイルパスを返す * * @return string */ function _cachePathForCookieByHost($host) { global $_conf; $cachefile = $_conf['cookie_dir'] . DIRECTORY_SEPARATOR . P2Util::escapeDirPath($host) . DIRECTORY_SEPARATOR . $_conf['cookie_file_name']; FileCtl::mkdirFor($cachefile); return $cachefile; }
/** * スレッドのdatをダウンロードし、保存する * * @param ThreadRead $thread * @return bool */ public static function invoke(ThreadRead $thread) { global $_conf; // {{{ 既得datの取得レス数が適正かどうかを念のためチェック if (file_exists($thread->keydat)) { $dls = FileCtl::file_read_lines($thread->keydat); if (!$dls || count($dls) != $thread->gotnum) { // echo 'bad size!<br>'; unlink($thread->keydat); $thread->gotnum = 0; } } else { $thread->gotnum = 0; } // }}} // {{{ offlaw.cgiからdatをダウンロード $host = $thread->host; $bbs = $thread->bbs; $key = $thread->key; if ($thread->gotnum == 0) { $option = ''; $append = false; } else { $option = sprintf('%d-', $thread->gotnum + 1); $append = true; } // http://[SERVER]/bbs/offlaw.cgi/[BBS]/[KEY]/[OPTION]; $url = "http://{$host}/bbs/offlaw.cgi/{$bbs}/{$key}/{$option}"; $tempfile = $thread->keydat . '.tmp'; FileCtl::mkdirFor($tempfile); if ($append) { touch($tempfile, filemtime($thread->keydat)); } elseif (file_exists($tempfile)) { unlink($tempfile); } $response = P2Util::fileDownload($url, $tempfile); if ($response->isError()) { if (304 != $response->code) { $thread->diedat = true; } return false; } // }}} // {{{ ダウンロードした各行をチェックしつつローカルdatに書き込み $lines = file($tempfile); unlink($tempfile); if ($append) { $fp = fopen($thread->keydat, 'ab'); } else { $fp = fopen($thread->keydat, 'wb'); } if (!$fp) { p2die("cannot write file. ({$thread->keydat})"); } flock($fp, LOCK_EX); foreach ($lines as $i => $line) { // 取得済みレス数をインクリメント $thread->gotnum++; // 行を分解、要素数チェック (厳密には === 6) $lar = explode('<>', rtrim($line)); if (count($lar) >= 5) { // レス番号は保存しないので取り出す $resnum = (int) array_shift($lar); // レス番号と取得済みレス数が異なっていたらあぼーん扱い while ($thread->gotnum < $resnum) { $abn = "あぼーん<>あぼーん<>あぼーん<>あぼーん<>"; if ($thread->gotnum == 1) { $abn .= $lar[4]; // スレタイトル } $abn .= "\n"; fwrite($fp, $abn); $thread->gotnum++; } // 行を書き込む fwrite($fp, implode('<>', $lar) . "\n"); } else { $thread->gotnum--; $lineno = $i + 1; P2Util::pushInfoHtml("<p>rep2 info: dat書式エラー: line {$lineno} of {$url}.</p>"); break; } } flock($fp, LOCK_UN); fclose($fp); // }}} $thread->isonline = true; return true; }
/** * ダウンロードURLからキャッシュファイルパスを返す */ public static function cacheFileForDL($url) { global $_conf; $parsed = parse_url($url); // URL分解 $save_uri = isset($parsed['host']) ? $parsed['host'] : ''; $save_uri .= isset($parsed['port']) ? ':' . $parsed['port'] : ''; $save_uri .= isset($parsed['path']) ? $parsed['path'] : ''; $save_uri .= isset($parsed['query']) ? '?' . $parsed['query'] : ''; $cachefile = $_conf['cache_dir'] . '/' . $save_uri; FileCtl::mkdirFor($cachefile); return $cachefile; }
/** * 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公式メニューをパースし、板-ホストの対応表を作成する * * @return array site/bbs/(host,itaj) の多次元連想配列 * ダウンロードに失敗したときは false * @access private * @static */ function _getMapping() { global $_conf; static $map = null; // {{{ 設定 $bbsmenu_url = 'http://menu.2ch.net/bbsmenu.html'; $map_cache_path = $_conf['cache_dir'] . '/host_bbs_map.txt'; $map_cache_lifetime = 600; // TTLは少し短めに $errfmt = '<p>rep2 error: BbsMap: %s - %s をダウンロードできませんでした。</p>'; // }}} // {{{ キャッシュ確認 if (!is_null($map)) { return $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); $map = unserialize($map_cahce); return $map; } } else { FileCtl::mkdirFor($map_cache_path); } touch($map_cache_path); clearstatcache(); // }}} // {{{ メニューをダウンロード $params = array(); $params['timeout'] = $_conf['fsockopen_time_limit']; //$params['readTimeout'] = array($_conf['fsockopen_time_limit'], 0); if (isset($mtime)) { $params['requestHeaders'] = array('If-Modified-Since' => gmdate('D, d M Y H:i:s', $mtime) . ' GMT'); } 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)) { $errmsg = sprintf($errfmt, htmlspecialchars($err->getMessage()), htmlspecialchars($bbsmenu_url, ENT_QUOTES)); P2Util::pushInfoHtml($errmsg); 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); $map = unserialize($map_cahce); return $map; } elseif ($code != 200) { $errmsg = sprintf($errfmt, htmlspecialchars(strval($code)), htmlspecialchars($bbsmenu_url, ENT_QUOTES)); P2Util::pushInfoHtml($errmsg); 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 = BbsMap::_detectHostType($host); !isset($map[$type]) and $map[$type] = array(); $map[$type][$bbs] = array('host' => $host, 'itaj' => $itaj); } // }}} // キャッシュする $map_cache = serialize($map); if (false === FileCtl::filePutRename($map_cache_path, $map_cache)) { $errmsg = sprintf('p2 error: cannot write file. (%s)', htmlspecialchars($map_cache_path, ENT_QUOTES)); P2Util::pushInfoHtml($errmsg); if (file_exists($map_cache_path)) { return unserialize(file_get_contents($map_cache_path)); } else { return false; } } return $map; }
/** * keyからファイルの保存パスをす * * @param string $base_dir * @param string $key * @param string $extension * @return string */ public static function getKeyPath($base_dir, $key, $extension = '') { $filename = $key . $extension; $old_path = $base_dir . $filename; if (preg_match('/^[0-9]+$/', $key)) { $path = $base_dir . date('Ym', (int) $key) . DIRECTORY_SEPARATOR . $filename; if (!file_exists($path) && file_exists($old_path)) { FileCtl::mkdirFor($path); rename($old_path, $path); } return $path; } return $old_path; }
/** * まちBBSの read.cgi を読んで datに保存する関数 * * @access public * @return boolean */ function downloadDatMachiBbs(&$ThreadRead) { // {{{ 既得datの取得レス数が適性かどうかを念のためチェック if (file_exists($ThreadRead->keydat)) { $dls = file($ThreadRead->keydat); if (sizeof($dls) != $ThreadRead->gotnum) { // echo 'bad size!<br>'; unlink($ThreadRead->keydat); $ThreadRead->gotnum = 0; } } else { $ThreadRead->gotnum = 0; } // }}} if ($ThreadRead->gotnum == 0) { $file_append = false; $START = 1; } else { $file_append = true; $START = $ThreadRead->gotnum + 1; } // まちBBS $machiurl = "http://{$ThreadRead->host}/bbs/read.cgi?BBS={$ThreadRead->bbs}&KEY={$ThreadRead->key}&START={$START}"; $tempfile = $ThreadRead->keydat . '.html.temp'; FileCtl::mkdirFor($tempfile); $machiurl_res = P2Util::fileDownload($machiurl, $tempfile); if (!$machiurl_res or !$machiurl_res->is_success()) { $ThreadRead->diedat = true; return false; } $mlines = file($tempfile); // 一時ファイルを削除する unlink($tempfile); // (まちBBS)<html>error</html> if (trim($mlines[0]) == '<html>error</html>') { $ThreadRead->pushDownloadDatErrorMsgHtml('error' . '<br>'); $ThreadRead->diedat = true; return false; } // {{{ DATを書き込む $latest_num = 0; if ($mdatlines = _machiHtmltoDatLines($mlines, $latest_num)) { $cont = ''; for ($i = $START; $i <= $latest_num; $i++) { if (isset($mdatlines[$i])) { $cont .= $mdatlines[$i]; } else { $cont .= "あぼーん<>あぼーん<>あぼーん<>あぼーん<>\n"; } } $done = false; if ($fp = fopen($ThreadRead->keydat, 'ab+')) { flock($fp, LOCK_EX); if (false !== fwrite($fp, $cont)) { $done = true; } flock($fp, LOCK_UN); fclose($fp); } if (!$done) { trigger_error('cannot write file (' . $ThreadRead->keydat . ')', E_USER_WARNING); die('Error: cannot write file.'); } } // }}} $ThreadRead->isonline = true; return true; }
/** * Atom 0.3 を RSS 1.0 に変換する(共通) */ function atom_to_rss($input, $stylesheet, $output) { global $_conf; // 保存用ディレクトリがなければつくる if (!is_dir(dirname($output))) { FileCtl::mkdirFor($output); } // 変換 if (extension_loaded('xslt')) { // PHP4, Sablotron $rss_content = atom_to_rss_by_xslt($input, $stylesheet, $output); } elseif (extension_loaded('xsl')) { // PHP5, LibXSLT $rss_content = atom_to_rss_by_xsl($input, $stylesheet, $output); } // チェック if (!$rss_content) { if (file_exists($output)) { unlink($output); } return FALSE; } chmod($output, $_conf['expack.rss.setting_perm']); // FreeBSD 5.3 Ports の textproc/php4-xslt ではバグのせいか変換の際に名前空間が失われるので補正する // (php4-xslt-4.3.10_2, expat-1.95.8, libiconv-1.9.2_1, Sablot-1.0.1) // バグのない環境なら何も変わらない・・・はず。 $rss_fix_patterns = array('/<(\\/)?(RDF|Seq|li)( .+?)?>/u' => '<$1rdf:$2$3>', '/<(channel|item) about=/u' => '<$1 rdf:about=', '/<(\\/)?(encoded)>/u' => '<$1content:$2>', '/<(\\/)?(creator|subject|date|pubdate)>/u' => '<$1dc:$2>'); $rss_fixed = preg_replace(array_keys($rss_fix_patterns), array_values($rss_fix_patterns), $rss_content); if (md5($rss_content) != md5($rss_fixed)) { $fp = @fopen($output, 'wb') or p2die("cannot write. ({$output})"); flock($fp, LOCK_EX); fwrite($fp, $rss_fixed); flock($fp, LOCK_UN); fclose($fp); } return TRUE; }
/** * したらばJBBSの rawmode.cgi を読んで、datに保存する(2ch風に整形) */ function shitarabaDownload(ThreadRead $aThread) { $GLOBALS['machi_latest_num'] = ''; // {{{ 既得datの取得レス数が適性かどうかを念のためチェック if (file_exists($aThread->keydat)) { $dls = FileCtl::file_read_lines($aThread->keydat); if (!$dls || sizeof($dls) != $aThread->gotnum) { // echo 'bad size!<br>'; unlink($aThread->keydat); $aThread->gotnum = 0; } } else { $aThread->gotnum = 0; } // }}} if ($aThread->gotnum == 0) { $file_append = false; $START = 1; } else { $file_append = true; $START = $aThread->gotnum + 1; } // JBBS@したらば if (P2Util::isHostJbbsShitaraba($aThread->host)) { // したらばのlivedoor移転に対応。読込先をlivedoorとする。 $host = P2Util::adjustHostJbbs($aThread->host); list($host, $category, ) = explode('/', $host); $machiurl = "http://{$host}/bbs/rawmode.cgi/{$category}/{$aThread->bbs}/{$aThread->key}/{$START}-"; } $tempfile = $aThread->keydat . '.dat.temp'; FileCtl::mkdirFor($tempfile); $machiurl_res = P2Util::fileDownload($machiurl, $tempfile); if ($machiurl_res->isError()) { $aThread->diedat = true; return false; } // {{{ したらばならEUCをSJISに変換 if (P2Util::isHostJbbsShitaraba($aThread->host)) { $temp_data = FileCtl::file_read_contents($tempfile); $temp_data = mb_convert_encoding($temp_data, 'CP932', 'CP51932'); if (FileCtl::file_write_contents($tempfile, $temp_data) === false) { p2die('cannot write file.'); } } // }}} $mlines = FileCtl::file_read_lines($tempfile); // 一時ファイルを削除する unlink($tempfile); // ↓rawmode.cgiではこれは出ないだろう /* // (JBBS)ERROR!: スレッドがありません。過去ログ倉庫にもありません。 if (stripos($mlines[0], 'ERROR') === 0) { $aThread->getdat_error_msg_ht .= $mlines[0]; $aThread->diedat = true; return false; } */ // {{{ DATを書き込む if ($mdatlines = shitarabaDatTo2chDatLines($mlines)) { $file_append = $file_append ? FILE_APPEND : 0; $cont = ''; for ($i = $START; $i <= $GLOBALS['machi_latest_num']; $i++) { if ($mdatlines[$i]) { $cont .= $mdatlines[$i]; } else { $cont .= "あぼーん<>あぼーん<>あぼーん<>あぼーん<>\n"; } } if (FileCtl::file_write_contents($aThread->keydat, $cont, $file_append) === false) { p2die('cannot write file.'); } } // }}} $aThread->isonline = true; return true; }