/** * チェックした書き込み記事を削除する * * @access public * @return boolean */ function deleMsg($checked_hists) { global $_conf; if (!($reslines = file($_conf['p2_res_hist_dat']))) { p2die(sprintf('%s を開けませんでした', $_conf['p2_res_hist_dat'])); return false; } $reslines = array_map('rtrim', $reslines); // ファイルの下に記録されているものが新しいので逆順にする $reslines = array_reverse($reslines); $neolines = array(); // チェックして整えて if ($reslines) { $rmnums = _getRmNums($checked_hists, $reslines); $neolines = _rmLine($rmnums, $reslines); P2Util::pushInfoHtml("<p>p2 info: " . count($rmnums) . "件のレス記事を削除しました</p>"); } if (is_array($neolines)) { // 行順を戻す $neolines = array_reverse($neolines); $cont = ""; if ($neolines) { $cont = implode("\n", $neolines) . "\n"; } // 書き込み処理 if (false === FileCtl::filePutRename($_conf['p2_res_hist_dat'], $cont)) { $errmsg = sprintf('p2 error: %s(), FileCtl::filePutRename() failed.', __FUNCTION__); trigger_error($errmsg, E_USER_WARNING); return false; } } return true; }
/** * スレを殿堂入りにセットする関数 * * $set は、0(解除), 1(追加), top, up, down, bottom * * @access public * @return boolean */ function setPalace($host, $bbs, $key, $set) { global $_conf; $idxfile = P2Util::getKeyIdxFilePath($host, $bbs, $key); // 既に key.idx データがあるなら読み込む if (file_exists($idxfile) and $lines = file($idxfile)) { $l = rtrim($lines[0]); $data = explode('<>', $l); } if (false === FileCtl::make_datafile($_conf['palace_file'], $_conf['palace_perm'])) { return false; } if (false === ($pallines = file($_conf['palace_file']))) { return false; } $newlines = array(); $before_line_num = 0; // {{{ 最初に重複要素を削除しておく if (!empty($pallines)) { $i = -1; foreach ($pallines as $l) { $i++; $l = rtrim($l); $lar = explode('<>', $l); // 重複回避 if ($lar[1] == $key && $lar[11] == $bbs) { $before_line_num = $i; // 移動前の行番号をセット continue; // keyのないものは不正データなのでスキップ } elseif (!$lar[1]) { continue; } else { $newlines[] = $l; } } } // }}} if (!empty($GLOBALS['brazil'])) { //$newlines = _removeLargePallistData($newlines); } // 新規データ設定 if ($set) { $newdata = implode('<>', array(geti($data[0]), $key, geti($data[2]), geti($data[3]), geti($data[4]), geti($data[5]), geti($data[6]), geti($data[7]), geti($data[8]), geti($data[9]), $host, $bbs)); require_once P2_LIB_DIR . '/getSetPosLines.func.php'; $rec_lines = getSetPosLines($newlines, $newdata, $before_line_num, $set); } else { $rec_lines = $newlines; } if (false === FileCtl::filePutRename($_conf['palace_file'], $rec_lines ? implode("\n", $rec_lines) . "\n" : '')) { trigger_error(sprintf('p2 error: %s(), FileCtl::filePutRename() failed.', __FUNCTION__), E_USER_WARNING); return false; } return true; }
/** * 指定したキーの書き込み履歴を削除する * * @access public * @return integer|false 削除したなら1, 削除対象がなければ2。失敗はfalse */ function offResHist($host, $bbs, $key) { global $_conf; if (!file_exists($_conf['res_hist_idx'])) { return 2; } $lines = file($_conf['res_hist_idx']); if ($lines === false) { return false; } $neolines = array(); // {{{ あれば削除 if (is_array($lines)) { foreach ($lines as $l) { $l = rtrim($l); $lar = explode('<>', $l); // 削除(スキップ) if ($lar[1] == $key && $lar[10] == $host && $lar[11] == $bbs) { $done = true; continue; } $neolines[] = $l; } } // }}} // {{{ 書き込む if (is_array($neolines)) { $cont = ''; foreach ($neolines as $l) { $cont .= $l . "\n"; } if (false === FileCtl::filePutRename($_conf['res_hist_idx'], $cont)) { $errmsg = sprintf('p2 error: %s(), FileCtl::filePutRename() failed.', __FUNCTION__); trigger_error($errmsg, E_USER_WARNING); return false; } } // }}} if (!empty($done)) { return 1; } else { return 2; } }
/** * brdファイルを生成する * * @access public * @return string|false 成功したら生成したbrdファイルのパスを返す */ function makeBrdFile($cachefile) { global $_conf; $cont = ''; $data = file($cachefile); $this->setBrdMatch($cachefile); // パターンマッチ形式を登録 $this->setBrdList($data); // カテゴリーと板をセット if ($this->categories) { foreach ($this->categories as $cate) { if ($cate->num > 0) { $cont .= $cate->name . "\t0\n"; foreach ($cate->menuitas as $mita) { $cont .= "\t{$mita->host}\t{$mita->bbs}\t{$mita->itaj}\n"; } } } } if (!$cont) { // 2008/07/14 なぜここでこんな条件が必要だったのか不明。コメントアウトしてみる。 //if (strlen($GLOBALS['word']) > 0) { P2Util::pushInfoHtml(sprintf("<p>p2 error: %s から板メニューを生成することはできませんでした。</p>\n", hs($cachefile))); //} unlink($cachefile); return false; } $p2brdfile = BrdCtl::getP2BrdFile($cachefile); if (false === FileCtl::make_datafile($p2brdfile, $_conf['p2_perm'])) { return false; } if (false === FileCtl::filePutRename($p2brdfile, $cont)) { die(sprintf('p2 error: %s を更新できませんでした', hs($p2brdfile))); return false; } return $p2brdfile; }
/** * @access private * @return boolean */ function saveSettingSrd($setting_array) { if (false === FileCtl::filePutRename($this->setting_srd, serialize($setting_array))) { return false; } return true; }
/** * 最近読んだスレに記録する * * @param array $data_ar * @return boolean */ function _recRecent($data_ar) { global $_conf; $data_line = implode('<>', $data_ar); $host = $data_ar[10]; $key = $data_ar[1]; // 速報headlineは最近読んだスレに記録しないようにしてみる if ($host == 'headline.2ch.net') { return true; } if (false === FileCtl::make_datafile($_conf['recent_file'], $_conf['rct_perm'])) { return false; } $lines = file($_conf['recent_file']); $newlines = array(); // 最初に重複要素を削除しておく if (is_array($lines)) { foreach ($lines as $line) { $line = rtrim($line); $lar = explode('<>', $line); if ($lar[1] == $key) { continue; } // keyで重複回避 if (!$lar[1]) { continue; } // keyのないものは不正データ $newlines[] = $line; } } // 新規データ追加 array_unshift($newlines, $data_line); while (sizeof($newlines) > $_conf['rct_rec_num']) { array_pop($newlines); } // 書き込む if ($newlines) { $cont = ''; foreach ($newlines as $l) { $cont .= $l . "\n"; } if (false === FileCtl::filePutRename($_conf['recent_file'], $cont)) { $errmsg = sprintf('p2 error: %s(), FileCtl::filePutRename() failed.', __FUNCTION__); trigger_error($errmsg, E_USER_WARNING); return false; } } return true; }
/** * 更新後のデータを書き込む * * @param string $path 書き込むファイルのパス * @param array $neolines 書き込むデータの配列 * @return void * @access private * @static */ function _writeData($path, $neolines) { if (is_array($neolines) && count($neolines) > 0) { $cont = implode('', $neolines); /*} elseif (is_scalar($neolines)) { $cont = strval($neolines);*/ } else { $cont = ''; } if (false === FileCtl::filePutRename($path, $cont)) { $errmsg = sprintf('Error: cannot write file. (%s)', htmlspecialchars($path, ENT_QUOTES)); die($errmsg); } }
/** * 書き込み履歴を記録する * * @return void */ function _recResHist($host, $bbs, $key, $tagCsv, $ttitle) { global $_conf; if (!($host && $bbs && $key)) { return; } FileCtl::make_datafile($_conf['res_hist_idx'], $_conf['res_write_perm']); $lines = file($_conf['res_hist_idx']); $neolines = array(); // 最初に重複要素を削除しておく if (is_array($lines)) { foreach ($lines as $line) { $line = rtrim($line); $lar = explode('<>', $line); if ($lar[1] == $key) { continue; } // 重複回避 if (!$lar[1]) { continue; } // keyのないものは不正データ $neolines[] = $line; } } // 新規データ追加 $newdata = "{$ttitle}<>{$key}<><><><><><>" . $tagCsv['FROM'] . '<>' . $tagCsv['mail'] . "<><>{$host}<>{$bbs}"; array_unshift($neolines, $newdata); while (sizeof($neolines) > $_conf['res_hist_rec_num']) { array_pop($neolines); } // 書き込む if ($neolines) { $cont = ''; foreach ($neolines as $l) { $cont .= $l . "\n"; } if (false === FileCtl::filePutRename($_conf['res_hist_idx'], $cont)) { $errmsg = sprintf('p2 error: %s(), FileCtl::filePutRename() failed.', __FUNCTION__); trigger_error($errmsg, E_USER_WARNING); //return false; } } }
/** * hostとbbsから板名を取得する * * @access public * @return string|null */ function getItaName($host, $bbs) { global $_conf, $ita_names; $id = $host . '/' . $bbs; if (isset($ita_names[$id])) { return $ita_names[$id]; } $p2_setting_txt = P2Util::idxDirOfHostBbs($host, $bbs) . 'p2_setting.txt'; if (file_exists($p2_setting_txt)) { $p2_setting_cont = file_get_contents($p2_setting_txt); if ($p2_setting_cont) { $p2_setting = unserialize($p2_setting_cont); if (isset($p2_setting['itaj'])) { $ita_names[$id] = $p2_setting['itaj']; return $ita_names[$id]; } } } // 板名Longの取得 if (!isset($p2_setting['itaj'])) { require_once P2_LIB_DIR . '/BbsMap.php'; $itaj = BbsMap::getBbsName($host, $bbs); if ($itaj != $bbs) { $ita_names[$id] = $p2_setting['itaj'] = $itaj; FileCtl::make_datafile($p2_setting_txt, $_conf['p2_perm']); $p2_setting_cont = serialize($p2_setting); if (false === FileCtl::filePutRename($p2_setting_txt, $p2_setting_cont)) { die("Error: {$p2_setting_txt} を更新できませんでした"); } return $ita_names[$id]; } } return null; }
/** * cachedGetHostByAddr/cachedGetHostByName のキャッシュエンジン * * @return string * @access private * @static */ function _cachedGetHost($remote, $function, $cache_file) { static $caches_ = array(); if (array_key_exists("{$function}/{$remote}", $caches_)) { return $caches_["{$function}/{$remote}"]; } $ttl = $GLOBALS['_HOSTCHKCONF']['gethostby_expires']; // クライアントホストの名前解決はできるだけ避けるようにする if ($function == 'gethostbyaddr' and HostCheck::isAddrLocal() || HostCheck::isAddrPrivate()) { $caches_["{$function}/{$remote}"] = ''; return $caches_["{$function}/{$remote}"]; } // ファイルキャッシュしない設定のとき if ($ttl <= 0) { $caches_["{$function}/{$remote}"] = $function($remote); return $caches_["{$function}/{$remote}"]; } // ファイルキャッシュ有効のとき $now = time(); $list = array(); // キャッシュファイルが無ければ作成する if (!file_exists($cache_file)) { FileCtl::make_datafile($cache_file); } // キャッシュを読み込む $lines = file($cache_file); if (is_array($lines)) { foreach ($lines as $line) { list($query, $result, $expires) = explode("\t", rtrim($line, "\n")); if ($expires > $now) { $list[$query] = array($result, $expires); } } } // キャッシュされているとき if (isset($list[$remote])) { $caches_["{$function}/{$remote}"] = $list[$remote][0]; return $caches_["{$function}/{$remote}"]; } // キャッシュされていないとき $result = $function($remote); $list[$remote] = array($result, $ttl + $now); // キャッシュを保存する $content = ''; foreach ($list as $query => $item) { $content .= $query . "\t" . $item[0] . "\t" . $item[1] . "\n"; } FileCtl::filePutRename($cache_file, $content); $caches_["{$function}/{$remote}"] = $result; return $caches_["{$function}/{$remote}"]; }
$neolines[] = $line; } } // 新規データ追加 $newdata = "{$ttitle}<>{$key}<><><><><><>" . $tagCsv['FROM'] . '<>' . $tagCsv['mail'] . "<><>{$host}<>{$bbs}"; array_unshift($neolines, $newdata); while (sizeof($neolines) > $_conf['res_hist_rec_num']) { array_pop($neolines); } // 書き込む if ($neolines) { $cont = ''; foreach ($neolines as $l) { $cont .= $l . "\n"; } if (FileCtl::filePutRename($rh_idx, $cont) === false) { $errmsg = sprintf('p2 error: %s(), FileCtl::filePutRename() failed.', __FUNCTION__); trigger_error($errmsg, E_USER_WARNING); //return false; } } } // }}} // 書き込みログ記録 $tagCsv['message'] = formatMessageTagCvs($MESSAGE); if ($_conf['res_write_rec']) { recResLog($tagCsv['FROM'], $tagCsv['mail'], $tagCsv['message'], $ttitle, $host, $bbs, $key, $rescount); } recResLogSecu($tagCsv['FROM'], $tagCsv['mail'], $tagCsv['message'], $ttitle, $host, $bbs, $key, $rescount); exit; //=======================================================================
/** * 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; }