PlomWiki: Zur Start-Seite Suche Letzte Änderungen (Feed) Letzte Kommentare (Feed)
Impressum Datenschutz-Erklärung

AutoLink2SourceCodeV0-4

Ansicht Bearbeiten Anzeige-Titel setzen Versions-Geschichte Seiten-Passwort setzen AutoLink-Anzeige ein-/ausschalten
<?php if (!defined('PmWiki')) exit(); 
/*  
Autolink2 version 0.4 / a PmWiki plug-in by Christian Heller / www.plomlompom.de 
Inspired by Karl Loncarek's http://www.pmwiki.org/wiki/Cookbook/AutomaticLinks 
 
This program is free software; you can redistribute it and/or modify it under 
the terms of the GNU General Public License as published by the Free Software  
Foundation; either version 2 of the License, or (at your option) any later 
version. 
 
WHAT THIS DOES 
 
Automatically links phrases in PmWiki page texts to pages in the same wiki group 
that have a sufficiently similar name, giving a (user-definable) tolerance 
towards flexible word part endings, umlauts and case insensitivity.  
 
Autolink does not alter the page text itself, only adds the links during and for 
the page display. 
 
Also provides "(:autolink backlinks:)" PmWiki directive outputting a link list 
of pages linkink back to the current page in the automatic way just described. 
 
INSTALLATION / ACTIVATION 
 
Copy this file into your cookbook/ directory and add this line to the config 
file of the page group for which you want to activate the plug-in: 
 
      include_once("$FarmD/cookbook/autolink2.php"); AutolinkActivate(); 
 
The next time a page from that group gets loaded, initial database generation 
starts. Until this is finished, no page display will happen for said group. 
Depending on your PHP's max_execution_time and the size of your wiki, the 
process won't be finished in a single try; reload until it is.  
 
(As a rough estimate: For my own wiki of 1000+ pages and max_execution_time of  
30 seconds, I need about 10 reloads.) To avoid collision of several parallel  
dabatase manipulation processes, page reloads won't resume the work earlier than 
$AutolinkTimeExceed seconds after the last one started. 
 
TECHNICAL OVERVIEW 
 
Autolink's database consists of the directories and files below $AutolinkDir. 
Each wiki group gets its own sub-directory, which contains files on each page of 
that group except those listed in $AutolinkBannedPages. 
 
Each such file entry contains three lines. The 1st contains a regex to match the 
page's name. The 2nd contains the autolinks-out: pagenames whose regexes match 
the page's text. The 3rd contains the autolinks-in: names of pages the texts of 
which contain matches to the regex from the 1st line. 
 
On each page display, AutolinkMarkup() reads the autolinks-out from a page's  
file; pulls the regexes of those pagenames from the files on their pages; and  
creates PmWiki markups mutating those regexes matches in the page text into HTML 
linking to their respective pages. 
 
The latter is done with the help of AutolinkSet(). It has some text analysis and 
decision-making built-in to determine which pagename from $AutolinksOut is to be 
linked for a given string, since it's entirely plausible that one string could 
fit the regexes of several pagenames. 
 
Additionally, AutolinkMarkup() -- by help of AutolinkGetBacklinksString() -- 
builds a PmWiki markup translating the string "(:autolink_backlinks:)" into a 
HTML list of links to the pagenames in the autolinks-in line of the page's file. 
 
Before any page display occurs, AutolinkActivate() looks for $AutolinkWorklist, 
containing Autolink database manipulation tasks for AutolinkWorklist(). Each 
task is determined by its own line, which consists of the name of the page to be 
manipulated preceded by a "+" (create entry) or "-" (remove entry). 
 
Tasks are added during the initial database creation and by any further page 
creation, deletion and update (simply performed as the deletion of an entry 
followed by its re-creation). Finished tasks get commented out by a "#". Once  
all jobs are commented out, $AutolinkWorklist gets deleted. 
 
This process may be aborted any time and resumed by the next page load. A lock 
file ensures that only one process works on the database at any time, to avoid 
data corruption. It contains a timestamp and will be ignored if it's older than 
$AutolinkTimeExceed (ideally larger than server's $max_execution_time) seconds. 
 
Entry creation involves AutolinkCreateRegex(), containing most of Autolink's 
design choices on what to autolink and what not. Both entry creation and removal 
affect not only the files of the pages on which they are called, but also of 
those to which they are found out to link with via AutolinkLinkPages(). 
 
ISSUES / BUGS 
 
* Pagenames must be ASCII-only. Page texts are assumed to be ASCII or UTF-8. 
  Multibyte string support is supposed to be enabled in your PHP installation. 
 
* On a page display, any tolerant matches to pagenames in the page's  
  $AutolinksOut get autolinked -- including stuff outside of the actual page  
  text, like the page title. Nevertheless, only the page text gets searched for 
  pagename regular expression matches when $AutolinksOut gets generated. Thus, 
  expect inconsistent auto-linking outside of the page text. 
 
* Although $AutolinkGapsToAllowLong can be used for multi-character gaps, do not 
  expect HTML entities like "&amp;" for "&" to work right away. PmWiki seems to 
  internally encode them differently at different stages. Must research further. 
 
WEBSITE 
 
For more info, see: http://www.plomlompom.de/wiki/pmwiki.php?n=Mind.AutoLink2 */ 
 
