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