File: SpecialPageExecutor.php

package info (click to toggle)
mediawiki 1%3A1.43.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 417,464 kB
  • sloc: php: 1,062,949; javascript: 664,290; sql: 9,714; python: 5,458; xml: 3,489; sh: 1,131; makefile: 64
file content (142 lines) | stat: -rw-r--r-- 4,047 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<?php

use MediaWiki\Context\DerivativeContext;
use MediaWiki\Context\RequestContext;
use MediaWiki\Language\Language;
use MediaWiki\Output\OutputPage;
use MediaWiki\Permissions\Authority;
use MediaWiki\Request\FauxRequest;
use MediaWiki\Request\FauxResponse;
use MediaWiki\Request\WebRequest;
use MediaWiki\SpecialPage\SpecialPage;

/**
 * @author Addshore
 *
 * @since 1.27
 */
class SpecialPageExecutor {

	/**
	 * @param SpecialPage $page The special page to execute
	 * @param string|null $subPage The subpage parameter to call the page with
	 * @param WebRequest|null $request Web request that may contain URL parameters, etc
	 * @param Language|string|null $language The language which should be used in the context;
	 * if not specified, the pseudo-code 'qqx' is used
	 * @param Authority|null $performer The user which should be used in the context of this special page
	 * @param bool $fullHtml if true, the entirety of the generated HTML will be returned, this
	 * includes the opening <!DOCTYPE> declaration and closing </html> tag. If false, only value
	 * of OutputPage::getHTML() will be returned except if the page is redirect or where OutputPage
	 * is completely disabled.
	 *
	 * @return array [ string, WebResponse ] A two-elements array containing the HTML output
	 * generated by the special page as well as the response object.
	 */
	public function executeSpecialPage(
		SpecialPage $page,
		$subPage = '',
		?WebRequest $request = null,
		$language = null,
		?Authority $performer = null,
		$fullHtml = false
	) {
		$context = $this->newContext( $request, $language, $performer );

		$output = new OutputPage( $context );
		$context->setOutput( $output );

		$page->setContext( $context );
		$output->setTitle( $page->getPageTitle() );

		$html = $this->getHTMLFromSpecialPage( $page, $subPage, $fullHtml );
		$response = $context->getRequest()->response();

		if ( $response instanceof FauxResponse ) {
			$code = $response->getStatusCode();

			if ( $code > 0 ) {
				$response->header( 'Status: ' . $code . ' ' . HttpStatus::getMessage( $code ) );
			}
		}

		return [ $html, $response ];
	}

	/**
	 * @param WebRequest|null $request
	 * @param Language|string|null $language Defaults to 'qqx'
	 * @param Authority|null $performer
	 *
	 * @return DerivativeContext
	 */
	private function newContext(
		?WebRequest $request = null,
		$language = null,
		?Authority $performer = null
	) {
		$context = new DerivativeContext( RequestContext::getMain() );

		$context->setRequest( $request ?: new FauxRequest() );

		$context->setLanguage( $language ?: 'qqx' );

		if ( $performer !== null ) {
			$context->setAuthority( $performer );
		}

		$this->setEditTokenFromUser( $context );

		// Make sure the skin context is correctly set https://phabricator.wikimedia.org/T200771
		$context->getSkin()->setContext( $context );

		return $context;
	}

	/**
	 * If we are trying to edit and no token is set, supply one.
	 *
	 * @param DerivativeContext $context
	 */
	private function setEditTokenFromUser( DerivativeContext $context ) {
		$request = $context->getRequest();

		// Edits via GET are a security issue and should not succeed. On the other hand, not all
		// POST requests are edits, but should ignore unused parameters.
		if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) {
			$request->setVal( 'wpEditToken', $context->getUser()->getEditToken() );
		}
	}

	/**
	 * @param SpecialPage $page
	 * @param string|null $subPage
	 * @param bool $fullHtml
	 *
	 * @return string HTML
	 */
	private function getHTMLFromSpecialPage( SpecialPage $page, $subPage, $fullHtml ) {
		ob_start();

		try {
			$page->execute( $subPage );

			$output = $page->getOutput();

			if ( $output->getRedirect() !== '' ) {
				$output->output();
				$html = ob_get_contents();
			} elseif ( $output->isDisabled() ) {
				$html = ob_get_contents();
			} elseif ( $fullHtml ) {
				$html = $output->output( true );
			} else {
				$html = $output->getHTML();
			}
		} finally {
			ob_end_clean();
		}

		return $html;
	}

}