#################################### 
#                                  # 
#   g e n e r a l      s t u f f   # 
#                                  # 
#################################### 
 
############################### 
#   common global variables   # 
############################### 
 
# Class attribute for HTML <a> tag of autolinks. Use for fancy CSS games. 
$AutolinkClass = 'autolink'; 
 
# Relevant for pattern generation and translation, esp. AutolinkGenerateRegex(). 
$AutolinkMinimalRoot = 4;           # Minimum unchanged chars at pattern start. 
$AutolinkSuffixTolerance = 3;       # Leeway to give at pattern part ends. 
$AutolinkGapsToAllowEasy = ' .,:;'; # What to allow between pattern parts. 
$AutolinkGapsToAllowLong = array(); # Long: multi-char. Hard: need escape char. 
$AutolinkGapsToAllowHard = array('\'', '/', '\\', '(', ')', '[', ']'); 
$AutolinkUmlautTable = array('äÄ' => array('ae', 'Ae'), # Pattern knowledge 
                             'öÖ' => array('oe', 'Oe'), # about possible umlaut 
                             'üÜ' => array('ue', 'Ue'), # transliterations. 
                             'ß'  => array('ss'));      # Feel free to add. 
$AutolinkEncoding = 'UTF-8'; 
 
# Don't autolink on or to these pages. (System and other problematical pages.) 
$AutolinkBannedPages = array('RecentChanges', 
                             'GroupHeader', 
                             'GroupFooter', 
                             'PageActions'); 
 
# Group and name part of the current $pagename. 
list($AutolinkGroupname,$AutolinkPagename) = AutolinkDivideGroupName($pagename); 
 
# Various filesystem variables. 
$AutolinkDir = $WorkDir.'/autolink-data'; 
$AutolinkGroupDir = $AutolinkDir.'/'.$AutolinkGroupname; 
$AutolinkPath = $AutolinkGroupDir.'/'.$AutolinkPagename; 
$AutolinkWorklist = $AutolinkDir.'/Worklist.'.$AutolinkGroupname; 
 
# This will be populated by AutolinkActivate(). 
$AutolinksOut = array(); 
 
# Minimum wait time before AutolinkWorklist() can ignore a timestamped lock. 
$AutolinkTimeExceed = 60; 
 
###################### 
#   initialization   # 
###################### 
 
