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