Localisation updates from https://translatewiki.net.
[mediawiki.git] / includes / PHPVersionCheck.php
blob95f222c3aa74c65525b596d143bad8f53fb236a5
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
18 * @file
21 // phpcs:disable Generic.Arrays.DisallowLongArraySyntax,PSR2.Classes.PropertyDeclaration,MediaWiki.Usage.DirUsage
22 // phpcs:disable Squiz.Scope.MemberVarScope.Missing,Squiz.Scope.MethodScope.Missing
23 /**
24 * Check PHP Version, as well as for composer dependencies in entry points,
25 * and display something vaguely comprehensible in the event of a totally
26 * unrecoverable error.
28 * @note Since we can't rely on anything external, the minimum PHP versions
29 * and MW current version are hardcoded in this class.
31 * @note This class uses setter methods instead of a constructor so that
32 * it can be compatible with PHP 4 through PHP 8 (without warnings).
34 class PHPVersionCheck {
35 /** @var string The number of the MediaWiki version used. If you're updating MW_VERSION in Defines.php, you must also update this value. */
36 var $mwVersion = '1.44';
38 /** @var string[] A mapping of PHP functions to PHP extensions. */
39 var $functionsExtensionsMapping = array(
40 'mb_substr' => 'mbstring',
41 'xml_parser_create' => 'xml',
42 'ctype_digit' => 'ctype',
43 'json_decode' => 'json',
44 'iconv' => 'iconv',
45 'mime_content_type' => 'fileinfo',
46 'intl_is_failure' => 'intl',
49 /**
50 * @var string The format used for errors. One of "text" or "html"
52 var $format = 'text';
54 /**
55 * @var string
57 var $scriptPath = '/';
59 /**
60 * Set the format used for errors.
62 * @param string $format One of "text" or "html"
64 function setFormat( $format ) {
65 $this->format = $format;
68 /**
69 * Set the script path used for images in HTML-formatted errors.
71 * @param string $scriptPath
73 function setScriptPath( $scriptPath ) {
74 $this->scriptPath = $scriptPath;
77 /**
78 * Displays an error, if the installed PHP version does not meet the minimum requirement.
80 function checkRequiredPHPVersion() {
81 $minimumVersion = '7.4.3';
83 /**
84 * This is a list of known-bad ranges of PHP versions. Syntax is like SemVer – either:
86 * - '1.2.3' to prohibit a single version of PHP, or
87 * - '1.2.3 – 1.2.5' to block a range, inclusive.
89 * Whitespace will be ignored.
91 * The key is not shown to users; use it to prompt future developers as to why this was
92 * chosen, ideally one or more Phabricator task references.
94 * Remember to drop irrelevant ranges when bumping $minimumVersion.
96 $knownBad = array(
99 $passes = version_compare( PHP_VERSION, $minimumVersion, '>=' );
101 $versionString = "PHP $minimumVersion or higher";
103 // Left as a programmatic check to make it easier to update.
104 if ( count( $knownBad ) ) {
105 $versionString .= ' (and not ' . implode( ', ', array_values( $knownBad ) ) . ')';
107 foreach ( $knownBad as $range ) {
108 // As we don't have composer at this point, we have to do our own version range checking.
109 if ( strpos( $range, '-' ) ) {
110 $passes = $passes && !(
111 version_compare( PHP_VERSION, trim( strstr( $range, '-', true ) ), '>=' )
112 && version_compare( PHP_VERSION, trim( substr( strstr( $range, '-', false ), 1 ) ), '<' )
114 } else {
115 $passes = $passes && version_compare( PHP_VERSION, trim( $range ), '<>' );
120 if ( !$passes ) {
121 $cliText = "Error: You are using an unsupported PHP version (PHP " . PHP_VERSION . ").\n"
122 . "MediaWiki $this->mwVersion needs $versionString.\n\nCheck if you might have a newer "
123 . "PHP executable with a different name.\n\n";
125 $web = array();
126 $web['intro'] = "MediaWiki $this->mwVersion requires $versionString; you are using PHP "
127 . PHP_VERSION . ".";
129 $web['longTitle'] = "Supported PHP versions";
130 // phpcs:disable Generic.Files.LineLength
131 $web['longHtml'] = <<<HTML
133 Please consider <a href="https://www.php.net/downloads.php">upgrading your copy of PHP</a>.
134 PHP versions less than v8.1.0 are no longer <a href="https://www.php.net/supported-versions.php">supported</a>
135 by the PHP Group and will not receive security or bugfix updates.
136 </p>
138 If for some reason you are unable to upgrade your PHP version, you will need to
139 <a href="https://www.mediawiki.org/wiki/Download">download</a> an older version of
140 MediaWiki from our website. See our
141 <a href="https://www.mediawiki.org/wiki/Compatibility#PHP">compatibility page</a>
142 for details of which versions are compatible with prior versions of PHP.
143 </p>
144 HTML;
145 // phpcs:enable Generic.Files.LineLength
146 $this->triggerError(
147 $web,
148 $cliText
154 * Displays an error, if the vendor/autoload.php file could not be found.
156 function checkVendorExistence() {
157 if ( !file_exists( dirname( __FILE__ ) . '/../vendor/autoload.php' ) ) {
158 $cliText = "Error: You are missing some dependencies. \n"
159 . "MediaWiki has dependencies that need to be installed via Composer\n"
160 . "or from a separate repository. Please see\n"
161 . "https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries\n"
162 . "for help with installing them.";
164 $web = array();
165 $web['intro'] = "Installing some dependencies is required.";
166 $web['longTitle'] = 'Dependencies';
167 // phpcs:disable Generic.Files.LineLength
168 $web['longHtml'] = <<<HTML
170 MediaWiki has dependencies that need to be installed via Composer
171 or from a separate repository. Please see the
172 <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">instructions
173 for installing external libraries</a> on MediaWiki.org.
174 </p>
175 HTML;
176 // phpcs:enable Generic.Files.LineLength
178 $this->triggerError( $web, $cliText );
183 * Displays an error, if a PHP extension does not exist.
185 function checkExtensionExistence() {
186 $missingExtensions = array();
187 foreach ( $this->functionsExtensionsMapping as $function => $extension ) {
188 if ( !function_exists( $function ) ) {
189 $missingExtensions[] = $extension;
193 if ( $missingExtensions ) {
194 $missingExtText = '';
195 $missingExtHtml = '';
196 $baseUrl = 'https://www.php.net';
197 foreach ( $missingExtensions as $ext ) {
198 $missingExtText .= " * $ext <$baseUrl/$ext>\n";
199 $missingExtHtml .= "<li><b>$ext</b> "
200 . "(<a href=\"$baseUrl/$ext\">more information</a>)</li>";
203 $cliText = "Error: Missing one or more required PHP extensions. Please see\n"
204 . "https://www.mediawiki.org/wiki/Manual:Installation_requirements#PHP\n"
205 . "for help with installing them.\n"
206 . "Please install or enable:\n" . $missingExtText;
208 $web = array();
209 $web['intro'] = "Installing some PHP extensions is required.";
210 $web['longTitle'] = 'Required PHP extensions';
211 $web['longHtml'] = <<<HTML
213 You are missing one or more extensions to PHP that MediaWiki requires to run. Please see the
214 <a href="https://www.mediawiki.org/wiki/Manual:Installation_requirements#PHP">PHP
215 installation requirements</a> on MediaWiki.org.
216 </p>
217 <p>Please install or enable:</p>
218 <ul>
219 $missingExtHtml
220 </ul>
221 HTML;
223 $this->triggerError( $web, $cliText );
228 * Output headers that prevents error pages to be cached.
230 function outputHTMLHeader() {
231 $protocol = isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
233 header( "$protocol 500 MediaWiki configuration Error" );
234 // Don't cache error pages! They cause no end of trouble...
235 header( 'Cache-Control: no-cache' );
239 * Returns an error page, which is suitable for output to the end user via a web browser.
241 * @param string $introText
242 * @param string $longTitle
243 * @param string $longHtml
244 * @return string
246 function getIndexErrorOutput( $introText, $longTitle, $longHtml ) {
247 $encLogo =
248 htmlspecialchars( str_replace( '//', '/', $this->scriptPath . '/' ) .
249 'resources/assets/mediawiki.png' );
251 $introHtml = htmlspecialchars( $introText );
252 $longTitleHtml = htmlspecialchars( $longTitle );
254 header( 'Content-type: text/html; charset=UTF-8' );
256 $finalOutput = <<<HTML
257 <!DOCTYPE html>
258 <html lang="en" dir="ltr">
259 <head>
260 <meta charset="UTF-8" />
261 <title>MediaWiki {$this->mwVersion}</title>
262 <style media="screen">
263 body {
264 color: #000;
265 background-color: #fff;
266 font-family: sans-serif;
267 padding: 2em;
268 text-align: center;
270 p, img, h1, h2, ul {
271 text-align: left;
272 margin: 0.5em 0 1em;
274 h1 {
275 font-size: 120%;
277 h2 {
278 font-size: 110%;
280 </style>
281 </head>
282 <body>
283 <img src="{$encLogo}" alt="The MediaWiki logo" />
284 <h1>MediaWiki {$this->mwVersion} internal error</h1>
286 {$introHtml}
287 </p>
288 <h2>{$longTitleHtml}</h2>
289 {$longHtml}
290 </body>
291 </html>
292 HTML;
294 return $finalOutput;
298 * Display something vaguely comprehensible in the event of a totally unrecoverable error.
299 * Does not assume access to *anything*; no globals, no autoloader, no database, no localisation.
300 * Safe for PHP4 (and putting this here means that WebStart.php and GlobalSettings.php
301 * no longer need to be).
303 * This function immediately terminates the PHP process.
305 * @param string[] $web
306 * - (string) intro: Short error message, displayed on top.
307 * - (string) longTitle: Title for the longer message.
308 * - (string) longHtml: The longer message, as raw HTML.
309 * @param string $cliText
311 function triggerError( $web, $cliText ) {
312 if ( $this->format === 'html' ) {
313 // Used by index.php and mw-config/index.php
314 $this->outputHTMLHeader();
315 $finalOutput = $this->getIndexErrorOutput(
316 $web['intro'],
317 $web['longTitle'],
318 $web['longHtml']
320 } else {
321 // Used by Maintenance.php (CLI)
322 $finalOutput = $cliText;
325 echo "$finalOutput\n";
326 die( 1 );
331 * Check PHP version and that external dependencies are installed, and
332 * display an informative error if either condition is not satisfied.
334 * @param string $format One of "text" or "html"
335 * @param string $scriptPath Used when an error is formatted as HTML.
337 function wfEntryPointCheck( $format = 'text', $scriptPath = '/' ) {
338 $phpVersionCheck = new PHPVersionCheck();
339 $phpVersionCheck->setFormat( $format );
340 $phpVersionCheck->setScriptPath( $scriptPath );
341 $phpVersionCheck->checkRequiredPHPVersion();
342 $phpVersionCheck->checkVendorExistence();
343 $phpVersionCheck->checkExtensionExistence();