11 $wgMagicFound = false;
13 /** Actual keyword to be used is set in Language.php */
20 'MAG_CURRENTMONTHNAME',
21 'MAG_CURRENTMONTHNAMEGEN',
22 'MAG_CURRENTMONTHABBREV',
28 'MAG_NUMBEROFARTICLES',
55 'MAG_NOCONTENTCONVERT',
62 'MAG_IMG_MANUALTHUMB',
82 'MAG_SUBJECTPAGENAME',
83 'MAG_SUBJECTPAGENAMEE',
92 'MAG_CURRENTTIMESTAMP',
95 'MAG_CONTENTLANGUAGE',
96 'MAG_PAGESINNAMESPACE',
100 if ( ! defined( 'MEDIAWIKI_INSTALL' ) )
101 wfRunHooks( 'MagicWordMagicWords', array( &$magicWords ) );
103 for ( $i = 0; $i < count( $magicWords ); ++
$i )
104 define( $magicWords[$i], $i );
106 $wgVariableIDs = array(
108 MAG_CURRENTMONTHNAME
,
109 MAG_CURRENTMONTHNAMEGEN
,
110 MAG_CURRENTMONTHABBREV
,
116 MAG_NUMBEROFARTICLES
,
141 MAG_SUBJECTPAGENAMEE
,
150 MAG_CURRENTTIMESTAMP
,
154 MAG_PAGESINNAMESPACE
,
157 if ( ! defined( 'MEDIAWIKI_INSTALL' ) )
158 wfRunHooks( 'MagicWordwgVariableIDs', array( &$wgVariableIDs ) );
161 * This class encapsulates "magic words" such as #redirect, __NOTOC__, etc.
163 * if (MagicWord::get( MAG_REDIRECT )->match( $text ) )
165 * Possible future improvements:
166 * * Simultaneous searching for a number of magic words
167 * * $wgMagicWords in shared memory
169 * Please avoid reading the data out of one of these objects and then writing
170 * special case code. If possible, add another match()-like function here.
178 var $mId, $mSynonyms, $mCaseSensitive, $mRegex;
179 var $mRegexStart, $mBaseRegex, $mVariableRegex;
183 function MagicWord($id = 0, $syn = '', $cs = false) {
185 $this->mSynonyms
= (array)$syn;
186 $this->mCaseSensitive
= $cs;
188 $this->mRegexStart
= '';
189 $this->mVariableRegex
= '';
190 $this->mVariableStartToEndRegex
= '';
191 $this->mModified
= false;
195 * Factory: creates an object representing an ID
198 function &get( $id ) {
199 global $wgMagicWords;
201 if ( !is_array( $wgMagicWords ) ) {
202 throw new MWException( "Incorrect initialisation order, \$wgMagicWords does not exist\n" );
204 if (!array_key_exists( $id, $wgMagicWords ) ) {
205 $mw = new MagicWord();
207 $wgMagicWords[$id] = $mw;
209 return $wgMagicWords[$id];
212 # Initialises this object with an ID
213 function load( $id ) {
216 $wgContLang->getMagic( $this );
220 * Preliminary initialisation
223 function initRegex() {
224 #$variableClass = Title::legalChars();
225 # This was used for matching "$1" variables, but different uses of the feature will have
226 # different restrictions, which should be checked *after* the MagicWord has been matched,
230 foreach ( $this->mSynonyms
as $synonym )
231 // In case a magic word contains /, like that's going to happen;)
232 $escSyn[] = preg_quote( $synonym, '/' );
233 $this->mBaseRegex
= implode( '|', $escSyn );
235 $case = $this->mCaseSensitive ?
'' : 'i';
236 $this->mRegex
= "/{$this->mBaseRegex}/{$case}";
237 $this->mRegexStart
= "/^(?:{$this->mBaseRegex})/{$case}";
238 $this->mVariableRegex
= str_replace( "\\$1", "(.*?)", $this->mRegex
);
239 $this->mVariableStartToEndRegex
= str_replace( "\\$1", "(.*?)",
240 "/^(?:{$this->mBaseRegex})$/{$case}" );
244 * Gets a regex representing matching the word
246 function getRegex() {
247 if ($this->mRegex
== '' ) {
250 return $this->mRegex
;
254 * Gets the regexp case modifier to use, i.e. i or nothing, to be used if
255 * one is using MagicWord::getBaseRegex(), otherwise it'll be included in
256 * the complete expression
258 function getRegexCase() {
259 if ( $this->mRegex
=== '' )
262 return $this->mCaseSensitive ?
'' : 'i';
266 * Gets a regex matching the word, if it is at the string start
268 function getRegexStart() {
269 if ($this->mRegex
== '' ) {
272 return $this->mRegexStart
;
276 * regex without the slashes and what not
278 function getBaseRegex() {
279 if ($this->mRegex
== '') {
282 return $this->mBaseRegex
;
286 * Returns true if the text contains the word
289 function match( $text ) {
290 return preg_match( $this->getRegex(), $text );
294 * Returns true if the text starts with the word
297 function matchStart( $text ) {
298 return preg_match( $this->getRegexStart(), $text );
302 * Returns NULL if there's no match, the value of $1 otherwise
303 * The return code is the matched string, if there's no variable
304 * part in the regex and the matched variable part ($1) if there
307 function matchVariableStartToEnd( $text ) {
309 $matchcount = preg_match( $this->getVariableStartToEndRegex(), $text, $matches );
310 if ( $matchcount == 0 ) {
312 } elseif ( count($matches) == 1 ) {
315 # multiple matched parts (variable match); some will be empty because of synonyms
316 # the variable will be the second non-empty one so remove any blank elements and re-sort the indices
317 $matches = array_values(array_filter($matches));
324 * Returns true if the text matches the word, and alters the
325 * input string, removing all instances of the word
327 function matchAndRemove( &$text ) {
328 global $wgMagicFound;
329 $wgMagicFound = false;
330 $text = preg_replace_callback( $this->getRegex(), 'pregRemoveAndRecord', $text );
331 return $wgMagicFound;
334 function matchStartAndRemove( &$text ) {
335 global $wgMagicFound;
336 $wgMagicFound = false;
337 $text = preg_replace_callback( $this->getRegexStart(), 'pregRemoveAndRecord', $text );
338 return $wgMagicFound;
343 * Replaces the word with something else
345 function replace( $replacement, $subject, $limit=-1 ) {
346 $res = preg_replace( $this->getRegex(), wfRegexReplacement( $replacement ), $subject, $limit );
347 $this->mModified
= !($res === $subject);
352 * Variable handling: {{SUBST:xxx}} style words
353 * Calls back a function to determine what to replace xxx with
354 * Input word must contain $1
356 function substituteCallback( $text, $callback ) {
357 $res = preg_replace_callback( $this->getVariableRegex(), $callback, $text );
358 $this->mModified
= !($res === $text);
363 * Matches the word, where $1 is a wildcard
365 function getVariableRegex() {
366 if ( $this->mVariableRegex
== '' ) {
369 return $this->mVariableRegex
;
373 * Matches the entire string, where $1 is a wildcard
375 function getVariableStartToEndRegex() {
376 if ( $this->mVariableStartToEndRegex
== '' ) {
379 return $this->mVariableStartToEndRegex
;
383 * Accesses the synonym list directly
385 function getSynonym( $i ) {
386 return $this->mSynonyms
[$i];
390 * Returns true if the last call to replace() or substituteCallback()
391 * returned a modified text, otherwise false.
393 function getWasModified(){
394 return $this->mModified
;
398 * $magicarr is an associative array of (magic word ID => replacement)
399 * This method uses the php feature to do several replacements at the same time,
400 * thereby gaining some efficiency. The result is placed in the out variable
401 * $result. The return value is true if something was replaced.
404 function replaceMultiple( $magicarr, $subject, &$result ){
407 foreach( $magicarr as $id => $replacement ){
408 $mw = MagicWord
::get( $id );
409 $search[] = $mw->getRegex();
410 $replace[] = $replacement;
413 $result = preg_replace( $search, $replace, $subject );
414 return !($result === $subject);
418 * Adds all the synonyms of this MagicWord to an array, to allow quick
419 * lookup in a list of magic words
421 function addToArray( &$array, $value ) {
422 foreach ( $this->mSynonyms
as $syn ) {
423 $array[$syn] = $value;
429 * Used in matchAndRemove()
432 function pregRemoveAndRecord( $match ) {
433 global $wgMagicFound;
434 $wgMagicFound = true;