MediaWiki  master
SpecialExpandTemplates.php
Go to the documentation of this file.
1 <?php
24 namespace MediaWiki\Specials;
25 
26 use HTMLForm;
35 use Parser;
36 use ParserFactory;
37 use ParserOptions;
38 use ParserOutput;
39 use Xml;
40 
48 
50  private const MAX_INCLUDE_SIZE = 50000000;
51 
52  private ParserFactory $parserFactory;
53  private UserOptionsLookup $userOptionsLookup;
54  private TidyDriverBase $tidy;
55 
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 
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  [ '_&lt;nowiki&gt;_', '_&lt;/nowiki&gt;_', '_&lt;nowiki */&gt;_' ],
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 
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 
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 
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 
248  private function showHtmlPreview( Title $title, ParserOutput $pout, OutputPage $out ) {
249  $lang = $title->getPageViewLanguage();
250  $out->addHTML( "<h2>" . $this->msg( 'expand_templates_preview' )->escaped() . "</h2>\n" );
251 
252  if ( $this->getConfig()->get( MainConfigNames::RawHtml ) ) {
253  $request = $this->getRequest();
254  $user = $this->getUser();
255 
256  // To prevent cross-site scripting attacks, don't show the preview if raw HTML is
257  // allowed and a valid edit token is not provided (T73111). However, MediaWiki
258  // does not currently provide logged-out users with CSRF protection; in that case,
259  // do not show the preview unless anonymous editing is allowed.
260  if ( $user->isAnon() && !$this->getAuthority()->isAllowed( 'edit' ) ) {
261  $error = [ 'expand_templates_preview_fail_html_anon' ];
262  } elseif ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ), '', $request ) ) {
263  $error = [ 'expand_templates_preview_fail_html' ];
264  } else {
265  $error = false;
266  }
267 
268  if ( $error ) {
269  $out->addHTML(
271  $out->msg( $error )->parse(),
272  '',
273  'previewnote'
274  )
275  );
276  return;
277  }
278  }
279 
280  $out->addHTML( Html::openElement( 'div', [
281  'class' => 'mw-content-' . $lang->getDir(),
282  'dir' => $lang->getDir(),
283  'lang' => $lang->getHtmlCode(),
284  ] ) );
285  $out->addParserOutputContent( $pout, [ 'enableSectionEditLinks' => false ] );
286  $out->addHTML( Html::closeElement( 'div' ) );
287  $out->setCategoryLinks( $pout->getCategories() );
288  }
289 
290  protected function getGroupName() {
291  return 'wiki';
292  }
293 }
294 
298 class_alias( SpecialExpandTemplates::class, 'SpecialExpandTemplates' );
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:158
static factory( $displayFormat, $descriptor, IContextSource $context, $messagePrefix='')
Construct a HTMLForm object for given display type.
Definition: HTMLForm.php:360
This class is a collection of static functions that serve two purposes:
Definition: Html.php:57
static errorBox( $html, $heading='', $className='')
Return an error box.
Definition: Html.php:822
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:280
static closeElement( $element)
Returns "</$element>".
Definition: Html.php:344
A class containing constants representing the names of configuration variables.
const RawHtml
Name constant for the RawHtml setting, for use with Config::get()
This is one of the Core classes and should be read at least once by any new developers.
Definition: OutputPage.php:93
Parent class for all special pages.
Definition: SpecialPage.php:66
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getUser()
Shortcut to get the User executing this instance.
getPageTitle( $subpage=false)
Get a self-referential title object.
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getContentLanguage()
Shortcut to get content language.
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
A special page that expands submitted templates, parser functions, and variables, allowing easier deb...
execute( $subpage)
Show the special page.
__construct(ParserFactory $parserFactory, UserOptionsLookup $userOptionsLookup, TidyDriverBase $tidy)
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
onSubmitInput(array $values)
Callback for the HTMLForm used in self::makeForm.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition: Status.php:58
Base class for HTML cleanup utilities.
Represents a title within MediaWiki.
Definition: Title.php:76
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:400
Provides access to user options.
Set options of the Parser.
static newFromContext(IContextSource $context)
Get a ParserOptions object from a IContextSource object.
getText( $options=[])
Get the output HTML.
PHP Parser - Processes wiki markup (which uses a more user-friendly syntax, such as "[[link]]" for ma...
Definition: Parser.php:115
const OT_PREPROCESS
Output type: like Parser::preprocess()
Definition: Parser.php:156
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:73
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:85
Module of static functions for generating XML.
Definition: Xml.php:33
static textarea( $name, $content, $cols=40, $rows=5, $attribs=[])
Shortcut for creating textareas.
Definition: Xml.php:650