MediaWiki master
StripState.php
Go to the documentation of this file.
1<?php
24namespace MediaWiki\Parser;
25
26use Closure;
27use InvalidArgumentException;
28
36 protected $data;
38 protected $regex;
39
40 protected ?Parser $parser;
41
45 protected $depth = 0;
47 protected $highestDepth = 0;
49 protected $expandSize = 0;
50
52 protected $depthLimit = 20;
54 protected $sizeLimit = 5_000_000;
55
62 public function __construct( ?Parser $parser = null, $options = [] ) {
63 $this->data = [
64 'nowiki' => [],
65 'general' => []
66 ];
67 $this->regex = '/' . Parser::MARKER_PREFIX . "([^\x7f<>&'\"]+)" . Parser::MARKER_SUFFIX . '/';
68 $this->circularRefGuard = [];
69 $this->parser = $parser;
70
71 if ( isset( $options['depthLimit'] ) ) {
72 $this->depthLimit = $options['depthLimit'];
73 }
74 if ( isset( $options['sizeLimit'] ) ) {
75 $this->sizeLimit = $options['sizeLimit'];
76 }
77 }
78
84 public function addNoWiki( $marker, $value ) {
85 $this->addItem( 'nowiki', $marker, $value );
86 }
87
92 public function addGeneral( $marker, $value ) {
93 $this->addItem( 'general', $marker, $value );
94 }
95
104 protected function addItem( $type, $marker, $value ) {
105 if ( !preg_match( $this->regex, $marker, $m ) ) {
106 throw new InvalidArgumentException( "Invalid marker: $marker" );
107 }
108
109 $this->data[$type][$m[1]] = $value;
110 }
111
116 public function unstripGeneral( $text ) {
117 return $this->unstripType( 'general', $text );
118 }
119
124 public function unstripNoWiki( $text ) {
125 return $this->unstripType( 'nowiki', $text );
126 }
127
133 public function replaceNoWikis( string $text, callable $callback ): string {
134 // Shortcut
135 if ( !count( $this->data['nowiki'] ) ) {
136 return $text;
137 }
138
139 $callback = function ( $m ) use ( $callback ) {
140 $marker = $m[1];
141 if ( isset( $this->data['nowiki'][$marker] ) ) {
142 $value = $this->data['nowiki'][$marker];
143 if ( $value instanceof Closure ) {
144 $value = $value();
145 }
146
147 $this->expandSize += strlen( $value );
148 if ( $this->expandSize > $this->sizeLimit ) {
149 return $this->getLimitationWarning( 'unstrip-size', $this->sizeLimit );
150 }
151
152 return call_user_func( $callback, $value );
153 } else {
154 return $m[0];
155 }
156 };
157
158 return preg_replace_callback( $this->regex, $callback, $text );
159 }
160
165 public function unstripBoth( $text ) {
166 $text = $this->unstripType( 'general', $text );
167 $text = $this->unstripType( 'nowiki', $text );
168 return $text;
169 }
170
176 protected function unstripType( $type, $text ) {
177 // Shortcut
178 if ( !count( $this->data[$type] ) ) {
179 return $text;
180 }
181
182 $callback = function ( $m ) use ( $type ) {
183 $marker = $m[1];
184 if ( isset( $this->data[$type][$marker] ) ) {
185 if ( isset( $this->circularRefGuard[$marker] ) ) {
186 return $this->getWarning( 'parser-unstrip-loop-warning' );
187 }
188
189 if ( $this->depth > $this->highestDepth ) {
190 $this->highestDepth = $this->depth;
191 }
192 if ( $this->depth >= $this->depthLimit ) {
193 return $this->getLimitationWarning( 'unstrip-depth', $this->depthLimit );
194 }
195
196 $value = $this->data[$type][$marker];
197 if ( $value instanceof Closure ) {
198 $value = $value();
199 }
200
201 $this->expandSize += strlen( $value );
202 if ( $this->expandSize > $this->sizeLimit ) {
203 return $this->getLimitationWarning( 'unstrip-size', $this->sizeLimit );
204 }
205
206 $this->circularRefGuard[$marker] = true;
207 $this->depth++;
208 $ret = $this->unstripType( $type, $value );
209 $this->depth--;
210 unset( $this->circularRefGuard[$marker] );
211
212 return $ret;
213 } else {
214 return $m[0];
215 }
216 };
217
218 $text = preg_replace_callback( $this->regex, $callback, $text );
219 return $text;
220 }
221
229 private function getLimitationWarning( $type, $max = '' ) {
230 if ( $this->parser ) {
231 $this->parser->limitationWarn( $type, $max );
232 }
233 return $this->getWarning( "$type-warning", $max );
234 }
235
243 private function getWarning( $message, $max = '' ) {
244 return '<span class="error">' .
245 wfMessage( $message )
246 ->numParams( $max )->inContentLanguage()->text() .
247 '</span>';
248 }
249
256 public function getLimitReport() {
257 return [
258 [ 'limitreport-unstrip-depth',
259 [
260 $this->highestDepth,
261 $this->depthLimit
262 ],
263 ],
264 [ 'limitreport-unstrip-size',
265 [
266 $this->expandSize,
267 $this->sizeLimit
268 ],
269 ]
270 ];
271 }
272
279 public function killMarkers( $text ) {
280 return preg_replace( $this->regex, '', $text );
281 }
282}
283
285class_alias( StripState::class, 'StripState' );
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:81
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition Parser.php:143
addNoWiki( $marker, $value)
Add a nowiki strip item.
__construct(?Parser $parser=null, $options=[])
replaceNoWikis(string $text, callable $callback)
killMarkers( $text)
Remove any strip markers found in the given text.
getLimitReport()
Get an array of parameters to pass to ParserOutput::setLimitReportData()
addGeneral( $marker, $value)
addItem( $type, $marker, $value)