PageRenderTime 46ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/P2Util.php

https://github.com/unpush/p2-php
PHP | 2058 lines | 1059 code | 286 blank | 713 comment | 228 complexity | c9deb0a52adfee67c3ca5924eadc5a13 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. // {{{ P2Util
  3. /**
  4. * rep2 - p2用のユーティリティクラス
  5. * インスタンスを作らずにクラスメソッドで利用する
  6. *
  7. * @create 2004/07/15
  8. * @static
  9. */
  10. class P2Util
  11. {
  12. // {{{ properties
  13. /**
  14. * getItaName() のキャッシュ
  15. */
  16. static private $_itaNames = array();
  17. /**
  18. * _p2DirOfHost() のキャッシュ
  19. */
  20. static private $_hostDirs = array();
  21. /**
  22. * isHost2chs() のキャッシュ
  23. */
  24. static private $_hostIs2chs = array();
  25. /**
  26. * isHostBe2chNet() のキャッシュ
  27. */
  28. //static private $_hostIsBe2chNet = array();
  29. /**
  30. * isHostBbsPink() のキャッシュ
  31. */
  32. static private $_hostIsBbsPink = array();
  33. /**
  34. * isHostMachiBbs() のキャッシュ
  35. */
  36. static private $_hostIsMachiBbs = array();
  37. /**
  38. * isHostMachiBbsNet() のキャッシュ
  39. */
  40. static private $_hostIsMachiBbsNet = array();
  41. /**
  42. * isHostJbbsShitaraba() のキャッシュ
  43. */
  44. static private $_hostIsJbbsShitaraba = array();
  45. /**
  46. * P2Imeオブジェクト
  47. *
  48. * @var P2Ime
  49. */
  50. static private $_ime = null;
  51. /**
  52. * P2Imeで自動転送しない拡張子のリスト
  53. *
  54. * @var array
  55. */
  56. static private $_imeMenualExtensions = null;
  57. // }}}
  58. // {{{ getMyHost()
  59. /**
  60. * ポート番号を削ったホスト名を取得する
  61. *
  62. * @param void
  63. * @return string|null
  64. */
  65. static public function getMyHost()
  66. {
  67. if (!isset($_SERVER['HTTP_HOST'])) {
  68. return null;
  69. }
  70. return preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST']);
  71. }
  72. // }}}
  73. // {{{ getCookieDomain()
  74. /**
  75. * @param void
  76. * @return string
  77. */
  78. static public function getCookieDomain()
  79. {
  80. return '';
  81. }
  82. // }}}
  83. // {{{ encodeCookieName()
  84. /**
  85. * @param string $key
  86. * @return string
  87. */
  88. static private function encodeCookieName($key)
  89. {
  90. // 配列指定用に、[]だけそのまま残して、URLエンコードをかける
  91. return $key_urlen = preg_replace_callback(
  92. '/[^\\[\\]]+/',
  93. array(__CLASS__, 'rawurlencodeCallback'),
  94. $key
  95. );
  96. }
  97. // }}}
  98. // {{{ setCookie()
  99. /**
  100. * setcookie() では、auで必要なmax ageが設定されないので、こちらを利用する
  101. *
  102. * @access public
  103. * @param string $key
  104. * @param string $value
  105. * @param int $expires
  106. * @param string $path
  107. * @param string $domain
  108. * @param boolean $secure
  109. * @param boolean $httponly
  110. * @return boolean
  111. */
  112. static public function setCookie($key, $value = '', $expires = null, $path = '', $domain = null, $secure = false, $httponly = true)
  113. {
  114. if (is_null($domain)) {
  115. $domain = self::getCookieDomain();
  116. }
  117. is_null($expires) and $expires = time() + 60 * 60 * 24 * 365;
  118. if (headers_sent()) {
  119. return false;
  120. }
  121. // Mac IEは、動作不良を起こすらしいっぽいので、httponlyの対象から外す。(そもそも対応もしていない)
  122. // MAC IE5.1 Mozilla/4.0 (compatible; MSIE 5.16; Mac_PowerPC)
  123. if (preg_match('/MSIE \d\\.\d+; Mac/', geti($_SERVER['HTTP_USER_AGENT']))) {
  124. $httponly = false;
  125. }
  126. // setcookie($key, $value, $expires, $path, $domain, $secure = false, $httponly = true);
  127. /*
  128. if (is_array($name)) {
  129. list($k, $v) = each($name);
  130. $name = $k . '[' . $v . ']';
  131. }
  132. */
  133. if ($expires) {
  134. $maxage = $expires - time();
  135. }
  136. header(
  137. 'Set-Cookie: '. self::encodeCookieName($key) . '=' . rawurlencode($value)
  138. . (empty($domain) ? '' : '; Domain=' . $domain)
  139. . (empty($expires) ? '' : '; expires=' . gmdate('D, d-M-Y H:i:s', $expires) . ' GMT')
  140. . (empty($maxage) ? '' : '; Max-Age=' . $maxage)
  141. . (empty($path) ? '' : '; Path=' . $path)
  142. . (!$secure ? '' : '; Secure')
  143. . (!$httponly ? '' : '; HttpOnly'),
  144. $replace = false
  145. );
  146. return true;
  147. }
  148. // }}}
  149. // {{{ unsetCookie()
  150. /**
  151. * クッキーを消去する。変数 $_COOKIE も。
  152. *
  153. * @param string $key key, k1[k2]
  154. * @param string $path
  155. * @param string $domain
  156. * @return boolean
  157. */
  158. static public function unsetCookie($key, $path = '', $domain = null)
  159. {
  160. if (is_null($domain)) {
  161. $domain = self::getCookieDomain();
  162. }
  163. // 配列をsetcookie()する時は、キー文字列をPHPの配列の場合のように、'' や "" でクォートしない。
  164. // それらはキー文字列として認識されてしまう。['hoge']ではなく、[hoge]と指定する。
  165. // setcookie()で、一時キーは[]で囲まないようにする。(無効な処理となる。) k1[k2] という表記で指定する。
  166. // setcookie()では配列をまとめて削除することはできない。
  167. // k1 の指定で k1[k2] は消えないので、このメソッドで対応している。
  168. // $keyが配列として指定されていたなら
  169. $cakey = null; // $_COOKIE用のキー
  170. if (preg_match('/\]$/', $key)) {
  171. // 最初のキーを[]で囲む
  172. $cakey = preg_replace('/^([^\[]+)/', '[$1]', $key);
  173. // []のキーを''で囲む
  174. $cakey = preg_replace('/\[([^\[\]]+)\]/', "['$1']", $cakey);
  175. //var_dump($cakey);
  176. }
  177. // 対象Cookie値が配列であれば再帰処理を行う
  178. $cArray = null;
  179. if ($cakey) {
  180. eval("isset(\$_COOKIE{$cakey}) && is_array(\$_COOKIE{$cakey}) and \$cArray = \$_COOKIE{$cakey};");
  181. } else {
  182. if (isset($_COOKIE[$key]) && is_array($_COOKIE[$key])) {
  183. $cArray = $_COOKIE[$key];
  184. }
  185. }
  186. if (is_array($cArray)) {
  187. foreach ($cArray as $k => $v) {
  188. $keyr = "{$key}[{$k}]";
  189. if (!self::unsetCookie($keyr, $path, $domain)) {
  190. return false;
  191. }
  192. }
  193. }
  194. if (is_array($cArray) or setcookie("$key", '', time() - 3600, $path, $domain)) {
  195. if ($cakey) {
  196. eval("unset(\$_COOKIE{$cakey});");
  197. } else {
  198. unset($_COOKIE[$key]);
  199. }
  200. return true;
  201. }
  202. return false;
  203. }
  204. // }}}
  205. // {{{ fileDownload()
  206. /**
  207. * ファイルをダウンロード保存する
  208. */
  209. static public function fileDownload($url, $localfile,
  210. $disp_error = true,
  211. $trace_redirection = false)
  212. {
  213. global $_conf;
  214. $perm = (isset($_conf['dl_perm'])) ? $_conf['dl_perm'] : 0606;
  215. if (file_exists($localfile)) {
  216. $modified = http_date(filemtime($localfile));
  217. } else {
  218. $modified = false;
  219. }
  220. // DL
  221. $wap_ua = new WapUserAgent();
  222. $wap_ua->setTimeout($_conf['http_conn_timeout'], $_conf['http_read_timeout']);
  223. $wap_ua->setAtFsockopen(true);
  224. $wap_req = new WapRequest();
  225. $wap_req->setUrl($url);
  226. $wap_req->setModified($modified);
  227. if ($_conf['proxy_use']) {
  228. $wap_req->setProxy($_conf['proxy_host'], $_conf['proxy_port']);
  229. }
  230. $wap_res = $wap_ua->request($wap_req);
  231. // 1段階だけリダイレクトを追跡
  232. if ($wap_res->isRedirect() && array_key_exists('Location', $wap_res->headers) &&
  233. ($trace_redirection === true || $trace_redirection == $wap_res->code))
  234. {
  235. $wap_req->setUrl($wap_res->headers['Location']);
  236. $wap_res = $wap_ua->request($wap_req);
  237. }
  238. // エラーメッセージを設定
  239. if ($wap_res->isError() && $disp_error) {
  240. $url_t = self::throughIme($wap_req->url);
  241. $info_msg_ht = "<p class=\"info-msg\">Error: {$wap_res->code} {$wap_res->message}<br>";
  242. if ($wap_res->isRedirect() && array_key_exists('Location', $wap_res->headers)) {
  243. $location = $wap_res->headers['Location'];
  244. $location_ht = htmlspecialchars($location, ENT_QUOTES);
  245. $location_t = self::throughIme($location);
  246. $info_msg_ht .= "Location: <a href=\"{$location_t}\"{$_conf['ext_win_target_at']}>{$location_ht}</a><br>";
  247. }
  248. $info_msg_ht .= "rep2 info: <a href=\"{$url_t}\"{$_conf['ext_win_target_at']}>{$wap_req->url}</a> に接続できませんでした。</p>";
  249. self::pushInfoHtml($info_msg_ht);
  250. }
  251. // 更新されていたら
  252. if ($wap_res->isSuccess() && $wap_res->code != 304) {
  253. if (FileCtl::file_write_contents($localfile, $wap_res->content) === false) {
  254. p2die('cannot write file.');
  255. }
  256. chmod($localfile, $perm);
  257. }
  258. return $wap_res;
  259. }
  260. // }}}
  261. // {{{ checkDirWritable()
  262. /**
  263. * パーミッションの注意を喚起する
  264. */
  265. static public function checkDirWritable($aDir)
  266. {
  267. global $_conf;
  268. // マルチユーザモード時は、情報メッセージを抑制している。
  269. $info_msg_ht = '';
  270. if (!is_dir($aDir)) {
  271. /*
  272. $info_msg_ht .= '<p class="info-msg">';
  273. $info_msg_ht .= '注意: データ保存用ディレクトリがありません。<br>';
  274. $info_msg_ht .= $aDir."<br>";
  275. */
  276. if (is_dir(dirname(realpath($aDir))) && is_writable(dirname(realpath($aDir)))) {
  277. //$info_msg_ht .= "ディレクトリの自動作成を試みます...<br>";
  278. if (mkdir($aDir, $_conf['data_dir_perm'])) {
  279. //$info_msg_ht .= "ディレクトリの自動作成が成功しました。";
  280. chmod($aDir, $_conf['data_dir_perm']);
  281. } else {
  282. //$info_msg_ht .= "ディレクトリを自動作成できませんでした。<br>手動でディレクトリを作成し、パーミッションを設定して下さい。";
  283. }
  284. } else {
  285. //$info_msg_ht .= "ディレクトリを作成し、パーミッションを設定して下さい。";
  286. }
  287. //$info_msg_ht .= '</p>';
  288. } elseif (!is_writable($aDir)) {
  289. $info_msg_ht .= '<p class="info-msg">注意: データ保存用ディレクトリに書き込み権限がありません。<br>';
  290. //$info_msg_ht .= $aDir.'<br>';
  291. $info_msg_ht .= 'ディレクトリのパーミッションを見直して下さい。</p>';
  292. }
  293. self::pushInfoHtml($info_msg_ht);
  294. }
  295. // }}}
  296. // {{{ cacheFileForDL()
  297. /**
  298. * ダウンロードURLからキャッシュファイルパスを返す
  299. */
  300. static public function cacheFileForDL($url)
  301. {
  302. global $_conf;
  303. $parsed = parse_url($url); // URL分解
  304. $save_uri = isset($parsed['host']) ? $parsed['host'] : '';
  305. $save_uri .= isset($parsed['port']) ? ':' . $parsed['port'] : '';
  306. $save_uri .= isset($parsed['path']) ? $parsed['path'] : '';
  307. $save_uri .= isset($parsed['query']) ? '?' . $parsed['query'] : '';
  308. $cachefile = $_conf['cache_dir'] . '/' . $save_uri;
  309. FileCtl::mkdirFor($cachefile);
  310. return $cachefile;
  311. }
  312. // }}}
  313. // {{{ getItaName()
  314. /**
  315. * hostとbbsから板名を返す
  316. */
  317. static public function getItaName($host, $bbs)
  318. {
  319. global $_conf;
  320. $id = $host . '/' . $bbs;
  321. if (array_key_exists($id, self::$_itaNames)) {
  322. return self::$_itaNames[$id];
  323. }
  324. $p2_setting_txt = self::idxDirOfHostBbs($host, $bbs) . 'p2_setting.txt';
  325. if (file_exists($p2_setting_txt)) {
  326. $p2_setting_cont = FileCtl::file_read_contents($p2_setting_txt);
  327. if ($p2_setting_cont) {
  328. $p2_setting = unserialize($p2_setting_cont);
  329. if (isset($p2_setting['itaj'])) {
  330. self::$_itaNames[$id] = $p2_setting['itaj'];
  331. return self::$_itaNames[$id];
  332. }
  333. }
  334. }
  335. // 板名Longの取得
  336. if (!isset($p2_setting['itaj'])) {
  337. $itaj = BbsMap::getBbsName($host, $bbs);
  338. if ($itaj != $bbs) {
  339. self::$_itaNames[$id] = $p2_setting['itaj'] = $itaj;
  340. FileCtl::make_datafile($p2_setting_txt, $_conf['p2_perm']);
  341. $p2_setting_cont = serialize($p2_setting);
  342. if (FileCtl::file_write_contents($p2_setting_txt, $p2_setting_cont) === false) {
  343. p2die("{$p2_setting_txt} を更新できませんでした");
  344. }
  345. return self::$_itaNames[$id];
  346. }
  347. }
  348. return null;
  349. }
  350. // }}}
  351. // {{{ _p2DirOfHost()
  352. /**
  353. * hostからrep2の各種データ保存ディレクトリを返す
  354. *
  355. * @param string $base_dir
  356. * @param string $host
  357. * @param bool $dir_sep
  358. * @return string
  359. */
  360. static private function _p2DirOfHost($base_dir, $host, $dir_sep = true)
  361. {
  362. $key = $base_dir . DIRECTORY_SEPARATOR . $host;
  363. if (array_key_exists($key, self::$_hostDirs)) {
  364. if ($dir_sep) {
  365. return self::$_hostDirs[$key] . DIRECTORY_SEPARATOR;
  366. }
  367. return self::$_hostDirs[$key];
  368. }
  369. $host = self::normalizeHostName($host);
  370. // 2channel or bbspink
  371. if (self::isHost2chs($host)) {
  372. $host_dir = $base_dir . DIRECTORY_SEPARATOR . '2channel';
  373. // machibbs.com
  374. } elseif (self::isHostMachiBbs($host)) {
  375. $host_dir = $base_dir . DIRECTORY_SEPARATOR . 'machibbs.com';
  376. // jbbs.livedoor.jp (livedoor レンタル掲示板)
  377. } elseif (self::isHostJbbsShitaraba($host)) {
  378. if (DIRECTORY_SEPARATOR == '/') {
  379. $host_dir = $base_dir . DIRECTORY_SEPARATOR . $host;
  380. } else {
  381. $host_dir = $base_dir . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $host);
  382. }
  383. // livedoor レンタル掲示板以外でスラッシュ等の文字を含むとき
  384. } elseif (preg_match('/[^0-9A-Za-z.\\-_]/', $host)) {
  385. $host_dir = $base_dir . DIRECTORY_SEPARATOR . rawurlencode($host);
  386. /*
  387. if (DIRECTORY_SEPARATOR == '/') {
  388. $old_host_dir = $base_dir . DIRECTORY_SEPARATOR . $host;
  389. } else {
  390. $old_host_dir = $base_dir . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $host);
  391. }
  392. if (is_dir($old_host_dir)) {
  393. rename($old_host_dir, $host_dir);
  394. clearstatcache();
  395. }
  396. */
  397. // その他
  398. } else {
  399. $host_dir = $base_dir . DIRECTORY_SEPARATOR . $host;
  400. }
  401. // キャッシュする
  402. self::$_hostDirs[$key] = $host_dir;
  403. // ディレクトリ区切り文字を追加
  404. if ($dir_sep) {
  405. $host_dir .= DIRECTORY_SEPARATOR;
  406. }
  407. return $host_dir;
  408. }
  409. // }}}
  410. // {{{ datDirOfHost()
  411. /**
  412. * hostからdatの保存ディレクトリを返す
  413. * 古いコードとの互換のため、デフォルトではディレクトリ区切り文字を追加しない
  414. *
  415. * @param string $host
  416. * @param bool $dir_sep
  417. * @return string
  418. * @see P2Util::_p2DirOfHost()
  419. */
  420. static public function datDirOfHost($host, $dir_sep = false)
  421. {
  422. return self::_p2DirOfHost($GLOBALS['_conf']['dat_dir'], $host, $dir_sep);
  423. }
  424. // }}}
  425. // {{{ idxDirOfHost()
  426. /**
  427. * hostからidxの保存ディレクトリを返す
  428. * 古いコードとの互換のため、デフォルトではディレクトリ区切り文字を追加しない
  429. *
  430. * @param string $host
  431. * @param bool $dir_sep
  432. * @return string
  433. * @see P2Util::_p2DirOfHost()
  434. */
  435. static public function idxDirOfHost($host, $dir_sep = false)
  436. {
  437. return self::_p2DirOfHost($GLOBALS['_conf']['idx_dir'], $host, $dir_sep);
  438. }
  439. // }}}
  440. // {{{ datDirOfHostBbs()
  441. /**
  442. * host,bbsからdatの保存ディレクトリを返す
  443. * デフォルトでディレクトリ区切り文字を追加する
  444. *
  445. * @param string $host
  446. * @param string $bbs
  447. * @param bool $dir_sep
  448. * @return string
  449. * @see P2Util::_p2DirOfHost()
  450. */
  451. static public function datDirOfHostBbs($host, $bbs, $dir_sep = true)
  452. {
  453. $dir = self::_p2DirOfHost($GLOBALS['_conf']['dat_dir'], $host) . $bbs;
  454. if ($dir_sep) {
  455. $dir .= DIRECTORY_SEPARATOR;
  456. }
  457. return $dir;
  458. }
  459. // }}}
  460. // {{{ idxDirOfHostBbs()
  461. /**
  462. * host,bbsからidxの保存ディレクトリを返す
  463. * デフォルトでディレクトリ区切り文字を追加する
  464. *
  465. * @param string $host
  466. * @param string $bbs
  467. * @param bool $dir_sep
  468. * @return string
  469. * @see P2Util::_p2DirOfHost()
  470. */
  471. static public function idxDirOfHostBbs($host, $bbs, $dir_sep = true)
  472. {
  473. $dir = self::_p2DirOfHost($GLOBALS['_conf']['idx_dir'], $host) . $bbs;
  474. if ($dir_sep) {
  475. $dir .= DIRECTORY_SEPARATOR;
  476. }
  477. return $dir;
  478. }
  479. // }}}
  480. // {{{ pathForHost()
  481. /**
  482. * hostに対応する汎用のパスを返す
  483. *
  484. * @param string $host
  485. * @param bool $with_slashes
  486. * @return string
  487. * @see P2Util::_p2DirOfHost()
  488. */
  489. static public function pathForHost($host, $with_slashes = true)
  490. {
  491. $path = self::_p2DirOfHost('', $host, $with_slashes);
  492. if (DIRECTORY_SEPARATOR != '/') {
  493. $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
  494. }
  495. if (!$with_slashes) {
  496. $path = trim($path, '/');
  497. }
  498. return $path;
  499. }
  500. // }}}
  501. // {{{ pathForHostBbs()
  502. /**
  503. * host,bbsに対応する汎用のパスを返す
  504. *
  505. * @param string $host
  506. * @param string $bbs
  507. * @param bool $with_slash
  508. * @return string
  509. * @see P2Util::_p2DirOfHost()
  510. */
  511. static public function pathForHostBbs($host, $bbs, $with_slashes = true)
  512. {
  513. $path = self::_p2DirOfHost('', $host, true) . $bbs;
  514. if (DIRECTORY_SEPARATOR != '/') {
  515. $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
  516. }
  517. if ($with_slashes) {
  518. $path .= '/';
  519. } else {
  520. $path = trim($path, '/');
  521. }
  522. return $path;
  523. }
  524. // }}}
  525. // {{{ getListNaviRange()
  526. /**
  527. * リストのナビ範囲を返す
  528. */
  529. static public function getListNaviRange($disp_from, $disp_range, $disp_all_num)
  530. {
  531. if (!$disp_all_num) {
  532. return array(
  533. 'all_once' => true,
  534. 'from' => 0,
  535. 'end' => 0,
  536. 'limit' => 0,
  537. 'offset' => 0,
  538. 'mae_from' => 1,
  539. 'tugi_from' => 1,
  540. 'range_st' => '-',
  541. );
  542. }
  543. $disp_from = max(1, $disp_from);
  544. $disp_range = max(0, $disp_range - 1);
  545. $disp_navi = array();
  546. $disp_navi['all_once'] = false;
  547. $disp_navi['from'] = $disp_from;
  548. // fromが越えた
  549. if ($disp_navi['from'] > $disp_all_num) {
  550. $disp_navi['from'] = max(1, $disp_all_num - $disp_range);
  551. $disp_navi['end'] = $disp_all_num;
  552. // from 越えない
  553. } else {
  554. $disp_navi['end'] = $disp_navi['from'] + $disp_range;
  555. // end 越えた
  556. if ($disp_navi['end'] > $disp_all_num) {
  557. $disp_navi['end'] = $disp_all_num;
  558. if ($disp_navi['from'] == 1) {
  559. $disp_navi['all_once'] = true;
  560. }
  561. }
  562. }
  563. $disp_navi['offset'] = $disp_navi['from'] - 1;
  564. $disp_navi['limit'] = $disp_navi['end'] - $disp_navi['offset'];
  565. $disp_navi['mae_from'] = max(1, $disp_navi['offset'] - $disp_range);
  566. $disp_navi['tugi_from'] = min($disp_all_num, $disp_navi['end']) + 1;
  567. if ($disp_navi['from'] == $disp_navi['end']) {
  568. $range_on_st = $disp_navi['from'];
  569. } else {
  570. $range_on_st = "{$disp_navi['from']}-{$disp_navi['end']}";
  571. }
  572. $disp_navi['range_st'] = "{$range_on_st}/{$disp_all_num} ";
  573. return $disp_navi;
  574. }
  575. // }}}
  576. // {{{ recKeyIdx()
  577. /**
  578. * key.idx に data を記録する
  579. *
  580. * @param array $data 要素の順番に意味あり。
  581. */
  582. static public function recKeyIdx($keyidx, $data)
  583. {
  584. global $_conf;
  585. // 基本は配列で受け取る
  586. if (is_array($data)) {
  587. $cont = implode('<>', $data);
  588. // 旧互換用にstringも受付
  589. } else {
  590. $cont = rtrim($data);
  591. }
  592. $cont = $cont . "\n";
  593. FileCtl::make_datafile($keyidx, $_conf['key_perm']);
  594. if (FileCtl::file_write_contents($keyidx, $cont) === false) {
  595. p2die('cannot write file.');
  596. }
  597. return true;
  598. }
  599. // }}}
  600. // {{{ throughIme()
  601. /**
  602. * 中継ゲートを通すためのURL変換
  603. *
  604. * @param string $url
  605. * @param int $delay 負数の場合は手動転送、それ以外はゲートの仕様による
  606. * @return string
  607. */
  608. static public function throughIme($url, $delay = null)
  609. {
  610. if (self::$_ime === null) {
  611. self::configureIme();
  612. }
  613. return self::$_ime->through($url, $delay);
  614. }
  615. // }}}
  616. // {{{ configureIme()
  617. /**
  618. * URL変換の設定をする
  619. *
  620. * @param string $type
  621. * @param array $exceptions
  622. * @param boolean $ignoreHttp
  623. * @return void
  624. * @see P2Ime::__construct()
  625. */
  626. static public function configureIme($type = null, array $exceptions = null, $ignoreHttp = null)
  627. {
  628. self::$_ime = new P2Ime($type, $exceptions, $ignoreHttp);
  629. }
  630. // }}}
  631. // {{{ normalizeHostName()
  632. /**
  633. * hostを正規化する
  634. *
  635. * @param string $host
  636. * @return string
  637. */
  638. static public function normalizeHostName($host)
  639. {
  640. $host = trim($host, '/');
  641. if (($sp = strpos($host, '/')) !== false) {
  642. return strtolower(substr($host, 0, $sp)) . substr($host, $sp);
  643. }
  644. return strtolower($host);
  645. }
  646. // }}}
  647. // {{ isHostExample
  648. /**
  649. * host が例示用ドメインなら true を返す
  650. *
  651. * @param string $host
  652. * @return bool
  653. */
  654. static public function isHostExample($host)
  655. {
  656. return (bool)preg_match('/(?:^|\\.)example\\.(?:com|net|org|jp)$/i', $host);
  657. }
  658. // }}}
  659. // {{{ isHost2chs()
  660. /**
  661. * host が 2ch or bbspink なら true を返す
  662. *
  663. * @param string $host
  664. * @return bool
  665. */
  666. static public function isHost2chs($host)
  667. {
  668. if (!array_key_exists($host, self::$_hostIs2chs)) {
  669. self::$_hostIs2chs[$host] = (bool)preg_match('<^\\w+\\.(?:2ch\\.net|bbspink\\.com)$>', $host);
  670. }
  671. return self::$_hostIs2chs[$host];
  672. }
  673. // }}}
  674. // {{{ isHostBe2chNet()
  675. /**
  676. * host が be.2ch.net なら true を返す
  677. *
  678. * @param string $host
  679. * @return bool
  680. */
  681. static public function isHostBe2chNet($host)
  682. {
  683. return ($host == 'be.2ch.net');
  684. /*
  685. if (!array_key_exists($host, self::$_hostIsBe2chNet)) {
  686. self::$_hostIsBe2chNet[$host] = ($host == 'be.2ch.net');
  687. }
  688. return self::$_hostIsBe2chNet[$host];
  689. */
  690. }
  691. // }}}
  692. // {{{ isHostBbsPink()
  693. /**
  694. * host が bbspink なら true を返す
  695. *
  696. * @param string $host
  697. * @return bool
  698. */
  699. static public function isHostBbsPink($host)
  700. {
  701. if (!array_key_exists($host, self::$_hostIsBbsPink)) {
  702. self::$_hostIsBbsPink[$host] = (bool)preg_match('<^\\w+\\.bbspink\\.com$>', $host);
  703. }
  704. return self::$_hostIsBbsPink[$host];
  705. }
  706. // }}}
  707. // {{{ isHostMachiBbs()
  708. /**
  709. * host が machibbs なら true を返す
  710. *
  711. * @param string $host
  712. * @return bool
  713. */
  714. static public function isHostMachiBbs($host)
  715. {
  716. if (!array_key_exists($host, self::$_hostIsMachiBbs)) {
  717. self::$_hostIsMachiBbs[$host] = (bool)preg_match('<^\\w+\\.machi(?:bbs\\.com|\\.to)$>', $host);
  718. }
  719. return self::$_hostIsMachiBbs[$host];
  720. }
  721. // }}}
  722. // {{{ isHostMachiBbsNet()
  723. /**
  724. * host が machibbs.net まちビねっと なら true を返す
  725. *
  726. * @param string $host
  727. * @return bool
  728. */
  729. static public function isHostMachiBbsNet($host)
  730. {
  731. if (!array_key_exists($host, self::$_hostIsMachiBbsNet)) {
  732. self::$_hostIsMachiBbsNet[$host] = (bool)preg_match('<^\\w+\\.machibbs\\.net$>', $host);
  733. }
  734. return self::$_hostIsMachiBbsNet[$host];
  735. }
  736. // }}}
  737. // {{{ isHostJbbsShitaraba()
  738. /**
  739. * host が livedoor レンタル掲示板 : したらば なら true を返す
  740. *
  741. * @param string $host
  742. * @return bool
  743. */
  744. static public function isHostJbbsShitaraba($in_host)
  745. {
  746. if (!array_key_exists($in_host, self::$_hostIsJbbsShitaraba)) {
  747. if ($in_host == 'rentalbbs.livedoor.com') {
  748. self::$_hostIsJbbsShitaraba[$in_host] = true;
  749. } elseif (preg_match('<^jbbs\\.(?:shitaraba\\.com|livedoor\\.(?:com|jp))(?:/|$)>', $in_host)) {
  750. self::$_hostIsJbbsShitaraba[$in_host] = true;
  751. } else {
  752. self::$_hostIsJbbsShitaraba[$in_host] = false;
  753. }
  754. }
  755. return self::$_hostIsJbbsShitaraba[$in_host];
  756. }
  757. // }}}
  758. // {{{ adjustHostJbbs()
  759. /**
  760. * livedoor レンタル掲示板 : したらばのホスト名変更に対応して変更する
  761. *
  762. * @param string $in_str ホスト名でもURLでもなんでも良い
  763. * @return string
  764. */
  765. static public function adjustHostJbbs($in_str)
  766. {
  767. return preg_replace('<(^|/)jbbs\\.(?:shitaraba|livedoor)\\.com(/|$)>', '\\1jbbs.livedoor.jp\\2', $in_str, 1);
  768. //return preg_replace('<(^|/)jbbs\\.(?:shitaraba\\.com|livedoor\\.(?:com|jp))(/|$)>', '\\1rentalbbs.livedoor.com\\2', $in_str, 1);
  769. }
  770. // }}}
  771. // {{{ header_nocache()
  772. /**
  773. * http header no cache を出力
  774. *
  775. * @return void
  776. */
  777. static public function header_nocache()
  778. {
  779. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // 日付が過去
  780. header("Last-Modified: " . http_date()); // 常に修正されている
  781. header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
  782. header("Cache-Control: post-check=0, pre-check=0", false);
  783. header("Pragma: no-cache"); // HTTP/1.0
  784. }
  785. // }}}
  786. // {{{ header_content_type()
  787. /**
  788. * HTTP header Content-Type 出力
  789. *
  790. * @param string $content_type
  791. * @return void
  792. */
  793. static public function header_content_type($content_type = null)
  794. {
  795. if ($content_type) {
  796. if (strpos($content_type, 'Content-Type: ') === 0) {
  797. header($content_type);
  798. } else {
  799. header('Content-Type: ' . $content_type);
  800. }
  801. } else {
  802. header('Content-Type: text/html; charset=Shift_JIS');
  803. }
  804. }
  805. // }}}
  806. // {{{ transResHistLogPhpToDat()
  807. /**
  808. * データPHP形式(TAB)の書き込み履歴をdat形式(TAB)に変換する
  809. *
  810. * 最初は、dat形式(<>)だったのが、データPHP形式(TAB)になり、そしてまた v1.6.0 でdat形式(<>)に戻った
  811. */
  812. static public function transResHistLogPhpToDat()
  813. {
  814. global $_conf;
  815. // 書き込み履歴を記録しない設定の場合は何もしない
  816. if ($_conf['res_write_rec'] == 0) {
  817. return true;
  818. }
  819. // p2_res_hist.dat.php が読み込み可能であったら
  820. if (is_readable($_conf['res_hist_dat_php'])) {
  821. // 読み込んで
  822. if ($cont = DataPhp::getDataPhpCont($_conf['res_hist_dat_php'])) {
  823. // タブ区切りから<>区切りに変更する
  824. $cont = str_replace("\t", "<>", $cont);
  825. // p2_res_hist.dat があれば、名前を変えてバックアップ。(もう要らない)
  826. if (file_exists($_conf['res_hist_dat'])) {
  827. $bak_file = $_conf['res_hist_dat'] . '.bak';
  828. if (P2_OS_WINDOWS && file_exists($bak_file)) {
  829. unlink($bak_file);
  830. }
  831. rename($_conf['res_hist_dat'], $bak_file);
  832. }
  833. // 保存
  834. FileCtl::make_datafile($_conf['res_hist_dat'], $_conf['res_write_perm']);
  835. FileCtl::file_write_contents($_conf['res_hist_dat'], $cont);
  836. // p2_res_hist.dat.php を名前を変えてバックアップ。(もう要らない)
  837. $bak_file = $_conf['res_hist_dat_php'] . '.bak';
  838. if (P2_OS_WINDOWS && file_exists($bak_file)) {
  839. unlink($bak_file);
  840. }
  841. rename($_conf['res_hist_dat_php'], $bak_file);
  842. }
  843. }
  844. return true;
  845. }
  846. // }}}
  847. // {{{ transResHistLogDatToPhp()
  848. /**
  849. * dat形式(<>)の書き込み履歴をデータPHP形式(TAB)に変換する
  850. */
  851. static public function transResHistLogDatToPhp()
  852. {
  853. global $_conf;
  854. // 書き込み履歴を記録しない設定の場合は何もしない
  855. if ($_conf['res_write_rec'] == 0) {
  856. return true;
  857. }
  858. // p2_res_hist.dat.php がなくて、p2_res_hist.dat が読み込み可能であったら
  859. if ((!file_exists($_conf['res_hist_dat_php'])) and is_readable($_conf['res_hist_dat'])) {
  860. // 読み込んで
  861. if ($cont = FileCtl::file_read_contents($_conf['res_hist_dat'])) {
  862. // <>区切りからタブ区切りに変更する
  863. // まずタブを全て外して
  864. $cont = str_replace("\t", "", $cont);
  865. // <>をタブに変換して
  866. $cont = str_replace("<>", "\t", $cont);
  867. // データPHP形式で保存
  868. DataPhp::writeDataPhp($_conf['res_hist_dat_php'], $cont, $_conf['res_write_perm']);
  869. }
  870. }
  871. return true;
  872. }
  873. // }}}
  874. // {{{ getLastAccessLog()
  875. /**
  876. * 前回のアクセス情報を取得
  877. */
  878. static public function getLastAccessLog($logfile)
  879. {
  880. // 読み込んで
  881. if (!$lines = DataPhp::fileDataPhp($logfile)) {
  882. return false;
  883. }
  884. if (!isset($lines[1])) {
  885. return false;
  886. }
  887. $line = rtrim($lines[1]);
  888. $lar = explode("\t", $line);
  889. $alog['user'] = $lar[6];
  890. $alog['date'] = $lar[0];
  891. $alog['ip'] = $lar[1];
  892. $alog['host'] = $lar[2];
  893. $alog['ua'] = $lar[3];
  894. $alog['referer'] = $lar[4];
  895. return $alog;
  896. }
  897. // }}}
  898. // {{{ recAccessLog()
  899. /**
  900. * アクセス情報をログに記録する
  901. */
  902. static public function recAccessLog($logfile, $maxline = 100, $format = 'dataphp')
  903. {
  904. global $_conf, $_login;
  905. // ログファイルの中身を取得する
  906. if ($format == 'dataphp') {
  907. $lines = DataPhp::fileDataPhp($logfile);
  908. } else {
  909. $lines = FileCtl::file_read_lines($logfile);
  910. }
  911. if ($lines) {
  912. // 制限行調整
  913. while (sizeof($lines) > $maxline -1) {
  914. array_pop($lines);
  915. }
  916. } else {
  917. $lines = array();
  918. }
  919. $lines = array_map('rtrim', $lines);
  920. // 変数設定
  921. $date = date('Y/m/d (D) G:i:s');
  922. // IPアドレスを取得
  923. if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
  924. $remote_addr = $_SERVER['REMOTE_ADDR'];
  925. } else {
  926. $remote_addr = '';
  927. }
  928. // HOSTを取得
  929. if (array_key_exists('REMOTE_HOST', $_SERVER)) {
  930. $remote_host = $_SERVER['REMOTE_HOST'];
  931. } else {
  932. $remote_host = '';
  933. }
  934. if (!$remote_host) {
  935. $remote_host = gethostbyaddr($_SERVER['REMOTE_ADDR']);
  936. }
  937. if ($remote_host == $_SERVER['REMOTE_ADDR']) {
  938. $remote_host = '';
  939. }
  940. // UAを取得
  941. if (array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
  942. $user_agent = $_SERVER['HTTP_USER_AGENT'];
  943. } else {
  944. $user_agent = '';
  945. }
  946. // リファラを取得
  947. if (array_key_exists('HTTP_REFERER', $_SERVER)) {
  948. $referrer = $_SERVER['HTTP_REFERER'];
  949. } else {
  950. $referrer = '';
  951. }
  952. $user = (isset($_login->user_u)) ? $_login->user_u : '';
  953. // 新しいログ行を設定
  954. $newdata = implode('<>', array($date, $remote_addr, $remote_host, $user_agent, $referrer, '', $user));
  955. //$newdata = htmlspecialchars($newdata, ENT_QUOTES);
  956. // まずタブを全て外して
  957. $newdata = str_replace("\t", "", $newdata);
  958. // <>をタブに変換して
  959. $newdata = str_replace("<>", "\t", $newdata);
  960. // 新しいデータを一番上に追加
  961. @array_unshift($lines, $newdata);
  962. $cont = implode("\n", $lines) . "\n";
  963. FileCtl::make_datafile($logfile, $_conf['p2_perm']);
  964. // 書き込み処理
  965. if ($format == 'dataphp') {
  966. DataPhp::writeDataPhp($logfile, $cont, $_conf['p2_perm']);
  967. } else {
  968. FileCtl::file_write_contents($logfile, $cont);
  969. }
  970. return true;
  971. }
  972. // }}}
  973. // {{{ isBrowserSafariGroup()
  974. /**
  975. * ブラウザがSafari系ならtrueを返す
  976. */
  977. static public function isBrowserSafariGroup()
  978. {
  979. return UA::isSafariGroup();
  980. }
  981. // }}}
  982. // {{{ isClientOSWindowsCE()
  983. /**
  984. * ブラウザがWindows CEで動作するものならtrueを返す
  985. */
  986. static public function isClientOSWindowsCE()
  987. {
  988. return (strpos($_SERVER['HTTP_USER_AGENT'], 'Windows CE') !== false);
  989. }
  990. // }}}
  991. // {{{ isBrowserNintendoDS()
  992. /**
  993. * ニンテンドーDSブラウザーならtrueを返す
  994. */
  995. static public function isBrowserNintendoDS()
  996. {
  997. return UA::isNintendoDS();
  998. }
  999. // }}}
  1000. // {{{ isBrowserPSP()
  1001. /**
  1002. * ブラウザがPSPならtrueを返す
  1003. */
  1004. static public function isBrowserPSP()
  1005. {
  1006. return UA::isPSP();
  1007. }
  1008. // }}}
  1009. // {{{ isBrowserIphone()
  1010. /**
  1011. * ブラウザがiPhone, iPod Touch or Androidならtrueを返す
  1012. */
  1013. static public function isBrowserIphone()
  1014. {
  1015. return UA::isIPhoneGroup();
  1016. }
  1017. // }}}
  1018. // {{{ isUrlWikipediaJa()
  1019. /**
  1020. * URLがウィキペディア日本語版の記事ならtrueを返す
  1021. */
  1022. static public function isUrlWikipediaJa($url)
  1023. {
  1024. return (strncmp($url, 'http://ja.wikipedia.org/wiki/', 29) == 0);
  1025. }
  1026. // }}}
  1027. // {{{ saveIdPw2ch()
  1028. /**
  1029. * 2ch●ログインのIDとPASSと自動ログイン設定を保存する
  1030. */
  1031. static public function saveIdPw2ch($login2chID, $login2chPW, $autoLogin2ch = '')
  1032. {
  1033. global $_conf;
  1034. $md5_crypt_key = self::getAngoKey();
  1035. $crypted_login2chPW = MD5Crypt::encrypt($login2chPW, $md5_crypt_key, 32);
  1036. $idpw2ch_cont = <<<EOP
  1037. <?php
  1038. \$rec_login2chID = '{$login2chID}';
  1039. \$rec_login2chPW = '{$crypted_login2chPW}';
  1040. \$rec_autoLogin2ch = '{$autoLogin2ch}';
  1041. ?>
  1042. EOP;
  1043. FileCtl::make_datafile($_conf['idpw2ch_php'], $_conf['pass_perm']); // ファイルがなければ生成
  1044. $fp = @fopen($_conf['idpw2ch_php'], 'wb');
  1045. if (!$fp) {
  1046. p2die("{$_conf['idpw2ch_php']} を更新できませんでした");
  1047. }
  1048. flock($fp, LOCK_EX);
  1049. fputs($fp, $idpw2ch_cont);
  1050. flock($fp, LOCK_UN);
  1051. fclose($fp);
  1052. return true;
  1053. }
  1054. // }}}
  1055. // {{{ readIdPw2ch()
  1056. /**
  1057. * 2ch●ログインの保存済みIDとPASSと自動ログイン設定を読み込む
  1058. */
  1059. static public function readIdPw2ch()
  1060. {
  1061. global $_conf;
  1062. if (!file_exists($_conf['idpw2ch_php'])) {
  1063. return false;
  1064. }
  1065. $rec_login2chID = NULL;
  1066. $login2chPW = NULL;
  1067. $rec_autoLogin2ch = NULL;
  1068. include $_conf['idpw2ch_php'];
  1069. // パスを複合化
  1070. if (!is_null($rec_login2chPW)) {
  1071. $md5_crypt_key = self::getAngoKey();
  1072. $login2chPW = MD5Crypt::decrypt($rec_login2chPW, $md5_crypt_key, 32);
  1073. }
  1074. return array($rec_login2chID, $login2chPW, $rec_autoLogin2ch);
  1075. }
  1076. // }}}
  1077. // {{{ getAngoKey()
  1078. /**
  1079. * getAngoKey
  1080. */
  1081. static public function getAngoKey()
  1082. {
  1083. global $_login;
  1084. return $_login->user_u . $_SERVER['SERVER_NAME'] . $_SERVER['SERVER_SOFTWARE'];
  1085. }
  1086. // }}}
  1087. // {{{ getCsrfId()
  1088. /**
  1089. * getCsrfId
  1090. */
  1091. static public function getCsrfId($salt = '')
  1092. {
  1093. global $_login;
  1094. $key = $_login->user_u . $_login->pass_x . $_SERVER['HTTP_USER_AGENT'] . $salt;
  1095. if (array_key_exists('login_microtime', $_SESSION)) {
  1096. $key .= $_SESSION['login_microtime'];
  1097. }
  1098. return UrlSafeBase64::encode(sha1($key, true));
  1099. }
  1100. // }}}
  1101. // {{{ print403()
  1102. /**
  1103. * 403 Fobbidenを出力する
  1104. */
  1105. static public function print403($msg = '')
  1106. {
  1107. header('HTTP/1.0 403 Forbidden');
  1108. echo <<<ERR
  1109. <html>
  1110. <head>
  1111. <meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
  1112. <meta name="ROBOTS" content="NOINDEX, NOFOLLOW">
  1113. <title>403 Forbidden</title>
  1114. </head>
  1115. <body>
  1116. <h1>403 Forbidden</h1>
  1117. <p>{$msg}</p>
  1118. </body>
  1119. </html>
  1120. ERR;
  1121. // IEデフォルトのメッセージを表示させないようにスペースを出力
  1122. if (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
  1123. for ($i = 0 ; $i < 512; $i++) {
  1124. echo ' ';
  1125. }
  1126. }
  1127. exit;
  1128. }
  1129. // }}}
  1130. // {{{ scandir_r()
  1131. /**
  1132. * 再帰的にディレクトリを走査する
  1133. *
  1134. * リストをファイルとディレクトリに分けて返す。それそれのリストは単純な配列
  1135. */
  1136. static public function scandir_r($dir)
  1137. {
  1138. $dir = realpath($dir);
  1139. $list = array('files' => array(), 'dirs' => array());
  1140. $files = scandir($dir);
  1141. foreach ($files as $filename) {
  1142. if ($filename == '.' || $filename == '..') {
  1143. continue;
  1144. }
  1145. $filename = $dir . DIRECTORY_SEPARATOR . $filename;
  1146. if (is_dir($filename)) {
  1147. $child = self::scandir_r($filename);
  1148. if ($child) {
  1149. $list['dirs'] = array_merge($list['dirs'], $child['dirs']);
  1150. $list['files'] = array_merge($list['files'], $child['files']);
  1151. }
  1152. $list['dirs'][] = $filename;
  1153. } else {
  1154. $list['files'][] = $filename;
  1155. }
  1156. }
  1157. return $list;
  1158. }
  1159. // }}}
  1160. // {{{ garbageCollection()
  1161. /**
  1162. * いわゆるひとつのガベコレ
  1163. *
  1164. * $targetDirから最終更新より$lifeTime秒以上たったファイルを削除
  1165. *
  1166. * @param string $targetDir ガーベッジコレクション対象ディレクトリ
  1167. * @param integer $lifeTime ファイルの有効期限(秒)
  1168. * @param string $prefix 対象ファイル名の接頭辞(オプション)
  1169. * @param string $suffix 対象ファイル名の接尾辞(オプション)
  1170. * @param boolean $recurive 再帰的にガーベッジコレクションするか否か(デフォルトではFALSE)
  1171. * @return array 削除に成功したファイルと失敗したファイルを別々に記録した二次元の配列
  1172. */
  1173. static public function garbageCollection($targetDir,
  1174. $lifeTime,
  1175. $prefix = '',
  1176. $suffix = '',
  1177. $recursive = false
  1178. )
  1179. {
  1180. $result = array('successed' => array(), 'failed' => array(), 'skipped' => array());
  1181. $expire = time() - $lifeTime;
  1182. //ファイルリスト取得
  1183. if ($recursive) {
  1184. $list = self::scandir_r($targetDir);
  1185. $files = $list['files'];
  1186. } else {
  1187. $list = scandir($targetDir);
  1188. $files = array();
  1189. $targetDir = realpath($targetDir) . DIRECTORY_SEPARATOR;
  1190. foreach ($list as $filename) {
  1191. if ($filename == '.' || $filename == '..') { continue; }
  1192. $files[] = $targetDir . $filename;
  1193. }
  1194. }
  1195. //検索パターン設定($prefixと$suffixにスラッシュを含まないように)
  1196. if ($prefix || $suffix) {
  1197. $prefix = (is_array($prefix)) ? implode('|', array_map('preg_quote', $prefix)) : preg_quote($prefix);
  1198. $suffix = (is_array($suffix)) ? implode('|', array_map('preg_quote', $suffix)) : preg_quote($suffix);
  1199. $pattern = '/^' . $prefix . '.+' . $suffix . '$/';
  1200. } else {
  1201. $pattern = '';
  1202. }
  1203. //ガベコレ開始
  1204. foreach ($files as $filename) {
  1205. if ($pattern && !preg_match($pattern, basename($filename))) {
  1206. //$result['skipped'][] = $filename;
  1207. continue;
  1208. }
  1209. if (filemtime($filename) < $expire) {
  1210. if (@unlink($filename)) {
  1211. $result['successed'][] = $filename;
  1212. } else {
  1213. $result['failed'][] = $filename;
  1214. }
  1215. }
  1216. }
  1217. return $result;
  1218. }
  1219. // }}}
  1220. // {{{ session_gc()
  1221. /**
  1222. * セッションファイルのガーベッジコレクション
  1223. *
  1224. * session.save_pathのパスの深さが2より大きい場合、ガーベッジコレクションは行われないため
  1225. * 自分でガーベッジコレクションしないといけない。
  1226. *
  1227. * @return void
  1228. *
  1229. * @link http://jp.php.net/manual/ja/ref.session.php#ini.session.save-path
  1230. */
  1231. static public function session_gc()
  1232. {
  1233. global $_conf;
  1234. if (session_module_name() != 'files') {
  1235. return;
  1236. }
  1237. $d = (int)ini_get('session.gc_divisor');
  1238. $p = (int)ini_get('session.gc_probability');
  1239. mt_srand();
  1240. if (mt_rand(1, $d) <= $p) {
  1241. $m = (int)ini_get('session.gc_maxlifetime');
  1242. self::garbageCollection($_conf['session_dir'], $m);
  1243. }
  1244. }
  1245. // }}}
  1246. // {{{ Info_Dump()
  1247. /**
  1248. * 多次元配列を再帰的にテーブルに変換する
  1249. *
  1250. * 2ちゃんねるのsetting.txtをパースした配列用の条件分岐あり
  1251. * 普通にダンプするなら Var_Dump::display($value, TRUE) がお勧め
  1252. * (バージョン1.0.0以降、Var_Dump::display() の第二引数が真のとき
  1253. * 直接表示する代わりに、ダンプ結果が文字列として返る。)
  1254. *
  1255. * @param array $info テーブルにしたい配列
  1256. * @param integer $indent 結果のHTMLを見やすくするためのインデント量
  1257. * @return string <table>~</table>
  1258. */
  1259. static public function Info_Dump($info, $indent = 0)
  1260. {
  1261. $table = '<table border="0" cellspacing="1" cellpadding="0">' . "\n";
  1262. $n = count($info);
  1263. foreach ($info as $key => $value) {
  1264. if (!is_object($value) && !is_resource($value)) {
  1265. for ($i = 0; $i < $indent; $i++) { $table .= "\t"; }
  1266. if ($n == 1 && $key === 0) {
  1267. $table .= '<tr><td class="tdcont">';
  1268. /*} elseif (preg_match('/^\w+$/', $key)) {
  1269. $table .= '<tr class="setting"><td class="tdleft"><b>' . $key . '</b></td><td class="tdcont">';*/
  1270. } else {
  1271. $table .= '<tr><td class="tdleft"><b>' . $key . '</b></td><td class="tdcont">';
  1272. }
  1273. if (is_array($value)) {
  1274. $table .= self::Info_Dump($value, $indent+1); //配列の場合は再帰呼び出しで展開
  1275. } elseif ($value === true) {
  1276. $table .= '<i>TRUE</i>';
  1277. } elseif ($value === false) {
  1278. $table .= '<i>FALSE</i>';
  1279. } elseif (is_null($value)) {
  1280. $table .= '<i>NULL</i>';
  1281. } elseif (is_scalar($value)) {
  1282. if ($value === '') { //例外:空文字列。0を含めないように型を考慮して比較
  1283. $table .= '<i>(no value)</i>';
  1284. } elseif ($key == 'ログ取得済<br>スレッド数') { //ログ削除専用
  1285. $table .= $value;
  1286. } elseif ($key == 'ローカルルール') { //ローカルルール専用
  1287. $table .= '<table border="0" cellspacing="1" cellpadding="0" class="child">';
  1288. $table .= "\n\t\t<tr><td id=\"rule\">{$value}</tr></td>\n\t</table>";
  1289. } elseif (preg_match('/^(https?|ftp):\/\/[\w\/\.\+\-\?=~@#%&:;]+$/i', $value)) { //リンク
  1290. $table .= '<a href="' . self::throughIme($value) . '" target="_blank">' . $value . '</a>';
  1291. } elseif ($key == '背景色' || substr($key, -6) == '_COLOR') { //カラーサンプル
  1292. $table .= "<span class=\"colorset\" style=\"color:{$value};\">■</span>({$value})";
  1293. } else {
  1294. $table .= htmlspecialchars($value, ENT_QUOTES);
  1295. }
  1296. }
  1297. $table .= '</td></tr>' . "\n";
  1298. }
  1299. }
  1300. for ($i = 1; $i < $indent; $i++) { $table .= "\t"; }
  1301. $table .= '</table>';
  1302. $table = str_replace('<td class="tdcont"><table border="0" cellspacing="1" cellpadding="0">',
  1303. '<td class="tdcont"><table border="0" cellspacing="1" cellpadding="0" class="child">', $table);
  1304. return $table;
  1305. }
  1306. // }}}
  1307. // {{{ re_htmlspecialchars()
  1308. /**
  1309. * ["&<>]が実体参照になっているかどうか不明な文字列に対してhtmlspecialchars()をかける
  1310. */
  1311. static public function re_htmlspecialchars($str, $charset = 'Shift_JIS')
  1312. {
  1313. return htmlspecialchars($str, ENT_QUOTES, $charset, false);
  1314. }
  1315. // }}}
  1316. // {{{ mkTrip()
  1317. /**
  1318. * トリップを生成する
  1319. */
  1320. static public function mkTrip($key)
  1321. {
  1322. if (strlen($key) < 12) {
  1323. //if (strlen($key) > 8) {
  1324. // return self::mkTrip1(substr($key, 0, 8));
  1325. //} else {
  1326. return self::mkTrip1($key);
  1327. //}
  1328. }
  1329. switch (substr($key, 0, 1)) {
  1330. case '$';
  1331. return '???';
  1332. case '#':
  1333. if (preg_match('|^#([0-9A-Fa-f]{16})([./0-9A-Za-z]{0,2})$|', $key, $matches)) {
  1334. return self::mkTrip1(pack('H*', $matches[1]), $matches[2]);
  1335. } else {
  1336. return '???';
  1337. }
  1338. default:
  1339. return self::mkTrip2($key);
  1340. }
  1341. }
  1342. // }}}
  1343. // {{{ mkTrip1()
  1344. /**
  1345. * 旧方式トリップを生成する
  1346. */
  1347. static public function mkTrip1($key, $length = 10, $salt = null)
  1348. {
  1349. if (is_null($salt)) {
  1350. $salt = substr($key . 'H.', 1, 2);
  1351. } else {
  1352. $salt = substr($salt . '..', 0, 2);
  1353. }
  1354. $salt = preg_replace('/[^.-z]/', '.', $salt);
  1355. $salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
  1356. return substr(crypt($key, $salt), -$length);
  1357. }
  1358. // }}}
  1359. // {{{ mkTrip2()
  1360. /**
  1361. * 新方式トリップを生成する
  1362. */
  1363. static public function mkTrip2($key)
  1364. {
  1365. return str_replace('+', '.', substr(base64_encode(sha1($key, true)), 0, 12));
  1366. }
  1367. // }}}
  1368. // {{{ getWebPage
  1369. /**
  1370. * Webページを取得する
  1371. *
  1372. * 200 OK
  1373. * 206 Partial Content
  1374. * 304 Not Modified → 失敗扱い
  1375. *
  1376. * @return array|false 成功したらページ内容を返す。失敗したらfalseを返す。
  1377. */
  1378. static public function getWebPage($url, &$error_msg, $timeout = 15)
  1379. {
  1380. if (!class_exists('HTTP_Request', false)) {
  1381. require 'HTTP/Request.php';
  1382. }
  1383. $params = array("timeout" => $timeout);
  1384. if (!empty($_conf['proxy_use'])) {
  1385. $params['proxy_host'] = $_conf['proxy_host'];
  1386. $params['proxy_port'] = $_conf['proxy_port'];
  1387. }
  1388. $req = new HTTP_Request($url, $params);
  1389. //$req->addHeader("X-PHP-Version", phpversion());
  1390. $response = $req->sendRequest();
  1391. if (PEAR::isError($response)) {
  1392. $error_msg = $response->getMessage();
  1393. } else {
  1394. $code = $req->getResponseCode();
  1395. if ($code == 200 || $code == 206) { // || $code == 304) {
  1396. return $req->getResponseBody();
  1397. } else {
  1398. //var_dump($req->getResponseHeader());
  1399. $error_msg = $code;
  1400. }
  1401. }
  1402. return false;
  1403. }
  1404. // }}}
  1405. // {{{ getMyUrl()
  1406. /**
  1407. * 現在のURLを取得する(GETクエリーはなし)
  1408. *
  1409. * @return string
  1410. * @see http://ns1.php.gr.jp/pipermail/php-users/2003-June/016472.html
  1411. */
  1412. static public function getMyUrl()
  1413. {
  1414. $s = empty($_SERVER['HTTPS']) ? '' : 's';
  1415. $url = "http{$s}://" . $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];
  1416. // もしくは
  1417. //$port = ($_SERVER['SERVER_PORT'] == ($s ? 443 : 80)) ? '' : ':' . $_SERVER['SERVER_PORT'];
  1418. //$url = "http{$s}://" . $_SERVER['SERVER_NAME'] . $port . $_SERVER['SCRIPT_NAME'];
  1419. return $url;
  1420. }
  1421. // }}}
  1422. // {{{ printSimpleHtml()
  1423. /**
  1424. * シンプルにHTMLを表示する
  1425. *
  1426. * @return void
  1427. */
  1428. static public function printSimpleHtml($body)
  1429. {
  1430. echo "<html><body>{$body}</body></html>";
  1431. }
  1432. // }}}
  1433. // {{{ pushInfoHtml()
  1434. /**
  1435. * 2006/11/24 $_info_msg_ht を直接扱うのはやめてこのメソッドを通す方向で
  1436. *
  1437. * @return void
  1438. */
  1439. static public function pushInfoHtml($html)
  1440. {
  1441. global $_info_msg_ht;
  1442. // 表示フォーマットを統一する試み
  1443. $html = preg_replace('!^<p>!', '<p class="info-msg">', $html);
  1444. $html = preg_replace('!\\b(?:re)?p2(?: | )+(error|info)(?: *[:\\-] *)!', 'rep2 $1: ', $html);
  1445. if (!isset($_info_msg_ht)) {
  1446. $_info_msg_ht = $html;
  1447. } else {
  1448. $_info_msg_ht .= $html;
  1449. }
  1450. }
  1451. // }}}
  1452. // {{{ printInfoHtml()
  1453. /**
  1454. * @return void
  1455. */
  1456. static public function printInfoHtml()
  1457. {
  1458. global $_info_msg_ht, $_conf;
  1459. if (!isset($_info_msg_ht)) {
  1460. return;
  1461. }
  1462. if ($_conf['ktai'] && $_conf['mobile.save_packet']) {
  1463. echo mb_convert_kana($_info_msg_ht, 'rnsk');
  1464. } else {
  1465. echo $_info_msg_ht;
  1466. }
  1467. $_info_msg_ht = '';
  1468. }
  1469. // }}}
  1470. // {{{ getInfoHtml()
  1471. /**
  1472. * @return string|null
  1473. */
  1474. static public function getInfoHtml()
  1475. {
  1476. global $_info_msg_ht窶ヲ

Large files files are truncated, but you can click here to view the full file