4 * Give information about the version of MediaWiki, PHP, the DB and extensions
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
12 class SpecialVersion
extends SpecialPage
{
13 private $firstExtOpened = true;
15 function __construct(){
16 parent
::__construct( 'Version' );
22 function execute( $par ) {
23 global $wgOut, $wgMessageCache, $wgSpecialVersionShowHooks, $wgContLang;
24 $wgMessageCache->loadAllMessages();
27 $this->outputHeader();
29 if( $wgContLang->isRTL() ) {
30 $wgOut->addHTML( '<div dir="rtl">' );
32 $wgOut->addHTML( '<div dir="ltr">' );
35 $this->MediaWikiCredits() .
36 $this->softwareInformation() .
37 $this->extensionCredits();
38 if ( $wgSpecialVersionShowHooks ) {
39 $text .= $this->wgHooks();
41 $wgOut->addWikiText( $text );
42 $wgOut->addHTML( $this->IPInfo() );
43 $wgOut->addHTML( '</div>' );
47 * check executive path existence
48 * @param string command
49 * @return mixed existsIn
51 static function checkExecPath( $cmd ) {
53 $pathDirArray = explode( ';' , $_SERVER['PATH'] );
54 foreach ( $pathDirArray as $pathDir ) {
55 $pathDir = str_replace('\\', '/', $pathDir);
57 if ( ( file_exists ( $pathDir . '/' . $cmd ) ) ||
( file_exists( trim( $pathDir . '/' . $cmd, '"' ) . '.exe' ) ) ) {
65 * execuate command for output
66 * @param string command
67 * @return string output
69 static function execOutput( $cmd ) {
71 exec( $cmd.' 2>&1', $out );
73 return implode("\n", $out );
81 * @return wiki text showing the license information
83 static function MediaWikiCredits() {
86 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-license' ), wfMsg( 'version-license' ) );
88 // This text is always left-to-right.
89 $ret .= '<div dir="ltr">';
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.
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.
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.
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].
115 return str_replace( "\t\t", '', $ret ) . "\n";
119 * @return wiki text showing the third party software versions (apache, php, mysql).
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
);
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
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();
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 ) {
142 $serverSoftware = trim( substr( $serverSoftware, 0, strrpos($serverSoftware,'PHP') - 1 ) );
145 // Get the web server name and its version.
146 $serverSoftwareLine = explode('/',$serverSoftware);
147 $serverSoftwareName = $serverSoftwareLine[0];
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/';
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];
168 $serverSoftwareVersion = '';
171 if ( isset( $serverSoftwareURL ) )
172 $software["[$serverSoftwareURL $serverSoftwareName]"] = $serverSoftwareVersion;
174 $software[$serverSoftwareName] = $serverSoftwareVersion;
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;
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;
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;
203 if( function_exists( 'gd_info' ) ) {
205 if ( strstr( $gdInfo['GD Version'], 'bundled' ) != false ) {
206 $gd_URL = 'http://www.php.net/gd';
208 $gd_URL = 'http://www.libgd.org';
210 $software['[' . $gd_URL . ' GD library]'] = $gdInfo['GD Version'];
214 // Look for SVG converter and print the version info
215 if ( in_array( 'svg', $wgFileExtensions ) ) {
216 $swSVGConvName = $wgSVGConverter;
218 $haveSVGConvVer = false;
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 . '"';
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;
267 if ( $haveSVGConvVer )
268 $software["[$swSVGConvURL $swSVGConvName]"] = $swSVGConvVer;
271 // Look for TeX support and print the software version info
273 $binPath = '/usr/bin/';
276 'gs' => 'Ghostscript',
279 'imagemagick' => 'ImageMagick',
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/',
293 'imagemagick' => 'convert',
295 $swMathParam = Array(
296 'ocaml' => '-version',
300 'imagemagick' => '-version',
302 foreach ( $swMathExec as $swMath => $swMathCmd ) {
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] );
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 . '/';
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 );
334 $swMathVer[$swMath] = trim( $swMathVerInfo );
335 $software["[$swMathURL[$swMath] $swMathName[$swMath]]"] = $swMathVer[$swMath];
341 // Allow a hook to add/remove items
342 wfRunHooks( 'SoftwareInfo', array( &$software ) );
344 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
345 Xml
::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-software' ) ) .
347 <th>" . wfMsg( 'version-software-product' ) . "</th>
348 <th>" . wfMsg( 'version-software-version' ) . "</th>
350 foreach( $software as $name => $version ) {
352 <td>" . $name . "</td>
353 <td>" . $version . "</td>
356 return $out . Xml
::closeElement( 'table' );
360 * Return a string of the MediaWiki version with SVN revision if available
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 );
370 $version = $wgVersion;
371 } elseif( $flags === 'nodb' ) {
372 $version = "$wgVersion (r$svnCo)";
374 $version = $wgVersion . wfMsg( 'version-svn-revision', $svn, $svnCo );
376 wfProfileOut( __METHOD__
);
381 * Return a string of the MediaWiki version with a link to SVN revision if
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__
);
400 /** Generate wikitext showing extensions name, URL, author and description */
401 function extensionCredits() {
402 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
404 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
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' ),
414 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
416 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
417 Xml
::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) );
419 foreach ( $extensionTypes as $type => $text ) {
420 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
421 $out .= $this->openExtType( $text );
423 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
425 foreach ( $wgExtensionCredits[$type] as $extension ) {
428 $subVersionCo = 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);
435 $viewvc = $subVersionDir . $subVersionCo;
437 if ( isset( $extension['version'] ) ) {
438 $version = $extension['version'];
441 $out .= $this->formatCredits(
442 isset ( $extension['name'] ) ?
$extension['name'] : '',
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
456 if ( count( $wgExtensionFunctions ) ) {
457 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
458 $out .= '<tr><td colspan="4">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
461 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
462 for ( $i = 0; $i < $cnt; ++
$i )
463 $tags[$i] = "<{$tags[$i]}>";
464 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
465 $out .= '<tr><td colspan="4">' . $this->listToText( $tags ). "</td></tr>\n";
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";
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";
477 $out .= Xml
::closeElement( 'table' );
481 /** Callback to sort extensions by type */
482 function compare( $a, $b ) {
484 if( $a['name'] === $b['name'] ) {
487 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
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;
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 );
508 $msg = wfMsg( $descriptionMsg );
510 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
515 if ( $haveSubversion ) {
517 <td><em>$extension $version</em></td>
518 <td><em>$subVersion</em></td>";
521 <td colspan=\"2\"><em>$extension $version</em></td>";
523 $extDescAuthor = "<td>$description</td>
524 <td>" . $this->listToText( (array)$author ) . "</td>
526 return $ret = $extNameVer . $extDescAuthor;
536 if ( count( $wgHooks ) ) {
537 $myWgHooks = $wgHooks;
540 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
541 Xml
::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) ) .
543 <th>" . wfMsg( 'version-hook-name' ) . "</th>
544 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
547 foreach ( $myWgHooks as $hook => $hooks )
550 <td>" . $this->listToText( $hooks ) . "</td>
553 $ret .= Xml
::closeElement( 'table' );
559 private function openExtType($text, $name = null) {
560 $opt = array( 'colspan' => 4 );
563 if(!$this->firstExtOpened
) {
564 // Insert a spacing line
565 $out .= '<tr class="sv-space">' . Xml
::element( 'td', $opt ) . "</tr>\n";
567 $this->firstExtOpened
= false;
569 if($name) { $opt['id'] = "sv-$name"; }
571 $out .= "<tr>" . Xml
::element( 'th', $opt, $text) . "</tr>\n";
579 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
580 return "<!-- visited from $ip -->\n" .
581 "<span style='display:none'>visited from $ip</span>";
588 function listToText( $list ) {
589 $cnt = count( $list );
592 // Enforce always returning a string
593 return (string)self
::arrayToString( $list[0] );
594 } elseif ( $cnt == 0 ) {
599 return $wgLang->listToText( array_map( array( __CLASS__
, 'arrayToString' ), $list ) );
604 * @param mixed $list Will convert an array to string if given and return
605 * the paramater unaltered otherwise
608 static function arrayToString( $list ) {
609 if( is_array( $list ) && count( $list ) == 1 )
611 if( is_object( $list ) ) {
612 $class = get_class( $list );
614 } elseif ( !is_array( $list ) ) {
617 if( is_object( $list[0] ) )
618 $class = get_class( $list[0] );
621 return "($class, {$list[1]})";
626 * Retrieve the revision number of a Subversion working directory.
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
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';
641 if( !file_exists( $entries ) ) {
645 $content = file( $entries );
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
655 // SimpleXml whines about the xmlns...
656 wfSuppressWarnings();
657 $xml = simplexml_load_file( $entries );
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'] );
672 // subversion is release 1.4 or above
674 $endPath = strstr( $content[4], 'tags' );
676 $endPath = strstr( $content[4], 'branches' );
678 $endPath = strstr( $content[4], 'trunk' );
683 $endPath = trim ( $endPath );
685 $wmSvnPath = 'svn.wikimedia.org/svnroot/mediawiki';
686 $isWMSvn = strstr($content[5],$wmSvnPath);
687 if (!strcmp($isWMSvn,null)) {
690 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
691 if (strstr( $content[4], 'trunk' ))
692 $viewvcEnd = '/?pathrev=';
694 // Avoids 404 error using pathrev when it does not found
695 $viewvcEnd = '/?revision=';
696 $viewvc = $viewvcStart . $endPath . $viewvcEnd;
703 // get the directory checkout revsion number
704 return intval( $content[3]) ;
706 // get the directory last modified revision number
707 return intval( $content[10] );