PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/class/Util.php

http://github.com/ethna/ethna
PHP | 865 lines | 766 code | 22 blank | 77 comment | 35 complexity | 15cc02722577c20a731aba3764e2c0d1 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4. * Util.php
  5. *
  6. * @author Masaki Fujimoto <fujimoto@php.net>
  7. * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
  8. * @package Ethna
  9. * @version $Id: dadbf5387e7343b38756852834579d07ce3998fa $
  10. */
  11. // {{{ Ethna_Util
  12. /**
  13. * ユーティリティクラス
  14. *
  15. * @author Masaki Fujimoto <fujimoto@php.net>
  16. * @access public
  17. * @package Ethna
  18. */
  19. class Ethna_Util
  20. {
  21. // {{{ isDuplicatePost
  22. /**
  23. * POSTのユニークチェックを行う
  24. *
  25. * @access public
  26. * @return bool true:2回目以降のPOST false:1回目のPOST
  27. */
  28. public static function isDuplicatePost()
  29. {
  30. $c = Ethna_Controller::getInstance();
  31. // use raw post data
  32. if (isset($_POST['uniqid'])) {
  33. $uniqid = $_POST['uniqid'];
  34. } else if (isset($_GET['uniqid'])) {
  35. $uniqid = $_GET['uniqid'];
  36. } else {
  37. return false;
  38. }
  39. // purge old files
  40. Ethna_Util::purgeTmp("uniqid_", 60*60*1);
  41. $filename = sprintf("%s/uniqid_%s_%s",
  42. $c->getDirectory('tmp'),
  43. $_SERVER['REMOTE_ADDR'],
  44. $uniqid);
  45. if (file_exists($filename) == false) {
  46. touch($filename);
  47. return false;
  48. }
  49. $st = stat($filename);
  50. if ($st[9] + 60*60*1 < time()) {
  51. // too old
  52. return false;
  53. }
  54. return true;
  55. }
  56. // }}}
  57. // {{{ clearDuplicatePost
  58. /**
  59. * POSTのユニークチェックフラグをクリアする
  60. *
  61. * @acccess public
  62. * @return mixed 0:正常終了 Ethna_Error:エラー
  63. */
  64. public static function clearDuplicatePost()
  65. {
  66. $c = Ethna_Controller::getInstance();
  67. // use raw post data
  68. if (isset($_POST['uniqid'])) {
  69. $uniqid = $_POST['uniqid'];
  70. } else {
  71. return 0;
  72. }
  73. $filename = sprintf("%s/uniqid_%s_%s",
  74. $c->getDirectory('tmp'),
  75. $_SERVER['REMOTE_ADDR'],
  76. $uniqid);
  77. if (file_exists($filename)) {
  78. if (unlink($filename) == false) {
  79. return Ethna::raiseWarning("File Write Error [%s]", E_APP_WRITE, $filename);
  80. }
  81. }
  82. return 0;
  83. }
  84. // }}}
  85. // {{{ isCsrfSafeValid
  86. /**
  87. * CSRFをチェックする
  88. *
  89. * @access public
  90. * @return bool true:正常なPOST false:不正なPOST
  91. */
  92. public static function isCsrfSafe()
  93. {
  94. $c = Ethna_Controller::getInstance();
  95. $name = $c->getConfig()->get('csrf');
  96. if (is_null($name)) {
  97. $name = 'Session';
  98. }
  99. $plugin = $c->getPlugin('Csrf', $name);
  100. $csrf = $plugin->getPlugin('Csrf', $name);
  101. return $csrf->isValid();
  102. }
  103. // }}}
  104. // {{{ setCsrfID
  105. /**
  106. * CSRFをチェックする
  107. *
  108. * @access public
  109. * @return bool true:成功
  110. */
  111. public static function setCsrfID()
  112. {
  113. $c = Ethna_Controller::getInstance();
  114. $name = $c->getConfig()->get('csrf');
  115. if (is_null($name)) {
  116. $name = 'Session';
  117. }
  118. $plugin = $c->getPlugin('Csrf', $name);
  119. $csrf = $plugin->getPlugin('Csrf', $name);
  120. return $csrf->set();
  121. }
  122. // }}}
  123. // {{{ checkMailAddress
  124. /**
  125. * メールアドレスが正しいかどうかをチェックする
  126. *
  127. * @access public
  128. * @param string $mailaddress チェックするメールアドレス
  129. * @return bool true: 正しいメールアドレス false: 不正な形式
  130. */
  131. public static function checkMailAddress($mailaddress)
  132. {
  133. if (preg_match('#^([a-z0-9_]|\-|\.|\+|\/)+@(([a-z0-9_]|\-)+\.)+[a-z]{2,6}$#i',
  134. $mailaddress)) {
  135. return true;
  136. }
  137. return false;
  138. }
  139. // }}}
  140. // {{{ explodeCSV
  141. /**
  142. * CSV形式の文字列を配列に分割する
  143. *
  144. * @access public
  145. * @param string $csv CSV形式の文字列(1行分)
  146. * @param string $delimiter フィールドの区切り文字
  147. * @return mixed (array):分割結果 Ethna_Error:エラー(行継続)
  148. */
  149. public static function explodeCSV($csv, $delimiter = ",")
  150. {
  151. $space_list = '';
  152. foreach (array(" ", "\t", "\r", "\n") as $c) {
  153. if ($c != $delimiter) {
  154. $space_list .= $c;
  155. }
  156. }
  157. $line_end = "";
  158. if (preg_match("/([$space_list]+)\$/sS", $csv, $match)) {
  159. $line_end = $match[1];
  160. }
  161. $csv = substr($csv, 0, strlen($csv)-strlen($line_end));
  162. $csv .= ' ';
  163. $field = '';
  164. $retval = array();
  165. $index = 0;
  166. $csv_len = strlen($csv);
  167. do {
  168. // 1. skip leading spaces
  169. if (preg_match("/^([$space_list]+)/sS", substr($csv, $index), $match)) {
  170. $index += strlen($match[1]);
  171. }
  172. if ($index >= $csv_len) {
  173. break;
  174. }
  175. // 2. read field
  176. if ($csv{$index} == '"') {
  177. // 2A. handle quote delimited field
  178. $index++;
  179. while ($index < $csv_len) {
  180. if ($csv{$index} == '"') {
  181. // handle double quote
  182. if ($csv{$index+1} == '"') {
  183. $field .= $csv{$index};
  184. $index += 2;
  185. } else {
  186. // must be end of string
  187. while ($csv{$index} != $delimiter && $index < $csv_len) {
  188. $index++;
  189. }
  190. if ($csv{$index} == $delimiter) {
  191. $index++;
  192. }
  193. break;
  194. }
  195. } else {
  196. // normal character
  197. if (preg_match("/^([^\"]*)/S", substr($csv, $index), $match)) {
  198. $field .= $match[1];
  199. $index += strlen($match[1]);
  200. }
  201. if ($index == $csv_len) {
  202. $field = substr($field, 0, strlen($field)-1);
  203. $field .= $line_end;
  204. // request one more line
  205. return Ethna::raiseNotice('CSV Split Error (line continue)', E_UTIL_CSV_CONTINUE);
  206. }
  207. }
  208. }
  209. } else {
  210. // 2B. handle non-quoted field
  211. if (preg_match("/^([^$delimiter]*)/S", substr($csv, $index), $match)) {
  212. $field .= $match[1];
  213. $index += strlen($match[1]);
  214. }
  215. // remove trailing spaces
  216. $field = preg_replace("/[$space_list]+\$/S", '', $field);
  217. if ($csv{$index} == $delimiter) {
  218. $index++;
  219. }
  220. }
  221. $retval[] = $field;
  222. $field = '';
  223. } while ($index < $csv_len);
  224. return $retval;
  225. }
  226. // }}}
  227. // {{{ escapeCSV
  228. /**
  229. * CSVエスケープ処理を行う
  230. *
  231. * @access public
  232. * @param string $csv エスケープ対象の文字列(CSVの各要素)
  233. * @param bool $escape_nl 改行文字(\r/\n)のエスケープフラグ
  234. * @return string CSVエスケープされた文字列
  235. */
  236. public static function escapeCSV($csv, $escape_nl = false)
  237. {
  238. if (preg_match('/[,"\r\n]/', $csv)) {
  239. if ($escape_nl) {
  240. $csv = preg_replace('/\r/', "\\r", $csv);
  241. $csv = preg_replace('/\n/', "\\n", $csv);
  242. }
  243. $csv = preg_replace('/"/', "\"\"", $csv);
  244. $csv = "\"$csv\"";
  245. }
  246. return $csv;
  247. }
  248. // }}}
  249. // {{{ escapeHtml
  250. /**
  251. * 配列の要素を全てHTMLエスケープして返す
  252. *
  253. * @access public
  254. * @param array $target HTMLエスケープ対象となる配列
  255. * @param string $encoding
  256. * @return array エスケープされた配列
  257. */
  258. public static function escapeHtml($target, $encoding = "UTF-8")
  259. {
  260. $r = array();
  261. Ethna_Util::_escapeHtml($target, $r, $encoding);
  262. return $r;
  263. }
  264. /**
  265. * 配列の要素を全てHTMLエスケープして返す
  266. *
  267. * @access private
  268. * @param mixed $vars HTMLエスケープ対象となる配列
  269. * @param mixed $retval HTMLエスケープ対象となる子要素
  270. */
  271. private static function _escapeHtml(&$vars, &$retval, $encoding)
  272. {
  273. foreach (array_keys($vars) as $name) {
  274. if (is_array($vars[$name])) {
  275. $retval[$name] = array();
  276. Ethna_Util::_escapeHtml($vars[$name], $retval[$name], $encoding);
  277. } else if (!is_object($vars[$name])) {
  278. $retval[$name] = htmlspecialchars($vars[$name], ENT_QUOTES, $encoding);
  279. }
  280. }
  281. }
  282. // }}}
  283. // {{{ encode_MIME
  284. /**
  285. * 文字列をMIMEエンコードする
  286. *
  287. * @access public
  288. * @param string $string MIMEエンコードする文字列
  289. * @return エンコード済みの文字列
  290. */
  291. public static function encode_MIME($string)
  292. {
  293. $pos = 0;
  294. $split = 36;
  295. $_string = "";
  296. while ($pos < mb_strlen($string))
  297. {
  298. $tmp = mb_strimwidth($string, $pos, $split, "");
  299. $pos += mb_strlen($tmp);
  300. $_string .= (($_string)? ' ' : '') . mb_encode_mimeheader($tmp, 'ISO-2022-JP');
  301. }
  302. return $_string;
  303. }
  304. // }}}
  305. // {{{ getDirectLinkList
  306. /**
  307. * Google風リンクリストを返す
  308. *
  309. * @access public
  310. * @param int $total 検索総件数
  311. * @param int $offset 表示オフセット
  312. * @param int $count 表示件数
  313. * @return array リンク情報を格納した配列
  314. */
  315. public static function getDirectLinkList($total, $offset, $count)
  316. {
  317. $direct_link_list = array();
  318. if ($total == 0) {
  319. return array();
  320. }
  321. // backwards
  322. $current = $offset - $count;
  323. while ($current > 0) {
  324. array_unshift($direct_link_list, $current);
  325. $current -= $count;
  326. }
  327. if ($offset != 0 && $current <= 0) {
  328. array_unshift($direct_link_list, 0);
  329. }
  330. // current
  331. $backward_count = count($direct_link_list);
  332. array_push($direct_link_list, $offset);
  333. // forwards
  334. $current = $offset + $count;
  335. for ($i = 0; $i < 10; $i++) {
  336. if ($current >= $total) {
  337. break;
  338. }
  339. array_push($direct_link_list, $current);
  340. $current += $count;
  341. }
  342. $forward_count = count($direct_link_list) - $backward_count - 1;
  343. $backward_count -= 4;
  344. if ($forward_count < 5) {
  345. $backward_count -= 5 - $forward_count;
  346. }
  347. if ($backward_count < 0) {
  348. $backward_count = 0;
  349. }
  350. // add index
  351. $n = 1;
  352. $r = array();
  353. foreach ($direct_link_list as $direct_link) {
  354. $v = array('offset' => $direct_link, 'index' => $n);
  355. $r[] = $v;
  356. $n++;
  357. }
  358. return array_splice($r, $backward_count, 10);
  359. }
  360. // }}}
  361. // {{{ getEra
  362. /**
  363. * 元号制での年を返す
  364. *
  365. * @access public
  366. * @param int $t unix time
  367. * @return string 元号(不明な場合はnull)
  368. */
  369. public static function getEra($t)
  370. {
  371. $tm = localtime($t, true);
  372. $year = $tm['tm_year'] + 1900;
  373. if ($year >= 1989) {
  374. $heisei_str = _et('Heisei');
  375. return array($heisei_str, $year - 1988);
  376. } else if ($year >= 1926) {
  377. $showa_str = _et('Showa');
  378. return array($showa_str, $year - 1925);
  379. }
  380. return null;
  381. }
  382. // }}}
  383. // {{{ getImageExtName
  384. /**
  385. * getimagesize()の返すイメージタイプに対応する拡張子を返す
  386. *
  387. * @access public
  388. * @param int $type getimagesize()関数の返すイメージタイプ
  389. * @return string $typeに対応する拡張子
  390. */
  391. public static function getImageExtName($type)
  392. {
  393. $ext_list = array(
  394. 1 => 'gif',
  395. 2 => 'jpg',
  396. 3 => 'png',
  397. 4 => 'swf',
  398. 5 => 'psd',
  399. 6 => 'bmp',
  400. 7 => 'tiff',
  401. 8 => 'tiff',
  402. 9 => 'jpc',
  403. 10 => 'jp2',
  404. 11 => 'jpx',
  405. 12 => 'jb2',
  406. 13 => 'swc',
  407. 14 => 'iff',
  408. 15 => 'wbmp',
  409. 16 => 'xbm',
  410. );
  411. return @$ext_list[$type];
  412. }
  413. // }}}
  414. // {{{ getRandom
  415. /**
  416. * ランダムなハッシュ値を生成する
  417. *
  418. * 決して高速ではないので乱用は避けること
  419. *
  420. * @access public
  421. * @param int $length ハッシュ値の長さ(〜64)
  422. * @return string ハッシュ値
  423. */
  424. public static function getRandom($length = 64)
  425. {
  426. static $srand = false;
  427. if ($srand == false) {
  428. list($usec, $sec) = explode(' ', microtime());
  429. mt_srand((float) $sec + ((float) $usec * 100000) + getmypid());
  430. $srand = true;
  431. }
  432. // open_basedir がオンで、かつ /proc が許可されているか?
  433. // open_basedir が空なら許可されていると看做す
  434. $devfile = '/proc/net/dev';
  435. $open_basedir_conf = ini_get('open_basedir');
  436. $devfile_enabled = (empty($open_basedir_conf)
  437. || (preg_match('#:/proc#', $open_basedir_conf) > 0
  438. || preg_match('#^/proc#', $open_basedir_conf) > 0));
  439. $value = "";
  440. for ($i = 0; $i < 2; $i++) {
  441. // for Linux
  442. if ($devfile_enabled && file_exists($devfile)) {
  443. $rx = $tx = 0;
  444. $fp = fopen($devfile, 'r');
  445. if ($fp != null) {
  446. $header = true;
  447. while (feof($fp) === false) {
  448. $s = fgets($fp, 4096);
  449. if ($header) {
  450. $header = false;
  451. continue;
  452. }
  453. $v = preg_split('/[:\s]+/', $s);
  454. if (is_array($v) && count($v) > 10) {
  455. $rx += $v[2];
  456. $tx += $v[10];
  457. }
  458. }
  459. }
  460. $platform_value = $rx . $tx . mt_rand() . getmypid();
  461. } else {
  462. $platform_value = mt_rand() . getmypid();
  463. }
  464. $now = strftime('%Y%m%d %T');
  465. $time = gettimeofday();
  466. $v = $now . $time['usec'] . $platform_value . mt_rand(0, time());
  467. $value .= md5($v);
  468. }
  469. if ($length < 64) {
  470. $value = substr($value, 0, $length);
  471. }
  472. return $value;
  473. }
  474. // }}}
  475. // {{{ get2dArray
  476. /**
  477. * 1次元配列をm x nに再構成する
  478. *
  479. * @access public
  480. * @param array $array 処理対象の1次元配列
  481. * @param int $m 軸の要素数
  482. * @param int $order $mをX軸と見做すかY軸と見做すか(0:X軸 1:Y軸)
  483. * @return array m x nに再構成された配列
  484. */
  485. public static function get2dArray($array, $m, $order)
  486. {
  487. $r = array();
  488. $n = intval(count($array) / $m);
  489. if ((count($array) % $m) > 0) {
  490. $n++;
  491. }
  492. for ($i = 0; $i < $n; $i++) {
  493. $elts = array();
  494. for ($j = 0; $j < $m; $j++) {
  495. if ($order == 0) {
  496. // 横並び(横:$m列 縦:無制限)
  497. $key = $i*$m+$j;
  498. } else {
  499. // 縦並び(横:無制限 縦:$m行)
  500. $key = $i+$n*$j;
  501. }
  502. if (array_key_exists($key, $array) == false) {
  503. $array[$key] = null;
  504. }
  505. $elts[] = $array[$key];
  506. }
  507. $r[] = $elts;
  508. }
  509. return $r;
  510. }
  511. // }}}
  512. // {{{ isAbsolute
  513. /**
  514. * パス名が絶対パスかどうかを返す
  515. *
  516. * port from File in PEAR (for BC)
  517. *
  518. * @access public
  519. * @param string $path
  520. * @return bool true:絶対パス false:相対パス
  521. */
  522. public static function isAbsolute($path)
  523. {
  524. if (preg_match("/\.\./", $path)) {
  525. return false;
  526. }
  527. if (DIRECTORY_SEPARATOR == '/'
  528. && (substr($path, 0, 1) == '/' || substr($path, 0, 1) == '~')) {
  529. return true;
  530. } else if (DIRECTORY_SEPARATOR == '\\' && preg_match('/^[a-z]:\\\/i', $path)) {
  531. return true;
  532. }
  533. return false;
  534. }
  535. // }}}
  536. // {{{ isRootDir
  537. /**
  538. * パス名がルートディレクトリかどうかを返す
  539. *
  540. * @access public
  541. * @param string $path
  542. * @static
  543. */
  544. public static function isRootDir($path)
  545. {
  546. if ($path === DIRECTORY_SEPARATOR) {
  547. // avoid stat().
  548. return true;
  549. }
  550. if (is_dir($path) === false) {
  551. return false;
  552. }
  553. return $path === basename($path) . DIRECTORY_SEPARATOR;
  554. }
  555. // }}}
  556. // {{{ mkdir
  557. /**
  558. * mkdir -p
  559. *
  560. * @access public
  561. * @param string $dir 作成するディレクトリ
  562. * @param int $mode パーミッション
  563. * @return bool true:成功 false:失敗
  564. * @static
  565. */
  566. public static function mkdir($dir, $mode)
  567. {
  568. if (file_exists($dir)) {
  569. return is_dir($dir);
  570. }
  571. $parent = dirname($dir);
  572. if ($dir === $parent) {
  573. return true;
  574. }
  575. if (is_dir($parent) === false) {
  576. if (Ethna_Util::mkdir($parent, $mode) === false) {
  577. return false;
  578. }
  579. }
  580. return mkdir($dir, $mode) && Ethna_Util::chmod($dir, $mode);
  581. }
  582. // }}}
  583. // {{{ chmod
  584. /**
  585. * ファイルのパーミッションを変更する
  586. */
  587. public static function chmod($file, $mode)
  588. {
  589. $st = stat($file);
  590. if (($st[2] & 0777) == $mode) {
  591. return true;
  592. }
  593. return chmod($file, $mode);
  594. }
  595. // }}}
  596. // {{{ purgeDir
  597. /**
  598. * ディレクトリを再帰的に削除する
  599. * (途中で失敗しても中断せず、削除できるものはすべて消す)
  600. *
  601. * @access public
  602. * @param string $file 削除するファイルまたはディレクトリ
  603. * @return bool true:成功 false:失敗
  604. * @static
  605. */
  606. public static function purgeDir($dir)
  607. {
  608. if (file_exists($dir) === false) {
  609. return false;
  610. }
  611. if (is_dir($dir) === false) {
  612. return unlink($dir);
  613. }
  614. $dh = opendir($dir);
  615. if ($dh === false) {
  616. return false;
  617. }
  618. $ret = true;
  619. while (($entry = readdir($dh)) !== false) {
  620. if ($entry === '.' || $entry === '..') {
  621. continue;
  622. }
  623. $ret = $ret && Ethna_Util::purgeDir("{$dir}/{$entry}");
  624. }
  625. closedir($dh);
  626. if ($ret) {
  627. return rmdir($dir);
  628. } else {
  629. return false;
  630. }
  631. }
  632. // }}}
  633. // {{{ purgeTmp
  634. /**
  635. * テンポラリディレクトリのファイルを削除する
  636. *
  637. * @access public
  638. * @param string $prefix ファイルのプレフィクス
  639. * @param int $timeout 削除対象閾値(秒−60*60*1なら1時間)
  640. */
  641. public static function purgeTmp($prefix, $timeout)
  642. {
  643. $c = Ethna_Controller::getInstance();
  644. $dh = opendir($c->getDirectory('tmp'));
  645. if ($dh) {
  646. while (($file = readdir($dh)) !== false) {
  647. if ($file == '.' || $file == '..') {
  648. continue;
  649. } else if (is_dir($c->getDirectory('tmp') . '/' . $file)) {
  650. continue;
  651. } else if (strncmp($file, $prefix, strlen($prefix)) == 0) {
  652. $f = $c->getDirectory('tmp') . "/" . $file;
  653. $st = stat($f);
  654. if ($st[9] + $timeout < time()) {
  655. unlink($f);
  656. }
  657. }
  658. }
  659. closedir($dh);
  660. }
  661. }
  662. // }}}
  663. // {{{ lockFile
  664. /**
  665. * ファイルをロックする
  666. *
  667. * @access public
  668. * @param string $file ロックするファイル名
  669. * @param int $mode ロックモード('r', 'rw')
  670. * @param int $timeout ロック待ちタイムアウト(秒−0なら無限)
  671. * @return int ロックハンドル(falseならエラー)
  672. */
  673. public static function lockFile($file, $mode, $timeout = 0)
  674. {
  675. if (file_exists($file) === false) {
  676. touch($file);
  677. }
  678. $lh = fopen($file, $mode);
  679. if ($lh == null) {
  680. return Ethna::raiseError("File Read Error [%s]", E_APP_READ, $file);
  681. }
  682. $lock_mode = $mode == 'r' ? LOCK_SH : LOCK_EX;
  683. for ($i = 0; $i < $timeout || $timeout == 0; $i++) {
  684. $r = flock($lh, $lock_mode | LOCK_NB);
  685. if ($r == true) {
  686. break;
  687. }
  688. sleep(1);
  689. }
  690. if ($timeout > 0 && $i == $timeout) {
  691. // timed out
  692. return Ethna::raiseError("File lock get error [%s]", E_APP_LOCK, $file);
  693. }
  694. return $lh;
  695. }
  696. // }}}
  697. // {{{ unlockFile
  698. /**
  699. * ファイルのロックを解除する
  700. *
  701. * @access public
  702. * @param int $lh ロックハンドル
  703. */
  704. public static function unlockFile($lh)
  705. {
  706. fclose($lh);
  707. }
  708. // }}}
  709. // {{{ formatBacktrace
  710. /**
  711. * バックトレースをフォーマットして返す
  712. *
  713. * @access public
  714. * @param array $bt debug_backtrace()関数で取得したバックトレース
  715. * @return string 文字列にフォーマットされたバックトレース
  716. */
  717. public static function formatBacktrace($bt)
  718. {
  719. $r = "";
  720. $i = 0;
  721. foreach ($bt as $elt) {
  722. $r .= sprintf("[%02d] %s:%d:%s.%s\n", $i,
  723. isset($elt['file']) ? $elt['file'] : 'unknown file',
  724. isset($elt['line']) ? $elt['line'] : 'unknown line',
  725. isset($elt['class']) ? $elt['class'] : 'global',
  726. $elt['function']);
  727. $i++;
  728. if (isset($elt['args']) == false || is_array($elt['args']) == false) {
  729. continue;
  730. }
  731. // 引数のダンプ
  732. foreach ($elt['args'] as $arg) {
  733. $r .= Ethna_Util::_formatBacktrace($arg);
  734. }
  735. }
  736. return $r;
  737. }
  738. /**
  739. * バックトレース引数をフォーマットして返す
  740. *
  741. * @access private
  742. * @param string $arg バックトレースの引数
  743. * @param int $level バックトレースのネストレベル
  744. * @param int $wrap 改行フラグ
  745. * @return string 文字列にフォーマットされたバックトレース
  746. */
  747. private static function _formatBacktrace($arg, $level = 0, $wrap = true)
  748. {
  749. $pad = str_repeat(" ", $level);
  750. if (is_array($arg)) {
  751. $r = sprintf(" %s[array] => (\n", $pad);
  752. if ($level+1 > 4) {
  753. $r .= sprintf(" %s *too deep*\n", $pad);
  754. } else {
  755. foreach ($arg as $key => $elt) {
  756. $r .= Ethna_Util::_formatBacktrace($key, $level, false);
  757. $r .= " => \n";
  758. $r .= Ethna_Util::_formatBacktrace($elt, $level+1);
  759. }
  760. }
  761. $r .= sprintf(" %s)\n", $pad);
  762. } else if (is_object($arg)) {
  763. $r = sprintf(" %s[object]%s%s", $pad, get_class($arg), $wrap ? "\n" : "");
  764. } else {
  765. $r = sprintf(" %s[%s]%s%s", $pad, gettype($arg), $arg, $wrap ? "\n" : "");
  766. }
  767. return $r;
  768. }
  769. // }}}
  770. /**
  771. * Site url from request uri (instead of a config)
  772. */
  773. public static function getUrlFromRequestUri()
  774. {
  775. if (isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1)
  776. || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
  777. ) {
  778. $protocol = 'https://';
  779. }
  780. else {
  781. $protocol = 'http://';
  782. }
  783. $url = $protocol . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/') . '/';
  784. return $url;
  785. }
  786. }
  787. // }}}