function AutolinkActivate() 
# Initialization to go through each page view. Call this in your config file. 
{ global $action, $AutolinkBannedPages, $AutolinkGroupDir, $AutolinkPath,  
                                              $AutolinkWorklist, $EditFunctions; 
 
  # If no DB directory is found, build a DB creation worklist. 
  if (!is_dir($AutolinkGroupDir)) AutolinkStartDb();  
 
  # Check for $AutolinkWorklist. If found, work through it. Will reload page. 
  if (is_file($AutolinkWorklist))  
  { echo 'Autolink2 working on its database. Execution time exceeded? Reload! '; 
    AutolinkWorklist(); } 
 
  # Splice Autolink DB manipulation stuff into $EditFunctions. 
  $position_PostPage = array_search('PostPage', $EditFunctions); 
  array_splice($EditFunctions, $position_PostPage + 1, 0, 'AutolinkUpdateDb'); 
 
  # Don't do anything further if there's no Autolink file for the page displayed 
  # or it belongs to $AutolinkBanned Pages or we aren't just browsing passively. 
  if (!is_file($AutolinkPath)  
      or in_array($AutolinkPagename, $AutolinkBannedPages) 
      or ($action != 'browse'))  
    return; 
 
  # Create and add to PmWiki's markup chain page-specific Autolink markups. 
  AutolinkMarkup(); } 
 
 
 
############################### 
#   common helper functions   # 
############################### 
 
function AutolinkDivideGroupName($filename) 
# Divide a PmWiki pagefile name into the group and the name part. 
{ $dot_position = strpos($filename, '.'); 
  return array(substr($filename, 0, $dot_position),  
                                          substr($filename, $dot_position+1)); } 
 
 
 
function AutolinkGetRegexFromFile($filename) 
# Get the regex saved in the first line of $filename in $AutolinkGroupDir. 
{ global $AutolinkGroupDir; 
  $p_file = fopen($AutolinkGroupDir.'/'.$filename, 'r'); 
  $regex = substr(fgets($p_file), 0, -1); 
  fclose($p_file); 
  return $regex; } 
 
 
 
function AutolinkGetTextField($pagename) 
# Get the content of the 'text=' field from a page referenced by $filename. 
{ global $WorkDir, $AutolinkGroupname; 
  $p_file = fopen($WorkDir.'/'.$AutolinkGroupname.'.'.$pagename, 'r'); 
  $TextFound = FALSE; 
  while (!feof($p_file) and !$TextFound) 
  { $line = fgets($p_file); 
    if (substr($line, 0, 5) == 'text=') $TextFound = TRUE; } 
  fclose($p_file); 
  return substr($line, 5); } 
 
 
 
##################################### 
#                                   # 
#   l i n k i n g   m a r k u p s   # 
#                                   # 
##################################### 
 
function AutolinkMarkup() 
# Create and add to PmWiki's markup chain page-specific autolinking markups. 
{ global $AutolinkPath, $AutolinksOut; 
 
  # Get $AutolinksOut from second line of the current page's Autolink DB file. 
  $p_file = fopen($AutolinkPath, 'r');  
  fgets($p_file);  
  $second_line = substr(fgets($p_file), 0, -1); # Strip line end's newline char. 
  $AutolinksOut = explode(',', $second_line);  
  fclose($p_file); 
 
  # For all $AutolinksOut, create markups regex-matching and linking pagenames. 
  # The best place in PmWiki's markup chain to slice them into: after 'restore'. 
  $old_markup = 'restore'; 
  foreach ($AutolinksOut as $linked_page) 
  { $new_markup = 'autolink-'.$linked_page; 
 
    # Build regex to match with Markup() from $regex_pagename. 
    $regex_pagename = AutolinkGetRegexFromFile($linked_page); 
    $regex_markup = '/('.$regex_pagename.')(?=[^>]*($|<(?!\/(a|script))))/ieu'; 
    # This is to make sure we don't catch  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    # 1) <tag value="any patterns inside HTML tag declarations" /> or  
    # 2) <a href=''>enclosed by "a"</a><script>or "script" tags</script>. 
    # REGEX DECIPHERMENT: Instead, only catch patterns that are ... 
    #     (?=             ... followed by ... 
    #     [^>]*           ... any number of signs not a '>' ... 
    #     ($|             ... until end of string or ... 
    #     <               ... until a '<' appears ... 
    #     (?!             ... that is not followed by ... 
    #     \/(a|script))   ... any '/a' or '/script' ... 
    #     ))              ... (closing parantheses) 
 
    # PmWiki's Markup() places $new_markup after $old_markup in its markup 
    # chain, matches $regex_markup and throws the result to AutolinkSet(). 
    Markup($new_markup, '>'.$old_markup, $regex_markup, 'AutolinkSet("$1")');  
    $old_markup = $new_markup; } 
   
  # (:autolink backlinks:) PmWiki markup, calling AutolinkGetBacklinksString(). 
  Markup('autolink_backlinks', '<nl0', '/\(:autolink backlinks:\)/e', 
                                        'Keep(AutolinkGetBacklinksString())'); } 
 
 
 
