54 private $sourceAdapterId;
57 private $foreignNamespaces =
null;
60 private $mLogItemCallback;
63 private $mUploadCallback;
66 private $mRevisionCallback;
69 private $mPageCallback;
72 private $mSiteInfoCallback;
75 private $mPageOutCallback;
78 private $mNoticeCallback;
84 private $mImportUploads;
87 private $mImageBasePath;
90 private $mNoUpdates =
false;
93 private $pageOffset = 0;
99 private $importTitleFactory;
105 private $countableCache = [];
108 private $disableStatisticsUpdate =
false;
111 private $externalUserNames;
114 private $contentLanguage;
117 private $namespaceInfo;
120 private $titleFactory;
123 private $wikiPageFactory;
126 private $uploadRevisionImporter;
129 private $permissionManager;
132 private $contentHandlerFactory;
135 private $slotRoleRegistry;
165 $this->config = $config;
166 $this->hookRunner =
new HookRunner( $hookContainer );
167 $this->contentLanguage = $contentLanguage;
168 $this->namespaceInfo = $namespaceInfo;
169 $this->titleFactory = $titleFactory;
170 $this->wikiPageFactory = $wikiPageFactory;
171 $this->uploadRevisionImporter = $uploadRevisionImporter;
172 $this->permissionManager = $permissionManager;
173 $this->contentHandlerFactory = $contentHandlerFactory;
174 $this->slotRoleRegistry = $slotRoleRegistry;
176 if ( !in_array(
'uploadsource', stream_get_wrappers() ) ) {
177 stream_wrapper_register(
'uploadsource', UploadSourceAdapter::class );
191 $this->contentLanguage,
192 $this->namespaceInfo,
202 return $this->reader;
209 $this->
debug(
"FAILURE: $err" );
210 wfDebug(
"WikiImporter XML error: $err" );
217 if ( $this->mDebug ) {
225 public function warn( $data ) {
233 public function notice( $msg, ...$params ) {
234 if ( is_callable( $this->mNoticeCallback ) ) {
235 call_user_func( $this->mNoticeCallback, $msg, $params );
248 $this->mDebug = $debug;
256 $this->mNoUpdates = $noupdates;
266 $this->pageOffset = $nthPage;
276 return wfSetVar( $this->mNoticeCallback, $callback );
285 $previous = $this->mPageCallback;
286 $this->mPageCallback = $callback;
300 $previous = $this->mPageOutCallback;
301 $this->mPageOutCallback = $callback;
311 $previous = $this->mRevisionCallback;
312 $this->mRevisionCallback = $callback;
322 $previous = $this->mUploadCallback;
323 $this->mUploadCallback = $callback;
333 $previous = $this->mLogItemCallback;
334 $this->mLogItemCallback = $callback;
344 $previous = $this->mSiteInfoCallback;
345 $this->mSiteInfoCallback = $callback;
355 $this->importTitleFactory = $factory;
364 if ( $namespace ===
null ) {
368 $this->contentLanguage,
369 $this->namespaceInfo,
376 $this->namespaceInfo->exists( intval( $namespace ) )
378 $namespace = intval( $namespace );
381 $this->namespaceInfo,
398 $status = Status::newGood();
399 $nsInfo = $this->namespaceInfo;
400 if ( $rootpage ===
null ) {
404 $this->contentLanguage,
409 } elseif ( $rootpage !==
'' ) {
410 $rootpage = rtrim( $rootpage,
'/' );
411 $title = Title::newFromText( $rootpage );
414 $status->fatal(
'import-rootpage-invalid' );
415 } elseif ( !$nsInfo->hasSubpages(
$title->getNamespace() ) ) {
418 : $this->contentLanguage->getNsText(
$title->getNamespace() );
419 $status->fatal(
'import-rootpage-nosubpage', $displayNSText );
439 $this->mImageBasePath = $dir;
446 $this->mImportUploads = $import;
455 $this->externalUserNames =
new ExternalUserNames( $usernamePrefix, $assignKnownUsers );
473 $title = $titleAndForeignTitle[0];
474 $page = $this->wikiPageFactory->newFromTitle(
$title );
475 $this->countableCache[
'title_' .
$title->getPrefixedText()] = $page->isCountable();
485 if ( !$revision->getContentHandler()->canBeUsedOn( $revision->getTitle() ) ) {
486 $this->
notice(
'import-error-bad-location',
487 $revision->getTitle()->getPrefixedText(),
489 $revision->getModel(),
490 $revision->getFormat()
497 return $revision->importOldRevision();
499 $this->
notice(
'import-error-unserialize',
500 $revision->getTitle()->getPrefixedText(),
502 $revision->getModel(),
503 $revision->getFormat()
516 return $revision->importLogItem();
525 $status = $this->uploadRevisionImporter->import( $revision );
526 return $status->isGood();
539 $sRevCount, $pageInfo
548 $page = $this->wikiPageFactory->newFromTitle( $pageIdentity );
550 $page->loadPageData( WikiPage::READ_LATEST );
551 $rev = $page->getRevisionRecord();
552 if ( $rev ===
null ) {
554 wfDebug( __METHOD__ .
': Skipping article count adjustment for ' . $pageIdentity .
555 ' because WikiPage::getRevisionRecord() returned null' );
557 $user = RequestContext::getMain()->getUser();
558 $update = $page->newPageUpdater( $user )->prepareUpdate();
559 $countKey =
'title_' . CacheKeyHelper::getKeyForPage( $pageIdentity );
560 $countable = $update->isCountable();
561 if ( array_key_exists( $countKey, $this->countableCache ) &&
562 $countable != $this->countableCache[$countKey] ) {
563 DeferredUpdates::addUpdate( SiteStatsUpdate::factory( [
564 'articles' => ( (
int)$countable - (
int)$this->countableCache[$countKey] )
570 $title = Title::castFromPageIdentity( $pageIdentity );
572 return $this->hookRunner->onAfterImportPage(
$title, $foreignTitle,
573 $revCount, $sRevCount, $pageInfo );
581 private function siteInfoCallback( $siteInfo ) {
582 if ( isset( $this->mSiteInfoCallback ) ) {
583 return call_user_func_array(
584 $this->mSiteInfoCallback,
597 if ( isset( $this->mPageCallback ) ) {
598 call_user_func( $this->mPageCallback,
$title );
610 private function pageOutCallback(
PageIdentity $pageIdentity, $foreignTitle, $revCount,
611 $sucCount, $pageInfo ) {
612 if ( isset( $this->mPageOutCallback ) ) {
613 call_user_func_array( $this->mPageOutCallback, func_get_args() );
622 private function revisionCallback( $revision ) {
623 if ( isset( $this->mRevisionCallback ) ) {
624 return call_user_func_array(
625 $this->mRevisionCallback,
638 private function logItemCallback( $revision ) {
639 if ( isset( $this->mLogItemCallback ) ) {
640 return call_user_func_array(
641 $this->mLogItemCallback,
656 return $this->reader->getAttribute( $attr ) ??
'';
667 if ( $this->reader->isEmptyElement ) {
671 while ( $this->reader->read() ) {
672 switch ( $this->reader->nodeType ) {
673 case XMLReader::TEXT:
674 case XMLReader::CDATA:
675 case XMLReader::SIGNIFICANT_WHITESPACE:
676 $buffer .= $this->reader->value;
678 case XMLReader::END_ELEMENT:
683 $this->reader->close();
694 $this->syntaxCheckXML();
700 $oldDisable = @libxml_disable_entity_loader(
true );
702 $this->reader->read();
704 if ( $this->reader->localName !=
'mediawiki' ) {
706 @libxml_disable_entity_loader( $oldDisable );
707 $error = libxml_get_last_error();
709 throw new NormalizedException(
"XML error at line {line}: {message}", [
710 'line' => $error->line,
711 'message' => $error->message,
715 "Expected '<mediawiki>' tag, got '<{$this->reader->localName}>' tag."
719 $this->
debug(
"<mediawiki> tag is correct." );
721 $this->
debug(
"Starting primary dump processing loop." );
723 $keepReading = $this->reader->read();
726 while ( $keepReading ) {
727 $tag = $this->reader->localName;
728 if ( $this->pageOffset ) {
729 if ( $tag ===
'page' ) {
732 if ( $pageCount < $this->pageOffset ) {
733 $keepReading = $this->reader->next();
737 $type = $this->reader->nodeType;
739 if ( !$this->hookRunner->onImportHandleToplevelXMLTag( $this ) ) {
741 } elseif ( $tag ==
'mediawiki' &&
$type == XMLReader::END_ELEMENT ) {
743 } elseif ( $tag ==
'siteinfo' ) {
744 $this->handleSiteInfo();
745 } elseif ( $tag ==
'page' ) {
747 } elseif ( $tag ==
'logitem' ) {
748 $this->handleLogItem();
749 } elseif ( $tag !=
'#text' ) {
750 $this->
warn(
"Unhandled top-level XML tag $tag" );
756 $keepReading = $this->reader->next();
758 $this->
debug(
"Skip" );
760 $keepReading = $this->reader->read();
765 @libxml_disable_entity_loader( $oldDisable );
766 $this->reader->close();
772 private function handleSiteInfo() {
773 $this->debug(
"Enter site info handler." );
777 $normalFields = [
'sitename',
'base',
'generator',
'case' ];
779 while ( $this->reader->read() ) {
780 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
781 $this->reader->localName ==
'siteinfo' ) {
785 $tag = $this->reader->localName;
787 if ( $tag ==
'namespace' ) {
790 } elseif ( in_array( $tag, $normalFields ) ) {
795 $siteInfo[
'_namespaces'] = $this->foreignNamespaces;
796 $this->siteInfoCallback( $siteInfo );
799 private function handleLogItem() {
800 $this->
debug(
"Enter log item handler." );
804 $normalFields = [
'id',
'comment',
'type',
'action',
'timestamp',
805 'logtitle',
'params' ];
807 while ( $this->reader->read() ) {
808 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
809 $this->reader->localName ==
'logitem' ) {
813 $tag = $this->reader->localName;
815 if ( !$this->hookRunner->onImportHandleLogItemXMLTag( $this, $logInfo ) ) {
817 } elseif ( in_array( $tag, $normalFields ) ) {
819 } elseif ( $tag ==
'contributor' ) {
820 $logInfo[
'contributor'] = $this->handleContributor();
821 } elseif ( $tag !=
'#text' ) {
822 $this->
warn(
"Unhandled log-item XML tag $tag" );
826 $this->processLogItem( $logInfo );
833 private function processLogItem( $logInfo ) {
836 if ( isset( $logInfo[
'id'] ) ) {
837 $revision->setID( $logInfo[
'id'] );
839 $revision->setType( $logInfo[
'type'] );
840 $revision->setAction( $logInfo[
'action'] );
841 if ( isset( $logInfo[
'timestamp'] ) ) {
842 $revision->setTimestamp( $logInfo[
'timestamp'] );
844 if ( isset( $logInfo[
'params'] ) ) {
845 $revision->setParams( $logInfo[
'params'] );
847 if ( isset( $logInfo[
'logtitle'] ) ) {
850 $revision->setTitle( Title::newFromText( $logInfo[
'logtitle'] ) );
853 $revision->setNoUpdates( $this->mNoUpdates );
855 if ( isset( $logInfo[
'comment'] ) ) {
856 $revision->setComment( $logInfo[
'comment'] );
859 if ( isset( $logInfo[
'contributor'][
'username'] ) ) {
860 $revision->setUsername(
861 $this->externalUserNames->applyPrefix( $logInfo[
'contributor'][
'username'] )
863 } elseif ( isset( $logInfo[
'contributor'][
'ip'] ) ) {
864 $revision->setUserIP( $logInfo[
'contributor'][
'ip'] );
866 $revision->setUsername( $this->externalUserNames->addPrefix(
'Unknown user' ) );
869 return $this->logItemCallback( $revision );
872 private function handlePage() {
874 $this->
debug(
"Enter page handler." );
875 $pageInfo = [
'revisionCount' => 0,
'successfulRevisionCount' => 0 ];
878 $normalFields = [
'title',
'ns',
'id',
'redirect',
'restrictions' ];
883 while ( $skip ? $this->reader->next() : $this->reader->read() ) {
884 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
885 $this->reader->localName ==
'page' ) {
891 $tag = $this->reader->localName;
896 } elseif ( !$this->hookRunner->onImportHandlePageXMLTag( $this, $pageInfo ) ) {
898 } elseif ( in_array( $tag, $normalFields ) ) {
906 if ( $tag ==
'redirect' ) {
911 } elseif ( $tag ==
'revision' || $tag ==
'upload' ) {
913 $title = $this->processTitle( $pageInfo[
'title'],
914 $pageInfo[
'ns'] ??
null );
917 if ( is_array(
$title ) ) {
919 [ $pageInfo[
'_title'], $foreignTitle ] =
$title;
927 if ( $tag ==
'revision' ) {
928 $this->handleRevision( $pageInfo );
930 $this->handleUpload( $pageInfo );
933 } elseif ( $tag !=
'#text' ) {
934 $this->
warn(
"Unhandled page XML tag $tag" );
944 if ( array_key_exists(
'_title', $pageInfo ) ) {
946 $title = $pageInfo[
'_title'];
947 $this->pageOutCallback(
951 $pageInfo[
'revisionCount'],
952 $pageInfo[
'successfulRevisionCount'],
961 private function handleRevision( &$pageInfo ) {
962 $this->
debug(
"Enter revision handler" );
965 $normalFields = [
'id',
'parentid',
'timestamp',
'comment',
'minor',
'origin',
966 'model',
'format',
'text',
'sha1' ];
970 while ( $skip ? $this->reader->next() : $this->reader->read() ) {
971 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
972 $this->reader->localName ==
'revision' ) {
976 $tag = $this->reader->localName;
978 if ( !$this->hookRunner->onImportHandleRevisionXMLTag(
979 $this, $pageInfo, $revisionInfo )
982 } elseif ( in_array( $tag, $normalFields ) ) {
984 } elseif ( $tag ==
'content' ) {
986 $revisionInfo[$tag][] = $this->handleContent();
987 } elseif ( $tag ==
'contributor' ) {
988 $revisionInfo[
'contributor'] = $this->handleContributor();
989 } elseif ( $tag !=
'#text' ) {
990 $this->
warn(
"Unhandled revision XML tag $tag" );
995 $pageInfo[
'revisionCount']++;
996 if ( $this->processRevision( $pageInfo, $revisionInfo ) ) {
997 $pageInfo[
'successfulRevisionCount']++;
1001 private function handleContent() {
1002 $this->
debug(
"Enter content handler" );
1005 $normalFields = [
'role',
'origin',
'model',
'format',
'text' ];
1009 while ( $skip ? $this->reader->next() : $this->reader->read() ) {
1010 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
1011 $this->reader->localName ==
'content' ) {
1015 $tag = $this->reader->localName;
1017 if ( !$this->hookRunner->onImportHandleContentXMLTag(
1018 $this, $contentInfo )
1021 } elseif ( in_array( $tag, $normalFields ) ) {
1023 } elseif ( $tag !=
'#text' ) {
1024 $this->
warn(
"Unhandled content XML tag $tag" );
1029 return $contentInfo;
1040 private function makeContent(
Title $title, $revisionId, $contentInfo ) {
1041 $maxArticleSize = MediaWikiServices::getInstance()->getMainConfig()->get(
1042 MainConfigNames::MaxArticleSize );
1044 if ( !isset( $contentInfo[
'text'] ) ) {
1045 throw new MWException(
'Missing text field in import.' );
1052 if ( ( !isset( $contentInfo[
'model'] ) ||
1053 in_array( $contentInfo[
'model'], [
1061 strlen( $contentInfo[
'text'] ) > $maxArticleSize * 1024
1065 "the revision with ID $revisionId" :
1067 ) .
" exceeds the maximum allowable size ({$maxArticleSize} KiB)" );
1070 $role = $contentInfo[
'role'] ?? SlotRecord::MAIN;
1071 $model = $contentInfo[
'model'] ?? $this->getDefaultContentModel(
$title, $role );
1072 $handler = $this->getContentHandler( $model );
1074 $text = $handler->importTransform( $contentInfo[
'text'] );
1076 return $handler->unserializeContent( $text );
1085 private function processRevision( $pageInfo, $revisionInfo ) {
1088 $revId = $revisionInfo[
'id'] ?? 0;
1090 $revision->setID( $revisionInfo[
'id'] );
1093 $title = $pageInfo[
'_title'];
1094 $revision->setTitle(
$title );
1097 $revision->setContent( SlotRecord::MAIN,
$content );
1099 foreach ( $revisionInfo[
'content'] ?? [] as $slotInfo ) {
1100 if ( !isset( $slotInfo[
'role'] ) ) {
1101 throw new MWException(
"Missing role for imported slot." );
1105 $revision->setContent( $slotInfo[
'role'],
$content );
1107 $revision->setTimestamp( $revisionInfo[
'timestamp'] ??
wfTimestampNow() );
1109 if ( isset( $revisionInfo[
'comment'] ) ) {
1110 $revision->setComment( $revisionInfo[
'comment'] );
1113 if ( isset( $revisionInfo[
'minor'] ) ) {
1114 $revision->setMinor(
true );
1116 if ( isset( $revisionInfo[
'contributor'][
'username'] ) ) {
1117 $revision->setUsername(
1118 $this->externalUserNames->applyPrefix( $revisionInfo[
'contributor'][
'username'] )
1120 } elseif ( isset( $revisionInfo[
'contributor'][
'ip'] ) ) {
1121 $revision->setUserIP( $revisionInfo[
'contributor'][
'ip'] );
1123 $revision->setUsername( $this->externalUserNames->addPrefix(
'Unknown user' ) );
1125 if ( isset( $revisionInfo[
'sha1'] ) ) {
1126 $revision->setSha1Base36( $revisionInfo[
'sha1'] );
1128 $revision->setNoUpdates( $this->mNoUpdates );
1130 return $this->revisionCallback( $revision );
1137 private function handleUpload( &$pageInfo ) {
1138 $this->
debug(
"Enter upload handler" );
1141 $normalFields = [
'timestamp',
'comment',
'filename',
'text',
1142 'src',
'size',
'sha1base36',
'archivename',
'rel' ];
1146 while ( $skip ? $this->reader->next() : $this->reader->read() ) {
1147 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
1148 $this->reader->localName ==
'upload' ) {
1152 $tag = $this->reader->localName;
1154 if ( !$this->hookRunner->onImportHandleUploadXMLTag( $this, $pageInfo ) ) {
1156 } elseif ( in_array( $tag, $normalFields ) ) {
1158 } elseif ( $tag ==
'contributor' ) {
1159 $uploadInfo[
'contributor'] = $this->handleContributor();
1160 } elseif ( $tag ==
'contents' ) {
1162 $encoding = $this->reader->getAttribute(
'encoding' );
1163 if ( $encoding ===
'base64' ) {
1164 $uploadInfo[
'fileSrc'] = $this->dumpTemp( base64_decode( $contents ) );
1165 $uploadInfo[
'isTempSrc'] =
true;
1167 } elseif ( $tag !=
'#text' ) {
1168 $this->
warn(
"Unhandled upload XML tag $tag" );
1173 if ( $this->mImageBasePath && isset( $uploadInfo[
'rel'] ) ) {
1174 $path =
"{$this->mImageBasePath}/{$uploadInfo['rel']}";
1175 if ( file_exists(
$path ) ) {
1176 $uploadInfo[
'fileSrc'] =
$path;
1177 $uploadInfo[
'isTempSrc'] =
false;
1181 if ( $this->mImportUploads ) {
1182 return $this->processUpload( $pageInfo, $uploadInfo );
1190 private function dumpTemp( $contents ) {
1191 $filename = tempnam(
wfTempDir(),
'importupload' );
1192 file_put_contents( $filename, $contents );
1201 private function processUpload( $pageInfo, $uploadInfo ) {
1203 $revId = $pageInfo[
'id'];
1204 $title = $pageInfo[
'_title'];
1206 $uploadInfo[
'text'] = $uploadInfo[
'text'] ??
'';
1209 $revision->setTitle(
$title );
1210 $revision->setID( $revId );
1211 $revision->setTimestamp( $uploadInfo[
'timestamp'] );
1212 $revision->setContent( SlotRecord::MAIN,
$content );
1213 $revision->setFilename( $uploadInfo[
'filename'] );
1214 if ( isset( $uploadInfo[
'archivename'] ) ) {
1215 $revision->setArchiveName( $uploadInfo[
'archivename'] );
1217 $revision->setSrc( $uploadInfo[
'src'] );
1218 if ( isset( $uploadInfo[
'fileSrc'] ) ) {
1219 $revision->setFileSrc( $uploadInfo[
'fileSrc'],
1220 !empty( $uploadInfo[
'isTempSrc'] )
1223 if ( isset( $uploadInfo[
'sha1base36'] ) ) {
1224 $revision->setSha1Base36( $uploadInfo[
'sha1base36'] );
1226 $revision->setSize( intval( $uploadInfo[
'size'] ) );
1227 $revision->setComment( $uploadInfo[
'comment'] );
1229 if ( isset( $uploadInfo[
'contributor'][
'username'] ) ) {
1230 $revision->setUsername(
1231 $this->externalUserNames->applyPrefix( $uploadInfo[
'contributor'][
'username'] )
1233 } elseif ( isset( $uploadInfo[
'contributor'][
'ip'] ) ) {
1234 $revision->setUserIP( $uploadInfo[
'contributor'][
'ip'] );
1236 $revision->setNoUpdates( $this->mNoUpdates );
1238 return call_user_func( $this->mUploadCallback, $revision );
1244 private function handleContributor() {
1245 $this->
debug(
"Enter contributor handler." );
1247 if ( $this->reader->isEmptyElement ) {
1251 $fields = [
'id',
'ip',
'username' ];
1254 while ( $this->reader->read() ) {
1255 if ( $this->reader->nodeType == XMLReader::END_ELEMENT &&
1256 $this->reader->localName ==
'contributor' ) {
1260 $tag = $this->reader->localName;
1262 if ( in_array( $tag, $fields ) ) {
1275 private function processTitle( $text, $ns =
null ) {
1276 if ( $this->foreignNamespaces ===
null ) {
1278 $this->contentLanguage
1282 $this->foreignNamespaces );
1285 $foreignTitle = $foreignTitleFactory->createForeignTitle( $text,
1288 $title = $this->importTitleFactory->createTitleFromForeignTitle(
1291 $commandLineMode = $this->config->get(
'CommandLineMode' );
1293 # Invalid page title? Ignore the page
1294 $this->
notice(
'import-error-invalid', $foreignTitle->getFullText() );
1296 } elseif (
$title->isExternal() ) {
1297 $this->
notice(
'import-error-interwiki',
$title->getPrefixedText() );
1299 } elseif ( !
$title->canExist() ) {
1300 $this->
notice(
'import-error-special',
$title->getPrefixedText() );
1302 } elseif ( !$commandLineMode ) {
1305 if ( !$this->permissionManager->userCan(
'edit', $user,
$title ) ) {
1306 # Do not import if the importing wiki user cannot edit this page
1307 $this->
notice(
'import-error-edit',
$title->getPrefixedText() );
1313 return [
$title, $foreignTitle ];
1320 private function getContentHandler( $model ) {
1321 return $this->contentHandlerFactory->getContentHandler( $model );
1330 private function getDefaultContentModel(
$title, $role ) {
1331 return $this->slotRoleRegistry
1332 ->getRoleHandler( $role )
1333 ->getDefaultModel(
$title );
1340 private function openReader() {
1344 $oldDisable = @libxml_disable_entity_loader(
false );
1346 if ( PHP_VERSION_ID >= 80000 ) {
1348 $reader = XMLReader::open(
1349 'uploadsource://' . $this->sourceAdapterId,
null, LIBXML_PARSEHUGE );
1350 if ( $reader instanceof XMLReader ) {
1351 $this->reader = $reader;
1358 $this->reader =
new XMLReader;
1359 $status = $this->reader->open(
1360 'uploadsource://' . $this->sourceAdapterId,
null, LIBXML_PARSEHUGE );
1363 $error = libxml_get_last_error();
1365 @libxml_disable_entity_loader( $oldDisable );
1367 'Encountered an internal error while initializing WikiImporter object: ' . $error->message
1371 @libxml_disable_entity_loader( $oldDisable );
1377 private function syntaxCheckXML() {
1381 AtEase::suppressWarnings();
1382 $oldDisable = libxml_disable_entity_loader(
false );
1384 while ( $this->reader->read() );
1385 $error = libxml_get_last_error();
1387 $errorMessage =
'XML error at line ' . $error->line .
': ' . $error->message;
1388 wfDebug( __METHOD__ .
': Invalid xml found - ' . $errorMessage );
1392 libxml_disable_entity_loader( $oldDisable );
1393 AtEase::restoreWarnings();
1394 $this->reader->close();
1399 $this->openReader();