Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 131 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
SpecialExpandTemplates | |
0.00% |
0 / 130 |
|
0.00% |
0 / 7 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
110 | |||
onSubmitInput | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
makeForm | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
2 | |||
makeOutput | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
showHtmlPreview | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
42 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** |
3 | * Implements Special:ExpandTemplates |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup SpecialPage |
22 | */ |
23 | |
24 | namespace MediaWiki\Specials; |
25 | |
26 | use MediaWiki\Html\Html; |
27 | use MediaWiki\HTMLForm\HTMLForm; |
28 | use MediaWiki\MainConfigNames; |
29 | use MediaWiki\Output\OutputPage; |
30 | use MediaWiki\Parser\Parser; |
31 | use MediaWiki\Parser\ParserOutput; |
32 | use MediaWiki\SpecialPage\SpecialPage; |
33 | use MediaWiki\Status\Status; |
34 | use MediaWiki\Tidy\TidyDriverBase; |
35 | use MediaWiki\Title\Title; |
36 | use MediaWiki\User\Options\UserOptionsLookup; |
37 | use ParserFactory; |
38 | use ParserOptions; |
39 | use Xml; |
40 | |
41 | /** |
42 | * A special page that expands submitted templates, parser functions, |
43 | * and variables, allowing easier debugging of these. |
44 | * |
45 | * @ingroup SpecialPage |
46 | */ |
47 | class SpecialExpandTemplates extends SpecialPage { |
48 | |
49 | /** @var int Maximum size in bytes to include. 50 MB allows fixing those huge pages */ |
50 | private const MAX_INCLUDE_SIZE = 50_000_000; |
51 | |
52 | private ParserFactory $parserFactory; |
53 | private UserOptionsLookup $userOptionsLookup; |
54 | private TidyDriverBase $tidy; |
55 | |
56 | /** |
57 | * @param ParserFactory $parserFactory |
58 | * @param UserOptionsLookup $userOptionsLookup |
59 | * @param TidyDriverBase $tidy |
60 | */ |
61 | public function __construct( |
62 | ParserFactory $parserFactory, |
63 | UserOptionsLookup $userOptionsLookup, |
64 | TidyDriverBase $tidy |
65 | ) { |
66 | parent::__construct( 'ExpandTemplates' ); |
67 | $this->parserFactory = $parserFactory; |
68 | $this->userOptionsLookup = $userOptionsLookup; |
69 | $this->tidy = $tidy; |
70 | } |
71 | |
72 | /** |
73 | * Show the special page |
74 | * @param string|null $subpage |
75 | */ |
76 | public function execute( $subpage ) { |
77 | $this->setHeaders(); |
78 | $this->addHelpLink( 'Help:ExpandTemplates' ); |
79 | |
80 | $request = $this->getRequest(); |
81 | $input = $request->getText( 'wpInput' ); |
82 | |
83 | if ( strlen( $input ) ) { |
84 | $removeComments = $request->getBool( 'wpRemoveComments', false ); |
85 | $removeNowiki = $request->getBool( 'wpRemoveNowiki', false ); |
86 | $generateXML = $request->getBool( 'wpGenerateXml' ); |
87 | $generateRawHtml = $request->getBool( 'wpGenerateRawHtml' ); |
88 | |
89 | $options = ParserOptions::newFromContext( $this->getContext() ); |
90 | $options->setRemoveComments( $removeComments ); |
91 | $options->setMaxIncludeSize( self::MAX_INCLUDE_SIZE ); |
92 | |
93 | $titleStr = $request->getText( 'wpContextTitle' ); |
94 | $title = Title::newFromText( $titleStr ); |
95 | if ( !$title ) { |
96 | $title = $this->getPageTitle(); |
97 | $options->setTargetLanguage( $this->getContentLanguage() ); |
98 | } |
99 | |
100 | $parser = $this->parserFactory->getInstance(); |
101 | if ( $generateXML ) { |
102 | $parser->startExternalParse( $title, $options, Parser::OT_PREPROCESS ); |
103 | $dom = $parser->preprocessToDom( $input ); |
104 | |
105 | if ( method_exists( $dom, 'saveXML' ) ) { |
106 | // @phan-suppress-next-line PhanUndeclaredMethod |
107 | $xml = $dom->saveXML(); |
108 | } else { |
109 | // @phan-suppress-next-line PhanUndeclaredMethod |
110 | $xml = $dom->__toString(); |
111 | } |
112 | } |
113 | |
114 | $output = $parser->preprocess( $input, $title, $options ); |
115 | $this->makeForm(); |
116 | |
117 | $out = $this->getOutput(); |
118 | if ( $generateXML && strlen( $output ) > 0 ) { |
119 | // @phan-suppress-next-line PhanPossiblyUndeclaredVariable xml is set when used |
120 | $out->addHTML( $this->makeOutput( $xml, 'expand_templates_xml_output' ) ); |
121 | } |
122 | |
123 | $tmp = $this->makeOutput( $output ); |
124 | |
125 | if ( $removeNowiki ) { |
126 | $tmp = preg_replace( |
127 | [ '_<nowiki>_', '_</nowiki>_', '_<nowiki */>_' ], |
128 | '', |
129 | $tmp |
130 | ); |
131 | } |
132 | |
133 | $tmp = $this->tidy->tidy( $tmp ); |
134 | |
135 | $out->addHTML( $tmp ); |
136 | |
137 | $pout = $parser->parse( $output, $title, $options ); |
138 | $rawhtml = $pout->getText( [ 'enableSectionEditLinks' => false ] ); |
139 | if ( $generateRawHtml && strlen( $rawhtml ) > 0 ) { |
140 | // @phan-suppress-next-line SecurityCheck-DoubleEscaped Wanted here to display the html |
141 | $out->addHTML( $this->makeOutput( $rawhtml, 'expand_templates_html_output' ) ); |
142 | } |
143 | |
144 | $this->showHtmlPreview( $title, $pout, $out ); |
145 | } else { |
146 | $this->makeForm(); |
147 | } |
148 | } |
149 | |
150 | /** |
151 | * Callback for the HTMLForm used in self::makeForm. |
152 | * Checks, if the input was given, and if not, returns a fatal Status |
153 | * object with an error message. |
154 | * |
155 | * @param array $values The values submitted to the HTMLForm |
156 | * @return Status |
157 | */ |
158 | public function onSubmitInput( array $values ) { |
159 | $status = Status::newGood(); |
160 | if ( !strlen( $values['Input'] ) ) { |
161 | $status = Status::newFatal( 'expand_templates_input_missing' ); |
162 | } |
163 | return $status; |
164 | } |
165 | |
166 | /** |
167 | * Generate a form allowing users to enter information |
168 | */ |
169 | private function makeForm() { |
170 | $fields = [ |
171 | 'ContextTitle' => [ |
172 | 'type' => 'text', |
173 | 'label' => $this->msg( 'expand_templates_title' )->plain(), |
174 | 'id' => 'contexttitle', |
175 | 'size' => 60, |
176 | 'autofocus' => true, |
177 | ], |
178 | 'Input' => [ |
179 | 'type' => 'textarea', |
180 | 'label' => $this->msg( 'expand_templates_input' )->text(), |
181 | 'rows' => 10, |
182 | 'id' => 'input', |
183 | 'useeditfont' => true, |
184 | ], |
185 | 'RemoveComments' => [ |
186 | 'type' => 'check', |
187 | 'label' => $this->msg( 'expand_templates_remove_comments' )->text(), |
188 | 'id' => 'removecomments', |
189 | 'default' => true, |
190 | ], |
191 | 'RemoveNowiki' => [ |
192 | 'type' => 'check', |
193 | 'label' => $this->msg( 'expand_templates_remove_nowiki' )->text(), |
194 | 'id' => 'removenowiki', |
195 | ], |
196 | 'GenerateXml' => [ |
197 | 'type' => 'check', |
198 | 'label' => $this->msg( 'expand_templates_generate_xml' )->text(), |
199 | 'id' => 'generate_xml', |
200 | ], |
201 | 'GenerateRawHtml' => [ |
202 | 'type' => 'check', |
203 | 'label' => $this->msg( 'expand_templates_generate_rawhtml' )->text(), |
204 | 'id' => 'generate_rawhtml', |
205 | ], |
206 | ]; |
207 | |
208 | $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() ); |
209 | $form |
210 | ->setSubmitTextMsg( 'expand_templates_ok' ) |
211 | ->setWrapperLegendMsg( 'expandtemplates' ) |
212 | ->setHeaderHtml( $this->msg( 'expand_templates_intro' )->parse() ) |
213 | ->setSubmitCallback( [ $this, 'onSubmitInput' ] ) |
214 | ->showAlways(); |
215 | } |
216 | |
217 | /** |
218 | * Generate a nice little box with a heading for output |
219 | * |
220 | * @param string $output Wiki text output |
221 | * @param string $heading |
222 | * @return string |
223 | */ |
224 | private function makeOutput( $output, $heading = 'expand_templates_output' ) { |
225 | $out = "<h2>" . $this->msg( $heading )->escaped() . "</h2>\n"; |
226 | $out .= Xml::textarea( |
227 | 'output', |
228 | $output, |
229 | 10, |
230 | 10, |
231 | [ |
232 | 'id' => 'output', |
233 | 'readonly' => 'readonly', |
234 | 'class' => 'mw-editfont-' . $this->userOptionsLookup->getOption( $this->getUser(), 'editfont' ) |
235 | ] |
236 | ); |
237 | |
238 | return $out; |
239 | } |
240 | |
241 | /** |
242 | * Wraps the provided html code in a div and outputs it to the page |
243 | * |
244 | * @param Title $title |
245 | * @param ParserOutput $pout |
246 | * @param OutputPage $out |
247 | */ |
248 | private function showHtmlPreview( Title $title, ParserOutput $pout, OutputPage $out ) { |
249 | $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" ); |
250 | |
251 | if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) { |
252 | $request = $this->getRequest(); |
253 | $user = $this->getUser(); |
254 | |
255 | // To prevent cross-site scripting attacks, don't show the preview if raw HTML is |
256 | // allowed and a valid edit token is not provided (T73111). However, MediaWiki |
257 | // does not currently provide logged-out users with CSRF protection; in that case, |
258 | // do not show the preview unless anonymous editing is allowed. |
259 | if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) { |
260 | $error = [ 'expand_templates_preview_fail_html_anon' ]; |
261 | } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) { |
262 | $error = [ 'expand_templates_preview_fail_html' ]; |
263 | } else { |
264 | $error = false; |
265 | } |
266 | |
267 | if ( $error ) { |
268 | $out->addHTML( |
269 | Html::errorBox( |
270 | $out->msg( $error )->parse(), |
271 | '', |
272 | 'previewnote' |
273 | ) |
274 | ); |
275 | return; |
276 | } |
277 | } |
278 | |
279 | $out->addParserOutputContent( $pout, [ 'enableSectionEditLinks' => false ] ); |
280 | $out->setCategoryLinks( $pout->getCategoryMap() ); |
281 | } |
282 | |
283 | protected function getGroupName() { |
284 | return 'wiki'; |
285 | } |
286 | } |
287 | |
288 | /** @deprecated class alias since 1.41 */ |
289 | class_alias( SpecialExpandTemplates::class, 'SpecialExpandTemplates' ); |