MediaWiki  1.32.0
WikiImporter.php
Go to the documentation of this file.
1 <?php
28 
35 class WikiImporter {
36  private $reader = null;
37  private $foreignNamespaces = null;
42  private $mNoUpdates = false;
43  private $pageOffset = 0;
45  private $config;
49  private $countableCache = [];
51  private $disableStatisticsUpdate = false;
54 
62  if ( !class_exists( 'XMLReader' ) ) {
63  throw new Exception( 'Import requires PHP to have been compiled with libxml support' );
64  }
65 
66  $this->reader = new XMLReader();
67  $this->config = $config;
68 
69  if ( !in_array( 'uploadsource', stream_get_wrappers() ) ) {
70  stream_wrapper_register( 'uploadsource', UploadSourceAdapter::class );
71  }
73 
74  // Enable the entity loader, as it is needed for loading external URLs via
75  // XMLReader::open (T86036)
76  $oldDisable = libxml_disable_entity_loader( false );
77  if ( defined( 'LIBXML_PARSEHUGE' ) ) {
78  $status = $this->reader->open( "uploadsource://$id", null, LIBXML_PARSEHUGE );
79  } else {
80  $status = $this->reader->open( "uploadsource://$id" );
81  }
82  if ( !$status ) {
83  $error = libxml_get_last_error();
84  libxml_disable_entity_loader( $oldDisable );
85  throw new MWException( 'Encountered an internal error while initializing WikiImporter object: ' .
86  $error->message );
87  }
88  libxml_disable_entity_loader( $oldDisable );
89 
90  // Default callbacks
91  $this->setPageCallback( [ $this, 'beforeImportPage' ] );
92  $this->setRevisionCallback( [ $this, "importRevision" ] );
93  $this->setUploadCallback( [ $this, 'importUpload' ] );
94  $this->setLogItemCallback( [ $this, 'importLogItem' ] );
95  $this->setPageOutCallback( [ $this, 'finishImportPage' ] );
96 
97  $this->importTitleFactory = new NaiveImportTitleFactory();
98  $this->externalUserNames = new ExternalUserNames( 'imported', false );
99  }
100 
104  public function getReader() {
105  return $this->reader;
106  }
107 
108  public function throwXmlError( $err ) {
109  $this->debug( "FAILURE: $err" );
110  wfDebug( "WikiImporter XML error: $err\n" );
111  }
112 
113  public function debug( $data ) {
114  if ( $this->mDebug ) {
115  wfDebug( "IMPORT: $data\n" );
116  }
117  }
118 
119  public function warn( $data ) {
120  wfDebug( "IMPORT: $data\n" );
121  }
122 
123  public function notice( $msg /*, $param, ...*/ ) {
124  $params = func_get_args();
125  array_shift( $params );
126 
127  if ( is_callable( $this->mNoticeCallback ) ) {
128  call_user_func( $this->mNoticeCallback, $msg, $params );
129  } else { # No ImportReporter -> CLI
130  // T177997: the command line importers should call setNoticeCallback()
131  // for their own custom callback to echo the notice
132  wfDebug( wfMessage( $msg, $params )->text() . "\n" );
133  }
134  }
135 
140  function setDebug( $debug ) {
141  $this->mDebug = $debug;
142  }
143 
148  function setNoUpdates( $noupdates ) {
149  $this->mNoUpdates = $noupdates;
150  }
151 
158  function setPageOffset( $nthPage ) {
159  $this->pageOffset = $nthPage;
160  }
161 
168  public function setNoticeCallback( $callback ) {
169  return wfSetVar( $this->mNoticeCallback, $callback );
170  }
171 
177  public function setPageCallback( $callback ) {
178  $previous = $this->mPageCallback;
179  $this->mPageCallback = $callback;
180  return $previous;
181  }
182 
192  public function setPageOutCallback( $callback ) {
193  $previous = $this->mPageOutCallback;
194  $this->mPageOutCallback = $callback;
195  return $previous;
196  }
197 
203  public function setRevisionCallback( $callback ) {
204  $previous = $this->mRevisionCallback;
205  $this->mRevisionCallback = $callback;
206  return $previous;
207  }
208 
214  public function setUploadCallback( $callback ) {
215  $previous = $this->mUploadCallback;
216  $this->mUploadCallback = $callback;
217  return $previous;
218  }
219 
225  public function setLogItemCallback( $callback ) {
226  $previous = $this->mLogItemCallback;
227  $this->mLogItemCallback = $callback;
228  return $previous;
229  }
230 
236  public function setSiteInfoCallback( $callback ) {
237  $previous = $this->mSiteInfoCallback;
238  $this->mSiteInfoCallback = $callback;
239  return $previous;
240  }
241 
247  public function setImportTitleFactory( $factory ) {
248  $this->importTitleFactory = $factory;
249  }
250 
256  public function setTargetNamespace( $namespace ) {
257  if ( is_null( $namespace ) ) {
258  // Don't override namespaces
260  return true;
261  } elseif (
262  $namespace >= 0 &&
263  MWNamespace::exists( intval( $namespace ) )
264  ) {
265  $namespace = intval( $namespace );
266  $this->setImportTitleFactory( new NamespaceImportTitleFactory( $namespace ) );
267  return true;
268  } else {
269  return false;
270  }
271  }
272 
278  public function setTargetRootPage( $rootpage ) {
280  if ( is_null( $rootpage ) ) {
281  // No rootpage
283  } elseif ( $rootpage !== '' ) {
284  $rootpage = rtrim( $rootpage, '/' ); // avoid double slashes
285  $title = Title::newFromText( $rootpage );
286 
287  if ( !$title || $title->isExternal() ) {
288  $status->fatal( 'import-rootpage-invalid' );
289  } else {
290  if ( !MWNamespace::hasSubpages( $title->getNamespace() ) ) {
291  $displayNSText = $title->getNamespace() == NS_MAIN
292  ? wfMessage( 'blanknamespace' )->text()
293  : MediaWikiServices::getInstance()->getContentLanguage()->
294  getNsText( $title->getNamespace() );
295  $status->fatal( 'import-rootpage-nosubpage', $displayNSText );
296  } else {
297  // set namespace to 'all', so the namespace check in processTitle() can pass
298  $this->setTargetNamespace( null );
300  }
301  }
302  }
303  return $status;
304  }
305 
309  public function setImageBasePath( $dir ) {
310  $this->mImageBasePath = $dir;
311  }
312 
316  public function setImportUploads( $import ) {
317  $this->mImportUploads = $import;
318  }
319 
325  public function setUsernamePrefix( $usernamePrefix, $assignKnownUsers ) {
326  $this->externalUserNames = new ExternalUserNames( $usernamePrefix, $assignKnownUsers );
327  }
328 
333  public function disableStatisticsUpdate() {
334  $this->disableStatisticsUpdate = true;
335  }
336 
343  public function beforeImportPage( $titleAndForeignTitle ) {
344  $title = $titleAndForeignTitle[0];
345  $page = WikiPage::factory( $title );
346  $this->countableCache['title_' . $title->getPrefixedText()] = $page->isCountable();
347  return true;
348  }
349 
355  public function importRevision( $revision ) {
356  if ( !$revision->getContentHandler()->canBeUsedOn( $revision->getTitle() ) ) {
357  $this->notice( 'import-error-bad-location',
358  $revision->getTitle()->getPrefixedText(),
359  $revision->getID(),
360  $revision->getModel(),
361  $revision->getFormat() );
362 
363  return false;
364  }
365 
366  try {
367  return $revision->importOldRevision();
368  } catch ( MWContentSerializationException $ex ) {
369  $this->notice( 'import-error-unserialize',
370  $revision->getTitle()->getPrefixedText(),
371  $revision->getID(),
372  $revision->getModel(),
373  $revision->getFormat() );
374  }
375 
376  return false;
377  }
378 
384  public function importLogItem( $revision ) {
385  return $revision->importLogItem();
386  }
387 
393  public function importUpload( $revision ) {
394  return $revision->importUpload();
395  }
396 
406  public function finishImportPage( $title, $foreignTitle, $revCount,
407  $sRevCount, $pageInfo
408  ) {
409  // Update article count statistics (T42009)
410  // The normal counting logic in WikiPage->doEditUpdates() is designed for
411  // one-revision-at-a-time editing, not bulk imports. In this situation it
412  // suffers from issues of replica DB lag. We let WikiPage handle the total page
413  // and revision count, and we implement our own custom logic for the
414  // article (content page) count.
415  if ( !$this->disableStatisticsUpdate ) {
416  $page = WikiPage::factory( $title );
417  $page->loadPageData( 'fromdbmaster' );
418  $content = $page->getContent();
419  if ( $content === null ) {
420  wfDebug( __METHOD__ . ': Skipping article count adjustment for ' . $title .
421  ' because WikiPage::getContent() returned null' );
422  } else {
423  $editInfo = $page->prepareContentForEdit( $content );
424  $countKey = 'title_' . $title->getPrefixedText();
425  $countable = $page->isCountable( $editInfo );
426  if ( array_key_exists( $countKey, $this->countableCache ) &&
427  $countable != $this->countableCache[$countKey] ) {
429  'articles' => ( (int)$countable - (int)$this->countableCache[$countKey] )
430  ] ) );
431  }
432  }
433  }
434 
435  $args = func_get_args();
436  return Hooks::run( 'AfterImportPage', $args );
437  }
438 
443  public function debugRevisionHandler( &$revision ) {
444  $this->debug( "Got revision:" );
445  if ( is_object( $revision->title ) ) {
446  $this->debug( "-- Title: " . $revision->title->getPrefixedText() );
447  } else {
448  $this->debug( "-- Title: <invalid>" );
449  }
450  $this->debug( "-- User: " . $revision->user_text );
451  $this->debug( "-- Timestamp: " . $revision->timestamp );
452  $this->debug( "-- Comment: " . $revision->comment );
453  $this->debug( "-- Text: " . $revision->text );
454  }
455 
461  private function siteInfoCallback( $siteInfo ) {
462  if ( isset( $this->mSiteInfoCallback ) ) {
463  return call_user_func_array( $this->mSiteInfoCallback,
464  [ $siteInfo, $this ] );
465  } else {
466  return false;
467  }
468  }
469 
474  function pageCallback( $title ) {
475  if ( isset( $this->mPageCallback ) ) {
476  call_user_func( $this->mPageCallback, $title );
477  }
478  }
479 
488  private function pageOutCallback( $title, $foreignTitle, $revCount,
489  $sucCount, $pageInfo ) {
490  if ( isset( $this->mPageOutCallback ) ) {
491  $args = func_get_args();
492  call_user_func_array( $this->mPageOutCallback, $args );
493  }
494  }
495 
501  private function revisionCallback( $revision ) {
502  if ( isset( $this->mRevisionCallback ) ) {
503  return call_user_func_array( $this->mRevisionCallback,
504  [ $revision, $this ] );
505  } else {
506  return false;
507  }
508  }
509 
515  private function logItemCallback( $revision ) {
516  if ( isset( $this->mLogItemCallback ) ) {
517  return call_user_func_array( $this->mLogItemCallback,
518  [ $revision, $this ] );
519  } else {
520  return false;
521  }
522  }
523 
530  public function nodeAttribute( $attr ) {
531  return $this->reader->getAttribute( $attr );
532  }
533 
541  public function nodeContents() {
542  if ( $this->reader->isEmptyElement ) {
543  return "";
544  }
545  $buffer = "";
546  while ( $this->reader->read() ) {
547  switch ( $this->reader->nodeType ) {
548  case XMLReader::TEXT:
549  case XMLReader::CDATA:
550  case XMLReader::SIGNIFICANT_WHITESPACE:
551  $buffer .= $this->reader->value;
552  break;
553  case XMLReader::END_ELEMENT:
554  return $buffer;
555  }
556  }
557 
558  $this->reader->close();
559  return '';
560  }
561 
568  public function doImport() {
569  // Calls to reader->read need to be wrapped in calls to
570  // libxml_disable_entity_loader() to avoid local file
571  // inclusion attacks (T48932).
572  $oldDisable = libxml_disable_entity_loader( true );
573  $this->reader->read();
574 
575  if ( $this->reader->localName != 'mediawiki' ) {
576  libxml_disable_entity_loader( $oldDisable );
577  throw new MWException( "Expected <mediawiki> tag, got " .
578  $this->reader->localName );
579  }
580  $this->debug( "<mediawiki> tag is correct." );
581 
582  $this->debug( "Starting primary dump processing loop." );
583 
584  $keepReading = $this->reader->read();
585  $skip = false;
586  $rethrow = null;
587  $pageCount = 0;
588  try {
589  while ( $keepReading ) {
590  $tag = $this->reader->localName;
591  if ( $this->pageOffset ) {
592  if ( $tag === 'page' ) {
593  $pageCount++;
594  }
595  if ( $pageCount < $this->pageOffset ) {
596  $keepReading = $this->reader->next();
597  continue;
598  }
599  }
600  $type = $this->reader->nodeType;
601 
602  if ( !Hooks::run( 'ImportHandleToplevelXMLTag', [ $this ] ) ) {
603  // Do nothing
604  } elseif ( $tag == 'mediawiki' && $type == XMLReader::END_ELEMENT ) {
605  break;
606  } elseif ( $tag == 'siteinfo' ) {
607  $this->handleSiteInfo();
608  } elseif ( $tag == 'page' ) {
609  $this->handlePage();
610  } elseif ( $tag == 'logitem' ) {
611  $this->handleLogItem();
612  } elseif ( $tag != '#text' ) {
613  $this->warn( "Unhandled top-level XML tag $tag" );
614 
615  $skip = true;
616  }
617 
618  if ( $skip ) {
619  $keepReading = $this->reader->next();
620  $skip = false;
621  $this->debug( "Skip" );
622  } else {
623  $keepReading = $this->reader->read();
624  }
625  }
626  } catch ( Exception $ex ) {
627  $rethrow = $ex;
628  }
629 
630  // finally
631  libxml_disable_entity_loader( $oldDisable );
632  $this->reader->close();
633 
634  if ( $rethrow ) {
635  throw $rethrow;
636  }
637 
638  return true;
639  }
640 
641  private function handleSiteInfo() {
642  $this->debug( "Enter site info handler." );
643  $siteInfo = [];
644 
645  // Fields that can just be stuffed in the siteInfo object
646  $normalFields = [ 'sitename', 'base', 'generator', 'case' ];
647 
648  while ( $this->reader->read() ) {
649  if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
650  $this->reader->localName == 'siteinfo' ) {
651  break;
652  }
653 
654  $tag = $this->reader->localName;
655 
656  if ( $tag == 'namespace' ) {
657  $this->foreignNamespaces[$this->nodeAttribute( 'key' )] =
658  $this->nodeContents();
659  } elseif ( in_array( $tag, $normalFields ) ) {
660  $siteInfo[$tag] = $this->nodeContents();
661  }
662  }
663 
664  $siteInfo['_namespaces'] = $this->foreignNamespaces;
665  $this->siteInfoCallback( $siteInfo );
666  }
667 
668  private function handleLogItem() {
669  $this->debug( "Enter log item handler." );
670  $logInfo = [];
671 
672  // Fields that can just be stuffed in the pageInfo object
673  $normalFields = [ 'id', 'comment', 'type', 'action', 'timestamp',
674  'logtitle', 'params' ];
675 
676  while ( $this->reader->read() ) {
677  if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
678  $this->reader->localName == 'logitem' ) {
679  break;
680  }
681 
682  $tag = $this->reader->localName;
683 
684  if ( !Hooks::run( 'ImportHandleLogItemXMLTag', [
685  $this, $logInfo
686  ] ) ) {
687  // Do nothing
688  } elseif ( in_array( $tag, $normalFields ) ) {
689  $logInfo[$tag] = $this->nodeContents();
690  } elseif ( $tag == 'contributor' ) {
691  $logInfo['contributor'] = $this->handleContributor();
692  } elseif ( $tag != '#text' ) {
693  $this->warn( "Unhandled log-item XML tag $tag" );
694  }
695  }
696 
697  $this->processLogItem( $logInfo );
698  }
699 
704  private function processLogItem( $logInfo ) {
705  $revision = new WikiRevision( $this->config );
706 
707  if ( isset( $logInfo['id'] ) ) {
708  $revision->setID( $logInfo['id'] );
709  }
710  $revision->setType( $logInfo['type'] );
711  $revision->setAction( $logInfo['action'] );
712  if ( isset( $logInfo['timestamp'] ) ) {
713  $revision->setTimestamp( $logInfo['timestamp'] );
714  }
715  if ( isset( $logInfo['params'] ) ) {
716  $revision->setParams( $logInfo['params'] );
717  }
718  if ( isset( $logInfo['logtitle'] ) ) {
719  // @todo Using Title for non-local titles is a recipe for disaster.
720  // We should use ForeignTitle here instead.
721  $revision->setTitle( Title::newFromText( $logInfo['logtitle'] ) );
722  }
723 
724  $revision->setNoUpdates( $this->mNoUpdates );
725 
726  if ( isset( $logInfo['comment'] ) ) {
727  $revision->setComment( $logInfo['comment'] );
728  }
729 
730  if ( isset( $logInfo['contributor']['ip'] ) ) {
731  $revision->setUserIP( $logInfo['contributor']['ip'] );
732  }
733 
734  if ( !isset( $logInfo['contributor']['username'] ) ) {
735  $revision->setUsername( $this->externalUserNames->addPrefix( 'Unknown user' ) );
736  } else {
737  $revision->setUsername(
738  $this->externalUserNames->applyPrefix( $logInfo['contributor']['username'] )
739  );
740  }
741 
742  return $this->logItemCallback( $revision );
743  }
744 
745  private function handlePage() {
746  // Handle page data.
747  $this->debug( "Enter page handler." );
748  $pageInfo = [ 'revisionCount' => 0, 'successfulRevisionCount' => 0 ];
749 
750  // Fields that can just be stuffed in the pageInfo object
751  $normalFields = [ 'title', 'ns', 'id', 'redirect', 'restrictions' ];
752 
753  $skip = false;
754  $badTitle = false;
755 
756  while ( $skip ? $this->reader->next() : $this->reader->read() ) {
757  if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
758  $this->reader->localName == 'page' ) {
759  break;
760  }
761 
762  $skip = false;
763 
764  $tag = $this->reader->localName;
765 
766  if ( $badTitle ) {
767  // The title is invalid, bail out of this page
768  $skip = true;
769  } elseif ( !Hooks::run( 'ImportHandlePageXMLTag', [ $this,
770  &$pageInfo ] ) ) {
771  // Do nothing
772  } elseif ( in_array( $tag, $normalFields ) ) {
773  // An XML snippet:
774  // <page>
775  // <id>123</id>
776  // <title>Page</title>
777  // <redirect title="NewTitle"/>
778  // ...
779  // Because the redirect tag is built differently, we need special handling for that case.
780  if ( $tag == 'redirect' ) {
781  $pageInfo[$tag] = $this->nodeAttribute( 'title' );
782  } else {
783  $pageInfo[$tag] = $this->nodeContents();
784  }
785  } elseif ( $tag == 'revision' || $tag == 'upload' ) {
786  if ( !isset( $title ) ) {
787  $title = $this->processTitle( $pageInfo['title'],
788  $pageInfo['ns'] ?? null );
789 
790  // $title is either an array of two titles or false.
791  if ( is_array( $title ) ) {
792  $this->pageCallback( $title );
793  list( $pageInfo['_title'], $foreignTitle ) = $title;
794  } else {
795  $badTitle = true;
796  $skip = true;
797  }
798  }
799 
800  if ( $title ) {
801  if ( $tag == 'revision' ) {
802  $this->handleRevision( $pageInfo );
803  } else {
804  $this->handleUpload( $pageInfo );
805  }
806  }
807  } elseif ( $tag != '#text' ) {
808  $this->warn( "Unhandled page XML tag $tag" );
809  $skip = true;
810  }
811  }
812 
813  // @note $pageInfo is only set if a valid $title is processed above with
814  // no error. If we have a valid $title, then pageCallback is called
815  // above, $pageInfo['title'] is set and we do pageOutCallback here.
816  // If $pageInfo['_title'] is not set, then $foreignTitle is also not
817  // set since they both come from $title above.
818  if ( array_key_exists( '_title', $pageInfo ) ) {
819  $this->pageOutCallback( $pageInfo['_title'], $foreignTitle,
820  $pageInfo['revisionCount'],
821  $pageInfo['successfulRevisionCount'],
822  $pageInfo );
823  }
824  }
825 
829  private function handleRevision( &$pageInfo ) {
830  $this->debug( "Enter revision handler" );
831  $revisionInfo = [];
832 
833  $normalFields = [ 'id', 'timestamp', 'comment', 'minor', 'model', 'format', 'text', 'sha1' ];
834 
835  $skip = false;
836 
837  while ( $skip ? $this->reader->next() : $this->reader->read() ) {
838  if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
839  $this->reader->localName == 'revision' ) {
840  break;
841  }
842 
843  $tag = $this->reader->localName;
844 
845  if ( !Hooks::run( 'ImportHandleRevisionXMLTag', [
846  $this, $pageInfo, $revisionInfo
847  ] ) ) {
848  // Do nothing
849  } elseif ( in_array( $tag, $normalFields ) ) {
850  $revisionInfo[$tag] = $this->nodeContents();
851  } elseif ( $tag == 'contributor' ) {
852  $revisionInfo['contributor'] = $this->handleContributor();
853  } elseif ( $tag != '#text' ) {
854  $this->warn( "Unhandled revision XML tag $tag" );
855  $skip = true;
856  }
857  }
858 
859  $pageInfo['revisionCount']++;
860  if ( $this->processRevision( $pageInfo, $revisionInfo ) ) {
861  $pageInfo['successfulRevisionCount']++;
862  }
863  }
864 
871  private function processRevision( $pageInfo, $revisionInfo ) {
872  global $wgMaxArticleSize;
873 
874  // Make sure revisions won't violate $wgMaxArticleSize, which could lead to
875  // database errors and instability. Testing for revisions with only listed
876  // content models, as other content models might use serialization formats
877  // which aren't checked against $wgMaxArticleSize.
878  if ( ( !isset( $revisionInfo['model'] ) ||
879  in_array( $revisionInfo['model'], [
880  'wikitext',
881  'css',
882  'json',
883  'javascript',
884  'text',
885  ''
886  ] ) ) &&
887  strlen( $revisionInfo['text'] ) > $wgMaxArticleSize * 1024
888  ) {
889  throw new MWException( 'The text of ' .
890  ( isset( $revisionInfo['id'] ) ?
891  "the revision with ID $revisionInfo[id]" :
892  'a revision'
893  ) . " exceeds the maximum allowable size ($wgMaxArticleSize KB)" );
894  }
895 
896  $revision = new WikiRevision( $this->config );
897 
898  if ( isset( $revisionInfo['id'] ) ) {
899  $revision->setID( $revisionInfo['id'] );
900  }
901  if ( isset( $revisionInfo['model'] ) ) {
902  $revision->setModel( $revisionInfo['model'] );
903  }
904  if ( isset( $revisionInfo['format'] ) ) {
905  $revision->setFormat( $revisionInfo['format'] );
906  }
907  $revision->setTitle( $pageInfo['_title'] );
908 
909  if ( isset( $revisionInfo['text'] ) ) {
910  $handler = $revision->getContentHandler();
911  $text = $handler->importTransform(
912  $revisionInfo['text'],
913  $revision->getFormat() );
914 
915  $revision->setText( $text );
916  }
917  if ( isset( $revisionInfo['timestamp'] ) ) {
918  $revision->setTimestamp( $revisionInfo['timestamp'] );
919  } else {
920  $revision->setTimestamp( wfTimestampNow() );
921  }
922 
923  if ( isset( $revisionInfo['comment'] ) ) {
924  $revision->setComment( $revisionInfo['comment'] );
925  }
926 
927  if ( isset( $revisionInfo['minor'] ) ) {
928  $revision->setMinor( true );
929  }
930  if ( isset( $revisionInfo['contributor']['ip'] ) ) {
931  $revision->setUserIP( $revisionInfo['contributor']['ip'] );
932  } elseif ( isset( $revisionInfo['contributor']['username'] ) ) {
933  $revision->setUsername(
934  $this->externalUserNames->applyPrefix( $revisionInfo['contributor']['username'] )
935  );
936  } else {
937  $revision->setUsername( $this->externalUserNames->addPrefix( 'Unknown user' ) );
938  }
939  if ( isset( $revisionInfo['sha1'] ) ) {
940  $revision->setSha1Base36( $revisionInfo['sha1'] );
941  }
942  $revision->setNoUpdates( $this->mNoUpdates );
943 
944  return $this->revisionCallback( $revision );
945  }
946 
951  private function handleUpload( &$pageInfo ) {
952  $this->debug( "Enter upload handler" );
953  $uploadInfo = [];
954 
955  $normalFields = [ 'timestamp', 'comment', 'filename', 'text',
956  'src', 'size', 'sha1base36', 'archivename', 'rel' ];
957 
958  $skip = false;
959 
960  while ( $skip ? $this->reader->next() : $this->reader->read() ) {
961  if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
962  $this->reader->localName == 'upload' ) {
963  break;
964  }
965 
966  $tag = $this->reader->localName;
967 
968  if ( !Hooks::run( 'ImportHandleUploadXMLTag', [
969  $this, $pageInfo
970  ] ) ) {
971  // Do nothing
972  } elseif ( in_array( $tag, $normalFields ) ) {
973  $uploadInfo[$tag] = $this->nodeContents();
974  } elseif ( $tag == 'contributor' ) {
975  $uploadInfo['contributor'] = $this->handleContributor();
976  } elseif ( $tag == 'contents' ) {
977  $contents = $this->nodeContents();
978  $encoding = $this->reader->getAttribute( 'encoding' );
979  if ( $encoding === 'base64' ) {
980  $uploadInfo['fileSrc'] = $this->dumpTemp( base64_decode( $contents ) );
981  $uploadInfo['isTempSrc'] = true;
982  }
983  } elseif ( $tag != '#text' ) {
984  $this->warn( "Unhandled upload XML tag $tag" );
985  $skip = true;
986  }
987  }
988 
989  if ( $this->mImageBasePath && isset( $uploadInfo['rel'] ) ) {
990  $path = "{$this->mImageBasePath}/{$uploadInfo['rel']}";
991  if ( file_exists( $path ) ) {
992  $uploadInfo['fileSrc'] = $path;
993  $uploadInfo['isTempSrc'] = false;
994  }
995  }
996 
997  if ( $this->mImportUploads ) {
998  return $this->processUpload( $pageInfo, $uploadInfo );
999  }
1000  }
1001 
1006  private function dumpTemp( $contents ) {
1007  $filename = tempnam( wfTempDir(), 'importupload' );
1008  file_put_contents( $filename, $contents );
1009  return $filename;
1010  }
1011 
1017  private function processUpload( $pageInfo, $uploadInfo ) {
1018  $revision = new WikiRevision( $this->config );
1019  $text = $uploadInfo['text'] ?? '';
1020 
1021  $revision->setTitle( $pageInfo['_title'] );
1022  $revision->setID( $pageInfo['id'] );
1023  $revision->setTimestamp( $uploadInfo['timestamp'] );
1024  $revision->setText( $text );
1025  $revision->setFilename( $uploadInfo['filename'] );
1026  if ( isset( $uploadInfo['archivename'] ) ) {
1027  $revision->setArchiveName( $uploadInfo['archivename'] );
1028  }
1029  $revision->setSrc( $uploadInfo['src'] );
1030  if ( isset( $uploadInfo['fileSrc'] ) ) {
1031  $revision->setFileSrc( $uploadInfo['fileSrc'],
1032  !empty( $uploadInfo['isTempSrc'] ) );
1033  }
1034  if ( isset( $uploadInfo['sha1base36'] ) ) {
1035  $revision->setSha1Base36( $uploadInfo['sha1base36'] );
1036  }
1037  $revision->setSize( intval( $uploadInfo['size'] ) );
1038  $revision->setComment( $uploadInfo['comment'] );
1039 
1040  if ( isset( $uploadInfo['contributor']['ip'] ) ) {
1041  $revision->setUserIP( $uploadInfo['contributor']['ip'] );
1042  }
1043  if ( isset( $uploadInfo['contributor']['username'] ) ) {
1044  $revision->setUsername(
1045  $this->externalUserNames->applyPrefix( $uploadInfo['contributor']['username'] )
1046  );
1047  }
1048  $revision->setNoUpdates( $this->mNoUpdates );
1049 
1050  return call_user_func( $this->mUploadCallback, $revision );
1051  }
1052 
1056  private function handleContributor() {
1057  $fields = [ 'id', 'ip', 'username' ];
1058  $info = [];
1059 
1060  if ( $this->reader->isEmptyElement ) {
1061  return $info;
1062  }
1063  while ( $this->reader->read() ) {
1064  if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
1065  $this->reader->localName == 'contributor' ) {
1066  break;
1067  }
1068 
1069  $tag = $this->reader->localName;
1070 
1071  if ( in_array( $tag, $fields ) ) {
1072  $info[$tag] = $this->nodeContents();
1073  }
1074  }
1075 
1076  return $info;
1077  }
1078 
1084  private function processTitle( $text, $ns = null ) {
1085  if ( is_null( $this->foreignNamespaces ) ) {
1086  $foreignTitleFactory = new NaiveForeignTitleFactory();
1087  } else {
1088  $foreignTitleFactory = new NamespaceAwareForeignTitleFactory(
1089  $this->foreignNamespaces );
1090  }
1091 
1092  $foreignTitle = $foreignTitleFactory->createForeignTitle( $text,
1093  intval( $ns ) );
1094 
1095  $title = $this->importTitleFactory->createTitleFromForeignTitle(
1096  $foreignTitle );
1097 
1098  $commandLineMode = $this->config->get( 'CommandLineMode' );
1099  if ( is_null( $title ) ) {
1100  # Invalid page title? Ignore the page
1101  $this->notice( 'import-error-invalid', $foreignTitle->getFullText() );
1102  return false;
1103  } elseif ( $title->isExternal() ) {
1104  $this->notice( 'import-error-interwiki', $title->getPrefixedText() );
1105  return false;
1106  } elseif ( !$title->canExist() ) {
1107  $this->notice( 'import-error-special', $title->getPrefixedText() );
1108  return false;
1109  } elseif ( !$title->userCan( 'edit' ) && !$commandLineMode ) {
1110  # Do not import if the importing wiki user cannot edit this page
1111  $this->notice( 'import-error-edit', $title->getPrefixedText() );
1112  return false;
1113  } elseif ( !$title->exists() && !$title->userCan( 'create' ) && !$commandLineMode ) {
1114  # Do not import if the importing wiki user cannot create this page
1115  $this->notice( 'import-error-create', $title->getPrefixedText() );
1116  return false;
1117  }
1118 
1119  return [ $title, $foreignTitle ];
1120  }
1121 }
NaiveImportTitleFactory
A class to convert page titles on a foreign wiki (ForeignTitle objects) into page titles on the local...
Definition: NaiveImportTitleFactory.php:34
WikiImporter\processRevision
processRevision( $pageInfo, $revisionInfo)
Definition: WikiImporter.php:871
$status
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action, or null $user:User who performed the tagging when the tagging is subsequent to the action, or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'ContentSecurityPolicyDefaultSource':Modify the allowed CSP load sources. This affects all directives except for the script directive. If you want to add a script source, see ContentSecurityPolicyScriptSource hook. & $defaultSrc:Array of Content-Security-Policy allowed sources $policyConfig:Current configuration for the Content-Security-Policy header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyDirectives':Modify the content security policy directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. & $directives:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyScriptSource':Modify the allowed CSP script sources. Note that you also have to use ContentSecurityPolicyDefaultSource if you want non-script sources to be loaded from whatever you add. & $scriptSrc:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DeleteUnknownPreferences':Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed with 'gadget-', and so anything with that prefix is excluded from the deletion. &where:An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted from the user_properties table. $db:The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1305
WikiImporter\$mUploadCallback
$mUploadCallback
Definition: WikiImporter.php:38
WikiImporter
XML file reader for the page data importer.
Definition: WikiImporter.php:35
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:280
$wgMaxArticleSize
$wgMaxArticleSize
Maximum article size in kilobytes.
Definition: DefaultSettings.php:2286
WikiImporter\setImageBasePath
setImageBasePath( $dir)
Definition: WikiImporter.php:309
wfSetVar
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
Definition: GlobalFunctions.php:1673
UploadSourceAdapter\registerSource
static registerSource(ImportSource $source)
Definition: UploadSourceAdapter.php:48
WikiImporter\$mImportUploads
$mImportUploads
Definition: WikiImporter.php:41
NamespaceAwareForeignTitleFactory
A parser that translates page titles on a foreign wiki into ForeignTitle objects, using information a...
Definition: NamespaceAwareForeignTitleFactory.php:25
WikiImporter\$mRevisionCallback
$mRevisionCallback
Definition: WikiImporter.php:38
WikiImporter\revisionCallback
revisionCallback( $revision)
Notify the callback function of a revision.
Definition: WikiImporter.php:501
WikiImporter\setNoticeCallback
setNoticeCallback( $callback)
Set a callback that displays notice messages.
Definition: WikiImporter.php:168
DeferredUpdates\addUpdate
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the deferred list to be run later by execute()
Definition: DeferredUpdates.php:79
NaiveForeignTitleFactory
A parser that translates page titles on a foreign wiki into ForeignTitle objects, with no knowledge o...
Definition: NaiveForeignTitleFactory.php:27
WikiImporter\$mPageOutCallback
$mPageOutCallback
Definition: WikiImporter.php:39
WikiImporter\setNoUpdates
setNoUpdates( $noupdates)
Set 'no updates' mode.
Definition: WikiImporter.php:148
WikiImporter\getReader
getReader()
Definition: WikiImporter.php:104
ExternalUserNames
Class to parse and build external user names.
Definition: ExternalUserNames.php:29
WikiImporter\processLogItem
processLogItem( $logInfo)
Definition: WikiImporter.php:704
$params
$params
Definition: styleTest.css.php:44
WikiImporter\handleRevision
handleRevision(&$pageInfo)
Definition: WikiImporter.php:829
WikiImporter\setRevisionCallback
setRevisionCallback( $callback)
Sets the action to perform as each page revision is reached.
Definition: WikiImporter.php:203
WikiImporter\handleContributor
handleContributor()
Definition: WikiImporter.php:1056
WikiImporter\setUsernamePrefix
setUsernamePrefix( $usernamePrefix, $assignKnownUsers)
Definition: WikiImporter.php:325
ImportReporter
Reporting callback.
Definition: ImportReporter.php:27
WikiImporter\$externalUserNames
ExternalUserNames $externalUserNames
Definition: WikiImporter.php:53
NamespaceImportTitleFactory
A class to convert page titles on a foreign wiki (ForeignTitle objects) into page titles on the local...
Definition: NamespaceImportTitleFactory.php:26
WikiImporter\nodeContents
nodeContents()
Shouldn't something like this be built-in to XMLReader? Fetches text contents of the current element,...
Definition: WikiImporter.php:541
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
WikiImporter\siteInfoCallback
siteInfoCallback( $siteInfo)
Notify the callback function of site info.
Definition: WikiImporter.php:461
$debug
$debug
Definition: mcc.php:31
NS_MAIN
const NS_MAIN
Definition: Defines.php:64
Config
Interface for configuration instances.
Definition: Config.php:28
MWException
MediaWiki exception.
Definition: MWException.php:26
ImportTitleFactory
Represents an object that can convert page titles on a foreign wiki (ForeignTitle objects) into page ...
Definition: ImportTitleFactory.php:25
$title
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:964
WikiPage\factory
static factory(Title $title)
Create a WikiPage object of the appropriate class for the given title.
Definition: WikiPage.php:127
WikiImporter\dumpTemp
dumpTemp( $contents)
Definition: WikiImporter.php:1006
WikiImporter\$countableCache
array $countableCache
Definition: WikiImporter.php:49
WikiImporter\pageOutCallback
pageOutCallback( $title, $foreignTitle, $revCount, $sucCount, $pageInfo)
Notify the callback function when a "</page>" is closed.
Definition: WikiImporter.php:488
WikiImporter\__construct
__construct(ImportSource $source, Config $config)
Creates an ImportXMLReader drawing from the source provided.
Definition: WikiImporter.php:61
MWContentSerializationException
Exception representing a failure to serialize or unserialize a content object.
Definition: MWContentSerializationException.php:7
WikiImporter\throwXmlError
throwXmlError( $err)
Definition: WikiImporter.php:108
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
MWNamespace\hasSubpages
static hasSubpages( $index)
Does the namespace allow subpages?
Definition: MWNamespace.php:364
SubpageImportTitleFactory
A class to convert page titles on a foreign wiki (ForeignTitle objects) into page titles on the local...
Definition: SubpageImportTitleFactory.php:26
SiteStatsUpdate\factory
static factory(array $deltas)
Definition: SiteStatsUpdate.php:66
WikiImporter\finishImportPage
finishImportPage( $title, $foreignTitle, $revCount, $sRevCount, $pageInfo)
Mostly for hook use.
Definition: WikiImporter.php:406
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1983
WikiImporter\$importTitleFactory
ImportTitleFactory $importTitleFactory
Definition: WikiImporter.php:47
WikiImporter\processUpload
processUpload( $pageInfo, $uploadInfo)
Definition: WikiImporter.php:1017
WikiImporter\disableStatisticsUpdate
disableStatisticsUpdate()
Statistics update can cause a lot of time.
Definition: WikiImporter.php:333
WikiImporter\setImportUploads
setImportUploads( $import)
Definition: WikiImporter.php:316
WikiImporter\$mNoUpdates
$mNoUpdates
Definition: WikiImporter.php:42
array
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:988
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
WikiImporter\$mPageCallback
$mPageCallback
Definition: WikiImporter.php:38
WikiImporter\$mSiteInfoCallback
$mSiteInfoCallback
Definition: WikiImporter.php:39
WikiImporter\beforeImportPage
beforeImportPage( $titleAndForeignTitle)
Default per-page callback.
Definition: WikiImporter.php:343
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:81
WikiImporter\importRevision
importRevision( $revision)
Default per-revision callback, performs the import.
Definition: WikiImporter.php:355
WikiImporter\doImport
doImport()
Primary entry point.
Definition: WikiImporter.php:568
WikiImporter\processTitle
processTitle( $text, $ns=null)
Definition: WikiImporter.php:1084
WikiImporter\$mImageBasePath
$mImageBasePath
Definition: WikiImporter.php:41
WikiImporter\$foreignNamespaces
$foreignNamespaces
Definition: WikiImporter.php:37
WikiImporter\notice
notice( $msg)
Definition: WikiImporter.php:123
WikiImporter\setDebug
setDebug( $debug)
Set debug mode...
Definition: WikiImporter.php:140
MWNamespace\exists
static exists( $index)
Returns whether the specified namespace exists.
Definition: MWNamespace.php:182
WikiImporter\$reader
$reader
Definition: WikiImporter.php:36
$handler
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check set to true or false to override the $wgMaxImageArea check result gives extension the possibility to transform it themselves $handler
Definition: hooks.txt:813
WikiImporter\handleUpload
handleUpload(&$pageInfo)
Definition: WikiImporter.php:951
WikiImporter\setUploadCallback
setUploadCallback( $callback)
Sets the action to perform as each file upload version is reached.
Definition: WikiImporter.php:214
WikiImporter\warn
warn( $data)
Definition: WikiImporter.php:119
WikiImporter\handleSiteInfo
handleSiteInfo()
Definition: WikiImporter.php:641
WikiImporter\setTargetRootPage
setTargetRootPage( $rootpage)
Set a target root page under which all pages are imported.
Definition: WikiImporter.php:278
text
This list may contain false positives That usually means there is additional text with links below the first Each row contains links to the first and second as well as the first line of the second redirect text
Definition: All_system_messages.txt:1267
$args
if( $line===false) $args
Definition: cdb.php:64
WikiImporter\$mNoticeCallback
$mNoticeCallback
Definition: WikiImporter.php:40
wfTempDir
wfTempDir()
Tries to get the system directory for temporary files.
Definition: GlobalFunctions.php:2031
WikiRevision
Represents a revision, log entry or upload during the import process.
Definition: WikiRevision.php:37
WikiImporter\debug
debug( $data)
Definition: WikiImporter.php:113
WikiImporter\importLogItem
importLogItem( $revision)
Default per-revision callback, performs the import.
Definition: WikiImporter.php:384
WikiImporter\importUpload
importUpload( $revision)
Dummy for now...
Definition: WikiImporter.php:393
WikiImporter\setPageOffset
setPageOffset( $nthPage)
Sets 'pageOffset' value.
Definition: WikiImporter.php:158
WikiImporter\handleLogItem
handleLogItem()
Definition: WikiImporter.php:668
ImportSource
Source interface for XML import.
Definition: ImportSource.php:32
$path
$path
Definition: NoLocalSettings.php:25
WikiImporter\$pageOffset
$pageOffset
Definition: WikiImporter.php:43
WikiImporter\$config
Config $config
Definition: WikiImporter.php:45
WikiImporter\setSiteInfoCallback
setSiteInfoCallback( $callback)
Sets the action to perform when site info is encountered.
Definition: WikiImporter.php:236
WikiImporter\setPageOutCallback
setPageOutCallback( $callback)
Sets the action to perform as each page in the stream is completed.
Definition: WikiImporter.php:192
WikiImporter\debugRevisionHandler
debugRevisionHandler(&$revision)
Alternate per-revision callback, for debugging.
Definition: WikiImporter.php:443
WikiImporter\$disableStatisticsUpdate
bool $disableStatisticsUpdate
Definition: WikiImporter.php:51
$source
$source
Definition: mwdoc-filter.php:46
$content
$content
Definition: pageupdater.txt:72
WikiImporter\handlePage
handlePage()
Definition: WikiImporter.php:745
WikiImporter\nodeAttribute
nodeAttribute( $attr)
Retrieves the contents of the named attribute of the current element.
Definition: WikiImporter.php:530
class
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
WikiImporter\setPageCallback
setPageCallback( $callback)
Sets the action to perform as each new page in the stream is reached.
Definition: WikiImporter.php:177
WikiImporter\setImportTitleFactory
setImportTitleFactory( $factory)
Sets the factory object to use to convert ForeignTitle objects into local Title objects.
Definition: WikiImporter.php:247
MediaWikiServices
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
WikiImporter\setTargetNamespace
setTargetNamespace( $namespace)
Set a target namespace to override the defaults.
Definition: WikiImporter.php:256
wfMessage
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead 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
WikiImporter\logItemCallback
logItemCallback( $revision)
Notify the callback function of a new log item.
Definition: WikiImporter.php:515
Hooks\run
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
WikiImporter\pageCallback
pageCallback( $title)
Notify the callback function when a new "<page>" is reached.
Definition: WikiImporter.php:474
WikiImporter\$mLogItemCallback
$mLogItemCallback
Definition: WikiImporter.php:38
$buffer
$buffer
Definition: mwdoc-filter.php:49
WikiImporter\$mDebug
$mDebug
Definition: WikiImporter.php:40
WikiImporter\setLogItemCallback
setLogItemCallback( $callback)
Sets the action to perform as each log item reached.
Definition: WikiImporter.php:225
$type
$type
Definition: testCompression.php:48