function AutolinkSet($pattern) 
# To the best pagename match for $pattern in $AutolinksOut, output a link. 
{ global $AutolinkClass, $AutolinkEncoding, $AutolinkGapsToAllowEasy,  
                $AutolinkGapsToAllowHard, $AutolinkGroupDir, $AutolinkGroupname, 
               $AutolinksOut, $AutolinkUmlautTable, $EnablePathInfo, $ScriptUrl; 
 
  # Create 3 $pattern versions: all de-umlauted, 2 lowercased, 1 sans hyphens. 
  $pattern_UmlautsNo = $pattern; 
  foreach ($AutolinkUmlautTable as $umlaut => $transl) 
  { $umlaut_lower = mb_substr($umlaut, 0, 1, $AutolinkEncoding); 
    $umlaut_upper = mb_substr($umlaut, 1, 1, $AutolinkEncoding); 
    $pattern_UmlautsNo = str_replace($umlaut_lower, $transl[0],  
                                                            $pattern_UmlautsNo); 
    if ($umlaut_upper != '') 
      $pattern_UmlautsNo = str_replace($umlaut_upper, $transl[1],  
                                                          $pattern_UmlautsNo); } 
  $pattern_HyphenYes =  
         strtolower(str_replace(array_merge(str_split($AutolinkGapsToAllowEasy), 
                            $AutolinkGapsToAllowHard), '', $pattern_UmlautsNo)); 
  $pattern_HyphenNo  = str_replace('-', '', $pattern_HyphenYes ); 
 
  # Search $AutolinksOut pagenames for char-precise, case-insensitive matches. 
  $val_max = 9000; 
  $page_matching = array(NULL, 0); 
  foreach ($AutolinksOut as $linked_pagename) 
  { 
    # If a hyphen-precise match is found, break with success. 
    $pagename_lower = strtolower($linked_pagename); 
    if ($pagename_lower == $pattern_HyphenYes) 
    { $page_matching[0] = $linked_pagename; 
      break; } 
 
    # First non-hyphen-precise match. Only to be beaten by a hyphen-precise one. 
    if ($page_matching[1] < $val_max) 
    { $pagename_HyphenNo = str_replace('-', '', $pagename_lower); 
      if ($pagename_HyphenNo == $pattern_HyphenNo) 
        $page_matching = array($linked_pagename, $val_max); } } 
 
  # Find the next-best, non-char-precise $regex match by levenshtein() ranking. 
  if ($page_matching[1] < $val_max) 
    foreach ($AutolinksOut as $linked_pagename) 
      if (strtolower($linked_pagename[0]) == strtolower($pattern_UmlautsNo[0])) 
      { $p_file = fopen($AutolinkGroupDir.'/'.$linked_pagename, 'r'); 
        $regex = substr(fgets($p_file), 0, -1); 
        if (preg_match('/'.$regex.'/iu', $pattern)) 
        { $similarity_score = $val_max - levenshtein($linked_pagename, $pattern, 
                                                                       1, 2, 1); 
          if ($similarity_score > $page_matching[1]) 
            $page_matching = array($linked_pagename, $similarity_score); } 
        fclose($p_file); } 
 
  # Output the formatted link to the best pagename match. 
  return '<a class="'.$AutolinkClass.'" href='. 
    ($EnablePathInfo ? $ScriptUrl.'/': $ScriptUrl.'?n=').$AutolinkGroupname.'.'. 
                                        $page_matching[0].'>'.$pattern.'</a>'; } 
 
 
 
