571a010efbf42842632fb472dae64c8488511cbf
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, Andrew Garrett, Raimond Spekking, Alexandre Emsenhuber,
66 Siebrand Mazeland, Chad Horohoe and others.
68 MediaWiki is free software; you can redistribute it and/or modify
69 it under the terms of the GNU General Public License as published by
70 the Free Software Foundation; either version 2 of the License, or
71 (at your option) any later version.
73 MediaWiki is distributed in the hope that it will be useful,
74 but WITHOUT ANY WARRANTY; without even the implied warranty of
75 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76 GNU General Public License for more details.
78 You should have received [{{SERVER}}{{SCRIPTPATH}}/COPYING a copy of the GNU General Public License]
79 along with this program; if not, write to the Free Software
80 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
81 or [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].
85 return str_replace( "\t\t", '', $ret ) . "\n";
89 * @return wiki text showing the third party software versions (apache, php, mysql).
91 static function softwareInformation() {
92 $dbr = wfGetDB( DB_SLAVE
);
94 // Put the software in an array of form 'name' => 'version'. All messages should
95 // be loaded here, so feel free to use wfMsg*() in the 'name'. Raw HTML or wikimarkup
98 $software['[http://www.mediawiki.org/ MediaWiki]'] = self
::getVersionLinked();
99 $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . php_sapi_name() . ")";
100 $software[$dbr->getSoftwareLink()] = $dbr->getServerVersion();
102 // Allow a hook to add/remove items
103 wfRunHooks( 'SoftwareInfo', array( &$software ) );
105 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
106 Xml
::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-software' ) ) .
108 <th>" . wfMsg( 'version-software-product' ) . "</th>
109 <th>" . wfMsg( 'version-software-version' ) . "</th>
111 foreach( $software as $name => $version ) {
113 <td>" . $name . "</td>
114 <td>" . $version . "</td>
117 return $out . Xml
::closeElement( 'table' );
121 * Return a string of the MediaWiki version with SVN revision if available
125 public static function getVersion( $flags = '' ) {
126 global $wgVersion, $IP;
127 wfProfileIn( __METHOD__
);
128 $svn = self
::getSvnRevision( $IP, false, false , false );
129 $svnCo = self
::getSvnRevision( $IP, true, false , false );
131 $version = $wgVersion;
132 } elseif( $flags === 'nodb' ) {
133 $version = "$wgVersion (r$svnCo)";
135 $version = $wgVersion . wfMsg( 'version-svn-revision', $svn, $svnCo );
137 wfProfileOut( __METHOD__
);
142 * Return a string of the MediaWiki version with a link to SVN revision if
147 public static function getVersionLinked() {
148 global $wgVersion, $IP;
149 wfProfileIn( __METHOD__
);
150 $svn = self
::getSvnRevision( $IP, false, false, false );
151 $svnCo = self
::getSvnRevision( $IP, true, false, false );
152 $svnDir = self
::getSvnRevision( $IP, true, false, true );
153 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
154 $viewvcEnd = '/?pathrev=';
155 $viewvc = $viewvcStart . $svnDir . $viewvcEnd;
156 $version = $svn ?
$wgVersion . " [{$viewvc}{$svnCo} " . wfMsg( 'version-svn-revision', $svn, $svnCo ) . ']' : $wgVersion;
157 wfProfileOut( __METHOD__
);
161 /** Generate wikitext showing extensions name, URL, author and description */
162 function extensionCredits() {
163 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
165 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
168 $extensionTypes = array(
169 'specialpage' => wfMsg( 'version-specialpages' ),
170 'parserhook' => wfMsg( 'version-parserhooks' ),
171 'variable' => wfMsg( 'version-variables' ),
172 'media' => wfMsg( 'version-mediahandlers' ),
173 'other' => wfMsg( 'version-other' ),
175 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
177 $out = Xml
::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
178 Xml
::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-ext' ) );
180 foreach ( $extensionTypes as $type => $text ) {
181 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
182 $out .= $this->openExtType( $text );
184 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
186 foreach ( $wgExtensionCredits[$type] as $extension ) {
189 $subVersionCo = null;
191 if ( isset( $extension['path'] ) ) {
192 $subVersion = self
::getSvnRevision(dirname($extension['path']), false, true, false);
193 $subVersionCo = self
::getSvnRevision(dirname($extension['path']), true, true, false);
194 $subVersionDir = self
::getSvnRevision(dirname($extension['path']), false, true, true);
196 $viewvc = $subVersionDir . $subVersionCo;
198 if ( isset( $extension['version'] ) ) {
199 $version = $extension['version'];
202 $out .= $this->formatCredits(
203 isset ( $extension['name'] ) ?
$extension['name'] : '',
208 isset ( $extension['author'] ) ?
$extension['author'] : '',
209 isset ( $extension['url'] ) ?
$extension['url'] : null,
210 isset ( $extension['description'] ) ?
$extension['description'] : '',
211 isset ( $extension['descriptionmsg'] ) ?
$extension['descriptionmsg'] : null
217 if ( count( $wgExtensionFunctions ) ) {
218 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
219 $out .= '<tr><td colspan="4">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
222 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
223 for ( $i = 0; $i < $cnt; ++
$i )
224 $tags[$i] = "<{$tags[$i]}>";
225 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
226 $out .= '<tr><td colspan="4">' . $this->listToText( $tags ). "</td></tr>\n";
229 if( $cnt = count( $fhooks = $wgParser->getFunctionHooks() ) ) {
230 $out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ) );
231 $out .= '<tr><td colspan="4">' . $this->listToText( $fhooks ) . "</td></tr>\n";
234 if ( count( $wgSkinExtensionFunctions ) ) {
235 $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ) );
236 $out .= '<tr><td colspan="4">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
238 $out .= Xml
::closeElement( 'table' );
242 /** Callback to sort extensions by type */
243 function compare( $a, $b ) {
245 if( $a['name'] === $b['name'] ) {
248 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
254 function formatCredits( $name, $version = null, $subVersion = null, $subVersionCo = null, $subVersionURL = null, $author = null, $url = null, $description = null, $descriptionMsg = null ) {
255 $haveSubversion = $subVersion;
256 $extension = isset( $url ) ?
"[$url $name]" : $name;
257 $version = isset( $version ) ?
'<span class="mw-version-ext-version">' . wfMsg( 'version-version', $version ) . '</span>' : '';
258 $subVersion = isset( $subVersion ) ?
wfMsg( 'version-svn-revision', $subVersion, $subVersionCo ) : '';
259 $subVersion = isset( $subVersionURL ) ?
"[$subVersionURL $subVersion]" : $subVersion;
261 # Look for a localized description
262 if( isset( $descriptionMsg ) ) {
263 if( is_array( $descriptionMsg ) ) {
264 $descriptionMsgKey = $descriptionMsg[0]; // Get the message key
265 array_shift( $descriptionMsg ); // Shift out the message key to get the parameters only
266 array_map( "htmlspecialchars", $descriptionMsg ); // For sanity
267 $msg = wfMsg( $descriptionMsgKey, $descriptionMsg );
269 $msg = wfMsg( $descriptionMsg );
271 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
276 if ( $haveSubversion ) {
278 <td><em>$extension $version</em></td>
279 <td><em>$subVersion</em></td>";
282 <td colspan=\"2\"><em>$extension $version</em></td>";
284 $extDescAuthor = "<td>$description</td>
285 <td>" . $this->listToText( (array)$author ) . "</td>
287 return $ret = $extNameVer . $extDescAuthor;
297 if ( count( $wgHooks ) ) {
298 $myWgHooks = $wgHooks;
301 $ret = Xml
::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
302 Xml
::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) ) .
304 <th>" . wfMsg( 'version-hook-name' ) . "</th>
305 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
308 foreach ( $myWgHooks as $hook => $hooks )
311 <td>" . $this->listToText( $hooks ) . "</td>
314 $ret .= Xml
::closeElement( 'table' );
320 private function openExtType($text, $name = null) {
321 $opt = array( 'colspan' => 4 );
324 if(!$this->firstExtOpened
) {
325 // Insert a spacing line
326 $out .= '<tr class="sv-space">' . Xml
::element( 'td', $opt ) . "</tr>\n";
328 $this->firstExtOpened
= false;
330 if($name) { $opt['id'] = "sv-$name"; }
332 $out .= "<tr>" . Xml
::element( 'th', $opt, $text) . "</tr>\n";
340 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
341 return "<!-- visited from $ip -->\n" .
342 "<span style='display:none'>visited from $ip</span>";
349 function listToText( $list ) {
350 $cnt = count( $list );
353 // Enforce always returning a string
354 return (string)self
::arrayToString( $list[0] );
355 } elseif ( $cnt == 0 ) {
360 return $wgLang->listToText( array_map( array( __CLASS__
, 'arrayToString' ), $list ) );
365 * @param mixed $list Will convert an array to string if given and return
366 * the paramater unaltered otherwise
369 static function arrayToString( $list ) {
370 if( is_array( $list ) && count( $list ) == 1 )
372 if( is_object( $list ) ) {
373 $class = get_class( $list );
375 } elseif ( !is_array( $list ) ) {
378 if( is_object( $list[0] ) )
379 $class = get_class( $list[0] );
382 return "($class, {$list[1]})";
387 * Retrieve the revision number of a Subversion working directory.
389 * @param String $dir Directory of the svn checkout
390 * @param Boolean $coRev optional to return value whether is Last Modified
391 * or Checkout revision number
392 * @param Boolean $extension optional to check the path whether is from
393 * Wikimedia SVN server or not
394 * @param Boolean $relPath optional to get the end part of the checkout path
395 * @return mixed revision number as int, end part of the checkout path,
396 * or false if not a SVN checkout
398 public static function getSvnRevision( $dir, $coRev = false, $extension = false, $relPath = false) {
399 // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
400 $entries = $dir . '/.svn/entries';
402 if( !file_exists( $entries ) ) {
406 $content = file( $entries );
408 // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
409 if( preg_match( '/^<\?xml/', $content[0] ) ) {
410 // subversion is release <= 1.3
411 if( !function_exists( 'simplexml_load_file' ) ) {
412 // We could fall back to expat... YUCK
416 // SimpleXml whines about the xmlns...
417 wfSuppressWarnings();
418 $xml = simplexml_load_file( $entries );
422 foreach( $xml->entry
as $entry ) {
423 if( $xml->entry
[0]['name'] == '' ) {
424 // The directory entry should always have a revision marker.
425 if( $entry['revision'] ) {
426 return intval( $entry['revision'] );
433 // subversion is release 1.4 or above
435 $endPath = strstr( $content[4], 'tags' );
437 $endPath = strstr( $content[4], 'branches' );
439 $endPath = strstr( $content[4], 'trunk' );
444 $endPath = trim ( $endPath );
446 $wmSvnPath = 'svn.wikimedia.org/svnroot/mediawiki';
447 $isWMSvn = strstr($content[5],$wmSvnPath);
448 if (!strcmp($isWMSvn,null)) {
451 $viewvcStart = 'http://svn.wikimedia.org/viewvc/mediawiki/';
452 if (strstr( $content[4], 'trunk' ))
453 $viewvcEnd = '/?pathrev=';
455 // Avoids 404 error using pathrev when it does not found
456 $viewvcEnd = '/?revision=';
457 $viewvc = $viewvcStart . $endPath . $viewvcEnd;
464 // get the directory checkout revsion number
465 return intval( $content[3]) ;
467 // get the directory last modified revision number
468 return intval( $content[10] );