Changeset 746
- Timestamp:
- 10/11/2007 03:08:48 AM (3 years ago)
- Files:
-
- 1 modified
-
branches/1.1.6.4/libs/Wakka.class.php (modified) (30 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/1.1.6.4/libs/Wakka.class.php
r745 r746 2 2 /** 3 3 * This file is part of Wikka, a PHP wiki engine. 4 * 4 * 5 5 * It includes the Wakka class, which provides the core functions 6 * to run Wikka. 6 * to run Wikka. 7 7 * 8 8 * @package Wikka … … 11 11 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 12 12 * @filesource 13 * 13 * 14 14 * @author Hendrik Mans <hendrik@mans.de> 15 15 * @author Jason Tourtelotte <wikka-admin@jsnx.com> … … 18 18 * @author {@link http://wikkawiki.org/DotMG Mahefa Randimbisoa} 19 19 * @author {@link http://wikkawiki.org/DarTar Dario Taraborelli} 20 * 20 * 21 21 * @copyright Copyright 2002-2003, Hendrik Mans <hendrik@mans.de> 22 22 * @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} 24 24 */ 25 25 26 26 /** 27 27 * The Wikka core. 28 * 28 * 29 29 * This class contains all the core methods used to run Wikka. 30 30 * @name Wakka 31 31 * @package Wikka 32 32 * @subpackage Libs 33 * 33 * 34 34 */ 35 35 class Wakka … … 101 101 * @author {@link http://wikkawiki.org/JavaWoman JavaWoman} 102 102 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License 103 * @since Wikka 1.1.6.4 103 104 * @version 1.1 104 105 * … … 167 168 function IncludeBuffered($filename, $notfoundText='', $vars='', $path='') 168 169 { 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 172 173 173 174 // check if required parameter $path is supplied (see TODO) 174 175 if ('' != trim($path)) 175 { 176 { 176 177 // build full (relative) path to requested plugin (method/action/formatter) 177 178 $fullfilepath = trim($path).DIRECTORY_SEPARATOR.$filename; #89 - Note $filename may actually already contain a (partial) path … … 203 204 } 204 205 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 */ 205 312 function ReturnSafeHTML($html) 206 313 { … … 219 326 * 220 327 # * Any already-present '&' is first turned into '&'; then htmlspecialchars() is applied so 221 * Any already-present '&' 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 '&' 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 224 331 * them. 225 332 * 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, 227 334 * handlers etc. 228 * 335 * 229 336 * Note: hsc_secure() is the secure replacement for PHP's htmlspecialchars(). 230 * See #427. 337 * See #427. 231 338 * 232 339 * @author {@link http://wikkawiki.org/JavaWoman JavaWoman} … … 249 356 * Wrapper around hsc_secure() which preserves entity references. 250 357 * 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 252 359 * 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 254 361 * passed on to our hsc_secure() replacement for htmlspecialchars(). 255 * 362 * 256 363 * Since hsc_secure() does not need a character set parameter, we don't 257 364 * 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 261 368 * its work: numeic entity references are always "unescaped' since they are 262 369 * valid for both HTML and XML doctypes; for XML the named entity references 263 370 * 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 269 376 * (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 272 379 * always added in the output where it was omitted. 273 380 * 274 381 * 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 277 384 * of as their corresponding characters. 278 * 385 * 279 386 * 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 281 388 * 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 283 390 * the same time updating the 'XML' doctype with apos as named entity). 284 391 * … … 289 396 * @uses Wakka::hsc_secure() 290 397 * @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 294 401 * quotes) 295 402 * @param string $doctype 'HTML' (default) or 'XML'; for XML only the XML 296 403 * 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 298 405 * 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 301 408 * alone, thus transform &error; to &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 305 412 * and may not be worth the effort 306 413 */ … … 309 416 // re-establish default if overwritten because of third parameter 310 417 // [ENT_COMPAT] => 2 311 // [ENT_QUOTES] => 3312 // [ENT_NOQUOTES] => 0418 // [ENT_QUOTES] => 3 419 // [ENT_NOQUOTES] => 0 313 420 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 317 424 // define patterns 318 425 $terminator = ';|(?=($|[\n<]|<))'; // semicolon; or end-of-string, newline or tag … … 322 429 { 323 430 // only valid named entities in XML (case-sensitive) 324 $named = 'lt|gt|quot|apos|amp'; 431 $named = 'lt|gt|quot|apos|amp'; 325 432 $ignore_case = ''; 326 433 $entitystring = $named.'|'.$numdec.'|'.$numhex; … … 347 454 /** 348 455 * 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 351 458 * for this replacement function. 352 * 459 * 353 460 * The INTERFACE for this function is almost the same as that for 354 461 * htmlspecialchars(), with the same default for quote style; however, there 355 462 * is no 'charset' parameter. The reason for this is as follows: 356 * 463 * 357 464 * The PHP docs say: 358 465 * "The third argument charset defines character set used in conversion." 359 * 466 * 360 467 * 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 362 469 * 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 366 473 * htmlentities() which certainly is working at byte-value level.) 367 * 474 * 368 475 * 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 370 477 * parameter is needed or provided. If a third parameter is passed, it will 371 478 * be silently ignored. 372 * 479 * 373 480 * In the OUTPUT there is a minor difference in that we use ''' instead 374 481 * of PHP's ''' for a single quote: this provides compatibility with 375 482 * 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 ''' 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 ''' for the 488 * single quote. For the other special characters we use the named entity 382 489 * references, as PHP is doing. 383 * 490 * 384 491 * 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 387 494 * Team and finally used by JavaWoman. :) 388 * 495 * 389 496 * @author {@link http://wikkawiki.org/JavaWoman Marjolein Katsma} 390 497 * 391 498 * @since Wikka 1.1.7 392 499 * @version 1.0 393 * @license http://www.gnu.org/copyleft/lgpl.html 500 * @license http://www.gnu.org/copyleft/lgpl.html 394 501 * GNU Lesser General Public License 395 * @copyright Copyright 2007, {@link http://wikkawiki.org/CreditsPage 502 * @copyright Copyright 2007, {@link http://wikkawiki.org/CreditsPage 396 503 * Wikka Development Team} 397 * 504 * 398 505 * @access public 399 506 * @param string $string string to be converted 400 * @param integer $quote_style 507 * @param integer $quote_style 401 508 * - ENT_COMPAT: escapes &, <, > and double quote (default) 402 509 * - ENT_NOQUOTES: escapes only &, < and > 403 510 * - ENT_QUOTES: escapes &, <, >, double and single quotes 404 * @return string converted string 511 * @return string converted string 405 512 */ 406 513 function hsc_secure($string, $quote_style=ENT_COMPAT) 407 514 { 408 // init409 $aTransSpecchar = array('&' => '&',410 '"' => '"',411 '<' => '<',515 // init 516 $aTransSpecchar = array('&' => '&', 517 '"' => '"', 518 '<' => '<', 412 519 '>' => '>' 413 520 ); // ENT_COMPAT set … … 535 642 // parse and return highlighted code 536 643 // 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"; 538 645 } 539 646 … … 666 773 $this->Query("insert into ".$this->config["table_prefix"]."pages set ". 667 774 "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)."', ". 671 778 "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)."'"); 674 781 675 782 if ($pingdata = $this->GetPingParams($this->config["wikiping_server"], $tag, $user, $note)) … … 686 793 if ($title) return strip_tags($this->Format($title)); # fix for forced links in heading 687 794 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 Katsma694 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License695 * @version 1.0696 *697 * @access public698 * @uses Query()699 *700 * @param string $page page name to check701 * @return boolean TRUE if page exists, FALSE otherwise702 */703 function ExistsPage($page)704 {705 $count = 0;706 $query = "SELECT COUNT(tag)707 FROM ".$this->config['table_prefix']."pages708 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;715 795 } 716 796 … … 784 864 if ($tag) $ping["tag"] = $tag; else return false; // set page-title 785 865 if (!$ping["taglink"] = $this->Href("", $tag)) return false; // set page-url 786 if (!$ping["wiki"] = $this->config["wakka_name"]) return false; // set site-name866 if (!$ping["wiki"] = $this->config["wakka_name"]) return false; // set site-name 787 867 $ping["history"] = $this->Href("revisions", $tag); // set url to history 788 868 … … 839 919 '<meta http-equiv="refresh" content="0; url=\''.$url.'\'" /></head><body><div><script type="text/javascript">window.location.href="'.$url.'";</script>'. 840 920 '</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 843 923 { 844 924 header("Location: ".$url); … … 859 939 } 860 940 /** 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 864 944 * this method. 865 945 * 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 872 952 * @access public 873 953 * @return string … … 948 1028 949 1029 // 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 950 1041 function FormOpen($method = "", $tag = "", $formMethod = "post") 951 1042 { … … 954 1045 return $result; 955 1046 } 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 */ 956 1170 function FormClose() 957 1171 { … … 1012 1226 } 1013 1227 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 1014 1287 // PLUGINS 1288 1015 1289 function Action($actionspec, $forceLinkTracking = 0) 1016 1290 { … … 1020 1294 if (!preg_match('/^\s*([a-zA-Z0-9]+)(\s.+?)?\s*$/', $actionspec, $matches)) # see also #34 1021 1295 { 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] 1023 1297 } 1024 1298 else … … 1037 1311 // prepare an array for extract() (in $this->IncludeBuffered()) to work with 1038 1312 $vars = array(); 1039 if (is_array($matches)) 1313 if (is_array($matches)) 1040 1314 { 1041 for ($a = 0; $a < count($matches[0]); $a++) 1315 for ($a = 0; $a < count($matches[0]); $a++) 1042 1316 { 1043 1317 // parameter value is sanitized using htmlspecialchars_ent(); if an 1044 1318 // action really needs "raw" HTML as input it can still be "unescaped"by the action 1045 1319 // 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_, 1047 1321 // but not interpreted. 1048 1322 $vars[$matches[1][$a]] = $this->htmlspecialchars_ent($matches[3][$a]); // parameter name = sanitized value [SEC] … … 1061 1335 if (strstr($method, '/')) 1062 1336 { 1063 # Observations - MK 2007-03-30 1337 # Observations - MK 2007-03-30 1064 1338 # extract part after the last slash (if the whole request contained multiple slashes) 1065 1339 # TODO: 1066 1340 # but should such requests be accepted in the first place? 1067 1341 # 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 1069 1343 $method = substr($method, strrpos($method, '/')+1); 1070 1344 } … … 1072 1346 if (!preg_match('/^([a-zA-Z0-9_.-]+)$/', $method)) // allow letters, numbers, underscores, dashes and dots only (for now); see also #34 1073 1347 { 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] 1075 1349 } 1076 1350 else … … 1083 1357 return $this->IncludeBuffered($methodLocation, '<em class="error">Unknown method "'.$methodLocation.'"</em>', '', $this->config['handler_path']); 1084 1358 } 1085 function Format($text, $formatter='wakka') 1086 { 1359 function Format($text, $formatter='wakka') 1360 { 1087 1361 // check valid formatter name syntax (similar to Action()) 1088 1362 if (!preg_match('/^([a-zA-Z0-9_.-]+)$/', $formatter)) // allow letters, numbers, underscores, dashes and dots only (for now); see also #34 1089 1363 { 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] 1091 1365 } 1092 1366 else … … 1095 1369 $formatter = strtolower($formatter); 1096 1370 } 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']); 1098 1372 } 1099 1373 … … 1164 1438 1165 1439 // 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 * 1169 1443 * @access public 1170 1444 * @uses Wakka::GetPageOwner() 1171 * @uses Wakka::GetPageTag() 1445 * @uses Wakka::GetPageTag() 1172 1446 * @uses Wakka::GetUser() 1173 1447 * @uses Wakka::GetUserName() 1174 1448 * @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 */ 1179 1453 function UserIsOwner($tag = "") 1180 1454 { 1181 // if not logged in, user can't be owner! 1455 // if not logged in, user can't be owner! 1182 1456 if (!$this->GetUser()) return false; 1183 1457 … … 1325 1599 if (!$this->tag = trim($tag)) $this->Redirect($this->Href("", $this->config["root_page"])); 1326 1600 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"]))) 1328 1602 { 1329 1603 //Old cookies : delete them 1330 SetCookie('wikka_user_name', "", 1, "/"); 1604 SetCookie('wikka_user_name', "", 1, "/"); 1331 1605 $_COOKIE['wikka_user_name'] = ""; 1332 1606 SetCookie('wikka_pass', '', 1, '/'); … … 1371 1645 } 1372 1646 } 1373 } 1647 } 1374 1648 ?>