OSDN Git Service

Renamed sanitize() => input_filter(), to avoid misunderstanding
[pukiwiki/pukiwiki.git] / file.php
index 511cde7..28eb31c 100644 (file)
--- a/file.php
+++ b/file.php
@@ -2,13 +2,14 @@
 /////////////////////////////////////////////////
 // PukiWiki - Yet another WikiWikiWeb clone.
 //
-// $Id: file.php,v 1.5 2003/02/11 04:51:58 panda Exp $
+// $Id: file.php,v 1.43 2004/07/10 10:59:38 henoheno Exp $
 //
 
 // ¥½¡¼¥¹¤ò¼èÆÀ
-function get_source($page)
+function get_source($page=NULL)
 {
-       if (!is_page($page)) {
+       if (!is_page($page))
+       {
                return array();
        }
        return str_replace("\r",'',file(get_filename($page)));
@@ -17,6 +18,10 @@ function get_source($page)
 // ¥Ú¡¼¥¸¤Î¹¹¿·»þ¹ï¤òÆÀ¤ë
 function get_filetime($page)
 {
+       if (!is_page($page))
+       {
+               return 0;
+       }
        return filemtime(get_filename($page)) - LOCALZONE;
 }
 
@@ -27,12 +32,12 @@ function get_filename($page)
 }
 
 // ¥Ú¡¼¥¸¤Î½ÐÎÏ
-function page_write($page,$postdata)
+function page_write($page,$postdata,$notimestamp=FALSE)
 {
-       $postdata = user_rules_str($postdata);
+       $postdata = make_str_rules($postdata);
        
        // º¹Ê¬¥Õ¥¡¥¤¥ë¤ÎºîÀ®
-       $oldpostdata = is_page($page) ? join('',get_source($page)) : "\n";
+       $oldpostdata = is_page($page) ? join('',get_source($page)) : '';
        $diffdata = do_diff($oldpostdata,$postdata);
        file_write(DIFF_DIR,$page,$diffdata);
        
@@ -40,193 +45,466 @@ function page_write($page,$postdata)
        make_backup($page,$postdata == '');
        
        // ¥Õ¥¡¥¤¥ë¤Î½ñ¤­¹þ¤ß
-       file_write(DATA_DIR,$page,$postdata);
+       file_write(DATA_DIR,$page,$postdata,$notimestamp);
        
-       // is_page¤Î¥­¥ã¥Ã¥·¥å¤ò¥¯¥ê¥¢¤¹¤ë¡£
-       is_page($page,true);
+       // TrackBack Ping ¤ÎÁ÷¿®
+       // ¡ÖÄɲá׹ԤòÃê½Ð
+       $lines = join("\n",preg_replace('/^\+/','',preg_grep('/^\+/',explode("\n",$diffdata))));
+       tb_send($page,$lines);
        
        // link¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¹¹¿·
        links_update($page);
 }
 
+// ¥æ¡¼¥¶ÄêµÁ¥ë¡¼¥ë(¥½¡¼¥¹¤òÃÖ´¹¤¹¤ë)
+function make_str_rules($str)
+{
+       global $str_rules,$fixed_heading_anchor;
+       
+       $arr = explode("\n",$str);
+       
+       $retvars = array();
+       foreach ($arr as $str)
+       {
+               if ($str != '' and $str{0} != ' ' and $str{0} != "\t")
+               {
+                       foreach ($str_rules as $rule => $replace)
+                       {
+                               $str = preg_replace("/$rule/",$replace,$str);
+                       }
+               }
+               // ¸«½Ð¤·¤Ë¸ÇÍ­ID¤òÉÕÍ¿¤¹¤ë
+               if ($fixed_heading_anchor and
+                       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)
+function file_write($dir,$page,$str,$notimestamp=FALSE)
 {
-       global $post,$update_exec;
+       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 and $str == '' and file_exists($file)) {
+       if ($dir == DATA_DIR and $str == '' and file_exists($file))
+       {
                unlink($file);
+               put_recentdeleted($page);
        }
-       else {
+       if ($str != '')
+       {
                $str = preg_replace("/\r/",'',$str);
                $str = rtrim($str)."\n";
                
-               if (!empty($post['notimestamp']) and file_exists($file)) {
+               if ($notimestamp and 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).'<br>maybe permission is not writable or filename is too long');
+                       or die_message('cannot write page file or diff file or other'.htmlspecialchars($page).'<br />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) {
+               if ($timestamp)
+               {
                        touch($file,$timestamp + LOCALZONE);
                }
        }
        
-       if (!$timestamp) {
+       // is_page¤Î¥­¥ã¥Ã¥·¥å¤ò¥¯¥ê¥¢¤¹¤ë¡£
+       is_page($page,TRUE);
+       
+       if (!$timestamp and $dir == DATA_DIR)
+       {
                put_lastmodified();
        }
        
-       if ($update_exec and $dir == DATA_DIR) {
+       if ($update_exec and $dir == DATA_DIR)
+       {
                system($update_exec.' > /dev/null &');
        }
+       
+       if ($notify and $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 = array();
+       foreach (get_source($whatsdeleted) as $line)
+       {
+               if (preg_match('/^-(.+) - (\[\[.+\]\])$/',$line,$matches))
+               {
+                       $lines[$matches[2]] = $line;
+               }
+       }
+       $_page = "[[$page]]";
+       if (array_key_exists($_page,$lines))
+       {
+               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).'<br />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 $script,$post,$maxshow,$whatsnew,$non_list;
+       global $maxshow,$whatsnew,$non_list,$autolink;
 
-       $pages = array();
-       foreach(get_existpages() as $page) {
-               if ($page == $whatsnew or preg_match("/$non_list/",$page)) {
-                       continue;
+       $pages = get_existpages();
+       $recent_pages = array();
+       foreach($pages as $page)
+       {
+               if ($page != $whatsnew and !preg_match("/$non_list/",$page))
+               {
+                       $recent_pages[$page] = get_filetime($page);
                }
-               
-               $time = get_filetime($page);
-               $s_page = htmlspecialchars($page);
-               $pages[$s_page] = $time;
        }
        
-       arsort($pages); //»þ¹ï¹ß½ç¤Ç¥½¡¼¥È
-       
-       $fp = fopen(get_filename($whatsnew),'w')
-               or die_message('cannot write page file '.htmlspecialchars($whatsnew).'<br>maybe permission is not writable or filename is too long');
+       //»þ¹ï¹ß½ç¤Ç¥½¡¼¥È
+       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<br />maybe permission is not writable or filename is too long');
+       set_file_buffer($fp, 0);
        flock($fp,LOCK_EX);
-       
-       foreach($pages as $s_page => $time) {
-               fputs($fp, "//$time $s_page\n");
+       rewind($fp);
+       foreach ($recent_pages as $page=>$time)
+       {
+               fputs($fp,"$time\t$page\n");
        }
-       
-       $pages = array_splice($pages,0,$maxshow);
-       
-       foreach($pages as $s_page => $time) {
-               $lastmod = format_date($time);
-               fputs($fp, "-$lastmod - [[$s_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).'<br />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<br />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;
-       static $pg_passage;
+       static $pg_passage = array();
        
-       if (!$show_passage) {
+       if (!$show_passage)
+       {
                return '';
        }
        
-       if (!isset($pg_passage)) {
-               $pg_passage = array();
-       }
-       
-       if (!array_key_exists($page,$pg_passage)) {
-               $pg_passage[$page] = (is_page($page) and $time = get_filetime($page)) ? get_passage($time) : '';
+       if (!array_key_exists($page,$pg_passage))
+       {
+               $pg_passage[$page] = (is_page($page) and $time = get_filetime($page)) ?
+                       get_passage($time) : '';
        }
        
-       return $sw ? "<small>{$pg_passage[$page]}</small>" : $pg_passage[$page];
+       return $sw ? "<small>{$pg_passage[$page]}</small>" : " {$pg_passage[$page]}";
 }
 
 // Last-Modified ¥Ø¥Ã¥À
-function header_lastmod()
+function header_lastmod($page=NULL)
 {
        global $lastmod;
        
-       if ($lastmod and is_page($page)) {
+       if ($lastmod and is_page($page))
+       {
                header('Last-Modified: '.date('D, d M Y H:i:s',get_filetime($page)).' GMT');
        }
 }
 
 // Á´¥Ú¡¼¥¸Ì¾¤òÇÛÎó¤Ë
-function get_existpages($dir = DATA_DIR)
+function get_existpages($dir=DATA_DIR,$ext='.txt')
 {
        $aryret = array();
        
-       $dir = @opendir($dir) or die();
+       $pattern = '^((?:[0-9A-F]{2})+)';
+       if ($ext != '')
+       {
+               $pattern .= 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,$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();
        
-       while ($file = readdir($dir)) {
-               if (preg_match('/^([0-9A-F]+)/',$file,$matches)) {
-                       $aryret[] = decode($matches[1]);
+       $readings = array();
+       foreach ($pages as $page) {
+               $readings[$page] = '';
+       }
+       $deletedPage = FALSE;
+       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;
+                       }
+               }
+       }
+       if($pagereading_enable) {
+               // ChaSen/KAKASI ¸Æ¤Ó½Ð¤·¤¬Í­¸ú¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç
+               $unknownPage = FALSE;
+               // Æɤߤ¬ÉÔÌÀ¤Î¥Ú¡¼¥¸¤¬¤¢¤ë¤«¥Á¥§¥Ã¥¯
+               foreach ($readings as $page => $reading) {
+                       if($reading=='') {
+                               $unknownPage = TRUE;
+                               break;
+                       }
+               }
+               if($unknownPage) {
+                       // Æɤߤ¬ÉÔÌÀ¤Î¥Ú¡¼¥¸¤¬¤¢¤ë¾ì¹ç¡¢ChaSen/KAKASI ¤ò¼Â¹Ô
+                       switch(strtolower($pagereading_kanji2kana_converter)) {
+                       case 'chasen':
+                               $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=='') {
+                                               fputs($fp, mb_convert_encoding("$page\n", $pagereading_kanji2kana_encoding, SOURCE_ENCODING));
+                                       }
+                               }
+                               fclose($fp);
+                               if(!file_exists($pagereading_chasen_path)) {
+                                       unlink($tmpfname);
+                                       die_message("CHASEN not found: $pagereading_chasen_path");
+                               }
+                               $fp = popen("$pagereading_chasen_path -F %y $tmpfname", "r");
+                               if(!$fp) {
+                                       unlink($tmpfname);
+                                       die_message("ChaSen execution failed: $pagereading_chasen_path -F %y $tmpfname");
+                               }
+                               foreach ($readings as $page => $reading) {
+                                       if($reading=='') {
+                                               $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':
+                               $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=='') {
+                                               fputs($fp, mb_convert_encoding("$page\n", $pagereading_kanji2kana_encoding, SOURCE_ENCODING));
+                                       }
+                               }
+                               fclose($fp);
+                               if(!file_exists($pagereading_kakasi_path)) {
+                                       unlink($tmpfname);
+                                       die_message("KAKASI not found: $pagereading_kakasi_path");
+                               }                                       
+                               $fp = popen("$pagereading_kakasi_path -kK -HK -JK <$tmpfname", "r");
+                               if(!$fp) {
+                                       unlink($tmpfname);
+                                       die_message("KAKASI execution failed: $pagereading_kakasi_path -kK -HK -JK <$tmpfname");
+                               }
+                               foreach ($readings as $page => $reading) {
+                                       if($reading=='') {
+                                               $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 = array();
+                               $replacements = 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=='') {
+                                               $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 or $deletedPage) {
+                       // Æɤߤǥ½¡¼¥È
+                       asort($readings);
+                       
+                       // ¥Ú¡¼¥¸¤ò½ñ¤­¹þ¤ß
+                       $body = '';
+                       foreach ($readings as $page => $reading) {
+                               $body .= "-[[$page]] $reading\n";
+                       }
+                       page_write($pagereading_config_page, $body);
                }
        }
        
-       closedir($dir);
+       // ÆɤßÉÔÌÀ¤Î¥Ú¡¼¥¸¤Ï¡¢¤½¤Î¤Þ¤Þ¥Ú¡¼¥¸Ì¾¤òÊÖ¤¹ (ChaSen/KAKASI ¸Æ
+       // ¤Ó½Ð¤·¤¬Ìµ¸ú¤ËÀßÄꤵ¤ì¤Æ¤¤¤ë¾ì¹ç¤ä¡¢ChaSen/KAKASI ¸Æ¤Ó½Ð¤·¤Ë
+       // ¼ºÇÔ¤·¤¿»þ¤Î°Ù)
+       foreach ($pages as $page) {
+               if($readings[$page]=='') {
+                       $readings[$page] = $page;
+               }
+       }
        
-       return $aryret;
+       return $readings;
 }
-
-function links_update($page)
+//¥Õ¥¡¥¤¥ë̾¤Î°ìÍ÷¤òÇÛÎó¤Ë(¥¨¥ó¥³¡¼¥ÉºÑ¤ß¡¢³ÈÄ¥»Ò¤ò»ØÄê)
+function get_existfiles($dir,$ext)
 {
-       global $vars;
-
-       // link¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¹¹¿·
-       if (defined('LINK_DB') and exist_plugin_action('links')) {
-               // ¤Á¤ç¤Ã¤È¸È©
-               $tmp = $vars['page'];
-               $vars['page'] = $page;
-               do_plugin_action('links');
-               $vars['page'] = $tmp;
+       $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;
+       static $links = array();
        
-       if (!isset($links)) {
-               $links = array();
-       }
-       
-       if (array_key_exists($page,$links)) {
+       if (array_key_exists($page,$links))
+       {
                return $links[$page];
        }
        
        // ²Äǽ¤Ê¤émake_link()¤ÇÀ¸À®¤·¤¿´ØÏ¢¥Ú¡¼¥¸¤ò¼è¤ê¹þ¤à
        $links[$page] = ($page == $vars['page']) ? $related : array();
        
-       $a_page = addslashes($page);
-       
-       if (defined('LINK_DB')) {
-               $sql = <<<EOD
-SELECT refpage.name,refpage.lastmod FROM page left join link on page.id = page_id left join page as refpage on ref_id = refpage.id where page.name = '$a_page'
-UNION
-SELECT DISTINCT refpage.name,refpage.lastmod FROM page left join link on page.id = ref_id left join page as refpage on page_id = refpage.id where page.name = '$a_page';
-EOD;
-               $rows = db_query($sql);
-               
-               foreach ($rows as $row) {
-                       if (empty($row['name']) or substr($row['name'],0,1) == ':') {
-                               continue;
-                       }
-                       $links[$page][$row['name']] = $row['lastmod'];
-               }
-       }
-       else {
-               $links[$page] = array_merge($links[$page],do_search($page,'OR',1));
-       }
+       // ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é´ØÏ¢¥Ú¡¼¥¸¤òÆÀ¤ë
+       $links[$page] += links_get_related_db($vars['page']);
        
        return $links[$page];
 }