quick fix for r52624: handle the case when the executable isn't found, since it's...
[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 }
244 if ( file_exists( $binPath . $swMathCmd ) || file_exists( $wBinPath . $swMathCmd ) ) {
245 $swMathInfo = self::execOutput( $swMathCmd . ' ' . $swMathParam[$swMath] );
246 $swMathLine = explode( "\n", $swMathInfo, 2);
247 $swMathVerInfo = $swMathLine[0];
248 if ( !strcmp( $swMath, 'gs' ) )
249 $swMathVerInfo = str_replace( 'GPL Ghostscript ', '', $swMathVerInfo );
250 else if ( !strcmp( $swMath, 'dvips' ) ) {
251 $swMathVerParts = explode( ' ' , $swMathVerInfo );
252 $swMathVerInfo = $swMathVerParts[3];
253 } else if ( !strcmp( $swMath, 'imagemagick' ) ) {
254 list( $head, $tail ) = explode( 'ImageMagick', $swMathVerInfo );
255 list( $swMathVerInfo ) = explode('http://www.imagemagick.org', $tail );
256 }
257 $swMathVer[$swMath] = trim( $swMathVerInfo );
258 $software["[$swMathURL[$swMath] $swMathName[$swMath]]"] = $swMathVer[$swMath];
259 }
260 }
261 }
262
263 // Allow a hook to add/remove items
264 wfRunHooks( 'SoftwareInfo', array( &$software ) );
265
266 $out = Xml::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
267 Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-software' ) ) .
268 "<tr>
269 <th>" . wfMsg( 'version-software-product' ) . "</th>
270 <th>" . wfMsg( 'version-software-version' ) . "</th>
271 </tr>\n";
272 foreach( $software as $name => $version ) {
273 $out .= "<tr>
274 <td>" . $name . "</td>
275 <td>" . $version . "</td>
276 </tr>\n";
277 }
278 return $out . Xml::closeElement( 'table' );
279 }
280
281 /**
282 * Return a string of the MediaWiki version with SVN revision if available
283 *
284 * @return mixed
285 */
286 public static function getVersion( $flags = '' ) {
287 global $wgVersion, $IP;
288 wfProfileIn( __METHOD__ );
289 $svn = self::getSvnRevision( $IP, false, false , false );
290 $svnCo = self::getSvnRevision( $IP, true, false , false );
291 if ( !$svn ) {
292 $version = $wgVersion;
293 } elseif( $flags === 'nodb' ) {
294 $version = "$wgVersion (r$svnCo)";
295 } else {
296 $version = $wgVersion . wfMsg( 'version-svn-revision', $svn, $svnCo );
297 }
298 wfProfileOut( __METHOD__ );
299 return $version;
300 }
301
302 /**
303 * Return a string of the MediaWiki version with a link to SVN revision if
304 * available
305 *
306 * @return mixed
307 */
308 public static function getVersionLinked() {
309 global $wgVersion, $IP;
310 wfProfileIn( __METHOD__ );
311 $svn = self::getSvnRevision( $IP, false, false, false );
312 $svnCo = self::getSvnRevision( $IP, true, false, false );
313 $svnDir = self::getSvnRevision( $IP, true, false, true );
314 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
315 $viewvcEnd = '/?pathrev=';
316 $viewvc = $viewvcStart . $svnDir . $viewvcEnd;
317 $version = $svn ? $wgVersion . " [{$viewvc}{$svnCo} " . wfMsg( 'version-svn-revision', $svn, $svnCo ) . ']' : $wgVersion;
318 wfProfileOut( __METHOD__ );
319 return $version;
320 }
321
322 /** Generate wikitext showing extensions name, URL, author and description */
323 function extensionCredits() {
324 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
325
326 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
327 return '';
328
329 $extensionTypes = array(
330 'specialpage' => wfMsg( 'version-specialpages' ),
331 'parserhook' => wfMsg( 'version-parserhooks' ),
332 'variable' => wfMsg( 'version-variables' ),
333 'media' => wfMsg( 'version-mediahandlers' ),
334 'other' => wfMsg( 'version-other' ),
335 );
336 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
337
338 $out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
339 Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) );
340
341 foreach ( $extensionTypes as $type => $text ) {
342 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
343 $out .= $this->openExtType( $text );
344
345 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
346
347 foreach ( $wgExtensionCredits[$type] as $extension ) {
348 $version = null;
349 $subVersion = null;
350 $subVersionCo = null;
351 $viewvc = null;
352 if ( isset( $extension['path'] ) ) {
353 $subVersion = self::getSvnRevision(dirname($extension['path']), false, true, false);
354 $subVersionCo = self::getSvnRevision(dirname($extension['path']), true, true, false);
355 $subVersionDir = self::getSvnRevision(dirname($extension['path']), false, true, true);
356 if ($subVersionDir)
357 $viewvc = $subVersionDir . $subVersionCo;
358 }
359 if ( isset( $extension['version'] ) ) {
360 $version = $extension['version'];
361 }
362
363 $out .= $this->formatCredits(
364 isset ( $extension['name'] ) ? $extension['name'] : '',
365 $version,
366 $subVersion,
367 $subVersionCo,
368 $viewvc,
369 isset ( $extension['author'] ) ? $extension['author'] : '',
370 isset ( $extension['url'] ) ? $extension['url'] : null,
371 isset ( $extension['description'] ) ? $extension['description'] : '',
372 isset ( $extension['descriptionmsg'] ) ? $extension['descriptionmsg'] : null
373 );
374 }
375 }
376 }
377
378 if ( count( $wgExtensionFunctions ) ) {
379 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
380 $out .= '<tr><td colspan="4">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
381 }
382
383 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
384 for ( $i = 0; $i < $cnt; ++$i )
385 $tags[$i] = "&lt;{$tags[$i]}&gt;";
386 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
387 $out .= '<tr><td colspan="4">' . $this->listToText( $tags ). "</td></tr>\n";
388 }
389
390 if( $cnt = count( $fhooks = $wgParser->getFunctionHooks() ) ) {
391 $out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ) );
392 $out .= '<tr><td colspan="4">' . $this->listToText( $fhooks ) . "</td></tr>\n";
393 }
394
395 if ( count( $wgSkinExtensionFunctions ) ) {
396 $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ) );
397 $out .= '<tr><td colspan="4">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
398 }
399 $out .= Xml::closeElement( 'table' );
400 return $out;
401 }
402
403 /** Callback to sort extensions by type */
404 function compare( $a, $b ) {
405 global $wgLang;
406 if( $a['name'] === $b['name'] ) {
407 return 0;
408 } else {
409 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
410 ? 1
411 : -1;
412 }
413 }
414
415 function formatCredits( $name, $version = null, $subVersion = null, $subVersionCo = null, $subVersionURL = null, $author = null, $url = null, $description = null, $descriptionMsg = null ) {
416 $haveSubversion = $subVersion;
417 $extension = isset( $url ) ? "[$url $name]" : $name;
418 $version = isset( $version ) ? wfMsg( 'version-version', $version ) : '';
419 $subVersion = isset( $subVersion ) ? wfMsg( 'version-svn-revision', $subVersion, $subVersionCo ) : '';
420 $subVersion = isset( $subVersionURL ) ? "[$subVersionURL $subVersion]" : $subVersion;
421
422 # Look for a localized description
423 if( isset( $descriptionMsg ) ) {
424 $msg = wfMsg( $descriptionMsg );
425 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
426 $description = $msg;
427 }
428 }
429
430 if ( $haveSubversion ) {
431 $extNameVer = "<tr>
432 <td><em>$extension $version</em></td>
433 <td><em>$subVersion</em></td>";
434 } else {
435 $extNameVer = "<tr>
436 <td colspan=\"2\"><em>$extension $version</em></td>";
437 }
438 $extDescAuthor = "<td>$description</td>
439 <td>" . $this->listToText( (array)$author ) . "</td>
440 </tr>\n";
441 return $ret = $extNameVer . $extDescAuthor;
442 return $ret;
443 }
444
445 /**
446 * @return string
447 */
448 function wgHooks() {
449 global $wgHooks;
450
451 if ( count( $wgHooks ) ) {
452 $myWgHooks = $wgHooks;
453 ksort( $myWgHooks );
454
455 $ret = Xml::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
456 Xml::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) ) .
457 "<tr>
458 <th>" . wfMsg( 'version-hook-name' ) . "</th>
459 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
460 </tr>\n";
461
462 foreach ( $myWgHooks as $hook => $hooks )
463 $ret .= "<tr>
464 <td>$hook</td>
465 <td>" . $this->listToText( $hooks ) . "</td>
466 </tr>\n";
467
468 $ret .= Xml::closeElement( 'table' );
469 return $ret;
470 } else
471 return '';
472 }
473
474 private function openExtType($text, $name = null) {
475 $opt = array( 'colspan' => 4 );
476 $out = '';
477
478 if(!$this->firstExtOpened) {
479 // Insert a spacing line
480 $out .= '<tr class="sv-space">' . Xml::element( 'td', $opt ) . "</tr>\n";
481 }
482 $this->firstExtOpened = false;
483
484 if($name) { $opt['id'] = "sv-$name"; }
485
486 $out .= "<tr>" . Xml::element( 'th', $opt, $text) . "</tr>\n";
487 return $out;
488 }
489
490 /**
491 * @return string
492 */
493 function IPInfo() {
494 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
495 return "<!-- visited from $ip -->\n" .
496 "<span style='display:none'>visited from $ip</span>";
497 }
498
499 /**
500 * @param array $list
501 * @return string
502 */
503 function listToText( $list ) {
504 $cnt = count( $list );
505
506 if ( $cnt == 1 ) {
507 // Enforce always returning a string
508 return (string)self::arrayToString( $list[0] );
509 } elseif ( $cnt == 0 ) {
510 return '';
511 } else {
512 global $wgLang;
513 sort( $list );
514 return $wgLang->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
515 }
516 }
517
518 /**
519 * @param mixed $list Will convert an array to string if given and return
520 * the paramater unaltered otherwise
521 * @return mixed
522 */
523 static function arrayToString( $list ) {
524 if( is_array( $list ) && count( $list ) == 1 )
525 $list = $list[0];
526 if( is_object( $list ) ) {
527 $class = get_class( $list );
528 return "($class)";
529 } elseif ( !is_array( $list ) ) {
530 return $list;
531 } else {
532 if( is_object( $list[0] ) )
533 $class = get_class( $list[0] );
534 else
535 $class = $list[0];
536 return "($class, {$list[1]})";
537 }
538 }
539
540 /**
541 * Retrieve the revision number of a Subversion working directory.
542 *
543 * @param String $dir Directory of the svn checkout
544 * @param Boolean $coRev optional to return value whether is Last Modified
545 * or Checkout revision number
546 * @param Boolean $extension optional to check the path whether is from
547 * Wikimedia SVN server or not
548 * @param Boolean $relPath optional to get the end part of the checkout path
549 * @return mixed revision number as int, end part of the checkout path,
550 * or false if not a SVN checkout
551 */
552 public static function getSvnRevision( $dir, $coRev = false, $extension = false, $relPath = false) {
553 // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
554 $entries = $dir . '/.svn/entries';
555
556 if( !file_exists( $entries ) ) {
557 return false;
558 }
559
560 $content = file( $entries );
561
562 // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
563 if( preg_match( '/^<\?xml/', $content[0] ) ) {
564 // subversion is release <= 1.3
565 if( !function_exists( 'simplexml_load_file' ) ) {
566 // We could fall back to expat... YUCK
567 return false;
568 }
569
570 // SimpleXml whines about the xmlns...
571 wfSuppressWarnings();
572 $xml = simplexml_load_file( $entries );
573 wfRestoreWarnings();
574
575 if( $xml ) {
576 foreach( $xml->entry as $entry ) {
577 if( $xml->entry[0]['name'] == '' ) {
578 // The directory entry should always have a revision marker.
579 if( $entry['revision'] ) {
580 return intval( $entry['revision'] );
581 }
582 }
583 }
584 }
585 return false;
586 } else {
587 // subversion is release 1.4 or above
588 if ($relPath) {
589 $endPath = strstr( $content[4], 'tags' );
590 if (!$endPath) {
591 $endPath = strstr( $content[4], 'branches' );
592 if (!$endPath) {
593 $endPath = strstr( $content[4], 'trunk' );
594 if (!$endPath)
595 return false;
596 }
597 }
598 $endPath = trim ( $endPath );
599 if ($extension) {
600 $wmSvnPath = 'svn.wikimedia.org/svnroot/mediawiki';
601 $isWMSvn = strstr($content[5],$wmSvnPath);
602 if (!strcmp($isWMSvn,null)) {
603 return false;
604 } else {
605 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
606 if (strstr( $content[4], 'trunk' ))
607 $viewvcEnd = '/?pathrev=';
608 else
609 // Avoids 404 error using pathrev when it does not found
610 $viewvcEnd = '/?revision=';
611 $viewvc = $viewvcStart . $endPath . $viewvcEnd;
612 return $viewvc;
613 }
614 }
615 return $endPath;
616 }
617 if ($coRev)
618 // get the directory checkout revsion number
619 return intval( $content[3]) ;
620 else
621 // get the directory last modified revision number
622 return intval( $content[10] );
623 }
624 }
625
626 /**#@-*/
627 }