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