]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/PHPVersionCheck.php
MediaWiki 1.30.2-scripts2
[autoinstalls/mediawiki.git] / includes / PHPVersionCheck.php
1 <?php
2 // @codingStandardsIgnoreFile Generic.Arrays.DisallowLongArraySyntax
3 // @codingStandardsIgnoreFile Generic.Files.LineLength
4 // @codingStandardsIgnoreFile MediaWiki.Usage.DirUsage.FunctionFound
5 /**
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  * http://www.gnu.org/copyleft/gpl.html
20  *
21  * @file
22  */
23
24 /**
25  * Check PHP Version, as well as for composer dependencies in entry points,
26  * and display something vaguely comprehensible in the event of a totally
27  * unrecoverable error.
28  * @class
29  */
30 class PHPVersionCheck {
31         /* @var string The number of the MediaWiki version used */
32         var $mwVersion = '1.30';
33         var $functionsExtensionsMapping = array(
34                 'mb_substr'   => 'mbstring',
35                 'utf8_encode' => 'xml',
36                 'ctype_digit' => 'ctype',
37                 'json_decode' => 'json',
38                 'iconv'       => 'iconv',
39                 'mime_content_type' => 'fileinfo',
40         );
41
42         /**
43          * @var string Which entry point we are protecting. One of:
44          *   - index.php
45          *   - load.php
46          *   - api.php
47          *   - mw-config/index.php
48          *   - cli
49          */
50         var $entryPoint = null;
51
52         /**
53          * @param string $entryPoint Which entry point we are protecting. One of:
54          *   - index.php
55          *   - load.php
56          *   - api.php
57          *   - mw-config/index.php
58          *   - cli
59          * @return $this
60          */
61         function setEntryPoint( $entryPoint ) {
62                 $this->entryPoint = $entryPoint;
63         }
64
65         /**
66          * Returns the version of the installed php implementation.
67          *
68          * @param string $impl By default, the function returns the info of the currently installed PHP
69          *  implementation. Using this parameter the caller can decide, what version info will be
70          *  returned. Valid values: HHVM, PHP
71          * @return array An array of information about the php implementation, containing:
72          *  - 'version': The version of the php implementation (specific to the implementation, not
73          *  the version of the implemented php version)
74          *  - 'implementation': The name of the implementation used
75          *  - 'vendor': The development group, vendor or developer of the implementation.
76          *  - 'upstreamSupported': The minimum version of the implementation supported by the named vendor.
77          *  - 'minSupported': The minimum version supported by MediWiki
78          *  - 'upgradeURL': The URL to the website of the implementation that contains
79          *  upgrade/installation instructions.
80          */
81         function getPHPInfo( $impl = false ) {
82                 if (
83                         ( defined( 'HHVM_VERSION' ) && $impl !== 'PHP' ) ||
84                         $impl === 'HHVM'
85                 ) {
86                         return array(
87                                 'implementation' => 'HHVM',
88                                 'version' => defined( 'HHVM_VERSION' ) ? HHVM_VERSION : 'undefined',
89                                 'vendor' => 'Facebook',
90                                 'upstreamSupported' => '3.6.5',
91                                 'minSupported' => '3.6.5',
92                                 'upgradeURL' => 'https://docs.hhvm.com/hhvm/installation/introduction',
93                         );
94                 }
95                 return array(
96                         'implementation' => 'PHP',
97                         'version' => PHP_VERSION,
98                         'vendor' => 'the PHP Group',
99                         'upstreamSupported' => '5.5.0',
100                         'minSupported' => '5.5.9',
101                         'upgradeURL' => 'https://secure.php.net/downloads.php',
102                 );
103         }
104
105         /**
106          * Displays an error, if the installed php version does not meet the minimum requirement.
107          *
108          * @return $this
109          */
110         function checkRequiredPHPVersion() {
111                 $phpInfo = $this->getPHPInfo();
112                 $minimumVersion = $phpInfo['minSupported'];
113                 $otherInfo = $this->getPHPInfo( $phpInfo['implementation'] === 'HHVM' ? 'PHP' : 'HHVM' );
114                 if (
115                         !function_exists( 'version_compare' )
116                         || version_compare( $phpInfo['version'], $minimumVersion ) < 0
117                 ) {
118                         $shortText = "MediaWiki $this->mwVersion requires at least {$phpInfo['implementation']}"
119                                 . " version $minimumVersion or {$otherInfo['implementation']} version "
120                                 . "{$otherInfo['minSupported']}, you are using {$phpInfo['implementation']} "
121                                 . "{$phpInfo['version']}.";
122
123                         $longText = "Error: You might be using an older {$phpInfo['implementation']} version. \n"
124                                 . "MediaWiki $this->mwVersion needs {$phpInfo['implementation']}"
125                                 . " $minimumVersion or higher or {$otherInfo['implementation']} version "
126                                 . "{$otherInfo['minSupported']}.\n\nCheck if you have a"
127                                 . " newer php executable with a different name, such as php5.\n\n";
128
129                         $longHtml = <<<HTML
130                         Please consider <a href="{$phpInfo['upgradeURL']}">upgrading your copy of
131                         {$phpInfo['implementation']}</a>.
132                         {$phpInfo['implementation']} versions less than {$phpInfo['upstreamSupported']} are no 
133                         longer supported by {$phpInfo['vendor']} and will not receive
134                         security or bugfix updates.
135                 </p>
136                 <p>
137                         If for some reason you are unable to upgrade your {$phpInfo['implementation']} version,
138                         you will need to <a href="https://www.mediawiki.org/wiki/Download">download</a> an 
139                         older version of MediaWiki from our website.
140                         See our <a href="https://www.mediawiki.org/wiki/Compatibility#PHP">compatibility page</a>
141                         for details of which versions are compatible with prior versions of {$phpInfo['implementation']}.
142 HTML;
143                         $this->triggerError(
144                                 "Supported {$phpInfo['implementation']} versions",
145                                 $shortText,
146                                 $longText,
147                                 $longHtml
148                         );
149                 }
150         }
151
152         /**
153          * Displays an error, if the vendor/autoload.php file could not be found.
154          *
155          * @return $this
156          */
157         function checkVendorExistence() {
158                 if ( !file_exists( dirname( __FILE__ ) . '/../vendor/autoload.php' ) ) {
159                         $shortText = "Installing some external dependencies (e.g. via composer) is required.";
160
161                         $longText = "Error: You are missing some external dependencies. \n"
162                                 . "MediaWiki now also has some external dependencies that need to be installed\n"
163                                 . "via composer or from a separate git repo. Please see\n"
164                                 . "https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries\n"
165                                 . "for help on installing the required components.";
166
167                         $longHtml = <<<HTML
168                 MediaWiki now also has some external dependencies that need to be installed via
169                 composer or from a separate git repo. Please see
170                 <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a>
171                 for help on installing the required components.
172 HTML;
173
174                         $this->triggerError( 'External dependencies', $shortText, $longText, $longHtml );
175                 }
176         }
177
178         /**
179          * Displays an error, if a PHP extension does not exist.
180          *
181          * @return $this
182          */
183         function checkExtensionExistence() {
184                 $missingExtensions = array();
185                 foreach ( $this->functionsExtensionsMapping as $function => $extension ) {
186                         if ( !function_exists( $function ) ) {
187                                 $missingExtensions[] = $extension;
188                         }
189                 }
190
191                 if ( $missingExtensions ) {
192                         $shortText = "Installing some PHP extensions is required.";
193
194                         $missingExtText = '';
195                         $missingExtHtml = '';
196                         $baseUrl = 'https://secure.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>";
201                         }
202
203                         $cliText = "Error: Missing one or more required components of PHP.\n"
204                                 . "You are missing a required extension to PHP that MediaWiki needs.\n"
205                                 . "Please install:\n" . $missingExtText;
206
207                         $longHtml = <<<HTML
208                 You are missing a required extension to PHP that MediaWiki
209                 requires to run. Please install:
210                 <ul>
211                 $missingExtHtml
212                 </ul>
213 HTML;
214
215                         $this->triggerError( 'Required components', $shortText, $cliText, $longHtml );
216                 }
217         }
218
219         /**
220          * Output headers that prevents error pages to be cached.
221          */
222         function outputHTMLHeader() {
223                 $protocol = isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0';
224
225                 header( "$protocol 500 MediaWiki configuration Error" );
226                 // Don't cache error pages!  They cause no end of trouble...
227                 header( 'Cache-control: none' );
228                 header( 'Pragma: no-cache' );
229         }
230
231         /**
232          * Returns an error page, which is suitable for output to the end user via a web browser.
233          *
234          * @param string $title
235          * @param string $longHtml
236          * @param string $shortText
237          * @return string
238          */
239         function getIndexErrorOutput( $title, $longHtml, $shortText ) {
240                 $pathinfo = pathinfo( $_SERVER['SCRIPT_NAME'] );
241                 if ( $this->entryPoint == 'mw-config/index.php' ) {
242                         $dirname = dirname( $pathinfo['dirname'] );
243                 } else {
244                         $dirname = $pathinfo['dirname'];
245                 }
246                 $encLogo =
247                         htmlspecialchars( str_replace( '//', '/', $dirname . '/' ) .
248                                 'resources/assets/mediawiki.png' );
249                 $shortHtml = htmlspecialchars( $shortText );
250
251                 header( 'Content-type: text/html; charset=UTF-8' );
252
253                 $finalOutput = <<<HTML
254 <!DOCTYPE html>
255 <html lang="en" dir="ltr">
256         <head>
257                 <meta charset="UTF-8" />
258                 <title>MediaWiki {$this->mwVersion}</title>
259                 <style media='screen'>
260                         body {
261                                 color: #000;
262                                 background-color: #fff;
263                                 font-family: sans-serif;
264                                 padding: 2em;
265                                 text-align: center;
266                         }
267                         p, img, h1, h2, ul  {
268                                 text-align: left;
269                                 margin: 0.5em 0 1em;
270                         }
271                         h1 {
272                                 font-size: 120%;
273                         }
274                         h2 {
275                                 font-size: 110%;
276                         }
277                 </style>
278         </head>
279         <body>
280                 <img src="{$encLogo}" alt='The MediaWiki logo' />
281                 <h1>MediaWiki {$this->mwVersion} internal error</h1>
282                 <div class='error'>
283                 <p>
284                         {$shortHtml}
285                 </p>
286                 <h2>{$title}</h2>
287                 <p>
288                         {$longHtml}
289                 </p>
290                 </div>
291         </body>
292 </html>
293 HTML;
294
295                 return $finalOutput;
296         }
297
298         /**
299          * Display something vaguely comprehensible in the event of a totally unrecoverable error.
300          * Does not assume access to *anything*; no globals, no autoloader, no database, no localisation.
301          * Safe for PHP4 (and putting this here means that WebStart.php and GlobalSettings.php
302          * no longer need to be).
303          *
304          * Calling this function kills execution immediately.
305          *
306          * @param string $title HTML code to be put within an <h2> tag
307          * @param string $shortText
308          * @param string $longText
309          * @param string $longHtml
310          */
311         function triggerError( $title, $shortText, $longText, $longHtml ) {
312                 switch ( $this->entryPoint ) {
313                         case 'cli':
314                                 $finalOutput = $longText;
315                                 break;
316                         case 'index.php':
317                         case 'mw-config/index.php':
318                                 $this->outputHTMLHeader();
319                                 $finalOutput = $this->getIndexErrorOutput( $title, $longHtml, $shortText );
320                                 break;
321                         case 'load.php':
322                                 $this->outputHTMLHeader();
323                                 $finalOutput = "/* $shortText */";
324                                 break;
325                         default:
326                                 $this->outputHTMLHeader();
327                                 // Handle everything that's not index.php
328                                 $finalOutput = $shortText;
329                 }
330
331                 echo "$finalOutput\n";
332                 die( 1 );
333         }
334 }
335
336 /**
337  * Check php version and that external dependencies are installed, and
338  * display an informative error if either condition is not satisfied.
339  *
340  * @note Since we can't rely on anything, the minimum PHP versions and MW current
341  * version are hardcoded here
342  */
343 function wfEntryPointCheck( $entryPoint ) {
344         $phpVersionCheck = new PHPVersionCheck();
345         $phpVersionCheck->setEntryPoint( $entryPoint );
346         $phpVersionCheck->checkRequiredPHPVersion();
347         $phpVersionCheck->checkVendorExistence();
348         $phpVersionCheck->checkExtensionExistence();
349 }