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