* Update plural for uk
[mediawiki.git] / includes / SpecialVersion.php
bloba745949e53767882e8de88e8a1c4e79fd0619aa6
1 <?php
2 /**#@+
3 * Give information about the version of MediaWiki, PHP, the DB and extensions
5 * @file
6 * @ingroup SpecialPage
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
13 /**
14 * constructor
16 function wfSpecialVersion() {
17 $version = new SpecialVersion;
18 $version->execute();
21 /**
22 * @ingroup SpecialPage
24 class SpecialVersion {
25 private $firstExtOpened = true;
27 /**
28 * main()
30 function execute() {
31 global $wgOut, $wgMessageCache;
32 $wgMessageCache->loadAllMessages();
34 $wgOut->addHTML( '<div dir="ltr">' );
35 $wgOut->addWikiText(
36 $this->MediaWikiCredits() .
37 $this->softwareInformation() .
38 $this->extensionCredits() .
39 $this->wgHooks()
41 $wgOut->addHTML( $this->IPInfo() );
42 $wgOut->addHTML( '</div>' );
45 /**#@+
46 * @private
49 /**
50 * @return wiki text showing the license information
52 static function MediaWikiCredits() {
53 $ret = Xml::element( 'h2', array( 'id' => 'mw-version-license' ), wfMsg( 'version-license' ) ) .
54 "__NOTOC__
55 This wiki is powered by '''[http://www.mediawiki.org/ MediaWiki]''',
56 copyright (C) 2001-2008 Magnus Manske, Brion Vibber, Lee Daniel Crocker,
57 Tim Starling, Erik Möller, Gabriel Wicke, Ævar Arnfjörð Bjarmason,
58 Niklas Laxström, Domas Mituzas, Rob Church, Yuri Astrakhan and others.
60 MediaWiki is free software; you can redistribute it and/or modify
61 it under the terms of the GNU General Public License as published by
62 the Free Software Foundation; either version 2 of the License, or
63 (at your option) any later version.
65 MediaWiki is distributed in the hope that it will be useful,
66 but WITHOUT ANY WARRANTY; without even the implied warranty of
67 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
68 GNU General Public License for more details.
70 You should have received [{{SERVER}}{{SCRIPTPATH}}/COPYING a copy of the GNU General Public License]
71 along with this program; if not, write to the Free Software
72 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
73 or [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html read it online].
76 return str_replace( "\t\t", '', $ret ) . "\n";
79 /**
80 * @return wiki text showing the third party software versions (apache, php, mysql).
82 static function softwareInformation() {
83 $dbr = wfGetDB( DB_SLAVE );
85 return Xml::element( 'h2', array( 'id' => 'mw-version-software' ), wfMsg( 'version-software' ) ) .
86 Xml::openElement( 'table', array( 'id' => 'sv-software' ) ) .
87 "<tr>
88 <th>" . wfMsg( 'version-software-product' ) . "</th>
89 <th>" . wfMsg( 'version-software-version' ) . "</th>
90 </tr>\n
91 <tr>
92 <td>[http://www.mediawiki.org/ MediaWiki]</td>
93 <td>" . self::getVersionLinked() . "</td>
94 </tr>\n
95 <tr>
96 <td>[http://www.php.net/ PHP]</td>
97 <td>" . phpversion() . " (" . php_sapi_name() . ")</td>
98 </tr>\n
99 <tr>
100 <td>" . $dbr->getSoftwareLink() . "</td>
101 <td>" . $dbr->getServerVersion() . "</td>
102 </tr>\n" .
103 Xml::closeElement( 'table' );
107 * Return a string of the MediaWiki version with SVN revision if available
109 * @return mixed
111 public static function getVersion() {
112 global $wgVersion, $IP;
113 wfProfileIn( __METHOD__ );
114 $svn = self::getSvnRevision( $IP );
115 $version = $svn ? "$wgVersion (r$svn)" : $wgVersion;
116 wfProfileOut( __METHOD__ );
117 return $version;
121 * Return a string of the MediaWiki version with a link to SVN revision if
122 * available
124 * @return mixed
126 public static function getVersionLinked() {
127 global $wgVersion, $IP;
128 wfProfileIn( __METHOD__ );
129 $svn = self::getSvnRevision( $IP );
130 $viewvc = 'http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/?pathrev=';
131 $version = $svn ? "$wgVersion ([{$viewvc}{$svn} r$svn])" : $wgVersion;
132 wfProfileOut( __METHOD__ );
133 return $version;
136 /** Generate wikitext showing extensions name, URL, author and description */
137 function extensionCredits() {
138 global $wgExtensionCredits, $wgExtensionFunctions, $wgParser, $wgSkinExtensionFunctions;
140 if ( ! count( $wgExtensionCredits ) && ! count( $wgExtensionFunctions ) && ! count( $wgSkinExtensionFunctions ) )
141 return '';
143 $extensionTypes = array(
144 'specialpage' => wfMsg( 'version-specialpages' ),
145 'parserhook' => wfMsg( 'version-parserhooks' ),
146 'variable' => wfMsg( 'version-variables' ),
147 'media' => wfMsg( 'version-mediahandlers' ),
148 'other' => wfMsg( 'version-other' ),
150 wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
152 $out = Xml::element( 'h2', array( 'id' => 'mw-version-ext' ), wfMsg( 'version-extensions' ) ) .
153 Xml::openElement( 'table', array( 'id' => 'sv-ext' ) );
155 foreach ( $extensionTypes as $type => $text ) {
156 if ( isset ( $wgExtensionCredits[$type] ) && count ( $wgExtensionCredits[$type] ) ) {
157 $out .= $this->openExtType( $text );
159 usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
161 foreach ( $wgExtensionCredits[$type] as $extension ) {
162 if ( isset( $extension['version'] ) ) {
163 $version = $extension['version'];
164 } elseif ( isset( $extension['svn-revision'] ) &&
165 preg_match( '/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
166 $extension['svn-revision'], $m ) )
168 $version = 'r' . $m[1];
169 } else {
170 $version = null;
173 $out .= $this->formatCredits(
174 isset ( $extension['name'] ) ? $extension['name'] : '',
175 $version,
176 isset ( $extension['author'] ) ? $extension['author'] : '',
177 isset ( $extension['url'] ) ? $extension['url'] : null,
178 isset ( $extension['description'] ) ? $extension['description'] : '',
179 isset ( $extension['descriptionmsg'] ) ? $extension['descriptionmsg'] : ''
185 if ( count( $wgExtensionFunctions ) ) {
186 $out .= $this->openExtType( wfMsg( 'version-extension-functions' ) );
187 $out .= '<tr><td colspan="3">' . $this->listToText( $wgExtensionFunctions ) . "</td></tr>\n";
190 if ( $cnt = count( $tags = $wgParser->getTags() ) ) {
191 for ( $i = 0; $i < $cnt; ++$i )
192 $tags[$i] = "&lt;{$tags[$i]}&gt;";
193 $out .= $this->openExtType( wfMsg( 'version-parser-extensiontags' ) );
194 $out .= '<tr><td colspan="3">' . $this->listToText( $tags ). "</td></tr>\n";
197 if( $cnt = count( $fhooks = $wgParser->getFunctionHooks() ) ) {
198 $out .= $this->openExtType( wfMsg( 'version-parser-function-hooks' ) );
199 $out .= '<tr><td colspan="3">' . $this->listToText( $fhooks ) . "</td></tr>\n";
202 if ( count( $wgSkinExtensionFunctions ) ) {
203 $out .= $this->openExtType( wfMsg( 'version-skin-extension-functions' ) );
204 $out .= '<tr><td colspan="3">' . $this->listToText( $wgSkinExtensionFunctions ) . "</td></tr>\n";
206 $out .= Xml::closeElement( 'table' );
207 return $out;
210 /** Callback to sort extensions by type */
211 function compare( $a, $b ) {
212 global $wgLang;
213 if( $a['name'] === $b['name'] ) {
214 return 0;
215 } else {
216 return $wgLang->lc( $a['name'] ) > $wgLang->lc( $b['name'] )
218 : -1;
222 function formatCredits( $name, $version = null, $author = null, $url = null, $description = null, $descriptionMsg = null ) {
223 $extension = isset( $url ) ? "[$url $name]" : $name;
224 $version = isset( $version ) ? "(" . wfMsg( 'version-version' ) . " $version)" : '';
226 # Look for a localized description
227 if( isset( $descriptionMsg ) ) {
228 $msg = wfMsg( $descriptionMsg );
229 if ( !wfEmptyMsg( $descriptionMsg, $msg ) && $msg != '' ) {
230 $description = $msg;
234 return "<tr>
235 <td><em>$extension $version</em></td>
236 <td>$description</td>
237 <td>" . $this->listToText( (array)$author ) . "</td>
238 </tr>\n";
242 * @return string
244 function wgHooks() {
245 global $wgHooks;
247 if ( count( $wgHooks ) ) {
248 $myWgHooks = $wgHooks;
249 ksort( $myWgHooks );
251 $ret = Xml::element( 'h2', array( 'id' => 'mw-version-hooks' ), wfMsg( 'version-hooks' ) ) .
252 Xml::openElement( 'table', array( 'id' => 'sv-hooks' ) ) .
253 "<tr>
254 <th>" . wfMsg( 'version-hook-name' ) . "</th>
255 <th>" . wfMsg( 'version-hook-subscribedby' ) . "</th>
256 </tr>\n";
258 foreach ( $myWgHooks as $hook => $hooks )
259 $ret .= "<tr>
260 <td>$hook</td>
261 <td>" . $this->listToText( $hooks ) . "</td>
262 </tr>\n";
264 $ret .= Xml::closeElement( 'table' );
265 return $ret;
266 } else
267 return '';
270 private function openExtType($text, $name = null) {
271 $opt = array( 'colspan' => 3 );
272 $out = '';
274 if(!$this->firstExtOpened) {
275 // Insert a spacing line
276 $out .= '<tr class="sv-space">' . Xml::element( 'td', $opt ) . "</tr>\n";
278 $this->firstExtOpened = false;
280 if($name) { $opt['id'] = "sv-$name"; }
282 $out .= "<tr>" . Xml::element( 'th', $opt, $text) . "</tr>\n";
283 return $out;
287 * @static
289 * @return string
291 function IPInfo() {
292 $ip = str_replace( '--', ' - ', htmlspecialchars( wfGetIP() ) );
293 return "<!-- visited from $ip -->\n" .
294 "<span style='display:none'>visited from $ip</span>";
298 * @param array $list
299 * @return string
301 function listToText( $list ) {
302 $cnt = count( $list );
304 if ( $cnt == 1 ) {
305 // Enforce always returning a string
306 return (string)$this->arrayToString( $list[0] );
307 } elseif ( $cnt == 0 ) {
308 return '';
309 } else {
310 sort( $list );
311 $t = array_slice( $list, 0, $cnt - 1 );
312 $one = array_map( array( &$this, 'arrayToString' ), $t );
313 $two = $this->arrayToString( $list[$cnt - 1] );
314 $and = wfMsg( 'and' );
316 return implode( ', ', $one ) . " $and $two";
321 * @static
323 * @param mixed $list Will convert an array to string if given and return
324 * the paramater unaltered otherwise
325 * @return mixed
327 function arrayToString( $list ) {
328 if( is_object( $list ) ) {
329 $class = get_class( $list );
330 return "($class)";
331 } elseif ( ! is_array( $list ) ) {
332 return $list;
333 } else {
334 $class = get_class( $list[0] );
335 return "($class, {$list[1]})";
340 * Retrieve the revision number of a Subversion working directory.
342 * @param string $dir
343 * @return mixed revision number as int, or false if not a SVN checkout
345 public static function getSvnRevision( $dir ) {
346 // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
347 $entries = $dir . '/.svn/entries';
349 if( !file_exists( $entries ) ) {
350 return false;
353 $content = file( $entries );
355 // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
356 if( preg_match( '/^<\?xml/', $content[0] ) ) {
357 // subversion is release <= 1.3
358 if( !function_exists( 'simplexml_load_file' ) ) {
359 // We could fall back to expat... YUCK
360 return false;
363 // SimpleXml whines about the xmlns...
364 wfSuppressWarnings();
365 $xml = simplexml_load_file( $entries );
366 wfRestoreWarnings();
368 if( $xml ) {
369 foreach( $xml->entry as $entry ) {
370 if( $xml->entry[0]['name'] == '' ) {
371 // The directory entry should always have a revision marker.
372 if( $entry['revision'] ) {
373 return intval( $entry['revision'] );
378 return false;
379 } else {
380 // subversion is release 1.4
381 return intval( $content[3] );
385 /**#@-*/
388 /**#@-*/