X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=lib%2Ffunc.php;h=4d929abcd48ab1552be5295e5aed5f63623ccf24;hb=a5f0333013b20756c8b7566d192f745cc1281cf2;hp=30fdd23df3b7fff61368185fa7d791718cda8919;hpb=443f978ee556cd7b054ec3c82a43bebc00366bfe;p=pukiwiki%2Fpukiwiki.git diff --git a/lib/func.php b/lib/func.php index 30fdd23..4d929ab 100644 --- a/lib/func.php +++ b/lib/func.php @@ -1,9 +1,48 @@ format('Y-m-d H:i:s.u'), 0, 23); + } else { + $timestamp = date('Y-m-d H:i:s'); + } + error_log($timestamp . ' ' . $message . "\n", 3, $log_filepath); +} + +/** + * ctype_digit that supports PHP4+. + * + * PHP official document says PHP4 has ctype_digit() function. + * But sometimes it doen't exists on PHP 4.1. + */ +function pkwk_ctype_digit($s) { + static $ctype_digit_exists; + if (!isset($ctype_digit_exists)) { + $ctype_digit_exists = function_exists('ctype_digit'); + } + if ($ctype_digit_exists) { + return ctype_digit($s); + } + return preg_match('/^[0-9]+$/', $s) ? true : false; +} + function is_interwiki($str) { global $InterWikiName; @@ -75,16 +114,31 @@ function is_freeze($page, $clearcache = FALSE) $is_freeze[$page] = FALSE; return FALSE; } else { - $fp = fopen(get_filename($page), 'rb'); - $buffer = fgets($fp, 8); - fclose($fp); - - $is_freeze[$page] = ($buffer != FALSE && rtrim($buffer) == '#freeze'); + $fp = fopen(get_filename($page), 'rb') or + die('is_freeze(): fopen() failed: ' . htmlsc($page)); + flock($fp, LOCK_SH) or die('is_freeze(): flock() failed'); + rewind($fp); + $buffer = fread($fp, 1000); + flock($fp, LOCK_UN) or die('is_freeze(): flock() failed'); + fclose($fp) or die('is_freeze(): fclose() failed: ' . htmlsc($page)); + $is_freeze[$page] = (bool) preg_match('/^#freeze$/m', $buffer); return $is_freeze[$page]; } } -// ¼«Æ°¥Æ¥ó¥×¥ì¡¼¥È +// Handling $non_list +// $non_list will be preg_quote($str, '/') later. +function check_non_list($page = '') +{ + global $non_list; + static $regex; + + if (! isset($regex)) $regex = '/' . $non_list . '/'; + + return preg_match($regex, $page); +} + +// Auto template function auto_template($page) { global $auto_template_func, $auto_template_rules; @@ -118,106 +172,142 @@ function auto_template($page) return $body; } -// ¸¡º÷¸ì¤òŸ³«¤¹¤ë -function get_search_words($words, $special = FALSE) +// Expand all search-words to regexes and push them into an array +function get_search_words($words = array(), $do_escape = FALSE) { - $retval = array(); - - // Perl¥á¥â - Àµ¤·¤¯¥Ñ¥¿¡¼¥ó¥Þ¥Ã¥Á¤µ¤»¤ë - // http://www.din.or.jp/~ohzaki/perl.htm#JP_Match + static $init, $mb_convert_kana, $pre, $post, $quote = '/'; - $eucpre = $eucpost = ''; - if (SOURCE_ENCODING == 'EUC-JP') { - $eucpre = '(?$value) + $keys[$key] = '/' . $value . '/S'; - $_pages = get_existpages(); - $pages = array(); + $pages = get_existpages(); - $non_list_pattern = '/' . $non_list . '/'; - foreach ($_pages as $page) { - if ($page == $whatsnew || (! $search_non_list && preg_match($non_list_pattern, $page))) - continue; + // Avoid + if ($base != '') { + $pages = preg_grep('/^' . preg_quote($base, '/') . '/S', $pages); + } + if (! $search_non_list) { + $pages = array_diff($pages, preg_grep('/' . $non_list . '/S', $pages)); + } + $pages = array_flip($pages); + unset($pages[$whatsnew]); + + $count = count($pages); + foreach (array_keys($pages) as $page) { + $b_match = FALSE; - // ¸¡º÷Âоݥڡ¼¥¸¤ÎÀ©¸Â¤ò¤«¤±¤ë¤«¤É¤¦¤« (¥Ú¡¼¥¸Ì¾¤ÏÀ©¸Â³°) + // Search for page name + if (! $non_format) { + foreach ($keys as $key) { + $b_match = preg_match($key, $page); + if ($b_type xor $b_match) break; // OR + } + if ($b_match) continue; + } + + // Search auth for page contents if ($search_auth && ! check_readable($page, false, false)) { - $source = get_source(); // ¸¡º÷Âоݥڡ¼¥¸ÆâÍƤò¶õ¤Ë¡£ - } else { - $source = get_source($page); + unset($pages[$page]); + --$count; } - if (! $non_format) - array_unshift($source, $page); // ¥Ú¡¼¥¸Ì¾¤â¸¡º÷ÂÐ¾Ý¤Ë - $b_match = FALSE; + // Search for page contents foreach ($keys as $key) { - $tmp = preg_grep('/' . $key . '/', $source); - $b_match = ! empty($tmp); - if ($b_match xor $b_type) break; + $b_match = preg_match($key, get_source($page, TRUE, TRUE)); + if ($b_type xor $b_match) break; // OR } - if ($b_match) $pages[$page] = get_filetime($page); + if ($b_match) continue; + + unset($pages[$page]); // Miss } if ($non_format) return array_keys($pages); $r_word = rawurlencode($word); - $s_word = htmlspecialchars($word); + $s_word = htmlsc($word); if (empty($pages)) return str_replace('$1', $s_word, $_msg_notfoundresult); - ksort($pages); + ksort($pages, SORT_STRING); + $retval = '' . "\n"; $retval .= str_replace('$1', $s_word, str_replace('$2', count($pages), - str_replace('$3', count($_pages), $b_type ? $_msg_andresult : $_msg_orresult))); + str_replace('$3', $count, $b_type ? $_msg_andresult : $_msg_orresult))); return $retval; } -// ¥×¥í¥°¥é¥à¤Ø¤Î°ú¿ô¤Î¥Á¥§¥Ã¥¯ +// Argument check for program function arg_check($str) { global $vars; return isset($vars['cmd']) && (strpos($vars['cmd'], $str) === 0); } -// ¥Ú¡¼¥¸Ì¾¤Î¥¨¥ó¥³¡¼¥É -function encode($key) +function _pagename_urlencode_callback($matches) +{ + return rawurlencode($matches[0]); +} + +function pagename_urlencode($page) +{ + return preg_replace_callback('|[^/:]+|', '_pagename_urlencode_callback', $page); +} + +// Encode page-name +function encode($str) { - return ($key == '') ? '' : strtoupper(bin2hex($key)); + $str = strval($str); + return ($str == '') ? '' : strtoupper(bin2hex($str)); // Equal to strtoupper(join('', unpack('H*0', $key))); // But PHP 4.3.10 says 'Warning: unpack(): Type H: outside of string in ...' } -// ¥Ú¡¼¥¸Ì¾¤Î¥Ç¥³¡¼¥É -function decode($key) +// Decode page name +function decode($str) +{ + return pkwk_hex2bin($str); +} + +// Inversion of bin2hex() +function pkwk_hex2bin($hex_string) { - return ($key == '') ? '' : substr(pack('H*', '20202020' . $key), 4); + // preg_match : Avoid warning : pack(): Type H: illegal hex digit ... + // (string) : Always treat as string (not int etc). See BugTrack2/31 + return preg_match('/^[0-9a-f]+$/i', $hex_string) ? + pack('H*', (string)$hex_string) : $hex_string; } -// [[ ]] ¤ò¼è¤ê½ü¤¯ +// Remove [[ ]] (brackets) function strip_bracket($str) { $match = array(); @@ -262,14 +372,14 @@ function strip_bracket($str) } } -// ¥Ú¡¼¥¸°ìÍ÷¤ÎºîÀ® +// Create list of pages function page_list($pages, $cmd = 'read', $withfilename = FALSE) { global $script, $list_index; global $_msg_symbol, $_msg_other; global $pagereading_enable; - // ¥½¡¼¥È¥­¡¼¤ò·èÄꤹ¤ë¡£ ' ' < '[a-zA-Z]' < 'zz'¤È¤¤¤¦Á°Äó¡£ + // ソートキーを決定する。 ' ' < '[a-zA-Z]' < 'zz'という前提。 $symbol = ' '; $other = 'zz'; @@ -281,17 +391,24 @@ function page_list($pages, $cmd = 'read', $withfilename = FALSE) } $list = $matches = array(); + + // Shrink URI for read + if ($cmd == 'read') { + $href = $script . '?'; + } else { + $href = $script . '?cmd=' . $cmd . '&page='; + } + foreach($pages as $file=>$page) { - $r_page = rawurlencode($page); - $s_page = htmlspecialchars($page, ENT_QUOTES); + $r_page = pagename_urlencode($page); + $s_page = htmlsc($page, ENT_QUOTES); $passage = get_pg_passage($page); - $str = '
  • ' . $s_page . '' . $passage; + $str = '
  • ' . + $s_page . '' . $passage; if ($withfilename) { - $s_file = htmlspecialchars($file); + $s_file = htmlsc($file); $str .= "\n" . ' ' . "\n" . ' '; } @@ -300,22 +417,22 @@ function page_list($pages, $cmd = 'read', $withfilename = FALSE) // WARNING: Japanese code hard-wired if($pagereading_enable) { if(mb_ereg('^([A-Za-z])', mb_convert_kana($page, 'a'), $matches)) { + $head = strtoupper($matches[1]); + } elseif (isset($readings[$page]) && mb_ereg('^([ァ-ヶ])', $readings[$page], $matches)) { // here $head = $matches[1]; - } elseif(mb_ereg('^([¥¡-¥ö])', $readings[$page], $matches)) { // here - $head = $matches[1]; - } elseif (mb_ereg('^[ -~]|[^¤¡-¤ó°¡-ô¦]', $page)) { // and here + } elseif (mb_ereg('^[ -~]|[^ぁ-ん亜-熙]', $page)) { // and here $head = $symbol; } else { $head = $other; } } else { - $head = (preg_match('/^([A-Za-z])/', $page, $matches)) ? $matches[1] : - (preg_match('/^([ -~])/', $page, $matches) ? $symbol : $other); + $head = (preg_match('/^([A-Za-z])/', $page, $matches)) ? strtoupper($matches[1]) : + (preg_match('/^([ -~])/', $page) ? $symbol : $other); } $list[$head][$page] = $str; } - ksort($list); + uksort($pages, 'strnatcmp'); $cnt = 0; $arr_index = array(); @@ -336,7 +453,7 @@ function page_list($pages, $cmd = 'read', $withfilename = FALSE) '">' . $head . '' . "\n" . ' \n
  • \n"; @@ -359,7 +476,7 @@ function catrule() global $rule_page; if (! is_page($rule_page)) { - return '

    Sorry, page \'' . htmlspecialchars($rule_page) . + return '

    Sorry, page \'' . htmlsc($rule_page) . '\' unavailable.

    '; } else { return convert_html(get_source($rule_page)); @@ -379,13 +496,17 @@ EOD; if(defined('SKIN_FILE') && file_exists(SKIN_FILE) && is_readable(SKIN_FILE)) { catbody($title, $page, $body); } else { - header('Content-Type: text/html; charset=euc-jp'); + $charset = 'utf-8'; + if(defined('CONTENT_CHARSET')) { + $charset = CONTENT_CHARSET; + } + header("Content-Type: text/html; charset=$charset"); print << + + $title - $body @@ -396,14 +517,22 @@ EOD; exit; } -// ¸½ºß»þ¹ï¤ò¥Þ¥¤¥¯¥íÉäǼèÆÀ +// Have the time (as microtime) function getmicrotime() { list($usec, $sec) = explode(' ', microtime()); return ((float)$sec + (float)$usec); } -// Æü»þ¤òÆÀ¤ë +// Elapsed time by second +//define('MUTIME', getmicrotime()); +function elapsedtime() +{ + $at_the_microtime = MUTIME; + return sprintf('%01.03f', getmicrotime() - $at_the_microtime); +} + +// Get the date function get_date($format, $timestamp = NULL) { $format = preg_replace('/(?60, 'h'=>24, 'd'=>1); @@ -450,37 +580,35 @@ function drop_submit($str) 'read(); $ignorepages = $config->get('IgnoreList'); $forceignorepages = $config->get('ForceIgnoreList'); unset($config); $auto_pages = array_merge($ignorepages, $forceignorepages); - foreach ($pages as $page) { + foreach ($pages as $page) if (preg_match('/^' . $WikiName . '$/', $page) ? $nowikiname : strlen($page) >= $autolink) $auto_pages[] = $page; - } - - if (empty($auto_pages)) - return $nowikiname ? '(?!)' : $WikiName; - $auto_pages = array_unique($auto_pages); - sort($auto_pages, SORT_STRING); - - $auto_pages_a = array_values(preg_grep('/^[A-Z]+$/i', $auto_pages)); - $auto_pages = array_values(array_diff($auto_pages, $auto_pages_a)); + if (empty($auto_pages)) { + $result = $result_a = $nowikiname ? '(?!)' : $WikiName; + } else { + $auto_pages = array_unique($auto_pages); + sort($auto_pages, SORT_STRING); - $result = get_autolink_pattern_sub($auto_pages, 0, count($auto_pages), 0); - $result_a = get_autolink_pattern_sub($auto_pages_a, 0, count($auto_pages_a), 0); + $auto_pages_a = array_values(preg_grep('/^[A-Z]+$/i', $auto_pages)); + $auto_pages = array_values(array_diff($auto_pages, $auto_pages_a)); + $result = get_autolink_pattern_sub($auto_pages, 0, count($auto_pages), 0); + $result_a = get_autolink_pattern_sub($auto_pages_a, 0, count($auto_pages_a), 0); + } return array($result, $result_a, $forceignorepages); } @@ -493,12 +621,11 @@ function get_autolink_pattern_sub(& $pages, $start, $end, $pos) $x = (mb_strlen($pages[$start]) <= $pos); if ($x) ++$start; - for ($i = $start; $i < $end; $i = $j) - { + for ($i = $start; $i < $end; $i = $j) { $char = mb_substr($pages[$i], $pos, 1); - for ($j = $i; $j < $end; $j++) { + for ($j = $i; $j < $end; $j++) if (mb_substr($pages[$j], $pos, 1) != $char) break; - } + if ($i != $start) $result .= '|'; if ($i >= ($j - 1)) { $result .= str_replace(' ', '\\ ', preg_quote(mb_substr($pages[$i], $pos), '/')); @@ -514,7 +641,7 @@ function get_autolink_pattern_sub(& $pages, $start, $end, $pos) return $result; } -// pukiwiki.php¥¹¥¯¥ê¥×¥È¤Îabsolute-uri¤òÀ¸À® +// Get absolute-URI of this script function get_script_uri($init_uri = '') { global $script_directory_index; @@ -531,13 +658,13 @@ function get_script_uri($init_uri = '') $script .= SERVER_NAME; // host $script .= (SERVER_PORT == 80 ? '' : ':' . SERVER_PORT); // port - // SCRIPT_NAME ¤¬'/'¤Ç»Ï¤Þ¤Ã¤Æ¤¤¤Ê¤¤¾ì¹ç(cgi¤Ê¤É) REQUEST_URI¤ò»È¤Ã¤Æ¤ß¤ë + // SCRIPT_NAME が'/'で始まっていない場合(cgiなど) REQUEST_URIを使ってみる $path = SCRIPT_NAME; if ($path{0} != '/') { if (! isset($_SERVER['REQUEST_URI']) || $_SERVER['REQUEST_URI']{0} != '/') die_message($msg); - // REQUEST_URI¤ò¥Ñ¡¼¥¹¤·¡¢pathÉôʬ¤À¤±¤ò¼è¤ê½Ð¤¹ + // REQUEST_URIをパースし、path部分だけを取り出す $parse_url = parse_url($script . $_SERVER['REQUEST_URI']); if (! isset($parse_url['path']) || $parse_url['path']{0} != '/') die_message($msg); @@ -561,7 +688,7 @@ function get_script_uri($init_uri = '') if (isset($script_directory_index)) { if (! file_exists($script_directory_index)) die_message('Directory index file not found: ' . - htmlspecialchars($script_directory_index)); + htmlsc($script_directory_index)); $matches = array(); if (preg_match('#^(.+/)' . preg_quote($script_directory_index, '#') . '$#', $script, $matches)) $script = $matches[1]; @@ -570,16 +697,15 @@ function get_script_uri($init_uri = '') return $script; } -/* -ÊÑ¿ôÆâ¤Înull(\0)¥Ð¥¤¥È¤òºï½ü¤¹¤ë -PHP¤Ïfopen("hoge.php\0.txt")¤Ç"hoge.php"¤ò³«¤¤¤Æ¤·¤Þ¤¦¤Ê¤É¤ÎÌäÂꤢ¤ê - -http://ns1.php.gr.jp/pipermail/php-users/2003-January/012742.html -[PHP-users 12736] null byte attack - -2003-05-16: magic quotes gpc¤ÎÉü¸µ½èÍý¤òÅý¹ç -2003-05-21: Ï¢ÁÛÇÛÎó¤Î¥­¡¼¤Ïbinary safe -*/ +// Remove null(\0) bytes from variables +// +// NOTE: PHP had vulnerabilities that opens "hoge.php" via fopen("hoge.php\0.txt") etc. +// [PHP-users 12736] null byte attack +// http://ns1.php.gr.jp/pipermail/php-users/2003-January/012742.html +// +// 2003-05-16: magic quotes gpcの復元処理を統合 +// 2003-05-21: 連想配列のキーはbinary safe +// function input_filter($param) { static $magic_quotes_gpc = NULL; @@ -600,7 +726,7 @@ function sanitize($param) { return input_filter($param); } -// CSV·Á¼°¤Îʸ»úÎó¤òÇÛÎó¤Ë +// Explode Comma-Separated Values to an array function csv_explode($separator, $string) { $retval = $matches = array(); @@ -625,26 +751,70 @@ function csv_implode($glue, $pieces) $_glue = ($glue != '') ? '\\' . $glue{0} : ''; $arr = array(); foreach ($pieces as $str) { - if (ereg('[' . $_glue . '"' . "\n\r" . ']', $str)) + if (preg_match('/[' . '"' . "\n\r" . $_glue . ']/', $str)) $str = '"' . str_replace('"', '""', $str) . '"'; $arr[] = $str; } return join($glue, $arr); } -function pkwk_login($pass = '') +// Sugar with default settings +function htmlsc($string = '', $flags = ENT_COMPAT, $charset = CONTENT_CHARSET) { - global $adminpass; - - if ($pass != '' && md5($pass) == $adminpass) { + return htmlspecialchars($string, $flags, $charset); // htmlsc() +} + +/** + * Get redirect page name on Page Redirect Rules + * + * This function returns exactly false if it doesn't need redirection. + * So callers need check return value is false or not. + * + * @param $page page name + * @return new page name or false + */ +function get_pagename_on_redirect($page) { + global $page_redirect_rules; + foreach ($page_redirect_rules as $rule=>$replace) { + if (preg_match($rule, $page)) { + if (is_string($replace)) { + $new_page = preg_replace($rule, $replace, $page); + } elseif (is_object($replace) && is_callable($replace)) { + $new_page = preg_replace_callback($rule, $replace, $page); + } else { + die_message('Invalid redirect rule: ' . $rule . '=>' . $replace); + } + if ($page !== $new_page) { + return $new_page; + } + } + } + return false; +} + +/** + * Redirect from an old page to new page + * + * This function returns true when a redirection occurs. + * So callers need check return value is false or true. + * And if it is true, then you have to exit PHP script. + * + * @return bool Inticates a redirection occurred or not + */ +function manage_page_redirect() { + global $vars; + if (isset($vars['page'])) { + $page = $vars['page']; + } + $new_page = get_pagename_on_redirect($page); + if ($new_page != false) { + header('Location: ' . get_script_uri() . '?' . + pagename_urlencode($new_page)); return TRUE; - } else { - sleep(2); // Blocking brute force attack - return FALSE; } + return FALSE; } - //// Compat //// // is_a -- Returns TRUE if the object is of this class or has this class as one of its parents @@ -691,4 +861,14 @@ if (! function_exists('md5_file')) { return md5($data); } } -?> + +// sha1 -- Compute SHA-1 hash +// (PHP 4 >= 4.3.0, PHP5) +if (! function_exists('sha1')) { + if (extension_loaded('mhash')) { + function sha1($str) + { + return bin2hex(mhash(MHASH_SHA1, $str)); + } + } +}