52 parent::__construct(
'Export' );
53 $this->dbProvider = $dbProvider;
54 $this->wikiExporterFactory = $wikiExporterFactory;
55 $this->titleFormatter = $titleFormatter;
56 $this->linksMigration = $linksMigration;
65 $this->curonly =
true;
68 $this->templates = $request->getCheck(
'templates' );
70 $request->getIntOrNull(
'pagelink-depth' )
75 if ( $request->getCheck(
'addcat' ) ) {
76 $page = $request->getText(
'pages' );
77 $catname = $request->getText(
'catname' );
79 if ( $catname !==
'' && $catname !==
null && $catname !==
false ) {
80 $t = Title::makeTitleSafe(
NS_MAIN, $catname );
92 $page .= implode(
"\n", $catpages );
97 $page = $request->getText(
'pages' );
98 $nsindex = $request->getText(
'nsindex',
'' );
100 if ( strval( $nsindex ) !==
'' ) {
106 $page .=
"\n" . implode(
"\n", $nspages );
119 } elseif ( $request->wasPosted() && $par ==
'' ) {
122 LoggerFactory::getInstance(
'export' )->debug(
123 'Special:Export POST, dir: [{dir}], offset: [{offset}], limit: [{limit}]', [
124 'dir' => $request->getRawVal(
'dir' ),
125 'offset' => $request->getRawVal(
'offset' ),
126 'limit' => $request->getRawVal(
'limit' ),
129 $page = $request->getText(
'pages' );
130 $this->curonly = $request->getCheck(
'curonly' );
131 $rawOffset = $request->getVal(
'offset' );
140 $limit = $request->getInt(
'limit' );
141 $dir = $request->getVal(
'dir' );
145 'limit' => $maxHistory,
147 $historyCheck = $request->getCheck(
'history' );
149 if ( $this->curonly ) {
150 $history = WikiExporter::CURRENT;
151 } elseif ( !$historyCheck ) {
152 if ( $limit > 0 && ( $maxHistory == 0 || $limit < $maxHistory ) ) {
153 $history[
'limit'] = $limit;
156 if ( $offset !==
null ) {
157 $history[
'offset'] = $offset;
160 if ( strtolower( $dir ??
'' ) ==
'desc' ) {
161 $history[
'dir'] =
'desc';
170 $page = $request->getText(
'pages', $par ??
'' );
171 $historyCheck = $request->getCheck(
'history' );
173 if ( $historyCheck ) {
174 $history = WikiExporter::FULL;
176 $history = WikiExporter::CURRENT;
186 $history = WikiExporter::CURRENT;
189 $list_authors = $request->getCheck(
'listauthors' );
191 $list_authors =
false;
200 $request->response()->header(
'Content-type: application/xml; charset=utf-8' );
201 $request->response()->header(
'X-Robots-Tag: noindex,nofollow' );
202 ContentSecurityPolicy::sendRestrictiveHeader();
204 if ( $request->getCheck(
'wpDownload' ) ) {
208 $request->response()->header(
"Content-disposition: attachment;filename={$filename}" );
213 $this->
doExport( $page, $history, $list_authors, $exportall );
219 $out->addWikiMsg(
'exporttext' );
222 $categoryName = $request->getText(
'catname' );
227 $hideIf = $canExportAll ? [
'hide-if' => [
'===',
'exportall',
'1' ] ] : [];
231 'type' =>
'textwithbutton',
233 'horizontal-label' =>
true,
234 'label-message' =>
'export-addcattext',
235 'default' => $categoryName,
237 'buttontype' =>
'submit',
238 'buttonname' =>
'addcat',
239 'buttondefault' => $this->
msg(
'export-addcat' )->text(),
245 'type' =>
'namespaceselectwithbutton',
246 'default' => $nsindex,
247 'label-message' =>
'export-addnstext',
248 'horizontal-label' =>
true,
251 'cssclass' =>
'namespaceselector',
252 'buttontype' =>
'submit',
253 'buttonname' =>
'addns',
254 'buttondefault' => $this->
msg(
'export-addns' )->text(),
259 if ( $canExportAll ) {
263 'label-message' =>
'exportall',
264 'name' =>
'exportall',
266 'default' => $request->wasPosted() && $request->getCheck(
'exportall' ),
273 'class' => HTMLTextAreaField::class,
275 'label-message' =>
'export-manual',
286 'label-message' =>
'exportcuronly',
289 'default' => !$request->wasPosted() || $request->getCheck(
'curonly' ),
293 $out->addWikiMsg(
'exportnohistory' );
299 'label-message' =>
'export-templates',
300 'name' =>
'templates',
301 'id' =>
'wpExportTemplates',
302 'default' => $request->wasPosted() && $request->getCheck(
'templates' ),
308 'pagelink-depth' => [
310 'name' =>
'pagelink-depth',
311 'id' =>
'pagelink-depth',
312 'label-message' =>
'export-pagelinks',
322 'name' =>
'wpDownload',
323 'id' =>
'wpDownload',
324 'default' => !$request->wasPosted() || $request->getCheck(
'wpDownload' ),
325 'label-message' =>
'export-download',
333 'label-message' =>
'exportlistauthors',
334 'default' => $request->wasPosted() && $request->getCheck(
'listauthors' ),
335 'name' =>
'listauthors',
336 'id' =>
'listauthors',
341 $htmlForm = HTMLForm::factory(
'ooui', $formDescriptor, $this->
getContext() );
342 $htmlForm->setSubmitTextMsg(
'export-submit' );
343 $htmlForm->prepareForm()->displayForm(
false );
351 return $this->
getAuthority()->isAllowed(
'override-export-depth' );
363 protected function doExport( $page, $history, $list_authors, $exportall ) {
366 $history = WikiExporter::FULL;
371 foreach ( explode(
"\n", $page ) as $pageName ) {
372 $pageName = trim( $pageName );
373 $title = Title::newFromText( $pageName );
374 if ( $title && !$title->isExternal() && $title->getText() !==
'' ) {
376 $pageSet[$title->getPrefixedText()] =
true;
381 $inputPages = array_keys( $pageSet );
384 if ( $this->templates ) {
385 $pageSet = $this->
getTemplates( $inputPages, $pageSet );
387 $pageSet = $this->getExtraPages( $inputPages, $pageSet );
390 $pageSet = $this->
getPageLinks( $inputPages, $pageSet, $linkDepth );
393 $pages = array_keys( $pageSet );
396 foreach ( $pages as $k => $v ) {
397 $pages[$k] = str_replace(
' ',
'_', $v );
400 $pages = array_unique( $pages );
404 $db = $this->dbProvider->getReplicaDatabase();
406 $exporter = $this->wikiExporterFactory->getWikiExporter( $db, $history );
407 $exporter->list_authors = $list_authors;
408 $exporter->openStream();
411 $exporter->allPages();
414 foreach ( $pages as $page ) {
415 # T10824: Only export pages the user can read
416 $title = Title::newFromText( $page );
417 if ( $title ===
null ) {
422 if ( !$this->
getAuthority()->authorizeRead(
'read', $title ) ) {
427 $exporter->pageByTitle( $title );
431 $exporter->closeStream();
443 $dbr = $this->dbProvider->getReplicaDatabase( CategoryLinksTable::VIRTUAL_DOMAIN );
444 $res = $dbr->newSelectQueryBuilder()
445 ->select( [
'page_namespace',
'page_title' ] )
447 ->join(
'categorylinks',
null,
'cl_from=page_id' )
448 ->join(
'linktarget',
null,
'cl_target_id = lt_id' )
449 ->where( [
'lt_title' => $name,
'lt_namespace' =>
NS_CATEGORY ] )
451 ->caller( __METHOD__ )
456 foreach ( $res as $row ) {
457 $pages[] = Title::makeName( $row->page_namespace, $row->page_title );
470 $dbr = $this->dbProvider->getReplicaDatabase();
471 $res = $dbr->newSelectQueryBuilder()
472 ->select( [
'page_namespace',
'page_title' ] )
474 ->where( [
'page_namespace' => $nsindex ] )
476 ->caller( __METHOD__ )->fetchResultSet();
480 foreach ( $res as $row ) {
481 $pages[] = Title::makeName( $row->page_namespace, $row->page_title );
494 [ $nsField, $titleField ] = $this->linksMigration->getTitleFields(
'templatelinks' );
495 $queryInfo = $this->linksMigration->getQueryInfo(
'templatelinks' );
496 $dbr = $this->dbProvider->getReplicaDatabase( TemplateLinksTable::VIRTUAL_DOMAIN );
497 $queryBuilder = $dbr->newSelectQueryBuilder()
498 ->caller( __METHOD__ )
499 ->select( [
'namespace' => $nsField,
'title' => $titleField ] )
501 ->join(
'templatelinks',
null,
'page_id=tl_from' )
502 ->tables( array_diff( $queryInfo[
'tables'], [
'templatelinks' ] ) )
503 ->joinConds( $queryInfo[
'joins'] );
504 return $this->
getLinks( $inputPages, $pageSet, $queryBuilder );
513 private function getExtraPages( $inputPages, $pageSet ) {
515 $this->
getHookRunner()->onSpecialExportGetExtraPages( $inputPages, $extraPages );
516 foreach ( $extraPages as $extraPage ) {
517 $pageSet[$this->titleFormatter->getPrefixedText( $extraPage )] =
true;
528 if ( $depth ===
null || $depth < 0 ) {
534 if ( $depth > $maxLinkDepth ) {
535 return $maxLinkDepth;
545 return intval( min( $depth, 5 ) );
556 for ( ; $depth > 0; --$depth ) {
557 [ $nsField, $titleField ] = $this->linksMigration->getTitleFields(
'pagelinks' );
558 $queryInfo = $this->linksMigration->getQueryInfo(
'pagelinks' );
559 $dbr = $this->dbProvider->getReplicaDatabase( PageLinksTable::VIRTUAL_DOMAIN );
560 $queryBuilder = $dbr->newSelectQueryBuilder()
561 ->caller( __METHOD__ )
562 ->select( [
'namespace' => $nsField,
'title' => $titleField ] )
564 ->join(
'pagelinks',
null,
'page_id=pl_from' )
565 ->tables( array_diff( $queryInfo[
'tables'], [
'pagelinks' ] ) )
566 ->joinConds( $queryInfo[
'joins'] );
567 $pageSet = $this->
getLinks( $inputPages, $pageSet, $queryBuilder );
568 $inputPages = array_keys( $pageSet );
582 foreach ( $inputPages as $page ) {
583 $title = Title::newFromText( $page );
585 $pageSet[$title->getPrefixedText()] =
true;
588 $result = ( clone $queryBuilder )
590 'page_namespace' => $title->getNamespace(),
591 'page_title' => $title->getDBkey()
595 foreach ( $result as $row ) {
597 $pageSet[$template->getPrefixedText()] =
true;
612class_alias( SpecialExport::class,
'SpecialExport' );
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfResetOutputBuffers( $resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
A class containing constants representing the names of configuration variables.
const ExportMaxLinkDepth
Name constant for the ExportMaxLinkDepth setting, for use with Config::get()
const Sitename
Name constant for the Sitename setting, for use with Config::get()
const ExportAllowAll
Name constant for the ExportAllowAll setting, for use with Config::get()
const ExportMaxHistory
Name constant for the ExportMaxHistory setting, for use with Config::get()
const ExportAllowListContributors
Name constant for the ExportAllowListContributors setting, for use with Config::get()
const ExportPagelistLimit
Name constant for the ExportPagelistLimit setting, for use with Config::get()
const ExportFromNamespaces
Name constant for the ExportFromNamespaces setting, for use with Config::get()
const ExportAllowHistory
Name constant for the ExportAllowHistory setting, for use with Config::get()
Handle sending Content-Security-Policy headers.
Parent class for all special pages.
setHeaders()
Sets headers - this should be called from the execute() method of all derived classes!
getConfig()
Shortcut to get main config object.
getContext()
Gets the context this SpecialPage is executed in.
getRequest()
Get the WebRequest being used for this instance.
msg( $key,... $params)
Wrapper around wfMessage that sets the current context.
getOutput()
Get the OutputPage being used for this instance.
getAuthority()
Shortcut to get the Authority executing this instance.
outputHeader( $summaryMessageKey='')
Outputs a summary message on top of special pages By default the message key is the canonical name of...
addHelpLink( $to, $overrideBaseUrl=false)
Adds help link with an icon via page indicators.
Interface for objects (potentially) representing an editable wiki page.