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',
77 if ( ! defined( 'MEDIAWIKI_INSTALL' ) )
78 wfRunHooks( 'MagicWordMagicWords', array( &$magicWords ) );
80 for ( $i = 0; $i < count( $magicWords ); ++
$i )
81 define( $magicWords[$i], $i );
83 $wgVariableIDs = array(
86 MAG_CURRENTMONTHNAMEGEN
,
87 MAG_CURRENTMONTHABBREV
,
112 if ( ! defined( 'MEDIAWIKI_INSTALL' ) )
113 wfRunHooks( 'MagicWordwgVariableIDs', array( &$wgVariableIDs ) );
116 * This class encapsulates "magic words" such as #redirect, __NOTOC__, etc.
118 * if (MagicWord::get( MAG_REDIRECT )->match( $text ) )
120 * Possible future improvements:
121 * * Simultaneous searching for a number of magic words
122 * * $wgMagicWords in shared memory
124 * Please avoid reading the data out of one of these objects and then writing
125 * special case code. If possible, add another match()-like function here.
133 var $mId, $mSynonyms, $mCaseSensitive, $mRegex;
134 var $mRegexStart, $mBaseRegex, $mVariableRegex;
138 function MagicWord($id = 0, $syn = '', $cs = false) {
140 $this->mSynonyms
= (array)$syn;
141 $this->mCaseSensitive
= $cs;
143 $this->mRegexStart
= '';
144 $this->mVariableRegex
= '';
145 $this->mVariableStartToEndRegex
= '';
146 $this->mModified
= false;
150 * Factory: creates an object representing an ID
153 function &get( $id ) {
154 global $wgMagicWords;
156 if ( !is_array( $wgMagicWords ) ) {
157 wfDebugDieBacktrace( "Incorrect initialisation order, \$wgMagicWords does not exist\n" );
159 if (!array_key_exists( $id, $wgMagicWords ) ) {
160 $mw = new MagicWord();
162 $wgMagicWords[$id] = $mw;
164 return $wgMagicWords[$id];
167 # Initialises this object with an ID
168 function load( $id ) {
171 $wgContLang->getMagic( $this );
175 * Preliminary initialisation
178 function initRegex() {
179 #$variableClass = Title::legalChars();
180 # This was used for matching "$1" variables, but different uses of the feature will have
181 # different restrictions, which should be checked *after* the MagicWord has been matched,
185 foreach ( $this->mSynonyms
as $synonym )
186 // In case a magic word contains /, like that's going to happen;)
187 $escSyn[] = preg_quote( $synonym, '/' );
188 $this->mBaseRegex
= implode( '|', $escSyn );
190 $case = $this->mCaseSensitive ?
'' : 'i';
191 $this->mRegex
= "/{$this->mBaseRegex}/{$case}";
192 $this->mRegexStart
= "/^(?:{$this->mBaseRegex})/{$case}";
193 $this->mVariableRegex
= str_replace( "\\$1", "(.*?)", $this->mRegex
);
194 $this->mVariableStartToEndRegex
= str_replace( "\\$1", "(.*?)",
195 "/^(?:{$this->mBaseRegex})$/{$case}" );
199 * Gets a regex representing matching the word
201 function getRegex() {
202 if ($this->mRegex
== '' ) {
205 return $this->mRegex
;
209 * Gets the regexp case modifier to use, i.e. i or nothing, to be used if
210 * one is using MagicWord::getBaseRegex(), otherwise it'll be included in
211 * the complete expression
213 function getRegexCase() {
214 if ( $this->mRegex
=== '' )
217 return $this->mCaseSensitive ?
'' : 'i';
221 * Gets a regex matching the word, if it is at the string start
223 function getRegexStart() {
224 if ($this->mRegex
== '' ) {
227 return $this->mRegexStart
;
231 * regex without the slashes and what not
233 function getBaseRegex() {
234 if ($this->mRegex
== '') {
237 return $this->mBaseRegex
;
241 * Returns true if the text contains the word
244 function match( $text ) {
245 return preg_match( $this->getRegex(), $text );
249 * Returns true if the text starts with the word
252 function matchStart( $text ) {
253 return preg_match( $this->getRegexStart(), $text );
257 * Returns NULL if there's no match, the value of $1 otherwise
258 * The return code is the matched string, if there's no variable
259 * part in the regex and the matched variable part ($1) if there
262 function matchVariableStartToEnd( $text ) {
264 $matchcount = preg_match( $this->getVariableStartToEndRegex(), $text, $matches );
265 if ( $matchcount == 0 ) {
267 } elseif ( count($matches) == 1 ) {
270 # multiple matched parts (variable match); some will be empty because of synonyms
271 # the variable will be the second non-empty one so remove any blank elements and re-sort the indices
272 $matches = array_values(array_filter($matches));
279 * Returns true if the text matches the word, and alters the
280 * input string, removing all instances of the word
282 function matchAndRemove( &$text ) {
283 global $wgMagicFound;
284 $wgMagicFound = false;
285 $text = preg_replace_callback( $this->getRegex(), 'pregRemoveAndRecord', $text );
286 return $wgMagicFound;
289 function matchStartAndRemove( &$text ) {
290 global $wgMagicFound;
291 $wgMagicFound = false;
292 $text = preg_replace_callback( $this->getRegexStart(), 'pregRemoveAndRecord', $text );
293 return $wgMagicFound;
298 * Replaces the word with something else
300 function replace( $replacement, $subject ) {
301 $res = preg_replace( $this->getRegex(), wfRegexReplacement( $replacement ), $subject );
302 $this->mModified
= !($res === $subject);
307 * Variable handling: {{SUBST:xxx}} style words
308 * Calls back a function to determine what to replace xxx with
309 * Input word must contain $1
311 function substituteCallback( $text, $callback ) {
312 $res = preg_replace_callback( $this->getVariableRegex(), $callback, $text );
313 $this->mModified
= !($res === $text);
318 * Matches the word, where $1 is a wildcard
320 function getVariableRegex() {
321 if ( $this->mVariableRegex
== '' ) {
324 return $this->mVariableRegex
;
328 * Matches the entire string, where $1 is a wildcard
330 function getVariableStartToEndRegex() {
331 if ( $this->mVariableStartToEndRegex
== '' ) {
334 return $this->mVariableStartToEndRegex
;
338 * Accesses the synonym list directly
340 function getSynonym( $i ) {
341 return $this->mSynonyms
[$i];
345 * Returns true if the last call to replace() or substituteCallback()
346 * returned a modified text, otherwise false.
348 function getWasModified(){
349 return $this->mModified
;
353 * $magicarr is an associative array of (magic word ID => replacement)
354 * This method uses the php feature to do several replacements at the same time,
355 * thereby gaining some efficiency. The result is placed in the out variable
356 * $result. The return value is true if something was replaced.
359 function replaceMultiple( $magicarr, $subject, &$result ){
362 foreach( $magicarr as $id => $replacement ){
363 $mw = MagicWord
::get( $id );
364 $search[] = $mw->getRegex();
365 $replace[] = $replacement;
368 $result = preg_replace( $search, $replace, $subject );
369 return !($result === $subject);
373 * Adds all the synonyms of this MagicWord to an array, to allow quick
374 * lookup in a list of magic words
376 function addToArray( &$array, $value ) {
377 foreach ( $this->mSynonyms
as $syn ) {
378 $array[$syn] = $value;
384 * Used in matchAndRemove()
387 function pregRemoveAndRecord( $match ) {
388 global $wgMagicFound;
389 $wgMagicFound = true;