MediaWiki  1.23.14
SpecialVersion.php
Go to the documentation of this file.
1 <?php
31 class SpecialVersion extends SpecialPage {
32  protected $firstExtOpened = false;
33 
37  protected $coreId = '';
38 
39  protected static $extensionTypes = false;
40 
41  protected static $viewvcUrls = array(
42  'svn+ssh://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
43  'http://svn.wikimedia.org/svnroot/mediawiki' => 'http://svn.wikimedia.org/viewvc/mediawiki',
44  'https://svn.wikimedia.org/svnroot/mediawiki' => 'https://svn.wikimedia.org/viewvc/mediawiki',
45  );
46 
47  public function __construct() {
48  parent::__construct( 'Version' );
49  }
50 
54  public function execute( $par ) {
55  global $IP, $wgExtensionCredits;
56 
57  $this->setHeaders();
58  $this->outputHeader();
59  $out = $this->getOutput();
60  $out->allowClickjacking();
61 
62  // Explode the sub page information into useful bits
63  $parts = explode( '/', (string)$par );
64  $extNode = null;
65  if ( isset( $parts[1] ) ) {
66  $extName = str_replace( '_', ' ', $parts[1] );
67  // Find it!
68  foreach ( $wgExtensionCredits as $group => $extensions ) {
69  foreach ( $extensions as $ext ) {
70  if ( isset( $ext['name'] ) && ( $ext['name'] === $extName ) ) {
71  $extNode = &$ext;
72  break 2;
73  }
74  }
75  }
76  if ( !$extNode ) {
77  $out->setStatusCode( 404 );
78  }
79  } else {
80  $extName = 'MediaWiki';
81  }
82 
83  // Now figure out what to do
84  switch ( strtolower( $parts[0] ) ) {
85  case 'credits':
86  $wikiText = '{{int:version-credits-not-found}}';
87  if ( $extName === 'MediaWiki' ) {
88  $wikiText = file_get_contents( $IP . '/CREDITS' );
89  } elseif ( ( $extNode !== null ) && isset( $extNode['path'] ) ) {
90  $file = $this->getExtAuthorsFileName( dirname( $extNode['path'] ) );
91  if ( $file ) {
92  $wikiText = file_get_contents( $file );
93  if ( substr( $file, -4 ) === '.txt' ) {
94  $wikiText = Html::element( 'pre', array(), $wikiText );
95  }
96  }
97  }
98 
99  $out->setPageTitle( $this->msg( 'version-credits-title', $extName ) );
100  $out->addWikiText( $wikiText );
101  break;
102 
103  case 'license':
104  $wikiText = '{{int:version-license-not-found}}';
105  if ( $extName === 'MediaWiki' ) {
106  $wikiText = file_get_contents( $IP . '/COPYING' );
107  } elseif ( ( $extNode !== null ) && isset( $extNode['path'] ) ) {
108  $file = $this->getExtLicenseFileName( dirname( $extNode['path'] ) );
109  if ( $file ) {
110  $wikiText = file_get_contents( $file );
111  if ( !isset( $extNode['license-name'] ) ) {
112  // If the developer did not explicitly set license-name they probably
113  // are unaware that we're now sucking this file in and thus it's probably
114  // not wikitext friendly.
115  $wikiText = "<pre>$wikiText</pre>";
116  }
117  }
118  }
119 
120  $out->setPageTitle( $this->msg( 'version-license-title', $extName ) );
121  $out->addWikiText( $wikiText );
122  break;
123 
124  default:
125  $out->addModules( 'mediawiki.special.version' );
126  $out->addWikiText(
127  $this->getMediaWikiCredits() .
128  $this->softwareInformation() .
129  $this->getEntryPointInfo()
130  );
131  $out->addHtml(
132  $this->getExtensionCredits() .
133  $this->getParserTags() .
134  $this->getParserFunctionHooks()
135  );
136  $out->addWikiText( $this->getWgHooks() );
137  $out->addHTML( $this->IPInfo() );
138 
139  break;
140  }
141  }
142 
148  private static function getMediaWikiCredits() {
149  $ret = Xml::element(
150  'h2',
151  array( 'id' => 'mw-version-license' ),
152  wfMessage( 'version-license' )->text()
153  );
154 
155  // This text is always left-to-right.
156  $ret .= '<div class="plainlinks">';
157  $ret .= "__NOTOC__
159  " . wfMessage( 'version-license-info' )->text();
160  $ret .= '</div>';
161 
162  return str_replace( "\t\t", '', $ret ) . "\n";
163  }
164 
170  public static function getCopyrightAndAuthorList() {
171  global $wgLang;
172 
173  if ( defined( 'MEDIAWIKI_INSTALL' ) ) {
174  $othersLink = '[//www.mediawiki.org/wiki/Special:Version/Credits ' .
175  wfMessage( 'version-poweredby-others' )->text() . ']';
176  } else {
177  $othersLink = '[[Special:Version/Credits|' .
178  wfMessage( 'version-poweredby-others' )->text() . ']]';
179  }
180 
181  $translatorsLink = '[//translatewiki.net/wiki/Translating:MediaWiki/Credits ' .
182  wfMessage( 'version-poweredby-translators' )->text() . ']';
183 
184  $authorList = array(
185  'Magnus Manske', 'Brion Vibber', 'Lee Daniel Crocker',
186  'Tim Starling', 'Erik Möller', 'Gabriel Wicke', 'Ævar Arnfjörð Bjarmason',
187  'Niklas Laxström', 'Domas Mituzas', 'Rob Church', 'Yuri Astrakhan',
188  'Aryeh Gregor', 'Aaron Schulz', 'Andrew Garrett', 'Raimond Spekking',
189  'Alexandre Emsenhuber', 'Siebrand Mazeland', 'Chad Horohoe',
190  'Roan Kattouw', 'Trevor Parscal', 'Bryan Tong Minh', 'Sam Reed',
191  'Victor Vasiliev', 'Rotem Liss', 'Platonides', 'Antoine Musso',
192  'Timo Tijhof', 'Daniel Kinzler', 'Jeroen De Dauw', $othersLink,
193  $translatorsLink
194  );
195 
196  return wfMessage( 'version-poweredby-credits', MWTimestamp::getLocalInstance()->format( 'Y' ),
197  $wgLang->listToText( $authorList ) )->text();
198  }
199 
205  static function softwareInformation() {
206  $dbr = wfGetDB( DB_SLAVE );
207 
208  // Put the software in an array of form 'name' => 'version'. All messages should
209  // be loaded here, so feel free to use wfMessage in the 'name'. Raw HTML or
210  // wikimarkup can be used.
211  $software = array();
212  $software['[https://www.mediawiki.org/ MediaWiki]'] = self::getVersionLinked();
213  $software['[http://www.php.net/ PHP]'] = phpversion() . " (" . PHP_SAPI . ")";
214  $software[$dbr->getSoftwareLink()] = $dbr->getServerInfo();
215 
216  // Allow a hook to add/remove items.
217  wfRunHooks( 'SoftwareInfo', array( &$software ) );
218 
219  $out = Xml::element(
220  'h2',
221  array( 'id' => 'mw-version-software' ),
222  wfMessage( 'version-software' )->text()
223  ) .
224  Xml::openElement( 'table', array( 'class' => 'wikitable plainlinks', 'id' => 'sv-software' ) ) .
225  "<tr>
226  <th>" . wfMessage( 'version-software-product' )->text() . "</th>
227  <th>" . wfMessage( 'version-software-version' )->text() . "</th>
228  </tr>\n";
229 
230  foreach ( $software as $name => $version ) {
231  $out .= "<tr>
232  <td>" . $name . "</td>
233  <td dir=\"ltr\">" . $version . "</td>
234  </tr>\n";
235  }
236 
237  return $out . Xml::closeElement( 'table' );
238  }
239 
246  public static function getVersion( $flags = '' ) {
247  global $wgVersion, $IP;
248  wfProfileIn( __METHOD__ );
249 
250  $gitInfo = self::getGitHeadSha1( $IP );
251  $svnInfo = self::getSvnInfo( $IP );
252  if ( !$svnInfo && !$gitInfo ) {
253  $version = $wgVersion;
254  } elseif ( $gitInfo && $flags === 'nodb' ) {
255  $shortSha1 = substr( $gitInfo, 0, 7 );
256  $version = "$wgVersion ($shortSha1)";
257  } elseif ( $gitInfo ) {
258  $shortSha1 = substr( $gitInfo, 0, 7 );
259  $shortSha1 = wfMessage( 'parentheses' )->params( $shortSha1 )->escaped();
260  $version = "$wgVersion $shortSha1";
261  } elseif ( $flags === 'nodb' ) {
262  $version = "$wgVersion (r{$svnInfo['checkout-rev']})";
263  } else {
264  $version = $wgVersion . ' ' .
265  wfMessage(
266  'version-svn-revision',
267  isset( $info['directory-rev'] ) ? $info['directory-rev'] : '',
268  $info['checkout-rev']
269  )->text();
270  }
271 
272  wfProfileOut( __METHOD__ );
273 
274  return $version;
275  }
276 
285  public static function getVersionLinked() {
286  global $wgVersion;
287  wfProfileIn( __METHOD__ );
288 
289  $gitVersion = self::getVersionLinkedGit();
290  if ( $gitVersion ) {
291  $v = $gitVersion;
292  } else {
293  $svnVersion = self::getVersionLinkedSvn();
294  if ( $svnVersion ) {
295  $v = $svnVersion;
296  } else {
297  $v = $wgVersion; // fallback
298  }
299  }
300 
301  wfProfileOut( __METHOD__ );
302 
303  return $v;
304  }
305 
309  private static function getVersionLinkedSvn() {
310  global $IP;
311 
312  $info = self::getSvnInfo( $IP );
313  if ( !isset( $info['checkout-rev'] ) ) {
314  return false;
315  }
316 
317  $linkText = wfMessage(
318  'version-svn-revision',
319  isset( $info['directory-rev'] ) ? $info['directory-rev'] : '',
320  $info['checkout-rev']
321  )->text();
322 
323  if ( isset( $info['viewvc-url'] ) ) {
324  $version = "[{$info['viewvc-url']} $linkText]";
325  } else {
326  $version = $linkText;
327  }
328 
329  return self::getwgVersionLinked() . " $version";
330  }
331 
335  private static function getwgVersionLinked() {
336  global $wgVersion;
337  $versionUrl = "";
338  if ( wfRunHooks( 'SpecialVersionVersionUrl', array( $wgVersion, &$versionUrl ) ) ) {
339  $versionParts = array();
340  preg_match( "/^(\d+\.\d+)/", $wgVersion, $versionParts );
341  $versionUrl = "https://www.mediawiki.org/wiki/MediaWiki_{$versionParts[1]}";
342  }
343 
344  return "[$versionUrl $wgVersion]";
345  }
346 
352  private static function getVersionLinkedGit() {
353  global $IP, $wgLang;
354 
355  $gitInfo = new GitInfo( $IP );
356  $headSHA1 = $gitInfo->getHeadSHA1();
357  if ( !$headSHA1 ) {
358  return false;
359  }
360 
361  $shortSHA1 = '(' . substr( $headSHA1, 0, 7 ) . ')';
362 
363  $gitHeadUrl = $gitInfo->getHeadViewUrl();
364  if ( $gitHeadUrl !== false ) {
365  $shortSHA1 = "[$gitHeadUrl $shortSHA1]";
366  }
367 
368  $gitHeadCommitDate = $gitInfo->getHeadCommitDate();
369  if ( $gitHeadCommitDate ) {
370  $shortSHA1 .= Html::element( 'br' ) . $wgLang->timeanddate( $gitHeadCommitDate, true );
371  }
372 
373  return self::getwgVersionLinked() . " $shortSHA1";
374  }
375 
388  public static function getExtensionTypes() {
389  if ( self::$extensionTypes === false ) {
390  self::$extensionTypes = array(
391  'specialpage' => wfMessage( 'version-specialpages' )->text(),
392  'parserhook' => wfMessage( 'version-parserhooks' )->text(),
393  'variable' => wfMessage( 'version-variables' )->text(),
394  'media' => wfMessage( 'version-mediahandlers' )->text(),
395  'antispam' => wfMessage( 'version-antispam' )->text(),
396  'skin' => wfMessage( 'version-skins' )->text(),
397  'api' => wfMessage( 'version-api' )->text(),
398  'other' => wfMessage( 'version-other' )->text(),
399  );
400 
401  wfRunHooks( 'ExtensionTypes', array( &self::$extensionTypes ) );
402  }
403 
404  return self::$extensionTypes;
405  }
406 
416  public static function getExtensionTypeName( $type ) {
417  $types = self::getExtensionTypes();
418 
419  return isset( $types[$type] ) ? $types[$type] : $types['other'];
420  }
421 
427  function getExtensionCredits() {
428  global $wgExtensionCredits;
429 
430  if ( !count( $wgExtensionCredits ) ) {
431  return '';
432  }
433 
435 
439  wfRunHooks( 'SpecialVersionExtensionTypes', array( &$this, &$extensionTypes ) );
440 
441  $out = Xml::element(
442  'h2',
443  array( 'id' => 'mw-version-ext' ),
444  $this->msg( 'version-extensions' )->text()
445  ) .
446  Xml::openElement( 'table', array( 'class' => 'wikitable plainlinks', 'id' => 'sv-ext' ) );
447 
448  // Make sure the 'other' type is set to an array.
449  if ( !array_key_exists( 'other', $wgExtensionCredits ) ) {
450  $wgExtensionCredits['other'] = array();
451  }
452 
453  // Find all extensions that do not have a valid type and give them the type 'other'.
454  foreach ( $wgExtensionCredits as $type => $extensions ) {
455  if ( !array_key_exists( $type, $extensionTypes ) ) {
456  $wgExtensionCredits['other'] = array_merge( $wgExtensionCredits['other'], $extensions );
457  }
458  }
459 
460  // Loop through the extension categories to display their extensions in the list.
461  foreach ( $extensionTypes as $type => $message ) {
462  if ( $type != 'other' ) {
463  $out .= $this->getExtensionCategory( $type, $message );
464  }
465  }
466 
467  // We want the 'other' type to be last in the list.
468  $out .= $this->getExtensionCategory( 'other', $extensionTypes['other'] );
469 
470  $out .= Xml::closeElement( 'table' );
471 
472  return $out;
473  }
474 
480  protected function getParserTags() {
482 
483  $tags = $wgParser->getTags();
484 
485  if ( count( $tags ) ) {
487  'h2',
488  array( 'class' => 'mw-headline' ),
490  '//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Tag_extensions',
491  $this->msg( 'version-parser-extensiontags' )->parse(),
492  false /* msg()->parse() already escapes */
493  )
494  );
495 
496  array_walk( $tags, function ( &$value ) {
497  $value = '&lt;' . htmlentities( $value ) . '&gt;';
498  } );
499  $out .= $this->listToText( $tags );
500  } else {
501  $out = '';
502  }
503 
504  return $out;
505  }
506 
512  protected function getParserFunctionHooks() {
514 
515  $fhooks = $wgParser->getFunctionHooks();
516  if ( count( $fhooks ) ) {
517  $out = Html::rawElement( 'h2', array( 'class' => 'mw-headline' ), Linker::makeExternalLink(
518  '//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Parser_functions',
519  $this->msg( 'version-parser-function-hooks' )->parse(),
520  false /* msg()->parse() already escapes */
521  ) );
522 
523  $out .= $this->listToText( $fhooks );
524  } else {
525  $out = '';
526  }
527 
528  return $out;
529  }
530 
541  protected function getExtensionCategory( $type, $message ) {
542  global $wgExtensionCredits;
543 
544  $out = '';
545 
546  if ( array_key_exists( $type, $wgExtensionCredits ) && count( $wgExtensionCredits[$type] ) > 0 ) {
547  $out .= $this->openExtType( $message, 'credits-' . $type );
548 
549  usort( $wgExtensionCredits[$type], array( $this, 'compare' ) );
550 
551  foreach ( $wgExtensionCredits[$type] as $extension ) {
552  $out .= $this->getCreditsForExtension( $extension );
553  }
554  }
555 
556  return $out;
557  }
558 
565  function compare( $a, $b ) {
566  if ( $a['name'] === $b['name'] ) {
567  return 0;
568  } else {
569  return $this->getLanguage()->lc( $a['name'] ) > $this->getLanguage()->lc( $b['name'] )
570  ? 1
571  : -1;
572  }
573  }
574 
592  function getCreditsForExtension( array $extension ) {
593  $out = $this->getOutput();
594 
595  // We must obtain the information for all the bits and pieces!
596  // ... such as extension names and links
597  $extensionName = isset( $extension['name'] ) ? $extension['name'] : '[no name]';
598  if ( isset( $extension['url'] ) ) {
599  $extensionNameLink = Linker::makeExternalLink(
600  $extension['url'],
601  $extensionName,
602  true,
603  '',
604  array( 'class' => 'mw-version-ext-name' )
605  );
606  } else {
607  $extensionNameLink = $extensionName;
608  }
609 
610  // ... and the version information
611  // If the extension path is set we will check that directory for GIT and SVN
612  // metadata in an attempt to extract date and vcs commit metadata.
613  $canonicalVersion = '&ndash;';
614  $extensionPath = null;
615  $vcsVersion = null;
616  $vcsLink = null;
617  $vcsDate = null;
618 
619  if ( isset( $extension['version'] ) ) {
620  $canonicalVersion = $out->parseInline( $extension['version'] );
621  }
622 
623  if ( isset( $extension['path'] ) ) {
624  global $IP;
625  if ( $this->coreId == '' ) {
626  wfDebug( 'Looking up core head id' );
627  $coreHeadSHA1 = self::getGitHeadSha1( $IP );
628  if ( $coreHeadSHA1 ) {
629  $this->coreId = $coreHeadSHA1;
630  } else {
631  $svnInfo = self::getSvnInfo( $IP );
632  if ( $svnInfo !== false ) {
633  $this->coreId = $svnInfo['checkout-rev'];
634  }
635  }
636  }
638  $memcKey = wfMemcKey( 'specialversion-ext-version-text', $extension['path'], $this->coreId );
639  list( $vcsVersion, $vcsLink, $vcsDate ) = $cache->get( $memcKey );
640 
641  if ( !$vcsVersion ) {
642  wfDebug( "Getting VCS info for extension $extensionName" );
643  $extensionPath = dirname( $extension['path'] );
644  $gitInfo = new GitInfo( $extensionPath );
645  $vcsVersion = $gitInfo->getHeadSHA1();
646  if ( $vcsVersion !== false ) {
647  $vcsVersion = substr( $vcsVersion, 0, 7 );
648  $vcsLink = $gitInfo->getHeadViewUrl();
649  $vcsDate = $gitInfo->getHeadCommitDate();
650  } else {
651  $svnInfo = self::getSvnInfo( $extensionPath );
652  if ( $svnInfo !== false ) {
653  $vcsVersion = $this->msg( 'version-svn-revision', $svnInfo['checkout-rev'] )->text();
654  $vcsLink = isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
655  }
656  }
657  $cache->set( $memcKey, array( $vcsVersion, $vcsLink, $vcsDate ), 60 * 60 * 24 );
658  } else {
659  wfDebug( "Pulled VCS info for extension $extensionName from cache" );
660  }
661  }
662 
663  $versionString = Html::rawElement(
664  'span',
665  array( 'class' => 'mw-version-ext-version' ),
666  $canonicalVersion
667  );
668 
669  if ( $vcsVersion ) {
670  if ( $vcsLink ) {
671  $vcsVerString = Linker::makeExternalLink(
672  $vcsLink,
673  $this->msg( 'version-version', $vcsVersion ),
674  true,
675  '',
676  array( 'class' => 'mw-version-ext-vcs-version' )
677  );
678  } else {
679  $vcsVerString = Html::element( 'span',
680  array( 'class' => 'mw-version-ext-vcs-version' ),
681  "({$vcsVersion})"
682  );
683  }
684  $versionString .= " {$vcsVerString}";
685 
686  if ( $vcsDate ) {
687  $vcsTimeString = Html::element( 'span',
688  array( 'class' => 'mw-version-ext-vcs-timestamp' ),
689  $this->getLanguage()->timeanddate( $vcsDate )
690  );
691  $versionString .= " {$vcsTimeString}";
692  }
693  $versionString = Html::rawElement( 'span',
694  array( 'class' => 'mw-version-ext-meta-version' ),
695  $versionString
696  );
697  }
698 
699  // ... and license information; if a license file exists we
700  // will link to it
701  $licenseLink = '';
702  if ( isset( $extension['license-name'] ) ) {
703  $licenseLink = Linker::link(
704  $this->getPageTitle( 'License/' . $extensionName ),
705  $out->parseInline( $extension['license-name'] ),
706  array( 'class' => 'mw-version-ext-license' )
707  );
708  } elseif ( $this->getExtLicenseFileName( $extensionPath ) ) {
709  $licenseLink = Linker::link(
710  $this->getPageTitle( 'License/' . $extensionName ),
711  $this->msg( 'version-ext-license' ),
712  array( 'class' => 'mw-version-ext-license' )
713  );
714  }
715 
716  // ... and generate the description; which can be a parameterized l10n message
717  // in the form array( <msgname>, <parameter>, <parameter>... ) or just a straight
718  // up string
719  if ( isset( $extension['descriptionmsg'] ) ) {
720  // Localized description of extension
721  $descriptionMsg = $extension['descriptionmsg'];
722 
723  if ( is_array( $descriptionMsg ) ) {
724  $descriptionMsgKey = $descriptionMsg[0]; // Get the message key
725  array_shift( $descriptionMsg ); // Shift out the message key to get the parameters only
726  array_map( "htmlspecialchars", $descriptionMsg ); // For sanity
727  $description = $this->msg( $descriptionMsgKey, $descriptionMsg )->text();
728  } else {
729  $description = $this->msg( $descriptionMsg )->text();
730  }
731  } elseif ( isset( $extension['description'] ) ) {
732  // Non localized version
733  $description = $extension['description'];
734  } else {
735  $description = '';
736  }
737  $description = $out->parseInline( $description );
738 
739  // ... now get the authors for this extension
740  $authors = isset( $extension['author'] ) ? $extension['author'] : array();
741  $authors = $this->listAuthors( $authors, $extensionName, $extensionPath );
742 
743  // Finally! Create the table
744  $html = Html::openElement( 'tr', array(
745  'class' => 'mw-version-ext',
746  'id' => "mw-version-ext-{$extensionName}"
747  )
748  );
749 
750  $html .= Html::rawElement( 'td', array(), $extensionNameLink );
751  $html .= Html::rawElement( 'td', array(), $versionString );
752  $html .= Html::rawElement( 'td', array(), $licenseLink );
753  $html .= Html::rawElement( 'td', array( 'class' => 'mw-version-ext-description' ), $description );
754  $html .= Html::rawElement( 'td', array( 'class' => 'mw-version-ext-authors' ), $authors );
755 
756  $html .= Html::closeElement( 'td' );
757 
758  return $html;
759  }
760 
766  private function getWgHooks() {
767  global $wgSpecialVersionShowHooks, $wgHooks;
768 
769  if ( $wgSpecialVersionShowHooks && count( $wgHooks ) ) {
770  $myWgHooks = $wgHooks;
771  ksort( $myWgHooks );
772 
773  $ret = array();
774  $ret[] = '== {{int:version-hooks}} ==';
775  $ret[] = Html::openElement( 'table', array( 'class' => 'wikitable', 'id' => 'sv-hooks' ) );
776  $ret[] = Html::openElement( 'tr' );
777  $ret[] = Html::element( 'th', array(), $this->msg( 'version-hook-name' )->text() );
778  $ret[] = Html::element( 'th', array(), $this->msg( 'version-hook-subscribedby' )->text() );
779  $ret[] = Html::closeElement( 'tr' );
780 
781  foreach ( $myWgHooks as $hook => $hooks ) {
782  $ret[] = Html::openElement( 'tr' );
783  $ret[] = Html::element( 'td', array(), $hook );
784  $ret[] = Html::element( 'td', array(), $this->listToText( $hooks ) );
785  $ret[] = Html::closeElement( 'tr' );
786  }
787 
788  $ret[] = Html::closeElement( 'table' );
789 
790  return implode( "\n", $ret );
791  } else {
792  return '';
793  }
794  }
795 
796  private function openExtType( $text, $name = null ) {
797  $out = '';
798 
799  $opt = array( 'colspan' => 5 );
800  if ( $this->firstExtOpened ) {
801  // Insert a spacing line
802  $out .= Html::rawElement( 'tr', array( 'class' => 'sv-space' ),
803  Html::element( 'td', $opt )
804  );
805  }
806  $this->firstExtOpened = true;
807 
808  if ( $name ) {
809  $opt['id'] = "sv-$name";
810  }
811 
812  $out .= Html::rawElement( 'tr', array(),
813  Html::element( 'th', $opt, $text )
814  );
815 
816  $out .= Html::openElement( 'tr' );
817  $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
818  $this->msg( 'version-ext-colheader-name' )->text() );
819  $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
820  $this->msg( 'version-ext-colheader-version' )->text() );
821  $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
822  $this->msg( 'version-ext-colheader-license' )->text() );
823  $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
824  $this->msg( 'version-ext-colheader-description' )->text() );
825  $out .= Html::element( 'th', array( 'class' => 'mw-version-ext-col-label' ),
826  $this->msg( 'version-ext-colheader-credits' )->text() );
827  $out .= Html::closeElement( 'tr' );
828 
829  return $out;
830  }
831 
837  private function IPInfo() {
838  $ip = str_replace( '--', ' - ', htmlspecialchars( $this->getRequest()->getIP() ) );
839 
840  return "<!-- visited from $ip -->\n<span style='display:none'>visited from $ip</span>";
841  }
842 
863  function listAuthors( $authors, $extName, $extDir ) {
864  $hasOthers = false;
865 
866  $list = array();
867  foreach ( (array)$authors as $item ) {
868  if ( $item == '...' ) {
869  $hasOthers = true;
870 
871  if ( $this->getExtAuthorsFileName( $extDir ) ) {
872  $text = Linker::link(
873  $this->getPageTitle( "Credits/$extName" ),
874  $this->msg( 'version-poweredby-others' )->text()
875  );
876  } else {
877  $text = $this->msg( 'version-poweredby-others' )->text();
878  }
879  $list[] = $text;
880  } elseif ( substr( $item, -5 ) == ' ...]' ) {
881  $hasOthers = true;
882  $list[] = $this->getOutput()->parseInline(
883  substr( $item, 0, -4 ) . $this->msg( 'version-poweredby-others' )->text() . "]"
884  );
885  } else {
886  $list[] = $this->getOutput()->parseInline( $item );
887  }
888  }
889 
890  if ( !$hasOthers && $this->getExtAuthorsFileName( $extDir ) ) {
891  $list[] = $text = Linker::link(
892  $this->getPageTitle( "Credits/$extName" ),
893  $this->msg( 'version-poweredby-others' )->text()
894  );
895  }
896 
897  return $this->listToText( $list, false );
898  }
899 
911  public static function getExtAuthorsFileName( $extDir ) {
912  if ( !$extDir ) {
913  return false;
914  }
915 
916  foreach ( scandir( $extDir ) as $file ) {
917  $fullPath = $extDir . DIRECTORY_SEPARATOR . $file;
918  if ( preg_match( '/^((AUTHORS)|(CREDITS))(\.txt)?$/', $file ) &&
919  is_readable( $fullPath ) &&
920  is_file( $fullPath )
921  ) {
922  return $fullPath;
923  }
924  }
925 
926  return false;
927  }
928 
940  public static function getExtLicenseFileName( $extDir ) {
941  if ( !$extDir ) {
942  return false;
943  }
944 
945  foreach ( scandir( $extDir ) as $file ) {
946  $fullPath = $extDir . DIRECTORY_SEPARATOR . $file;
947  if ( preg_match( '/^((COPYING)|(LICENSE))(\.txt)?$/', $file ) &&
948  is_readable( $fullPath ) &&
949  is_file( $fullPath )
950  ) {
951  return $fullPath;
952  }
953  }
954 
955  return false;
956  }
957 
966  function listToText( $list, $sort = true ) {
967  $cnt = count( $list );
968 
969  if ( $cnt == 1 ) {
970  // Enforce always returning a string
971  return (string)self::arrayToString( $list[0] );
972  } elseif ( $cnt == 0 ) {
973  return '';
974  } else {
975  if ( $sort ) {
976  sort( $list );
977  }
978 
979  return $this->getLanguage()
980  ->listToText( array_map( array( __CLASS__, 'arrayToString' ), $list ) );
981  }
982  }
983 
992  public static function arrayToString( $list ) {
993  if ( is_array( $list ) && count( $list ) == 1 ) {
994  $list = $list[0];
995  }
996  if ( is_object( $list ) ) {
997  $class = wfMessage( 'parentheses' )->params( get_class( $list ) )->escaped();
998 
999  return $class;
1000  } elseif ( !is_array( $list ) ) {
1001  return $list;
1002  } else {
1003  if ( is_object( $list[0] ) ) {
1004  $class = get_class( $list[0] );
1005  } else {
1006  $class = $list[0];
1007  }
1008 
1009  return wfMessage( 'parentheses' )->params( "$class, {$list[1]}" )->escaped();
1010  }
1011  }
1012 
1029  public static function getSvnInfo( $dir ) {
1030  // http://svnbook.red-bean.com/nightly/en/svn.developer.insidewc.html
1031  $entries = $dir . '/.svn/entries';
1032 
1033  if ( !file_exists( $entries ) ) {
1034  return false;
1035  }
1036 
1037  $lines = file( $entries );
1038  if ( !count( $lines ) ) {
1039  return false;
1040  }
1041 
1042  // check if file is xml (subversion release <= 1.3) or not (subversion release = 1.4)
1043  if ( preg_match( '/^<\?xml/', $lines[0] ) ) {
1044  // subversion is release <= 1.3
1045  if ( !function_exists( 'simplexml_load_file' ) ) {
1046  // We could fall back to expat... YUCK
1047  return false;
1048  }
1049 
1050  // SimpleXml whines about the xmlns...
1052  $xml = simplexml_load_file( $entries );
1054 
1055  if ( $xml ) {
1056  foreach ( $xml->entry as $entry ) {
1057  if ( $xml->entry[0]['name'] == '' ) {
1058  // The directory entry should always have a revision marker.
1059  if ( $entry['revision'] ) {
1060  return array( 'checkout-rev' => intval( $entry['revision'] ) );
1061  }
1062  }
1063  }
1064  }
1065 
1066  return false;
1067  }
1068 
1069  // Subversion is release 1.4 or above.
1070  if ( count( $lines ) < 11 ) {
1071  return false;
1072  }
1073 
1074  $info = array(
1075  'checkout-rev' => intval( trim( $lines[3] ) ),
1076  'url' => trim( $lines[4] ),
1077  'repo-url' => trim( $lines[5] ),
1078  'directory-rev' => intval( trim( $lines[10] ) )
1079  );
1080 
1081  if ( isset( self::$viewvcUrls[$info['repo-url']] ) ) {
1082  $viewvc = str_replace(
1083  $info['repo-url'],
1084  self::$viewvcUrls[$info['repo-url']],
1085  $info['url']
1086  );
1087 
1088  $viewvc .= '/?pathrev=';
1089  $viewvc .= urlencode( $info['checkout-rev'] );
1090  $info['viewvc-url'] = $viewvc;
1091  }
1092 
1093  return $info;
1094  }
1095 
1103  public static function getSvnRevision( $dir ) {
1104  $info = self::getSvnInfo( $dir );
1105 
1106  if ( $info === false ) {
1107  return false;
1108  } elseif ( isset( $info['checkout-rev'] ) ) {
1109  return $info['checkout-rev'];
1110  } else {
1111  return false;
1112  }
1113  }
1114 
1119  public static function getGitHeadSha1( $dir ) {
1120  $repo = new GitInfo( $dir );
1121 
1122  return $repo->getHeadSHA1();
1123  }
1124 
1129  public function getEntryPointInfo() {
1130  global $wgArticlePath, $wgScriptPath;
1131  $scriptPath = $wgScriptPath ? $wgScriptPath : "/";
1132  $entryPoints = array(
1133  'version-entrypoints-articlepath' => $wgArticlePath,
1134  'version-entrypoints-scriptpath' => $scriptPath,
1135  'version-entrypoints-index-php' => wfScript( 'index' ),
1136  'version-entrypoints-api-php' => wfScript( 'api' ),
1137  'version-entrypoints-load-php' => wfScript( 'load' ),
1138  );
1139 
1140  $language = $this->getLanguage();
1141  $thAttribures = array(
1142  'dir' => $language->getDir(),
1143  'lang' => $language->getCode()
1144  );
1145  $out = Html::element(
1146  'h2',
1147  array( 'id' => 'mw-version-entrypoints' ),
1148  $this->msg( 'version-entrypoints' )->text()
1149  ) .
1150  Html::openElement( 'table',
1151  array(
1152  'class' => 'wikitable plainlinks',
1153  'id' => 'mw-version-entrypoints-table',
1154  'dir' => 'ltr',
1155  'lang' => 'en'
1156  )
1157  ) .
1158  Html::openElement( 'tr' ) .
1159  Html::element(
1160  'th',
1161  $thAttribures,
1162  $this->msg( 'version-entrypoints-header-entrypoint' )->text()
1163  ) .
1164  Html::element(
1165  'th',
1166  $thAttribures,
1167  $this->msg( 'version-entrypoints-header-url' )->text()
1168  ) .
1169  Html::closeElement( 'tr' );
1170 
1171  foreach ( $entryPoints as $message => $value ) {
1172  $url = wfExpandUrl( $value, PROTO_RELATIVE );
1173  $out .= Html::openElement( 'tr' ) .
1174  // ->text() looks like it should be ->parse(), but this function
1175  // returns wikitext, not HTML, boo
1176  Html::rawElement( 'td', array(), $this->msg( $message )->text() ) .
1177  Html::rawElement( 'td', array(), Html::rawElement( 'code', array(), "[$url $value]" ) ) .
1178  Html::closeElement( 'tr' );
1179  }
1180 
1181  $out .= Html::closeElement( 'table' );
1182 
1183  return $out;
1184  }
1185 
1186  protected function getGroupName() {
1187  return 'wiki';
1188  }
1189 }
SpecialVersion\getExtensionCredits
getExtensionCredits()
Generate wikitext showing extensions name, URL, author and description.
Definition: SpecialVersion.php:427
SpecialPage\getPageTitle
getPageTitle( $subpage=false)
Get a self-referential title object.
Definition: SpecialPage.php:488
SpecialVersion\__construct
__construct()
Definition: SpecialVersion.php:47
SpecialVersion\listAuthors
listAuthors( $authors, $extName, $extDir)
Return a formatted unsorted list of authors.
Definition: SpecialVersion.php:863
SpecialVersion\getExtAuthorsFileName
static getExtAuthorsFileName( $extDir)
Obtains the full path of an extensions authors or credits file if one exists.
Definition: SpecialVersion.php:911
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
$html
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses & $html
Definition: hooks.txt:1530
SpecialPage\getOutput
getOutput()
Get the OutputPage being used for this instance.
Definition: SpecialPage.php:535
SpecialVersion\listToText
listToText( $list, $sort=true)
Convert an array of items into a list for display.
Definition: SpecialVersion.php:966
SpecialVersion\getMediaWikiCredits
static getMediaWikiCredits()
Returns wiki text showing the license information.
Definition: SpecialVersion.php:148
$extensions
$extensions
Definition: importImages.php:62
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3714
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
SpecialVersion\compare
compare( $a, $b)
Callback to sort extensions by type.
Definition: SpecialVersion.php:565
SpecialVersion\getCopyrightAndAuthorList
static getCopyrightAndAuthorList()
Get the "MediaWiki is copyright 2001-20xx by lots of cool guys" text.
Definition: SpecialVersion.php:170
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1530
wfSuppressWarnings
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
Definition: GlobalFunctions.php:2434
wfGetCache
wfGetCache( $inputType)
Get a cache object.
Definition: GlobalFunctions.php:4013
SpecialVersion\$coreId
$coreId
Stores the current rev id/SHA hash of MediaWiki core.
Definition: SpecialVersion.php:37
$wgHooks
$wgHooks['ArticleShow'][]
Definition: hooks.txt:110
SpecialPage\getLanguage
getLanguage()
Shortcut to get user's language.
Definition: SpecialPage.php:578
SpecialVersion\getParserFunctionHooks
getParserFunctionHooks()
Obtains a list of installed parser function hooks and the associated H2 header.
Definition: SpecialVersion.php:512
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2124
SpecialVersion\openExtType
openExtType( $text, $name=null)
Definition: SpecialVersion.php:796
Xml\openElement
static openElement( $element, $attribs=null)
This opens an XML element.
Definition: Xml.php:109
SpecialVersion\getSvnRevision
static getSvnRevision( $dir)
Retrieve the revision number of a Subversion working directory.
Definition: SpecialVersion.php:1103
Linker\makeExternalLink
static makeExternalLink( $url, $text, $escape=true, $linktype='', $attribs=array(), $title=null)
Make an external link.
Definition: Linker.php:1034
SpecialVersion\getVersionLinked
static getVersionLinked()
Return a wikitext-formatted string of the MediaWiki version with a link to the SVN revision or the gi...
Definition: SpecialVersion.php:285
$dbr
$dbr
Definition: testCompression.php:48
Linker\link
static link( $target, $html=null, $customAttribs=array(), $query=array(), $options=array())
This function returns an HTML link to the given target.
Definition: Linker.php:192
SpecialVersion\arrayToString
static arrayToString( $list)
Convert an array or object to a string for display.
Definition: SpecialVersion.php:992
SpecialVersion\softwareInformation
static softwareInformation()
Returns wiki text showing the third party software versions (apache, php, mysql).
Definition: SpecialVersion.php:205
Html\closeElement
static closeElement( $element)
Returns "</$element>", except if $wgWellFormedXml is off, in which case it returns the empty string w...
Definition: Html.php:235
file
We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going and make changes or fix bugs In we can take all the code that deals with the little used title reversing we can concentrate it all in an extension file
Definition: hooks.txt:93
SpecialVersion\$extensionTypes
static $extensionTypes
Definition: SpecialVersion.php:39
Html\openElement
static openElement( $element, $attribs=array())
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition: Html.php:166
SpecialVersion\IPInfo
IPInfo()
Get information about client's IP address.
Definition: SpecialVersion.php:837
wfMemcKey
wfMemcKey()
Get a cache key.
Definition: GlobalFunctions.php:3635
$out
$out
Definition: UtfNormalGenerate.php:167
wfRestoreWarnings
wfRestoreWarnings()
Restore error level to previous value.
Definition: GlobalFunctions.php:2464
wfScript
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
Definition: GlobalFunctions.php:3794
Html\element
static element( $element, $attribs=array(), $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition: Html.php:148
SpecialVersion\getExtensionTypeName
static getExtensionTypeName( $type)
Returns the internationalized name for an extension type.
Definition: SpecialVersion.php:416
SpecialVersion\getCreditsForExtension
getCreditsForExtension(array $extension)
Creates and formats a version line for a single extension.
Definition: SpecialVersion.php:592
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
wfMessage
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
Xml\element
static element( $element, $attribs=null, $contents='', $allowShortTag=true)
Format an XML element with given attributes and, optionally, text content.
Definition: Xml.php:39
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4066
$lines
$lines
Definition: router.php:65
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
SpecialPage\setHeaders
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
Definition: SpecialPage.php:352
SpecialVersion\getExtensionTypes
static getExtensionTypes()
Returns an array with the base extension types.
Definition: SpecialVersion.php:388
SpecialVersion\$viewvcUrls
static $viewvcUrls
Definition: SpecialVersion.php:41
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
SpecialVersion\getWgHooks
getWgHooks()
Generate wikitext showing hooks in $wgHooks.
Definition: SpecialVersion.php:766
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
$sort
$sort
Definition: profileinfo.php:301
SpecialVersion\getGroupName
getGroupName()
Under which header this special page is listed in Special:SpecialPages See messages 'specialpages-gro...
Definition: SpecialVersion.php:1186
SpecialVersion\getExtLicenseFileName
static getExtLicenseFileName( $extDir)
Obtains the full path of an extensions copying or license file if one exists.
Definition: SpecialVersion.php:940
SpecialVersion\getwgVersionLinked
static getwgVersionLinked()
Definition: SpecialVersion.php:335
SpecialVersion\execute
execute( $par)
main()
Definition: SpecialVersion.php:54
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:980
GitInfo
Definition: GitInfo.php:26
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
$value
$value
Definition: styleTest.css.php:45
SpecialPage\msg
msg()
Wrapper around wfMessage that sets the current context.
Definition: SpecialPage.php:609
SpecialVersion\getVersionLinkedSvn
static getVersionLinkedSvn()
Definition: SpecialVersion.php:309
SpecialPage
Parent class for all special pages.
Definition: SpecialPage.php:33
SpecialVersion\getSvnInfo
static getSvnInfo( $dir)
Get an associative array of information about a given path, from its .svn subdirectory.
Definition: SpecialVersion.php:1029
SpecialPage\getRequest
getRequest()
Get the WebRequest being used for this instance.
Definition: SpecialPage.php:525
CACHE_ANYTHING
const CACHE_ANYTHING
Definition: Defines.php:111
SpecialVersion
Give information about the version of MediaWiki, PHP, the DB and extensions.
Definition: SpecialVersion.php:31
$version
$version
Definition: parserTests.php:86
PROTO_RELATIVE
const PROTO_RELATIVE
Definition: Defines.php:269
SpecialVersion\getGitHeadSha1
static getGitHeadSha1( $dir)
Definition: SpecialVersion.php:1119
SpecialVersion\getEntryPointInfo
getEntryPointInfo()
Get the list of entry points and their URLs.
Definition: SpecialVersion.php:1129
SpecialVersion\$firstExtOpened
$firstExtOpened
Definition: SpecialVersion.php:32
$file
if(PHP_SAPI !='cli') $file
Definition: UtfNormalTest2.php:30
$wgArticlePath
$wgArticlePath
Definition: img_auth.php:48
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
SpecialVersion\getVersionLinkedGit
static getVersionLinkedGit()
Definition: SpecialVersion.php:352
$wgLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as $wgLang
Definition: design.txt:56
Xml\closeElement
static closeElement( $element)
Shortcut to close an XML element.
Definition: Xml.php:118
$cache
$cache
Definition: mcc.php:32
$wgParser
$wgParser
Definition: Setup.php:587
$dir
if(count( $args)==0) $dir
Definition: importImages.php:49
$ext
$ext
Definition: NoLocalSettings.php:34
format
if the prop value should be in the metadata multi language array format
Definition: hooks.txt:1230
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
SpecialVersion\getParserTags
getParserTags()
Obtains a list of installed parser tags and the associated H2 header.
Definition: SpecialVersion.php:480
Html\rawElement
static rawElement( $element, $attribs=array(), $contents='')
Returns an HTML element in a string.
Definition: Html.php:124
$IP
$IP
Definition: WebStart.php:92
MWTimestamp\getLocalInstance
static getLocalInstance( $ts=false)
Get a timestamp instance in the server local timezone ($wgLocaltimezone)
Definition: MWTimestamp.php:373
SpecialPage\outputHeader
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages Per default the message key is the canonical name o...
Definition: SpecialPage.php:443
wfExpandUrl
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
Definition: GlobalFunctions.php:544
SpecialVersion\getVersion
static getVersion( $flags='')
Return a string of the MediaWiki version with SVN revision if available.
Definition: SpecialVersion.php:246
$type
$type
Definition: testCompression.php:46
SpecialVersion\getExtensionCategory
getExtensionCategory( $type, $message)
Creates and returns the HTML for a single extension category.
Definition: SpecialVersion.php:541