function AutolinkGetBacklinksString() 
# Return a string of a list in HTML of Autolink backlinks to the current page. 
{ global $AutolinkGroupDir, $AutolinkPagename, $AutolinkGroupname; 
 
  $p_file = fopen($AutolinkGroupDir.'/'.$AutolinkPagename, 'r'); 
  fgets($p_file); 
  fgets($p_file); 
  $backlinks = explode(',', fgets($p_file)); 
  fclose($p_file); 
 
  $string_backlinks = '<ul>'; 
  foreach ($backlinks as $backlink)  
    $string_backlinks .= '<li><a href="pmwiki.php?n='.$AutolinkGroupname.'.'. 
                                           $backlink.'">'.$backlink.'</a></li>'; 
  $string_backlinks .= '</ul>'; 
 
  return $string_backlinks; } 
 
 
 
########################################################## 
#                                                        # 
#   r e g u l a r      e x p r e s s i o n     w o r k   # 
#                                                        # 
########################################################## 
 
function AutolinkGenerateRegex($pagename) 
# Generate the regular expression to match $pagename for autolinking in pages. 
{ global $AutolinkSuffixTolerance, $AutolinkMinimalRoot, $AutolinkUmlautTable, 
          $AutolinkEncoding, $AutolinkGapsToAllowEasy, $AutolinkGapsToAllowLong,  
                                                       $AutolinkGapsToAllowHard; 
 
  # Divide with "!" over hyphens; at digit vs. char; char followed by uppercase. 
  $regex = preg_replace(        '/(-+)/',           '!',   $pagename); 
  $regex = preg_replace(   '/([0-9])([A-Za-z])/', '$1!$2', $regex); 
  $regex = preg_replace('/([A-Za-z])([0-9])/',    '$1!$2', $regex); 
  $regex = preg_replace('/([A-Za-z])(?=[A-Z])/',  '$1!',   $regex); 
 
  # Umlauts to be allowed in the tolerances at regex part ends (see next step). 
  $legal_umlauts = ''; 
  foreach($AutolinkUmlautTable as $umlaut => $translation) 
    $legal_umlauts .= mb_substr($umlaut, 0, 1, $AutolinkEncoding); 
 
  # Build toleration for char additions or even changes, at regex part ends. 
  $regex_parts = explode('!', $regex); 
  $minimal_root = $AutolinkMinimalRoot; 
  foreach ($regex_parts as &$part) 
  { 
    # In non-numerical parts, see if changed ending chars can be tolerated. 
    if (strpos('0123456789', $part[0]) === FALSE) 
    {  
      # $ln_flexible: number of chars in string beyond $minimal_root. 
      $ln_part = strlen($part); 
      $ln_static = min($minimal_root, $ln_part); 
      $minimal_root -= $ln_static; 
      $ln_flexible = $ln_part - $ln_static; 
       
      # $replace_tolerance: largest-possible mirror of $AutolinkSuffixTolerance 
      # that fits into $ln_flexible and is not larger than 1/3 of $ln_part. 
      $replace_tolerance = $AutolinkSuffixTolerance; 
      while ($replace_tolerance > 0) 
      { if (($ln_flexible >= $replace_tolerance)  
                                       and ($ln_part >= 2 * $replace_tolerance)) 
        { $part = substr($part, 0, -$replace_tolerance); break; } 
        $replace_tolerance--; } 
 
      # To a possibly reduced $part, add tolerance => $AutolinkSuffixTolerance. 
      $tolerance_sum =  
                 min($ln_part, ($replace_tolerance + $AutolinkSuffixTolerance)); 
      $part .= '[a-z'.$legal_umlauts.']{0,'.$tolerance_sum.'}'; } 
     
    # In a numerical $part, just add tolerance of $AutolinkSuffixTolerance size. 
    else $part .= '[a-z'.$legal_umlauts.']{0,'.$AutolinkSuffixTolerance.'}'; } 
 
  # $gaps_to_allow: glue for $regex_parts. Integrate $AutolinkGapsToAllowEasy as 
  # is, $...Hard with escape chars and $...Long with their own "or" parantheses. 
  $gaps_to_allow = $AutolinkGapsToAllowEasy; 
  foreach ($AutolinkGapsToAllowHard as $char) 
    $gaps_to_allow .= '\\'.$char; 
  $gaps_to_allow = '['.$gaps_to_allow.'\-]'; 
  if (!empty($AutolinkGapsToAllowLong)) 
    $gaps_to_allow = 
          '(('.implode(')|(', $AutolinkGapsToAllowLong).')|'.$gaps_to_allow.')'; 
  $regex = implode($gaps_to_allow.'*', $regex_parts); 
 
  # Make regexes umlaut-cognitive according to $AutolinkUmlautTable. 
  foreach ($AutolinkUmlautTable as $umlaut => $transl) 
  {  
    # Slice uppercase and lowercase versions off $umlaut *multibyte-compatibly*. 
    $umlaut_lower = mb_substr($umlaut, 0, 1, $AutolinkEncoding); 
    $umlaut_upper = mb_substr($umlaut, 1, 1, $AutolinkEncoding); 
     
    # For any multi-char umlaut translation, also allow a first-char version. 
    $transl_lower = $transl[0]; 
    $transl_upper = $transl[1]; 
    if (strlen($transl_lower) > 1)  
                             $transl_lower = $transl_lower.'|'.$transl_lower[0]; 
    if (strlen($transl_upper) > 1)  
                             $transl_upper = $transl_upper.'|'.$transl_upper[0]; 
     
    # Replace "ae" etc. with "(ä|ae)" etc. Check for uppercase versions. 
    $regex = str_replace($transl[0], '('.$transl_lower.'|'.$umlaut_lower.')',  
                                                                        $regex); 
    if ($umlaut_upper != '') 
      $regex = str_replace($transl[1], '('.$transl_upper.'|'.$umlaut_upper.')', 
                                                                      $regex); } 
 
  return $regex; } 
 
 
 
