From 49eb6e38061d744f4a35b78082dce49fa35f79c8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Fri, 15 Jan 2010 19:50:13 +0100 Subject: [PATCH] some more coding standard compliance updates --- feed.php | 2 +- inc/HTTPClient.php | 1 - inc/IXR_Library.php | 15 +- inc/TarLib.class.php | 1547 ++++++++++++++++++------------------ inc/actions.php | 830 +++++++++---------- inc/cache.php | 448 +++++------ inc/changelog.php | 611 +++++++------- inc/cliopts.php | 37 +- inc/common.php | 1792 +++++++++++++++++++++--------------------- inc/confutils.php | 297 +++---- inc/events.php | 320 ++++---- inc/form.php | 4 +- inc/fulltext.php | 178 ++--- install.php | 25 +- 14 files changed, 3027 insertions(+), 3080 deletions(-) diff --git a/feed.php b/feed.php index e7ea5808c..0ad1c2c30 100644 --- a/feed.php +++ b/feed.php @@ -25,7 +25,7 @@ $opt = rss_parseOptions(); // the feed is dynamic - we need a cache for each combo // (but most people just use the default feed so it's still effective) $cache = getCacheName(join('',array_values($opt)).$_SERVER['REMOTE_USER'],'.feed'); -$key = join('', array_values($opt)) . $_SERVER['REMOTE_USER']; +$key = join('', array_values($opt)) . $_SERVER['REMOTE_USER']; $cache = new cache($key, '.feed'); // prepare cache depends diff --git a/inc/HTTPClient.php b/inc/HTTPClient.php index 578d7e7cd..c88d1c45d 100644 --- a/inc/HTTPClient.php +++ b/inc/HTTPClient.php @@ -279,7 +279,6 @@ class HTTPClient { $written += $ret; } - // read headers from socket $r_headers = ''; do{ diff --git a/inc/IXR_Library.php b/inc/IXR_Library.php index 2752e31f2..25d1066b0 100644 --- a/inc/IXR_Library.php +++ b/inc/IXR_Library.php @@ -300,7 +300,7 @@ class IXR_Server { if (!$data) { global $HTTP_RAW_POST_DATA; if (!$HTTP_RAW_POST_DATA) { - die('XML-RPC server accepts POST requests only.'); + die('XML-RPC server accepts POST requests only.'); } $data = $HTTP_RAW_POST_DATA; } @@ -342,14 +342,13 @@ EOD; $method = $this->callbacks[$methodname]; // Perform the callback and send the response -# Removed for DokuWiki to have a more consistent interface -# if (count($args) == 1) { -# // If only one paramater just send that instead of the whole array -# $args = $args[0]; -# } + # Removed for DokuWiki to have a more consistent interface + # if (count($args) == 1) { + # // If only one paramater just send that instead of the whole array + # $args = $args[0]; + # } - -# Adjusted for DokuWiki to use call_user_func_array + # Adjusted for DokuWiki to use call_user_func_array // args need to be an array $args = (array) $args; diff --git a/inc/TarLib.class.php b/inc/TarLib.class.php index ab802163b..3c1827554 100644 --- a/inc/TarLib.class.php +++ b/inc/TarLib.class.php @@ -59,860 +59,803 @@ define('ARCHIVE_DYNAMIC',0); define('ARCHIVE_RENAMECOMP',5); define('COMPRESS_DETECT',-1); -class TarLib -{ - var $_comptype; - var $_compzlevel; - var $_fp; - var $_memdat; - var $_nomf; - var $_result; - var $_initerror; - - /** - * constructor, initialize the class - * - * The constructor initialize the variables and prepare the class for the - * archive, and return the object created. Note that you can use multiple - * instances of the MaxgTar class, if you call this function another time and - * store the object in an other variable. - * - * In fact, MaxgTar accepts the following arguments (all are optional) : - * - * filename can be either a file name (absolute or relative). In this - * case, it can be used both for reading and writing. You can also open - * remote archive if you add a protocole name at the beginning of the file - * (ie https://host.dom/archive.tar.gz), but for reading only and if the - * directive allow_url_fopen is enabled in PHP.INI (this can be checked with - * TarInfo()). If you pass a file that doesn't exist, the script - * will try to create it. If the archive already exists and contains files, - * you can use Add() to append files.But by default this parameter - * is ARCHIVE_DYNAMIC (write only) so the archive is created in memory and - * can be sent to a file [writeArchive()] or to the client - * [sendClient()] - * - * compression_type should be a constant that represents a type of - * compression, or its integer value. The different values are described in - * the constants. - * - * compression_level is an integer between 1 and 9 (by default) an - * represent the GZIP or BZIP compression level. 1 produce fast compression, - * and 9 produce smaller files. See the RFC 1952 for more infos. - */ - function tarlib($p_filen = ARCHIVE_DYNAMIC , $p_comptype = COMPRESS_AUTO, $p_complevel = 9) - { - $this->_initerror = 0; - $this->_nomf = $p_filen; $flag=0; - if($p_comptype && $p_comptype % 5 == 0){$p_comptype /= ARCHIVE_RENAMECOMP; $flag=1;} - - if($p_complevel > 0 && $p_complevel <= 9) $this->_compzlevel = $p_complevel; - else $p_complevel = 9; - - if($p_comptype == COMPRESS_DETECT) - { - if(strtolower(substr($p_filen,-3)) == '.gz') $p_comptype = COMPRESS_GZIP; - elseif(strtolower(substr($p_filen,-4)) == '.bz2') $p_comptype = COMPRESS_BZIP; - else $p_comptype = COMPRESS_NONE; - } +class TarLib { + var $_comptype; + var $_compzlevel; + var $_fp; + var $_memdat; + var $_nomf; + var $_result; + var $_initerror; + + /** + * constructor, initialize the class + * + * The constructor initialize the variables and prepare the class for the + * archive, and return the object created. Note that you can use multiple + * instances of the MaxgTar class, if you call this function another time and + * store the object in an other variable. + * + * In fact, MaxgTar accepts the following arguments (all are optional) : + * + * filename can be either a file name (absolute or relative). In this + * case, it can be used both for reading and writing. You can also open + * remote archive if you add a protocole name at the beginning of the file + * (ie https://host.dom/archive.tar.gz), but for reading only and if the + * directive allow_url_fopen is enabled in PHP.INI (this can be checked with + * TarInfo()). If you pass a file that doesn't exist, the script + * will try to create it. If the archive already exists and contains files, + * you can use Add() to append files.But by default this parameter + * is ARCHIVE_DYNAMIC (write only) so the archive is created in memory and + * can be sent to a file [writeArchive()] or to the client + * [sendClient()] + * + * compression_type should be a constant that represents a type of + * compression, or its integer value. The different values are described in + * the constants. + * + * compression_level is an integer between 1 and 9 (by default) an + * represent the GZIP or BZIP compression level. 1 produce fast compression, + * and 9 produce smaller files. See the RFC 1952 for more infos. + */ + function tarlib($p_filen = ARCHIVE_DYNAMIC , $p_comptype = COMPRESS_AUTO, $p_complevel = 9) { + $this->_initerror = 0; + $this->_nomf = $p_filen; + $flag=0; + if($p_comptype && $p_comptype % 5 == 0){ + $p_comptype /= ARCHIVE_RENAMECOMP; + $flag=1; + } - switch($p_comptype) - { - case COMPRESS_GZIP: - if(!extension_loaded('zlib')) $this->_initerror = -1; - $this->_comptype = COMPRESS_GZIP; - break; - - case COMPRESS_BZIP: - if(!extension_loaded('bz2')) $this->_inierror = -2; - $this->_comptype = COMPRESS_BZIP; - break; - - case COMPRESS_AUTO: - if(extension_loaded('zlib')) - $this->_comptype = COMPRESS_GZIP; - elseif(extension_loaded('bz2')) - $this->_comptype = COMPRESS_BZIP; - else - $this->_comptype = COMPRESS_NONE; - break; + if($p_complevel > 0 && $p_complevel <= 9) $this->_compzlevel = $p_complevel; + else $p_complevel = 9; - default: - $this->_comptype = COMPRESS_NONE; + if($p_comptype == COMPRESS_DETECT) { + if(strtolower(substr($p_filen,-3)) == '.gz') $p_comptype = COMPRESS_GZIP; + elseif(strtolower(substr($p_filen,-4)) == '.bz2') $p_comptype = COMPRESS_BZIP; + else $p_comptype = COMPRESS_NONE; + } + + switch($p_comptype) { + case COMPRESS_GZIP: + if(!extension_loaded('zlib')) $this->_initerror = -1; + $this->_comptype = COMPRESS_GZIP; + break; + + case COMPRESS_BZIP: + if(!extension_loaded('bz2')) $this->_inierror = -2; + $this->_comptype = COMPRESS_BZIP; + break; + + case COMPRESS_AUTO: + if(extension_loaded('zlib')) + $this->_comptype = COMPRESS_GZIP; + elseif(extension_loaded('bz2')) + $this->_comptype = COMPRESS_BZIP; + else + $this->_comptype = COMPRESS_NONE; + break; + + default: + $this->_comptype = COMPRESS_NONE; + } + + if($this->_init_error < 0) $this->_comptype = COMPRESS_NONE; + + if($flag) $this->_nomf.= '.'.$this->getCompression(1); + $this->_result = true; } - if($this->_init_error < 0) $this->_comptype = COMPRESS_NONE; - - if($flag) $this->_nomf.= '.'.$this->getCompression(1); - $this->_result = true; - } - - /** - * Recycle a TAR object. - * - * This function does exactly the same as TarLib (constructor), except it - * returns a status code. - */ - function setArchive($p_name='', $p_comp = COMPRESS_AUTO, $p_level=9) - { - $this->_CompTar(); - $this->TarLib($p_name, $p_comp, $p_level); - return $this->_result; - } - - /** - * Get the compression used to generate the archive - * - * This is a very useful function when you're using dynamical archives. - * Besides, if you let the script chose which compression to use, you'll have - * a problem when you'll want to send it to the client if you don't know - * which compression was used. - * - * There are two ways to call this function : if you call it without argument - * or with FALSE, it will return the compression constants, explained on the - * MaxgTar Constants. If you call it with GetExtension on TRUE it will - * return the extension without starting dot (ie "tar" or "tar.bz2" or - * "tar.gz") - * - * NOTE: This can be done with the flag ARCHIVE_RENAMECOMP, see the - * MaxgTar Constants - */ - function getCompression($ext = false) - { - $exts = Array('tar','tar.gz','tar.bz2'); - if($ext) return $exts[$this->_comptype]; - return $this->_comptype; - } - - /** - * Change the compression mode. - * - * This function will change the compression methode to read or write - * the archive. See the MaxgTar Constants to see which constants you can use. - * It may look strange, but it returns the GZIP compression level. - */ - function setCompression($p_comp = COMPRESS_AUTO) - { - $this->setArchive($this->_nomf, $p_comp, $this->_compzlevel); - return $this->_compzlevel; - } - - /** - * Returns the compressed dynamic archive. - * - * When you're working with dynamic archives, use this function to grab - * the final compressed archive in a string ready to be put in a SQL table or - * in a file. - */ - function getDynamicArchive() - { - return $this->_encode($this->_memdat); - } - - /** - * Write a dynamical archive into a file - * - * This function attempts to write a dynamicaly-genrated archive into - * TargetFile on the webserver. It returns a TarErrorStr() status - * code. - * - * To know the extension to add to the file if you're using AUTO_DETECT - * compression, you can use getCompression(). - */ - function writeArchive($p_archive) { - if(!$this->_memdat) return -7; - $fp = @fopen($p_archive, 'wb'); - if(!$fp) return -6; - - fwrite($fp, $this->_memdat); - fclose($fp); - - return true; - } - - /** - * Send a TAR archive to the client browser. - * - * This function will send an archive to the client, and return a status - * code, but can behave differently depending on the arguments you give. All - * arguments are optional. - * - * ClientName is used to specify the archive name to give to the browser. If - * you don't give one, it will send the constructor filename or return an - * error code in case of dynamical archive. - * - * FileName is optional and used to send a specific archive. Leave it blank - * to send dynamical archives or the current working archive. - * - * If SendHeaders is enabled (by default), the library will send the HTTP - * headers itself before it sends the contents. This headers are : - * Content-Type, Content-Disposition, Content-Length and Accept-Range. - * - * Please note that this function DOES NOT stops the script so don't forget - * to exit() to avoid your script sending other data and corrupt the archive. - * Another note : for AUTO_DETECT dynamical archives you can know the - * extension to add to the name with getCompression() - */ - function sendClient($name = '', $archive = '', $headers = true) - { - if(!$name && !$this->_nomf) return -9; - if(!$archive && !$this->_memdat) return -10; - if(!$name) $name = basename($this->_nomf); - - if($archive){ if(!file_exists($archive)) return -11; } - else $decoded = $this->getDynamicArchive(); - - if($headers) - { - header('Content-Type: application/x-gtar'); - header('Content-Disposition: attachment; filename='.basename($name)); - header('Accept-Ranges: bytes'); - header('Content-Length: '.($archive ? filesize($archive) : strlen($decoded))); + /** + * Recycle a TAR object. + * + * This function does exactly the same as TarLib (constructor), except it + * returns a status code. + */ + function setArchive($p_name='', $p_comp = COMPRESS_AUTO, $p_level=9) { + $this->_CompTar(); + $this->TarLib($p_name, $p_comp, $p_level); + return $this->_result; } - if($archive) - { - $fp = @fopen($archive,'rb'); - if(!$fp) return -4; + /** + * Get the compression used to generate the archive + * + * This is a very useful function when you're using dynamical archives. + * Besides, if you let the script chose which compression to use, you'll have + * a problem when you'll want to send it to the client if you don't know + * which compression was used. + * + * There are two ways to call this function : if you call it without argument + * or with FALSE, it will return the compression constants, explained on the + * MaxgTar Constants. If you call it with GetExtension on TRUE it will + * return the extension without starting dot (ie "tar" or "tar.bz2" or + * "tar.gz") + * + * NOTE: This can be done with the flag ARCHIVE_RENAMECOMP, see the + * MaxgTar Constants + */ + function getCompression($ext = false) { + $exts = Array('tar','tar.gz','tar.bz2'); + if($ext) return $exts[$this->_comptype]; + return $this->_comptype; + } - while(!feof($fp)) echo fread($fp,2048); + /** + * Change the compression mode. + * + * This function will change the compression methode to read or write + * the archive. See the MaxgTar Constants to see which constants you can use. + * It may look strange, but it returns the GZIP compression level. + */ + function setCompression($p_comp = COMPRESS_AUTO) { + $this->setArchive($this->_nomf, $p_comp, $this->_compzlevel); + return $this->_compzlevel; } - else - { - echo $decoded; + + /** + * Returns the compressed dynamic archive. + * + * When you're working with dynamic archives, use this function to grab + * the final compressed archive in a string ready to be put in a SQL table or + * in a file. + */ + function getDynamicArchive() { + return $this->_encode($this->_memdat); } - return true; - } - - /** - * Extract part or totality of the archive. - * - * This function can extract files from an archive, and returns then a - * status codes that can be converted with TarErrorStr() into a - * human readable message. - * - * Only the first argument is required, What and it can be either the - * constant FULL_ARCHIVE or an indexed array containing each file you want to - * extract. - * - * To contains the target folder to extract the archive. It is optional and - * the default value is '.' which means the current folder. If the target - * folder doesn't exist, the script attempts to create it and give it - * permissions 0777 by default. - * - * RemovePath is very usefull when you want to extract files from a subfoler - * in the archive to a root folder. For instance, if you have a file in the - * archive called some/sub/folder/test.txt and you want to extract it to the - * script folder, you can call Extract with To = '.' and RemovePath = - * 'some/sub/folder/' - * - * FileMode is optional and its default value is 0755. It is in fact the UNIX - * permission in octal mode (prefixed with a 0) that will be given on each - * extracted file. - */ - function Extract($p_what = FULL_ARCHIVE, $p_to = '.', $p_remdir='', $p_mode = 0755) - { - if(!$this->_OpenRead()) return -4; -// if(!@is_dir($p_to)) if(!@mkdir($p_to, 0777)) return -8; --CS - if(!@is_dir($p_to)) if(!$this->_dirApp($p_to)) return -8; //--CS (route through correct dir fn) - - $ok = $this->_extractList($p_to, $p_what, $p_remdir, $p_mode); - $this->_CompTar(); - - return $ok; - } - - /** - * Create a new package with the given files - * - * This function will attempt to create a new archive with global headers - * then add the given files into. If the archive is a real file, the - * contents are written directly into the file, if it is a dynamic archive - * contents are only stored in memory. This function should not be used to - * add files to an existing archive, you should use Add() instead. - * - * The FileList actually supports three different modes : - * - * - You can pass a string containing filenames separated by pipes '|'. - * In this case the file are read from the webserver filesystem and the - * root folder is the folder where the script using the MaxgTar is called. - * - * - You can also give a unidimensional indexed array containing the - * filenames. The behaviour for the content reading is the same that a - * '|'ed string. - * - * - The more useful usage is to pass bidimensional arrays, where the - * first element contains the filename and the second contains the file - * contents. You can even add empty folders to the package if the filename - * has a leading '/'. Once again, have a look at the exemples to understand - * better. - * - * Note you can also give arrays with both dynamic contents and static files. - * - * The optional parameter RemovePath can be used to delete a part of the tree - * of the filename you're adding, for instance if you're adding in the root - * of a package a file that is stored somewhere in the server tree. - * - * On the contrary the parameter AddPath can be used to add a prefix folder - * to the file you store. Note also that the RemovePath is applied before the - * AddPath is added, so it HAS a sense to use both parameters together. - */ - function Create($p_filelist,$p_add='',$p_rem='') - { - if(!$fl = $this->_fetchFilelist($p_filelist)) return -5; - if(!$this->_OpenWrite()) return -6; - - $ok = $this->_addFileList($fl,$p_add,$p_rem); - - if($ok) $this->_writeFooter(); - else{ $this->_CompTar(); @unlink($this->_nomf); } - - return $ok; - } - - /** - * Add files to an existing package. - * - * This function does exactly the same than Create() exept it - * will append the given files at the end of the archive. Please not the is - * safe to call Add() on a newly created archive whereas the - * contrary will fail ! - * - * This function returns a status code, you can use TarErrorStr() on - * it to get the human-readable description of the error. - */ - function Add($p_filelist, $p_add = '', $p_rem = '') { if (($this->_nomf -!= ARCHIVE_DYNAMIC && @is_file($this->_nomf)) || ($this->_nomf == -ARCHIVE_DYNAMIC && !$this->_memdat)) return $this->Create($p_filelist, -$p_add, $p_rem); - - if(!$fl = $this->_fetchFilelist($p_filelist)) return -5; - return $this->_append($fl, $p_add, $p_rem); - } - - /** - * Read the contents of a TAR archive - * - * This function attempts to get the list of the files stored in the - * archive, and return either an error code or an indexed array of - * associative array containing for each file the following informations : - * - * checksum Tar Checksum of the file - * filename The full name of the stored file (up to 100 c.) - * mode UNIX permissions in DECIMAL, not octal - * uid The Owner ID - * gid The Group ID - * size Uncompressed filesize - * mtime Timestamp of last modification - * typeflag Empty for files, set for folders - * link For the links, did you guess it ? - * uname Owner name - * gname Group name - */ - function ListContents() - { - if(!$this->_nomf) return -3; - if(!$this->_OpenRead()) return -4; - - $result = Array(); - - while ($dat = $this->_read(512)) - { - $dat = $this->_readHeader($dat); - if(!is_array($dat)) continue; - - $this->_seek(ceil($dat['size']/512)*512,1); - $result[] = $dat; + /** + * Write a dynamical archive into a file + * + * This function attempts to write a dynamicaly-genrated archive into + * TargetFile on the webserver. It returns a TarErrorStr() status + * code. + * + * To know the extension to add to the file if you're using AUTO_DETECT + * compression, you can use getCompression(). + */ + function writeArchive($p_archive) { + if(!$this->_memdat) return -7; + $fp = @fopen($p_archive, 'wb'); + if(!$fp) return -6; + + fwrite($fp, $this->_memdat); + fclose($fp); + + return true; } - return $result; - } - - /** - * Convert a status code into a human readable message - * - * Some MaxgTar functions like Create(), Add() ... return numerical - * status code. You can pass them to this function to grab their english - * equivalent. - */ - function TarErrorStr($i) - { - $ecodes = Array( - 1 => true, - 0 => "Undocumented error", - -1 => "Can't use COMPRESS_GZIP compression : ZLIB extensions are not loaded !", - -2 => "Can't use COMPRESS_BZIP compression : BZ2 extensions are not loaded !", - -3 => "You must set a archive file to read the contents !", - -4 => "Can't open the archive file for read !", - -5 => "Invalide file list !", - -6 => "Can't open the archive in write mode !", - -7 => "There is no ARCHIVE_DYNAMIC to write !", - -8 => "Can't create the directory to extract files !", - -9 => "Please pass a archive name to send if you made created an ARCHIVE_DYNAMIC !", - -10 => "You didn't pass an archive filename and there is no stored ARCHIVE_DYNAMIC !", - -11 => "Given archive doesn't exist !" - ); - - return isset($ecodes[$i]) ? $ecodes[$i] : $ecodes[0]; - } - - /** - * Display informations about the MaxgTar Class. - * - * This function will display vaious informations about the server - * MaxgTar is running on. - * - * The optional parameter DispHeaders is used to generate a full page with - * HTML headers (TRUE by default) or just the table with the informations - * (FALSE). Note that the HTML page generated is verified compatible XHTML - * 1.0, but not HTML 4.0 compatible. - */ - function TarInfo($headers = true) - { - if($headers) - { - ?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<html> - -<head> - <title>MaxgComp TAR</title> - <style type="text/css"> - body{margin: 20px;} - body,td{font-size:10pt;font-family: arial;} - </style> - <meta name="Author" content="The Maxg Network, http://maxg.info" /> - <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> -</head> - -<body bgcolor="#EFEFEF"> -<?php + /** + * Send a TAR archive to the client browser. + * + * This function will send an archive to the client, and return a status + * code, but can behave differently depending on the arguments you give. All + * arguments are optional. + * + * ClientName is used to specify the archive name to give to the browser. If + * you don't give one, it will send the constructor filename or return an + * error code in case of dynamical archive. + * + * FileName is optional and used to send a specific archive. Leave it blank + * to send dynamical archives or the current working archive. + * + * If SendHeaders is enabled (by default), the library will send the HTTP + * headers itself before it sends the contents. This headers are : + * Content-Type, Content-Disposition, Content-Length and Accept-Range. + * + * Please note that this function DOES NOT stops the script so don't forget + * to exit() to avoid your script sending other data and corrupt the archive. + * Another note : for AUTO_DETECT dynamical archives you can know the + * extension to add to the name with getCompression() + */ + function sendClient($name = '', $archive = '', $headers = true) { + if(!$name && !$this->_nomf) return -9; + if(!$archive && !$this->_memdat) return -10; + if(!$name) $name = basename($this->_nomf); + + if($archive){ if(!file_exists($archive)) return -11; } + else $decoded = $this->getDynamicArchive(); + + if($headers) { + header('Content-Type: application/x-gtar'); + header('Content-Disposition: attachment; filename='.basename($name)); + header('Accept-Ranges: bytes'); + header('Content-Length: '.($archive ? filesize($archive) : strlen($decoded))); + } + + if($archive) { + $fp = @fopen($archive,'rb'); + if(!$fp) return -4; + + while(!feof($fp)) echo fread($fp,2048); + } else { + echo $decoded; + } + + return true; } -?> -<table border="0" align="center" width="500" cellspacing="4" cellpadding="5" style="border:1px dotted black;"> -<tr> - <td align="center" bgcolor="#DFDFEF" colspan="3" style="font-size:15pt;font-color:#330000;border:1px solid black;">MaxgComp TAR</td> -</tr> -<tr> - <td colspan="2" bgcolor="#EFEFFE" style="border:1px solid black;">This software was created by the Maxg Network, <a href="http://maxg.info" target="_blank" style="text-decoration:none;color:#333366;">http://maxg.info</a> - <br />It is distributed under the GNU <a href="http://www.gnu.org/copyleft/lesser.html" target="_blank" style="text-decoration:none;color:#333366;">Lesser General Public License</a> - <br />You can find the documentation of this class <a href="http://docs.maxg.info" target="_blank" style="text-decoration:none;color:#333366;">here</a></td> - <td width="60" bgcolor="#EFEFFE" style="border:1px solid black;" align="center"><img src="http://img.maxg.info/menu/tar.gif" border="0" alt="MaxgComp TAR" /></td> -</tr> -<tr> - <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">MaxgComp TAR version</td> - <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=TARLIB_VERSION?></td> -</tr> -<tr> - <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">ZLIB extensions</td> - <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=(extension_loaded('zlib') ? '<b>Yes</b>' : '<i>No</i>')?></td> -</tr> -<tr> - <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">BZ2 extensions</td> - <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=(extension_loaded('bz2') ? '<b>Yes</b>' : '<i>No</i>')?></td> -</tr> -<tr> - <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">Allow URL fopen</td> - <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=(ini_get('allow_url_fopen') ? '<b>Yes</b>' : '<i>No</i>')?></td> -</tr> -<tr> - <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">Time limit</td> - <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=ini_get('max_execution_time')?></td> -</tr> -<tr> - <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">PHP Version</td> - <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=phpversion()?></td> -</tr> -<tr> - <td colspan="3" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"> - <i>Special thanks to « Vincent Blavet » for his PEAR::Archive_Tar class</i> - </td> -</tr> -</table> -<?php - if($headers) echo '</body></html>'; - } - - function _seek($p_flen, $tell=0) - { - if($this->_nomf === ARCHIVE_DYNAMIC) - $this->_memdat=substr($this->_memdat,0,($tell ? strlen($this->_memdat) : 0) + $p_flen); - elseif($this->_comptype == COMPRESS_GZIP) - @gzseek($this->_fp, ($tell ? @gztell($this->_fp) : 0)+$p_flen); - elseif($this->_comptype == COMPRESS_BZIP) - @fseek($this->_fp, ($tell ? @ftell($this->_fp) : 0)+$p_flen); - else - @fseek($this->_fp, ($tell ? @ftell($this->_fp) : 0)+$p_flen); - } - - function _OpenRead() - { - if($this->_comptype == COMPRESS_GZIP) - $this->_fp = @gzopen($this->_nomf, 'rb'); - elseif($this->_comptype == COMPRESS_BZIP) - $this->_fp = @bzopen($this->_nomf, 'rb'); - else - $this->_fp = @fopen($this->_nomf, 'rb'); - - return ($this->_fp ? true : false); - } - - function _OpenWrite($add = 'w') - { - if($this->_nomf === ARCHIVE_DYNAMIC) return true; - - if($this->_comptype == COMPRESS_GZIP) - $this->_fp = @gzopen($this->_nomf, $add.'b'.$this->_compzlevel); - elseif($this->_comptype == COMPRESS_BZIP) - $this->_fp = @bzopen($this->_nomf, $add.'b'); - else - $this->_fp = @fopen($this->_nomf, $add.'b'); - - return ($this->_fp ? true : false); - } - - function _CompTar() - { - if($this->_nomf === ARCHIVE_DYNAMIC || !$this->_fp) return; - - if($this->_comptype == COMPRESS_GZIP) @gzclose($this->_fp); - elseif($this->_comptype == COMPRESS_BZIP) @bzclose($this->_fp); - else @fclose($this->_fp); - } - - function _read($p_len) - { - if($this->_comptype == COMPRESS_GZIP) - return @gzread($this->_fp,$p_len); - elseif($this->_comptype == COMPRESS_BZIP) - return @bzread($this->_fp,$p_len); - else - return @fread($this->_fp,$p_len); - } - - function _write($p_data) - { - if($this->_nomf === ARCHIVE_DYNAMIC) $this->_memdat .= $p_data; - elseif($this->_comptype == COMPRESS_GZIP) - return @gzwrite($this->_fp,$p_data); - - elseif($this->_comptype == COMPRESS_BZIP) - return @bzwrite($this->_fp,$p_data); - - else - return @fwrite($this->_fp,$p_data); - } - - function _encode($p_dat) - { - if($this->_comptype == COMPRESS_GZIP) - return gzencode($p_dat, $this->_compzlevel); - elseif($this->_comptype == COMPRESS_BZIP) - return bzcompress($p_dat, $this->_compzlevel); - else return $p_dat; - } - - function _readHeader($p_dat) - { - if (!$p_dat || strlen($p_dat) != 512) return false; - - for ($i=0, $chks=0; $i<148; $i++) - $chks += ord($p_dat[$i]); - - for ($i=156,$chks+=256; $i<512; $i++) - $chks += ord($p_dat[$i]); - - $headers = @unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $p_dat); - if(!$headers) return false; - - $return['checksum'] = OctDec(trim($headers['checksum'])); - if ($return['checksum'] != $chks) return false; - - $return['filename'] = trim($headers['filename']); - $return['mode'] = OctDec(trim($headers['mode'])); - $return['uid'] = OctDec(trim($headers['uid'])); - $return['gid'] = OctDec(trim($headers['gid'])); - $return['size'] = OctDec(trim($headers['size'])); - $return['mtime'] = OctDec(trim($headers['mtime'])); - $return['typeflag'] = $headers['typeflag']; - $return['link'] = trim($headers['link']); - $return['uname'] = trim($headers['uname']); - $return['gname'] = trim($headers['gname']); - - return $return; - } - - function _fetchFilelist($p_filelist) - { - if(!$p_filelist || (is_array($p_filelist) && !@count($p_filelist))) return false; - - if(is_string($p_filelist)) - { - $p_filelist = explode('|',$p_filelist); - if(!is_array($p_filelist)) $p_filelist = Array($p_filelist); + + /** + * Extract part or totality of the archive. + * + * This function can extract files from an archive, and returns then a + * status codes that can be converted with TarErrorStr() into a + * human readable message. + * + * Only the first argument is required, What and it can be either the + * constant FULL_ARCHIVE or an indexed array containing each file you want to + * extract. + * + * To contains the target folder to extract the archive. It is optional and + * the default value is '.' which means the current folder. If the target + * folder doesn't exist, the script attempts to create it and give it + * permissions 0777 by default. + * + * RemovePath is very usefull when you want to extract files from a subfoler + * in the archive to a root folder. For instance, if you have a file in the + * archive called some/sub/folder/test.txt and you want to extract it to the + * script folder, you can call Extract with To = '.' and RemovePath = + * 'some/sub/folder/' + * + * FileMode is optional and its default value is 0755. It is in fact the UNIX + * permission in octal mode (prefixed with a 0) that will be given on each + * extracted file. + */ + function Extract($p_what = FULL_ARCHIVE, $p_to = '.', $p_remdir='', $p_mode = 0755) { + if(!$this->_OpenRead()) return -4; + // if(!@is_dir($p_to)) if(!@mkdir($p_to, 0777)) return -8; --CS + if(!@is_dir($p_to)) if(!$this->_dirApp($p_to)) return -8; //--CS (route through correct dir fn) + + $ok = $this->_extractList($p_to, $p_what, $p_remdir, $p_mode); + $this->_CompTar(); + + return $ok; } - return $p_filelist; - } + /** + * Create a new package with the given files + * + * This function will attempt to create a new archive with global headers + * then add the given files into. If the archive is a real file, the + * contents are written directly into the file, if it is a dynamic archive + * contents are only stored in memory. This function should not be used to + * add files to an existing archive, you should use Add() instead. + * + * The FileList actually supports three different modes : + * + * - You can pass a string containing filenames separated by pipes '|'. + * In this case the file are read from the webserver filesystem and the + * root folder is the folder where the script using the MaxgTar is called. + * + * - You can also give a unidimensional indexed array containing the + * filenames. The behaviour for the content reading is the same that a + * '|'ed string. + * + * - The more useful usage is to pass bidimensional arrays, where the + * first element contains the filename and the second contains the file + * contents. You can even add empty folders to the package if the filename + * has a leading '/'. Once again, have a look at the exemples to understand + * better. + * + * Note you can also give arrays with both dynamic contents and static files. + * + * The optional parameter RemovePath can be used to delete a part of the tree + * of the filename you're adding, for instance if you're adding in the root + * of a package a file that is stored somewhere in the server tree. + * + * On the contrary the parameter AddPath can be used to add a prefix folder + * to the file you store. Note also that the RemovePath is applied before the + * AddPath is added, so it HAS a sense to use both parameters together. + */ + function Create($p_filelist,$p_add='',$p_rem='') { + if(!$fl = $this->_fetchFilelist($p_filelist)) return -5; + if(!$this->_OpenWrite()) return -6; + + $ok = $this->_addFileList($fl,$p_add,$p_rem); + + if($ok){ + $this->_writeFooter(); + }else{ + $this->_CompTar(); + @unlink($this->_nomf); + } - function _addFileList($p_fl, $p_addir, $p_remdir) - { - foreach($p_fl as $file) - { - if(($file == $this->_nomf && $this->_nomf != ARCHIVE_DYNAMIC) || !$file || (!file_exists($file) && !is_array($file))) - continue; + return $ok; + } - if (!$this->_addFile($file, $p_addir, $p_remdir)) - continue; + /** + * Add files to an existing package. + * + * This function does exactly the same than Create() exept it + * will append the given files at the end of the archive. Please not the is + * safe to call Add() on a newly created archive whereas the + * contrary will fail ! + * + * This function returns a status code, you can use TarErrorStr() on + * it to get the human-readable description of the error. + */ + function Add($p_filelist, $p_add = '', $p_rem = '') { + if (($this->_nomf != ARCHIVE_DYNAMIC && @is_file($this->_nomf)) || + ($this->_nomf == ARCHIVE_DYNAMIC && !$this->_memdat)){ + return $this->Create($p_filelist, $p_add, $p_rem); + } - if (@is_dir($file)) - { - $d = @opendir($file); + if(!$fl = $this->_fetchFilelist($p_filelist)) return -5; + return $this->_append($fl, $p_add, $p_rem); + } - if(!$d) continue; - readdir($d); readdir($d); + /** + * Read the contents of a TAR archive + * + * This function attempts to get the list of the files stored in the + * archive, and return either an error code or an indexed array of + * associative array containing for each file the following informations : + * + * checksum Tar Checksum of the file + * filename The full name of the stored file (up to 100 c.) + * mode UNIX permissions in DECIMAL, not octal + * uid The Owner ID + * gid The Group ID + * size Uncompressed filesize + * mtime Timestamp of last modification + * typeflag Empty for files, set for folders + * link For the links, did you guess it ? + * uname Owner name + * gname Group name + */ + function ListContents() { + if(!$this->_nomf) return -3; + if(!$this->_OpenRead()) return -4; + + $result = Array(); + + while ($dat = $this->_read(512)) { + $dat = $this->_readHeader($dat); + if(!is_array($dat)) continue; + + $this->_seek(ceil($dat['size']/512)*512,1); + $result[] = $dat; + } + + return $result; + } - while($f = readdir($d)) - { - if($file != ".") $tmplist[0] = "$file/$f"; - else $tmplist[0] = $d; + /** + * Convert a status code into a human readable message + * + * Some MaxgTar functions like Create(), Add() ... return numerical + * status code. You can pass them to this function to grab their english + * equivalent. + */ + function TarErrorStr($i) { + $ecodes = Array( + 1 => true, + 0 => "Undocumented error", + -1 => "Can't use COMPRESS_GZIP compression : ZLIB extensions are not loaded !", + -2 => "Can't use COMPRESS_BZIP compression : BZ2 extensions are not loaded !", + -3 => "You must set a archive file to read the contents !", + -4 => "Can't open the archive file for read !", + -5 => "Invalide file list !", + -6 => "Can't open the archive in write mode !", + -7 => "There is no ARCHIVE_DYNAMIC to write !", + -8 => "Can't create the directory to extract files !", + -9 => "Please pass a archive name to send if you made created an ARCHIVE_DYNAMIC !", + -10 => "You didn't pass an archive filename and there is no stored ARCHIVE_DYNAMIC !", + -11 => "Given archive doesn't exist !" + ); + + return isset($ecodes[$i]) ? $ecodes[$i] : $ecodes[0]; + } - $this->_addFileList($tmplist, $p_addir, $p_remdir); + /** + * Display informations about the MaxgTar Class. + * + * This function will display vaious informations about the server + * MaxgTar is running on. + * + * The optional parameter DispHeaders is used to generate a full page with + * HTML headers (TRUE by default) or just the table with the informations + * (FALSE). Note that the HTML page generated is verified compatible XHTML + * 1.0, but not HTML 4.0 compatible. + */ + function TarInfo($headers = true) { + if($headers) { + ?> + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + <html> + + <head> + <title>MaxgComp TAR</title> + <style type="text/css"> + body{margin: 20px;} + body,td{font-size:10pt;font-family: arial;} + </style> + <meta name="Author" content="The Maxg Network, http://maxg.info" /> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> + </head> + + <body bgcolor="#EFEFEF"> + <?php } + ?> + <table border="0" align="center" width="500" cellspacing="4" cellpadding="5" style="border:1px dotted black;"> + <tr> + <td align="center" bgcolor="#DFDFEF" colspan="3" style="font-size:15pt;font-color:#330000;border:1px solid black;">MaxgComp TAR</td> + </tr> + <tr> + <td colspan="2" bgcolor="#EFEFFE" style="border:1px solid black;">This software was created by the Maxg Network, <a href="http://maxg.info" target="_blank" style="text-decoration:none;color:#333366;">http://maxg.info</a> + <br />It is distributed under the GNU <a href="http://www.gnu.org/copyleft/lesser.html" target="_blank" style="text-decoration:none;color:#333366;">Lesser General Public License</a> + <br />You can find the documentation of this class <a href="http://docs.maxg.info" target="_blank" style="text-decoration:none;color:#333366;">here</a></td> + <td width="60" bgcolor="#EFEFFE" style="border:1px solid black;" align="center"><img src="http://img.maxg.info/menu/tar.gif" border="0" alt="MaxgComp TAR" /></td> + </tr> + <tr> + <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">MaxgComp TAR version</td> + <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=TARLIB_VERSION?></td> + </tr> + <tr> + <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">ZLIB extensions</td> + <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=(extension_loaded('zlib') ? '<b>Yes</b>' : '<i>No</i>')?></td> + </tr> + <tr> + <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">BZ2 extensions</td> + <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=(extension_loaded('bz2') ? '<b>Yes</b>' : '<i>No</i>')?></td> + </tr> + <tr> + <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">Allow URL fopen</td> + <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=(ini_get('allow_url_fopen') ? '<b>Yes</b>' : '<i>No</i>')?></td> + </tr> + <tr> + <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">Time limit</td> + <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=ini_get('max_execution_time')?></td> + </tr> + <tr> + <td width="50%" align="center" style="border:1px solid black;" bgcolor="#DFDFEF">PHP Version</td> + <td colspan="2" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"><?=phpversion()?></td> + </tr> + <tr> + <td colspan="3" align="center" bgcolor="#EFEFFE" style="border:1px solid black;"> + <i>Special thanks to « Vincent Blavet » for his PEAR::Archive_Tar class</i> + </td> + </tr> + </table> + <?php + if($headers) echo '</body></html>'; + } - closedir($d); unset($tmplist,$f); - } + function _seek($p_flen, $tell=0) { + if($this->_nomf === ARCHIVE_DYNAMIC) + $this->_memdat=substr($this->_memdat,0,($tell ? strlen($this->_memdat) : 0) + $p_flen); + elseif($this->_comptype == COMPRESS_GZIP) + @gzseek($this->_fp, ($tell ? @gztell($this->_fp) : 0)+$p_flen); + elseif($this->_comptype == COMPRESS_BZIP) + @fseek($this->_fp, ($tell ? @ftell($this->_fp) : 0)+$p_flen); + else + @fseek($this->_fp, ($tell ? @ftell($this->_fp) : 0)+$p_flen); } - return true; - } - function _addFile($p_fn, $p_addir = '', $p_remdir = '') - { - if(is_array($p_fn)) list($p_fn, $data) = $p_fn; - $sname = $p_fn; + function _OpenRead() { + if($this->_comptype == COMPRESS_GZIP) + $this->_fp = @gzopen($this->_nomf, 'rb'); + elseif($this->_comptype == COMPRESS_BZIP) + $this->_fp = @bzopen($this->_nomf, 'rb'); + else + $this->_fp = @fopen($this->_nomf, 'rb'); + + return ($this->_fp ? true : false); + } - if($p_remdir) - { - if(substr($p_remdir,-1) != '/') $p_remdir .= "/"; + function _OpenWrite($add = 'w') { + if($this->_nomf === ARCHIVE_DYNAMIC) return true; + + if($this->_comptype == COMPRESS_GZIP) + $this->_fp = @gzopen($this->_nomf, $add.'b'.$this->_compzlevel); + elseif($this->_comptype == COMPRESS_BZIP) + $this->_fp = @bzopen($this->_nomf, $add.'b'); + else + $this->_fp = @fopen($this->_nomf, $add.'b'); - if(substr($sname, 0, strlen($p_remdir)) == $p_remdir) - $sname = substr($sname, strlen($p_remdir)); + return ($this->_fp ? true : false); } - if($p_addir) $sname = $p_addir.(substr($p_addir,-1) == '/' ? '' : "/").$sname; + function _CompTar() { + if($this->_nomf === ARCHIVE_DYNAMIC || !$this->_fp) return; - if(strlen($sname) > 99) return; + if($this->_comptype == COMPRESS_GZIP) @gzclose($this->_fp); + elseif($this->_comptype == COMPRESS_BZIP) @bzclose($this->_fp); + else @fclose($this->_fp); + } + + function _read($p_len) { + if($this->_comptype == COMPRESS_GZIP) + return @gzread($this->_fp,$p_len); + elseif($this->_comptype == COMPRESS_BZIP) + return @bzread($this->_fp,$p_len); + else + return @fread($this->_fp,$p_len); + } + + function _write($p_data) { + if($this->_nomf === ARCHIVE_DYNAMIC) $this->_memdat .= $p_data; + elseif($this->_comptype == COMPRESS_GZIP) + return @gzwrite($this->_fp,$p_data); - if(@is_dir($p_fn)) - { - if(!$this->_writeFileHeader($p_fn, $sname)) return false; + elseif($this->_comptype == COMPRESS_BZIP) + return @bzwrite($this->_fp,$p_data); + + else + return @fwrite($this->_fp,$p_data); } - else - { - if(!$data) - { - $fp = fopen($p_fn, 'rb'); - if(!$fp) return false; - } - - if(!$this->_writeFileHeader($p_fn, $sname, ($data ? strlen($data) : false))) return false; - - if(!$data) - { - while(!feof($fp)) - { - $packed = pack("a512", fread($fp,512)); - $this->_write($packed); - } - fclose($fp); - } - else - { - for($s = 0; $s < strlen($data); $s += 512) - $this->_write(pack("a512",substr($data,$s,512))); - } + + function _encode($p_dat) { + if($this->_comptype == COMPRESS_GZIP) + return gzencode($p_dat, $this->_compzlevel); + elseif($this->_comptype == COMPRESS_BZIP) + return bzcompress($p_dat, $this->_compzlevel); + else return $p_dat; } - return true; - } - - function _writeFileHeader($p_file, $p_sname, $p_data=false) - { - if(!$p_data) - { - if (!$p_sname) $p_sname = $p_file; - $p_sname = $this->_pathTrans($p_sname); - - $h_info = stat($p_file); - $h[0] = sprintf("%6s ", DecOct($h_info[4])); - $h[] = sprintf("%6s ", DecOct($h_info[5])); - $h[] = sprintf("%6s ", DecOct(fileperms($p_file))); - clearstatcache(); - $h[] = sprintf("%11s ", DecOct(filesize($p_file))); - $h[] = sprintf("%11s", DecOct(filemtime($p_file))); - - $dir = @is_dir($p_file) ? '5' : ''; - } - else - { - $dir = ''; - $p_data = sprintf("%11s ", DecOct($p_data)); - $time = sprintf("%11s ", DecOct(time())); - $h = Array(" 0 "," 0 "," 40777 ",$p_data,$time); - } - - $data_first = pack("a100a8a8a8a12A12", $p_sname, $h[2], $h[0], $h[1], $h[3], $h[4]); - $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $dir, '', '', '', '', '', '', '', '', ""); - - for ($i=0,$chks=0; $i<148; $i++) - $chks += ord($data_first[$i]); - - for ($i=156, $chks+=256, $j=0; $i<512; $i++, $j++) - $chks += ord($data_last[$j]); - - $this->_write($data_first); - - $chks = pack("a8",sprintf("%6s ", DecOct($chks))); - $this->_write($chks.$data_last); - - return true; - } - - function _append($p_filelist, $p_addir="", $p_remdir="") - { - if(!$this->_fp) if(!$this->_OpenWrite('a')) return -6; - - if($this->_nomf == ARCHIVE_DYNAMIC) - { - $s = strlen($this->_memdat); - $this->_memdat = substr($this->_memdat,0,-512); + function _readHeader($p_dat) { + if (!$p_dat || strlen($p_dat) != 512) return false; + + for ($i=0, $chks=0; $i<148; $i++) + $chks += ord($p_dat[$i]); + + for ($i=156,$chks+=256; $i<512; $i++) + $chks += ord($p_dat[$i]); + + $headers = @unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $p_dat); + if(!$headers) return false; + + $return['checksum'] = OctDec(trim($headers['checksum'])); + if ($return['checksum'] != $chks) return false; + + $return['filename'] = trim($headers['filename']); + $return['mode'] = OctDec(trim($headers['mode'])); + $return['uid'] = OctDec(trim($headers['uid'])); + $return['gid'] = OctDec(trim($headers['gid'])); + $return['size'] = OctDec(trim($headers['size'])); + $return['mtime'] = OctDec(trim($headers['mtime'])); + $return['typeflag'] = $headers['typeflag']; + $return['link'] = trim($headers['link']); + $return['uname'] = trim($headers['uname']); + $return['gname'] = trim($headers['gname']); + + return $return; } - else - { - $s = filesize($this->_nomf); - $this->_seek($s-512); + + function _fetchFilelist($p_filelist) { + if(!$p_filelist || (is_array($p_filelist) && !@count($p_filelist))) return false; + + if(is_string($p_filelist)) { + $p_filelist = explode('|',$p_filelist); + if(!is_array($p_filelist)) $p_filelist = Array($p_filelist); + } + + return $p_filelist; } - $ok = $this->_addFileList($p_filelist, $p_addir, $p_remdir); - $this->_writeFooter(); - - return $ok; - } - - function _pathTrans($p_dir) - { - if ($p_dir) - { - $subf = explode("/", $p_dir); $r=''; - - for ($i=count($subf)-1; $i>=0; $i--) - { - if ($subf[$i] == ".") {} - else if ($subf[$i] == "..") $i--; - else if (!$subf[$i] && $i!=count($subf)-1 && $i) {} - else $r = $subf[$i].($i!=(count($subf)-1) ? "/".$r : ""); - } + function _addFileList($p_fl, $p_addir, $p_remdir) { + foreach($p_fl as $file) { + if(($file == $this->_nomf && $this->_nomf != ARCHIVE_DYNAMIC) || !$file || (!file_exists($file) && !is_array($file))) + continue; + + if (!$this->_addFile($file, $p_addir, $p_remdir)) + continue; + + if (@is_dir($file)) { + $d = @opendir($file); + + if(!$d) continue; + readdir($d); + readdir($d); + + while($f = readdir($d)) { + if($file != ".") $tmplist[0] = "$file/$f"; + else $tmplist[0] = $d; + + $this->_addFileList($tmplist, $p_addir, $p_remdir); + } + + closedir($d); + unset($tmplist,$f); + } + } + return true; } - return $r; - } - - function _writeFooter() - { - $this->_write(pack("a512", "")); - } - - function _extractList($p_to, $p_files, $p_remdir, $p_mode = 0755) - { - if (!$p_to || ($p_to[0]!="/"&&substr($p_to,0,3)!="../"&&substr($p_to,1,3)!=":\\"&&substr($p_to,1,2)!=":/")) /*" // <- PHP Coder bug */ - $p_to = "./$p_to"; - - if ($p_remdir && substr($p_remdir,-1)!='/') $p_remdir .= '/'; - $p_remdirs = strlen($p_remdir); - while($dat = $this->_read(512)) - { - $headers = $this->_readHeader($dat); - if(!$headers['filename']) continue; - - if($p_files == -1 || $p_files[0] == -1) $extract = true; - else - { - $extract = false; - - foreach($p_files as $f) - { - if(substr($f,-1) == "/") { - if((strlen($headers['filename']) > strlen($f)) && (substr($headers['filename'],0,strlen($f))==$f)) { - $extract = true; break; + + function _addFile($p_fn, $p_addir = '', $p_remdir = '') { + if(is_array($p_fn)) list($p_fn, $data) = $p_fn; + $sname = $p_fn; + + if($p_remdir) { + if(substr($p_remdir,-1) != '/') $p_remdir .= "/"; + + if(substr($sname, 0, strlen($p_remdir)) == $p_remdir) + $sname = substr($sname, strlen($p_remdir)); + } + + if($p_addir) $sname = $p_addir.(substr($p_addir,-1) == '/' ? '' : "/").$sname; + + if(strlen($sname) > 99) return; + + if(@is_dir($p_fn)) { + if(!$this->_writeFileHeader($p_fn, $sname)) return false; + } else { + if(!$data) { + $fp = fopen($p_fn, 'rb'); + if(!$fp) return false; + } + + if(!$this->_writeFileHeader($p_fn, $sname, ($data ? strlen($data) : false))) return false; + + if(!$data) { + while(!feof($fp)) { + $packed = pack("a512", fread($fp,512)); + $this->_write($packed); + } + fclose($fp); + } else { + $len = strlen($data); + for($s = 0; $s < $len; $s += 512){ + $this->_write(pack("a512",substr($data,$s,512))); + } } - } - elseif($f == $headers['filename']) { - $extract = true; break; - } } - } - if ($extract) - { - $det[] = $headers; - if ($p_remdir && substr($headers['filename'],0,$p_remdirs)==$p_remdir) - $headers['filename'] = substr($headers['filename'],$p_remdirs); + return true; + } + + function _writeFileHeader($p_file, $p_sname, $p_data=false) { + if(!$p_data) { + if (!$p_sname) $p_sname = $p_file; + $p_sname = $this->_pathTrans($p_sname); + + $h_info = stat($p_file); + $h[0] = sprintf("%6s ", DecOct($h_info[4])); + $h[] = sprintf("%6s ", DecOct($h_info[5])); + $h[] = sprintf("%6s ", DecOct(fileperms($p_file))); + clearstatcache(); + $h[] = sprintf("%11s ", DecOct(filesize($p_file))); + $h[] = sprintf("%11s", DecOct(filemtime($p_file))); + + $dir = @is_dir($p_file) ? '5' : ''; + } else { + $dir = ''; + $p_data = sprintf("%11s ", DecOct($p_data)); + $time = sprintf("%11s ", DecOct(time())); + $h = Array(" 0 "," 0 "," 40777 ",$p_data,$time); + } - if($headers['filename'].'/' == $p_remdir && $headers['typeflag']=='5') continue; + $data_first = pack("a100a8a8a8a12A12", $p_sname, $h[2], $h[0], $h[1], $h[3], $h[4]); + $data_last = pack("a1a100a6a2a32a32a8a8a155a12", $dir, '', '', '', '', '', '', '', '', ""); - if ($p_to != "./" && $p_to != "/") - { - while($p_to{-1}=="/") $p_to = substr($p_to,0,-1); + for ($i=0,$chks=0; $i<148; $i++) + $chks += ord($data_first[$i]); + + for ($i=156, $chks+=256, $j=0; $i<512; $i++, $j++) + $chks += ord($data_last[$j]); + + $this->_write($data_first); + + $chks = pack("a8",sprintf("%6s ", DecOct($chks))); + $this->_write($chks.$data_last); + + return true; + } - if($headers['filename']{0} == "/") - $headers['filename'] = $p_to.$headers['filename']; - else - $headers['filename'] = $p_to."/".$headers['filename']; + function _append($p_filelist, $p_addir="", $p_remdir="") { + if(!$this->_fp) if(!$this->_OpenWrite('a')) return -6; + + if($this->_nomf == ARCHIVE_DYNAMIC) { + $s = strlen($this->_memdat); + $this->_memdat = substr($this->_memdat,0,-512); + } else { + $s = filesize($this->_nomf); + $this->_seek($s-512); } - $ok = $this->_dirApp($headers['typeflag']=="5" ? $headers['filename'] : dirname($headers['filename'])); - if($ok < 0) return $ok; + $ok = $this->_addFileList($p_filelist, $p_addir, $p_remdir); + $this->_writeFooter(); + + return $ok; + } + + function _pathTrans($p_dir) { + if ($p_dir) { + $subf = explode("/", $p_dir); + $r=''; + + for ($i=count($subf)-1; $i>=0; $i--) { + if ($subf[$i] == ".") { + # do nothing + } elseif ($subf[$i] == "..") { + $i--; + } elseif (!$subf[$i] && $i!=count($subf)-1 && $i) { + # do nothing + } else { + $r = $subf[$i].($i!=(count($subf)-1) ? "/".$r : ""); + } + } + } + return $r; + } - if (!$headers['typeflag']) - { - if (!$fp = @fopen($headers['filename'], "wb")) return -6; - $n = floor($headers['size']/512); + function _writeFooter() { + $this->_write(pack("a512", "")); + } - for ($i=0; $i<$n; $i++) fwrite($fp, $this->_read(512),512); - if (($headers['size'] % 512) != 0) fwrite($fp, $this->_read(512), $headers['size'] % 512); + function _extractList($p_to, $p_files, $p_remdir, $p_mode = 0755) { + if (!$p_to || ($p_to[0]!="/"&&substr($p_to,0,3)!="../"&&substr($p_to,1,3)!=":\\"&&substr($p_to,1,2)!=":/")) /*" // <- PHP Coder bug */ + $p_to = "./$p_to"; + + if ($p_remdir && substr($p_remdir,-1)!='/') $p_remdir .= '/'; + $p_remdirs = strlen($p_remdir); + while($dat = $this->_read(512)) { + $headers = $this->_readHeader($dat); + if(!$headers['filename']) continue; + + if($p_files == -1 || $p_files[0] == -1){ + $extract = true; + } else { + $extract = false; + + foreach($p_files as $f) { + if(substr($f,-1) == "/") { + if((strlen($headers['filename']) > strlen($f)) && (substr($headers['filename'],0,strlen($f))==$f)) { + $extract = true; + break; + } + } elseif($f == $headers['filename']) { + $extract = true; + break; + } + } + } - fclose($fp); - touch($headers['filename'], $headers['mtime']); - chmod($headers['filename'], $p_mode); + if ($extract) { + $det[] = $headers; + if ($p_remdir && substr($headers['filename'],0,$p_remdirs)==$p_remdir) + $headers['filename'] = substr($headers['filename'],$p_remdirs); + + if($headers['filename'].'/' == $p_remdir && $headers['typeflag']=='5') continue; + + if ($p_to != "./" && $p_to != "/") { + while($p_to{-1}=="/") $p_to = substr($p_to,0,-1); + + if($headers['filename']{0} == "/") + $headers['filename'] = $p_to.$headers['filename']; + else + $headers['filename'] = $p_to."/".$headers['filename']; + } + + $ok = $this->_dirApp($headers['typeflag']=="5" ? $headers['filename'] : dirname($headers['filename'])); + if($ok < 0) return $ok; + + if (!$headers['typeflag']) { + if (!$fp = @fopen($headers['filename'], "wb")) return -6; + $n = floor($headers['size']/512); + + for ($i=0; $i<$n; $i++){ + fwrite($fp, $this->_read(512),512); + } + if (($headers['size'] % 512) != 0) fwrite($fp, $this->_read(512), $headers['size'] % 512); + + fclose($fp); + touch($headers['filename'], $headers['mtime']); + chmod($headers['filename'], $p_mode); + } else { + $this->_seek(ceil($headers['size']/512)*512,1); + } + }else $this->_seek(ceil($headers['size']/512)*512,1); } - else - { - $this->_seek(ceil($headers['size']/512)*512,1); - } - }else $this->_seek(ceil($headers['size']/512)*512,1); + return $det; } - return $det; - } - -function _dirApp($d) - { -// map to dokuwiki function (its more robust) - return io_mkdir_p($d); -/* - $d = explode('/', $d); - $base = ''; - - foreach($d as $f) - { - if(!is_dir($base.$f)) - { - $ok = @mkdir($base.$f, 0777); - if(!$ok) return false; - } - $base .= "$f/"; + + function _dirApp($d) { + // map to dokuwiki function (its more robust) + return io_mkdir_p($d); } -*/ - } } diff --git a/inc/actions.php b/inc/actions.php index 27292e6f6..92f817133 100644 --- a/inc/actions.php +++ b/inc/actions.php @@ -18,149 +18,149 @@ require_once(DOKU_INC.'inc/template.php'); * @triggers ACTION_HEADERS_SEND */ function act_dispatch(){ - global $INFO; - global $ACT; - global $ID; - global $QUERY; - global $lang; - global $conf; - global $license; - - $preact = $ACT; - - // give plugins an opportunity to process the action - $evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT); - if ($evt->advise_before()) { - - //sanitize $ACT - $ACT = act_clean($ACT); - - //check if searchword was given - else just show - $s = cleanID($QUERY); - if($ACT == 'search' && empty($s)){ - $ACT = 'show'; - } + global $INFO; + global $ACT; + global $ID; + global $QUERY; + global $lang; + global $conf; + global $license; - //login stuff - if(in_array($ACT,array('login','logout'))){ - $ACT = act_auth($ACT); - } + $preact = $ACT; - //check if user is asking to (un)subscribe a page - if($ACT == 'subscribe' || $ACT == 'unsubscribe') - $ACT = act_subscription($ACT); + // give plugins an opportunity to process the action + $evt = new Doku_Event('ACTION_ACT_PREPROCESS',$ACT); + if ($evt->advise_before()) { - //check if user is asking to (un)subscribe a namespace - if($ACT == 'subscribens' || $ACT == 'unsubscribens') - $ACT = act_subscriptionns($ACT); + //sanitize $ACT + $ACT = act_clean($ACT); - //check permissions - $ACT = act_permcheck($ACT); + //check if searchword was given - else just show + $s = cleanID($QUERY); + if($ACT == 'search' && empty($s)){ + $ACT = 'show'; + } - //register - $nil = array(); - if($ACT == 'register' && $_POST['save'] && register()){ - $ACT = 'login'; - } + //login stuff + if(in_array($ACT,array('login','logout'))){ + $ACT = act_auth($ACT); + } - if ($ACT == 'resendpwd' && act_resendpwd()) { - $ACT = 'login'; - } + //check if user is asking to (un)subscribe a page + if($ACT == 'subscribe' || $ACT == 'unsubscribe') + $ACT = act_subscription($ACT); + + //check if user is asking to (un)subscribe a namespace + if($ACT == 'subscribens' || $ACT == 'unsubscribens') + $ACT = act_subscriptionns($ACT); - //update user profile - if ($ACT == 'profile') { - if(!$_SERVER['REMOTE_USER']) { - $ACT = 'login'; - } else { - if(updateprofile()) { - msg($lang['profchanged'],1); - $ACT = 'show'; + //check permissions + $ACT = act_permcheck($ACT); + + //register + $nil = array(); + if($ACT == 'register' && $_POST['save'] && register()){ + $ACT = 'login'; } - } - } - //revert - if($ACT == 'revert'){ - if(checkSecurityToken()){ - $ACT = act_revert($ACT); - }else{ - $ACT = 'show'; - } - } + if ($ACT == 'resendpwd' && act_resendpwd()) { + $ACT = 'login'; + } - //save - if($ACT == 'save'){ - if(checkSecurityToken()){ - $ACT = act_save($ACT); - }else{ - $ACT = 'show'; - } - } + //update user profile + if ($ACT == 'profile') { + if(!$_SERVER['REMOTE_USER']) { + $ACT = 'login'; + } else { + if(updateprofile()) { + msg($lang['profchanged'],1); + $ACT = 'show'; + } + } + } - //cancel conflicting edit - if($ACT == 'cancel') - $ACT = 'show'; + //revert + if($ACT == 'revert'){ + if(checkSecurityToken()){ + $ACT = act_revert($ACT); + }else{ + $ACT = 'show'; + } + } - //draft deletion - if($ACT == 'draftdel') - $ACT = act_draftdel($ACT); + //save + if($ACT == 'save'){ + if(checkSecurityToken()){ + $ACT = act_save($ACT); + }else{ + $ACT = 'show'; + } + } - //draft saving on preview - if($ACT == 'preview') - $ACT = act_draftsave($ACT); + //cancel conflicting edit + if($ACT == 'cancel') + $ACT = 'show'; - //edit - if(($ACT == 'edit' || $ACT == 'preview') && $INFO['editable']){ - $ACT = act_edit($ACT); - }else{ - unlock($ID); //try to unlock - } + //draft deletion + if($ACT == 'draftdel') + $ACT = act_draftdel($ACT); - //handle export - if(substr($ACT,0,7) == 'export_') - $ACT = act_export($ACT); + //draft saving on preview + if($ACT == 'preview') + $ACT = act_draftsave($ACT); - //display some infos - if($ACT == 'check'){ - check(); - $ACT = 'show'; - } + //edit + if(($ACT == 'edit' || $ACT == 'preview') && $INFO['editable']){ + $ACT = act_edit($ACT); + }else{ + unlock($ID); //try to unlock + } - //handle admin tasks - if($ACT == 'admin'){ - // retrieve admin plugin name from $_REQUEST['page'] - if (!empty($_REQUEST['page'])) { - $pluginlist = plugin_list('admin'); - if (in_array($_REQUEST['page'], $pluginlist)) { - // attempt to load the plugin - if ($plugin =& plugin_load('admin',$_REQUEST['page']) !== NULL) - $plugin->handle(); - } - } - } + //handle export + if(substr($ACT,0,7) == 'export_') + $ACT = act_export($ACT); - // check permissions again - the action may have changed - $ACT = act_permcheck($ACT); - } // end event ACTION_ACT_PREPROCESS default action - $evt->advise_after(); - unset($evt); + //display some infos + if($ACT == 'check'){ + check(); + $ACT = 'show'; + } - // when action 'show', the intial not 'show' and POST, do a redirect - if($ACT == 'show' && $preact != 'show' && strtolower($_SERVER['REQUEST_METHOD']) == 'post'){ - act_redirect($ID,$preact); - } + //handle admin tasks + if($ACT == 'admin'){ + // retrieve admin plugin name from $_REQUEST['page'] + if (!empty($_REQUEST['page'])) { + $pluginlist = plugin_list('admin'); + if (in_array($_REQUEST['page'], $pluginlist)) { + // attempt to load the plugin + if ($plugin =& plugin_load('admin',$_REQUEST['page']) !== null) + $plugin->handle(); + } + } + } + + // check permissions again - the action may have changed + $ACT = act_permcheck($ACT); + } // end event ACTION_ACT_PREPROCESS default action + $evt->advise_after(); + unset($evt); + + // when action 'show', the intial not 'show' and POST, do a redirect + if($ACT == 'show' && $preact != 'show' && strtolower($_SERVER['REQUEST_METHOD']) == 'post'){ + act_redirect($ID,$preact); + } - //call template FIXME: all needed vars available? - $headers[] = 'Content-Type: text/html; charset=utf-8'; - trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders'); + //call template FIXME: all needed vars available? + $headers[] = 'Content-Type: text/html; charset=utf-8'; + trigger_event('ACTION_HEADERS_SEND',$headers,'act_sendheaders'); - include(template('main.php')); - // output for the commands is now handled in inc/templates.php - // in function tpl_content() + include(template('main.php')); + // output for the commands is now handled in inc/templates.php + // in function tpl_content() } function act_sendheaders($headers) { - foreach ($headers as $hdr) header($hdr); + foreach ($headers as $hdr) header($hdr); } /** @@ -171,44 +171,44 @@ function act_sendheaders($headers) { * @author Andreas Gohr <andi@splitbrain.org> */ function act_clean($act){ - global $lang; - global $conf; + global $lang; + global $conf; - // check if the action was given as array key - if(is_array($act)){ - list($act) = array_keys($act); - } + // check if the action was given as array key + if(is_array($act)){ + list($act) = array_keys($act); + } - //remove all bad chars - $act = strtolower($act); - $act = preg_replace('/[^1-9a-z_]+/','',$act); + //remove all bad chars + $act = strtolower($act); + $act = preg_replace('/[^1-9a-z_]+/','',$act); - if($act == 'export_html') $act = 'export_xhtml'; - if($act == 'export_htmlbody') $act = 'export_xhtmlbody'; + if($act == 'export_html') $act = 'export_xhtml'; + if($act == 'export_htmlbody') $act = 'export_xhtmlbody'; - // check if action is disabled - if(!actionOK($act)){ - msg('Command disabled: '.htmlspecialchars($act),-1); - return 'show'; - } + // check if action is disabled + if(!actionOK($act)){ + msg('Command disabled: '.htmlspecialchars($act),-1); + return 'show'; + } - //disable all acl related commands if ACL is disabled - if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin', - 'subscribe','unsubscribe','profile','revert', - 'resendpwd','subscribens','unsubscribens',))){ - msg('Command unavailable: '.htmlspecialchars($act),-1); - return 'show'; - } - - if(!in_array($act,array('login','logout','register','save','cancel','edit','draft', - 'preview','search','show','check','index','revisions', - 'diff','recent','backlink','admin','subscribe','revert', - 'unsubscribe','profile','resendpwd','recover','wordblock', - 'draftdel','subscribens','unsubscribens',)) && substr($act,0,7) != 'export_' ) { - msg('Command unknown: '.htmlspecialchars($act),-1); - return 'show'; - } - return $act; + //disable all acl related commands if ACL is disabled + if(!$conf['useacl'] && in_array($act,array('login','logout','register','admin', + 'subscribe','unsubscribe','profile','revert', + 'resendpwd','subscribens','unsubscribens',))){ + msg('Command unavailable: '.htmlspecialchars($act),-1); + return 'show'; + } + + if(!in_array($act,array('login','logout','register','save','cancel','edit','draft', + 'preview','search','show','check','index','revisions', + 'diff','recent','backlink','admin','subscribe','revert', + 'unsubscribe','profile','resendpwd','recover','wordblock', + 'draftdel','subscribens','unsubscribens',)) && substr($act,0,7) != 'export_' ) { + msg('Command unknown: '.htmlspecialchars($act),-1); + return 'show'; + } + return $act; } /** @@ -217,44 +217,44 @@ function act_clean($act){ * @author Andreas Gohr <andi@splitbrain.org> */ function act_permcheck($act){ - global $INFO; - global $conf; - - if(in_array($act,array('save','preview','edit','recover'))){ - if($INFO['exists']){ - if($act == 'edit'){ - //the edit function will check again and do a source show - //when no AUTH_EDIT available - $permneed = AUTH_READ; - }else{ - $permneed = AUTH_EDIT; - } - }else{ - $permneed = AUTH_CREATE; - } - }elseif(in_array($act,array('login','search','recent','profile'))){ - $permneed = AUTH_NONE; - }elseif($act == 'revert'){ - $permneed = AUTH_ADMIN; - if($INFO['ismanager']) $permneed = AUTH_EDIT; - }elseif($act == 'register'){ - $permneed = AUTH_NONE; - }elseif($act == 'resendpwd'){ - $permneed = AUTH_NONE; - }elseif($act == 'admin'){ - if($INFO['ismanager']){ - // if the manager has the needed permissions for a certain admin - // action is checked later - $permneed = AUTH_READ; + global $INFO; + global $conf; + + if(in_array($act,array('save','preview','edit','recover'))){ + if($INFO['exists']){ + if($act == 'edit'){ + //the edit function will check again and do a source show + //when no AUTH_EDIT available + $permneed = AUTH_READ; + }else{ + $permneed = AUTH_EDIT; + } + }else{ + $permneed = AUTH_CREATE; + } + }elseif(in_array($act,array('login','search','recent','profile'))){ + $permneed = AUTH_NONE; + }elseif($act == 'revert'){ + $permneed = AUTH_ADMIN; + if($INFO['ismanager']) $permneed = AUTH_EDIT; + }elseif($act == 'register'){ + $permneed = AUTH_NONE; + }elseif($act == 'resendpwd'){ + $permneed = AUTH_NONE; + }elseif($act == 'admin'){ + if($INFO['ismanager']){ + // if the manager has the needed permissions for a certain admin + // action is checked later + $permneed = AUTH_READ; + }else{ + $permneed = AUTH_ADMIN; + } }else{ - $permneed = AUTH_ADMIN; + $permneed = AUTH_READ; } - }else{ - $permneed = AUTH_READ; - } - if($INFO['perm'] >= $permneed) return $act; + if($INFO['perm'] >= $permneed) return $act; - return 'denied'; + return 'denied'; } /** @@ -263,10 +263,10 @@ function act_permcheck($act){ * Deletes the draft for the current page and user */ function act_draftdel($act){ - global $INFO; - @unlink($INFO['draft']); - $INFO['draft'] = null; - return 'show'; + global $INFO; + @unlink($INFO['draft']); + $INFO['draft'] = null; + return 'show'; } /** @@ -275,23 +275,23 @@ function act_draftdel($act){ * @todo this currently duplicates code from ajax.php :-/ */ function act_draftsave($act){ - global $INFO; - global $ID; - global $conf; - if($conf['usedraft'] && $_POST['wikitext']){ - $draft = array('id' => $ID, - 'prefix' => $_POST['prefix'], - 'text' => $_POST['wikitext'], - 'suffix' => $_POST['suffix'], - 'date' => $_POST['date'], - 'client' => $INFO['client'], - ); - $cname = getCacheName($draft['client'].$ID,'.draft'); - if(io_saveFile($cname,serialize($draft))){ - $INFO['draft'] = $cname; + global $INFO; + global $ID; + global $conf; + if($conf['usedraft'] && $_POST['wikitext']){ + $draft = array('id' => $ID, + 'prefix' => $_POST['prefix'], + 'text' => $_POST['wikitext'], + 'suffix' => $_POST['suffix'], + 'date' => $_POST['date'], + 'client' => $INFO['client'], + ); + $cname = getCacheName($draft['client'].$ID,'.draft'); + if(io_saveFile($cname,serialize($draft))){ + $INFO['draft'] = $cname; + } } - } - return $act; + return $act; } /** @@ -304,31 +304,31 @@ function act_draftsave($act){ * @author Andreas Gohr <andi@splitbrain.org> */ function act_save($act){ - global $ID; - global $DATE; - global $PRE; - global $TEXT; - global $SUF; - global $SUM; - - //spam check - if(checkwordblock()) - return 'wordblock'; - //conflict check //FIXME use INFO - if($DATE != 0 && @filemtime(wikiFN($ID)) > $DATE ) - return 'conflict'; - - //save it - saveWikiText($ID,con($PRE,$TEXT,$SUF,1),$SUM,$_REQUEST['minor']); //use pretty mode for con - //unlock it - unlock($ID); - - //delete draft - act_draftdel($act); - session_write_close(); - - // when done, show page - return 'show'; + global $ID; + global $DATE; + global $PRE; + global $TEXT; + global $SUF; + global $SUM; + + //spam check + if(checkwordblock()) + return 'wordblock'; + //conflict check //FIXME use INFO + if($DATE != 0 && @filemtime(wikiFN($ID)) > $DATE ) + return 'conflict'; + + //save it + saveWikiText($ID,con($PRE,$TEXT,$SUF,1),$SUM,$_REQUEST['minor']); //use pretty mode for con + //unlock it + unlock($ID); + + //delete draft + act_draftdel($act); + session_write_close(); + + // when done, show page + return 'show'; } /** @@ -374,38 +374,38 @@ function act_revert($act){ * Tries to add the section id as hash mark after section editing */ function act_redirect($id,$preact){ - global $PRE; - global $TEXT; - global $MSG; - - //are there any undisplayed messages? keep them in session for display - //on the next page - if(isset($MSG) && count($MSG)){ - //reopen session, store data and close session again - @session_start(); - $_SESSION[DOKU_COOKIE]['msg'] = $MSG; - session_write_close(); - } - - $opts = array( - 'id' => $id, - 'preact' => $preact - ); - //get section name when coming from section edit - if($PRE && preg_match('/^\s*==+([^=\n]+)/',$TEXT,$match)){ - $check = false; //Byref - $opts['fragment'] = sectionID($match[0], $check); - } - - trigger_event('ACTION_SHOW_REDIRECT',$opts,'act_redirect_execute'); + global $PRE; + global $TEXT; + global $MSG; + + //are there any undisplayed messages? keep them in session for display + //on the next page + if(isset($MSG) && count($MSG)){ + //reopen session, store data and close session again + @session_start(); + $_SESSION[DOKU_COOKIE]['msg'] = $MSG; + session_write_close(); + } + + $opts = array( + 'id' => $id, + 'preact' => $preact + ); + //get section name when coming from section edit + if($PRE && preg_match('/^\s*==+([^=\n]+)/',$TEXT,$match)){ + $check = false; //Byref + $opts['fragment'] = sectionID($match[0], $check); + } + + trigger_event('ACTION_SHOW_REDIRECT',$opts,'act_redirect_execute'); } function act_redirect_execute($opts){ - $go = wl($opts['id'],'',true); - if(isset($opts['fragment'])) $go .= '#'.$opts['fragment']; + $go = wl($opts['id'],'',true); + if(isset($opts['fragment'])) $go .= '#'.$opts['fragment']; - //show it - send_redirect($go); + //show it + send_redirect($go); } /** @@ -414,30 +414,30 @@ function act_redirect_execute($opts){ * @author Andreas Gohr <andi@splitbrain.org> */ function act_auth($act){ - global $ID; - global $INFO; + global $ID; + global $INFO; - //already logged in? - if(isset($_SERVER['REMOTE_USER']) && $act=='login'){ - return 'show'; - } + //already logged in? + if(isset($_SERVER['REMOTE_USER']) && $act=='login'){ + return 'show'; + } - //handle logout - if($act=='logout'){ - $lockedby = checklock($ID); //page still locked? - if($lockedby == $_SERVER['REMOTE_USER']) - unlock($ID); //try to unlock + //handle logout + if($act=='logout'){ + $lockedby = checklock($ID); //page still locked? + if($lockedby == $_SERVER['REMOTE_USER']) + unlock($ID); //try to unlock - // do the logout stuff - auth_logoff(); + // do the logout stuff + auth_logoff(); - // rebuild info array - $INFO = pageinfo(); + // rebuild info array + $INFO = pageinfo(); - act_redirect($ID,'login'); - } + act_redirect($ID,'login'); + } - return $act; + return $act; } /** @@ -446,15 +446,15 @@ function act_auth($act){ * @author Andreas Gohr <andi@splitbrain.org> */ function act_edit($act){ - global $ID; - global $INFO; + global $ID; + global $INFO; - //check if locked by anyone - if not lock for my self - $lockedby = checklock($ID); - if($lockedby) return 'locked'; + //check if locked by anyone - if not lock for my self + $lockedby = checklock($ID); + if($lockedby) return 'locked'; - lock($ID); - return $act; + lock($ID); + return $act; } /** @@ -472,81 +472,81 @@ function act_edit($act){ * @author Michael Klier <chi@chimeric.de> */ function act_export($act){ - global $ID; - global $REV; - global $conf; - global $lang; - - $pre = ''; - $post = ''; - $output = ''; - $headers = array(); - - // search engines: never cache exported docs! (Google only currently) - $headers['X-Robots-Tag'] = 'noindex'; - - $mode = substr($act,7); - switch($mode) { - case 'raw': - $headers['Content-Type'] = 'text/plain; charset=utf-8'; - $headers['Content-Disposition'] = 'attachment; filename='.noNS($ID).'.txt'; - $output = rawWiki($ID,$REV); - break; - case 'xhtml': - $pre .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . DOKU_LF; - $pre .= ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . DOKU_LF; - $pre .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"' . DOKU_LF; - $pre .= ' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">' . DOKU_LF; - $pre .= '<head>' . DOKU_LF; - $pre .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . DOKU_LF; - $pre .= ' <title>'.$ID.'</title>' . DOKU_LF; - - // get metaheaders - ob_start(); - tpl_metaheaders(); - $pre .= ob_get_clean(); - - $pre .= '</head>' . DOKU_LF; - $pre .= '<body>' . DOKU_LF; - $pre .= '<div class="dokuwiki export">' . DOKU_LF; - - // get toc - $pre .= tpl_toc(true); - - $headers['Content-Type'] = 'text/html; charset=utf-8'; - $output = p_wiki_xhtml($ID,$REV,false); - - $post .= '</div>' . DOKU_LF; - $post .= '</body>' . DOKU_LF; - $post .= '</html>' . DOKU_LF; - break; - case 'xhtmlbody': - $headers['Content-Type'] = 'text/html; charset=utf-8'; - $output = p_wiki_xhtml($ID,$REV,false); - break; - default: - $output = p_cached_output(wikiFN($ID,$REV), $mode); - $headers = p_get_metadata($ID,"format $mode"); - break; - } - - // prepare event data - $data = array(); - $data['id'] = $ID; - $data['mode'] = $mode; - $data['headers'] = $headers; - $data['output'] =& $output; - - trigger_event('ACTION_EXPORT_POSTPROCESS', $data); - - if(!empty($data['output'])){ - if(is_array($data['headers'])) foreach($data['headers'] as $key => $val){ - header("$key: $val"); + global $ID; + global $REV; + global $conf; + global $lang; + + $pre = ''; + $post = ''; + $output = ''; + $headers = array(); + + // search engines: never cache exported docs! (Google only currently) + $headers['X-Robots-Tag'] = 'noindex'; + + $mode = substr($act,7); + switch($mode) { + case 'raw': + $headers['Content-Type'] = 'text/plain; charset=utf-8'; + $headers['Content-Disposition'] = 'attachment; filename='.noNS($ID).'.txt'; + $output = rawWiki($ID,$REV); + break; + case 'xhtml': + $pre .= '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"' . DOKU_LF; + $pre .= ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' . DOKU_LF; + $pre .= '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="'.$conf['lang'].'"' . DOKU_LF; + $pre .= ' lang="'.$conf['lang'].'" dir="'.$lang['direction'].'">' . DOKU_LF; + $pre .= '<head>' . DOKU_LF; + $pre .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . DOKU_LF; + $pre .= ' <title>'.$ID.'</title>' . DOKU_LF; + + // get metaheaders + ob_start(); + tpl_metaheaders(); + $pre .= ob_get_clean(); + + $pre .= '</head>' . DOKU_LF; + $pre .= '<body>' . DOKU_LF; + $pre .= '<div class="dokuwiki export">' . DOKU_LF; + + // get toc + $pre .= tpl_toc(true); + + $headers['Content-Type'] = 'text/html; charset=utf-8'; + $output = p_wiki_xhtml($ID,$REV,false); + + $post .= '</div>' . DOKU_LF; + $post .= '</body>' . DOKU_LF; + $post .= '</html>' . DOKU_LF; + break; + case 'xhtmlbody': + $headers['Content-Type'] = 'text/html; charset=utf-8'; + $output = p_wiki_xhtml($ID,$REV,false); + break; + default: + $output = p_cached_output(wikiFN($ID,$REV), $mode); + $headers = p_get_metadata($ID,"format $mode"); + break; } - print $pre.$data['output'].$post; - exit; - } - return 'show'; + + // prepare event data + $data = array(); + $data['id'] = $ID; + $data['mode'] = $mode; + $data['headers'] = $headers; + $data['output'] =& $output; + + trigger_event('ACTION_EXPORT_POSTPROCESS', $data); + + if(!empty($data['output'])){ + if(is_array($data['headers'])) foreach($data['headers'] as $key => $val){ + header("$key: $val"); + } + print $pre.$data['output'].$post; + exit; + } + return 'show'; } /** @@ -556,32 +556,32 @@ function act_export($act){ * @todo localize */ function act_subscription($act){ - global $ID; - global $INFO; - global $lang; - - $file=metaFN($ID,'.mlist'); - if ($act=='subscribe' && !$INFO['subscribed']){ - if ($INFO['userinfo']['mail']){ - if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) { - $INFO['subscribed'] = true; - msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1); - } else { - msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1); - } - } else { - msg($lang['subscribe_noaddress']); - } - } elseif ($act=='unsubscribe' && $INFO['subscribed']){ - if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) { - $INFO['subscribed'] = false; - msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1); - } else { - msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1); + global $ID; + global $INFO; + global $lang; + + $file=metaFN($ID,'.mlist'); + if ($act=='subscribe' && !$INFO['subscribed']){ + if ($INFO['userinfo']['mail']){ + if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) { + $INFO['subscribed'] = true; + msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1); + } else { + msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1); + } + } else { + msg($lang['subscribe_noaddress']); + } + } elseif ($act=='unsubscribe' && $INFO['subscribed']){ + if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) { + $INFO['subscribed'] = false; + msg(sprintf($lang[$act.'_success'], $INFO['userinfo']['name'], $ID),1); + } else { + msg(sprintf($lang[$act.'_error'], $INFO['userinfo']['name'], $ID),1); + } } - } - return 'show'; + return 'show'; } /** @@ -589,42 +589,42 @@ function act_subscription($act){ * */ function act_subscriptionns($act){ - global $ID; - global $INFO; - global $lang; - - if(!getNS($ID)) { - $file = metaFN(getNS($ID),'.mlist'); - $ns = "root"; - } else { - $file = metaFN(getNS($ID),'/.mlist'); - $ns = getNS($ID); - } - - // reuse strings used to display the status of the subscribe action - $act_msg = rtrim($act, 'ns'); - - if ($act=='subscribens' && !$INFO['subscribedns']){ - if ($INFO['userinfo']['mail']){ - if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) { - $INFO['subscribedns'] = true; - msg(sprintf($lang[$act_msg.'_success'], $INFO['userinfo']['name'], $ns),1); - } else { - msg(sprintf($lang[$act_msg.'_error'], $INFO['userinfo']['name'], $ns),1); - } + global $ID; + global $INFO; + global $lang; + + if(!getNS($ID)) { + $file = metaFN(getNS($ID),'.mlist'); + $ns = "root"; } else { - msg($lang['subscribe_noaddress']); + $file = metaFN(getNS($ID),'/.mlist'); + $ns = getNS($ID); } - } elseif ($act=='unsubscribens' && $INFO['subscribedns']){ - if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) { - $INFO['subscribedns'] = false; - msg(sprintf($lang[$act_msg.'_success'], $INFO['userinfo']['name'], $ns),1); - } else { - msg(sprintf($lang[$act_msg.'_error'], $INFO['userinfo']['name'], $ns),1); + + // reuse strings used to display the status of the subscribe action + $act_msg = rtrim($act, 'ns'); + + if ($act=='subscribens' && !$INFO['subscribedns']){ + if ($INFO['userinfo']['mail']){ + if (io_saveFile($file,$_SERVER['REMOTE_USER']."\n",true)) { + $INFO['subscribedns'] = true; + msg(sprintf($lang[$act_msg.'_success'], $INFO['userinfo']['name'], $ns),1); + } else { + msg(sprintf($lang[$act_msg.'_error'], $INFO['userinfo']['name'], $ns),1); + } + } else { + msg($lang['subscribe_noaddress']); + } + } elseif ($act=='unsubscribens' && $INFO['subscribedns']){ + if (io_deleteFromFile($file,$_SERVER['REMOTE_USER']."\n")) { + $INFO['subscribedns'] = false; + msg(sprintf($lang[$act_msg.'_success'], $INFO['userinfo']['name'], $ns),1); + } else { + msg(sprintf($lang[$act_msg.'_error'], $INFO['userinfo']['name'], $ns),1); + } } - } - return 'show'; + return 'show'; } //Setup VIM: ex: et ts=2 enc=utf-8 : diff --git a/inc/cache.php b/inc/cache.php index 8e8adfd6d..2e22edfb1 100644 --- a/inc/cache.php +++ b/inc/cache.php @@ -12,281 +12,281 @@ require_once(DOKU_INC.'inc/pageutils.php'); require_once(DOKU_INC.'inc/parserutils.php'); class cache { - var $key = ''; // primary identifier for this item - var $ext = ''; // file ext for cache data, secondary identifier for this item - var $cache = ''; // cache file name - var $depends = array(); // array containing cache dependency information, - // used by _useCache to determine cache validity - - var $_event = ''; // event to be triggered during useCache - - function cache($key,$ext) { - $this->key = $key; - $this->ext = $ext; - $this->cache = getCacheName($key,$ext); - } - - /** - * public method to determine whether the cache can be used - * - * to assist in cetralisation of event triggering and calculation of cache statistics, - * don't override this function override _useCache() - * - * @param array $depends array of cache dependencies, support dependecies: - * 'age' => max age of the cache in seconds - * 'files' => cache must be younger than mtime of each file - * (nb. dependency passes if file doesn't exist) - * - * @return bool true if cache can be used, false otherwise - */ - function useCache($depends=array()) { - $this->depends = $depends; - $this->_addDependencies(); - - if ($this->_event) { - return $this->_stats(trigger_event($this->_event,$this,array($this,'_useCache'))); - } else { - return $this->_stats($this->_useCache()); + var $key = ''; // primary identifier for this item + var $ext = ''; // file ext for cache data, secondary identifier for this item + var $cache = ''; // cache file name + var $depends = array(); // array containing cache dependency information, + // used by _useCache to determine cache validity + + var $_event = ''; // event to be triggered during useCache + + function cache($key,$ext) { + $this->key = $key; + $this->ext = $ext; + $this->cache = getCacheName($key,$ext); } - } - - /** - * private method containing cache use decision logic - * - * this function processes the following keys in the depends array - * purge - force a purge on any non empty value - * age - expire cache if older than age (seconds) - * files - expire cache if any file in this array was updated more recently than the cache - * - * can be overridden - * - * @return bool see useCache() - */ - function _useCache() { - - if (!empty($this->depends['purge'])) return false; // purge requested? - if (!($this->_time = @filemtime($this->cache))) return false; // cache exists? - - // cache too old? - if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) return false; - - if (!empty($this->depends['files'])) { - foreach ($this->depends['files'] as $file) { - if ($this->_time < @filemtime($file)) return false; // cache older than files it depends on? - } + + /** + * public method to determine whether the cache can be used + * + * to assist in cetralisation of event triggering and calculation of cache statistics, + * don't override this function override _useCache() + * + * @param array $depends array of cache dependencies, support dependecies: + * 'age' => max age of the cache in seconds + * 'files' => cache must be younger than mtime of each file + * (nb. dependency passes if file doesn't exist) + * + * @return bool true if cache can be used, false otherwise + */ + function useCache($depends=array()) { + $this->depends = $depends; + $this->_addDependencies(); + + if ($this->_event) { + return $this->_stats(trigger_event($this->_event,$this,array($this,'_useCache'))); + } else { + return $this->_stats($this->_useCache()); + } + } + + /** + * private method containing cache use decision logic + * + * this function processes the following keys in the depends array + * purge - force a purge on any non empty value + * age - expire cache if older than age (seconds) + * files - expire cache if any file in this array was updated more recently than the cache + * + * can be overridden + * + * @return bool see useCache() + */ + function _useCache() { + + if (!empty($this->depends['purge'])) return false; // purge requested? + if (!($this->_time = @filemtime($this->cache))) return false; // cache exists? + + // cache too old? + if (!empty($this->depends['age']) && ((time() - $this->_time) > $this->depends['age'])) return false; + + if (!empty($this->depends['files'])) { + foreach ($this->depends['files'] as $file) { + if ($this->_time < @filemtime($file)) return false; // cache older than files it depends on? + } + } + + return true; + } + + /** + * add dependencies to the depends array + * + * this method should only add dependencies, + * it should not remove any existing dependencies and + * it should only overwrite a dependency when the new value is more stringent than the old + */ + function _addDependencies() { + if (isset($_REQUEST['purge'])) $this->depends['purge'] = true; // purge requested } - return true; - } - - /** - * add dependencies to the depends array - * - * this method should only add dependencies, - * it should not remove any existing dependencies and - * it should only overwrite a dependency when the new value is more stringent than the old - */ - function _addDependencies() { - if (isset($_REQUEST['purge'])) $this->depends['purge'] = true; // purge requested - } - - /** - * retrieve the cached data - * - * @param bool $clean true to clean line endings, false to leave line endings alone - * @return string cache contents - */ - function retrieveCache($clean=true) { - return io_readFile($this->cache, $clean); - } - - /** - * cache $data - * - * @param string $data the data to be cached - * @return bool true on success, false otherwise - */ - function storeCache($data) { - return io_savefile($this->cache, $data); - } - - /** - * remove any cached data associated with this cache instance - */ - function removeCache() { - @unlink($this->cache); - } - - /** - * Record cache hits statistics. - * (Only when debugging allowed, to reduce overhead.) - * - * @param bool $success result of this cache use attempt - * @return bool pass-thru $success value - */ - function _stats($success) { - global $conf; - static $stats = NULL; - static $file; - - if (!$conf['allowdebug']) { return $success; } - - if (is_null($stats)) { - $file = $conf['cachedir'].'/cache_stats.txt'; - $lines = explode("\n",io_readFile($file)); - - foreach ($lines as $line) { - $i = strpos($line,','); - $stats[substr($line,0,$i)] = $line; - } + /** + * retrieve the cached data + * + * @param bool $clean true to clean line endings, false to leave line endings alone + * @return string cache contents + */ + function retrieveCache($clean=true) { + return io_readFile($this->cache, $clean); } - if (isset($stats[$this->ext])) { - list($ext,$count,$hits) = explode(',',$stats[$this->ext]); - } else { - $ext = $this->ext; - $count = 0; - $hits = 0; + /** + * cache $data + * + * @param string $data the data to be cached + * @return bool true on success, false otherwise + */ + function storeCache($data) { + return io_savefile($this->cache, $data); } - $count++; - if ($success) $hits++; - $stats[$this->ext] = "$ext,$count,$hits"; + /** + * remove any cached data associated with this cache instance + */ + function removeCache() { + @unlink($this->cache); + } + + /** + * Record cache hits statistics. + * (Only when debugging allowed, to reduce overhead.) + * + * @param bool $success result of this cache use attempt + * @return bool pass-thru $success value + */ + function _stats($success) { + global $conf; + static $stats = null; + static $file; + + if (!$conf['allowdebug']) { return $success; } + + if (is_null($stats)) { + $file = $conf['cachedir'].'/cache_stats.txt'; + $lines = explode("\n",io_readFile($file)); + + foreach ($lines as $line) { + $i = strpos($line,','); + $stats[substr($line,0,$i)] = $line; + } + } + + if (isset($stats[$this->ext])) { + list($ext,$count,$hits) = explode(',',$stats[$this->ext]); + } else { + $ext = $this->ext; + $count = 0; + $hits = 0; + } + + $count++; + if ($success) $hits++; + $stats[$this->ext] = "$ext,$count,$hits"; - io_saveFile($file,join("\n",$stats)); + io_saveFile($file,join("\n",$stats)); - return $success; - } + return $success; + } } class cache_parser extends cache { - var $file = ''; // source file for cache - var $mode = ''; // input mode (represents the processing the input file will undergo) + var $file = ''; // source file for cache + var $mode = ''; // input mode (represents the processing the input file will undergo) - var $_event = 'PARSER_CACHE_USE'; + var $_event = 'PARSER_CACHE_USE'; - function cache_parser($id, $file, $mode) { - if ($id) $this->page = $id; - $this->file = $file; - $this->mode = $mode; + function cache_parser($id, $file, $mode) { + if ($id) $this->page = $id; + $this->file = $file; + $this->mode = $mode; - parent::cache($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.$mode); - } + parent::cache($file.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'],'.'.$mode); + } - function _useCache() { + function _useCache() { - if (!@file_exists($this->file)) return false; // source exists? - return parent::_useCache(); - } + if (!@file_exists($this->file)) return false; // source exists? + return parent::_useCache(); + } - function _addDependencies() { - global $conf, $config_cascade; + function _addDependencies() { + global $conf, $config_cascade; - $this->depends['age'] = isset($this->depends['age']) ? - min($this->depends['age'],$conf['cachetime']) : $conf['cachetime']; + $this->depends['age'] = isset($this->depends['age']) ? + min($this->depends['age'],$conf['cachetime']) : $conf['cachetime']; - // parser cache file dependencies ... - $files = array($this->file, // ... source - DOKU_INC.'inc/parser/parser.php', // ... parser - DOKU_INC.'inc/parser/handler.php', // ... handler - ); - $files = array_merge($files, getConfigFiles('main')); // ... wiki settings + // parser cache file dependencies ... + $files = array($this->file, // ... source + DOKU_INC.'inc/parser/parser.php', // ... parser + DOKU_INC.'inc/parser/handler.php', // ... handler + ); + $files = array_merge($files, getConfigFiles('main')); // ... wiki settings - $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files; - parent::_addDependencies(); - } + $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files; + parent::_addDependencies(); + } } class cache_renderer extends cache_parser { - function useCache($depends=array()) { - $use = parent::useCache($depends); + function useCache($depends=array()) { + $use = parent::useCache($depends); + + // meta data needs to be kept in step with the cache + if (!$use && isset($this->page)) { + p_set_metadata($this->page,array(),true); + } - // meta data needs to be kept in step with the cache - if (!$use && isset($this->page)) { - p_set_metadata($this->page,array(),true); + return $use; } - return $use; - } + function _useCache() { + global $conf; - function _useCache() { - global $conf; + if (!parent::_useCache()) return false; - if (!parent::_useCache()) return false; + if (!isset($this->page)) { + return true; + } - if (!isset($this->page)) { - return true; - } + // check current link existence is consistent with cache version + // first check the purgefile + // - if the cache is more recent than the purgefile we know no links can have been updated + if ($this->_time >= @filemtime($conf['cachedir'].'/purgefile')) { + return true; + } - // check current link existence is consistent with cache version - // first check the purgefile - // - if the cache is more recent than the purgefile we know no links can have been updated - if ($this->_time >= @filemtime($conf['cachedir'].'/purgefile')) { - return true; - } + // for wiki pages, check metadata dependencies + $metadata = p_get_metadata($this->page); - // for wiki pages, check metadata dependencies - $metadata = p_get_metadata($this->page); + if (!isset($metadata['relation']['references']) || + empty($metadata['relation']['references'])) { + return true; + } - if (!isset($metadata['relation']['references']) || - empty($metadata['relation']['references'])) { - return true; - } + foreach ($metadata['relation']['references'] as $id => $exists) { + if ($exists != page_exists($id,'',false)) return false; + } - foreach ($metadata['relation']['references'] as $id => $exists) { - if ($exists != page_exists($id,'',false)) return false; + return true; } - return true; - } + function _addDependencies() { - function _addDependencies() { + // renderer cache file dependencies ... + $files = array( + DOKU_INC.'inc/parser/'.$this->mode.'.php', // ... the renderer + ); - // renderer cache file dependencies ... - $files = array( - DOKU_INC.'inc/parser/'.$this->mode.'.php', // ... the renderer - ); + // page implies metadata and possibly some other dependencies + if (isset($this->page)) { - // page implies metadata and possibly some other dependencies - if (isset($this->page)) { + $metafile = metaFN($this->page,'.meta'); + if (@file_exists($metafile)) { + $files[] = $metafile; // ... the page's own metadata + $files[] = DOKU_INC.'inc/parser/metadata.php'; // ... the metadata renderer - $metafile = metaFN($this->page,'.meta'); - if (@file_exists($metafile)) { - $files[] = $metafile; // ... the page's own metadata - $files[] = DOKU_INC.'inc/parser/metadata.php'; // ... the metadata renderer + $valid = p_get_metadata($this->page, 'date valid'); + if (!empty($valid['age'])) { + $this->depends['age'] = isset($this->depends['age']) ? + min($this->depends['age'],$valid['age']) : $valid['age']; + } - $valid = p_get_metadata($this->page, 'date valid'); - if (!empty($valid['age'])) { - $this->depends['age'] = isset($this->depends['age']) ? - min($this->depends['age'],$valid['age']) : $valid['age']; + } else { + $this->depends['purge'] = true; // ... purging cache will generate metadata + return; + } } - } else { - $this->depends['purge'] = true; // ... purging cache will generate metadata - return; - } + $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files; + parent::_addDependencies(); } - - $this->depends['files'] = !empty($this->depends['files']) ? array_merge($files, $this->depends['files']) : $files; - parent::_addDependencies(); - } } class cache_instructions extends cache_parser { - function cache_instructions($id, $file) { - parent::cache_parser($id, $file, 'i'); - } + function cache_instructions($id, $file) { + parent::cache_parser($id, $file, 'i'); + } - function retrieveCache($clean=true) { - $contents = io_readFile($this->cache, false); - return !empty($contents) ? unserialize($contents) : array(); - } + function retrieveCache($clean=true) { + $contents = io_readFile($this->cache, false); + return !empty($contents) ? unserialize($contents) : array(); + } - function storeCache($instructions) { - return io_savefile($this->cache,serialize($instructions)); - } + function storeCache($instructions) { + return io_savefile($this->cache,serialize($instructions)); + } } diff --git a/inc/changelog.php b/inc/changelog.php index bc2af2de3..d4130ac99 100644 --- a/inc/changelog.php +++ b/inc/changelog.php @@ -20,18 +20,18 @@ define('DOKU_CHANGE_TYPE_REVERT', 'R'); * @author Ben Coburn <btcoburn@silicodon.net> */ function parseChangelogLine($line) { - $tmp = explode("\t", $line); + $tmp = explode("\t", $line); if ($tmp!==false && count($tmp)>1) { - $info = array(); - $info['date'] = (int)$tmp[0]; // unix timestamp - $info['ip'] = $tmp[1]; // IPv4 address (127.0.0.1) - $info['type'] = $tmp[2]; // log line type - $info['id'] = $tmp[3]; // page id - $info['user'] = $tmp[4]; // user name - $info['sum'] = $tmp[5]; // edit summary (or action reason) - $info['extra'] = rtrim($tmp[6], "\n"); // extra data (varies by line type) - return $info; - } else { return false; } + $info = array(); + $info['date'] = (int)$tmp[0]; // unix timestamp + $info['ip'] = $tmp[1]; // IPv4 address (127.0.0.1) + $info['type'] = $tmp[2]; // log line type + $info['id'] = $tmp[3]; // page id + $info['user'] = $tmp[4]; // user name + $info['sum'] = $tmp[5]; // edit summary (or action reason) + $info['extra'] = rtrim($tmp[6], "\n"); // extra data (varies by line type) + return $info; + } else { return false; } } /** @@ -42,57 +42,57 @@ function parseChangelogLine($line) { * @author Ben Coburn <btcoburn@silicodon.net> */ function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extra='', $flags=null){ - global $conf, $INFO; - - // check for special flags as keys - if (!is_array($flags)) { $flags = array(); } - $flagExternalEdit = isset($flags['ExternalEdit']); - - $id = cleanid($id); - $file = wikiFN($id); - $created = @filectime($file); - $minor = ($type===DOKU_CHANGE_TYPE_MINOR_EDIT); - $wasRemoved = ($type===DOKU_CHANGE_TYPE_DELETE); - - if(!$date) $date = time(); //use current time if none supplied - $remote = (!$flagExternalEdit)?clientIP(true):'127.0.0.1'; - $user = (!$flagExternalEdit)?$_SERVER['REMOTE_USER']:''; - - $strip = array("\t", "\n"); - $logline = array( - 'date' => $date, - 'ip' => $remote, - 'type' => str_replace($strip, '', $type), - 'id' => $id, - 'user' => $user, - 'sum' => str_replace($strip, '', $summary), - 'extra' => str_replace($strip, '', $extra) - ); - - // update metadata - if (!$wasRemoved) { - $oldmeta = p_read_metadata($id); - $meta = array(); - if (!$INFO['exists'] && empty($oldmeta['persistent']['date']['created'])){ // newly created - $meta['date']['created'] = $created; - if ($user) $meta['creator'] = $INFO['userinfo']['name']; - } elseif (!$INFO['exists'] && !empty($oldmeta['persistent']['date']['created'])) { // re-created / restored - $meta['date']['created'] = $oldmeta['persistent']['date']['created']; - $meta['date']['modified'] = $created; // use the files ctime here - $meta['creator'] = $oldmeta['persistent']['creator']; - if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name']; - } elseif (!$minor) { // non-minor modification - $meta['date']['modified'] = $date; - if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name']; + global $conf, $INFO; + + // check for special flags as keys + if (!is_array($flags)) { $flags = array(); } + $flagExternalEdit = isset($flags['ExternalEdit']); + + $id = cleanid($id); + $file = wikiFN($id); + $created = @filectime($file); + $minor = ($type===DOKU_CHANGE_TYPE_MINOR_EDIT); + $wasRemoved = ($type===DOKU_CHANGE_TYPE_DELETE); + + if(!$date) $date = time(); //use current time if none supplied + $remote = (!$flagExternalEdit)?clientIP(true):'127.0.0.1'; + $user = (!$flagExternalEdit)?$_SERVER['REMOTE_USER']:''; + + $strip = array("\t", "\n"); + $logline = array( + 'date' => $date, + 'ip' => $remote, + 'type' => str_replace($strip, '', $type), + 'id' => $id, + 'user' => $user, + 'sum' => str_replace($strip, '', $summary), + 'extra' => str_replace($strip, '', $extra) + ); + + // update metadata + if (!$wasRemoved) { + $oldmeta = p_read_metadata($id); + $meta = array(); + if (!$INFO['exists'] && empty($oldmeta['persistent']['date']['created'])){ // newly created + $meta['date']['created'] = $created; + if ($user) $meta['creator'] = $INFO['userinfo']['name']; + } elseif (!$INFO['exists'] && !empty($oldmeta['persistent']['date']['created'])) { // re-created / restored + $meta['date']['created'] = $oldmeta['persistent']['date']['created']; + $meta['date']['modified'] = $created; // use the files ctime here + $meta['creator'] = $oldmeta['persistent']['creator']; + if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name']; + } elseif (!$minor) { // non-minor modification + $meta['date']['modified'] = $date; + if ($user) $meta['contributor'][$user] = $INFO['userinfo']['name']; + } + $meta['last_change'] = $logline; + p_set_metadata($id, $meta, true); } - $meta['last_change'] = $logline; - p_set_metadata($id, $meta, true); - } - - // add changelog lines - $logline = implode("\t", $logline)."\n"; - io_saveFile(metaFN($id,'.changes'),$logline,true); //page changelog - io_saveFile($conf['changelog'],$logline,true); //global changelog cache + + // add changelog lines + $logline = implode("\t", $logline)."\n"; + io_saveFile(metaFN($id,'.changes'),$logline,true); //page changelog + io_saveFile($conf['changelog'],$logline,true); //global changelog cache } /** @@ -104,28 +104,28 @@ function addLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extr * @author Ben Coburn <btcoburn@silicodon.net> */ function addMediaLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', $extra='', $flags=null){ - global $conf, $INFO; - - $id = cleanid($id); - - if(!$date) $date = time(); //use current time if none supplied - $remote = clientIP(true); - $user = $_SERVER['REMOTE_USER']; - - $strip = array("\t", "\n"); - $logline = array( - 'date' => $date, - 'ip' => $remote, - 'type' => str_replace($strip, '', $type), - 'id' => $id, - 'user' => $user, - 'sum' => str_replace($strip, '', $summary), - 'extra' => str_replace($strip, '', $extra) - ); - - // add changelog lines - $logline = implode("\t", $logline)."\n"; - io_saveFile($conf['media_changelog'],$logline,true); //global media changelog cache + global $conf, $INFO; + + $id = cleanid($id); + + if(!$date) $date = time(); //use current time if none supplied + $remote = clientIP(true); + $user = $_SERVER['REMOTE_USER']; + + $strip = array("\t", "\n"); + $logline = array( + 'date' => $date, + 'ip' => $remote, + 'type' => str_replace($strip, '', $type), + 'id' => $id, + 'user' => $user, + 'sum' => str_replace($strip, '', $summary), + 'extra' => str_replace($strip, '', $extra) + ); + + // add changelog lines + $logline = implode("\t", $logline)."\n"; + io_saveFile($conf['media_changelog'],$logline,true); //global media changelog cache } /** @@ -148,35 +148,34 @@ function addMediaLogEntry($date, $id, $type=DOKU_CHANGE_TYPE_EDIT, $summary='', * @author Ben Coburn <btcoburn@silicodon.net> */ function getRecents($first,$num,$ns='',$flags=0){ - global $conf; - $recent = array(); - $count = 0; - - if(!$num) - return $recent; + global $conf; + $recent = array(); + $count = 0; + + if(!$num) + return $recent; + + // read all recent changes. (kept short) + if ($flags & RECENTS_MEDIA_CHANGES) { + $lines = @file($conf['media_changelog']); + } else { + $lines = @file($conf['changelog']); + } - // read all recent changes. (kept short) - if ($flags & RECENTS_MEDIA_CHANGES) { - $lines = @file($conf['media_changelog']); - } else { - $lines = @file($conf['changelog']); - } - - - // handle lines - $seen = array(); // caches seen lines, _handleRecent() skips them - for($i = count($lines)-1; $i >= 0; $i--){ - $rec = _handleRecent($lines[$i], $ns, $flags, $seen); - if($rec !== false) { - if(--$first >= 0) continue; // skip first entries - $recent[] = $rec; - $count++; - // break when we have enough entries - if($count >= $num){ break; } + // handle lines + $seen = array(); // caches seen lines, _handleRecent() skips them + for($i = count($lines)-1; $i >= 0; $i--){ + $rec = _handleRecent($lines[$i], $ns, $flags, $seen); + if($rec !== false) { + if(--$first >= 0) continue; // skip first entries + $recent[] = $rec; + $count++; + // break when we have enough entries + if($count >= $num){ break; } + } } - } - return $recent; + return $recent; } /** @@ -200,39 +199,39 @@ function getRecents($first,$num,$ns='',$flags=0){ * @author Ben Coburn <btcoburn@silicodon.net> */ function getRecentsSince($from,$to=null,$ns='',$flags=0){ - global $conf; - $recent = array(); + global $conf; + $recent = array(); - if($to && $to < $from) - return $recent; + if($to && $to < $from) + return $recent; + + // read all recent changes. (kept short) + if ($flags & RECENTS_MEDIA_CHANGES) { + $lines = @file($conf['media_changelog']); + } else { + $lines = @file($conf['changelog']); + } - // read all recent changes. (kept short) - if ($flags & RECENTS_MEDIA_CHANGES) { - $lines = @file($conf['media_changelog']); - } else { - $lines = @file($conf['changelog']); - } - - // we start searching at the end of the list - $lines = array_reverse($lines); - - // handle lines - $seen = array(); // caches seen lines, _handleRecent() skips them - - foreach($lines as $line){ - $rec = _handleRecent($line, $ns, $flags, $seen); - if($rec !== false) { - if ($rec['date'] >= $from) { - if (!$to || $rec['date'] <= $to) { - $recent[] = $rec; + // we start searching at the end of the list + $lines = array_reverse($lines); + + // handle lines + $seen = array(); // caches seen lines, _handleRecent() skips them + + foreach($lines as $line){ + $rec = _handleRecent($line, $ns, $flags, $seen); + if($rec !== false) { + if ($rec['date'] >= $from) { + if (!$to || $rec['date'] <= $to) { + $recent[] = $rec; + } + } else { + break; + } } - } else { - break; - } } - } - return array_reverse($recent); + return array_reverse($recent); } /** @@ -245,39 +244,39 @@ function getRecentsSince($from,$to=null,$ns='',$flags=0){ * @author Ben Coburn <btcoburn@silicodon.net> */ function _handleRecent($line,$ns,$flags,&$seen){ - if(empty($line)) return false; //skip empty lines + if(empty($line)) return false; //skip empty lines - // split the line into parts - $recent = parseChangelogLine($line); - if ($recent===false) { return false; } + // split the line into parts + $recent = parseChangelogLine($line); + if ($recent===false) { return false; } - // skip seen ones - if(isset($seen[$recent['id']])) return false; + // skip seen ones + if(isset($seen[$recent['id']])) return false; - // skip minors - if($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false; + // skip minors + if($recent['type']===DOKU_CHANGE_TYPE_MINOR_EDIT && ($flags & RECENTS_SKIP_MINORS)) return false; - // remember in seen to skip additional sights - $seen[$recent['id']] = 1; + // remember in seen to skip additional sights + $seen[$recent['id']] = 1; - // check if it's a hidden page - if(isHiddenPage($recent['id'])) return false; + // check if it's a hidden page + if(isHiddenPage($recent['id'])) return false; - // filter namespace - if (($ns) && (strpos($recent['id'],$ns.':') !== 0)) return false; + // filter namespace + if (($ns) && (strpos($recent['id'],$ns.':') !== 0)) return false; - // exclude subnamespaces - if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false; + // exclude subnamespaces + if (($flags & RECENTS_SKIP_SUBSPACES) && (getNS($recent['id']) != $ns)) return false; - // check ACL - $recent['perms'] = auth_quickaclcheck($recent['id']); - if ($recent['perms'] < AUTH_READ) return false; + // check ACL + $recent['perms'] = auth_quickaclcheck($recent['id']); + if ($recent['perms'] < AUTH_READ) return false; - // check existance - $fn = (($flags & RECENTS_MEDIA_CHANGES) ? mediaFN($recent['id']) : wikiFN($recent['id'])); - if((!@file_exists($fn)) && ($flags & RECENTS_SKIP_DELETED)) return false; + // check existance + $fn = (($flags & RECENTS_MEDIA_CHANGES) ? mediaFN($recent['id']) : wikiFN($recent['id'])); + if((!@file_exists($fn)) && ($flags & RECENTS_SKIP_DELETED)) return false; - return $recent; + return $recent; } /** @@ -291,80 +290,80 @@ function _handleRecent($line,$ns,$flags,&$seen){ * @author Ben Coburn <btcoburn@silicodon.net> */ function getRevisionInfo($id, $rev, $chunk_size=8192) { - global $cache_revinfo; - $cache =& $cache_revinfo; - if (!isset($cache[$id])) { $cache[$id] = array(); } - $rev = max($rev, 0); - - // check if it's already in the memory cache - if (isset($cache[$id]) && isset($cache[$id][$rev])) { - return $cache[$id][$rev]; - } - - $file = metaFN($id, '.changes'); - if (!@file_exists($file)) { return false; } - if (filesize($file)<$chunk_size || $chunk_size==0) { - // read whole file - $lines = file($file); - if ($lines===false) { return false; } - } else { - // read by chunk - $fp = fopen($file, 'rb'); // "file pointer" - if ($fp===false) { return false; } - $head = 0; - fseek($fp, 0, SEEK_END); - $tail = ftell($fp); - $finger = 0; - $finger_rev = 0; - - // find chunk - while ($tail-$head>$chunk_size) { - $finger = $head+floor(($tail-$head)/2.0); - fseek($fp, $finger); - fgets($fp); // slip the finger forward to a new line - $finger = ftell($fp); - $tmp = fgets($fp); // then read at that location - $tmp = parseChangelogLine($tmp); - $finger_rev = $tmp['date']; - if ($finger==$head || $finger==$tail) { break; } - if ($finger_rev>$rev) { - $tail = $finger; - } else { - $head = $finger; - } + global $cache_revinfo; + $cache =& $cache_revinfo; + if (!isset($cache[$id])) { $cache[$id] = array(); } + $rev = max($rev, 0); + + // check if it's already in the memory cache + if (isset($cache[$id]) && isset($cache[$id][$rev])) { + return $cache[$id][$rev]; } - if ($tail-$head<1) { - // cound not find chunk, assume requested rev is missing - fclose($fp); - return false; - } + $file = metaFN($id, '.changes'); + if (!@file_exists($file)) { return false; } + if (filesize($file)<$chunk_size || $chunk_size==0) { + // read whole file + $lines = file($file); + if ($lines===false) { return false; } + } else { + // read by chunk + $fp = fopen($file, 'rb'); // "file pointer" + if ($fp===false) { return false; } + $head = 0; + fseek($fp, 0, SEEK_END); + $tail = ftell($fp); + $finger = 0; + $finger_rev = 0; + + // find chunk + while ($tail-$head>$chunk_size) { + $finger = $head+floor(($tail-$head)/2.0); + fseek($fp, $finger); + fgets($fp); // slip the finger forward to a new line + $finger = ftell($fp); + $tmp = fgets($fp); // then read at that location + $tmp = parseChangelogLine($tmp); + $finger_rev = $tmp['date']; + if ($finger==$head || $finger==$tail) { break; } + if ($finger_rev>$rev) { + $tail = $finger; + } else { + $head = $finger; + } + } + + if ($tail-$head<1) { + // cound not find chunk, assume requested rev is missing + fclose($fp); + return false; + } - // read chunk - $chunk = ''; - $chunk_size = max($tail-$head, 0); // found chunk size - $got = 0; - fseek($fp, $head); - while ($got<$chunk_size && !feof($fp)) { - $tmp = @fread($fp, max($chunk_size-$got, 0)); - if ($tmp===false) { break; } //error state - $got += strlen($tmp); - $chunk .= $tmp; + // read chunk + $chunk = ''; + $chunk_size = max($tail-$head, 0); // found chunk size + $got = 0; + fseek($fp, $head); + while ($got<$chunk_size && !feof($fp)) { + $tmp = @fread($fp, max($chunk_size-$got, 0)); + if ($tmp===false) { break; } //error state + $got += strlen($tmp); + $chunk .= $tmp; + } + $lines = explode("\n", $chunk); + array_pop($lines); // remove trailing newline + fclose($fp); } - $lines = explode("\n", $chunk); - array_pop($lines); // remove trailing newline - fclose($fp); - } - - // parse and cache changelog lines - foreach ($lines as $value) { - $tmp = parseChangelogLine($value); - if ($tmp!==false) { - $cache[$id][$tmp['date']] = $tmp; + + // parse and cache changelog lines + foreach ($lines as $value) { + $tmp = parseChangelogLine($value); + if ($tmp!==false) { + $cache[$id][$tmp['date']] = $tmp; + } } - } - if (!isset($cache[$id][$rev])) { return false; } - return $cache[$id][$rev]; + if (!isset($cache[$id][$rev])) { return false; } + return $cache[$id][$rev]; } /** @@ -388,87 +387,87 @@ function getRevisionInfo($id, $rev, $chunk_size=8192) { * @author Ben Coburn <btcoburn@silicodon.net> */ function getRevisions($id, $first, $num, $chunk_size=8192) { - global $cache_revinfo; - $cache =& $cache_revinfo; - if (!isset($cache[$id])) { $cache[$id] = array(); } - - $revs = array(); - $lines = array(); - $count = 0; - $file = metaFN($id, '.changes'); - $num = max($num, 0); - $chunk_size = max($chunk_size, 0); - if ($first<0) { $first = 0; } - else if (@file_exists(wikiFN($id))) { - // skip current revision if the page exists - $first = max($first+1, 0); - } - - if (!@file_exists($file)) { return $revs; } - if (filesize($file)<$chunk_size || $chunk_size==0) { - // read whole file - $lines = file($file); - if ($lines===false) { return $revs; } - } else { - // read chunks backwards - $fp = fopen($file, 'rb'); // "file pointer" - if ($fp===false) { return $revs; } - fseek($fp, 0, SEEK_END); - $tail = ftell($fp); - - // chunk backwards - $finger = max($tail-$chunk_size, 0); - while ($count<$num+$first) { - fseek($fp, $finger); - if ($finger>0) { - fgets($fp); // slip the finger forward to a new line - $finger = ftell($fp); - } - - // read chunk - if ($tail<=$finger) { break; } - $chunk = ''; - $read_size = max($tail-$finger, 0); // found chunk size - $got = 0; - while ($got<$read_size && !feof($fp)) { - $tmp = @fread($fp, max($read_size-$got, 0)); - if ($tmp===false) { break; } //error state - $got += strlen($tmp); - $chunk .= $tmp; - } - $tmp = explode("\n", $chunk); - array_pop($tmp); // remove trailing newline - - // combine with previous chunk - $count += count($tmp); - $lines = array_merge($tmp, $lines); - - // next chunk - if ($finger==0) { break; } // already read all the lines - else { - $tail = $finger; + global $cache_revinfo; + $cache =& $cache_revinfo; + if (!isset($cache[$id])) { $cache[$id] = array(); } + + $revs = array(); + $lines = array(); + $count = 0; + $file = metaFN($id, '.changes'); + $num = max($num, 0); + $chunk_size = max($chunk_size, 0); + if ($first<0) { $first = 0; } + else if (@file_exists(wikiFN($id))) { + // skip current revision if the page exists + $first = max($first+1, 0); + } + + if (!@file_exists($file)) { return $revs; } + if (filesize($file)<$chunk_size || $chunk_size==0) { + // read whole file + $lines = file($file); + if ($lines===false) { return $revs; } + } else { + // read chunks backwards + $fp = fopen($file, 'rb'); // "file pointer" + if ($fp===false) { return $revs; } + fseek($fp, 0, SEEK_END); + $tail = ftell($fp); + + // chunk backwards $finger = max($tail-$chunk_size, 0); - } + while ($count<$num+$first) { + fseek($fp, $finger); + if ($finger>0) { + fgets($fp); // slip the finger forward to a new line + $finger = ftell($fp); + } + + // read chunk + if ($tail<=$finger) { break; } + $chunk = ''; + $read_size = max($tail-$finger, 0); // found chunk size + $got = 0; + while ($got<$read_size && !feof($fp)) { + $tmp = @fread($fp, max($read_size-$got, 0)); + if ($tmp===false) { break; } //error state + $got += strlen($tmp); + $chunk .= $tmp; + } + $tmp = explode("\n", $chunk); + array_pop($tmp); // remove trailing newline + + // combine with previous chunk + $count += count($tmp); + $lines = array_merge($tmp, $lines); + + // next chunk + if ($finger==0) { break; } // already read all the lines + else { + $tail = $finger; + $finger = max($tail-$chunk_size, 0); + } + } + fclose($fp); } - fclose($fp); - } - - // skip parsing extra lines - $num = max(min(count($lines)-$first, $num), 0); - if ($first>0 && $num>0) { $lines = array_slice($lines, max(count($lines)-$first-$num, 0), $num); } - else if ($first>0 && $num==0) { $lines = array_slice($lines, 0, max(count($lines)-$first, 0)); } - else if ($first==0 && $num>0) { $lines = array_slice($lines, max(count($lines)-$num, 0)); } - - // handle lines in reverse order - for ($i = count($lines)-1; $i >= 0; $i--) { - $tmp = parseChangelogLine($lines[$i]); - if ($tmp!==false) { - $cache[$id][$tmp['date']] = $tmp; - $revs[] = $tmp['date']; + + // skip parsing extra lines + $num = max(min(count($lines)-$first, $num), 0); + if ($first>0 && $num>0) { $lines = array_slice($lines, max(count($lines)-$first-$num, 0), $num); } + else if ($first>0 && $num==0) { $lines = array_slice($lines, 0, max(count($lines)-$first, 0)); } + else if ($first==0 && $num>0) { $lines = array_slice($lines, max(count($lines)-$num, 0)); } + + // handle lines in reverse order + for ($i = count($lines)-1; $i >= 0; $i--) { + $tmp = parseChangelogLine($lines[$i]); + if ($tmp!==false) { + $cache[$id][$tmp['date']] = $tmp; + $revs[] = $tmp['date']; + } } - } - return $revs; + return $revs; } diff --git a/inc/cliopts.php b/inc/cliopts.php index a3698ab24..ede559a63 100644 --- a/inc/cliopts.php +++ b/inc/cliopts.php @@ -1,7 +1,7 @@ <?php /** -* Brutally chopped and modified from http://pear.php.net/package/Console_Getopts -*/ + * Brutally chopped and modified from http://pear.php.net/package/Console_Getopts + */ // +----------------------------------------------------------------------+ // | PHP Version 4 | // +----------------------------------------------------------------------+ @@ -23,10 +23,10 @@ //------------------------------------------------------------------------------ /** -* Sets up CLI environment based on SAPI and PHP version -* Helps resolve some issues between the CGI and CLI SAPIs -* as well is inconsistencies between PHP 4.3+ and older versions -*/ + * Sets up CLI environment based on SAPI and PHP version + * Helps resolve some issues between the CGI and CLI SAPIs + * as well is inconsistencies between PHP 4.3+ and older versions + */ if (version_compare(phpversion(), '4.3.0', '<') || php_sapi_name() == 'cgi') { // Handle output buffering @ob_end_flush(); @@ -67,16 +67,16 @@ define('DOKU_CLI_OPTS_ARG_READ',5);//Could not read argv * @author Andrei Zmievski <andrei@php.net> * */ - class Doku_Cli_Opts { +class Doku_Cli_Opts { /** - * <?php ?> - * @see http://www.sitepoint.com/article/php-command-line-1/3 - * @param string executing file name - this MUST be passed the __FILE__ constant - * @param string short options - * @param array (optional) long options - * @return Doku_Cli_Opts_Container or Doku_Cli_Opts_Error - */ + * <?php ?> + * @see http://www.sitepoint.com/article/php-command-line-1/3 + * @param string executing file name - this MUST be passed the __FILE__ constant + * @param string short options + * @param array (optional) long options + * @return Doku_Cli_Opts_Container or Doku_Cli_Opts_Error + */ function & getOptions($bin_file, $short_options, $long_options = null) { $args = Doku_Cli_Opts::readPHPArgv(); @@ -168,7 +168,8 @@ define('DOKU_CLI_OPTS_ARG_READ',5);//Could not read argv } function _parseShortOption($arg, $short_options, &$opts, &$args) { - for ($i = 0; $i < strlen($arg); $i++) { + $len = strlen($arg); + for ($i = 0; $i < $len; $i++) { $opt = $arg{$i}; $opt_arg = null; @@ -212,8 +213,9 @@ define('DOKU_CLI_OPTS_ARG_READ',5);//Could not read argv function _parseLongOption($arg, $long_options, &$opts, &$args) { @list($opt, $opt_arg) = explode('=', $arg); $opt_len = strlen($opt); + $opt_cnt = count($long_options); - for ($i = 0; $i < count($long_options); $i++) { + for ($i = 0; $i < $opt_cnt; $i++) { $long_opt = $long_options[$i]; $opt_start = substr($long_opt, 0, $opt_len); @@ -226,7 +228,7 @@ define('DOKU_CLI_OPTS_ARG_READ',5);//Could not read argv /* Check that the options uniquely matches one of the allowed options. */ if ($opt_rest != '' && $opt{0} != '=' && - $i + 1 < count($long_options) && + $i + 1 < $opt_cnt && $opt == substr($long_options[$i+1], 0, $opt_len)) { return Doku_Cli_Opts::raiseError( DOKU_CLI_OPTS_OPT_ABIGUOUS, @@ -326,7 +328,6 @@ class Doku_Cli_Opts_Container { $this->options[$opt_name] = $option[1]; } - $this->args = $options[1]; } diff --git a/inc/common.php b/inc/common.php index 321148c7a..85187f16d 100644 --- a/inc/common.php +++ b/inc/common.php @@ -29,7 +29,7 @@ define('RECENTS_MEDIA_CHANGES',16); * @see htmlspecialchars() */ function hsc($string){ - return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); + return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); } /** @@ -40,7 +40,7 @@ function hsc($string){ * @author Andreas Gohr <andi@splitbrain.org> */ function ptln($string,$indent=0){ - echo str_repeat(' ', $indent)."$string\n"; + echo str_repeat(' ', $indent)."$string\n"; } /** @@ -49,7 +49,7 @@ function ptln($string,$indent=0){ * @author Andreas Gohr <andi@splitbrain.org> */ function stripctl($string){ - return preg_replace('/[\x00-\x1F]+/s','',$string); + return preg_replace('/[\x00-\x1F]+/s','',$string); } /** @@ -61,21 +61,21 @@ function stripctl($string){ * @return string */ function getSecurityToken(){ - return md5(auth_cookiesalt().session_id()); + return md5(auth_cookiesalt().session_id()); } /** * Check the secret CSRF token */ function checkSecurityToken($token=null){ - if(!$_SERVER['REMOTE_USER']) return true; // no logged in user, no need for a check + if(!$_SERVER['REMOTE_USER']) return true; // no logged in user, no need for a check - if(is_null($token)) $token = $_REQUEST['sectok']; - if(getSecurityToken() != $token){ - msg('Security Token did not match. Possible CSRF attack.',-1); - return false; - } - return true; + if(is_null($token)) $token = $_REQUEST['sectok']; + if(getSecurityToken() != $token){ + msg('Security Token did not match. Possible CSRF attack.',-1); + return false; + } + return true; } /** @@ -84,12 +84,12 @@ function checkSecurityToken($token=null){ * @author Andreas Gohr <andi@splitbrain.org> */ function formSecurityToken($print=true){ - $ret = '<div class="no"><input type="hidden" name="sectok" value="'.getSecurityToken().'" /></div>'."\n"; - if($print){ - echo $ret; - }else{ - return $ret; - } + $ret = '<div class="no"><input type="hidden" name="sectok" value="'.getSecurityToken().'" /></div>'."\n"; + if($print){ + echo $ret; + }else{ + return $ret; + } } /** @@ -99,128 +99,128 @@ function formSecurityToken($print=true){ * @author Andreas Gohr <andi@splitbrain.org> */ function pageinfo(){ - global $ID; - global $REV; - global $RANGE; - global $USERINFO; - global $conf; - global $lang; - - // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml - // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary - $info['id'] = $ID; - $info['rev'] = $REV; + global $ID; + global $REV; + global $RANGE; + global $USERINFO; + global $conf; + global $lang; + + // include ID & REV not redundant, as some parts of DokuWiki may temporarily change $ID, e.g. p_wiki_xhtml + // FIXME ... perhaps it would be better to ensure the temporary changes weren't necessary + $info['id'] = $ID; + $info['rev'] = $REV; // set info about manager/admin status. $info['isadmin'] = false; $info['ismanager'] = false; - if(isset($_SERVER['REMOTE_USER'])){ - $info['userinfo'] = $USERINFO; - $info['perm'] = auth_quickaclcheck($ID); - $info['subscribed'] = is_subscribed($ID,$_SERVER['REMOTE_USER'],false); - $info['subscribedns'] = is_subscribed($ID,$_SERVER['REMOTE_USER'],true); - $info['client'] = $_SERVER['REMOTE_USER']; - - if($info['perm'] == AUTH_ADMIN){ - $info['isadmin'] = true; - $info['ismanager'] = true; - }elseif(auth_ismanager()){ - $info['ismanager'] = true; - } - - // if some outside auth were used only REMOTE_USER is set - if(!$info['userinfo']['name']){ - $info['userinfo']['name'] = $_SERVER['REMOTE_USER']; - } - - }else{ - $info['perm'] = auth_aclcheck($ID,'',null); - $info['subscribed'] = false; - $info['client'] = clientIP(true); - } - - $info['namespace'] = getNS($ID); - $info['locked'] = checklock($ID); - $info['filepath'] = fullpath(wikiFN($ID)); - $info['exists'] = @file_exists($info['filepath']); - if($REV){ - //check if current revision was meant - if($info['exists'] && (@filemtime($info['filepath'])==$REV)){ - $REV = ''; - }elseif($RANGE){ - //section editing does not work with old revisions! - $REV = ''; - $RANGE = ''; - msg($lang['nosecedit'],0); + if(isset($_SERVER['REMOTE_USER'])){ + $info['userinfo'] = $USERINFO; + $info['perm'] = auth_quickaclcheck($ID); + $info['subscribed'] = is_subscribed($ID,$_SERVER['REMOTE_USER'],false); + $info['subscribedns'] = is_subscribed($ID,$_SERVER['REMOTE_USER'],true); + $info['client'] = $_SERVER['REMOTE_USER']; + + if($info['perm'] == AUTH_ADMIN){ + $info['isadmin'] = true; + $info['ismanager'] = true; + }elseif(auth_ismanager()){ + $info['ismanager'] = true; + } + + // if some outside auth were used only REMOTE_USER is set + if(!$info['userinfo']['name']){ + $info['userinfo']['name'] = $_SERVER['REMOTE_USER']; + } + }else{ - //really use old revision - $info['filepath'] = fullpath(wikiFN($ID,$REV)); - $info['exists'] = @file_exists($info['filepath']); - } - } - $info['rev'] = $REV; - if($info['exists']){ - $info['writable'] = (is_writable($info['filepath']) && - ($info['perm'] >= AUTH_EDIT)); - }else{ - $info['writable'] = ($info['perm'] >= AUTH_CREATE); - } - $info['editable'] = ($info['writable'] && empty($info['lock'])); - $info['lastmod'] = @filemtime($info['filepath']); - - //load page meta data - $info['meta'] = p_get_metadata($ID); - - //who's the editor - if($REV){ - $revinfo = getRevisionInfo($ID, $REV, 1024); - }else{ - if (is_array($info['meta']['last_change'])) { - $revinfo = $info['meta']['last_change']; - } else { - $revinfo = getRevisionInfo($ID, $info['lastmod'], 1024); - // cache most recent changelog line in metadata if missing and still valid - if ($revinfo!==false) { + $info['perm'] = auth_aclcheck($ID,'',null); + $info['subscribed'] = false; + $info['client'] = clientIP(true); + } + + $info['namespace'] = getNS($ID); + $info['locked'] = checklock($ID); + $info['filepath'] = fullpath(wikiFN($ID)); + $info['exists'] = @file_exists($info['filepath']); + if($REV){ + //check if current revision was meant + if($info['exists'] && (@filemtime($info['filepath'])==$REV)){ + $REV = ''; + }elseif($RANGE){ + //section editing does not work with old revisions! + $REV = ''; + $RANGE = ''; + msg($lang['nosecedit'],0); + }else{ + //really use old revision + $info['filepath'] = fullpath(wikiFN($ID,$REV)); + $info['exists'] = @file_exists($info['filepath']); + } + } + $info['rev'] = $REV; + if($info['exists']){ + $info['writable'] = (is_writable($info['filepath']) && + ($info['perm'] >= AUTH_EDIT)); + }else{ + $info['writable'] = ($info['perm'] >= AUTH_CREATE); + } + $info['editable'] = ($info['writable'] && empty($info['lock'])); + $info['lastmod'] = @filemtime($info['filepath']); + + //load page meta data + $info['meta'] = p_get_metadata($ID); + + //who's the editor + if($REV){ + $revinfo = getRevisionInfo($ID, $REV, 1024); + }else{ + if (is_array($info['meta']['last_change'])) { + $revinfo = $info['meta']['last_change']; + } else { + $revinfo = getRevisionInfo($ID, $info['lastmod'], 1024); + // cache most recent changelog line in metadata if missing and still valid + if ($revinfo!==false) { + $info['meta']['last_change'] = $revinfo; + p_set_metadata($ID, array('last_change' => $revinfo)); + } + } + } + //and check for an external edit + if($revinfo!==false && $revinfo['date']!=$info['lastmod']){ + // cached changelog line no longer valid + $revinfo = false; $info['meta']['last_change'] = $revinfo; p_set_metadata($ID, array('last_change' => $revinfo)); - } - } - } - //and check for an external edit - if($revinfo!==false && $revinfo['date']!=$info['lastmod']){ - // cached changelog line no longer valid - $revinfo = false; - $info['meta']['last_change'] = $revinfo; - p_set_metadata($ID, array('last_change' => $revinfo)); - } - - $info['ip'] = $revinfo['ip']; - $info['user'] = $revinfo['user']; - $info['sum'] = $revinfo['sum']; - // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID. - // Use $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT in place of $info['minor']. - - if($revinfo['user']){ - $info['editor'] = $revinfo['user']; - }else{ - $info['editor'] = $revinfo['ip']; - } - - // draft - $draft = getCacheName($info['client'].$ID,'.draft'); - if(@file_exists($draft)){ - if(@filemtime($draft) < @filemtime(wikiFN($ID))){ - // remove stale draft - @unlink($draft); + } + + $info['ip'] = $revinfo['ip']; + $info['user'] = $revinfo['user']; + $info['sum'] = $revinfo['sum']; + // See also $INFO['meta']['last_change'] which is the most recent log line for page $ID. + // Use $INFO['meta']['last_change']['type']===DOKU_CHANGE_TYPE_MINOR_EDIT in place of $info['minor']. + + if($revinfo['user']){ + $info['editor'] = $revinfo['user']; }else{ - $info['draft'] = $draft; + $info['editor'] = $revinfo['ip']; + } + + // draft + $draft = getCacheName($info['client'].$ID,'.draft'); + if(@file_exists($draft)){ + if(@filemtime($draft) < @filemtime(wikiFN($ID))){ + // remove stale draft + @unlink($draft); + }else{ + $info['draft'] = $draft; + } } - } - // mobile detection - $info['ismobile'] = clientismobile(); + // mobile detection + $info['ismobile'] = clientismobile(); - return $info; + return $info; } /** @@ -229,16 +229,16 @@ function pageinfo(){ * @author Andreas Gohr */ function buildURLparams($params, $sep='&'){ - $url = ''; - $amp = false; - foreach($params as $key => $val){ - if($amp) $url .= $sep; - - $url .= $key.'='; - $url .= rawurlencode((string)$val); - $amp = true; - } - return $url; + $url = ''; + $amp = false; + foreach($params as $key => $val){ + if($amp) $url .= $sep; + + $url .= $key.'='; + $url .= rawurlencode((string)$val); + $amp = true; + } + return $url; } /** @@ -249,16 +249,16 @@ function buildURLparams($params, $sep='&'){ * @author Andreas Gohr */ function buildAttributes($params,$skipempty=false){ - $url = ''; - foreach($params as $key => $val){ - if($key{0} == '_') continue; - if($val === '' && $skipempty) continue; - - $url .= $key.'="'; - $url .= htmlspecialchars ($val); - $url .= '" '; - } - return $url; + $url = ''; + foreach($params as $key => $val){ + if($key{0} == '_') continue; + if($val === '' && $skipempty) continue; + + $url .= $key.'="'; + $url .= htmlspecialchars ($val); + $url .= '" '; + } + return $url; } @@ -268,47 +268,47 @@ function buildAttributes($params,$skipempty=false){ * @author Andreas Gohr <andi@splitbrain.org> */ function breadcrumbs(){ - // we prepare the breadcrumbs early for quick session closing - static $crumbs = null; - if($crumbs != null) return $crumbs; - - global $ID; - global $ACT; - global $conf; - - //first visit? - $crumbs = isset($_SESSION[DOKU_COOKIE]['bc']) ? $_SESSION[DOKU_COOKIE]['bc'] : array(); - //we only save on show and existing wiki documents - $file = wikiFN($ID); - if($ACT != 'show' || !@file_exists($file)){ + // we prepare the breadcrumbs early for quick session closing + static $crumbs = null; + if($crumbs != null) return $crumbs; + + global $ID; + global $ACT; + global $conf; + + //first visit? + $crumbs = isset($_SESSION[DOKU_COOKIE]['bc']) ? $_SESSION[DOKU_COOKIE]['bc'] : array(); + //we only save on show and existing wiki documents + $file = wikiFN($ID); + if($ACT != 'show' || !@file_exists($file)){ + $_SESSION[DOKU_COOKIE]['bc'] = $crumbs; + return $crumbs; + } + + // page names + $name = noNSorNS($ID); + if (useHeading('navigation')) { + // get page title + $title = p_get_first_heading($ID,true); + if ($title) { + $name = $title; + } + } + + //remove ID from array + if (isset($crumbs[$ID])) { + unset($crumbs[$ID]); + } + + //add to array + $crumbs[$ID] = $name; + //reduce size + while(count($crumbs) > $conf['breadcrumbs']){ + array_shift($crumbs); + } + //save to session $_SESSION[DOKU_COOKIE]['bc'] = $crumbs; return $crumbs; - } - - // page names - $name = noNSorNS($ID); - if (useHeading('navigation')) { - // get page title - $title = p_get_first_heading($ID,true); - if ($title) { - $name = $title; - } - } - - //remove ID from array - if (isset($crumbs[$ID])) { - unset($crumbs[$ID]); - } - - //add to array - $crumbs[$ID] = $name; - //reduce size - while(count($crumbs) > $conf['breadcrumbs']){ - array_shift($crumbs); - } - //save to session - $_SESSION[DOKU_COOKIE]['bc'] = $crumbs; - return $crumbs; } /** @@ -323,19 +323,19 @@ function breadcrumbs(){ * @author Andreas Gohr <andi@splitbrain.org> */ function idfilter($id,$ue=true){ - global $conf; - if ($conf['useslash'] && $conf['userewrite']){ - $id = strtr($id,':','/'); - }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && - $conf['userewrite']) { - $id = strtr($id,':',';'); - } - if($ue){ - $id = rawurlencode($id); - $id = str_replace('%3A',':',$id); //keep as colon - $id = str_replace('%2F','/',$id); //keep as slash - } - return $id; + global $conf; + if ($conf['useslash'] && $conf['userewrite']){ + $id = strtr($id,':','/'); + }elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && + $conf['userewrite']) { + $id = strtr($id,':',';'); + } + if($ue){ + $id = rawurlencode($id); + $id = str_replace('%3A',':',$id); //keep as colon + $id = str_replace('%2F','/',$id); //keep as slash + } + return $id; } /** @@ -347,35 +347,35 @@ function idfilter($id,$ue=true){ * @author Andreas Gohr <andi@splitbrain.org> */ function wl($id='',$more='',$abs=false,$sep='&'){ - global $conf; - if(is_array($more)){ - $more = buildURLparams($more,$sep); - }else{ - $more = str_replace(',',$sep,$more); - } - - $id = idfilter($id); - if($abs){ - $xlink = DOKU_URL; - }else{ - $xlink = DOKU_BASE; - } - - if($conf['userewrite'] == 2){ - $xlink .= DOKU_SCRIPT.'/'.$id; - if($more) $xlink .= '?'.$more; - }elseif($conf['userewrite']){ - $xlink .= $id; - if($more) $xlink .= '?'.$more; - }elseif($id){ - $xlink .= DOKU_SCRIPT.'?id='.$id; - if($more) $xlink .= $sep.$more; - }else{ - $xlink .= DOKU_SCRIPT; - if($more) $xlink .= '?'.$more; - } - - return $xlink; + global $conf; + if(is_array($more)){ + $more = buildURLparams($more,$sep); + }else{ + $more = str_replace(',',$sep,$more); + } + + $id = idfilter($id); + if($abs){ + $xlink = DOKU_URL; + }else{ + $xlink = DOKU_BASE; + } + + if($conf['userewrite'] == 2){ + $xlink .= DOKU_SCRIPT.'/'.$id; + if($more) $xlink .= '?'.$more; + }elseif($conf['userewrite']){ + $xlink .= $id; + if($more) $xlink .= '?'.$more; + }elseif($id){ + $xlink .= DOKU_SCRIPT.'?id='.$id; + if($more) $xlink .= $sep.$more; + }else{ + $xlink .= DOKU_SCRIPT; + if($more) $xlink .= '?'.$more; + } + + return $xlink; } /** @@ -386,33 +386,33 @@ function wl($id='',$more='',$abs=false,$sep='&'){ * @author Ben Coburn <btcoburn@silicodon.net> */ function exportlink($id='',$format='raw',$more='',$abs=false,$sep='&'){ - global $conf; - if(is_array($more)){ - $more = buildURLparams($more,$sep); - }else{ - $more = str_replace(',',$sep,$more); - } - - $format = rawurlencode($format); - $id = idfilter($id); - if($abs){ - $xlink = DOKU_URL; - }else{ - $xlink = DOKU_BASE; - } - - if($conf['userewrite'] == 2){ - $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format; - if($more) $xlink .= $sep.$more; - }elseif($conf['userewrite'] == 1){ - $xlink .= '_export/'.$format.'/'.$id; - if($more) $xlink .= '?'.$more; - }else{ - $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id; - if($more) $xlink .= $sep.$more; - } - - return $xlink; + global $conf; + if(is_array($more)){ + $more = buildURLparams($more,$sep); + }else{ + $more = str_replace(',',$sep,$more); + } + + $format = rawurlencode($format); + $id = idfilter($id); + if($abs){ + $xlink = DOKU_URL; + }else{ + $xlink = DOKU_BASE; + } + + if($conf['userewrite'] == 2){ + $xlink .= DOKU_SCRIPT.'/'.$id.'?do=export_'.$format; + if($more) $xlink .= $sep.$more; + }elseif($conf['userewrite'] == 1){ + $xlink .= '_export/'.$format.'/'.$id; + if($more) $xlink .= '?'.$more; + }else{ + $xlink .= DOKU_SCRIPT.'?do=export_'.$format.$sep.'id='.$id; + if($more) $xlink .= $sep.$more; + } + + return $xlink; } /** @@ -430,71 +430,71 @@ function exportlink($id='',$format='raw',$more='',$abs=false,$sep='&'){ * @param boolean $abs - Create an absolute URL */ function ml($id='',$more='',$direct=true,$sep='&',$abs=false){ - global $conf; - if(is_array($more)){ - // strip defaults for shorter URLs - if(isset($more['cache']) && $more['cache'] == 'cache') unset($more['cache']); - if(!$more['w']) unset($more['w']); - if(!$more['h']) unset($more['h']); - if(isset($more['id']) && $direct) unset($more['id']); - $more = buildURLparams($more,$sep); - }else{ - $more = str_replace('cache=cache','',$more); //skip default - $more = str_replace(',,',',',$more); - $more = str_replace(',',$sep,$more); - } - - if($abs){ - $xlink = DOKU_URL; - }else{ - $xlink = DOKU_BASE; - } - - // external URLs are always direct without rewriting - if(preg_match('#^(https?|ftp)://#i',$id)){ - $xlink .= 'lib/exe/fetch.php'; - // add hash: - $xlink .= '?hash='.substr(md5(auth_cookiesalt().$id),0,6); - if($more){ - $xlink .= $sep.$more; - $xlink .= $sep.'media='.rawurlencode($id); + global $conf; + if(is_array($more)){ + // strip defaults for shorter URLs + if(isset($more['cache']) && $more['cache'] == 'cache') unset($more['cache']); + if(!$more['w']) unset($more['w']); + if(!$more['h']) unset($more['h']); + if(isset($more['id']) && $direct) unset($more['id']); + $more = buildURLparams($more,$sep); }else{ - $xlink .= $sep.'media='.rawurlencode($id); + $more = str_replace('cache=cache','',$more); //skip default + $more = str_replace(',,',',',$more); + $more = str_replace(',',$sep,$more); } - return $xlink; - } - $id = idfilter($id); + if($abs){ + $xlink = DOKU_URL; + }else{ + $xlink = DOKU_BASE; + } - // decide on scriptname - if($direct){ - if($conf['userewrite'] == 1){ - $script = '_media'; + // external URLs are always direct without rewriting + if(preg_match('#^(https?|ftp)://#i',$id)){ + $xlink .= 'lib/exe/fetch.php'; + // add hash: + $xlink .= '?hash='.substr(md5(auth_cookiesalt().$id),0,6); + if($more){ + $xlink .= $sep.$more; + $xlink .= $sep.'media='.rawurlencode($id); + }else{ + $xlink .= $sep.'media='.rawurlencode($id); + } + return $xlink; + } + + $id = idfilter($id); + + // decide on scriptname + if($direct){ + if($conf['userewrite'] == 1){ + $script = '_media'; + }else{ + $script = 'lib/exe/fetch.php'; + } }else{ - $script = 'lib/exe/fetch.php'; + if($conf['userewrite'] == 1){ + $script = '_detail'; + }else{ + $script = 'lib/exe/detail.php'; + } } - }else{ - if($conf['userewrite'] == 1){ - $script = '_detail'; + + // build URL based on rewrite mode + if($conf['userewrite']){ + $xlink .= $script.'/'.$id; + if($more) $xlink .= '?'.$more; }else{ - $script = 'lib/exe/detail.php'; - } - } - - // build URL based on rewrite mode - if($conf['userewrite']){ - $xlink .= $script.'/'.$id; - if($more) $xlink .= '?'.$more; - }else{ - if($more){ - $xlink .= $script.'?'.$more; - $xlink .= $sep.'media='.$id; - }else{ - $xlink .= $script.'?media='.$id; - } - } - - return $xlink; + if($more){ + $xlink .= $script.'?'.$more; + $xlink .= $sep.'media='.$id; + }else{ + $xlink .= $script.'?media='.$id; + } + } + + return $xlink; } @@ -506,10 +506,7 @@ function ml($id='',$more='',$direct=true,$sep='&',$abs=false){ * @author Andreas Gohr <andi@splitbrain.org> */ function script($script='doku.php'){ -# $link = getBaseURL(); -# $link .= $script; -# return $link; - return DOKU_BASE.DOKU_SCRIPT; + return DOKU_BASE.DOKU_SCRIPT; } /** @@ -537,54 +534,54 @@ function script($script='doku.php'){ * @return bool - true if a spam word was found */ function checkwordblock($text=''){ - global $TEXT; - global $PRE; - global $SUF; - global $conf; - global $INFO; - - if(!$conf['usewordblock']) return false; - - if(!$text) $text = "$PRE $TEXT $SUF"; - - // we prepare the text a tiny bit to prevent spammers circumventing URL checks - $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i','\1http://\2 \2\3',$text); - - $wordblocks = getWordblocks(); - //how many lines to read at once (to work around some PCRE limits) - if(version_compare(phpversion(),'4.3.0','<')){ - //old versions of PCRE define a maximum of parenthesises even if no - //backreferences are used - the maximum is 99 - //this is very bad performancewise and may even be too high still - $chunksize = 40; - }else{ - //read file in chunks of 200 - this should work around the - //MAX_PATTERN_SIZE in modern PCRE - $chunksize = 200; - } - while($blocks = array_splice($wordblocks,0,$chunksize)){ - $re = array(); - #build regexp from blocks - foreach($blocks as $block){ - $block = preg_replace('/#.*$/','',$block); - $block = trim($block); - if(empty($block)) continue; - $re[] = $block; - } - if(count($re) && preg_match('#('.join('|',$re).')#si',$text,$matches)) { - //prepare event data - $data['matches'] = $matches; - $data['userinfo']['ip'] = $_SERVER['REMOTE_ADDR']; - if($_SERVER['REMOTE_USER']) { - $data['userinfo']['user'] = $_SERVER['REMOTE_USER']; - $data['userinfo']['name'] = $INFO['userinfo']['name']; - $data['userinfo']['mail'] = $INFO['userinfo']['mail']; - } - $callback = create_function('', 'return true;'); - return trigger_event('COMMON_WORDBLOCK_BLOCKED', $data, $callback, true); - } - } - return false; + global $TEXT; + global $PRE; + global $SUF; + global $conf; + global $INFO; + + if(!$conf['usewordblock']) return false; + + if(!$text) $text = "$PRE $TEXT $SUF"; + + // we prepare the text a tiny bit to prevent spammers circumventing URL checks + $text = preg_replace('!(\b)(www\.[\w.:?\-;,]+?\.[\w.:?\-;,]+?[\w/\#~:.?+=&%@\!\-.:?\-;,]+?)([.:?\-;,]*[^\w/\#~:.?+=&%@\!\-.:?\-;,])!i','\1http://\2 \2\3',$text); + + $wordblocks = getWordblocks(); + // how many lines to read at once (to work around some PCRE limits) + if(version_compare(phpversion(),'4.3.0','<')){ + // old versions of PCRE define a maximum of parenthesises even if no + // backreferences are used - the maximum is 99 + // this is very bad performancewise and may even be too high still + $chunksize = 40; + }else{ + // read file in chunks of 200 - this should work around the + // MAX_PATTERN_SIZE in modern PCRE + $chunksize = 200; + } + while($blocks = array_splice($wordblocks,0,$chunksize)){ + $re = array(); + // build regexp from blocks + foreach($blocks as $block){ + $block = preg_replace('/#.*$/','',$block); + $block = trim($block); + if(empty($block)) continue; + $re[] = $block; + } + if(count($re) && preg_match('#('.join('|',$re).')#si',$text,$matches)) { + // prepare event data + $data['matches'] = $matches; + $data['userinfo']['ip'] = $_SERVER['REMOTE_ADDR']; + if($_SERVER['REMOTE_USER']) { + $data['userinfo']['user'] = $_SERVER['REMOTE_USER']; + $data['userinfo']['name'] = $INFO['userinfo']['name']; + $data['userinfo']['mail'] = $INFO['userinfo']['mail']; + } + $callback = create_function('', 'return true;'); + return trigger_event('COMMON_WORDBLOCK_BLOCKED', $data, $callback, true); + } + } + return false; } /** @@ -601,60 +598,60 @@ function checkwordblock($text=''){ * @author Andreas Gohr <andi@splitbrain.org> */ function clientIP($single=false){ - $ip = array(); - $ip[] = $_SERVER['REMOTE_ADDR']; - if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) - $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_FORWARDED_FOR'])); - if(!empty($_SERVER['HTTP_X_REAL_IP'])) - $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_REAL_IP'])); - - // some IPv4/v6 regexps borrowed from Feyd - // see: http://forums.devnetwork.net/viewtopic.php?f=38&t=53479 - $dec_octet = '(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|[0-9])'; - $hex_digit = '[A-Fa-f0-9]'; - $h16 = "{$hex_digit}{1,4}"; - $IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet"; - $ls32 = "(?:$h16:$h16|$IPv4Address)"; - $IPv6Address = - "(?:(?:{$IPv4Address})|(?:". - "(?:$h16:){6}$ls32" . - "|::(?:$h16:){5}$ls32" . - "|(?:$h16)?::(?:$h16:){4}$ls32" . - "|(?:(?:$h16:){0,1}$h16)?::(?:$h16:){3}$ls32" . - "|(?:(?:$h16:){0,2}$h16)?::(?:$h16:){2}$ls32" . - "|(?:(?:$h16:){0,3}$h16)?::(?:$h16:){1}$ls32" . - "|(?:(?:$h16:){0,4}$h16)?::$ls32" . - "|(?:(?:$h16:){0,5}$h16)?::$h16" . - "|(?:(?:$h16:){0,6}$h16)?::" . - ")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)"; - - // remove any non-IP stuff - $cnt = count($ip); - $match = array(); - for($i=0; $i<$cnt; $i++){ - if(preg_match("/^$IPv4Address$/",$ip[$i],$match) || preg_match("/^$IPv6Address$/",$ip[$i],$match)) { - $ip[$i] = $match[0]; - } else { - $ip[$i] = ''; + $ip = array(); + $ip[] = $_SERVER['REMOTE_ADDR']; + if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) + $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_FORWARDED_FOR'])); + if(!empty($_SERVER['HTTP_X_REAL_IP'])) + $ip = array_merge($ip,explode(',',$_SERVER['HTTP_X_REAL_IP'])); + + // some IPv4/v6 regexps borrowed from Feyd + // see: http://forums.devnetwork.net/viewtopic.php?f=38&t=53479 + $dec_octet = '(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|[0-9])'; + $hex_digit = '[A-Fa-f0-9]'; + $h16 = "{$hex_digit}{1,4}"; + $IPv4Address = "$dec_octet\\.$dec_octet\\.$dec_octet\\.$dec_octet"; + $ls32 = "(?:$h16:$h16|$IPv4Address)"; + $IPv6Address = + "(?:(?:{$IPv4Address})|(?:". + "(?:$h16:){6}$ls32" . + "|::(?:$h16:){5}$ls32" . + "|(?:$h16)?::(?:$h16:){4}$ls32" . + "|(?:(?:$h16:){0,1}$h16)?::(?:$h16:){3}$ls32" . + "|(?:(?:$h16:){0,2}$h16)?::(?:$h16:){2}$ls32" . + "|(?:(?:$h16:){0,3}$h16)?::(?:$h16:){1}$ls32" . + "|(?:(?:$h16:){0,4}$h16)?::$ls32" . + "|(?:(?:$h16:){0,5}$h16)?::$h16" . + "|(?:(?:$h16:){0,6}$h16)?::" . + ")(?:\\/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))?)"; + + // remove any non-IP stuff + $cnt = count($ip); + $match = array(); + for($i=0; $i<$cnt; $i++){ + if(preg_match("/^$IPv4Address$/",$ip[$i],$match) || preg_match("/^$IPv6Address$/",$ip[$i],$match)) { + $ip[$i] = $match[0]; + } else { + $ip[$i] = ''; + } + if(empty($ip[$i])) unset($ip[$i]); } - if(empty($ip[$i])) unset($ip[$i]); - } - $ip = array_values(array_unique($ip)); - if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP - - if(!$single) return join(',',$ip); - - // decide which IP to use, trying to avoid local addresses - $ip = array_reverse($ip); - foreach($ip as $i){ - if(preg_match('/^(127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$i)){ - continue; - }else{ - return $i; + $ip = array_values(array_unique($ip)); + if(!$ip[0]) $ip[0] = '0.0.0.0'; // for some strange reason we don't have a IP + + if(!$single) return join(',',$ip); + + // decide which IP to use, trying to avoid local addresses + $ip = array_reverse($ip); + foreach($ip as $i){ + if(preg_match('/^(127\.|10\.|192\.168\.|172\.((1[6-9])|(2[0-9])|(3[0-1]))\.)/',$i)){ + continue; + }else{ + return $i; + } } - } - // still here? just use the first (last) address - return $ip[0]; + // still here? just use the first (last) address + return $ip[0]; } /** @@ -687,17 +684,17 @@ function clientismobile(){ * @returns a comma separated list of hostnames */ function gethostsbyaddrs($ips){ - $hosts = array(); - $ips = explode(',',$ips); + $hosts = array(); + $ips = explode(',',$ips); - if(is_array($ips)) { - foreach($ips as $ip){ - $hosts[] = gethostbyaddr(trim($ip)); + if(is_array($ips)) { + foreach($ips as $ip){ + $hosts[] = gethostbyaddr(trim($ip)); + } + return join(',',$hosts); + } else { + return gethostbyaddr(trim($ips)); } - return join(',',$hosts); - } else { - return gethostbyaddr(trim($ips)); - } } /** @@ -708,25 +705,25 @@ function gethostsbyaddrs($ips){ * @author Andreas Gohr <andi@splitbrain.org> */ function checklock($id){ - global $conf; - $lock = wikiLockFN($id); + global $conf; + $lock = wikiLockFN($id); - //no lockfile - if(!@file_exists($lock)) return false; + //no lockfile + if(!@file_exists($lock)) return false; - //lockfile expired - if((time() - filemtime($lock)) > $conf['locktime']){ - @unlink($lock); - return false; - } + //lockfile expired + if((time() - filemtime($lock)) > $conf['locktime']){ + @unlink($lock); + return false; + } - //my own lock - $ip = io_readFile($lock); - if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){ - return false; - } + //my own lock + $ip = io_readFile($lock); + if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){ + return false; + } - return $ip; + return $ip; } /** @@ -735,12 +732,12 @@ function checklock($id){ * @author Andreas Gohr <andi@splitbrain.org> */ function lock($id){ - $lock = wikiLockFN($id); - if($_SERVER['REMOTE_USER']){ - io_saveFile($lock,$_SERVER['REMOTE_USER']); - }else{ - io_saveFile($lock,clientIP()); - } + $lock = wikiLockFN($id); + if($_SERVER['REMOTE_USER']){ + io_saveFile($lock,$_SERVER['REMOTE_USER']); + }else{ + io_saveFile($lock,clientIP()); + } } /** @@ -750,15 +747,15 @@ function lock($id){ * @return bool true if a lock was removed */ function unlock($id){ - $lock = wikiLockFN($id); - if(@file_exists($lock)){ - $ip = io_readFile($lock); - if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){ - @unlink($lock); - return true; + $lock = wikiLockFN($id); + if(@file_exists($lock)){ + $ip = io_readFile($lock); + if( ($ip == clientIP()) || ($ip == $_SERVER['REMOTE_USER']) ){ + @unlink($lock); + return true; + } } - } - return false; + return false; } /** @@ -768,8 +765,8 @@ function unlock($id){ * @author Andreas Gohr <andi@splitbrain.org> */ function cleanText($text){ - $text = preg_replace("/(\015\012)|(\015)/","\012",$text); - return $text; + $text = preg_replace("/(\015\012)|(\015)/","\012",$text); + return $text; } /** @@ -781,8 +778,8 @@ function cleanText($text){ * @author Andreas Gohr <andi@splitbrain.org> */ function formText($text){ - $text = str_replace("\012","\015\012",$text); - return htmlspecialchars($text); + $text = str_replace("\012","\015\012",$text); + return htmlspecialchars($text); } /** @@ -791,7 +788,7 @@ function formText($text){ * @author Andreas Gohr <andi@splitbrain.org> */ function rawLocale($id){ - return io_readFile(localeFN($id)); + return io_readFile(localeFN($id)); } /** @@ -800,7 +797,7 @@ function rawLocale($id){ * @author Andreas Gohr <andi@splitbrain.org> */ function rawWiki($id,$rev=''){ - return io_readWikiPage(wikiFN($id, $rev), $id, $rev); + return io_readWikiPage(wikiFN($id, $rev), $id, $rev); } /** @@ -809,66 +806,66 @@ function rawWiki($id,$rev=''){ * @author Andreas Gohr <andi@splitbrain.org> */ function pageTemplate($data){ - $id = $data[0]; - global $conf; - global $INFO; - - $path = dirname(wikiFN($id)); - - if(@file_exists($path.'/_template.txt')){ - $tpl = io_readFile($path.'/_template.txt'); - }else{ - // search upper namespaces for templates - $len = strlen(rtrim($conf['datadir'],'/')); - while (strlen($path) >= $len){ - if(@file_exists($path.'/__template.txt')){ - $tpl = io_readFile($path.'/__template.txt'); - break; - } - $path = substr($path, 0, strrpos($path, '/')); - } - } - if(!$tpl) return ''; - - // replace placeholders - $file = noNS($id); - $page = strtr($file,'_',' '); - - $tpl = str_replace(array( - '@ID@', - '@NS@', - '@FILE@', - '@!FILE@', - '@!FILE!@', - '@PAGE@', - '@!PAGE@', - '@!!PAGE@', - '@!PAGE!@', - '@USER@', - '@NAME@', - '@MAIL@', - '@DATE@', - ), - array( - $id, - getNS($id), - $file, - utf8_ucfirst($file), - utf8_strtoupper($file), - $page, - utf8_ucfirst($page), - utf8_ucwords($page), - utf8_strtoupper($page), - $_SERVER['REMOTE_USER'], - $INFO['userinfo']['name'], - $INFO['userinfo']['mail'], - $conf['dformat'], - ), $tpl); - - // we need the callback to work around strftime's char limit - $tpl = preg_replace_callback('/%./',create_function('$m','return strftime($m[0]);'),$tpl); - - return $tpl; + $id = $data[0]; + global $conf; + global $INFO; + + $path = dirname(wikiFN($id)); + + if(@file_exists($path.'/_template.txt')){ + $tpl = io_readFile($path.'/_template.txt'); + }else{ + // search upper namespaces for templates + $len = strlen(rtrim($conf['datadir'],'/')); + while (strlen($path) >= $len){ + if(@file_exists($path.'/__template.txt')){ + $tpl = io_readFile($path.'/__template.txt'); + break; + } + $path = substr($path, 0, strrpos($path, '/')); + } + } + if(!$tpl) return ''; + + // replace placeholders + $file = noNS($id); + $page = strtr($file,'_',' '); + + $tpl = str_replace(array( + '@ID@', + '@NS@', + '@FILE@', + '@!FILE@', + '@!FILE!@', + '@PAGE@', + '@!PAGE@', + '@!!PAGE@', + '@!PAGE!@', + '@USER@', + '@NAME@', + '@MAIL@', + '@DATE@', + ), + array( + $id, + getNS($id), + $file, + utf8_ucfirst($file), + utf8_strtoupper($file), + $page, + utf8_ucfirst($page), + utf8_ucwords($page), + utf8_strtoupper($page), + $_SERVER['REMOTE_USER'], + $INFO['userinfo']['name'], + $INFO['userinfo']['mail'], + $conf['dformat'], + ), $tpl); + + // we need the callback to work around strftime's char limit + $tpl = preg_replace_callback('/%./',create_function('$m','return strftime($m[0]);'),$tpl); + + return $tpl; } @@ -883,16 +880,16 @@ function pageTemplate($data){ * @author Andreas Gohr <andi@splitbrain.org> */ function rawWikiSlices($range,$id,$rev=''){ - list($from,$to) = explode('-',$range,2); - $text = io_readWikiPage(wikiFN($id, $rev), $id, $rev); - if(!$from) $from = 0; - if(!$to) $to = strlen($text)+1; + list($from,$to) = explode('-',$range,2); + $text = io_readWikiPage(wikiFN($id, $rev), $id, $rev); + if(!$from) $from = 0; + if(!$to) $to = strlen($text)+1; - $slices[0] = substr($text,0,$from-1); - $slices[1] = substr($text,$from-1,$to-$from); - $slices[2] = substr($text,$to); + $slices[0] = substr($text,0,$from-1); + $slices[1] = substr($text,$from-1,$to-$from); + $slices[2] = substr($text,$to); - return $slices; + return $slices; } /** @@ -905,16 +902,15 @@ function rawWikiSlices($range,$id,$rev=''){ * @author Andreas Gohr <andi@splitbrain.org> */ function con($pre,$text,$suf,$pretty=false){ + if($pretty){ + if($pre && substr($pre,-1) != "\n") $pre .= "\n"; + if($suf && substr($text,-1) != "\n") $text .= "\n"; + } - if($pretty){ - if($pre && substr($pre,-1) != "\n") $pre .= "\n"; - if($suf && substr($text,-1) != "\n") $text .= "\n"; - } - - // Avoid double newline above section when saving section edit - //if($pre) $pre .= "\n"; - if($suf) $text .= "\n"; - return $pre.$text.$suf; + // Avoid double newline above section when saving section edit + //if($pre) $pre .= "\n"; + if($suf) $text .= "\n"; + return $pre.$text.$suf; } /** @@ -925,102 +921,102 @@ function con($pre,$text,$suf,$pretty=false){ * @author Ben Coburn <btcoburn@silicodon.net> */ function saveWikiText($id,$text,$summary,$minor=false){ - /* Note to developers: - This code is subtle and delicate. Test the behavior of - the attic and changelog with dokuwiki and external edits - after any changes. External edits change the wiki page - directly without using php or dokuwiki. - */ - global $conf; - global $lang; - global $REV; - // ignore if no changes were made - if($text == rawWiki($id,'')){ - return; - } - - $file = wikiFN($id); - $old = @filemtime($file); // from page - $wasRemoved = empty($text); - $wasCreated = !@file_exists($file); - $wasReverted = ($REV==true); - $newRev = false; - $oldRev = getRevisions($id, -1, 1, 1024); // from changelog - $oldRev = (int)(empty($oldRev)?0:$oldRev[0]); - if(!@file_exists(wikiFN($id, $old)) && @file_exists($file) && $old>=$oldRev) { - // add old revision to the attic if missing - saveOldRevision($id); - // add a changelog entry if this edit came from outside dokuwiki - if ($old>$oldRev) { - addLogEntry($old, $id, DOKU_CHANGE_TYPE_EDIT, $lang['external_edit'], '', array('ExternalEdit'=>true)); - // remove soon to be stale instructions - $cache = new cache_instructions($id, $file); - $cache->removeCache(); - } - } - - if ($wasRemoved){ - // Send "update" event with empty data, so plugins can react to page deletion - $data = array(array($file, '', false), getNS($id), noNS($id), false); - trigger_event('IO_WIKIPAGE_WRITE', $data); - // pre-save deleted revision - @touch($file); - clearstatcache(); - $newRev = saveOldRevision($id); - // remove empty file - @unlink($file); - // remove old meta info... - $mfiles = metaFiles($id); - $changelog = metaFN($id, '.changes'); - $metadata = metaFN($id, '.meta'); - foreach ($mfiles as $mfile) { - // but keep per-page changelog to preserve page history and keep meta data - if (@file_exists($mfile) && $mfile!==$changelog && $mfile!==$metadata) { @unlink($mfile); } - } - // purge meta data - p_purge_metadata($id); - $del = true; - // autoset summary on deletion - if(empty($summary)) $summary = $lang['deleted']; - // remove empty namespaces - io_sweepNS($id, 'datadir'); - io_sweepNS($id, 'mediadir'); - }else{ - // save file (namespace dir is created in io_writeWikiPage) - io_writeWikiPage($file, $text, $id); - // pre-save the revision, to keep the attic in sync - $newRev = saveOldRevision($id); - $del = false; - } - - // select changelog line type - $extra = ''; - $type = DOKU_CHANGE_TYPE_EDIT; - if ($wasReverted) { - $type = DOKU_CHANGE_TYPE_REVERT; - $extra = $REV; - } - else if ($wasCreated) { $type = DOKU_CHANGE_TYPE_CREATE; } - else if ($wasRemoved) { $type = DOKU_CHANGE_TYPE_DELETE; } - else if ($minor && $conf['useacl'] && $_SERVER['REMOTE_USER']) { $type = DOKU_CHANGE_TYPE_MINOR_EDIT; } //minor edits only for logged in users - - addLogEntry($newRev, $id, $type, $summary, $extra); - // send notify mails - notify($id,'admin',$old,$summary,$minor); - notify($id,'subscribers',$old,$summary,$minor); - - // update the purgefile (timestamp of the last time anything within the wiki was changed) - io_saveFile($conf['cachedir'].'/purgefile',time()); - - // if useheading is enabled, purge the cache of all linking pages - if(useHeading('content')){ - require_once(DOKU_INC.'inc/fulltext.php'); - $pages = ft_backlinks($id); - foreach ($pages as $page) { - $cache = new cache_renderer($page, wikiFN($page), 'xhtml'); - $cache->removeCache(); - } - } + /* Note to developers: + This code is subtle and delicate. Test the behavior of + the attic and changelog with dokuwiki and external edits + after any changes. External edits change the wiki page + directly without using php or dokuwiki. + */ + global $conf; + global $lang; + global $REV; + // ignore if no changes were made + if($text == rawWiki($id,'')){ + return; + } + + $file = wikiFN($id); + $old = @filemtime($file); // from page + $wasRemoved = empty($text); + $wasCreated = !@file_exists($file); + $wasReverted = ($REV==true); + $newRev = false; + $oldRev = getRevisions($id, -1, 1, 1024); // from changelog + $oldRev = (int)(empty($oldRev)?0:$oldRev[0]); + if(!@file_exists(wikiFN($id, $old)) && @file_exists($file) && $old>=$oldRev) { + // add old revision to the attic if missing + saveOldRevision($id); + // add a changelog entry if this edit came from outside dokuwiki + if ($old>$oldRev) { + addLogEntry($old, $id, DOKU_CHANGE_TYPE_EDIT, $lang['external_edit'], '', array('ExternalEdit'=>true)); + // remove soon to be stale instructions + $cache = new cache_instructions($id, $file); + $cache->removeCache(); + } + } + + if ($wasRemoved){ + // Send "update" event with empty data, so plugins can react to page deletion + $data = array(array($file, '', false), getNS($id), noNS($id), false); + trigger_event('IO_WIKIPAGE_WRITE', $data); + // pre-save deleted revision + @touch($file); + clearstatcache(); + $newRev = saveOldRevision($id); + // remove empty file + @unlink($file); + // remove old meta info... + $mfiles = metaFiles($id); + $changelog = metaFN($id, '.changes'); + $metadata = metaFN($id, '.meta'); + foreach ($mfiles as $mfile) { + // but keep per-page changelog to preserve page history and keep meta data + if (@file_exists($mfile) && $mfile!==$changelog && $mfile!==$metadata) { @unlink($mfile); } + } + // purge meta data + p_purge_metadata($id); + $del = true; + // autoset summary on deletion + if(empty($summary)) $summary = $lang['deleted']; + // remove empty namespaces + io_sweepNS($id, 'datadir'); + io_sweepNS($id, 'mediadir'); + }else{ + // save file (namespace dir is created in io_writeWikiPage) + io_writeWikiPage($file, $text, $id); + // pre-save the revision, to keep the attic in sync + $newRev = saveOldRevision($id); + $del = false; + } + + // select changelog line type + $extra = ''; + $type = DOKU_CHANGE_TYPE_EDIT; + if ($wasReverted) { + $type = DOKU_CHANGE_TYPE_REVERT; + $extra = $REV; + } + else if ($wasCreated) { $type = DOKU_CHANGE_TYPE_CREATE; } + else if ($wasRemoved) { $type = DOKU_CHANGE_TYPE_DELETE; } + else if ($minor && $conf['useacl'] && $_SERVER['REMOTE_USER']) { $type = DOKU_CHANGE_TYPE_MINOR_EDIT; } //minor edits only for logged in users + + addLogEntry($newRev, $id, $type, $summary, $extra); + // send notify mails + notify($id,'admin',$old,$summary,$minor); + notify($id,'subscribers',$old,$summary,$minor); + + // update the purgefile (timestamp of the last time anything within the wiki was changed) + io_saveFile($conf['cachedir'].'/purgefile',time()); + + // if useheading is enabled, purge the cache of all linking pages + if(useHeading('content')){ + require_once(DOKU_INC.'inc/fulltext.php'); + $pages = ft_backlinks($id); + foreach ($pages as $page) { + $cache = new cache_renderer($page, wikiFN($page), 'xhtml'); + $cache->removeCache(); + } + } } /** @@ -1030,13 +1026,13 @@ function saveWikiText($id,$text,$summary,$minor=false){ * @author Andreas Gohr <andi@splitbrain.org> */ function saveOldRevision($id){ - global $conf; - $oldf = wikiFN($id); - if(!@file_exists($oldf)) return ''; - $date = filemtime($oldf); - $newf = wikiFN($id,$date); - io_writeWikiPage($newf, rawWiki($id), $id, $date); - return $date; + global $conf; + $oldf = wikiFN($id); + if(!@file_exists($oldf)) return ''; + $date = filemtime($oldf); + $newf = wikiFN($id,$date); + io_writeWikiPage($newf, rawWiki($id), $id, $date); + return $date; } /** @@ -1052,72 +1048,72 @@ function saveOldRevision($id){ * @author Andreas Gohr <andi@splitbrain.org> */ function notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){ - global $lang; - global $conf; - global $INFO; - - // decide if there is something to do - if($who == 'admin'){ - if(empty($conf['notify'])) return; //notify enabled? - $text = rawLocale('mailtext'); - $to = $conf['notify']; - $bcc = ''; - }elseif($who == 'subscribers'){ - if(!$conf['subscribers']) return; //subscribers enabled? - if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return; //skip minors - $bcc = subscriber_addresslist($id,false); - if(empty($bcc)) return; - $to = ''; - $text = rawLocale('subscribermail'); - }elseif($who == 'register'){ - if(empty($conf['registernotify'])) return; - $text = rawLocale('registermail'); - $to = $conf['registernotify']; - $bcc = ''; - }else{ - return; //just to be safe - } - - $ip = clientIP(); - $text = str_replace('@DATE@',dformat(),$text); - $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text); - $text = str_replace('@IPADDRESS@',$ip,$text); - $text = str_replace('@HOSTNAME@',gethostsbyaddrs($ip),$text); - $text = str_replace('@NEWPAGE@',wl($id,'',true,'&'),$text); - $text = str_replace('@PAGE@',$id,$text); - $text = str_replace('@TITLE@',$conf['title'],$text); - $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text); - $text = str_replace('@SUMMARY@',$summary,$text); - $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text); - - foreach ($replace as $key => $substitution) { - $text = str_replace('@'.strtoupper($key).'@',$substitution, $text); - } - - if($who == 'register'){ - $subject = $lang['mail_new_user'].' '.$summary; - }elseif($rev){ - $subject = $lang['mail_changed'].' '.$id; - $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true,'&'),$text); - require_once(DOKU_INC.'inc/DifferenceEngine.php'); - $df = new Diff(explode("\n",rawWiki($id,$rev)), - explode("\n",rawWiki($id))); - $dformat = new UnifiedDiffFormatter(); - $diff = $dformat->format($df); - }else{ - $subject=$lang['mail_newpage'].' '.$id; - $text = str_replace('@OLDPAGE@','none',$text); - $diff = rawWiki($id); - } - $text = str_replace('@DIFF@',$diff,$text); - $subject = '['.$conf['title'].'] '.$subject; - - $from = $conf['mailfrom']; - $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from); - $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from); - $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from); - - mail_send($to,$subject,$text,$from,'',$bcc); + global $lang; + global $conf; + global $INFO; + + // decide if there is something to do + if($who == 'admin'){ + if(empty($conf['notify'])) return; //notify enabled? + $text = rawLocale('mailtext'); + $to = $conf['notify']; + $bcc = ''; + }elseif($who == 'subscribers'){ + if(!$conf['subscribers']) return; //subscribers enabled? + if($conf['useacl'] && $_SERVER['REMOTE_USER'] && $minor) return; //skip minors + $bcc = subscriber_addresslist($id,false); + if(empty($bcc)) return; + $to = ''; + $text = rawLocale('subscribermail'); + }elseif($who == 'register'){ + if(empty($conf['registernotify'])) return; + $text = rawLocale('registermail'); + $to = $conf['registernotify']; + $bcc = ''; + }else{ + return; //just to be safe + } + + $ip = clientIP(); + $text = str_replace('@DATE@',dformat(),$text); + $text = str_replace('@BROWSER@',$_SERVER['HTTP_USER_AGENT'],$text); + $text = str_replace('@IPADDRESS@',$ip,$text); + $text = str_replace('@HOSTNAME@',gethostsbyaddrs($ip),$text); + $text = str_replace('@NEWPAGE@',wl($id,'',true,'&'),$text); + $text = str_replace('@PAGE@',$id,$text); + $text = str_replace('@TITLE@',$conf['title'],$text); + $text = str_replace('@DOKUWIKIURL@',DOKU_URL,$text); + $text = str_replace('@SUMMARY@',$summary,$text); + $text = str_replace('@USER@',$_SERVER['REMOTE_USER'],$text); + + foreach ($replace as $key => $substitution) { + $text = str_replace('@'.strtoupper($key).'@',$substitution, $text); + } + + if($who == 'register'){ + $subject = $lang['mail_new_user'].' '.$summary; + }elseif($rev){ + $subject = $lang['mail_changed'].' '.$id; + $text = str_replace('@OLDPAGE@',wl($id,"rev=$rev",true,'&'),$text); + require_once(DOKU_INC.'inc/DifferenceEngine.php'); + $df = new Diff(explode("\n",rawWiki($id,$rev)), + explode("\n",rawWiki($id))); + $dformat = new UnifiedDiffFormatter(); + $diff = $dformat->format($df); + }else{ + $subject=$lang['mail_newpage'].' '.$id; + $text = str_replace('@OLDPAGE@','none',$text); + $diff = rawWiki($id); + } + $text = str_replace('@DIFF@',$diff,$text); + $subject = '['.$conf['title'].'] '.$subject; + + $from = $conf['mailfrom']; + $from = str_replace('@USER@',$_SERVER['REMOTE_USER'],$from); + $from = str_replace('@NAME@',$INFO['userinfo']['name'],$from); + $from = str_replace('@MAIL@',$INFO['userinfo']['mail'],$from); + + mail_send($to,$subject,$text,$from,'',$bcc); } /** @@ -1127,32 +1123,32 @@ function notify($id,$who,$rev='',$summary='',$minor=false,$replace=array()){ * @author Todd Augsburger <todd@rollerorgans.com> */ function getGoogleQuery(){ - if (!isset($_SERVER['HTTP_REFERER'])) { - return ''; - } - $url = parse_url($_SERVER['HTTP_REFERER']); - - $query = array(); - - // temporary workaround against PHP bug #49733 - // see http://bugs.php.net/bug.php?id=49733 - if(UTF8_MBSTRING) $enc = mb_internal_encoding(); - parse_str($url['query'],$query); - if(UTF8_MBSTRING) mb_internal_encoding($enc); - - $q = ''; - if(isset($query['q'])) - $q = $query['q']; // google, live/msn, aol, ask, altavista, alltheweb, gigablast - elseif(isset($query['p'])) - $q = $query['p']; // yahoo - elseif(isset($query['query'])) - $q = $query['query']; // lycos, netscape, clusty, hotbot - elseif(preg_match("#a9\.com#i",$url['host'])) // a9 - $q = urldecode(ltrim($url['path'],'/')); - - if($q === '') return ''; - $q = preg_split('/[\s\'"\\\\`()\]\[?:!\.{};,#+*<>\\/]+/',$q,-1,PREG_SPLIT_NO_EMPTY); - return $q; + if (!isset($_SERVER['HTTP_REFERER'])) { + return ''; + } + $url = parse_url($_SERVER['HTTP_REFERER']); + + $query = array(); + + // temporary workaround against PHP bug #49733 + // see http://bugs.php.net/bug.php?id=49733 + if(UTF8_MBSTRING) $enc = mb_internal_encoding(); + parse_str($url['query'],$query); + if(UTF8_MBSTRING) mb_internal_encoding($enc); + + $q = ''; + if(isset($query['q'])) + $q = $query['q']; // google, live/msn, aol, ask, altavista, alltheweb, gigablast + elseif(isset($query['p'])) + $q = $query['p']; // yahoo + elseif(isset($query['query'])) + $q = $query['query']; // lycos, netscape, clusty, hotbot + elseif(preg_match("#a9\.com#i",$url['host'])) // a9 + $q = urldecode(ltrim($url['path'],'/')); + + if($q === '') return ''; + $q = preg_split('/[\s\'"\\\\`()\]\[?:!\.{};,#+*<>\\/]+/',$q,-1,PREG_SPLIT_NO_EMPTY); + return $q; } /** @@ -1162,18 +1158,18 @@ function getGoogleQuery(){ * @author Andreas Gohr <andi@splitbrain.org> */ function setCorrectLocale(){ - global $conf; - global $lang; - - $enc = strtoupper($lang['encoding']); - foreach ($lang['locales'] as $loc){ - //try locale - if(@setlocale(LC_ALL,$loc)) return; - //try loceale with encoding - if(@setlocale(LC_ALL,"$loc.$enc")) return; - } - //still here? try to set from environment - @setlocale(LC_ALL,""); + global $conf; + global $lang; + + $enc = strtoupper($lang['encoding']); + foreach ($lang['locales'] as $loc){ + //try locale + if(@setlocale(LC_ALL,$loc)) return; + //try loceale with encoding + if(@setlocale(LC_ALL,"$loc.$enc")) return; + } + //still here? try to set from environment + @setlocale(LC_ALL,""); } /** @@ -1186,16 +1182,16 @@ function setCorrectLocale(){ * @version 1.0.0 */ function filesize_h($size, $dec = 1){ - $sizes = array('B', 'KB', 'MB', 'GB'); - $count = count($sizes); - $i = 0; + $sizes = array('B', 'KB', 'MB', 'GB'); + $count = count($sizes); + $i = 0; - while ($size >= 1024 && ($i < $count - 1)) { - $size /= 1024; - $i++; - } + while ($size >= 1024 && ($i < $count - 1)) { + $size /= 1024; + $i++; + } - return round($size, $dec) . ' ' . $sizes[$i]; + return round($size, $dec) . ' ' . $sizes[$i]; } /** @@ -1204,29 +1200,28 @@ function filesize_h($size, $dec = 1){ * @author Andreas Gohr <gohr@cosmocode.de> */ function datetime_h($dt){ - global $lang; - - $ago = time() - $dt; - if($ago > 24*60*60*30*12*2){ - return sprintf($lang['years'], round($ago/(24*60*60*30*12))); - } - if($ago > 24*60*60*30*2){ - return sprintf($lang['months'], round($ago/(24*60*60*30))); - } - if($ago > 24*60*60*7*2){ - return sprintf($lang['weeks'], round($ago/(24*60*60*7))); - } - if($ago > 24*60*60*2){ - return sprintf($lang['days'], round($ago/(24*60*60))); - } - if($ago > 60*60*2){ - return sprintf($lang['hours'], round($ago/(60*60))); - } - if($ago > 60*2){ - return sprintf($lang['minutes'], round($ago/(60))); - } - return sprintf($lang['seconds'], $ago); + global $lang; + $ago = time() - $dt; + if($ago > 24*60*60*30*12*2){ + return sprintf($lang['years'], round($ago/(24*60*60*30*12))); + } + if($ago > 24*60*60*30*2){ + return sprintf($lang['months'], round($ago/(24*60*60*30))); + } + if($ago > 24*60*60*7*2){ + return sprintf($lang['weeks'], round($ago/(24*60*60*7))); + } + if($ago > 24*60*60*2){ + return sprintf($lang['days'], round($ago/(24*60*60))); + } + if($ago > 60*60*2){ + return sprintf($lang['hours'], round($ago/(60*60))); + } + if($ago > 60*2){ + return sprintf($lang['minutes'], round($ago/(60))); + } + return sprintf($lang['seconds'], $ago); } /** @@ -1239,14 +1234,14 @@ function datetime_h($dt){ * @author Andreas Gohr <gohr@cosmocode.de> */ function dformat($dt=null,$format=''){ - global $conf; + global $conf; - if(is_null($dt)) $dt = time(); - $dt = (int) $dt; - if(!$format) $format = $conf['dformat']; + if(is_null($dt)) $dt = time(); + $dt = (int) $dt; + if(!$format) $format = $conf['dformat']; - $format = str_replace('%f',datetime_h($dt),$format); - return strftime($format,$dt); + $format = str_replace('%f',datetime_h($dt),$format); + return strftime($format,$dt); } /** @@ -1256,22 +1251,25 @@ function dformat($dt=null,$format=''){ * @author Christopher Smith <chris@jalakai.co.uk> */ function obfuscate($email) { - global $conf; - - switch ($conf['mailguard']) { - case 'visible' : - $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '); - return strtr($email, $obfuscate); - - case 'hex' : - $encode = ''; - for ($x=0; $x < strlen($email); $x++) $encode .= '&#x' . bin2hex($email{$x}).';'; - return $encode; - - case 'none' : - default : - return $email; - } + global $conf; + + switch ($conf['mailguard']) { + case 'visible' : + $obfuscate = array('@' => ' [at] ', '.' => ' [dot] ', '-' => ' [dash] '); + return strtr($email, $obfuscate); + + case 'hex' : + $encode = ''; + $len = strlen($email); + for ($x=0; $x < $len; $x++){ + $encode .= '&#x' . bin2hex($email{$x}).';'; + } + return $encode; + + case 'none' : + default : + return $email; + } } /** @@ -1280,22 +1278,22 @@ function obfuscate($email) { * @author Andreas Gohr <andi@splitbrain.org> */ function is_subscribed($id,$uid,$ns=false){ - if(!$ns) { - $file=metaFN($id,'.mlist'); - } else { - if(!getNS($id)) { - $file = metaFN(getNS($id),'.mlist'); + if(!$ns) { + $file=metaFN($id,'.mlist'); } else { - $file = metaFN(getNS($id),'/.mlist'); + if(!getNS($id)) { + $file = metaFN(getNS($id),'.mlist'); + } else { + $file = metaFN(getNS($id),'/.mlist'); + } + } + if (@file_exists($file)) { + $mlist = file($file); + $pos = array_search($uid."\n",$mlist); + return is_int($pos); } - } - if (@file_exists($file)) { - $mlist = file($file); - $pos = array_search($uid."\n",$mlist); - return is_int($pos); - } - return false; + return false; } /** @@ -1305,64 +1303,64 @@ function is_subscribed($id,$uid,$ns=false){ * @author Steven Danz <steven-danz@kc.rr.com> */ function subscriber_addresslist($id,$self=true){ - global $conf; - global $auth; - - if (!$conf['subscribers']) return ''; - - $users = array(); - $emails = array(); - - // load the page mlist file content - $mlist = array(); - $file=metaFN($id,'.mlist'); - if (@file_exists($file)) { - $mlist = file($file); - foreach ($mlist as $who) { - $who = rtrim($who); - if(!$self && $who == $_SERVER['REMOTE_USER']) continue; - $users[$who] = true; - } - } - - // load also the namespace mlist file content - $ns = getNS($id); - while ($ns) { - $nsfile = metaFN($ns,'/.mlist'); + global $conf; + global $auth; + + if (!$conf['subscribers']) return ''; + + $users = array(); + $emails = array(); + + // load the page mlist file content + $mlist = array(); + $file=metaFN($id,'.mlist'); + if (@file_exists($file)) { + $mlist = file($file); + foreach ($mlist as $who) { + $who = rtrim($who); + if(!$self && $who == $_SERVER['REMOTE_USER']) continue; + $users[$who] = true; + } + } + + // load also the namespace mlist file content + $ns = getNS($id); + while ($ns) { + $nsfile = metaFN($ns,'/.mlist'); + if (@file_exists($nsfile)) { + $mlist = file($nsfile); + foreach ($mlist as $who) { + $who = rtrim($who); + if(!$self && $who == $_SERVER['REMOTE_USER']) continue; + $users[$who] = true; + } + } + $ns = getNS($ns); + } + // root namespace + $nsfile = metaFN('','.mlist'); if (@file_exists($nsfile)) { - $mlist = file($nsfile); - foreach ($mlist as $who) { - $who = rtrim($who); - if(!$self && $who == $_SERVER['REMOTE_USER']) continue; - $users[$who] = true; - } - } - $ns = getNS($ns); - } - // root namespace - $nsfile = metaFN('','.mlist'); - if (@file_exists($nsfile)) { - $mlist = file($nsfile); - foreach ($mlist as $who) { - $who = rtrim($who); - if(!$self && $who == $_SERVER['REMOTE_USER']) continue; - $users[$who] = true; - } - } - if(!empty($users)) { - foreach (array_keys($users) as $who) { - $info = $auth->getUserData($who); - if($info === false) continue; - $level = auth_aclcheck($id,$who,$info['grps']); - if ($level >= AUTH_READ) { - if (strcasecmp($info['mail'],$conf['notify']) != 0) { - $emails[] = $info['mail']; + $mlist = file($nsfile); + foreach ($mlist as $who) { + $who = rtrim($who); + if(!$self && $who == $_SERVER['REMOTE_USER']) continue; + $users[$who] = true; + } + } + if(!empty($users)) { + foreach (array_keys($users) as $who) { + $info = $auth->getUserData($who); + if($info === false) continue; + $level = auth_aclcheck($id,$who,$info['grps']); + if ($level >= AUTH_READ) { + if (strcasecmp($info['mail'],$conf['notify']) != 0) { + $emails[] = $info['mail']; + } + } } - } } - } - return implode(',',$emails); + return implode(',',$emails); } /** @@ -1371,7 +1369,7 @@ function subscriber_addresslist($id,$self=true){ * @author Andreas Gohr <andi@splitbrain.org> */ function unslash($string,$char="'"){ - return str_replace('\\'.$char,$char,$string); + return str_replace('\\'.$char,$char,$string); } /** @@ -1422,7 +1420,7 @@ function preg_quote_cb($string){ */ function shorten($keep,$short,$max,$min=9,$char='…'){ $max = $max - utf8_strlen($keep); - if($max < $min) return $keep; + if($max < $min) return $keep; $len = utf8_strlen($short); if($len <= $max) return $keep.$short; $half = floor($max/2); @@ -1440,26 +1438,26 @@ function editorinfo($username){ global $auth; switch($conf['showuseras']){ - case 'username': - case 'email': - case 'email_link': - if($auth) $info = $auth->getUserData($username); - break; - default: - return hsc($username); + case 'username': + case 'email': + case 'email_link': + if($auth) $info = $auth->getUserData($username); + break; + default: + return hsc($username); } if(isset($info) && $info) { switch($conf['showuseras']){ - case 'username': - return hsc($info['name']); - case 'email': - return obfuscate($info['mail']); - case 'email_link': - $mail=obfuscate($info['mail']); - return '<a href="mailto:'.$mail.'">'.$mail.'</a>'; - default: - return hsc($username); + case 'username': + return hsc($info['name']); + case 'email': + return obfuscate($info['mail']); + case 'email_link': + $mail=obfuscate($info['mail']); + return '<a href="mailto:'.$mail.'">'.$mail.'</a>'; + default: + return hsc($username); } } else { return hsc($username); @@ -1503,22 +1501,24 @@ function license_img($type){ * @author Andreas Gohr <andi@splitbrain.org> */ function is_mem_available($mem,$bytes=1048576){ - $limit = trim(ini_get('memory_limit')); - if(empty($limit)) return true; // no limit set! + $limit = trim(ini_get('memory_limit')); + if(empty($limit)) return true; // no limit set! - // parse limit to bytes - $limit = php_to_byte($limit); + // parse limit to bytes + $limit = php_to_byte($limit); - // get used memory if possible - if(function_exists('memory_get_usage')){ - $used = memory_get_usage(); - } + // get used memory if possible + if(function_exists('memory_get_usage')){ + $used = memory_get_usage(); + }else{ + $used = $bytes; + } - if($used+$mem > $limit){ - return false; - } + if($used+$mem > $limit){ + return false; + } - return true; + return true; } /** @@ -1545,4 +1545,4 @@ function send_redirect($url){ exit; } -//Setup VIM: ex: et ts=2 enc=utf-8 : +//Setup VIM: ex: et ts=4 enc=utf-8 : diff --git a/inc/confutils.php b/inc/confutils.php index 9ec7a551e..abfde8a80 100644 --- a/inc/confutils.php +++ b/inc/confutils.php @@ -16,29 +16,29 @@ * @author Andreas Gohr <andi@splitbrain.org> */ function mimetype($file, $knownonly=true){ - $ret = array(false,false,false); // return array - $mtypes = getMimeTypes(); // known mimetypes - $exts = join('|',array_keys($mtypes)); // known extensions (regexp) - if(!$knownonly){ - $exts = $exts.'|[_\-A-Za-z0-9]+'; // any extension - } - if(preg_match('#\.('.$exts.')$#i',$file,$matches)){ - $ext = strtolower($matches[1]); - } - - if($ext){ - if (isset($mtypes[$ext])){ - if($mtypes[$ext][0] == '!'){ - $ret = array($ext, substr($mtypes[$ext],1), true); - }else{ - $ret = array($ext, $mtypes[$ext], false); - } - }elseif(!$knownonly){ - $ret = array($ext, 'application/octet-stream', true); + $ret = array(false,false,false); // return array + $mtypes = getMimeTypes(); // known mimetypes + $exts = join('|',array_keys($mtypes)); // known extensions (regexp) + if(!$knownonly){ + $exts = $exts.'|[_\-A-Za-z0-9]+'; // any extension + } + if(preg_match('#\.('.$exts.')$#i',$file,$matches)){ + $ext = strtolower($matches[1]); + } + + if($ext){ + if (isset($mtypes[$ext])){ + if($mtypes[$ext][0] == '!'){ + $ret = array($ext, substr($mtypes[$ext],1), true); + }else{ + $ret = array($ext, $mtypes[$ext], false); + } + }elseif(!$knownonly){ + $ret = array($ext, 'application/octet-stream', true); + } } - } - return $ret; + return $ret; } /** @@ -47,11 +47,11 @@ function mimetype($file, $knownonly=true){ * @author Andreas Gohr <andi@splitbrain.org> */ function getMimeTypes() { - static $mime = NULL; - if ( !$mime ) { - $mime = retrieveConfig('mime','confToHash'); - } - return $mime; + static $mime = null; + if ( !$mime ) { + $mime = retrieveConfig('mime','confToHash'); + } + return $mime; } /** @@ -60,11 +60,11 @@ function getMimeTypes() { * @author Harry Fuecks <hfuecks@gmail.com> */ function getAcronyms() { - static $acronyms = NULL; - if ( !$acronyms ) { - $acronyms = retrieveConfig('acronyms','confToHash'); - } - return $acronyms; + static $acronyms = null; + if ( !$acronyms ) { + $acronyms = retrieveConfig('acronyms','confToHash'); + } + return $acronyms; } /** @@ -73,11 +73,11 @@ function getAcronyms() { * @author Harry Fuecks <hfuecks@gmail.com> */ function getSmileys() { - static $smileys = NULL; - if ( !$smileys ) { - $smileys = retrieveConfig('smileys','confToHash'); - } - return $smileys; + static $smileys = null; + if ( !$smileys ) { + $smileys = retrieveConfig('smileys','confToHash'); + } + return $smileys; } /** @@ -86,11 +86,11 @@ function getSmileys() { * @author Harry Fuecks <hfuecks@gmail.com> */ function getEntities() { - static $entities = NULL; - if ( !$entities ) { - $entities = retrieveConfig('entities','confToHash'); - } - return $entities; + static $entities = null; + if ( !$entities ) { + $entities = retrieveConfig('entities','confToHash'); + } + return $entities; } /** @@ -99,13 +99,13 @@ function getEntities() { * @author Harry Fuecks <hfuecks@gmail.com> */ function getInterwiki() { - static $wikis = NULL; - if ( !$wikis ) { - $wikis = retrieveConfig('interwiki','confToHash',array(true)); - } - //add sepecial case 'this' - $wikis['this'] = DOKU_URL.'{NAME}'; - return $wikis; + static $wikis = null; + if ( !$wikis ) { + $wikis = retrieveConfig('interwiki','confToHash',array(true)); + } + //add sepecial case 'this' + $wikis['this'] = DOKU_URL.'{NAME}'; + return $wikis; } /** @@ -113,23 +113,23 @@ function getInterwiki() { * */ function getWordblocks() { - static $wordblocks = NULL; - if ( !$wordblocks ) { - $wordblocks = retrieveConfig('wordblock','file'); - } - return $wordblocks; + static $wordblocks = null; + if ( !$wordblocks ) { + $wordblocks = retrieveConfig('wordblock','file'); + } + return $wordblocks; } function getSchemes() { - static $schemes = NULL; - if ( !$schemes ) { - $schemes = retrieveConfig('scheme','file'); - } - $schemes = array_map('trim', $schemes); - $schemes = preg_replace('/^#.*/', '', $schemes); - $schemes = array_filter($schemes); - return $schemes; + static $schemes = null; + if ( !$schemes ) { + $schemes = retrieveConfig('scheme','file'); + } + $schemes = array_map('trim', $schemes); + $schemes = preg_replace('/^#.*/', '', $schemes); + $schemes = array_filter($schemes); + return $schemes; } /** @@ -143,22 +143,22 @@ function getSchemes() { * @author Gina Haeussge <gina@foosel.net> */ function linesToHash($lines, $lower=false) { - foreach ( $lines as $line ) { - //ignore comments (except escaped ones) - $line = preg_replace('/(?<![&\\\\])#.*$/','',$line); - $line = str_replace('\\#','#',$line); - $line = trim($line); - if(empty($line)) continue; - $line = preg_split('/\s+/',$line,2); - // Build the associative array - if($lower){ - $conf[strtolower($line[0])] = $line[1]; - }else{ - $conf[$line[0]] = $line[1]; + foreach ( $lines as $line ) { + //ignore comments (except escaped ones) + $line = preg_replace('/(?<![&\\\\])#.*$/','',$line); + $line = str_replace('\\#','#',$line); + $line = trim($line); + if(empty($line)) continue; + $line = preg_split('/\s+/',$line,2); + // Build the associative array + if($lower){ + $conf[strtolower($line[0])] = $line[1]; + }else{ + $conf[$line[0]] = $line[1]; + } } - } - return $conf; + return $conf; } /** @@ -172,11 +172,11 @@ function linesToHash($lines, $lower=false) { * @author Gina Haeussge <gina@foosel.net> */ function confToHash($file,$lower=false) { - $conf = array(); - $lines = @file( $file ); - if ( !$lines ) return $conf; + $conf = array(); + $lines = @file( $file ); + if ( !$lines ) return $conf; - return linesToHash($lines, $lower); + return linesToHash($lines, $lower); } /** @@ -190,23 +190,23 @@ function confToHash($file,$lower=false) { * @return array configuration values */ function retrieveConfig($type,$fn,$params=null) { - global $config_cascade; - - if(!is_array($params)) $params = array(); - - $combined = array(); - if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "'.$type.'"',E_USER_WARNING); - foreach (array('default','local','protected') as $config_group) { - if (empty($config_cascade[$type][$config_group])) continue; - foreach ($config_cascade[$type][$config_group] as $file) { - if (@file_exists($file)) { - $config = call_user_func_array($fn,array_merge(array($file),$params)); - $combined = array_merge($combined, $config); - } + global $config_cascade; + + if(!is_array($params)) $params = array(); + + $combined = array(); + if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "'.$type.'"',E_USER_WARNING); + foreach (array('default','local','protected') as $config_group) { + if (empty($config_cascade[$type][$config_group])) continue; + foreach ($config_cascade[$type][$config_group] as $file) { + if (@file_exists($file)) { + $config = call_user_func_array($fn,array_merge(array($file),$params)); + $combined = array_merge($combined, $config); + } + } } - } - return $combined; + return $combined; } /** @@ -218,16 +218,16 @@ function retrieveConfig($type,$fn,$params=null) { * @return array list of files, default before local before protected */ function getConfigFiles($type) { - global $config_cascade; - $files = array(); + global $config_cascade; + $files = array(); - if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "'.$type.'"',E_USER_WARNING); - foreach (array('default','local','protected') as $config_group) { - if (empty($config_cascade[$type][$config_group])) continue; - $files = array_merge($files, $config_cascade[$type][$config_group]); - } + if (!is_array($config_cascade[$type])) trigger_error('Missing config cascade for "'.$type.'"',E_USER_WARNING); + foreach (array('default','local','protected') as $config_group) { + if (empty($config_cascade[$type][$config_group])) continue; + $files = array_merge($files, $config_cascade[$type][$config_group]); + } - return $files; + return $files; } /** @@ -237,23 +237,23 @@ function getConfigFiles($type) { * @returns boolean true if enabled, false if disabled */ function actionOK($action){ - static $disabled = null; - if(is_null($disabled)){ - global $conf; - - // prepare disabled actions array and handle legacy options - $disabled = explode(',',$conf['disableactions']); - $disabled = array_map('trim',$disabled); - if(isset($conf['openregister']) && !$conf['openregister']) $disabled[] = 'register'; - if(isset($conf['resendpasswd']) && !$conf['resendpasswd']) $disabled[] = 'resendpwd'; - if(isset($conf['subscribers']) && !$conf['subscribers']) { - $disabled[] = 'subscribe'; - $disabled[] = 'subscribens'; + static $disabled = null; + if(is_null($disabled)){ + global $conf; + + // prepare disabled actions array and handle legacy options + $disabled = explode(',',$conf['disableactions']); + $disabled = array_map('trim',$disabled); + if(isset($conf['openregister']) && !$conf['openregister']) $disabled[] = 'register'; + if(isset($conf['resendpasswd']) && !$conf['resendpasswd']) $disabled[] = 'resendpwd'; + if(isset($conf['subscribers']) && !$conf['subscribers']) { + $disabled[] = 'subscribe'; + $disabled[] = 'subscribens'; + } + $disabled = array_unique($disabled); } - $disabled = array_unique($disabled); - } - return !in_array($action,$disabled); + return !in_array($action,$disabled); } /** @@ -266,25 +266,30 @@ function actionOK($action){ * @returns boolean true if headings should be used for $linktype, false otherwise */ function useHeading($linktype) { - static $useHeading = null; + static $useHeading = null; - if (is_null($useHeading)) { - global $conf; + if (is_null($useHeading)) { + global $conf; - if (!empty($conf['useheading'])) { - switch ($conf['useheading']) { - case 'content' : $useHeading['content'] = true; break; - case 'navigation' : $useHeading['navigation'] = true; break; - default: - $useHeading['content'] = true; - $useHeading['navigation'] = true; - } - } else { - $useHeading = array(); + if (!empty($conf['useheading'])) { + switch ($conf['useheading']) { + case 'content': + $useHeading['content'] = true; + break; + + case 'navigation': + $useHeading['navigation'] = true; + break; + default: + $useHeading['content'] = true; + $useHeading['navigation'] = true; + } + } else { + $useHeading = array(); + } } - } - return (!empty($useHeading[$linktype])); + return (!empty($useHeading[$linktype])); } /** @@ -295,13 +300,13 @@ function useHeading($linktype) { * @return string the encoded value */ function conf_encodeString($str,$code) { - switch ($code) { - case 'base64' : return '<b>'.base64_encode($str); - case 'uuencode' : return '<u>'.convert_uuencode($str); - case 'plain': - default: - return $str; - } + switch ($code) { + case 'base64' : return '<b>'.base64_encode($str); + case 'uuencode' : return '<u>'.convert_uuencode($str); + case 'plain': + default: + return $str; + } } /** * return obscured data as plain text @@ -310,11 +315,11 @@ function conf_encodeString($str,$code) { * @return string plain text */ function conf_decodeString($str) { - switch (substr($str,0,3)) { - case '<b>' : return base64_decode(substr($str,3)); - case '<u>' : return convert_uudecode(substr($str,3)); - default: // not encode (or unknown) - return $str; - } + switch (substr($str,0,3)) { + case '<b>' : return base64_decode(substr($str,3)); + case '<u>' : return convert_uudecode(substr($str,3)); + default: // not encode (or unknown) + return $str; + } } -//Setup VIM: ex: et ts=2 enc=utf-8 : +//Setup VIM: ex: et ts=4 enc=utf-8 : diff --git a/inc/events.php b/inc/events.php index 1604c73c6..e6b608f20 100644 --- a/inc/events.php +++ b/inc/events.php @@ -11,190 +11,190 @@ require_once(DOKU_INC.'inc/pluginutils.php'); class Doku_Event { - // public properties - var $name = ''; // READONLY event name, objects must register against this name to see the event - var $data = NULL; // READWRITE data relevant to the event, no standardised format (YET!) - var $result = NULL; // READWRITE the results of the event action, only relevant in "_AFTER" advise - // event handlers may modify this if they are preventing the default action - // to provide the after event handlers with event results - var $canPreventDefault = true; // READONLY if true, event handlers can prevent the events default action - - // private properties, event handlers can effect these through the provided methods - var $_default = true; // whether or not to carry out the default action associated with the event - var $_continue = true; // whether or not to continue propagating the event to other handlers - - /** - * event constructor - */ - function Doku_Event($name, &$data) { - - $this->name = $name; - $this->data =& $data; - - } - - /** - * advise functions - * - * advise all registered handlers of this event - * - * if these methods are used by functions outside of this object, they must - * properly handle correct processing of any default action and issue an - * advise_after() signal. e.g. - * $evt = new Doku_Event(name, data); - * if ($evt->advise_before(canPreventDefault) { - * // default action code block - * } - * $evt->advise_after(); - * unset($evt); - * - * @return results of processing the event, usually $this->_default - */ - function advise_before($enablePreventDefault=true) { - global $EVENT_HANDLER; - - $this->canPreventDefault = $enablePreventDefault; - $EVENT_HANDLER->process_event($this,'BEFORE'); - - return (!$enablePreventDefault || $this->_default); - } - - function advise_after() { - global $EVENT_HANDLER; - - $this->_continue = true; - $EVENT_HANDLER->process_event($this,'AFTER'); - } - - /** - * trigger - * - * - advise all registered (<event>_BEFORE) handlers that this event is about to take place - * - carry out the default action using $this->data based on $enablePrevent and - * $this->_default, all of which may have been modified by the event handlers. - * - advise all registered (<event>_AFTER) handlers that the event has taken place - * - * @return $event->results - * the value set by any <event>_before or <event> handlers if the default action is prevented - * or the results of the default action (as modified by <event>_after handlers) - * or NULL no action took place and no handler modified the value - */ - function trigger($action=NULL, $enablePrevent=true) { - - if (!is_callable($action)) $enablePrevent = false; - - if ($this->advise_before($enablePrevent) && is_callable($action)) { - if (is_array($action)) { - list($obj,$method) = $action; - $this->result = $obj->$method($this->data); - } else { - $this->result = $action($this->data); - } + // public properties + var $name = ''; // READONLY event name, objects must register against this name to see the event + var $data = null; // READWRITE data relevant to the event, no standardised format (YET!) + var $result = null; // READWRITE the results of the event action, only relevant in "_AFTER" advise + // event handlers may modify this if they are preventing the default action + // to provide the after event handlers with event results + var $canPreventDefault = true; // READONLY if true, event handlers can prevent the events default action + + // private properties, event handlers can effect these through the provided methods + var $_default = true; // whether or not to carry out the default action associated with the event + var $_continue = true; // whether or not to continue propagating the event to other handlers + + /** + * event constructor + */ + function Doku_Event($name, &$data) { + + $this->name = $name; + $this->data =& $data; + + } + + /** + * advise functions + * + * advise all registered handlers of this event + * + * if these methods are used by functions outside of this object, they must + * properly handle correct processing of any default action and issue an + * advise_after() signal. e.g. + * $evt = new Doku_Event(name, data); + * if ($evt->advise_before(canPreventDefault) { + * // default action code block + * } + * $evt->advise_after(); + * unset($evt); + * + * @return results of processing the event, usually $this->_default + */ + function advise_before($enablePreventDefault=true) { + global $EVENT_HANDLER; + + $this->canPreventDefault = $enablePreventDefault; + $EVENT_HANDLER->process_event($this,'BEFORE'); + + return (!$enablePreventDefault || $this->_default); + } + + function advise_after() { + global $EVENT_HANDLER; + + $this->_continue = true; + $EVENT_HANDLER->process_event($this,'AFTER'); + } + + /** + * trigger + * + * - advise all registered (<event>_BEFORE) handlers that this event is about to take place + * - carry out the default action using $this->data based on $enablePrevent and + * $this->_default, all of which may have been modified by the event handlers. + * - advise all registered (<event>_AFTER) handlers that the event has taken place + * + * @return $event->results + * the value set by any <event>_before or <event> handlers if the default action is prevented + * or the results of the default action (as modified by <event>_after handlers) + * or NULL no action took place and no handler modified the value + */ + function trigger($action=null, $enablePrevent=true) { + + if (!is_callable($action)) $enablePrevent = false; + + if ($this->advise_before($enablePrevent) && is_callable($action)) { + if (is_array($action)) { + list($obj,$method) = $action; + $this->result = $obj->$method($this->data); + } else { + $this->result = $action($this->data); + } + } + + $this->advise_after(); + + return $this->result; } - $this->advise_after(); - - return $this->result; - } - - /** - * stopPropagation - * - * stop any further processing of the event by event handlers - * this function does not prevent the default action taking place - */ - function stopPropagation() { $this->_continue = false; } - - /** - * preventDefault - * - * prevent the default action taking place - */ - function preventDefault() { $this->_default = false; } + /** + * stopPropagation + * + * stop any further processing of the event by event handlers + * this function does not prevent the default action taking place + */ + function stopPropagation() { $this->_continue = false; } + + /** + * preventDefault + * + * prevent the default action taking place + */ + function preventDefault() { $this->_default = false; } } class Doku_Event_Handler { - // public properties: none + // public properties: none - // private properties - var $_hooks = array(); // array of events and their registered handlers + // private properties + var $_hooks = array(); // array of events and their registered handlers - /** - * event_handler - * - * constructor, loads all action plugins and calls their register() method giving them - * an opportunity to register any hooks they require - */ - function Doku_Event_Handler() { + /** + * event_handler + * + * constructor, loads all action plugins and calls their register() method giving them + * an opportunity to register any hooks they require + */ + function Doku_Event_Handler() { - // load action plugins - $plugin = NULL; - $pluginlist = plugin_list('action'); + // load action plugins + $plugin = null; + $pluginlist = plugin_list('action'); - foreach ($pluginlist as $plugin_name) { - $plugin =& plugin_load('action',$plugin_name); + foreach ($pluginlist as $plugin_name) { + $plugin =& plugin_load('action',$plugin_name); - if ($plugin !== NULL) $plugin->register($this); - } - } - - /** - * register_hook - * - * register a hook for an event - * - * @PARAM $event (string) name used by the event, (incl '_before' or '_after' for triggers) - * @PARAM $obj (obj) object in whose scope method is to be executed, - * if NULL, method is assumed to be a globally available function - * @PARAM $method (function) event handler function - * @PARAM $param (mixed) data passed to the event handler - */ - function register_hook($event, $advise, &$obj, $method, $param=NULL) { - $this->_hooks[$event.'_'.$advise][] = array(&$obj, $method, $param); - } - - function process_event(&$event,$advise='') { - - $evt_name = $event->name . ($advise ? '_'.$advise : '_BEFORE'); - - if (!empty($this->_hooks[$evt_name])) { - $hook = reset($this->_hooks[$evt_name]); - do { -// list($obj, $method, $param) = $hook; - $obj =& $hook[0]; - $method = $hook[1]; - $param = $hook[2]; - - if (is_null($obj)) { - $method($event, $param); - } else { - $obj->$method($event, $param); + if ($plugin !== null) $plugin->register($this); } + } + + /** + * register_hook + * + * register a hook for an event + * + * @param $event (string) name used by the event, (incl '_before' or '_after' for triggers) + * @param $obj (obj) object in whose scope method is to be executed, + * if NULL, method is assumed to be a globally available function + * @param $method (function) event handler function + * @param $param (mixed) data passed to the event handler + */ + function register_hook($event, $advise, &$obj, $method, $param=null) { + $this->_hooks[$event.'_'.$advise][] = array(&$obj, $method, $param); + } - } while ($event->_continue && $hook = next($this->_hooks[$evt_name])); + function process_event(&$event,$advise='') { + + $evt_name = $event->name . ($advise ? '_'.$advise : '_BEFORE'); + + if (!empty($this->_hooks[$evt_name])) { + $hook = reset($this->_hooks[$evt_name]); + do { + // list($obj, $method, $param) = $hook; + $obj =& $hook[0]; + $method = $hook[1]; + $param = $hook[2]; + + if (is_null($obj)) { + $method($event, $param); + } else { + $obj->$method($event, $param); + } + + } while ($event->_continue && $hook = next($this->_hooks[$evt_name])); + } } - } } /** - * trigger_event + * trigger_event * - * function wrapper to process (create, trigger and destroy) an event + * function wrapper to process (create, trigger and destroy) an event * - * @PARAM $name (string) name for the event - * @PARAM $data (mixed) event data - * @PARAM $action (callback) (optional, default=NULL) default action, a php callback function - * @PARAM $canPreventDefault (bool) (optional, default=true) can hooks prevent the default action + * @param $name (string) name for the event + * @param $data (mixed) event data + * @param $action (callback) (optional, default=NULL) default action, a php callback function + * @param $canPreventDefault (bool) (optional, default=true) can hooks prevent the default action * - * @RETURN (mixed) the event results value after all event processing is complete + * @return (mixed) the event results value after all event processing is complete * by default this is the return value of the default action however * it can be set or modified by event handler hooks */ -function trigger_event($name, &$data, $action=NULL, $canPreventDefault=true) { +function trigger_event($name, &$data, $action=null, $canPreventDefault=true) { - $evt = new Doku_Event($name, $data); - return $evt->trigger($action, $canPreventDefault); + $evt = new Doku_Event($name, $data); + return $evt->trigger($action, $canPreventDefault); } // create the event handler diff --git a/inc/form.php b/inc/form.php index a514526b7..6d496f414 100644 --- a/inc/form.php +++ b/inc/form.php @@ -859,7 +859,9 @@ function form_menufield($attrs) { $s .= ' <select '.buildAttributes($attrs,true).'>'.DOKU_LF; if (!empty($attrs['_options'])) { $selected = false; - for($n=0;$n<count($attrs['_options']);$n++){ + + $cnt = count($attrs['_options']); + for($n=0; $n < $cnt; $n++){ @list($value,$text,$select) = $attrs['_options'][$n]; $p = ''; if (!is_null($text)) diff --git a/inc/fulltext.php b/inc/fulltext.php index c8236e1d4..94c68d675 100644 --- a/inc/fulltext.php +++ b/inc/fulltext.php @@ -20,10 +20,10 @@ require_once(DOKU_INC.'inc/indexer.php'); */ function ft_pageSearch($query,&$highlight){ - $data['query'] = $query; - $data['highlight'] =& $highlight; + $data['query'] = $query; + $data['highlight'] =& $highlight; - return trigger_event('SEARCH_QUERY_FULLPAGE', $data, '_ft_pageSearch'); + return trigger_event('SEARCH_QUERY_FULLPAGE', $data, '_ft_pageSearch'); } /** @@ -189,7 +189,7 @@ function ft_mediause($id,$max){ foreach($matches[1] as $img){ $img = trim($img); if(preg_match('/^https?:\/\//i',$img)) continue; // skip external images - list($img) = explode('?',$img); // remove any parameters + list($img) = explode('?',$img); // remove any parameters resolve_mediaid($ns,$img,$exists); // resolve the possibly relative img if($img == $id){ // we have a match @@ -286,11 +286,11 @@ function ft_pagesorter($a, $b){ function ft_snippet($id,$highlight){ $text = rawWiki($id); $evdata = array( - 'id' => $id, - 'text' => &$text, - 'highlight' => &$highlight, - 'snippet' => '', - ); + 'id' => $id, + 'text' => &$text, + 'highlight' => &$highlight, + 'snippet' => '', + ); $evt = new Doku_Event('FULLTEXT_SNIPPET_CREATE',$evdata); if ($evt->advise_before()) { @@ -305,60 +305,60 @@ function ft_snippet($id,$highlight){ $re3 = "$re1.{0,45}(?!\\1)$re1.{0,45}(?!\\1)(?!\\2)$re1"; for ($cnt=4; $cnt--;) { - if (0) { - } else if (preg_match('/'.$re3.'/iu',$text,$match,PREG_OFFSET_CAPTURE,$offset)) { - } else if (preg_match('/'.$re2.'/iu',$text,$match,PREG_OFFSET_CAPTURE,$offset)) { - } else if (preg_match('/'.$re1.'/iu',$text,$match,PREG_OFFSET_CAPTURE,$offset)) { - } else { - break; - } - - list($str,$idx) = $match[0]; - - // convert $idx (a byte offset) into a utf8 character offset - $utf8_idx = utf8_strlen(substr($text,0,$idx)); - $utf8_len = utf8_strlen($str); - - // establish context, 100 bytes surrounding the match string - // first look to see if we can go 100 either side, - // then drop to 50 adding any excess if the other side can't go to 50, - $pre = min($utf8_idx-$utf8_offset,100); - $post = min($len-$utf8_idx-$utf8_len,100); - - if ($pre>50 && $post>50) { - $pre = $post = 50; - } else if ($pre>50) { - $pre = min($pre,100-$post); - } else if ($post>50) { - $post = min($post, 100-$pre); - } else { - // both are less than 50, means the context is the whole string - // make it so and break out of this loop - there is no need for the - // complex snippet calculations - $snippets = array($text); - break; - } - - // establish context start and end points, try to append to previous - // context if possible - $start = $utf8_idx - $pre; - $append = ($start < $end) ? $end : false; // still the end of the previous context snippet - $end = $utf8_idx + $utf8_len + $post; // now set it to the end of this context - - if ($append) { - $snippets[count($snippets)-1] .= utf8_substr($text,$append,$end-$append); - } else { - $snippets[] = utf8_substr($text,$start,$end-$start); - } - - // set $offset for next match attempt - // substract strlen to avoid splitting a potential search success, - // this is an approximation as the search pattern may match strings - // of varying length and it will fail if the context snippet - // boundary breaks a matching string longer than the current match - $utf8_offset = $utf8_idx + $post; - $offset = $idx + strlen(utf8_substr($text,$utf8_idx,$post)); - $offset = utf8_correctIdx($text,$offset); + if (0) { + } else if (preg_match('/'.$re3.'/iu',$text,$match,PREG_OFFSET_CAPTURE,$offset)) { + } else if (preg_match('/'.$re2.'/iu',$text,$match,PREG_OFFSET_CAPTURE,$offset)) { + } else if (preg_match('/'.$re1.'/iu',$text,$match,PREG_OFFSET_CAPTURE,$offset)) { + } else { + break; + } + + list($str,$idx) = $match[0]; + + // convert $idx (a byte offset) into a utf8 character offset + $utf8_idx = utf8_strlen(substr($text,0,$idx)); + $utf8_len = utf8_strlen($str); + + // establish context, 100 bytes surrounding the match string + // first look to see if we can go 100 either side, + // then drop to 50 adding any excess if the other side can't go to 50, + $pre = min($utf8_idx-$utf8_offset,100); + $post = min($len-$utf8_idx-$utf8_len,100); + + if ($pre>50 && $post>50) { + $pre = $post = 50; + } else if ($pre>50) { + $pre = min($pre,100-$post); + } else if ($post>50) { + $post = min($post, 100-$pre); + } else { + // both are less than 50, means the context is the whole string + // make it so and break out of this loop - there is no need for the + // complex snippet calculations + $snippets = array($text); + break; + } + + // establish context start and end points, try to append to previous + // context if possible + $start = $utf8_idx - $pre; + $append = ($start < $end) ? $end : false; // still the end of the previous context snippet + $end = $utf8_idx + $utf8_len + $post; // now set it to the end of this context + + if ($append) { + $snippets[count($snippets)-1] .= utf8_substr($text,$append,$end-$append); + } else { + $snippets[] = utf8_substr($text,$start,$end-$start); + } + + // set $offset for next match attempt + // substract strlen to avoid splitting a potential search success, + // this is an approximation as the search pattern may match strings + // of varying length and it will fail if the context snippet + // boundary breaks a matching string longer than the current match + $utf8_offset = $utf8_idx + $post; + $offset = $idx + strlen(utf8_substr($text,$utf8_idx,$post)); + $offset = utf8_correctIdx($text,$offset); } $m = "\1"; @@ -391,16 +391,16 @@ function ft_resultCombine($args){ $result = array(); if ($array_count > 1) { - foreach ($args[0] as $key => $value) { - $result[$key] = $value; - for ($i = 1; $i !== $array_count; $i++) { - if (!isset($args[$i][$key])) { - unset($result[$key]); - break; + foreach ($args[0] as $key => $value) { + $result[$key] = $value; + for ($i = 1; $i !== $array_count; $i++) { + if (!isset($args[$i][$key])) { + unset($result[$key]); + break; + } + $result[$key] += $args[$i][$key]; } - $result[$key] += $args[$i][$key]; } - } } return $result; } @@ -651,30 +651,30 @@ function ft_queryParser($query){ switch (substr($token, 0, 3)) { case 'N+:': - $q['ns'][] = $body; // for backward compatibility - break; + $q['ns'][] = $body; // for backward compatibility + break; case 'N-:': - $q['notns'][] = $body; // for backward compatibility - break; + $q['notns'][] = $body; // for backward compatibility + break; case 'W_:': - $q['words'][] = $body; - break; + $q['words'][] = $body; + break; case 'W-:': - $q['words'][] = $body; - $q['not'][] = $body; // for backward compatibility - break; + $q['words'][] = $body; + $q['not'][] = $body; // for backward compatibility + break; case 'W+:': - $q['words'][] = $body; - $q['highlight'][] = str_replace('*', '', $body); - $q['and'][] = $body; // for backward compatibility - break; + $q['words'][] = $body; + $q['highlight'][] = str_replace('*', '', $body); + $q['and'][] = $body; // for backward compatibility + break; case 'P-:': - $q['phrases'][] = $body; - break; + $q['phrases'][] = $body; + break; case 'P+:': - $q['phrases'][] = $body; - $q['highlight'][] = str_replace('*', '', $body); - break; + $q['phrases'][] = $body; + $q['highlight'][] = str_replace('*', '', $body); + break; } } foreach (array('words', 'phrases', 'highlight', 'ns', 'notns', 'and', 'not') as $key) { diff --git a/install.php b/install.php index 414d3e99e..a9edbd445 100644 --- a/install.php +++ b/install.php @@ -202,16 +202,16 @@ function print_form($d){ } function print_retry() { - global $lang; - global $LC; -?> + global $lang; + global $LC; + ?> <form action="" method="get"> <fieldset> <input type="hidden" name="l" value="<?php echo $LC ?>" /> <input class="button" type="submit" value="<?php echo $lang['i_retry'];?>" /> </fieldset> </form> -<?php + <?php } /** @@ -360,7 +360,6 @@ function check_configs(){ 'auth' => DOKU_LOCAL.'acl.auth.php' ); - // main dokuwiki config file (conf/dokuwiki.php) must not have been modified $installation_hash = md5(preg_replace("/(\015\012)|(\015)/","\012", @file_get_contents(DOKU_CONF.'dokuwiki.php'))); @@ -437,8 +436,8 @@ function check_functions(){ 'preg_replace file_get_contents htmlspecialchars_decode'); if (!function_exists('mb_substr')) { - $funcs[] = 'utf8_encode'; - $funcs[] = 'utf8_decode'; + $funcs[] = 'utf8_encode'; + $funcs[] = 'utf8_decode'; } foreach($funcs as $func){ @@ -505,12 +504,12 @@ function print_errors(){ * @author Andreas Gohr <andi@splitbrain.org> */ function remove_magic_quotes(&$array) { - foreach (array_keys($array) as $key) { - if (is_array($array[$key])) { - remove_magic_quotes($array[$key]); - }else { - $array[$key] = stripslashes($array[$key]); + foreach (array_keys($array) as $key) { + if (is_array($array[$key])) { + remove_magic_quotes($array[$key]); + }else { + $array[$key] = stripslashes($array[$key]); + } } - } } -- GitLab