e589af932ba4ca48dabed50d4c44d04120ebadd1
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>' );
51 * @return wiki text showing the license information
53 static function MediaWikiCredits() {
56 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-license' ), wfMsg( 'version-license' ) );
58 // This text is always left-to-right.
59 $ret .= '<div dir="ltr">';
61 This wiki is powered by '''[http://www.mediawiki.org/ MediaWiki]''',
62 copyright © 2001-2009 Magnus Manske, Brion Vibber, Lee Daniel Crocker,
63 Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason,
64 Niklas Laxström, Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor,
65 Aaron Schulz and others.
67 MediaWiki is free software; you can redistribute it and/or modify
68 it under the terms of the GNU General Public License as published by
69 the Free Software Foundation; either version 2 of the License, or
70 (at your option) any later version.
72 MediaWiki is distributed in the hope that it will be useful,
73 but WITHOUT ANY WARRANTY; without even the implied warranty of
74 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
75 GNU General Public License for more details.
77 You should have received [{{SERVER}}{{SCRIPTPATH}}/COPYING a copy of the GNU General Public License]
78 along with this program; if not, write to the Free Software
79 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
80 or [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].
84 return str_replace( "\t\t", '', $ret ) . "\n";
88 * @return wiki text showing the third party software versions (apache, php, mysql).
90 static function softwareInformation() {
91 $dbr = wfGetDB( DB_SLAVE
);
93 // Put the software in an array of form 'name' => 'version'. All messages should
94 // be loaded here, so feel free to use wfMsg*() in the 'name'. Raw HTML or wikimarkup
97 $software['[http://www.mediawiki.org/ MediaWiki]'] = self
::getVersionLinked();
98 $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . php_sapi_name() . ")";
99 $software[$dbr->getSoftwareLink()] = $dbr->getServerVersion();
101 // Allow a hook to add/remove items
102 wfRunHooks( 'SoftwareInfo', array( &$software ) );
104 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
105 Xml
::openElement( 'table', array( 'id' => 'sv-software' ) ) .
107 <th>" . wfMsg( 'version-software-product' ) . "</th>
108 <th>" . wfMsg( 'version-software-version' ) . "</th>
110 foreach( $software as $name => $version ) {
112 <td>" . $name . "</td>
113 <td>" . $version . "</td>
116 return $out . Xml
::closeElement( 'table' );
120 * Return a string of the MediaWiki version with SVN revision if available
124 public static function getVersion( $flags = '' ) {
125 global $wgVersion, $IP;
126 wfProfileIn( __METHOD__
);
127 $svn = self
::getSvnRevision( $IP, false, false , false );
128 $svnCo = self
::getSvnRevision( $IP, true, false , false );
130 $version = $wgVersion;
131 } elseif( $flags === 'nodb' ) {
132 $version = "$wgVersion (r$svnCo)";
134 $version = $wgVersion . wfMsg( 'version-svn-revision', $svn, $svnCo );
136 wfProfileOut( __METHOD__
);
141 * Return a string of the MediaWiki version with a link to SVN revision if
146 public static function getVersionLinked() {
147 global $wgVersion, $IP;
148 wfProfileIn( __METHOD__
);
149 $svn = self
::getSvnRevision( $IP, false, false, false );
150 $svnCo = self
::getSvnRevision( $IP, true, false, false );
151 $svnDir = self
::getSvnRevision( $IP, true, false, true );
152 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
153 $viewvcEnd = '/?pathrev=';
154 $viewvc = $viewvcStart . $svnDir . $viewvcEnd;
155 $version = $svn ?
$wgVersion . " [{$viewvc}{$svnCo} " . wfMsg( 'version-svn-revision', $svn, $svnCo ) . ']' : $wgVersion;
156 wfProfileOut( __METHOD__
);
160 /** Generate wikitext showing extensions name, URL, author and description */
161 function extensionCredits() {
162 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
164 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
167 $extensionTypes = array(
168 'specialpage' => wfMsg( 'version-specialpages' ),
169 'parserhook' => wfMsg( 'version-parserhooks' ),
170 'variable' => wfMsg( 'version-variables' ),
171 'media' => wfMsg( 'version-mediahandlers' ),
172 'other' => wfMsg( 'version-other' ),
174 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
176 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
177 Xml
::openElement( 'table', array( 'id' => 'sv-ext' ) );
179 foreach ( $extensionTypes as $type => $text ) {
180 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
181 $out .= $this->openExtType( $text );
183 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
185 foreach ( $wgExtensionCredits[$type] as $extension ) {
188 $subVersionCo = null;
190 if ( isset( $extension['path'] ) ) {
191 $subVersion = self
::getSvnRevision(dirname($extension['path']), false, true, false);
192 $subVersionCo = self
::getSvnRevision(dirname($extension['path']), true, true, false);
193 $subVersionDir = self
::getSvnRevision(dirname($extension['path']), false, true, true);
195 $viewvc = $subVersionDir . $subVersionCo;
197 if ( isset( $extension['version'] ) ) {
198 $version = $extension['version'];
201 $out .= $this->formatCredits(
202 isset ( $extension['name'] ) ?
$extension['name'] : '',
207 isset ( $extension['author'] ) ?
$extension['author'] : '',
208 isset ( $extension['url'] ) ?
$extension['url'] : null,
209 isset ( $extension['description'] ) ?
$extension['description'] : '',
210 isset ( $extension['descriptionmsg'] ) ?
$extension['descriptionmsg'] : ''
216 if ( count( $wgExtensionFunctions ) ) {
217 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
218 $out .= '<tr><td colspan="4">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
221 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
222 for ( $i = 0; $i < $cnt; ++
$i )
223 $tags[$i] = "<{$tags[$i]}>";
224 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
225 $out .= '<tr><td colspan="4">' . $this->listToText( $tags ). "</td></tr>\n";
228 if( $cnt = count( $fhooks = $wgParser->getFunctionHooks() ) ) {
229 $out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ) );
230 $out .= '<tr><td colspan="4">' . $this->listToText( $fhooks ) . "</td></tr>\n";
233 if ( count( $wgSkinExtensionFunctions ) ) {
234 $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ) );
235 $out .= '<tr><td colspan="4">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
237 $out .= Xml
::closeElement( 'table' );
241 /** Callback to sort extensions by type */
242 function compare( $a, $b ) {
244 if( $a['name'] === $b['name'] ) {
247 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
253 function formatCredits( $name, $version = null, $subVersion = null, $subVersionCo = null, $subVersionURL = null, $author = null, $url = null, $description = null, $descriptionMsg = null ) {
254 $haveSubversion = $subVersion;
255 $extension = isset( $url ) ?
"[$url $name]" : $name;
256 $version = isset( $version ) ?
wfMsg( 'version-version', $version ) : '';
257 $subVersion = isset( $subVersion ) ?
wfMsg( 'version-svn-revision', $subVersion, $subVersionCo ) : '';
258 $subVersion = isset( $subVersionURL ) ?
"[$subVersionURL $subVersion]" : $subVersion;
260 # Look for a localized description
261 if( isset( $descriptionMsg ) ) {
262 $msg = wfMsg( $descriptionMsg );
263 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
268 if ( $haveSubversion ) {
270 <td><em>$extension $version</em></td>
271 <td><em>$subVersion</em></td>";
274 <td colspan=\"2\"><em>$extension $version</em></td>";
276 $extDescAuthor = "<td>$description</td>
277 <td>" . $this->listToText( (array)$author ) . "</td>
279 return $ret = $extNameVer . $extDescAuthor;
289 if ( count( $wgHooks ) ) {
290 $myWgHooks = $wgHooks;
293 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
294 Xml
::openElement( 'table', array( 'id' => 'sv-hooks' ) ) .
296 <th>" . wfMsg( 'version-hook-name' ) . "</th>
297 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
300 foreach ( $myWgHooks as $hook => $hooks )
303 <td>" . $this->listToText( $hooks ) . "</td>
306 $ret .= Xml
::closeElement( 'table' );
312 private function openExtType($text, $name = null) {
313 $opt = array( 'colspan' => 4 );
316 if(!$this->firstExtOpened
) {
317 // Insert a spacing line
318 $out .= '<tr class="sv-space">' . Xml
::element( 'td', $opt ) . "</tr>\n";
320 $this->firstExtOpened
= false;
322 if($name) { $opt['id'] = "sv-$name"; }
324 $out .= "<tr>" . Xml
::element( 'th', $opt, $text) . "</tr>\n";
332 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
333 return "<!-- visited from $ip -->\n" .
334 "<span style='display:none'>visited from $ip</span>";
341 function listToText( $list ) {
342 $cnt = count( $list );
345 // Enforce always returning a string
346 return (string)self
::arrayToString( $list[0] );
347 } elseif ( $cnt == 0 ) {
352 return $wgLang->listToText( array_map( array( __CLASS__
, 'arrayToString' ), $list ) );
357 * @param mixed $list Will convert an array to string if given and return
358 * the paramater unaltered otherwise
361 static function arrayToString( $list ) {
362 if( is_array( $list ) && count( $list ) == 1 )
364 if( is_object( $list ) ) {
365 $class = get_class( $list );
367 } elseif ( !is_array( $list ) ) {
370 if( is_object( $list[0] ) )
371 $class = get_class( $list[0] );
374 return "($class, {$list[1]})";
379 * Retrieve the revision number of a Subversion working directory.
381 * @param String $dir Directory of the svn checkout
382 * @param Boolean $coRev optional to return value whether is Last Modified
383 * or Checkout revision number
384 * @param Boolean $extension optional to check the path whether is from
385 * Wikimedia SVN server or not
386 * @param Boolean $relPath optional to get the end part of the checkout path
387 * @return mixed revision number as int, end part of the checkout path,
388 * or false if not a SVN checkout
390 public static function getSvnRevision( $dir, $coRev = false, $extension = false, $relPath = false) {
391 // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
392 $entries = $dir . '/.svn/entries';
394 if( !file_exists( $entries ) ) {
398 $content = file( $entries );
400 // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
401 if( preg_match( '/^<\?xml/', $content[0] ) ) {
402 // subversion is release <= 1.3
403 if( !function_exists( 'simplexml_load_file' ) ) {
404 // We could fall back to expat... YUCK
408 // SimpleXml whines about the xmlns...
409 wfSuppressWarnings();
410 $xml = simplexml_load_file( $entries );
414 foreach( $xml->entry
as $entry ) {
415 if( $xml->entry
[0]['name'] == '' ) {
416 // The directory entry should always have a revision marker.
417 if( $entry['revision'] ) {
418 return intval( $entry['revision'] );
425 // subversion is release 1.4 or above
427 $endPath = strstr( $content[4], 'tags' );
429 $endPath = strstr( $content[4], 'branches' );
431 $endPath = strstr( $content[4], 'trunk' );
436 $endPath = trim ( $endPath );
438 $wmSvnPath = 'svn.wikimedia.org/svnroot/mediawiki';
439 $isWMSvn = strstr($content[5],$wmSvnPath);
440 if (!strcmp($isWMSvn,null)) {
443 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
444 if (strstr( $content[4], 'trunk' ))
445 $viewvcEnd = '/?pathrev=';
447 // Avoids 404 error using pathrev when it does not found
448 $viewvcEnd = '/?revision=';
449 $viewvc = $viewvcStart . $endPath . $viewvcEnd;
456 // get the directory checkout revsion number
457 return intval( $content[3]) ;
459 // get the directory last modified revision number
460 return intval( $content[10] );