$replace)
$str = preg_replace("/$rule/", $replace, $str);
}
// 見出しに固有IDを付与する
if ($fixed_heading_anchor &&
preg_match('/^(\*{1,3}(.(?!\[#[A-Za-z][\w-]+\]))+)$/', $str, $matches))
{
// 固有IDを生成する
// ランダムな英字(1文字) + md5ハッシュのランダムな部分文字列(7文字)
$anchor = chr(mt_rand(ord('a'), ord('z'))).
substr(md5(uniqid(substr($matches[1], 0, 100), 1)), mt_rand(0, 24), 7);
$str = rtrim($matches[1]) . " [#$anchor]";
}
$retvars[] = $str;
}
return join("\n", $retvars);
}
// ファイルへの出力
function file_write($dir, $page, $str, $notimestamp = FALSE)
{
global $update_exec;
global $_msg_invalidiwn;
global $notify, $notify_diff_only, $notify_to, $notify_subject, $notify_header;
global $smtp_server, $smtp_auth;
if (! is_pagename($page))
die_message(str_replace('$1', htmlspecialchars($page),
str_replace('$2', 'WikiName', $_msg_invalidiwn))
);
$page = strip_bracket($page);
$timestamp = FALSE;
$file = $dir . encode($page) . '.txt';
if ($dir == DATA_DIR && $str == '' && file_exists($file)) {
unlink($file);
put_recentdeleted($page);
}
if ($str != '') {
$str = preg_replace("/\r/", '', $str);
$str = rtrim($str) . "\n";
if ($notimestamp && file_exists($file))
$timestamp = filemtime($file) - LOCALZONE;
$fp = fopen($file, 'w') or
die_message('Cannot write page file or diff file or other ' .
htmlspecialchars($page) .
'
Maybe permission is not writable or filename is too long');
set_file_buffer($fp, 0);
flock($fp, LOCK_EX);
rewind($fp);
fputs($fp, $str);
flock($fp, LOCK_UN);
fclose($fp);
if ($timestamp)
touch($file, $timestamp + LOCALZONE);
}
// is_pageのキャッシュをクリアする
is_page($page, TRUE);
if (! $timestamp && $dir == DATA_DIR)
put_lastmodified();
if ($update_exec && $dir == DATA_DIR)
system($update_exec . ' > /dev/null &');
if ($notify && $dir == DIFF_DIR) {
if ($notify_diff_only) // 差分だけを送信する
$str = preg_replace('/^[^-+].*\n/m', '', $str);
if ($smtp_auth)
pop_before_smtp();
$subject = str_replace('$page', $page, $notify_subject);
ini_set('SMTP', $smtp_server);
mb_language(LANG);
mb_send_mail($notify_to, $subject, $str, $notify_header);
}
}
// 削除履歴ページの更新
function put_recentdeleted($page)
{
global $whatsdeleted, $maxshow_deleted;
if ($maxshow_deleted == 0) return;
// Update RecentDeleted
$lines = $matches = array();
foreach (get_source($whatsdeleted) as $line) {
if (preg_match('/^-(.+) - (\[\[.+\]\])$/', $line, $matches))
$lines[$matches[2]] = $line;
}
$_page = "[[$page]]";
if (isset($lines[$_page])) unset($lines[$_page]);
array_unshift($lines, '-' . format_date(UTIME) . " - $_page\n");
$lines = array_splice($lines, 0, $maxshow_deleted);
$fp = fopen(get_filename($whatsdeleted), 'w') or
die_message('Cannot write page file ' .
htmlspecialchars($whatsdeleted) .
'
Maybe permission is not writable or filename is too long');
set_file_buffer($fp, 0);
flock($fp, LOCK_EX);
rewind($fp);
fputs($fp, join('', $lines));
fputs($fp, "#norelated\n"); // :)
flock($fp, LOCK_UN);
fclose($fp);
}
// 最終更新ページの更新
function put_lastmodified()
{
global $maxshow, $whatsnew, $non_list, $autolink;
$pages = get_existpages();
$recent_pages = array();
foreach($pages as $page) {
if ($page != $whatsnew && ! preg_match("/$non_list/", $page))
$recent_pages[$page] = get_filetime($page);
}
//時刻降順でソート
arsort($recent_pages, SORT_NUMERIC);
// create recent.dat (for recent.inc.php)
$fp = fopen(CACHE_DIR . 'recent.dat', 'w') or
die_message('Cannot write cache file ' .
CACHE_DIR . 'recent.dat' .
'
Maybe permission is not writable or filename is too long');
set_file_buffer($fp, 0);
flock($fp, LOCK_EX);
rewind($fp);
foreach ($recent_pages as $page=>$time)
fputs($fp, "$time\t$page\n");
flock($fp, LOCK_UN);
fclose($fp);
// create RecentChanges
$fp = fopen(get_filename($whatsnew), 'w') or
die_message('Cannot write page file ' .
htmlspecialchars($whatsnew) .
'
Maybe permission is not writable or filename is too long');
set_file_buffer($fp, 0);
flock($fp, LOCK_EX);
rewind($fp);
foreach (array_splice(array_keys($recent_pages), 0, $maxshow) as $page) {
$time = $recent_pages[$page];
$s_lastmod = htmlspecialchars(format_date($time));
$s_page = htmlspecialchars($page);
fputs($fp, "-$s_lastmod - [[$s_page]]\n");
}
fputs($fp, "#norelated\n"); // :)
flock($fp, LOCK_UN);
fclose($fp);
// for autolink
if ($autolink) {
list($pattern, $pattern_a, $forceignorelist) =
get_autolink_pattern($pages);
$fp = fopen(CACHE_DIR . 'autolink.dat', 'w') or
die_message('Cannot write autolink file ' .
CACHE_DIR . '/autolink.dat' .
'
Maybe permission is not writable');
set_file_buffer($fp, 0);
flock($fp, LOCK_EX);
rewind($fp);
fputs($fp, $pattern . "\n");
fputs($fp, $pattern_a . "\n");
fputs($fp, join("\t", $forceignorelist) . "\n");
flock($fp, LOCK_UN);
fclose($fp);
}
}
// 指定されたページの経過時刻
function get_pg_passage($page, $sw = TRUE)
{
global $show_passage;
if (! $show_passage) return '';
$time = get_filetime($page);
$pg_passage = ($time != 0) ? get_passage($time) : '';
return $sw ? "$pg_passage" : " $pg_passage";
}
// Last-Modified ヘッダ
function header_lastmod($page = NULL)
{
global $lastmod;
if ($lastmod && is_page($page))
header('Last-Modified: ' .
date('D, d M Y H:i:s', get_filetime($page)) . ' GMT');
}
// 全ページ名を配列に
function get_existpages($dir = DATA_DIR, $ext = '.txt')
{
$aryret = array();
$pattern = '^((?:[0-9A-F]{2})+)';
if ($ext != '')
$pattern .= preg_quote($ext, '/') . '$';
$dp = @opendir($dir) or
die_message($dir . ' is not found or not readable.');
$matches = array();
while ($file = readdir($dp)) {
if (preg_match("/$pattern/", $file, $matches))
$aryret[$file] = decode($matches[1]);
}
closedir($dp);
return $aryret;
}
// ページ名の読みを配列に
function get_readings()
{
global $pagereading_enable, $pagereading_kanji2kana_converter;
global $pagereading_kanji2kana_encoding, $pagereading_chasen_path;
global $pagereading_kakasi_path, $pagereading_config_page;
global $pagereading_config_dict;
$pages = get_existpages();
$readings = array();
foreach ($pages as $page)
$readings[$page] = '';
$deletedPage = FALSE;
$matches = array();
foreach (get_source($pagereading_config_page) as $line) {
$line = chop($line);
if(preg_match('/^-\[\[([^]]+)\]\]\s+(.+)$/', $line, $matches)) {
if(isset($readings[$matches[1]])) {
// 読みが不明のページ
$readings[$matches[1]] = $matches[2];
} else {
// 削除されたページ
$deletedPage = TRUE;
}
}
}
// ChaSen/KAKASI 呼び出しが有効に設定されている場合
if($pagereading_enable) {
// 読みが不明のページがあるかチェック
$unknownPage = FALSE;
foreach ($readings as $page => $reading) {
if($reading == '') {
$unknownPage = TRUE;
break;
}
}
// 読みが不明のページがある場合、ChaSen/KAKASI を実行
if($unknownPage) {
switch(strtolower($pagereading_kanji2kana_converter)) {
case 'chasen':
if(! file_exists($pagereading_chasen_path))
die_message("ChaSen not found: $pagereading_chasen_path");
$tmpfname = tempnam(CACHE_DIR, 'PageReading');
$fp = fopen($tmpfname, "w") or
die_message("Cannot write temporary file '$tmpfname'.\n");
foreach ($readings as $page => $reading) {
if($reading != '') continue;
fputs($fp, mb_convert_encoding("$page\n",
$pagereading_kanji2kana_encoding, SOURCE_ENCODING));
}
fclose($fp);
$chasen = "$pagereading_chasen_path -F %y $tmpfname";
$fp = popen($chasen, 'r');
if($fp === FALSE) {
unlink($tmpfname);
die_message("ChaSen execution failed: $chasen");
}
foreach ($readings as $page => $reading) {
if($reading != '') continue;
$line = fgets($fp);
$line = mb_convert_encoding($line, SOURCE_ENCODING,
$pagereading_kanji2kana_encoding);
$line = chop($line);
$readings[$page] = $line;
}
pclose($fp);
unlink($tmpfname) or
die_message("Temporary file can not be removed: $tmpfname");
break;
case 'kakasi':
case 'kakashi':
if(! file_exists($pagereading_kakasi_path))
die_message("KAKASI not found: $pagereading_kakasi_path");
$tmpfname = tempnam(CACHE_DIR, 'PageReading');
$fp = fopen($tmpfname, 'w') or
die_message("Cannot write temporary file '$tmpfname'.\n");
foreach ($readings as $page => $reading) {
if($reading != '') continue;
fputs($fp, mb_convert_encoding("$page\n",
$pagereading_kanji2kana_encoding, SOURCE_ENCODING));
}
fclose($fp);
$kakasi = "$pagereading_kakasi_path -kK -HK -JK < $tmpfname";
$fp = popen($kakasi, 'r');
if($fp === FALSE) {
unlink($tmpfname);
die_message("KAKASI execution failed: $kakasi");
}
foreach ($readings as $page => $reading) {
if($reading != '') continue;
$line = fgets($fp);
$line = mb_convert_encoding($line, SOURCE_ENCODING,
$pagereading_kanji2kana_encoding);
$line = chop($line);
$readings[$page] = $line;
}
pclose($fp);
unlink($tmpfname) or
die_message("Temporary file can not be removed: $tmpfname");
break;
case 'none':
$patterns = $replacements = $matches = array();
foreach (get_source($pagereading_config_dict) as $line) {
$line = chop($line);
if(preg_match('|^ /([^/]+)/,\s*(.+)$|', $line, $matches)) {
$patterns[] = $matches[1];
$replacements[] = $matches[2];
}
}
foreach ($readings as $page => $reading) {
if($reading != '') continue;
$readings[$page] = $page;
foreach ($patterns as $no => $pattern)
$readings[$page] = mb_convert_kana(mb_ereg_replace($pattern,
$replacements[$no], $readings[$page]), "aKCV");
}
break;
default:
die_message("Unknown kanji-kana converter: $pagereading_kanji2kana_converter.");
break;
}
}
if($unknownPage || $deletedPage) {
asort($readings); // 読みでソート
$body = '';
foreach ($readings as $page => $reading)
$body .= "-[[$page]] $reading\n";
// ページを書き込み
page_write($pagereading_config_page, $body);
}
}
// 読み不明のページは、そのままページ名を返す (ChaSen/KAKASI 呼
// び出しが無効に設定されている場合や、ChaSen/KAKASI 呼び出しに
// 失敗した時の為)
foreach ($pages as $page) {
if($readings[$page] == '')
$readings[$page] = $page;
}
return $readings;
}
//ファイル名の一覧を配列に(エンコード済み、拡張子を指定)
function get_existfiles($dir, $ext)
{
$aryret = array();
$pattern = '^(?:[0-9A-F]{2})+' . preg_quote($ext, '/') . '$';
$dp = @opendir($dir) or
die_message($dir . ' is not found or not readable.');
while ($file = readdir($dp)) {
if (preg_match("/$pattern/", $file))
$aryret[] = $dir . $file;
}
closedir($dp);
return $aryret;
}
//あるページの関連ページを得る
function links_get_related($page)
{
global $vars, $related;
static $links = array();
if (isset($links[$page])) return $links[$page];
// 可能ならmake_link()で生成した関連ページを取り込む
$links[$page] = ($page == $vars['page']) ? $related : array();
// データベースから関連ページを得る
$links[$page] += links_get_related_db($vars['page']);
return $links[$page];
}
?>