######################################################## 
#                                                      # 
#   d a t a b a s e       m a n i p u l a t i o n      # 
#                                                      # 
######################################################## 
 
function AutolinkWorkList() 
# Work through a file listing DB manipulation tasks. 
{ global $AutolinkWorklist, $AutolinkGroupDir, $AutolinkTimeExceed, $pagename; 
 
  # Check for a WorkList lockfile. Obey it if it contains a time too fresh. 
  # Else, continue and set a new timestamp to the lockfile. 
  $now = time(); 
  $lock = $AutolinkWorklist.',lock'; 
  if (is_file($lock)) 
  { $time = file_get_contents($lock); 
    if ($time + $AutolinkTimeExceed > $now) 
    { echo 'Lockfile found, timestamp too recent. Wait a bit.'; exit(); } } 
  file_put_contents($lock, $now); 
 
  # Go through $AutolinkWorklist line by line. Each line starts with a mark 
  # stating the manipulation to be done, followed by the pagename of the entry 
  # to be manipulated. Lines starting with a # are ignored. 
  $p_dbfile = fopen($AutolinkWorklist, 'r+'); 
  while (!feof($p_dbfile)) 
  { $position = ftell($p_dbfile); 
    $line = fgets($p_dbfile); 
    $mark = $line[0]; 
    if ($mark !== '#') 
    { $entry = substr($line, 1,-1); 
      if     ($mark == '+') AutolinkCreateEntry($entry); 
      elseif ($mark == '-') AutolinkDeleteEntry($entry); 
     
      # After performing desired manipulation, comment out worklist entry. 
      fseek($p_dbfile, $position); 
      fwrite($p_dbfile, '#'); 
      fgets($p_dbfile); } } 
 
  # A finished worklist must be deleted, else this function gets called again. 
  fclose($p_dbfile); 
  unlink($AutolinkWorklist);  
  unlink($lock); 
  Redirect($pagename); } 
 
 
 
