PukiWiki PHP Cross Reference Collaborative Wikis

Source: /lib/file.php - 792 lines - 22060 bytes - Summary - Text - Print

   1  <?php
   2  // PukiWiki - Yet another WikiWikiWeb clone.
   3  // $Id: file.php,v 1.72 2006/06/11 14:42:09 henoheno Exp $
   4  // Copyright (C)
   5  //   2002-2006 PukiWiki Developers Team
   6  //   2001-2002 Originally written by yu-ji
   7  // License: GPL v2 or (at your option) any later version
   8  //
   9  // File related functions
  10  
  11  // RecentChanges
  12  define('PKWK_MAXSHOW_ALLOWANCE', 10);
  13  define('PKWK_MAXSHOW_CACHE', 'recent.dat');
  14  
  15  // AutoLink
  16  define('PKWK_AUTOLINK_REGEX_CACHE', 'autolink.dat');
  17  
  18  // Get source(wiki text) data of the page
  19  function get_source($page = NULL, $lock = TRUE, $join = FALSE)
  20  {
  21      $result = $join ? '' : array();
  22  
  23      if (is_page($page)) {
  24          $path  = get_filename($page);
  25  
  26          if ($lock) {
  27              $fp = @fopen($path, 'r');
  28              if ($fp == FALSE) return $result;
  29              flock($fp, LOCK_SH);
  30          }
  31  
  32          if ($join) {
  33              // Returns a value
  34              $result = str_replace("\r", '', fread($fp, filesize($path)));
  35          } else {
  36              // Returns an array
  37              // Removing line-feeds: Because file() doesn't remove them.
  38              $result = str_replace("\r", '', file($path));
  39          }
  40  
  41          if ($lock) {
  42              flock($fp, LOCK_UN);
  43              @fclose($fp);
  44          }
  45      }
  46  
  47      return $result;
  48  }
  49  
  50  // Get last-modified filetime of the page
  51  function get_filetime($page)
  52  {
  53      return is_page($page) ? filemtime(get_filename($page)) - LOCALZONE : 0;
  54  }
  55  
  56  // Get physical file name of the page
  57  function get_filename($page)
  58  {
  59      return DATA_DIR . encode($page) . '.txt';
  60  }
  61  
  62  // Put a data(wiki text) into a physical file(diff, backup, text)
  63  function page_write($page, $postdata, $notimestamp = FALSE)
  64  {
  65      global $trackback;
  66  
  67      if (PKWK_READONLY) return; // Do nothing
  68  
  69      $postdata = make_str_rules($postdata);
  70  
  71      // Create and write diff
  72      $oldpostdata = is_page($page) ? join('', get_source($page)) : '';
  73      $diffdata    = do_diff($oldpostdata, $postdata);
  74      file_write(DIFF_DIR, $page, $diffdata);
  75  
  76      // Create backup
  77      make_backup($page, $postdata == ''); // Is $postdata null?
  78  
  79      // Create wiki text
  80      file_write(DATA_DIR, $page, $postdata, $notimestamp);
  81  
  82      if ($trackback) {
  83          // TrackBack Ping
  84          $_diff = explode("\n", $diffdata);
  85          $plus  = join("\n", preg_replace('/^\+/', '', preg_grep('/^\+/', $_diff)));
  86          $minus = join("\n", preg_replace('/^-/',  '', preg_grep('/^-/',  $_diff)));
  87          tb_send($page, $plus, $minus);
  88      }
  89  
  90      links_update($page);
  91  }
  92  
  93  // Modify original text with user-defined / system-defined rules
  94  function make_str_rules($source)
  95  {
  96      global $str_rules, $fixed_heading_anchor;
  97  
  98      $lines = explode("\n", $source);
  99      $count = count($lines);
 100  
 101      $modify    = TRUE;
 102      $multiline = 0;
 103      $matches   = array();
 104      for ($i = 0; $i < $count; $i++) {
 105          $line = & $lines[$i]; // Modify directly
 106  
 107          // Ignore null string and preformatted texts
 108          if ($line == '' || $line{0} == ' ' || $line{0} == "\t") continue;
 109  
 110          // Modify this line?
 111          if ($modify) {
 112              if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK &&
 113                  $multiline == 0 &&
 114                  preg_match('/#[^{]*(\{\{+)\s*$/', $line, $matches)) {
 115                      // Multiline convert plugin start
 116                  $modify    = FALSE;
 117                  $multiline = strlen($matches[1]); // Set specific number
 118              }
 119          } else {
 120              if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK &&
 121                  $multiline != 0 &&
 122                  preg_match('/^\}{' . $multiline . '}\s*$/', $line)) {
 123                      // Multiline convert plugin end
 124                  $modify    = TRUE;
 125                  $multiline = 0;
 126              }
 127          }
 128          if ($modify === FALSE) continue;
 129  
 130          // Replace with $str_rules
 131          foreach ($str_rules as $pattern => $replacement)
 132              $line = preg_replace('/' . $pattern . '/', $replacement, $line);
 133          
 134          // Adding fixed anchor into headings
 135          if ($fixed_heading_anchor &&
 136              preg_match('/^(\*{1,3}.*?)(?:\[#([A-Za-z][\w-]*)\]\s*)?$/', $line, $matches) &&
 137              (! isset($matches[2]) || $matches[2] == '')) {
 138              // Generate unique id
 139              $anchor = generate_fixed_heading_anchor_id($matches[1]);
 140              $line = rtrim($matches[1]) . ' [#' . $anchor . ']';
 141          }
 142      }
 143  
 144      // Multiline part has no stopper
 145      if (! PKWKEXP_DISABLE_MULTILINE_PLUGIN_HACK &&
 146          $modify === FALSE && $multiline != 0)
 147          $lines[] = str_repeat('}', $multiline);
 148  
 149      return implode("\n", $lines);
 150  }
 151  
 152  // Generate ID
 153  function generate_fixed_heading_anchor_id($seed)
 154  {
 155      // A random alphabetic letter + 7 letters of random strings from md()
 156      return chr(mt_rand(ord('a'), ord('z'))) .
 157          substr(md5(uniqid(substr($seed, 0, 100), TRUE)),
 158          mt_rand(0, 24), 7);
 159  }
 160  
 161  // Read top N lines as an array
 162  // (Use PHP file() function if you want to get ALL lines)
 163  function file_head($file, $count = 1, $lock = TRUE, $buffer = 8192)
 164  {
 165      $array = array();
 166  
 167      $fp = @fopen($file, 'r');
 168      if ($fp === FALSE) return FALSE;
 169      set_file_buffer($fp, 0);
 170      if ($lock) flock($fp, LOCK_SH);
 171      rewind($fp);
 172      $index = 0;
 173      while (! feof($fp)) {
 174          $line = fgets($fp, $buffer);
 175          if ($line != FALSE) $array[] = $line;
 176          if (++$index >= $count) break;
 177      }
 178      if ($lock) flock($fp, LOCK_UN);
 179      if (! fclose($fp)) return FALSE;
 180  
 181      return $array;
 182  }
 183  
 184  // Output to a file
 185  function file_write($dir, $page, $str, $notimestamp = FALSE)
 186  {
 187      global $_msg_invalidiwn, $notify, $notify_diff_only, $notify_subject;
 188      global $whatsdeleted, $maxshow_deleted;
 189  
 190      if (PKWK_READONLY) return; // Do nothing
 191      if ($dir != DATA_DIR && $dir != DIFF_DIR) die('file_write(): Invalid directory');
 192  
 193      $page = strip_bracket($page);
 194      $file = $dir . encode($page) . '.txt';
 195      $file_exists = file_exists($file);
 196  
 197      // ----
 198      // Delete?
 199  
 200      if ($dir == DATA_DIR && $str === '') {
 201          // Page deletion
 202          if (! $file_exists) return; // Ignore null posting for DATA_DIR
 203  
 204          // Update RecentDeleted (Add the $page)
 205          add_recent($page, $whatsdeleted, '', $maxshow_deleted);
 206  
 207          // Remove the page
 208          unlink($file);
 209  
 210          // Update RecentDeleted, and remove the page from RecentChanges
 211          lastmodified_add($whatsdeleted, $page);
 212  
 213          // Clear is_page() cache
 214          is_page($page, TRUE);
 215  
 216          return;
 217  
 218      } else if ($dir == DIFF_DIR && $str === " \n") {
 219          return; // Ignore null posting for DIFF_DIR
 220      }
 221  
 222      // ----
 223      // File replacement (Edit)
 224  
 225      if (! is_pagename($page))
 226          die_message(str_replace('$1', htmlspecialchars($page),
 227                      str_replace('$2', 'WikiName', $_msg_invalidiwn)));
 228  
 229      $str = rtrim(preg_replace('/' . "\r" . '/', '', $str)) . "\n";
 230      $timestamp = ($file_exists && $notimestamp) ? filemtime($file) : FALSE;
 231  
 232      $fp = fopen($file, 'a') or die('fopen() failed: ' .
 233          htmlspecialchars(basename($dir) . '/' . encode($page) . '.txt') .    
 234          '<br />' . "\n" .
 235          'Maybe permission is not writable or filename is too long');
 236      set_file_buffer($fp, 0);
 237      flock($fp, LOCK_EX);
 238      ftruncate($fp, 0);
 239      rewind($fp);
 240      fputs($fp, $str);
 241      flock($fp, LOCK_UN);
 242      fclose($fp);
 243  
 244      if ($timestamp) pkwk_touch_file($file, $timestamp);
 245  
 246      // Optional actions
 247      if ($dir == DATA_DIR) {
 248          // Update RecentChanges (Add or renew the $page)
 249          if ($timestamp === FALSE) lastmodified_add($page);
 250  
 251          // Command execution per update
 252          if (defined('PKWK_UPDATE_EXEC') && PKWK_UPDATE_EXEC)
 253              system(PKWK_UPDATE_EXEC . ' > /dev/null &');
 254  
 255      } else if ($dir == DIFF_DIR && $notify) {
 256          if ($notify_diff_only) $str = preg_replace('/^[^-+].*\n/m', '', $str);
 257          $footer['ACTION'] = 'Page update';
 258          $footer['PAGE']   = & $page;
 259          $footer['URI']    = get_script_uri() . '?' . rawurlencode($page);
 260          $footer['USER_AGENT']  = TRUE;
 261          $footer['REMOTE_ADDR'] = TRUE;
 262          pkwk_mail_notify($notify_subject, $str, $footer) or
 263              die('pkwk_mail_notify(): Failed');
 264      }
 265  
 266      is_page($page, TRUE); // Clear is_page() cache
 267  }
 268  
 269  // Update RecentDeleted
 270  function add_recent($page, $recentpage, $subject = '', $limit = 0)
 271  {
 272      if (PKWK_READONLY || $limit == 0 || $page == '' || $recentpage == '' ||
 273          check_non_list($page)) return;
 274  
 275      // Load
 276      $lines = $matches = array();
 277      foreach (get_source($recentpage) as $line)
 278          if (preg_match('/^-(.+) - (\[\[.+\]\])$/', $line, $matches))
 279              $lines[$matches[2]] = $line;
 280  
 281      $_page = '[[' . $page . ']]';
 282  
 283      // Remove a report about the same page
 284      if (isset($lines[$_page])) unset($lines[$_page]);
 285  
 286      // Add
 287      array_unshift($lines, '-' . format_date(UTIME) . ' - ' . $_page .
 288          htmlspecialchars($subject) . "\n");
 289  
 290      // Get latest $limit reports
 291      $lines = array_splice($lines, 0, $limit);
 292  
 293      // Update
 294      $fp = fopen(get_filename($recentpage), 'w') or
 295          die_message('Cannot write page file ' .
 296          htmlspecialchars($recentpage) .
 297          '<br />Maybe permission is not writable or filename is too long');
 298      set_file_buffer($fp, 0);
 299      flock($fp, LOCK_EX);
 300      rewind($fp);
 301      fputs($fp, '#freeze'    . "\n");
 302      fputs($fp, '#norelated' . "\n"); // :)
 303      fputs($fp, join('', $lines));
 304      flock($fp, LOCK_UN);
 305      fclose($fp);
 306  }
 307  
 308  // Update PKWK_MAXSHOW_CACHE itself (Add or renew about the $page) (Light)
 309  // Use without $autolink
 310  function lastmodified_add($update = '', $remove = '')
 311  {
 312      global $maxshow, $whatsnew, $autolink;
 313  
 314      // AutoLink implimentation needs everything, for now
 315      if ($autolink) {
 316          put_lastmodified(); // Try to (re)create ALL
 317          return;
 318      }
 319  
 320      if (($update == '' || check_non_list($update)) && $remove == '')
 321          return; // No need
 322  
 323      $file = CACHE_DIR . PKWK_MAXSHOW_CACHE;
 324      if (! file_exists($file)) {
 325          put_lastmodified(); // Try to (re)create ALL
 326          return;
 327      }
 328  
 329      // Open
 330      pkwk_touch_file($file);
 331      $fp = fopen($file, 'r+') or
 332          die_message('Cannot open ' . 'CACHE_DIR/' . PKWK_MAXSHOW_CACHE);
 333      set_file_buffer($fp, 0);
 334      flock($fp, LOCK_EX);
 335  
 336      // Read (keep the order of the lines)
 337      $recent_pages = $matches = array();
 338      foreach(file_head($file, $maxshow + PKWK_MAXSHOW_ALLOWANCE, FALSE) as $line)
 339          if (preg_match('/^([0-9]+)\t(.+)/', $line, $matches))
 340              $recent_pages[$matches[2]] = $matches[1];
 341  
 342      // Remove if it exists inside
 343      if (isset($recent_pages[$update])) unset($recent_pages[$update]);
 344      if (isset($recent_pages[$remove])) unset($recent_pages[$remove]);
 345  
 346      // Add to the top: like array_unshift()
 347      if ($update != '')
 348          $recent_pages = array($update => get_filetime($update)) + $recent_pages;
 349  
 350      // Check
 351      $abort = count($recent_pages) < $maxshow;
 352  
 353      if (! $abort) {
 354          // Write
 355          ftruncate($fp, 0);
 356          rewind($fp);
 357          foreach ($recent_pages as $_page=>$time)
 358              fputs($fp, $time . "\t" . $_page . "\n");
 359      }
 360  
 361      flock($fp, LOCK_UN);
 362      fclose($fp);
 363  
 364      if ($abort) {
 365          put_lastmodified(); // Try to (re)create ALL
 366          return;
 367      }
 368  
 369  
 370  
 371      // ----
 372      // Update the page 'RecentChanges'
 373  
 374      $recent_pages = array_splice($recent_pages, 0, $maxshow);
 375      $file = get_filename($whatsnew);
 376  
 377      // Open
 378      pkwk_touch_file($file);
 379      $fp = fopen($file, 'r+') or
 380          die_message('Cannot open ' . htmlspecialchars($whatsnew));
 381      set_file_buffer($fp, 0);
 382      flock($fp, LOCK_EX);
 383  
 384      // Recreate
 385      ftruncate($fp, 0);
 386      rewind($fp);
 387      foreach ($recent_pages as $_page=>$time)
 388          fputs($fp, '-' . htmlspecialchars(format_date($time)) .
 389              ' - ' . '[[' . htmlspecialchars($_page) . ']]' . "\n");
 390      fputs($fp, '#norelated' . "\n"); // :)
 391  
 392      flock($fp, LOCK_UN);
 393      fclose($fp);
 394  }
 395  
 396  // Re-create PKWK_MAXSHOW_CACHE (Heavy)
 397  function put_lastmodified()
 398  {
 399      global $maxshow, $whatsnew, $autolink;
 400  
 401      if (PKWK_READONLY) return; // Do nothing
 402  
 403      // Get WHOLE page list
 404      $pages = get_existpages();
 405  
 406      // Check ALL filetime
 407      $recent_pages = array();
 408      foreach($pages as $page)
 409          if ($page != $whatsnew && ! check_non_list($page))
 410              $recent_pages[$page] = get_filetime($page);
 411  
 412      // Sort decending order of last-modification date
 413      arsort($recent_pages, SORT_NUMERIC);
 414  
 415      // Cut unused lines
 416      // BugTrack2/179: array_splice() will break integer keys in hashtable
 417      $count   = $maxshow + PKWK_MAXSHOW_ALLOWANCE;
 418      $_recent = array();
 419      foreach($recent_pages as $key=>$value) {
 420          unset($recent_pages[$key]);
 421          $_recent[$key] = $value;
 422          if (--$count < 1) break;
 423      }
 424      $recent_pages = & $_recent;
 425  
 426      // Re-create PKWK_MAXSHOW_CACHE
 427      $file = CACHE_DIR . PKWK_MAXSHOW_CACHE;
 428      pkwk_touch_file($file);
 429      $fp = fopen($file, 'r+') or
 430          die_message('Cannot open' . 'CACHE_DIR/' . PKWK_MAXSHOW_CACHE);
 431      set_file_buffer($fp, 0);
 432      flock($fp, LOCK_EX);
 433      ftruncate($fp, 0);
 434      rewind($fp);
 435      foreach ($recent_pages as $page=>$time)
 436          fputs($fp, $time . "\t" . $page . "\n");
 437      flock($fp, LOCK_UN);
 438      fclose($fp);
 439  
 440      // Create RecentChanges
 441      $file = get_filename($whatsnew);
 442      pkwk_touch_file($file);
 443      $fp = fopen($file, 'r+') or
 444          die_message('Cannot open ' . htmlspecialchars($whatsnew));
 445      set_file_buffer($fp, 0);
 446      flock($fp, LOCK_EX);
 447      ftruncate($fp, 0);
 448      rewind($fp);
 449      foreach (array_keys($recent_pages) as $page) {
 450          $time      = $recent_pages[$page];
 451          $s_lastmod = htmlspecialchars(format_date($time));
 452          $s_page    = htmlspecialchars($page);
 453          fputs($fp, '-' . $s_lastmod . ' - [[' . $s_page . ']]' . "\n");
 454      }
 455      fputs($fp, '#norelated' . "\n"); // :)
 456      flock($fp, LOCK_UN);
 457      fclose($fp);
 458  
 459      // For AutoLink
 460      if ($autolink) {
 461          list($pattern, $pattern_a, $forceignorelist) =
 462              get_autolink_pattern($pages);
 463  
 464          $file = CACHE_DIR . PKWK_AUTOLINK_REGEX_CACHE;
 465          pkwk_touch_file($file);
 466          $fp = fopen($file, 'r+') or
 467              die_message('Cannot open ' . 'CACHE_DIR/' . PKWK_AUTOLINK_REGEX_CACHE);
 468          set_file_buffer($fp, 0);
 469          flock($fp, LOCK_EX);
 470          ftruncate($fp, 0);
 471          rewind($fp);
 472          fputs($fp, $pattern   . "\n");
 473          fputs($fp, $pattern_a . "\n");
 474          fputs($fp, join("\t", $forceignorelist) . "\n");
 475          flock($fp, LOCK_UN);
 476          fclose($fp);
 477      }
 478  }
 479  
 480  // Get elapsed date of the page
 481  function get_pg_passage($page, $sw = TRUE)
 482  {
 483      global $show_passage;
 484      if (! $show_passage) return '';
 485  
 486      $time = get_filetime($page);
 487      $pg_passage = ($time != 0) ? get_passage($time) : '';
 488  
 489      return $sw ? '<small>' . $pg_passage . '</small>' : ' ' . $pg_passage;
 490  }
 491  
 492  // Last-Modified header
 493  function header_lastmod($page = NULL)
 494  {
 495      global $lastmod;
 496  
 497      if ($lastmod && is_page($page)) {
 498          pkwk_headers_sent();
 499          header('Last-Modified: ' .
 500              date('D, d M Y H:i:s', get_filetime($page)) . ' GMT');
 501      }
 502  }
 503  
 504  // Get a page list of this wiki
 505  function get_existpages($dir = DATA_DIR, $ext = '.txt')
 506  {
 507      $aryret = array();
 508  
 509      $pattern = '((?:[0-9A-F]{2})+)';
 510      if ($ext != '') $ext = preg_quote($ext, '/');
 511      $pattern = '/^' . $pattern . $ext . '$/';
 512  
 513      $dp = @opendir($dir) or
 514          die_message($dir . ' is not found or not readable.');
 515      $matches = array();
 516      while ($file = readdir($dp))
 517          if (preg_match($pattern, $file, $matches))
 518              $aryret[$file] = decode($matches[1]);
 519      closedir($dp);
 520  
 521      return $aryret;
 522  }
 523  
 524  // Get PageReading(pronounce-annotated) data in an array()
 525  function get_readings()
 526  {
 527      global $pagereading_enable, $pagereading_kanji2kana_converter;
 528      global $pagereading_kanji2kana_encoding, $pagereading_chasen_path;
 529      global $pagereading_kakasi_path, $pagereading_config_page;
 530      global $pagereading_config_dict;
 531  
 532      $pages = get_existpages();
 533  
 534      $readings = array();
 535      foreach ($pages as $page) 
 536          $readings[$page] = '';
 537  
 538      $deletedPage = FALSE;
 539      $matches = array();
 540      foreach (get_source($pagereading_config_page) as $line) {
 541          $line = chop($line);
 542          if(preg_match('/^-\[\[([^]]+)\]\]\s+(.+)$/', $line, $matches)) {
 543              if(isset($readings[$matches[1]])) {
 544                  // This page is not clear how to be pronounced
 545                  $readings[$matches[1]] = $matches[2];
 546              } else {
 547                  // This page seems deleted
 548                  $deletedPage = TRUE;
 549              }
 550          }
 551      }
 552  
 553      // If enabled ChaSen/KAKASI execution
 554      if($pagereading_enable) {
 555  
 556          // Check there's non-clear-pronouncing page
 557          $unknownPage = FALSE;
 558          foreach ($readings as $page => $reading) {
 559              if($reading == '') {
 560                  $unknownPage = TRUE;
 561                  break;
 562              }
 563          }
 564  
 565          // Execute ChaSen/KAKASI, and get annotation
 566          if($unknownPage) {
 567              switch(strtolower($pagereading_kanji2kana_converter)) {
 568              case 'chasen':
 569                  if(! file_exists($pagereading_chasen_path))
 570                      die_message('ChaSen not found: ' . $pagereading_chasen_path);
 571  
 572                  $tmpfname = tempnam(realpath(CACHE_DIR), 'PageReading');
 573                  $fp = fopen($tmpfname, 'w') or
 574                      die_message('Cannot write temporary file "' . $tmpfname . '".' . "\n");
 575                  foreach ($readings as $page => $reading) {
 576                      if($reading != '') continue;
 577                      fputs($fp, mb_convert_encoding($page . "\n",
 578                          $pagereading_kanji2kana_encoding, SOURCE_ENCODING));
 579                  }
 580                  fclose($fp);
 581  
 582                  $chasen = "$pagereading_chasen_path -F %y $tmpfname";
 583                  $fp     = popen($chasen, 'r');
 584                  if($fp === FALSE) {
 585                      unlink($tmpfname);
 586                      die_message('ChaSen execution failed: ' . $chasen);
 587                  }
 588                  foreach ($readings as $page => $reading) {
 589                      if($reading != '') continue;
 590  
 591                      $line = fgets($fp);
 592                      $line = mb_convert_encoding($line, SOURCE_ENCODING,
 593                          $pagereading_kanji2kana_encoding);
 594                      $line = chop($line);
 595                      $readings[$page] = $line;
 596                  }
 597                  pclose($fp);
 598  
 599                  unlink($tmpfname) or
 600                      die_message('Temporary file can not be removed: ' . $tmpfname);
 601                  break;
 602  
 603              case 'kakasi':    /*FALLTHROUGH*/
 604              case 'kakashi':
 605                  if(! file_exists($pagereading_kakasi_path))
 606                      die_message('KAKASI not found: ' . $pagereading_kakasi_path);
 607  
 608                  $tmpfname = tempnam(realpath(CACHE_DIR), 'PageReading');
 609                  $fp       = fopen($tmpfname, 'w') or
 610                      die_message('Cannot write temporary file "' . $tmpfname . '".' . "\n");
 611                  foreach ($readings as $page => $reading) {
 612                      if($reading != '') continue;
 613                      fputs($fp, mb_convert_encoding($page . "\n",
 614                          $pagereading_kanji2kana_encoding, SOURCE_ENCODING));
 615                  }
 616                  fclose($fp);
 617  
 618                  $kakasi = "$pagereading_kakasi_path -kK -HK -JK < $tmpfname";
 619                  $fp     = popen($kakasi, 'r');
 620                  if($fp === FALSE) {
 621                      unlink($tmpfname);
 622                      die_message('KAKASI execution failed: ' . $kakasi);
 623                  }
 624  
 625                  foreach ($readings as $page => $reading) {
 626                      if($reading != '') continue;
 627  
 628                      $line = fgets($fp);
 629                      $line = mb_convert_encoding($line, SOURCE_ENCODING,
 630                          $pagereading_kanji2kana_encoding);
 631                      $line = chop($line);
 632                      $readings[$page] = $line;
 633                  }
 634                  pclose($fp);
 635  
 636                  unlink($tmpfname) or
 637                      die_message('Temporary file can not be removed: ' . $tmpfname);
 638                  break;
 639  
 640              case 'none':
 641                  $patterns = $replacements = $matches = array();
 642                  foreach (get_source($pagereading_config_dict) as $line) {
 643                      $line = chop($line);
 644                      if(preg_match('|^ /([^/]+)/,\s*(.+)$|', $line, $matches)) {
 645                          $patterns[]     = $matches[1];
 646                          $replacements[] = $matches[2];
 647                      }
 648                  }
 649                  foreach ($readings as $page => $reading) {
 650                      if($reading != '') continue;
 651  
 652                      $readings[$page] = $page;
 653                      foreach ($patterns as $no => $pattern)
 654                          $readings[$page] = mb_convert_kana(mb_ereg_replace($pattern,
 655                              $replacements[$no], $readings[$page]), 'aKCV');
 656                  }
 657                  break;
 658  
 659              default:
 660                  die_message('Unknown kanji-kana converter: ' . $pagereading_kanji2kana_converter . '.');
 661                  break;
 662              }
 663          }
 664  
 665          if($unknownPage || $deletedPage) {
 666  
 667              asort($readings); // Sort by pronouncing(alphabetical/reading) order
 668              $body = '';
 669              foreach ($readings as $page => $reading)
 670                  $body .= '-[[' . $page . ']] ' . $reading . "\n";
 671  
 672              page_write($pagereading_config_page, $body);
 673          }
 674      }
 675  
 676      // Pages that are not prounouncing-clear, return pagenames of themselves
 677      foreach ($pages as $page) {
 678          if($readings[$page] == '')
 679              $readings[$page] = $page;
 680      }
 681  
 682      return $readings;
 683  }
 684  
 685  // Get a list of encoded files (must specify a directory and a suffix)
 686  function get_existfiles($dir, $ext)
 687  {
 688      $pattern = '/^(?:[0-9A-F]{2})+' . preg_quote($ext, '/') . '$/';
 689      $aryret = array();
 690      $dp = @opendir($dir) or die_message($dir . ' is not found or not readable.');
 691      while ($file = readdir($dp))
 692          if (preg_match($pattern, $file))
 693              $aryret[] = $dir . $file;
 694      closedir($dp);
 695      return $aryret;
 696  }
 697  
 698  // Get a list of related pages of the page
 699  function links_get_related($page)
 700  {
 701      global $vars, $related;
 702      static $links = array();
 703  
 704      if (isset($links[$page])) return $links[$page];
 705  
 706      // If possible, merge related pages generated by make_link()
 707      $links[$page] = ($page == $vars['page']) ? $related : array();
 708  
 709      // Get repated pages from DB
 710      $links[$page] += links_get_related_db($vars['page']);
 711  
 712      return $links[$page];
 713  }
 714  
 715  // _If needed_, re-create the file to change/correct ownership into PHP's
 716  // NOTE: Not works for Windows
 717  function pkwk_chown($filename, $preserve_time = TRUE)
 718  {
 719      static $php_uid; // PHP's UID
 720  
 721      if (! isset($php_uid)) {
 722          if (extension_loaded('posix')) {
 723              $php_uid = posix_getuid(); // Unix
 724          } else {
 725              $php_uid = 0; // Windows
 726          }
 727      }
 728  
 729      // Lock for pkwk_chown()
 730      $lockfile = CACHE_DIR . 'pkwk_chown.lock';
 731      $flock = fopen($lockfile, 'a') or
 732          die('pkwk_chown(): fopen() failed for: CACHEDIR/' .
 733              basename(htmlspecialchars($lockfile)));
 734      flock($flock, LOCK_EX) or die('pkwk_chown(): flock() failed for lock');
 735  
 736      // Check owner
 737      $stat = stat($filename) or
 738          die('pkwk_chown(): stat() failed for: '  . basename(htmlspecialchars($filename)));
 739      if ($stat[4] === $php_uid) {
 740          // NOTE: Windows always here
 741          $result = TRUE; // Seems the same UID. Nothing to do
 742      } else {
 743          $tmp = $filename . '.' . getmypid() . '.tmp';
 744  
 745          // Lock source $filename to avoid file corruption
 746          // NOTE: Not 'r+'. Don't check write permission here
 747          $ffile = fopen($filename, 'r') or
 748              die('pkwk_chown(): fopen() failed for: ' .
 749                  basename(htmlspecialchars($filename)));
 750  
 751          // Try to chown by re-creating files
 752          // NOTE:
 753          //   * touch() before copy() is for 'rw-r--r--' instead of 'rwxr-xr-x' (with umask 022).
 754          //   * (PHP 4 < PHP 4.2.0) touch() with the third argument is not implemented and retuns NULL and Warn.
 755          //   * @unlink() before rename() is for Windows but here's for Unix only
 756          flock($ffile, LOCK_EX) or die('pkwk_chown(): flock() failed');
 757          $result = touch($tmp) && copy($filename, $tmp) &&
 758              ($preserve_time ? (touch($tmp, $stat[9], $stat[8]) || touch($tmp, $stat[9])) : TRUE) &&
 759              rename($tmp, $filename);
 760          flock($ffile, LOCK_UN) or die('pkwk_chown(): flock() failed');
 761  
 762          fclose($ffile) or die('pkwk_chown(): fclose() failed');
 763  
 764          if ($result === FALSE) @unlink($tmp);
 765      }
 766  
 767      // Unlock for pkwk_chown()
 768      flock($flock, LOCK_UN) or die('pkwk_chown(): flock() failed for lock');
 769      fclose($flock) or die('pkwk_chown(): fclose() failed for lock');
 770  
 771      return $result;
 772  }
 773  
 774  // touch() with trying pkwk_chown()
 775  function pkwk_touch_file($filename, $time = FALSE, $atime = FALSE)
 776  {
 777      // Is the owner incorrected and unable to correct?
 778      if (! file_exists($filename) || pkwk_chown($filename)) {
 779          if ($time === FALSE) {
 780              $result = touch($filename);
 781          } else if ($atime === FALSE) {
 782              $result = touch($filename, $time);
 783          } else {
 784              $result = touch($filename, $time, $atime);
 785          }
 786          return $result;
 787      } else {
 788          die('pkwk_touch_file(): Invalid UID and (not writable for the directory or not a flie): ' .
 789              htmlspecialchars(basename($filename)));
 790      }
 791  }
 792  ?>

title

Description

title

Description

title

Description

title

title

Body