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