function AutolinkStartDb() 
# Start DB by creating directories and a worklist for the creation of entries. 
{ global $AutolinkDir, $AutolinkGroupDir, $AutolinkGroupname,  
  $AutolinkBannedPages, $WorkDir, $AutolinkWorklist, $pagename; 
 
  # Create directories. 
  if (!is_dir($AutolinkDir)) mkdir($AutolinkDir); 
  mkdir($AutolinkGroupDir); 
 
  # Build worklist for creation of entries for pages not banned or deleted. 
  $p_dbfile = fopen($AutolinkWorklist, 'x'); 
  $p_dir = opendir($WorkDir); 
    while (FALSE !== ($fn = readdir($p_dir))) 
    { list($fn_group, $fn_page) = AutolinkDivideGroupName($fn); 
      if ($AutolinkGroupname == $fn_group 
          and !strpos($fn_page, ',') 
          and !in_array($fn_page, $AutolinkBannedPages)) 
        fwrite($p_dbfile, '+'.$fn_page."\n"); } 
  fclose($p_dbfile); } 
 
 
 
function AutolinkUpdateDb($pagename, $page, $new) 
# Catch wiki page updates, add appropriate DB manipulation tasks to worklist. 
{ global $AutolinkBannedPages, $AutolinkPagename, $AutolinkWorklist,  
                                         $DeleteKeyPattern, $IsPagePosted, $Now; 
 
  # Only catch changes actually posted. Ignore anything concerning banned pages. 
  if (!$IsPagePosted or in_array($AutolinkPagename, $AutolinkBannedPages)) 
    return; 
 
  $p_dbfile = fopen($AutolinkWorklist, 'a'); 
 
  # Catch page deletions. 
  if (preg_match("/$DeleteKeyPattern/", $new['text'])) 
    fwrite($p_dbfile, '-'.$AutolinkPagename."\n"); 
 
  # Catch page creations. 
  elseif ($page['ctime'] == $Now) 
    fwrite($p_dbfile, '+'.$AutolinkPagename."\n"); 
 
  # Treat a page update as if a page was deleted and then newly created. 
  else 
  { fwrite($p_dbfile, '-'.$AutolinkPagename."\n"); 
    fwrite($p_dbfile, '+'.$AutolinkPagename."\n"); }   
 
  fclose($p_dbfile);  
  return; } 
 
 
 
function AutolinkCreateEntry($entry_to_write) 
# Create DB entry for a wiki page and build appropriate links to other entries. 
{ global $AutolinkGroupDir; 
 
  # The regex matching the page's name. The page's text. 
  $regex_entry = AutolinkGenerateRegex($entry_to_write); 
  $text_entry = AutolinkGetTextField($entry_to_write); 
 
  # Find potentials autolinks in and out with other entries. 
  $links_out = array(); $links_in = array();  
  $p_dir = opendir($AutolinkGroupDir); 
  while (FALSE !== ($fn = readdir($p_dir))) if (($fn[0] != '.')  
                                            and ($fn != $entry_to_write)) 
  { # Collect $links_out by matching other pagenames' regexes to $text_entry. 
    $regex_foreign = AutolinkGetRegexFromFile($fn); 
    if (substr($fn, -5) == ',TEMP') $fn = substr($fn, 0, -5); 
    if (preg_match('/'.$regex_foreign.'/iu', $text_entry)) $links_out[] = $fn; 
 
    # Collect $links_in by matching $regex_entry to other page's texts. 
    $text_foreign  = AutolinkGetTextField($fn); 
    if (preg_match('/'.$regex_entry.'/iu', $text_foreign)) $links_in[]  = $fn; } 
  closedir($p_dir); 
 
  # Start entry with only the first regex line, the next two link lines empty. 
  # If entry already exists (a previous attempt's leftover?), delete it first. 
  $path = $AutolinkGroupDir.'/'.$entry_to_write; 
  if (is_file($path)) unlink($path); 
  $p_file = fopen($path, 'x'); 
  fwrite($p_file, $regex_entry."\n\n\n"); 
  fclose($p_file); 
 
  # Write the autolinks -in and -out into all affected entry files. 
  AutolinkLinkOutPages($links_out, $entry_to_write); 
  AutolinkLinkInPages ($links_in,  $entry_to_write); } 
 
 
 
