[ Index ] |
PHP Cross Reference of MediaWiki-1.24.0 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * File for magic words. 4 * 5 * See docs/magicword.txt. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * http://www.gnu.org/copyleft/gpl.html 21 * 22 * @file 23 * @ingroup Parser 24 */ 25 26 /** 27 * This class encapsulates "magic words" such as "#redirect", __NOTOC__, etc. 28 * 29 * @par Usage: 30 * @code 31 * if (MagicWord::get( 'redirect' )->match( $text ) ) { 32 * // some code 33 * } 34 * @endcode 35 * 36 * Possible future improvements: 37 * * Simultaneous searching for a number of magic words 38 * * MagicWord::$mObjects in shared memory 39 * 40 * Please avoid reading the data out of one of these objects and then writing 41 * special case code. If possible, add another match()-like function here. 42 * 43 * To add magic words in an extension, use $magicWords in a file listed in 44 * $wgExtensionMessagesFiles[]. 45 * 46 * @par Example: 47 * @code 48 * $magicWords = array(); 49 * 50 * $magicWords['en'] = array( 51 * 'magicwordkey' => array( 0, 'case_insensitive_magic_word' ), 52 * 'magicwordkey2' => array( 1, 'CASE_sensitive_magic_word2' ), 53 * ); 54 * @endcode 55 * 56 * For magic words which are also Parser variables, add a MagicWordwgVariableIDs 57 * hook. Use string keys. 58 * 59 * @ingroup Parser 60 */ 61 class MagicWord { 62 /**#@-*/ 63 64 /** @var int */ 65 public $mId; 66 67 /** @var array */ 68 public $mSynonyms; 69 70 /** @var bool */ 71 public $mCaseSensitive; 72 73 /** @var string */ 74 private $mRegex = ''; 75 76 /** @var string */ 77 private $mRegexStart = ''; 78 79 /** @var string */ 80 private $mRegexStartToEnd = ''; 81 82 /** @var string */ 83 private $mBaseRegex = ''; 84 85 /** @var string */ 86 private $mVariableRegex = ''; 87 88 /** @var string */ 89 private $mVariableStartToEndRegex = ''; 90 91 /** @var bool */ 92 private $mModified = false; 93 94 /** @var bool */ 95 private $mFound = false; 96 97 static public $mVariableIDsInitialised = false; 98 static public $mVariableIDs = array( 99 '!', 100 'currentmonth', 101 'currentmonth1', 102 'currentmonthname', 103 'currentmonthnamegen', 104 'currentmonthabbrev', 105 'currentday', 106 'currentday2', 107 'currentdayname', 108 'currentyear', 109 'currenttime', 110 'currenthour', 111 'localmonth', 112 'localmonth1', 113 'localmonthname', 114 'localmonthnamegen', 115 'localmonthabbrev', 116 'localday', 117 'localday2', 118 'localdayname', 119 'localyear', 120 'localtime', 121 'localhour', 122 'numberofarticles', 123 'numberoffiles', 124 'numberofedits', 125 'articlepath', 126 'pageid', 127 'sitename', 128 'server', 129 'servername', 130 'scriptpath', 131 'stylepath', 132 'pagename', 133 'pagenamee', 134 'fullpagename', 135 'fullpagenamee', 136 'namespace', 137 'namespacee', 138 'namespacenumber', 139 'currentweek', 140 'currentdow', 141 'localweek', 142 'localdow', 143 'revisionid', 144 'revisionday', 145 'revisionday2', 146 'revisionmonth', 147 'revisionmonth1', 148 'revisionyear', 149 'revisiontimestamp', 150 'revisionuser', 151 'revisionsize', 152 'subpagename', 153 'subpagenamee', 154 'talkspace', 155 'talkspacee', 156 'subjectspace', 157 'subjectspacee', 158 'talkpagename', 159 'talkpagenamee', 160 'subjectpagename', 161 'subjectpagenamee', 162 'numberofusers', 163 'numberofactiveusers', 164 'numberofpages', 165 'currentversion', 166 'rootpagename', 167 'rootpagenamee', 168 'basepagename', 169 'basepagenamee', 170 'currenttimestamp', 171 'localtimestamp', 172 'directionmark', 173 'contentlanguage', 174 'numberofadmins', 175 'numberofviews', 176 'cascadingsources', 177 ); 178 179 /* Array of caching hints for ParserCache */ 180 static public $mCacheTTLs = array( 181 'currentmonth' => 86400, 182 'currentmonth1' => 86400, 183 'currentmonthname' => 86400, 184 'currentmonthnamegen' => 86400, 185 'currentmonthabbrev' => 86400, 186 'currentday' => 3600, 187 'currentday2' => 3600, 188 'currentdayname' => 3600, 189 'currentyear' => 86400, 190 'currenttime' => 3600, 191 'currenthour' => 3600, 192 'localmonth' => 86400, 193 'localmonth1' => 86400, 194 'localmonthname' => 86400, 195 'localmonthnamegen' => 86400, 196 'localmonthabbrev' => 86400, 197 'localday' => 3600, 198 'localday2' => 3600, 199 'localdayname' => 3600, 200 'localyear' => 86400, 201 'localtime' => 3600, 202 'localhour' => 3600, 203 'numberofarticles' => 3600, 204 'numberoffiles' => 3600, 205 'numberofedits' => 3600, 206 'currentweek' => 3600, 207 'currentdow' => 3600, 208 'localweek' => 3600, 209 'localdow' => 3600, 210 'numberofusers' => 3600, 211 'numberofactiveusers' => 3600, 212 'numberofpages' => 3600, 213 'currentversion' => 86400, 214 'currenttimestamp' => 3600, 215 'localtimestamp' => 3600, 216 'pagesinnamespace' => 3600, 217 'numberofadmins' => 3600, 218 'numberofviews' => 3600, 219 'numberingroup' => 3600, 220 ); 221 222 static public $mDoubleUnderscoreIDs = array( 223 'notoc', 224 'nogallery', 225 'forcetoc', 226 'toc', 227 'noeditsection', 228 'newsectionlink', 229 'nonewsectionlink', 230 'hiddencat', 231 'index', 232 'noindex', 233 'staticredirect', 234 'notitleconvert', 235 'nocontentconvert', 236 ); 237 238 static public $mSubstIDs = array( 239 'subst', 240 'safesubst', 241 ); 242 243 static public $mObjects = array(); 244 static public $mDoubleUnderscoreArray = null; 245 246 /**#@-*/ 247 248 function __construct( $id = 0, $syn = array(), $cs = false ) { 249 $this->mId = $id; 250 $this->mSynonyms = (array)$syn; 251 $this->mCaseSensitive = $cs; 252 } 253 254 /** 255 * Factory: creates an object representing an ID 256 * 257 * @param int $id 258 * 259 * @return MagicWord 260 */ 261 static function &get( $id ) { 262 if ( !isset( self::$mObjects[$id] ) ) { 263 $mw = new MagicWord(); 264 $mw->load( $id ); 265 self::$mObjects[$id] = $mw; 266 } 267 return self::$mObjects[$id]; 268 } 269 270 /** 271 * Get an array of parser variable IDs 272 * 273 * @return array 274 */ 275 static function getVariableIDs() { 276 if ( !self::$mVariableIDsInitialised ) { 277 # Get variable IDs 278 wfRunHooks( 'MagicWordwgVariableIDs', array( &self::$mVariableIDs ) ); 279 self::$mVariableIDsInitialised = true; 280 } 281 return self::$mVariableIDs; 282 } 283 284 /** 285 * Get an array of parser substitution modifier IDs 286 * @return array 287 */ 288 static function getSubstIDs() { 289 return self::$mSubstIDs; 290 } 291 292 /** 293 * Allow external reads of TTL array 294 * 295 * @param int $id 296 * @return int 297 */ 298 static function getCacheTTL( $id ) { 299 if ( array_key_exists( $id, self::$mCacheTTLs ) ) { 300 return self::$mCacheTTLs[$id]; 301 } else { 302 return -1; 303 } 304 } 305 306 /** 307 * Get a MagicWordArray of double-underscore entities 308 * 309 * @return MagicWordArray 310 */ 311 static function getDoubleUnderscoreArray() { 312 if ( is_null( self::$mDoubleUnderscoreArray ) ) { 313 wfRunHooks( 'GetDoubleUnderscoreIDs', array( &self::$mDoubleUnderscoreIDs ) ); 314 self::$mDoubleUnderscoreArray = new MagicWordArray( self::$mDoubleUnderscoreIDs ); 315 } 316 return self::$mDoubleUnderscoreArray; 317 } 318 319 /** 320 * Clear the self::$mObjects variable 321 * For use in parser tests 322 */ 323 public static function clearCache() { 324 self::$mObjects = array(); 325 } 326 327 /** 328 * Initialises this object with an ID 329 * 330 * @param int $id 331 * @throws MWException 332 */ 333 function load( $id ) { 334 global $wgContLang; 335 wfProfileIn( __METHOD__ ); 336 $this->mId = $id; 337 $wgContLang->getMagic( $this ); 338 if ( !$this->mSynonyms ) { 339 $this->mSynonyms = array( 'brionmademeputthishere' ); 340 wfProfileOut( __METHOD__ ); 341 throw new MWException( "Error: invalid magic word '$id'" ); 342 } 343 wfProfileOut( __METHOD__ ); 344 } 345 346 /** 347 * Preliminary initialisation 348 * @private 349 */ 350 function initRegex() { 351 // Sort the synonyms by length, descending, so that the longest synonym 352 // matches in precedence to the shortest 353 $synonyms = $this->mSynonyms; 354 usort( $synonyms, array( $this, 'compareStringLength' ) ); 355 356 $escSyn = array(); 357 foreach ( $synonyms as $synonym ) { 358 // In case a magic word contains /, like that's going to happen;) 359 $escSyn[] = preg_quote( $synonym, '/' ); 360 } 361 $this->mBaseRegex = implode( '|', $escSyn ); 362 363 $case = $this->mCaseSensitive ? '' : 'iu'; 364 $this->mRegex = "/{$this->mBaseRegex}/{$case}"; 365 $this->mRegexStart = "/^(?:{$this->mBaseRegex})/{$case}"; 366 $this->mRegexStartToEnd = "/^(?:{$this->mBaseRegex})$/{$case}"; 367 $this->mVariableRegex = str_replace( "\\$1", "(.*?)", $this->mRegex ); 368 $this->mVariableStartToEndRegex = str_replace( "\\$1", "(.*?)", 369 "/^(?:{$this->mBaseRegex})$/{$case}" ); 370 } 371 372 /** 373 * A comparison function that returns -1, 0 or 1 depending on whether the 374 * first string is longer, the same length or shorter than the second 375 * string. 376 * 377 * @param string $s1 378 * @param string $s2 379 * 380 * @return int 381 */ 382 function compareStringLength( $s1, $s2 ) { 383 $l1 = strlen( $s1 ); 384 $l2 = strlen( $s2 ); 385 if ( $l1 < $l2 ) { 386 return 1; 387 } elseif ( $l1 > $l2 ) { 388 return -1; 389 } else { 390 return 0; 391 } 392 } 393 394 /** 395 * Gets a regex representing matching the word 396 * 397 * @return string 398 */ 399 function getRegex() { 400 if ( $this->mRegex == '' ) { 401 $this->initRegex(); 402 } 403 return $this->mRegex; 404 } 405 406 /** 407 * Gets the regexp case modifier to use, i.e. i or nothing, to be used if 408 * one is using MagicWord::getBaseRegex(), otherwise it'll be included in 409 * the complete expression 410 * 411 * @return string 412 */ 413 function getRegexCase() { 414 if ( $this->mRegex === '' ) { 415 $this->initRegex(); 416 } 417 418 return $this->mCaseSensitive ? '' : 'iu'; 419 } 420 421 /** 422 * Gets a regex matching the word, if it is at the string start 423 * 424 * @return string 425 */ 426 function getRegexStart() { 427 if ( $this->mRegex == '' ) { 428 $this->initRegex(); 429 } 430 return $this->mRegexStart; 431 } 432 433 /** 434 * Gets a regex matching the word from start to end of a string 435 * 436 * @return string 437 * @since 1.23 438 */ 439 function getRegexStartToEnd() { 440 if ( $this->mRegexStartToEnd == '' ) { 441 $this->initRegex(); 442 } 443 return $this->mRegexStartToEnd; 444 } 445 446 /** 447 * regex without the slashes and what not 448 * 449 * @return string 450 */ 451 function getBaseRegex() { 452 if ( $this->mRegex == '' ) { 453 $this->initRegex(); 454 } 455 return $this->mBaseRegex; 456 } 457 458 /** 459 * Returns true if the text contains the word 460 * 461 * @param string $text 462 * 463 * @return bool 464 */ 465 function match( $text ) { 466 return (bool)preg_match( $this->getRegex(), $text ); 467 } 468 469 /** 470 * Returns true if the text starts with the word 471 * 472 * @param string $text 473 * 474 * @return bool 475 */ 476 function matchStart( $text ) { 477 return (bool)preg_match( $this->getRegexStart(), $text ); 478 } 479 480 /** 481 * Returns true if the text matched the word 482 * 483 * @param string $text 484 * 485 * @return bool 486 * @since 1.23 487 */ 488 function matchStartToEnd( $text ) { 489 return (bool)preg_match( $this->getRegexStartToEnd(), $text ); 490 } 491 492 /** 493 * Returns NULL if there's no match, the value of $1 otherwise 494 * The return code is the matched string, if there's no variable 495 * part in the regex and the matched variable part ($1) if there 496 * is one. 497 * 498 * @param string $text 499 * 500 * @return string 501 */ 502 function matchVariableStartToEnd( $text ) { 503 $matches = array(); 504 $matchcount = preg_match( $this->getVariableStartToEndRegex(), $text, $matches ); 505 if ( $matchcount == 0 ) { 506 return null; 507 } else { 508 # multiple matched parts (variable match); some will be empty because of 509 # synonyms. The variable will be the second non-empty one so remove any 510 # blank elements and re-sort the indices. 511 # See also bug 6526 512 513 $matches = array_values( array_filter( $matches ) ); 514 515 if ( count( $matches ) == 1 ) { 516 return $matches[0]; 517 } else { 518 return $matches[1]; 519 } 520 } 521 } 522 523 /** 524 * Returns true if the text matches the word, and alters the 525 * input string, removing all instances of the word 526 * 527 * @param string $text 528 * 529 * @return bool 530 */ 531 function matchAndRemove( &$text ) { 532 $this->mFound = false; 533 $text = preg_replace_callback( 534 $this->getRegex(), 535 array( &$this, 'pregRemoveAndRecord' ), 536 $text 537 ); 538 539 return $this->mFound; 540 } 541 542 /** 543 * @param string $text 544 * @return bool 545 */ 546 function matchStartAndRemove( &$text ) { 547 $this->mFound = false; 548 $text = preg_replace_callback( 549 $this->getRegexStart(), 550 array( &$this, 'pregRemoveAndRecord' ), 551 $text 552 ); 553 554 return $this->mFound; 555 } 556 557 /** 558 * Used in matchAndRemove() 559 * 560 * @return string 561 */ 562 function pregRemoveAndRecord() { 563 $this->mFound = true; 564 return ''; 565 } 566 567 /** 568 * Replaces the word with something else 569 * 570 * @param string $replacement 571 * @param string $subject 572 * @param int $limit 573 * 574 * @return string 575 */ 576 function replace( $replacement, $subject, $limit = -1 ) { 577 $res = preg_replace( 578 $this->getRegex(), 579 StringUtils::escapeRegexReplacement( $replacement ), 580 $subject, 581 $limit 582 ); 583 $this->mModified = $res !== $subject; 584 return $res; 585 } 586 587 /** 588 * Variable handling: {{SUBST:xxx}} style words 589 * Calls back a function to determine what to replace xxx with 590 * Input word must contain $1 591 * 592 * @param string $text 593 * @param callable $callback 594 * 595 * @return string 596 */ 597 function substituteCallback( $text, $callback ) { 598 $res = preg_replace_callback( $this->getVariableRegex(), $callback, $text ); 599 $this->mModified = $res !== $text; 600 return $res; 601 } 602 603 /** 604 * Matches the word, where $1 is a wildcard 605 * 606 * @return string 607 */ 608 function getVariableRegex() { 609 if ( $this->mVariableRegex == '' ) { 610 $this->initRegex(); 611 } 612 return $this->mVariableRegex; 613 } 614 615 /** 616 * Matches the entire string, where $1 is a wildcard 617 * 618 * @return string 619 */ 620 function getVariableStartToEndRegex() { 621 if ( $this->mVariableStartToEndRegex == '' ) { 622 $this->initRegex(); 623 } 624 return $this->mVariableStartToEndRegex; 625 } 626 627 /** 628 * Accesses the synonym list directly 629 * 630 * @param int $i 631 * 632 * @return string 633 */ 634 function getSynonym( $i ) { 635 return $this->mSynonyms[$i]; 636 } 637 638 /** 639 * @return array 640 */ 641 function getSynonyms() { 642 return $this->mSynonyms; 643 } 644 645 /** 646 * Returns true if the last call to replace() or substituteCallback() 647 * returned a modified text, otherwise false. 648 * 649 * @return bool 650 */ 651 function getWasModified() { 652 return $this->mModified; 653 } 654 655 /** 656 * $magicarr is an associative array of (magic word ID => replacement) 657 * This method uses the php feature to do several replacements at the same time, 658 * thereby gaining some efficiency. The result is placed in the out variable 659 * $result. The return value is true if something was replaced. 660 * @todo Should this be static? It doesn't seem to be used at all 661 * 662 * @param array $magicarr 663 * @param string $subject 664 * @param string $result 665 * 666 * @return bool 667 */ 668 function replaceMultiple( $magicarr, $subject, &$result ) { 669 $search = array(); 670 $replace = array(); 671 foreach ( $magicarr as $id => $replacement ) { 672 $mw = MagicWord::get( $id ); 673 $search[] = $mw->getRegex(); 674 $replace[] = $replacement; 675 } 676 677 $result = preg_replace( $search, $replace, $subject ); 678 return $result !== $subject; 679 } 680 681 /** 682 * Adds all the synonyms of this MagicWord to an array, to allow quick 683 * lookup in a list of magic words 684 * 685 * @param array $array 686 * @param string $value 687 */ 688 function addToArray( &$array, $value ) { 689 global $wgContLang; 690 foreach ( $this->mSynonyms as $syn ) { 691 $array[$wgContLang->lc( $syn )] = $value; 692 } 693 } 694 695 /** 696 * @return bool 697 */ 698 function isCaseSensitive() { 699 return $this->mCaseSensitive; 700 } 701 702 /** 703 * @return int 704 */ 705 function getId() { 706 return $this->mId; 707 } 708 } 709 710 /** 711 * Class for handling an array of magic words 712 * @ingroup Parser 713 */ 714 class MagicWordArray { 715 /** @var array */ 716 public $names = array(); 717 718 /** @var array */ 719 private $hash; 720 721 private $baseRegex; 722 723 private $regex; 724 725 /** @todo Unused? */ 726 private $matches; 727 728 /** 729 * @param array $names 730 */ 731 function __construct( $names = array() ) { 732 $this->names = $names; 733 } 734 735 /** 736 * Add a magic word by name 737 * 738 * @param string $name 739 */ 740 public function add( $name ) { 741 $this->names[] = $name; 742 $this->hash = $this->baseRegex = $this->regex = null; 743 } 744 745 /** 746 * Add a number of magic words by name 747 * 748 * @param array $names 749 */ 750 public function addArray( $names ) { 751 $this->names = array_merge( $this->names, array_values( $names ) ); 752 $this->hash = $this->baseRegex = $this->regex = null; 753 } 754 755 /** 756 * Get a 2-d hashtable for this array 757 * @return array 758 */ 759 function getHash() { 760 if ( is_null( $this->hash ) ) { 761 global $wgContLang; 762 $this->hash = array( 0 => array(), 1 => array() ); 763 foreach ( $this->names as $name ) { 764 $magic = MagicWord::get( $name ); 765 $case = intval( $magic->isCaseSensitive() ); 766 foreach ( $magic->getSynonyms() as $syn ) { 767 if ( !$case ) { 768 $syn = $wgContLang->lc( $syn ); 769 } 770 $this->hash[$case][$syn] = $name; 771 } 772 } 773 } 774 return $this->hash; 775 } 776 777 /** 778 * Get the base regex 779 * @return array 780 */ 781 function getBaseRegex() { 782 if ( is_null( $this->baseRegex ) ) { 783 $this->baseRegex = array( 0 => '', 1 => '' ); 784 foreach ( $this->names as $name ) { 785 $magic = MagicWord::get( $name ); 786 $case = intval( $magic->isCaseSensitive() ); 787 foreach ( $magic->getSynonyms() as $i => $syn ) { 788 // Group name must start with a non-digit in PCRE 8.34+ 789 $it = strtr( $i, '0123456789', 'abcdefghij' ); 790 $group = "(?P<{$it}_{$name}>" . preg_quote( $syn, '/' ) . ')'; 791 if ( $this->baseRegex[$case] === '' ) { 792 $this->baseRegex[$case] = $group; 793 } else { 794 $this->baseRegex[$case] .= '|' . $group; 795 } 796 } 797 } 798 } 799 return $this->baseRegex; 800 } 801 802 /** 803 * Get an unanchored regex that does not match parameters 804 * @return array 805 */ 806 function getRegex() { 807 if ( is_null( $this->regex ) ) { 808 $base = $this->getBaseRegex(); 809 $this->regex = array( '', '' ); 810 if ( $this->baseRegex[0] !== '' ) { 811 $this->regex[0] = "/{$base[0]}/iuS"; 812 } 813 if ( $this->baseRegex[1] !== '' ) { 814 $this->regex[1] = "/{$base[1]}/S"; 815 } 816 } 817 return $this->regex; 818 } 819 820 /** 821 * Get a regex for matching variables with parameters 822 * 823 * @return string 824 */ 825 function getVariableRegex() { 826 return str_replace( "\\$1", "(.*?)", $this->getRegex() ); 827 } 828 829 /** 830 * Get a regex anchored to the start of the string that does not match parameters 831 * 832 * @return array 833 */ 834 function getRegexStart() { 835 $base = $this->getBaseRegex(); 836 $newRegex = array( '', '' ); 837 if ( $base[0] !== '' ) { 838 $newRegex[0] = "/^(?:{$base[0]})/iuS"; 839 } 840 if ( $base[1] !== '' ) { 841 $newRegex[1] = "/^(?:{$base[1]})/S"; 842 } 843 return $newRegex; 844 } 845 846 /** 847 * Get an anchored regex for matching variables with parameters 848 * 849 * @return array 850 */ 851 function getVariableStartToEndRegex() { 852 $base = $this->getBaseRegex(); 853 $newRegex = array( '', '' ); 854 if ( $base[0] !== '' ) { 855 $newRegex[0] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[0]})$/iuS" ); 856 } 857 if ( $base[1] !== '' ) { 858 $newRegex[1] = str_replace( "\\$1", "(.*?)", "/^(?:{$base[1]})$/S" ); 859 } 860 return $newRegex; 861 } 862 863 /** 864 * @since 1.20 865 * @return array 866 */ 867 public function getNames() { 868 return $this->names; 869 } 870 871 /** 872 * Parse a match array from preg_match 873 * Returns array(magic word ID, parameter value) 874 * If there is no parameter value, that element will be false. 875 * 876 * @param array $m 877 * 878 * @throws MWException 879 * @return array 880 */ 881 function parseMatch( $m ) { 882 reset( $m ); 883 while ( list( $key, $value ) = each( $m ) ) { 884 if ( $key === 0 || $value === '' ) { 885 continue; 886 } 887 $parts = explode( '_', $key, 2 ); 888 if ( count( $parts ) != 2 ) { 889 // This shouldn't happen 890 // continue; 891 throw new MWException( __METHOD__ . ': bad parameter name' ); 892 } 893 list( /* $synIndex */, $magicName ) = $parts; 894 $paramValue = next( $m ); 895 return array( $magicName, $paramValue ); 896 } 897 // This shouldn't happen either 898 throw new MWException( __METHOD__ . ': parameter not found' ); 899 } 900 901 /** 902 * Match some text, with parameter capture 903 * Returns an array with the magic word name in the first element and the 904 * parameter in the second element. 905 * Both elements are false if there was no match. 906 * 907 * @param string $text 908 * 909 * @return array 910 */ 911 public function matchVariableStartToEnd( $text ) { 912 $regexes = $this->getVariableStartToEndRegex(); 913 foreach ( $regexes as $regex ) { 914 if ( $regex !== '' ) { 915 $m = array(); 916 if ( preg_match( $regex, $text, $m ) ) { 917 return $this->parseMatch( $m ); 918 } 919 } 920 } 921 return array( false, false ); 922 } 923 924 /** 925 * Match some text, without parameter capture 926 * Returns the magic word name, or false if there was no capture 927 * 928 * @param string $text 929 * 930 * @return string|bool False on failure 931 */ 932 public function matchStartToEnd( $text ) { 933 $hash = $this->getHash(); 934 if ( isset( $hash[1][$text] ) ) { 935 return $hash[1][$text]; 936 } 937 global $wgContLang; 938 $lc = $wgContLang->lc( $text ); 939 if ( isset( $hash[0][$lc] ) ) { 940 return $hash[0][$lc]; 941 } 942 return false; 943 } 944 945 /** 946 * Returns an associative array, ID => param value, for all items that match 947 * Removes the matched items from the input string (passed by reference) 948 * 949 * @param string $text 950 * 951 * @return array 952 */ 953 public function matchAndRemove( &$text ) { 954 $found = array(); 955 $regexes = $this->getRegex(); 956 foreach ( $regexes as $regex ) { 957 if ( $regex === '' ) { 958 continue; 959 } 960 preg_match_all( $regex, $text, $matches, PREG_SET_ORDER ); 961 foreach ( $matches as $m ) { 962 list( $name, $param ) = $this->parseMatch( $m ); 963 $found[$name] = $param; 964 } 965 $text = preg_replace( $regex, '', $text ); 966 } 967 return $found; 968 } 969 970 /** 971 * Return the ID of the magic word at the start of $text, and remove 972 * the prefix from $text. 973 * Return false if no match found and $text is not modified. 974 * Does not match parameters. 975 * 976 * @param string $text 977 * 978 * @return int|bool False on failure 979 */ 980 public function matchStartAndRemove( &$text ) { 981 $regexes = $this->getRegexStart(); 982 foreach ( $regexes as $regex ) { 983 if ( $regex === '' ) { 984 continue; 985 } 986 if ( preg_match( $regex, $text, $m ) ) { 987 list( $id, ) = $this->parseMatch( $m ); 988 if ( strlen( $m[0] ) >= strlen( $text ) ) { 989 $text = ''; 990 } else { 991 $text = substr( $text, strlen( $m[0] ) ); 992 } 993 return $id; 994 } 995 } 996 return false; 997 } 998 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |