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;
24 $wgMessageCache->loadAllMessages();
27 $this->outputHeader();
29 $wgOut->addHTML( '<div dir="ltr">' );
31 $this->MediaWikiCredits() .
32 $this->softwareInformation() .
33 $this->extensionCredits();
34 if ( $wgSpecialVersionShowHooks ) {
35 $text .= $this->wgHooks();
37 $wgOut->addWikiText( $text );
38 $wgOut->addHTML( $this->IPInfo() );
39 $wgOut->addHTML( '</div>' );
47 * @return wiki text showing the license information
49 static function MediaWikiCredits() {
50 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-license' ), wfMsg( 'version-license' ) ) .
52 This wiki is powered by '''[http://www.mediawiki.org/ MediaWiki]''',
53 copyright (C) 2001-2009 Magnus Manske, Brion Vibber, Lee Daniel Crocker,
54 Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason,
55 Niklas Laxström, Domas Mituzas, Rob Church, Yuri Astrakhan, Aryeh Gregor,
56 Aaron Schulz and others.
58 MediaWiki is free software; you can redistribute it and/or modify
59 it under the terms of the GNU General Public License as published by
60 the Free Software Foundation; either version 2 of the License, or
61 (at your option) any later version.
63 MediaWiki is distributed in the hope that it will be useful,
64 but WITHOUT ANY WARRANTY; without even the implied warranty of
65 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
66 GNU General Public License for more details.
68 You should have received [{{SERVER}}{{SCRIPTPATH}}/COPYING a copy of the GNU General Public License]
69 along with this program; if not, write to the Free Software
70 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
71 or [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].
74 return str_replace( "\t\t", '', $ret ) . "\n";
78 * @return wiki text showing the third party software versions (apache, php, mysql).
80 static function softwareInformation() {
81 $dbr = wfGetDB( DB_SLAVE
);
83 // Put the software in an array of form 'name' => 'version'. All messages should
84 // be loaded here, so feel free to use wfMsg*() in the 'name'. Raw HTML or wikimarkup
87 $software['[http://www.mediawiki.org/ MediaWiki]'] = self
::getVersionLinked();
88 $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . php_sapi_name() . ")";
89 $software[$dbr->getSoftwareLink()] = $dbr->getServerVersion();
91 // Allow a hook to add/remove items
92 wfRunHooks( 'SoftwareInfo', array( &$software ) );
94 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
95 Xml
::openElement( 'table', array( 'id' => 'sv-software' ) ) .
97 <th>" . wfMsg( 'version-software-product' ) . "</th>
98 <th>" . wfMsg( 'version-software-version' ) . "</th>
100 foreach( $software as $name => $version ) {
102 <td>" . $name . "</td>
103 <td>" . $version . "</td>
106 return $out . Xml
::closeElement( 'table' );
110 * Return a string of the MediaWiki version with SVN revision if available
114 public static function getVersion() {
115 global $wgVersion, $IP;
116 wfProfileIn( __METHOD__
);
117 $svn = self
::getSvnRevision( $IP, false );
118 $version = $svn ?
"$wgVersion (r$svn)" : $wgVersion;
119 wfProfileOut( __METHOD__
);
124 * Return a string of the MediaWiki version with a link to SVN revision if
129 public static function getVersionLinked() {
130 global $wgVersion, $IP;
131 wfProfileIn( __METHOD__
);
132 $svn = self
::getSvnRevision( $IP, false );
133 $viewvc = 'http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/?pathrev=';
134 $version = $svn ?
"$wgVersion ([{$viewvc}{$svn} r$svn])" : $wgVersion;
135 wfProfileOut( __METHOD__
);
139 /** Generate wikitext showing extensions name, URL, author and description */
140 function extensionCredits() {
141 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
143 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
146 $extensionTypes = array(
147 'specialpage' => wfMsg( 'version-specialpages' ),
148 'parserhook' => wfMsg( 'version-parserhooks' ),
149 'variable' => wfMsg( 'version-variables' ),
150 'media' => wfMsg( 'version-mediahandlers' ),
151 'other' => wfMsg( 'version-other' ),
153 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
155 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
156 Xml
::openElement( 'table', array( 'id' => 'sv-ext' ) );
158 foreach ( $extensionTypes as $type => $text ) {
159 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
160 $out .= $this->openExtType( $text );
162 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
164 foreach ( $wgExtensionCredits[$type] as $extension ) {
167 if (isset($extension['path']))
168 $subVersion = self
::getSvnRevision(dirname($extension['path']), true);
169 if ( isset( $extension['version'] ) ) {
170 $version = $extension['version'];
173 $out .= $this->formatCredits(
174 isset ( $extension['name'] ) ?
$extension['name'] : '',
177 isset ( $extension['author'] ) ?
$extension['author'] : '',
178 isset ( $extension['url'] ) ?
$extension['url'] : null,
179 isset ( $extension['description'] ) ?
$extension['description'] : '',
180 isset ( $extension['descriptionmsg'] ) ?
$extension['descriptionmsg'] : ''
186 if ( count( $wgExtensionFunctions ) ) {
187 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
188 $out .= '<tr><td colspan="3">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
191 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
192 for ( $i = 0; $i < $cnt; ++
$i )
193 $tags[$i] = "<{$tags[$i]}>";
194 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
195 $out .= '<tr><td colspan="3">' . $this->listToText( $tags ). "</td></tr>\n";
198 if( $cnt = count( $fhooks = $wgParser->getFunctionHooks() ) ) {
199 $out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ) );
200 $out .= '<tr><td colspan="3">' . $this->listToText( $fhooks ) . "</td></tr>\n";
203 if ( count( $wgSkinExtensionFunctions ) ) {
204 $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ) );
205 $out .= '<tr><td colspan="3">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
207 $out .= Xml
::closeElement( 'table' );
211 /** Callback to sort extensions by type */
212 function compare( $a, $b ) {
214 if( $a['name'] === $b['name'] ) {
217 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
223 function formatCredits( $name, $version = null, $subVersion = null, $author = null, $url = null, $description = null, $descriptionMsg = null ) {
224 $extension = isset( $url ) ?
"[$url $name]" : $name;
225 $version = isset( $version ) ?
"(" . wfMsg( 'version-version' ) . " $version)" : '';
226 $subVersion = isset( $subVersion ) ?
"(" . wfMsg( 'version-revision' ) . " r$subVersion)" : '';
228 # Look for a localized description
229 if( isset( $descriptionMsg ) ) {
230 $msg = wfMsg( $descriptionMsg );
231 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
237 <td><em>$extension $version $subVersion</em></td>
238 <td>$description</td>
239 <td>" . $this->listToText( (array)$author ) . "</td>
249 if ( count( $wgHooks ) ) {
250 $myWgHooks = $wgHooks;
253 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
254 Xml
::openElement( 'table', array( 'id' => 'sv-hooks' ) ) .
256 <th>" . wfMsg( 'version-hook-name' ) . "</th>
257 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
260 foreach ( $myWgHooks as $hook => $hooks )
263 <td>" . $this->listToText( $hooks ) . "</td>
266 $ret .= Xml
::closeElement( 'table' );
272 private function openExtType($text, $name = null) {
273 $opt = array( 'colspan' => 3 );
276 if(!$this->firstExtOpened
) {
277 // Insert a spacing line
278 $out .= '<tr class="sv-space">' . Xml
::element( 'td', $opt ) . "</tr>\n";
280 $this->firstExtOpened
= false;
282 if($name) { $opt['id'] = "sv-$name"; }
284 $out .= "<tr>" . Xml
::element( 'th', $opt, $text) . "</tr>\n";
292 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
293 return "<!-- visited from $ip -->\n" .
294 "<span style='display:none'>visited from $ip</span>";
301 function listToText( $list ) {
302 $cnt = count( $list );
305 // Enforce always returning a string
306 return (string)self
::arrayToString( $list[0] );
307 } elseif ( $cnt == 0 ) {
312 return $wgLang->listToText( array_map( array( __CLASS__
, 'arrayToString' ), $list ) );
317 * @param mixed $list Will convert an array to string if given and return
318 * the paramater unaltered otherwise
321 static function arrayToString( $list ) {
322 if( is_array( $list ) && count( $list ) == 1 )
324 if( is_object( $list ) ) {
325 $class = get_class( $list );
327 } elseif ( !is_array( $list ) ) {
330 if( is_object( $list[0] ) )
331 $class = get_class( $list[0] );
334 return "($class, {$list[1]})";
339 * Retrieve the revision number of a Subversion working directory.
342 * @return mixed revision number as int, or false if not a SVN checkout
344 public static function getSvnRevision( $dir , $extension = false) {
345 // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
346 $entries = $dir . '/.svn/entries';
348 if( !file_exists( $entries ) ) {
352 $content = file( $entries );
354 // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
355 if( preg_match( '/^<\?xml/', $content[0] ) ) {
356 // subversion is release <= 1.3
357 if( !function_exists( 'simplexml_load_file' ) ) {
358 // We could fall back to expat... YUCK
362 // SimpleXml whines about the xmlns...
363 wfSuppressWarnings();
364 $xml = simplexml_load_file( $entries );
368 foreach( $xml->entry
as $entry ) {
369 if( $xml->entry
[0]['name'] == '' ) {
370 // The directory entry should always have a revision marker.
371 if( $entry['revision'] ) {
372 return intval( $entry['revision'] );
379 // subversion is release 1.4 or above
381 // get the last file revsion number
382 return intval( $content[10]) ;
384 // get the directory revsion number
385 return intval( $content[3] );