[ Index ]
 

Code source de DokuWiki 2006-11-06

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/inc/ -> changelog.php (source)

   1  <?php
   2  /**
   3   * Changelog handling functions
   4   *
   5   * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
   6   * @author     Andreas Gohr <andi@splitbrain.org>
   7   */
   8  
   9  /**
  10   * parses a changelog line into it's components
  11   *
  12   * @author Ben Coburn <btcoburn@silicodon.net>
  13   */
  14  function parseChangelogLine($line) {
  15    $tmp = explode("\t", $line);
  16      if ($tmp!==false && count($tmp)>1) {
  17        $info = array();
  18        $info['date']  = (int)$tmp[0]; // unix timestamp
  19        $info['ip']    = $tmp[1]; // IPv4 address (127.0.0.1)
  20        $info['type']  = $tmp[2]; // log line type
  21        $info['id']    = $tmp[3]; // page id
  22        $info['user']  = $tmp[4]; // user name
  23        $info['sum']   = $tmp[5]; // edit summary (or action reason)
  24        $info['extra'] = rtrim($tmp[6], "\n"); // extra data (varies by line type)
  25        return $info;
  26    } else { return false; }
  27  }
  28  
  29  /**
  30   * Add's an entry to the changelog and saves the metadata for the page
  31   *
  32   * @author Andreas Gohr <andi@splitbrain.org>
  33   * @author Esther Brunner <wikidesign@gmail.com>
  34   * @author Ben Coburn <btcoburn@silicodon.net>
  35   */
  36  function addLogEntry($date, $id, $type='E', $summary='', $extra=''){
  37    global $conf, $INFO;
  38  
  39    $id = cleanid($id);
  40    $file = wikiFN($id);
  41    $created = @filectime($file);
  42    $minor = ($type==='e');
  43    $wasRemoved = ($type==='D');
  44  
  45    if(!$date) $date = time(); //use current time if none supplied
  46    $remote = $_SERVER['REMOTE_ADDR'];
  47    $user   = $_SERVER['REMOTE_USER'];
  48  
  49    $strip = array("\t", "\n");
  50    $logline = array(
  51      'date'  => $date,
  52      'ip'    => $remote,
  53      'type'  => str_replace($strip, '', $type),
  54      'id'    => $id,
  55      'user'  => $user,
  56      'sum'   => str_replace($strip, '', $summary),
  57      'extra' => str_replace($strip, '', $extra)
  58    );
  59  
  60    // update metadata
  61    if (!$wasRemoved) {
  62      $meta = array();
  63      if (!$INFO['exists']){ // newly created
  64        $meta['date']['created'] = $created;
  65        if ($user) $meta['creator'] = $INFO['userinfo']['name'];
  66      } elseif (!$minor) {   // non-minor modification
  67        $meta['date']['modified'] = $date;
  68        if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name'];
  69      }
  70      $meta['last_change'] = $logline;
  71      p_set_metadata($id, $meta, true);
  72    }
  73  
  74    // add changelog lines
  75    $logline = implode("\t", $logline)."\n";
  76    io_saveFile(metaFN($id,'.changes'),$logline,true); //page changelog
  77    io_saveFile($conf['changelog'],$logline,true); //global changelog cache
  78  }
  79  
  80  /**
  81   * returns an array of recently changed files using the
  82   * changelog
  83   *
  84   * The following constants can be used to control which changes are
  85   * included. Add them together as needed.
  86   *
  87   * RECENTS_SKIP_DELETED   - don't include deleted pages
  88   * RECENTS_SKIP_MINORS    - don't include minor changes
  89   * RECENTS_SKIP_SUBSPACES - don't include subspaces
  90   *
  91   * @param int    $first   number of first entry returned (for paginating
  92   * @param int    $num     return $num entries
  93   * @param string $ns      restrict to given namespace
  94   * @param bool   $flags   see above
  95   *
  96   * @author Ben Coburn <btcoburn@silicodon.net>
  97   */
  98  function getRecents($first,$num,$ns='',$flags=0){
  99    global $conf;
 100    $recent = array();
 101    $count  = 0;
 102  
 103    if(!$num)
 104      return $recent;
 105  
 106    // read all recent changes. (kept short)
 107    $lines = file($conf['changelog']);
 108  
 109  
 110    // handle lines
 111    for($i = count($lines)-1; $i >= 0; $i--){
 112      $rec = _handleRecent($lines[$i], $ns, $flags);
 113      if($rec !== false) {
 114        if(--$first >= 0) continue; // skip first entries
 115        $recent[] = $rec;
 116        $count++;
 117        // break when we have enough entries
 118        if($count >= $num){ break; }
 119      }
 120    }
 121  
 122    return $recent;
 123  }
 124  
 125  /**
 126   * Internal function used by getRecents
 127   *
 128   * don't call directly
 129   *
 130   * @see getRecents()
 131   * @author Andreas Gohr <andi@splitbrain.org>
 132   * @author Ben Coburn <btcoburn@silicodon.net>
 133   */
 134  function _handleRecent($line,$ns,$flags){
 135    static $seen  = array();         //caches seen pages and skip them
 136    if(empty($line)) return false;   //skip empty lines
 137  
 138    // split the line into parts
 139    $recent = parseChangelogLine($line);
 140    if ($recent===false) { return false; }
 141  
 142    // skip seen ones
 143    if(isset($seen[$recent['id']])) return false;
 144  
 145    // skip minors
 146    if($recent['type']==='e' && ($flags & RECENTS_SKIP_MINORS)) return false;
 147  
 148    // remember in seen to skip additional sights
 149    $seen[$recent['id']] = 1;
 150  
 151    // check if it's a hidden page
 152    if(isHiddenPage($recent['id'])) return false;
 153  
 154    // filter namespace
 155    if (($ns) && (strpos($recent['id'],$ns.':') !== 0)) return false;
 156  
 157    // exclude subnamespaces
 158    if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false;
 159  
 160    // check ACL
 161    if (auth_quickaclcheck($recent['id']) < AUTH_READ) return false;
 162  
 163    // check existance
 164    if((!@file_exists(wikiFN($recent['id']))) && ($flags & RECENTS_SKIP_DELETED)) return false;
 165  
 166    return $recent;
 167  }
 168  
 169  /**
 170   * Get the changelog information for a specific page id
 171   * and revision (timestamp). Adjacent changelog lines
 172   * are optimistically parsed and cached to speed up
 173   * consecutive calls to getRevisionInfo. For large
 174   * changelog files, only the chunk containing the
 175   * requested changelog line is read.
 176   *
 177   * @author Ben Coburn <btcoburn@silicodon.net>
 178   */
 179  function getRevisionInfo($id, $rev, $chunk_size=8192) {
 180    global $cache_revinfo;
 181    $cache =& $cache_revinfo;
 182    if (!isset($cache[$id])) { $cache[$id] = array(); }
 183    $rev = max($rev, 0);
 184  
 185    // check if it's already in the memory cache
 186    if (isset($cache[$id]) && isset($cache[$id][$rev])) {
 187      return $cache[$id][$rev];
 188    }
 189  
 190    $file = metaFN($id, '.changes');
 191    if (!@file_exists($file)) { return false; }
 192    if (filesize($file)<$chunk_size || $chunk_size==0) {
 193      // read whole file
 194      $lines = file($file);
 195      if ($lines===false) { return false; }
 196    } else {
 197      // read by chunk
 198      $fp = fopen($file, 'rb'); // "file pointer"
 199      if ($fp===false) { return false; }
 200      $head = 0;
 201      fseek($fp, 0, SEEK_END);
 202      $tail = ftell($fp);
 203      $finger = 0;
 204      $finger_rev = 0;
 205  
 206      // find chunk
 207      while ($tail-$head>$chunk_size) {
 208        $finger = $head+floor(($tail-$head)/2.0);
 209        fseek($fp, $finger);
 210        fgets($fp); // slip the finger forward to a new line
 211        $finger = ftell($fp);
 212        $tmp = fgets($fp); // then read at that location
 213        $tmp = parseChangelogLine($tmp);
 214        $finger_rev = $tmp['date'];
 215        if ($finger==$head || $finger==$tail) { break; }
 216        if ($finger_rev>$rev) {
 217          $tail = $finger;
 218        } else {
 219          $head = $finger;
 220        }
 221      }
 222  
 223      if ($tail-$head<1) {
 224        // cound not find chunk, assume requested rev is missing
 225        fclose($fp);
 226        return false;
 227      }
 228  
 229      // read chunk
 230      $chunk = '';
 231      $chunk_size = max($tail-$head, 0); // found chunk size
 232      $got = 0;
 233      fseek($fp, $head);
 234      while ($got<$chunk_size && !feof($fp)) {
 235        $tmp = fread($fp, max($chunk_size-$got, 0));
 236        if ($tmp===false) { break; } //error state
 237        $got += strlen($tmp);
 238        $chunk .= $tmp;
 239      }
 240      $lines = explode("\n", $chunk);
 241      array_pop($lines); // remove trailing newline
 242      fclose($fp);
 243    }
 244  
 245    // parse and cache changelog lines
 246    foreach ($lines as $value) {
 247      $tmp = parseChangelogLine($value);
 248      if ($tmp!==false) {
 249        $cache[$id][$tmp['date']] = $tmp;
 250      }
 251    }
 252    if (!isset($cache[$id][$rev])) { return false; }
 253    return $cache[$id][$rev];
 254  }
 255  
 256  /**
 257   * Return a list of page revisions numbers
 258   * Does not guarantee that the revision exists in the attic,
 259   * only that a line with the date exists in the changelog.
 260   * By default the current revision is skipped.
 261   *
 262   * id:    the page of interest
 263   * first: skip the first n changelog lines
 264   * num:   number of revisions to return
 265   *
 266   * The current revision is automatically skipped when the page exists.
 267   * See $INFO['meta']['last_change'] for the current revision.
 268   *
 269   * For efficiency, the log lines are parsed and cached for later
 270   * calls to getRevisionInfo. Large changelog files are read
 271   * backwards in chunks untill the requested number of changelog
 272   * lines are recieved.
 273   *
 274   * @author Ben Coburn <btcoburn@silicodon.net>
 275   */
 276  function getRevisions($id, $first, $num, $chunk_size=8192) {
 277    global $cache_revinfo;
 278    $cache =& $cache_revinfo;
 279    if (!isset($cache[$id])) { $cache[$id] = array(); }
 280  
 281    $revs = array();
 282    $lines = array();
 283    $count  = 0;
 284    $file = metaFN($id, '.changes');
 285    $num = max($num, 0);
 286    $chunk_size = max($chunk_size, 0);
 287    if ($first<0) { $first = 0; }
 288    else if (@file_exists(wikiFN($id))) {
 289       // skip current revision if the page exists
 290      $first = max($first+1, 0);
 291    }
 292  
 293    if (!@file_exists($file)) { return $revs; }
 294    if (filesize($file)<$chunk_size || $chunk_size==0) {
 295      // read whole file
 296      $lines = file($file);
 297      if ($lines===false) { return $revs; }
 298    } else {
 299      // read chunks backwards
 300      $fp = fopen($file, 'rb'); // "file pointer"
 301      if ($fp===false) { return $revs; }
 302      fseek($fp, 0, SEEK_END);
 303      $tail = ftell($fp);
 304  
 305      // chunk backwards
 306      $finger = max($tail-$chunk_size, 0);
 307      while ($count<$num+$first) {
 308        fseek($fp, $finger);
 309        if ($finger>0) {
 310          fgets($fp); // slip the finger forward to a new line
 311          $finger = ftell($fp);
 312        }
 313  
 314        // read chunk
 315        if ($tail<=$finger) { break; }
 316        $chunk = '';
 317        $read_size = max($tail-$finger, 0); // found chunk size
 318        $got = 0;
 319        while ($got<$read_size && !feof($fp)) {
 320          $tmp = fread($fp, max($read_size-$got, 0));
 321          if ($tmp===false) { break; } //error state
 322          $got += strlen($tmp);
 323          $chunk .= $tmp;
 324        }
 325        $tmp = explode("\n", $chunk);
 326        array_pop($tmp); // remove trailing newline
 327  
 328        // combine with previous chunk
 329        $count += count($tmp);
 330        $lines = array_merge($tmp, $lines);
 331  
 332        // next chunk
 333        if ($finger==0) { break; } // already read all the lines
 334        else {
 335          $tail = $finger;
 336          $finger = max($tail-$chunk_size, 0);
 337        }
 338      }
 339      fclose($fp);
 340    }
 341  
 342    // skip parsing extra lines
 343    $num = max(min(count($lines)-$first, $num), 0);
 344    if      ($first>0 && $num>0)  { $lines = array_slice($lines, max(count($lines)-$first-$num, 0), $num); }
 345    else if ($first>0 && $num==0) { $lines = array_slice($lines, 0, max(count($lines)-$first, 0)); }
 346    else if ($first==0 && $num>0) { $lines = array_slice($lines, max(count($lines)-$num, 0)); }
 347  
 348    // handle lines in reverse order
 349    for ($i = count($lines)-1; $i >= 0; $i--) {
 350      $tmp = parseChangelogLine($lines[$i]);
 351      if ($tmp!==false) {
 352        $cache[$id][$tmp['date']] = $tmp;
 353        $revs[] = $tmp['date'];
 354      }
 355    }
 356  
 357    return $revs;
 358  }
 359  
 360  


Généré le : Tue Apr 3 20:47:31 2007 par Balluche grâce à PHPXref 0.7