Changeset 746

Show
Ignore:
Timestamp:
10/11/2007 03:08:48 AM (3 years ago)
Author:
JavaWoman
Message:

New & updated functions

  • makeID (new)
  • FormOpen (advanced version)
  • existsPage (update: name change for consistency)
  • existsHandler (new)

Note: existsHandler and existsPage are moved to a new section for such "sanity checks".

refs #562

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • branches/1.1.6.4/libs/Wakka.class.php

    r745 r746  
    22/** 
    33 * This file is part of Wikka, a PHP wiki engine. 
    4  *  
     4 * 
    55 * It includes the Wakka class, which provides the core functions 
    6  * to run Wikka.  
     6 * to run Wikka. 
    77 * 
    88 * @package Wikka 
     
    1111 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 
    1212 * @filesource 
    13  *  
     13 * 
    1414 * @author Hendrik Mans <hendrik@mans.de> 
    1515 * @author Jason Tourtelotte <wikka-admin@jsnx.com> 
     
    1818 * @author {@link http://wikkawiki.org/DotMG Mahefa Randimbisoa} 
    1919 * @author {@link http://wikkawiki.org/DarTar Dario Taraborelli} 
    20  *  
     20 * 
    2121 * @copyright Copyright 2002-2003, Hendrik Mans <hendrik@mans.de> 
    2222 * @copyright Copyright 2004-2005, Jason Tourtelotte <wikka-admin@jsnx.com> 
    23  * @copyright Copyright 2006, {@link http://wikkawiki.org/CreditsPage Wikka Development Team} 
     23 * @copyright Copyright 2006-2007 {@link http://wikkawiki.org/CreditsPage Wikka Development Team} 
    2424 */ 
    25   
     25 
    2626/** 
    2727 * The Wikka core. 
    28  *  
     28 * 
    2929 * This class contains all the core methods used to run Wikka. 
    3030 * @name Wakka 
    3131 * @package Wikka 
    3232 * @subpackage Libs 
    33  *  
     33 * 
    3434 */ 
    3535class Wakka 
     
    101101         * @author              {@link http://wikkawiki.org/JavaWoman JavaWoman} 
    102102         * @license             http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 
     103         * @since               Wikka 1.1.6.4 
    103104         * @version             1.1 
    104105         * 
     
    167168        function IncludeBuffered($filename, $notfoundText='', $vars='', $path='') 
    168169        { 
    169                 # TODO: change parameter order, so $path (no default,. it's required)  
    170                 # comes after $filename and only $notfoundtext and $vars will actually  
    171                 # be optional with a default of ''. MK/2007-03-31     
     170                # TODO: change parameter order, so $path (no default,. it's required) 
     171                # comes after $filename and only $notfoundtext and $vars will actually 
     172                # be optional with a default of ''. MK/2007-03-31 
    172173 
    173174                // check if required parameter $path is supplied (see TODO) 
    174175                if ('' != trim($path)) 
    175                 {  
     176                { 
    176177                        // build full (relative) path to requested plugin (method/action/formatter) 
    177178                        $fullfilepath = trim($path).DIRECTORY_SEPARATOR.$filename;      #89 - Note $filename may actually already contain a (partial) path 
     
    203204        } 
    204205 
     206        /** 
     207         * Create a unique id for an HTML element. 
     208         * 
     209         * Although - given Wikka accepts can use embedded HTML - it cannot be 
     210         * guaranteed that an id generated by this method is unique it tries its 
     211         * best to make it unique: 
     212         * - ids are organized into groups, with the group name used as a prefix 
     213         * - if an id is specified it is compared with other ids in the same group; 
     214         *   if an identical id exists within the same group, a sequence suffix is 
     215         *   added, otherwise the specified id is accepted and recorded as a member 
     216         *   of the group 
     217         * - if no id is specified (or an invalid one) an id will be generated, and 
     218         *   given a sequence suffix if needed 
     219         * 
     220         * For headings, it is possible to derive an id from the heading content; 
     221         * to support this, any embedded whitespace is replaced with underscores 
     222         * to generate a recognizable id that will remain (mostly) constant even if 
     223         * new headings are inserted in a page. (This is not done for embedded 
     224         * HTML.) 
     225         * 
     226         * The method supports embedded HTML as well: as long as the formatter 
     227         * passes each id found in embedded HTML through this method it can take 
     228         * care that the id is valid and unique. 
     229         * This works as follows: 
     230         * - indicate an 'embedded' id with group 'embed' 
     231         * - NO prefix will be added for this reserved group 
     232         * - ids will be recorded and checked for uniqueness and validity 
     233         * - invalid ids are replaced 
     234         * - already-existing ids in the group are given a sequence suffix 
     235         * The result is that as long as the already-defined id is valid and 
     236         * unique, it will be remain unchanged (but recorded to ensure uniqueness 
     237         * overall). 
     238         * 
     239         * @author              {@link http://wikka.jsnx.com/JavaWoman JavaWoman} 
     240         * @copyright   Copyright © 2005, Marjolein Katsma 
     241         * @license             http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 
     242         * @since               Wikka 1.1.6.4 
     243         * @version             1.0 
     244         * 
     245         * @access      public 
     246         * @uses        ID_LENGTH 
     247         * 
     248         * @param       string  $group  required: id group (e.g. form, head); will be 
     249         *                                                      used as prefix (except for the reserved group 
     250         *                                                      'embed' to be used for embedded HTML only) 
     251         * @param       string  $id             optional: id to use; if not specified or 
     252         *                                                      invalid, an id will be generated; if not 
     253         *                                                      unique, a sequence number will be appended 
     254         * @return      string  resulting id 
     255         */ 
     256        function makeId($group,$id='') 
     257        { 
     258                // initializations 
     259                static $aSeq = array();                                                                         # group sequences 
     260                static $aIds = array();                                                                         # used ids 
     261 
     262                // preparation for group 
     263                if (!preg_match('/^[A-Z-a-z]/',$group))                                         # make sure group starts with a letter 
     264                { 
     265                        $group = 'g'.$group; 
     266                } 
     267                if (!isset($aSeq[$group])) 
     268                { 
     269                        $aSeq[$group] = 0; 
     270                } 
     271                if (!isset($aIds[$group])) 
     272                { 
     273                        $aIds[$group] = array(); 
     274                } 
     275                if ('embed' != $group) 
     276                { 
     277                        $id = preg_replace('/\s+/','_',trim($id));                              # replace any whitespace sequence in $id with a single underscore 
     278                } 
     279 
     280                // validation (full for 'embed', characters only for other groups since we'll add a prefix) 
     281                if ('embed' == $group) 
     282                { 
     283                        $validId = preg_match('/^[A-Za-z][A-Za-z0-9_:.-]*$/',$id);      # ref: http://www.w3.org/TR/html4/types.html#type-id 
     284                } 
     285                else 
     286                { 
     287                        $validId = preg_match('/^[A-Za-z0-9_:.-]*$/',$id); 
     288                } 
     289 
     290                // build or generate id 
     291                if ('' == $id || !$validId || in_array($id,$aIds))                      # ignore specified id if it is invalid or exists already 
     292                { 
     293                        $id = substr(md5($group.$id),0,ID_LENGTH);                              # use group and id as basis for generated id 
     294                } 
     295                $idOut = ('embed' == $group) ? $id : $group.'_'.$id;            # add group prefix (unless embedded HTML) 
     296                if (in_array($id,$aIds[$group])) 
     297                { 
     298                        $idOut .= '_'.++$aSeq[$group];                                                  # add suffiX to make ID unique 
     299                } 
     300 
     301                // result 
     302                $aIds[$group][] = $id;                                                                          # keep track of both specified and generated ids (without suffix) 
     303                return $idOut; 
     304        } 
     305 
     306        /** 
     307         * Strip potentially dangerous tags from embedded HTML. 
     308         * 
     309         * @param       string $html mandatory: HTML to be secured 
     310         * @return      string sanitized HTML 
     311         */ 
    205312        function ReturnSafeHTML($html) 
    206313        { 
     
    219326         * 
    220327#        * Any already-present '&amp;' is first turned into '&'; then htmlspecialchars() is applied so 
    221          * Any already-present '&amp;' is first turned into '&'; then hsc_secure()  
    222          * is applied so all ampersands are "escaped" while characters that could be  
    223          * used to create a script attack (< > or ") are "neutralized" by escaping  
     328         * Any already-present '&amp;' is first turned into '&'; then hsc_secure() 
     329         * is applied so all ampersands are "escaped" while characters that could be 
     330         * used to create a script attack (< > or ") are "neutralized" by escaping 
    224331         * them. 
    225332         * 
    226          * This method should be applied on any user-provided url in actions,  
     333         * This method should be applied on any user-provided url in actions, 
    227334         * handlers etc. 
    228          *  
     335         * 
    229336         * Note: hsc_secure() is the secure replacement for PHP's htmlspecialchars(). 
    230          * See #427.  
     337         * See #427. 
    231338         * 
    232339         * @author              {@link http://wikkawiki.org/JavaWoman JavaWoman} 
     
    249356         * Wrapper around hsc_secure() which preserves entity references. 
    250357         * 
    251          * The first two parameters for this function as the same as those for  
     358         * The first two parameters for this function as the same as those for 
    252359         * htmlspecialchars() in PHP: the text to be treated, and an optional 
    253          * parameter determining how to handle quotes; both these parameters are  
     360         * parameter determining how to handle quotes; both these parameters are 
    254361         * passed on to our hsc_secure() replacement for htmlspecialchars(). 
    255          *  
     362         * 
    256363         * Since hsc_secure() does not need a character set parameter, we don't 
    257364         * have that here any more either. 
    258          *  
    259          * A third 'doctype' parameter is for local use only and determines how  
    260          * pre-existing entity references are treated after hsc_secure() has done  
     365         * 
     366         * A third 'doctype' parameter is for local use only and determines how 
     367         * pre-existing entity references are treated after hsc_secure() has done 
    261368         * its work: numeic entity references are always "unescaped' since they are 
    262369         * valid for both HTML and XML doctypes; for XML the named entity references 
    263370         * for the special characters are unescaped as well, while for for HTML any 
    264          * named entity reference is unescaped. This parameter is optional and  
    265          * defaults to HTML.    
    266          * 
    267          * The function first applies hsc_secure() to the input string and then  
    268          * "unescapes" character entity references and numeric character references  
     371         * named entity reference is unescaped. This parameter is optional and 
     372         * defaults to HTML. 
     373         * 
     374         * The function first applies hsc_secure() to the input string and then 
     375         * "unescapes" character entity references and numeric character references 
    269376         * (both decimal and hexadecimal). 
    270          * Entities are recognized also if the ending semicolon is omitted at the  
    271          * end or before a newline or tag but for consistency the semicolon is  
     377         * Entities are recognized also if the ending semicolon is omitted at the 
     378         * end or before a newline or tag but for consistency the semicolon is 
    272379         * always added in the output where it was omitted. 
    273380         * 
    274381         * Usage note: 
    275          * Where code should be rendered <em>as code</em> hsc_secure() should be  
    276          * used directly so that entity references are also rendered as such instead  
     382         * Where code should be rendered <em>as code</em> hsc_secure() should be 
     383         * used directly so that entity references are also rendered as such instead 
    277384         * of as their corresponding characters. 
    278          *  
     385         * 
    279386         * Documentation note: 
    280          * It seems the $doctype parameter was added in 1.1.6.2; version should have  
     387         * It seems the $doctype parameter was added in 1.1.6.2; version should have 
    281388         * been bumped up to 1.1, and the param documented. We'll assume the updated 
    282          * version was indeed 1.1, and put this one using hsc_secure() at 1.2 (at  
     389         * version was indeed 1.1, and put this one using hsc_secure() at 1.2 (at 
    283390         * the same time updating the 'XML' doctype with apos as named entity). 
    284391         * 
     
    289396         * @uses        Wakka::hsc_secure() 
    290397         * @param       string  $text required: text to be converted 
    291          * @param       integer $quote_style optional: quoting style - can be ENT_COMPAT  
    292          *                      (default, escape only double quotes), ENT_QUOTES (escape both  
    293          *                      double and single quotes) or ENT_NOQUOTES (don't escape any  
     398         * @param       integer $quote_style optional: quoting style - can be ENT_COMPAT 
     399         *                      (default, escape only double quotes), ENT_QUOTES (escape both 
     400         *                      double and single quotes) or ENT_NOQUOTES (don't escape any 
    294401         *                      quotes) 
    295402         * @param       string $doctype 'HTML' (default) or 'XML'; for XML only the XML 
    296403         *                      standard entities are unescaped so we'll have valid XML content 
    297          * @return      string  converted string with escaped special characted but  
     404         * @return      string  converted string with escaped special characted but 
    298405         *                      entity references intact 
    299          *  
    300          * @todo        (maybe) recognize valid html entities and only leave those  
     406         * 
     407         * @todo        (maybe) recognize valid html entities and only leave those 
    301408         *                      alone, thus transform &error; to &amp;error; 
    302          * @todo        later - maybe) support full range of situations where (in SGML)  
    303          *                      a terminating ; may legally be omitted (end, newline and tag are  
    304          *                      merely the most common ones); such usage is quite rare though  
     409         * @todo        later - maybe) support full range of situations where (in SGML) 
     410         *                      a terminating ; may legally be omitted (end, newline and tag are 
     411         *                      merely the most common ones); such usage is quite rare though 
    305412         *                      and may not be worth the effort 
    306413         */ 
     
    309416                // re-establish default if overwritten because of third parameter 
    310417                // [ENT_COMPAT] => 2 
    311             // [ENT_QUOTES] => 3 
    312             // [ENT_NOQUOTES] => 0 
     418                // [ENT_QUOTES] => 3 
     419                // [ENT_NOQUOTES] => 0 
    313420                if (!in_array($quote_style,array(ENT_COMPAT,ENT_QUOTES,ENT_NOQUOTES))) { 
    314                         $quote_style = ENT_COMPAT;       
    315                 } 
    316                  
     421                        $quote_style = ENT_COMPAT; 
     422                } 
     423 
    317424                // define patterns 
    318425                $terminator = ';|(?=($|[\n<]|&lt;))';   // semicolon; or end-of-string, newline or tag 
     
    322429                { 
    323430                        // only valid named entities in XML (case-sensitive) 
    324                         $named = 'lt|gt|quot|apos|amp';                  
     431                        $named = 'lt|gt|quot|apos|amp'; 
    325432                        $ignore_case = ''; 
    326433                        $entitystring = $named.'|'.$numdec.'|'.$numhex; 
     
    347454        /** 
    348455         * Secure replacement for PHP built-in function htmlspecialchars(). 
    349          *  
    350          * See ticket #427 (http://wush.net/trac/wikka/ticket/427) for the rationale  
     456         * 
     457         * See ticket #427 (http://wush.net/trac/wikka/ticket/427) for the rationale 
    351458         * for this replacement function. 
    352          *  
     459         * 
    353460         * The INTERFACE for this function is almost the same as that for 
    354461         * htmlspecialchars(), with the same default for quote style; however, there 
    355462         * is no 'charset' parameter. The reason for this is as follows: 
    356          *  
     463         * 
    357464         * The PHP docs say: 
    358465         *      "The third argument charset defines character set used in conversion." 
    359          *  
     466         * 
    360467         * I suspect PHP's htmlspecialchars() is working at the byte-value level and 
    361          * thus _needs_ to know (or asssume) a character set because the special  
     468         * thus _needs_ to know (or asssume) a character set because the special 
    362469         * characters to be replaced could exist at different code points in 
    363          * different character sets. (If indeed htmlspecialchars() works at  
    364          * byte-value level that goes some  way towards explaining why the  
    365          * vulnerability would exist in this function, too, and not only in  
     470         * different character sets. (If indeed htmlspecialchars() works at 
     471         * byte-value level that goes some  way towards explaining why the 
     472         * vulnerability would exist in this function, too, and not only in 
    366473         * htmlentities() which certainly is working at byte-value level.) 
    367          *  
     474         * 
    368475         * This replacement function however works at character level and should 
    369          * therefore be "immune" to character set differences - so no charset  
     476         * therefore be "immune" to character set differences - so no charset 
    370477         * parameter is needed or provided. If a third parameter is passed, it will 
    371478         * be silently ignored. 
    372          *  
     479         * 
    373480         * In the OUTPUT there is a minor difference in that we use '&#39;' instead 
    374481         * of PHP's '&#039;' for a single quote: this provides compatibility with 
    375482         *      get_html_translation_table(HTML_SPECIALCHARS, ENT_QUOTES) 
    376          * (see comment by mikiwoz at yahoo dot co dot uk on  
    377          * http://php.net/htmlspecialchars); it also matches the entity definition  
    378          * for XML 1.0  
    379          * (http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters).  
    380          * Like PHP we use a numeric character reference instead of '&apos;' for the  
    381          * single quote. For the other special characters we use the named entity  
     483         * (see comment by mikiwoz at yahoo dot co dot uk on 
     484         * http://php.net/htmlspecialchars); it also matches the entity definition 
     485         * for XML 1.0 
     486         * (http://www.w3.org/TR/xhtml1/dtds.html#a_dtd_Special_characters). 
     487         * Like PHP we use a numeric character reference instead of '&apos;' for the 
     488         * single quote. For the other special characters we use the named entity 
    382489         * references, as PHP is doing. 
    383          *  
     490         * 
    384491         * And finally: 
    385          * The name for this function was basically inspired by waawaamilk (GeSHi),  
    386          * kindly provided by BenBE (GeSHi), happily acknowledged by WikkaWiki Dev  
     492         * The name for this function was basically inspired by waawaamilk (GeSHi), 
     493         * kindly provided by BenBE (GeSHi), happily acknowledged by WikkaWiki Dev 
    387494         * Team and finally used by JavaWoman. :) 
    388          *  
     495         * 
    389496         * @author              {@link http://wikkawiki.org/JavaWoman Marjolein Katsma} 
    390497         * 
    391498         * @since               Wikka 1.1.7 
    392499         * @version             1.0 
    393          * @license             http://www.gnu.org/copyleft/lgpl.html  
     500         * @license             http://www.gnu.org/copyleft/lgpl.html 
    394501         *                              GNU Lesser General Public License 
    395          * @copyright   Copyright 2007, {@link http://wikkawiki.org/CreditsPage  
     502         * @copyright   Copyright 2007, {@link http://wikkawiki.org/CreditsPage 
    396503         *                              Wikka Development Team} 
    397          *  
     504         * 
    398505         * @access      public 
    399506         * @param       string  $string string to be converted 
    400          * @param       integer $quote_style  
     507         * @param       integer $quote_style 
    401508         *                      - ENT_COMPAT:   escapes &, <, > and double quote (default) 
    402509         *                      - ENT_NOQUOTES: escapes only &, < and > 
    403510         *                      - ENT_QUOTES:   escapes &, <, >, double and single quotes 
    404          * @return      string  converted string    
     511         * @return      string  converted string 
    405512         */ 
    406513         function hsc_secure($string, $quote_style=ENT_COMPAT) 
    407514         { 
    408                 // init 
    409                 $aTransSpecchar = array('&' => '&amp;', 
    410                                                                 '"' => '&quot;', 
    411                                                                 '<' => '&lt;', 
     515                // init 
     516                $aTransSpecchar = array('&' => '&amp;', 
     517                                                                '"' => '&quot;', 
     518                                                                '<' => '&lt;', 
    412519                                                                '>' => '&gt;' 
    413520                                                                );                      // ENT_COMPAT set 
     
    535642                // parse and return highlighted code 
    536643                // comments added to make GeSHi-highlighted block visible in code JW/20070220 
    537                 return '<!--start GeSHi-->'."\n".$geshi->parse_code()."\n".'<!--end GeSHi-->'."\n";      
     644                return '<!--start GeSHi-->'."\n".$geshi->parse_code()."\n".'<!--end GeSHi-->'."\n"; 
    538645        } 
    539646 
     
    666773                        $this->Query("insert into ".$this->config["table_prefix"]."pages set ". 
    667774                                "tag = '".mysql_real_escape_string($tag)."', ". 
    668                                 "time = now(), ". 
    669                                 "owner = '".mysql_real_escape_string($owner)."', ". 
    670                                 "user = '".mysql_real_escape_string($user)."', ". 
     775                                "time = now(), ". 
     776                                "owner = '".mysql_real_escape_string($owner)."', ". 
     777                                "user = '".mysql_real_escape_string($user)."', ". 
    671778                                "note = '".mysql_real_escape_string($note)."', ". 
    672                                 "latest = 'Y', ". 
    673                                 "body = '".mysql_real_escape_string($body)."'"); 
     779                                "latest = 'Y', ". 
     780                                "body = '".mysql_real_escape_string($body)."'"); 
    674781 
    675782                        if ($pingdata = $this->GetPingParams($this->config["wikiping_server"], $tag, $user, $note)) 
     
    686793                if ($title) return strip_tags($this->Format($title));                           # fix for forced links in heading 
    687794                else return $this->GetPageTag(); 
    688         } 
    689         /** 
    690          * Check by name if a page exists. 
    691          * 
    692          * @author              {@link http://wikkawiki.org/JavaWoman JavaWoman} 
    693          * @copyright   Copyright © 2004, Marjolein Katsma 
    694          * @license             http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 
    695          * @version             1.0 
    696          * 
    697          * @access              public 
    698          * @uses                Query() 
    699          * 
    700          * @param               string  $page  page name to check 
    701          * @return              boolean  TRUE if page exists, FALSE otherwise 
    702          */ 
    703         function ExistsPage($page) 
    704         { 
    705                 $count = 0; 
    706                 $query =        "SELECT COUNT(tag) 
    707                                         FROM ".$this->config['table_prefix']."pages 
    708                                         WHERE tag='".mysql_real_escape_string($page)."'"; 
    709                 if ($r = $this->Query($query)) 
    710                 { 
    711                         $count = mysql_result($r,0); 
    712                         mysql_free_result($r); 
    713                 } 
    714                 return ($count > 0) ? TRUE : FALSE; 
    715795        } 
    716796 
     
    784864                        if ($tag) $ping["tag"] = $tag; else return false; // set page-title 
    785865                        if (!$ping["taglink"] = $this->Href("", $tag)) return false; // set page-url 
    786                 if (!$ping["wiki"] = $this->config["wakka_name"]) return false; // set site-name 
     866                                if (!$ping["wiki"] = $this->config["wakka_name"]) return false; // set site-name 
    787867                        $ping["history"] = $this->Href("revisions", $tag); // set url to history 
    788868 
     
    839919'<meta http-equiv="refresh" content="0; url=\''.$url.'\'" /></head><body><div><script type="text/javascript">window.location.href="'.$url.'";</script>'. 
    840920'</div><noscript>If your browser does not redirect you, please follow <a href="'.$this->Href($url).'">this link</a></noscript></body></html>'); 
    841                 }  
    842                 else  
     921                } 
     922                else 
    843923                { 
    844924                        header("Location: ".$url); 
     
    859939        } 
    860940        /** 
    861          * Link  
    862          *  
    863          * Beware of the $title parameter: quotes and backslashes should be previously escaped before passed to  
     941         * Link 
     942         * 
     943         * Beware of the $title parameter: quotes and backslashes should be previously escaped before passed to 
    864944         * this method. 
    865945         * 
    866          * @param mixed $tag  
    867          * @param string $method  
    868          * @param string $text  
    869          * @param boolean $track  
    870          * @param boolean $escapeText  
    871          * @param string $title  
     946         * @param mixed $tag 
     947         * @param string $method 
     948         * @param string $text 
     949         * @param boolean $track 
     950         * @param boolean $escapeText 
     951         * @param string $title 
    872952         * @access public 
    873953         * @return string 
     
    9481028 
    9491029        // FORMS 
     1030        /** 
     1031         * Open form. 
     1032         * 
     1033         * @uses        Wakka::GetConfigValue() 
     1034         * 
     1035         * @todo        replace with advanced FormOpen (so IDs are generated, among other things!) 
     1036         * @todo        check if the hidden field is still needed - Href() already provides 
     1037         *                      the wakka= part of the URL... everything seems to work fine with 
     1038         *                      or without rewrite mode, and without this hidden field! 
     1039         */ 
     1040        /* replaced by http://wikkawiki.org/AdvancedFormOpen 
    9501041        function FormOpen($method = "", $tag = "", $formMethod = "post") 
    9511042        { 
     
    9541045                return $result; 
    9551046        } 
     1047        */ 
     1048        /** 
     1049         * Build an opening form tag with specified or generated attributes. 
     1050         * 
     1051         * This method builds an opening form tag, taking care that the result is valid XHTML 
     1052         * no matter where the parameters come from: invalid parameters are ignored and defaults used. 
     1053         * This enables this method to be used with user-provided parameter values. 
     1054         * 
     1055         * The form will always have the required action attribute and an id attribute to provide 
     1056         * a 'hook' for styling and scripting. This method tries its best to ensure the id attribute 
     1057         * is unique, among other things by adding a 'form_' prefix to make it different from ids for 
     1058         * other elements. 
     1059         * For a file upload form ($file=TRUE) the appropriate method and enctype attributes are generated. 
     1060         * 
     1061         * @author              {@link http://wikkawiki.org/JavaWoman JavaWoman} (Advanced version: complete rewrite; 2005) 
     1062         * @license             http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 
     1063         * 
     1064         * @access      public 
     1065         * @uses        makeId() 
     1066         * @uses        ID_LENGTH 
     1067         * @uses        existsHandler() 
     1068         * @uses        existsPage() 
     1069         * @uses        Href() 
     1070         * @uses        MiniHref()      only for hidden field 
     1071         * 
     1072         * @param       string  $handler        optional: "handler" which consists of handler name and possibly a query string 
     1073         *                                                              to be used as part of action attribute 
     1074         * @param       string  $tag            optional: page name to be used for action attribute; 
     1075         *                                                              if not specified, the current page will be used 
     1076         * @param       string  $formMethod     optional: method attribute; must be POST (default) or GET; 
     1077         *                                                              anything but POST is ignored and considered as GET; 
     1078         *                                                              always converted to lowercase 
     1079         * @param       string  $id                     optional: id attribute 
     1080         * @param       string  $class          optional: class attribute 
     1081         * @param       boolean $file           optional: specifies whether there will be a file upload field; 
     1082         *                                                              default: FALSE; if TRUE sets method attribute to POST and generates 
     1083         *                                                              appropriate enctype attribute 
     1084         * @return      string opening form tag 
     1085         * @todo        extend to handle a complete (external) URL instead of (handler+)pagename 
     1086         * @todo        extend to allow extra attributes 
     1087         */ 
     1088        function FormOpen($handler='', $tag='', $formMethod='post', $id='', $class='', $file=FALSE) 
     1089        { 
     1090                // init 
     1091                $attrMethod = '';                                                                       // no method for HTML default 'get' 
     1092                $attrClass = ''; 
     1093                $attrEnctype = '';                                                                      // default no enctype -> HTML default application/x-www-form-urlencoded 
     1094                $hidden = array(); 
     1095                // derivations 
     1096                $handler = trim($handler); 
     1097                $tag = trim($tag); 
     1098                $id = trim($id); 
     1099                $class = trim($class); 
     1100                // validations (needed only if parameters are actually specified) 
     1101                if (!empty($handler) && !$this->existsHandler($handler)) 
     1102                { 
     1103                        $handler = ''; 
     1104                } 
     1105                if (!empty($tag) && !$this->existsPage($tag)) 
     1106                { 
     1107                        $tag = '';      // Href() will pick up current page name if none specified 
     1108                } 
     1109 
     1110                // form action (action is a required attribute!) 
     1111                // !!! If rewrite mode is off, "tag" has to be passed as a hidden field 
     1112                // rather than part of the URL (where it gets ignored on submit!) 
     1113                if ($this->GetConfigValue('rewrite_mode')) 
     1114                { 
     1115                        // @@@ add passed extra GET params here by passing them as extra 
     1116                        // parameter to Href() 
     1117                        $attrAction = ' action="'.$this->Href($handler, $tag).'"'; 
     1118                } 
     1119                else 
     1120                { 
     1121                        $attrAction = ' action="'.$this->Href($handler).'"'; 
     1122                        $hidden['wakka'] = ('' != $tag) ? $tag : $this->tag; 
     1123                        // @@@ add passed extra GET params here by adding them as extra 
     1124                        // entries to $hidden (probably not by adding them to Href() 
     1125                        // but that needs to be tested when we get to it!) 
     1126                } 
     1127                // form method (ignore anything but post) and enctype 
     1128                if (TRUE === $file) 
     1129                { 
     1130                        $attrMethod  = ' method="post"';                                // required for file upload 
     1131                        $attrEnctype = ' enctype="multipart/form-data"';// required for file upload 
     1132                } 
     1133                elseif (preg_match('/^post$/i',$formMethod))            // ignore case... 
     1134                { 
     1135                        $attrMethod = ' method="post"';                                 // ...but generate lowercase 
     1136                } 
     1137                // form id 
     1138                if ('' == $id)                                                                          // if no id given, generate one based on other parameters 
     1139                { 
     1140                        $id = substr(md5($handler.$tag.$formMethod.$class),0,ID_LENGTH); 
     1141                } 
     1142                $attrId = ' id="'.$this->makeId('form',$id).'"';        // make sure we have a unique id 
     1143                // form class 
     1144                if ('' != $class) 
     1145                { 
     1146                        $attrClass = ' class="'.$class.'"'; 
     1147                } 
     1148 
     1149                // build HTML fragment 
     1150                $fragment = '<form'.$attrAction.$attrMethod.$attrEnctype.$attrId.$attrClass.'>'."\n"; 
     1151                // construct and add hidden fields (necessary if we are NOT using rewrite mode) 
     1152                if (count($hidden) > 0) 
     1153                { 
     1154                        $fragment .= '<fieldset class="hidden">'."\n"; 
     1155                        foreach ($hidden as $name => $value) 
     1156                        { 
     1157                                $fragment .= '  <input type="hidden" name="'.$name.'" value="'.$value.'" />'."\n"; 
     1158                        } 
     1159                        $fragment .= '</fieldset>'."\n"; 
     1160                } 
     1161 
     1162                // return resulting HTML fragment 
     1163                return $fragment; 
     1164        } 
     1165        /** 
     1166         * Close form 
     1167         * 
     1168         * @return      string  the XHTML tag to close a form and a newline. 
     1169         */ 
    9561170        function FormClose() 
    9571171        { 
     
    10121226        } 
    10131227 
     1228        // SANITY CHECKS 
     1229 
     1230        /** 
     1231         * Check by name if a page exists. 
     1232         * 
     1233         * @author              {@link http://wikkawiki.org/JavaWoman JavaWoman} 
     1234         * @copyright   Copyright © 2004, Marjolein Katsma 
     1235         * @license             http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 
     1236         * @version             1.0 
     1237         * 
     1238         * NOTE: name changed from ExistsPage() to existsPage() !!! 
     1239         * 
     1240         * @access              public 
     1241         * @uses                Query() 
     1242         * 
     1243         * @param               string  $page  page name to check 
     1244         * @return              boolean  TRUE if page exists, FALSE otherwise 
     1245         */ 
     1246        function existsPage($page) 
     1247        { 
     1248                $count = 0; 
     1249                $query =        "SELECT COUNT(tag) 
     1250                                        FROM ".$this->config['table_prefix']."pages 
     1251                                        WHERE tag='".mysql_real_escape_string($page)."'"; 
     1252                if ($r = $this->Query($query)) 
     1253                { 
     1254                        $count = mysql_result($r,0); 
     1255                        mysql_free_result($r); 
     1256                } 
     1257                return ($count > 0) ? TRUE : FALSE; 
     1258        } 
     1259        /** 
     1260         * Check if a handler (specified after page name) really exists. 
     1261         * 
     1262         * May be passed as handler plus query string; we'll need to look at handler only 
     1263         * so we strip off any querystring first. 
     1264         * 
     1265         * @author              {@link http://wikkawiki.org/JavaWoman JavaWoman} (created 2005; rewrite 2007) 
     1266         * @license             http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 
     1267         * 
     1268         * @access      public 
     1269         * @uses        Wakka::GetConfigValue() 
     1270         * 
     1271         * @param       string  $handler        handler name, optionally with appended parameters 
     1272         * @return      boolean TRUE if handler is found, FALSE otherwise 
     1273         */ 
     1274        function existsHandler($handler) 
     1275        { 
     1276                // first strip off any query string 
     1277                $parts = preg_split('/&/',$handler,1);                          # return only one part 
     1278                $handler = $parts[0]; 
     1279#echo 'handler: '.$handler.'<br/>'; 
     1280                // now check if a handler by that name exists 
     1281#echo 'checking path: '.$this->GetConfigValue('wikka_handler_path').DIRECTORY_SEPARATOR.$handler.DIRECTORY_SEPARATOR.$handler.'.php'.'<br/>'; 
     1282                $exists = file_exists($this->GetConfigValue('wikka_handler_path').DIRECTORY_SEPARATOR.$handler.DIRECTORY_SEPARATOR.$handler.'.php'); 
     1283                // return conclusion 
     1284                return $exists; 
     1285        } 
     1286 
    10141287        // PLUGINS 
     1288 
    10151289        function Action($actionspec, $forceLinkTracking = 0) 
    10161290        { 
     
    10201294                if (!preg_match('/^\s*([a-zA-Z0-9]+)(\s.+?)?\s*$/', $actionspec, $matches))     # see also #34 
    10211295                { 
    1022                         return '<em class="error">Unknown action; the action name must not contain special characters.</em>';   # [SEC]                  
     1296                        return '<em class="error">Unknown action; the action name must not contain special characters.</em>';   # [SEC] 
    10231297                } 
    10241298                else 
     
    10371311                        // prepare an array for extract() (in $this->IncludeBuffered()) to work with 
    10381312                        $vars = array(); 
    1039                         if (is_array($matches))  
     1313                        if (is_array($matches)) 
    10401314                        { 
    1041                                 for ($a = 0; $a < count($matches[0]); $a++)  
     1315                                for ($a = 0; $a < count($matches[0]); $a++) 
    10421316                                { 
    10431317                                        // parameter value is sanitized using htmlspecialchars_ent(); if an 
    10441318                                        // action really needs "raw" HTML as input it can still be "unescaped"by the action 
    10451319                                        // itself; for any other action this guards against XSS or directory traversal 
    1046                                         // via user-supplied action parameters. Any HTML will be displayed _as code_,  
     1320                                        // via user-supplied action parameters. Any HTML will be displayed _as code_, 
    10471321                                        // but not interpreted. 
    10481322                                        $vars[$matches[1][$a]] = $this->htmlspecialchars_ent($matches[3][$a]);  // parameter name = sanitized value [SEC] 
     
    10611335                if (strstr($method, '/')) 
    10621336                { 
    1063                         # Observations - MK 2007-03-30  
     1337                        # Observations - MK 2007-03-30 
    10641338                        # extract part after the last slash (if the whole request contained multiple slashes) 
    10651339                        # TODO: 
    10661340                        # but should such requests be accepted in the first place? 
    10671341                        # at least it is a SORT of defense against directory traversal (but not necessarily XSS) 
    1068                         # NOTE that name syntax check now takes care of XSS  
     1342                        # NOTE that name syntax check now takes care of XSS 
    10691343                        $method = substr($method, strrpos($method, '/')+1); 
    10701344                } 
     
    10721346                if (!preg_match('/^([a-zA-Z0-9_.-]+)$/', $method)) // allow letters, numbers, underscores, dashes and dots only (for now); see also #34 
    10731347                { 
    1074                         return '<em class="error">Unknown method; the method name must not contain special characters.</em>';   # [SEC]                  
     1348                        return '<em class="error">Unknown method; the method name must not contain special characters.</em>';   # [SEC] 
    10751349                } 
    10761350                else 
     
    10831357                return $this->IncludeBuffered($methodLocation, '<em class="error">Unknown method "'.$methodLocation.'"</em>', '', $this->config['handler_path']); 
    10841358        } 
    1085         function Format($text, $formatter='wakka')  
    1086         {  
     1359        function Format($text, $formatter='wakka') 
     1360        { 
    10871361                // check valid formatter name syntax (similar to Action()) 
    10881362                if (!preg_match('/^([a-zA-Z0-9_.-]+)$/', $formatter)) // allow letters, numbers, underscores, dashes and dots only (for now); see also #34 
    10891363                { 
    1090                         return '<em class="error">Unknown formatter; the formatter name must not contain special characters.</em>';     # [SEC]                  
     1364                        return '<em class="error">Unknown formatter; the formatter name must not contain special characters.</em>';     # [SEC] 
    10911365                } 
    10921366                else 
     
    10951369                        $formatter      = strtolower($formatter); 
    10961370                } 
    1097                 return $this->IncludeBuffered($formatter.'.php', '<em class="error">Formatter "'.$formatter.'" not found</em>', compact("text"), $this->config['wikka_formatter_path']);  
     1371                return $this->IncludeBuffered($formatter.'.php', '<em class="error">Formatter "'.$formatter.'" not found</em>', compact("text"), $this->config['wikka_formatter_path']); 
    10981372        } 
    10991373 
     
    11641438 
    11651439        // ACCESS CONTROL 
    1166         /**  
    1167          * Check if current user is the owner of the current or a specified page.  
    1168          *   
     1440        /** 
     1441         * Check if current user is the owner of the current or a specified page. 
     1442         * 
    11691443         * @access              public 
    11701444         * @uses                Wakka::GetPageOwner() 
    1171          * @uses                Wakka::GetPageTag()  
     1445         * @uses                Wakka::GetPageTag() 
    11721446         * @uses                Wakka::GetUser() 
    11731447         * @uses                Wakka::GetUserName() 
    11741448         * @uses                Wakka::IsAdmin() 
    1175          *  
    1176          * @param               string  $tag optional: page to be checked. Default: current page.  
    1177          * @return              boolean TRUE if the user is the owner, FALSE otherwise.  
    1178          */  
     1449         * 
     1450         * @param               string  $tag optional: page to be checked. Default: current page. 
     1451         * @return              boolean TRUE if the user is the owner, FALSE otherwise. 
     1452         */ 
    11791453        function UserIsOwner($tag = "") 
    11801454        { 
    1181                 // if not logged in, user can't be owner!  
     1455                // if not logged in, user can't be owner! 
    11821456                if (!$this->GetUser()) return false; 
    11831457 
     
    13251599                if (!$this->tag = trim($tag)) $this->Redirect($this->Href("", $this->config["root_page"])); 
    13261600                if (!$this->GetUser() && ($user = $this->LoadUser($this->GetCookie('user_name'), $this->GetCookie('pass')))) $this->SetUser($user); 
    1327                 if ((!$this->GetUser() && isset($_COOKIE["wikka_user_name"])) && ($user = $this->LoadUser($_COOKIE["wikka_user_name"], $_COOKIE["wikka_pass"])))  
     1601                if ((!$this->GetUser() && isset($_COOKIE["wikka_user_name"])) && ($user = $this->LoadUser($_COOKIE["wikka_user_name"], $_COOKIE["wikka_pass"]))) 
    13281602                { 
    13291603                 //Old cookies : delete them 
    1330                         SetCookie('wikka_user_name', "", 1, "/");  
     1604                        SetCookie('wikka_user_name', "", 1, "/"); 
    13311605                        $_COOKIE['wikka_user_name'] = ""; 
    13321606                        SetCookie('wikka_pass', '', 1, '/'); 
     
    13711645                } 
    13721646        } 
    1373 }  
     1647} 
    13741648?>