MediaWiki  master
StripState.php
Go to the documentation of this file.
1 <?php
29 class StripState {
30  protected $data;
31  protected $regex;
32 
33  protected $parser;
34 
35  protected $circularRefGuard;
36  protected $depth = 0;
37  protected $highestDepth = 0;
38  protected $expandSize = 0;
39 
40  protected $depthLimit = 20;
41  protected $sizeLimit = 5000000;
42 
49  public function __construct( Parser $parser = null, $options = [] ) {
50  $this->data = [
51  'nowiki' => [],
52  'general' => []
53  ];
54  $this->regex = '/' . Parser::MARKER_PREFIX . "([^\x7f<>&'\"]+)" . Parser::MARKER_SUFFIX . '/';
55  $this->circularRefGuard = [];
56  $this->parser = $parser;
57 
58  if ( isset( $options['depthLimit'] ) ) {
59  $this->depthLimit = $options['depthLimit'];
60  }
61  if ( isset( $options['sizeLimit'] ) ) {
62  $this->sizeLimit = $options['sizeLimit'];
63  }
64  }
65 
71  public function addNoWiki( $marker, $value ) {
72  $this->addItem( 'nowiki', $marker, $value );
73  }
74 
79  public function addGeneral( $marker, $value ) {
80  $this->addItem( 'general', $marker, $value );
81  }
82 
89  protected function addItem( $type, $marker, $value ) {
90  if ( !preg_match( $this->regex, $marker, $m ) ) {
91  throw new MWException( "Invalid marker: $marker" );
92  }
93 
94  $this->data[$type][$m[1]] = $value;
95  }
96 
101  public function unstripGeneral( $text ) {
102  return $this->unstripType( 'general', $text );
103  }
104 
109  public function unstripNoWiki( $text ) {
110  return $this->unstripType( 'nowiki', $text );
111  }
112 
118  public function replaceNoWikis( string $text, callable $callback ): string {
119  // Shortcut
120  if ( !count( $this->data['nowiki'] ) ) {
121  return $text;
122  }
123 
124  $callback = function ( $m ) use ( $callback ) {
125  $marker = $m[1];
126  if ( isset( $this->data['nowiki'][$marker] ) ) {
127  $value = $this->data['nowiki'][$marker];
128  if ( $value instanceof Closure ) {
129  $value = $value();
130  }
131 
132  $this->expandSize += strlen( $value );
133  if ( $this->expandSize > $this->sizeLimit ) {
134  return $this->getLimitationWarning( 'unstrip-size', $this->sizeLimit );
135  }
136 
137  return call_user_func( $callback, $value );
138  } else {
139  return $m[0];
140  }
141  };
142 
143  return preg_replace_callback( $this->regex, $callback, $text );
144  }
145 
150  public function unstripBoth( $text ) {
151  $text = $this->unstripType( 'general', $text );
152  $text = $this->unstripType( 'nowiki', $text );
153  return $text;
154  }
155 
161  protected function unstripType( $type, $text ) {
162  // Shortcut
163  if ( !count( $this->data[$type] ) ) {
164  return $text;
165  }
166 
167  $callback = function ( $m ) use ( $type ) {
168  $marker = $m[1];
169  if ( isset( $this->data[$type][$marker] ) ) {
170  if ( isset( $this->circularRefGuard[$marker] ) ) {
171  return $this->getWarning( 'parser-unstrip-loop-warning' );
172  }
173 
174  if ( $this->depth > $this->highestDepth ) {
175  $this->highestDepth = $this->depth;
176  }
177  if ( $this->depth >= $this->depthLimit ) {
178  return $this->getLimitationWarning( 'unstrip-depth', $this->depthLimit );
179  }
180 
181  $value = $this->data[$type][$marker];
182  if ( $value instanceof Closure ) {
183  $value = $value();
184  }
185 
186  $this->expandSize += strlen( $value );
187  if ( $this->expandSize > $this->sizeLimit ) {
188  return $this->getLimitationWarning( 'unstrip-size', $this->sizeLimit );
189  }
190 
191  $this->circularRefGuard[$marker] = true;
192  $this->depth++;
193  $ret = $this->unstripType( $type, $value );
194  $this->depth--;
195  unset( $this->circularRefGuard[$marker] );
196 
197  return $ret;
198  } else {
199  return $m[0];
200  }
201  };
202 
203  $text = preg_replace_callback( $this->regex, $callback, $text );
204  return $text;
205  }
206 
214  private function getLimitationWarning( $type, $max = '' ) {
215  if ( $this->parser ) {
216  $this->parser->limitationWarn( $type, $max );
217  }
218  return $this->getWarning( "$type-warning", $max );
219  }
220 
228  private function getWarning( $message, $max = '' ) {
229  return '<span class="error">' .
230  wfMessage( $message )
231  ->numParams( $max )->inContentLanguage()->text() .
232  '</span>';
233  }
234 
241  public function getLimitReport() {
242  return [
243  [ 'limitreport-unstrip-depth',
244  [
245  $this->highestDepth,
246  $this->depthLimit
247  ],
248  ],
249  [ 'limitreport-unstrip-size',
250  [
251  $this->expandSize,
252  $this->sizeLimit
253  ],
254  ]
255  ];
256  }
257 
264  public function killMarkers( $text ) {
265  return preg_replace( $this->regex, '', $text );
266  }
267 }
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
Definition: WebStart.php:88
MediaWiki exception.
Definition: MWException.php:32
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition: Parser.php:107
const MARKER_PREFIX
Definition: Parser.php:165
unstripBoth( $text)
Definition: StripState.php:150
unstripGeneral( $text)
Definition: StripState.php:101
addNoWiki( $marker, $value)
Add a nowiki strip item.
Definition: StripState.php:71
getLimitReport()
Get an array of parameters to pass to ParserOutput::setLimitReportData()
Definition: StripState.php:241
unstripType( $type, $text)
Definition: StripState.php:161
replaceNoWikis(string $text, callable $callback)
Definition: StripState.php:118
addGeneral( $marker, $value)
Definition: StripState.php:79
killMarkers( $text)
Remove any strip markers found in the given text.
Definition: StripState.php:264
addItem( $type, $marker, $value)
Definition: StripState.php:89
__construct(Parser $parser=null, $options=[])
Definition: StripState.php:49
unstripNoWiki( $text)
Definition: StripState.php:109