3 use MediaWiki\Context\DerivativeContext
;
4 use MediaWiki\Context\RequestContext
;
5 use MediaWiki\Language\Language
;
6 use MediaWiki\Output\OutputPage
;
7 use MediaWiki\Permissions\Authority
;
8 use MediaWiki\Request\FauxRequest
;
9 use MediaWiki\Request\FauxResponse
;
10 use MediaWiki\Request\WebRequest
;
11 use MediaWiki\SpecialPage\SpecialPage
;
18 class SpecialPageExecutor
{
21 * @param SpecialPage $page The special page to execute
22 * @param string|null $subPage The subpage parameter to call the page with
23 * @param WebRequest|null $request Web request that may contain URL parameters, etc
24 * @param Language|string|null $language The language which should be used in the context;
25 * if not specified, the pseudo-code 'qqx' is used
26 * @param Authority|null $performer The user which should be used in the context of this special page
27 * @param bool $fullHtml if true, the entirety of the generated HTML will be returned, this
28 * includes the opening <!DOCTYPE> declaration and closing </html> tag. If false, only value
29 * of OutputPage::getHTML() will be returned except if the page is redirect or where OutputPage
30 * is completely disabled.
32 * @return array [ string, WebResponse ] A two-elements array containing the HTML output
33 * generated by the special page as well as the response object.
35 public function executeSpecialPage(
38 ?WebRequest
$request = null,
40 ?Authority
$performer = null,
43 $context = $this->newContext( $request, $language, $performer );
45 $output = new OutputPage( $context );
46 $context->setOutput( $output );
48 $page->setContext( $context );
49 $output->setTitle( $page->getPageTitle() );
51 $html = $this->getHTMLFromSpecialPage( $page, $subPage, $fullHtml );
52 $response = $context->getRequest()->response();
54 if ( $response instanceof FauxResponse
) {
55 $code = $response->getStatusCode();
58 $response->header( 'Status: ' . $code . ' ' . HttpStatus
::getMessage( $code ) );
62 return [ $html, $response ];
66 * @param WebRequest|null $request
67 * @param Language|string|null $language Defaults to 'qqx'
68 * @param Authority|null $performer
70 * @return DerivativeContext
72 private function newContext(
73 ?WebRequest
$request = null,
75 ?Authority
$performer = null
77 $context = new DerivativeContext( RequestContext
::getMain() );
79 $context->setRequest( $request ?
: new FauxRequest() );
81 $context->setLanguage( $language ?
: 'qqx' );
83 if ( $performer !== null ) {
84 $context->setAuthority( $performer );
87 $this->setEditTokenFromUser( $context );
89 // Make sure the skin context is correctly set https://phabricator.wikimedia.org/T200771
90 $context->getSkin()->setContext( $context );
96 * If we are trying to edit and no token is set, supply one.
98 * @param DerivativeContext $context
100 private function setEditTokenFromUser( DerivativeContext
$context ) {
101 $request = $context->getRequest();
103 // Edits via GET are a security issue and should not succeed. On the other hand, not all
104 // POST requests are edits, but should ignore unused parameters.
105 if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) {
106 $request->setVal( 'wpEditToken', $context->getUser()->getEditToken() );
111 * @param SpecialPage $page
112 * @param string|null $subPage
113 * @param bool $fullHtml
115 * @return string HTML
117 private function getHTMLFromSpecialPage( SpecialPage
$page, $subPage, $fullHtml ) {
121 $page->execute( $subPage );
123 $output = $page->getOutput();
125 if ( $output->getRedirect() !== '' ) {
127 $html = ob_get_contents();
128 } elseif ( $output->isDisabled() ) {
129 $html = ob_get_contents();
130 } elseif ( $fullHtml ) {
131 $html = $output->output( true );
133 $html = $output->getHTML();