Fix PHP Fatal error for r54627.
[lhc/web/wiklou.git] / includes / specials / SpecialVersion.php
1 <?php
2
3 /**
4 * Give information about the version of MediaWiki, PHP, the DB and extensions
5 *
6 * @ingroup SpecialPage
7 *
8 * @author Ævar Arnfjörð Bjarmason <avarab@gmail.com>
9 * @copyright Copyright © 2005, Ævar Arnfjörð Bjarmason
10 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
11 */
12 class SpecialVersion extends SpecialPage {
13 private $firstExtOpened = true;
14
15 function __construct(){
16 parent::__construct( 'Version' );
17 }
18
19 /**
20 * main()
21 */
22 function execute( $par ) {
23 global $wgOut, $wgMessageCache, $wgSpecialVersionShowHooks, $wgContLang;
24 $wgMessageCache->loadAllMessages();
25
26 $this->setHeaders();
27 $this->outputHeader();
28
29 if( $wgContLang->isRTL() ) {
30 $wgOut->addHTML( '<div dir="rtl">' );
31 } else {
32 $wgOut->addHTML( '<div dir="ltr">' );
33 }
34 $text =
35 $this->MediaWikiCredits() .
36 $this->softwareInformation() .
37 $this->extensionCredits();
38 if ( $wgSpecialVersionShowHooks ) {
39 $text .= $this->wgHooks();
40 }
41 $wgOut->addWikiText( $text );
42 $wgOut->addHTML( $this->IPInfo() );
43 $wgOut->addHTML( '</div>' );
44 }
45
46 /**
47 * check executive path existence
48 * @param string command
49 * @return mixed existsIn
50 */
51 static function checkExecPath( $cmd ) {
52 $existsIn = false;
53 $pathDirArray = explode( ';' , $_SERVER['PATH'] );
54 foreach ( $pathDirArray as $pathDir ) {
55 $pathDir = str_replace('\\', '/', $pathDir);
56 $pathDir .= '/';
57 if ( ( file_exists ( $pathDir . '/' . $cmd ) ) || ( file_exists( trim( $pathDir . '/' . $cmd, '"' ) . '.exe' ) ) ) {
58 $existsIn = $pathDir;
59 }
60 }
61 return $existsIn;
62 }
63
64 /**
65 * execuate command for output
66 * @param string command
67 * @return string output
68 */
69 static function execOutput( $cmd ) {
70 $out = array( $cmd );
71 exec( $cmd.' 2>&1', $out );
72 unset($out[0]);
73 return implode("\n", $out );
74 }
75
76 /**#@+
77 * @private
78 */
79
80 /**
81 * @return wiki text showing the license information
82 */
83 static function MediaWikiCredits() {
84 global $wgContLang;
85
86 $ret = Xml::element( 'h2', array( 'id' => 'mw-version-license' ), wfMsg( 'version-license' ) );
87
88 // This text is always left-to-right.
89 $ret .= '<div dir="ltr">';
90 $ret .= "__NOTOC__
91 This wiki is powered by '''[http://www.mediawiki.org/ MediaWiki]''',
92 copyright © 2001-2009 Magnus Manske, Brion Vibber, Lee Daniel Crocker,
93 Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason,
94 Niklas Laxström, Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor,
95 Aaron Schulz, Andrew Garrett, Raimond Spekking, Alexandre Emsenhuber,
96 Siebrand Mazeland, Chad Horohoe and others.
97
98 MediaWiki is free software; you can redistribute it and/or modify
99 it under the terms of the GNU General Public License as published by
100 the Free Software Foundation; either version 2 of the License, or
101 (at your option) any later version.
102
103 MediaWiki is distributed in the hope that it will be useful,
104 but WITHOUT ANY WARRANTY; without even the implied warranty of
105 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
106 GNU General Public License for more details.
107
108 You should have received [{{SERVER}}{{SCRIPTPATH}}/COPYING a copy of the GNU General Public License]
109 along with this program; if not, write to the Free Software
110 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
111 or [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].
112 ";
113 $ret .= '</div>';
114
115 return str_replace( "\t\t", '', $ret ) . "\n";
116 }
117
118 /**
119 * @return wiki text showing the third party software versions (apache, php, mysql).
120 */
121 static function softwareInformation() {
122 global $wgUseImageMagick, $wgImageMagickConvertCommand, $wgDiff3, $wgDiff, $wgUseTeX;
123 global $wgFileExtensions, $wgSVGConverter, $wgSVGConverters, $wgSVGConverterPath;
124 global $wgUser, $wgSpecialVersionExtended;
125 $dbr = wfGetDB( DB_SLAVE );
126
127 // Put the software in an array of form 'name' => 'version'. All messages should
128 // be loaded here, so feel free to use wfMsg*() in the 'name'. Raw HTML or wikimarkup
129 // can be used
130 $software = array();
131
132 $software['[http://www.mediawiki.org/ MediaWiki]'] = self::getVersionLinked();
133 $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . php_sapi_name() . ")";
134 $software[$dbr->getSoftwareLink()] = $dbr->getServerVersion();
135
136 if( $wgSpecialVersionExtended || $wgUser->isAllowed( 'versiondetail' ) ) {
137 // Get the web server name and its version, if applicable
138 // Chop off PHP text from the string if it has the text desired
139 $serverSoftware = $_SERVER['SERVER_SOFTWARE'];
140 if ( strrpos( $serverSoftware, 'PHP' ) === false ) {
141 } else {
142 $serverSoftware = trim( substr( $serverSoftware, 0, strrpos($serverSoftware,'PHP') - 1 ) );
143 }
144
145 // Get the web server name and its version.
146 $serverSoftwareLine = explode('/',$serverSoftware);
147 $serverSoftwareName = $serverSoftwareLine[0];
148
149 // Insert the website of the web server if applicable.
150 if ( stristr( $serverSoftwareName, 'Apache' ) )
151 $serverSoftwareURL = 'http://httpd.apache.org/';
152 else if ( stristr( $serverSoftwareName, 'IIS' ) )
153 $serverSoftwareURL = 'http://www.microsoft.com/iis/';
154 else if ( stristr( $serverSoftwareName, 'Cherokee' ) )
155 $serverSoftwareURL = 'http://www.cherokee-project.com/';
156 else if ( stristr( $serverSoftwareName, 'lighttpd' ) )
157 $serverSoftwareURL = 'http://www.lighttpd.net/';
158 else if ( stristr( $serverSoftwareName, 'Sun' ) )
159 $serverSoftwareURL = 'http://www.sun.com/software/products/web_srvr/';
160 else if ( stristr( $serverSoftwareName, 'nginx' ) )
161 $serverSoftwareURL = 'http://nginx.net/';
162
163 // Get the version of the web server. If does not have one,
164 // leave it as empty.
165 if ( $serverSoftwareLine[1] != '' ) {
166 $serverSoftwareVersion = $serverSoftwareLine[1];
167 } else {
168 $serverSoftwareVersion = '';
169 }
170
171 if ( isset( $serverSoftwareURL ) )
172 $software["[$serverSoftwareURL $serverSoftwareName]"] = $serverSoftwareVersion;
173 else
174 $software[$serverSoftwareName] = $serverSoftwareVersion;
175
176 // Version information for diff3
177 if ( file_exists( trim( $wgDiff3, '"' ) ) ) {
178 $swDiff3Info = self::execOutput( $wgDiff3 . ' -v' );
179 $swDiff3Line = explode("\n",$swDiff3Info ,2);
180 $swDiff3Ver = $swDiff3Line[0];
181 $swDiff3Ver = str_replace( 'diff3 (GNU diffutils) ', '' , $swDiff3Ver);
182 $software['[http://www.gnu.org/software/diffutils/diffutils.html diff3]'] = $swDiff3Ver;
183 }
184
185 // Version information for diff
186 if ( file_exists( trim( $wgDiff, '"' ) ) ) {
187 $swDiffInfo = self::execOutput( $wgDiff . ' -v' );
188 $swDiffLine = explode("\n",$swDiffInfo ,2);
189 $swDiffVer = $swDiffLine[0];
190 $swDiffVer = str_replace( 'diff (GNU diffutils) ', '' , $swDiffVer);
191 $software['[http://www.gnu.org/software/diffutils/diffutils.html diff]'] = $swDiffVer;
192 }
193
194 // Look for ImageMagick's version, if did not found, try to find the GD library version
195 if ( $wgUseImageMagick ) {
196 if ( file_exists( trim( $wgImageMagickConvertCommand, '"' ) ) ) {
197 $swImageMagickInfo = self::execOutput( $wgImageMagickConvertCommand . ' -version' );
198 list( $head, $tail ) = explode( 'ImageMagick', $swImageMagickInfo );
199 list( $swImageMagickVer ) = explode('http://www.imagemagick.org', $tail );
200 $software['[http://www.imagemagick.org/ ImageMagick]'] = $swImageMagickVer;
201 }
202 } else {
203 if( function_exists( 'gd_info' ) ) {
204 $gdInfo = gd_info();
205 if ( strstr( $gdInfo['GD Version'], 'bundled' ) != false ) {
206 $gd_URL = 'http://www.php.net/gd';
207 } else {
208 $gd_URL = 'http://www.libgd.org';
209 }
210 $software['[' . $gd_URL . ' GD library]'] = $gdInfo['GD Version'];
211 }
212 }
213
214 // Look for SVG converter and print the version info
215 if ( in_array( 'svg', $wgFileExtensions ) ) {
216 $swSVGConvName = $wgSVGConverter;
217 $swSVGConvInfo = '';
218 $haveSVGConvVer = false;
219 $pathVar = '$path/';
220 $binPath = '/usr/bin/';
221 $execPath = strtok(strstr($wgSVGConverters[$wgSVGConverter],$pathVar), ' ');
222 $execPath = substr_replace($execPath, '', 0, strlen($pathVar));
223 $execFullPath = trim($wgSVGConverterPath,'"') . $execPath;
224 $execBinPath = $binPath . $execPath;
225 $execPathVal = self::checkExecPath( $execPath );
226 if (strstr($execFullPath, ' ') != false) {
227 $execFullPath = '"' . $execFullPath . '"';
228 }
229 if ( !strcmp( $wgSVGConverter, 'ImageMagick') ) {
230 // Get version info for ImageMagick
231 if ( file_exists( $execBinPath ) )
232 $swSVGConvInfo = self::execOutput( $execBinPath . ' -version' );
233 else if ( file_exists( trim( $execFullPath, '"' ) ) || ( file_exists( trim( $execFullPath, '"' ) . '.exe' ) ) )
234 $swSVGConvInfo = self::execOutput( $execFullPath . ' -version' );
235 else if ( $execPathVal != false )
236 $swSVGConvInfo = self::execOutput( $execPathVal . $execPath . ' -version' );
237 list( $head, $tail ) = explode( 'ImageMagick', $swSVGConvInfo );
238 list( $swSVGConvVer ) = explode('http://www.imagemagick.org', $tail );
239 $swSVGConvURL = 'http://www.imagemagick.org/';
240 $haveSVGConvVer = true;
241 } else if ( strstr ($execFullPath, 'rsvg') != false ) {
242 // Get version info for rsvg
243 if ( file_exists( $execBinPath ) )
244 $swSVGConvInfo = self::execOutput( $execBinPath . ' -v' );
245 else if ( file_exists( trim( $execFullPath, '"' ) ) || ( file_exists( trim( $execFullPath, '"' ) . '.exe' ) ) )
246 $swSVGConvInfo = self::execOutput( $execFullPath . ' -v' );
247 else if ( $execPathVal != false )
248 $swSVGConvInfo = self::execOutput( $execPathVal . $execPath . ' -v' );
249 $swSVGConvLine = explode("\n",$swSVGConvInfo ,2);
250 $swSVGConvVer = $swSVGConvLine[0];
251 $swSVGConvURL = 'http://librsvg.sourceforge.net/';
252 $haveSVGConvVer = true;
253 } else if ( strstr ($execFullPath, 'inkscape') != false ) {
254 // Get version info for Inkscape
255 if ( file_exists( $execBinPath ) )
256 $swSVGConvInfo = self::execOutput( $execBinPath . ' -z -V' );
257 else if ( file_exists( trim( $execFullPath, '"' ) ) || ( file_exists( trim( $execFullPath, '"' ) . '.exe' ) ) )
258 $swSVGConvInfo = self::execOutput( $execFullPath . ' -z -V' );
259 else if ( $execPathVal != false )
260 $swSVGConvInfo = self::execOutput( $execPathVal . $execPath . ' -z -V' );
261 $swSVGConvLine = explode("\n",$swSVGConvInfo ,2);
262 $swSVGConvVer = ltrim( $swSVGConvLine[0], 'Inkscape ' );
263 $swSVGConvURL = 'http://www.inkscape.org/';
264 $swSVGConvName = ucfirst( $wgSVGConverter );
265 $haveSVGConvVer = true;
266 }
267 if ( $haveSVGConvVer )
268 $software["[$swSVGConvURL $swSVGConvName]"] = $swSVGConvVer;
269 }
270
271 // Look for TeX support and print the software version info
272 if ( $wgUseTeX ) {
273 $binPath = '/usr/bin/';
274 $swMathName = Array(
275 'ocaml' => 'OCaml',
276 'gs' => 'Ghostscript',
277 'dvips' => 'Dvips',
278 'latex' => 'LaTeX',
279 'imagemagick' => 'ImageMagick',
280 );
281 $swMathURL = Array(
282 'ocaml' => 'http://caml.inria.fr/',
283 'gs' => 'http://www.ghostscript.com/',
284 'dvips' => 'http://www.radicaleye.com/dvips.html',
285 'latex' => 'http://www.latex-project.org/',
286 'imagemagick' => 'http://www.imagemagick.org/',
287 );
288 $swMathExec = Array(
289 'ocaml' => 'ocamlc',
290 'gs' => 'gs',
291 'dvips' => 'dvips',
292 'latex' => 'latex',
293 'imagemagick' => 'convert',
294 );
295 $swMathParam = Array(
296 'ocaml' => '-version',
297 'gs' => '-v',
298 'dvips' => '-v',
299 'latex' => '-v',
300 'imagemagick' => '-version',
301 );
302 foreach ( $swMathExec as $swMath => $swMathCmd ) {
303 $wBinPath = '';
304 if ( file_exists( $binPath . 'whereis' ) ) {
305 $swWhereIsInfo = self::execOutput( $binPath . 'whereis -b ' . $swMathCmd );
306 $swWhereIsLine = explode( "\n", $swWhereIsInfo, 2);
307 $swWhereIsFirstLine = $swWhereIsLine[0];
308 $swWhereIsBinPath = explode( ' ', $swWhereIsFirstLine, 3);
309 if ( count( $swWhereIsBinPath ) > 1 )
310 $wBinPath = dirname( $swWhereIsBinPath[1] );
311 } else {
312 $swPathLine = explode( ';', $_SERVER['PATH'] );
313 $swPathFound = false;
314 foreach( $swPathLine as $swPathDir ) {
315 if ( file_exists( $swPathDir . '/' . $swMathCmd . '.exe' ) && ($swPathFound === false) ) {
316 $wBinPath = $swPathDir . '/';
317 $swPathFound = true;
318 }
319 }
320 }
321 if ( file_exists( $binPath . $swMathCmd ) || file_exists( $wBinPath . $swMathCmd ) ) {
322 $swMathInfo = self::execOutput( $swMathCmd . ' ' . $swMathParam[$swMath] );
323 $swMathLine = explode( "\n", $swMathInfo, 2);
324 $swMathVerInfo = $swMathLine[0];
325 if ( !strcmp( $swMath, 'gs' ) )
326 $swMathVerInfo = str_replace( 'GPL Ghostscript ', '', $swMathVerInfo );
327 else if ( !strcmp( $swMath, 'dvips' ) ) {
328 $swMathVerParts = explode( ' ' , $swMathVerInfo );
329 $swMathVerInfo = $swMathVerParts[3];
330 } else if ( !strcmp( $swMath, 'imagemagick' ) ) {
331 list( $head, $tail ) = explode( 'ImageMagick', $swMathVerInfo );
332 list( $swMathVerInfo ) = explode('http://www.imagemagick.org', $tail );
333 }
334 $swMathVer[$swMath] = trim( $swMathVerInfo );
335 $software["[$swMathURL[$swMath] $swMathName[$swMath]]"] = $swMathVer[$swMath];
336 }
337 }
338 }
339 }
340
341 // Allow a hook to add/remove items
342 wfRunHooks( 'SoftwareInfo', array( &$software ) );
343
344 $out = Xml::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
345 Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-software' ) ) .
346 "<tr>
347 <th>" . wfMsg( 'version-software-product' ) . "</th>
348 <th>" . wfMsg( 'version-software-version' ) . "</th>
349 </tr>\n";
350 foreach( $software as $name => $version ) {
351 $out .= "<tr>
352 <td>" . $name . "</td>
353 <td>" . $version . "</td>
354 </tr>\n";
355 }
356 return $out . Xml::closeElement( 'table' );
357 }
358
359 /**
360 * Return a string of the MediaWiki version with SVN revision if available
361 *
362 * @return mixed
363 */
364 public static function getVersion( $flags = '' ) {
365 global $wgVersion, $IP;
366 wfProfileIn( __METHOD__ );
367 $svn = self::getSvnRevision( $IP, false, false , false );
368 $svnCo = self::getSvnRevision( $IP, true, false , false );
369 if ( !$svn ) {
370 $version = $wgVersion;
371 } elseif( $flags === 'nodb' ) {
372 $version = "$wgVersion (r$svnCo)";
373 } else {
374 $version = $wgVersion . wfMsg( 'version-svn-revision', $svn, $svnCo );
375 }
376 wfProfileOut( __METHOD__ );
377 return $version;
378 }
379
380 /**
381 * Return a string of the MediaWiki version with a link to SVN revision if
382 * available
383 *
384 * @return mixed
385 */
386 public static function getVersionLinked() {
387 global $wgVersion, $IP;
388 wfProfileIn( __METHOD__ );
389 $svn = self::getSvnRevision( $IP, false, false, false );
390 $svnCo = self::getSvnRevision( $IP, true, false, false );
391 $svnDir = self::getSvnRevision( $IP, true, false, true );
392 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
393 $viewvcEnd = '/?pathrev=';
394 $viewvc = $viewvcStart . $svnDir . $viewvcEnd;
395 $version = $svn ? $wgVersion . " [{$viewvc}{$svnCo} " . wfMsg( 'version-svn-revision', $svn, $svnCo ) . ']' : $wgVersion;
396 wfProfileOut( __METHOD__ );
397 return $version;
398 }
399
400 /** Generate wikitext showing extensions name, URL, author and description */
401 function extensionCredits() {
402 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
403
404 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
405 return '';
406
407 $extensionTypes = array(
408 'specialpage' => wfMsg( 'version-specialpages' ),
409 'parserhook' => wfMsg( 'version-parserhooks' ),
410 'variable' => wfMsg( 'version-variables' ),
411 'media' => wfMsg( 'version-mediahandlers' ),
412 'other' => wfMsg( 'version-other' ),
413 );
414 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
415
416 $out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
417 Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) );
418
419 foreach ( $extensionTypes as $type => $text ) {
420 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
421 $out .= $this->openExtType( $text );
422
423 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
424
425 foreach ( $wgExtensionCredits[$type] as $extension ) {
426 $version = null;
427 $subVersion = null;
428 $subVersionCo = null;
429 $viewvc = null;
430 if ( isset( $extension['path'] ) ) {
431 $subVersion = self::getSvnRevision(dirname($extension['path']), false, true, false);
432 $subVersionCo = self::getSvnRevision(dirname($extension['path']), true, true, false);
433 $subVersionDir = self::getSvnRevision(dirname($extension['path']), false, true, true);
434 if ($subVersionDir)
435 $viewvc = $subVersionDir . $subVersionCo;
436 }
437 if ( isset( $extension['version'] ) ) {
438 $version = $extension['version'];
439 }
440
441 $out .= $this->formatCredits(
442 isset ( $extension['name'] ) ? $extension['name'] : '',
443 $version,
444 $subVersion,
445 $subVersionCo,
446 $viewvc,
447 isset ( $extension['author'] ) ? $extension['author'] : '',
448 isset ( $extension['url'] ) ? $extension['url'] : null,
449 isset ( $extension['description'] ) ? $extension['description'] : '',
450 isset ( $extension['descriptionmsg'] ) ? $extension['descriptionmsg'] : null
451 );
452 }
453 }
454 }
455
456 if ( count( $wgExtensionFunctions ) ) {
457 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
458 $out .= '<tr><td colspan="4">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
459 }
460
461 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
462 for ( $i = 0; $i < $cnt; ++$i )
463 $tags[$i] = "&lt;{$tags[$i]}&gt;";
464 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
465 $out .= '<tr><td colspan="4">' . $this->listToText( $tags ). "</td></tr>\n";
466 }
467
468 if( $cnt = count( $fhooks = $wgParser->getFunctionHooks() ) ) {
469 $out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ) );
470 $out .= '<tr><td colspan="4">' . $this->listToText( $fhooks ) . "</td></tr>\n";
471 }
472
473 if ( count( $wgSkinExtensionFunctions ) ) {
474 $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ) );
475 $out .= '<tr><td colspan="4">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
476 }
477 $out .= Xml::closeElement( 'table' );
478 return $out;
479 }
480
481 /** Callback to sort extensions by type */
482 function compare( $a, $b ) {
483 global $wgLang;
484 if( $a['name'] === $b['name'] ) {
485 return 0;
486 } else {
487 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
488 ? 1
489 : -1;
490 }
491 }
492
493 function formatCredits( $name, $version = null, $subVersion = null, $subVersionCo = null, $subVersionURL = null, $author = null, $url = null, $description = null, $descriptionMsg = null ) {
494 $haveSubversion = $subVersion;
495 $extension = isset( $url ) ? "[$url $name]" : $name;
496 $version = isset( $version ) ? '<span class="mw-version-ext-version">' . wfMsg( 'version-version', $version ) . '</span>' : '';
497 $subVersion = isset( $subVersion ) ? wfMsg( 'version-svn-revision', $subVersion, $subVersionCo ) : '';
498 $subVersion = isset( $subVersionURL ) ? "[$subVersionURL $subVersion]" : $subVersion;
499
500 # Look for a localized description
501 if( isset( $descriptionMsg ) ) {
502 if( is_array( $descriptionMsg ) ) {
503 $descriptionMsgKey = $descriptionMsg[0]; // Get the message key
504 array_shift( $descriptionMsg ); // Shift out the message key to get the parameters only
505 array_map( "htmlspecialchars", $descriptionMsg ); // For sanity
506 $msg = wfMsg( $descriptionMsgKey, $descriptionMsg );
507 } else {
508 $msg = wfMsg( $descriptionMsg );
509 }
510 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
511 $description = $msg;
512 }
513 }
514
515 if ( $haveSubversion ) {
516 $extNameVer = "<tr>
517 <td><em>$extension $version</em></td>
518 <td><em>$subVersion</em></td>";
519 } else {
520 $extNameVer = "<tr>
521 <td colspan=\"2\"><em>$extension $version</em></td>";
522 }
523 $extDescAuthor = "<td>$description</td>
524 <td>" . $this->listToText( (array)$author ) . "</td>
525 </tr>\n";
526 return $ret = $extNameVer . $extDescAuthor;
527 return $ret;
528 }
529
530 /**
531 * @return string
532 */
533 function wgHooks() {
534 global $wgHooks;
535
536 if ( count( $wgHooks ) ) {
537 $myWgHooks = $wgHooks;
538 ksort( $myWgHooks );
539
540 $ret = Xml::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
541 Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) ) .
542 "<tr>
543 <th>" . wfMsg( 'version-hook-name' ) . "</th>
544 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
545 </tr>\n";
546
547 foreach ( $myWgHooks as $hook => $hooks )
548 $ret .= "<tr>
549 <td>$hook</td>
550 <td>" . $this->listToText( $hooks ) . "</td>
551 </tr>\n";
552
553 $ret .= Xml::closeElement( 'table' );
554 return $ret;
555 } else
556 return '';
557 }
558
559 private function openExtType($text, $name = null) {
560 $opt = array( 'colspan' => 4 );
561 $out = '';
562
563 if(!$this->firstExtOpened) {
564 // Insert a spacing line
565 $out .= '<tr class="sv-space">' . Xml::element( 'td', $opt ) . "</tr>\n";
566 }
567 $this->firstExtOpened = false;
568
569 if($name) { $opt['id'] = "sv-$name"; }
570
571 $out .= "<tr>" . Xml::element( 'th', $opt, $text) . "</tr>\n";
572 return $out;
573 }
574
575 /**
576 * @return string
577 */
578 function IPInfo() {
579 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
580 return "<!-- visited from $ip -->\n" .
581 "<span style='display:none'>visited from $ip</span>";
582 }
583
584 /**
585 * @param array $list
586 * @return string
587 */
588 function listToText( $list ) {
589 $cnt = count( $list );
590
591 if ( $cnt == 1 ) {
592 // Enforce always returning a string
593 return (string)self::arrayToString( $list[0] );
594 } elseif ( $cnt == 0 ) {
595 return '';
596 } else {
597 global $wgLang;
598 sort( $list );
599 return $wgLang->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
600 }
601 }
602
603 /**
604 * @param mixed $list Will convert an array to string if given and return
605 * the paramater unaltered otherwise
606 * @return mixed
607 */
608 static function arrayToString( $list ) {
609 if( is_array( $list ) && count( $list ) == 1 )
610 $list = $list[0];
611 if( is_object( $list ) ) {
612 $class = get_class( $list );
613 return "($class)";
614 } elseif ( !is_array( $list ) ) {
615 return $list;
616 } else {
617 if( is_object( $list[0] ) )
618 $class = get_class( $list[0] );
619 else
620 $class = $list[0];
621 return "($class, {$list[1]})";
622 }
623 }
624
625 /**
626 * Retrieve the revision number of a Subversion working directory.
627 *
628 * @param String $dir Directory of the svn checkout
629 * @param Boolean $coRev optional to return value whether is Last Modified
630 * or Checkout revision number
631 * @param Boolean $extension optional to check the path whether is from
632 * Wikimedia SVN server or not
633 * @param Boolean $relPath optional to get the end part of the checkout path
634 * @return mixed revision number as int, end part of the checkout path,
635 * or false if not a SVN checkout
636 */
637 public static function getSvnRevision( $dir, $coRev = false, $extension = false, $relPath = false) {
638 // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
639 $entries = $dir . '/.svn/entries';
640
641 if( !file_exists( $entries ) ) {
642 return false;
643 }
644
645 $content = file( $entries );
646
647 // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
648 if( preg_match( '/^<\?xml/', $content[0] ) ) {
649 // subversion is release <= 1.3
650 if( !function_exists( 'simplexml_load_file' ) ) {
651 // We could fall back to expat... YUCK
652 return false;
653 }
654
655 // SimpleXml whines about the xmlns...
656 wfSuppressWarnings();
657 $xml = simplexml_load_file( $entries );
658 wfRestoreWarnings();
659
660 if( $xml ) {
661 foreach( $xml->entry as $entry ) {
662 if( $xml->entry[0]['name'] == '' ) {
663 // The directory entry should always have a revision marker.
664 if( $entry['revision'] ) {
665 return intval( $entry['revision'] );
666 }
667 }
668 }
669 }
670 return false;
671 } else {
672 // subversion is release 1.4 or above
673 if ($relPath) {
674 $endPath = strstr( $content[4], 'tags' );
675 if (!$endPath) {
676 $endPath = strstr( $content[4], 'branches' );
677 if (!$endPath) {
678 $endPath = strstr( $content[4], 'trunk' );
679 if (!$endPath)
680 return false;
681 }
682 }
683 $endPath = trim ( $endPath );
684 if ($extension) {
685 $wmSvnPath = 'svn.wikimedia.org/svnroot/mediawiki';
686 $isWMSvn = strstr($content[5],$wmSvnPath);
687 if (!strcmp($isWMSvn,null)) {
688 return false;
689 } else {
690 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
691 if (strstr( $content[4], 'trunk' ))
692 $viewvcEnd = '/?pathrev=';
693 else
694 // Avoids 404 error using pathrev when it does not found
695 $viewvcEnd = '/?revision=';
696 $viewvc = $viewvcStart . $endPath . $viewvcEnd;
697 return $viewvc;
698 }
699 }
700 return $endPath;
701 }
702 if ($coRev)
703 // get the directory checkout revsion number
704 return intval( $content[3]) ;
705 else
706 // get the directory last modified revision number
707 return intval( $content[10] );
708 }
709 }
710
711 /**#@-*/
712 }