function AutolinkDeleteEntry($entry_to_erase) 
# Delete DB entry for a wiki page, but first eliminate links with other entries. 
{ global $AutolinkGroupDir; 
  $path = $AutolinkGroupDir.'/'.$entry_to_erase; 
 
  # Get the links to delete from $entry_to_erase. 
  $content = explode("\n", file_get_contents($path)); 
  $links_out = explode(',', $content[1]); 
  $links_in = explode(',', $content[2]); 
 
  # # Purge the autolinks -in and -out from all affected entry files. 
  AutolinkUnlinkOutPages($links_out, $entry_to_erase); 
  AutolinkUnlinkInPages($links_in, $entry_to_erase); 
 
  # Only after all links are deleted, delete the entry itself. 
  unlink($path); } 
 
 
######################################### 
#   autolinks-in and -out fields work   # 
######################################### 
 
# Human-readable aliases for specific AutolinkLinkPages() calls. 
function AutolinkLinkOutPages($links_out, $linked_page) 
{ AutolinkLinkPages($links_out, $linked_page, 2, 1, 0); } 
 
function AutolinkLinkInPages($links_in, $linked_page) 
{ AutolinkLinkPages($links_in, $linked_page, 1, 1, 0); } 
 
function AutolinkUnlinkOutPages($links_in, $linked_page) 
{ AutolinkLinkPages($links_in, $linked_page, 2, 1, 1); } 
 
function AutolinkUnlinkInPages($links_out, $linked_page) 
{ AutolinkLinkPages($links_out, $linked_page, 1, 1, 1); } 
 
 
 
function AutolinkLinkPages($links, $linked_page, $line, $mirror, $unlink) 
# Add or remove auto-linking references between DB entries for pages. 
{ global $AutolinkGroupDir; 
 
  foreach ($links as $fn) if ($fn) 
  { $path = $AutolinkGroupDir.'/'.$fn; 
 
    # Look for previous aborted file manipulations' leftovers. Repair those. 
    $path_temp = $path.',TEMP'; 
    if (is_file($path_temp)) 
      if (is_file($path)) unlink($path_temp); 
      else rename($path_temp, $path); 
 
    # Manipulate content of DB files: add or remove links pointing in or out. 
    $content = explode("\n", file_get_contents($path)); 
    $old_references = explode(',', $content[$line]); 
    if ($unlink == 0) 
      $references = array_merge($old_references, array($linked_page)); 
    else 
      $references = array_diff($old_references, array($linked_page)); 
    $references = array_diff($references, array('')); # Remove empty elements. 
    usort($references, 'AutolinkSortByLengthAlphabetAndCase'); # Sort elements. 
    $content[$line] = implode(',', array_unique($references)); 
    $content = implode("\n", $content); 
 
    # Expect process abortion: Write changes to $path_temp, *then* replace $path 
    file_put_contents($path_temp, $content);    
    unlink($path); 
    rename($path_temp, $path); 
 
    # Mirror the linking in the entry just linked. 
    if ($mirror)  
      AutolinkLinkPages(array($linked_page), $fn, 3-$line, 0, $unlink); } } 
 
 
 
function AutolinkSortByLengthAlphabetAndCase($a, $b) 
# Try to sort by stringlength, then follow sort() for uppercase vs. lowercase. 
{ $strlen_a = strlen($a); 
  $strlen_b = strlen($b); 
  if ($strlen_a < $strlen_b) return 1; 
  elseif ($strlen_a > $strlen_b) return -1; 
 
  $sort = array($a, $b); 
  sort($sort); 
  if ($sort[0] == $a) return -1; 
  return 1; } 

Kommentare

#0

Also ich finde das eine bodenlose Frechheit! Jeder hat doch eine recht auch mal auf seine Privatsphäre ohne ständig beobachtet zu werden oder was im Internet posten zu müssen!. Meinste Imitat am Arsch vorbeigeht, wie du lebst! Mich interessiert das doch nicht das ja dann machen!
Du Arschgeige!

Arschgeige /

(4 versteckte Kommentare zu dieser Seite.)

Schreibe deinen eigenen Kommentar

Kommentar-Schreiben derzeit nicht möglich: Kein Captcha gesetzt.

PlomWiki-Engine lizensiert unter der AGPLv3. Quellcode verfügbar auf GitHub.