Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 99
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
PurgeReviewablePages
0.00% covered (danger)
0.00%
0 / 93
0.00% covered (danger)
0.00%
0 / 4
506
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 listReviewablePages
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 1
90
 purgeReviewablePages
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
56
1<?php
2/**
3 * @ingroup Maintenance
4 */
5
6use MediaWiki\MainConfigNames;
7use MediaWiki\Maintenance\Maintenance;
8use MediaWiki\Title\Title;
9
10if ( getenv( 'MW_INSTALL_PATH' ) ) {
11    $IP = getenv( 'MW_INSTALL_PATH' );
12} else {
13    $IP = __DIR__ . '/../../..';
14}
15
16require_once "$IP/maintenance/Maintenance.php";
17
18class PurgeReviewablePages extends Maintenance {
19
20    public function __construct() {
21        parent::__construct();
22        $this->addDescription( "Use to purge CDN/file cache for all reviewable pages" );
23        $this->addOption( 'makelist',
24            "Build the list of reviewable pages to pagesToPurge.list" );
25        $this->addOption( 'purgelist',
26            "Purge the list of pages in pagesToPurge.list" );
27        $this->setBatchSize( 1000 );
28        $this->requireExtension( 'FlaggedRevs' );
29    }
30
31    /**
32     * @inheritDoc
33     */
34    public function execute() {
35        $fileName = "pagesToPurge.list";
36        // Build the list file...
37        if ( $this->getOption( 'makelist' ) ) {
38            $fileHandle = fopen( $fileName, 'w+' );
39            if ( !$fileHandle ) {
40                $this->fatalError( "Can't open file to create purge list." );
41            }
42            $this->listReviewablePages( $fileHandle );
43            fclose( $fileHandle );
44        // Purge pages on the list file...
45        } elseif ( $this->getOption( 'purgelist' ) ) {
46            $fileHandle = fopen( $fileName, 'r' );
47            if ( !$fileHandle ) {
48                $this->fatalError( "Can't open file to read purge list." );
49            }
50            $this->purgeReviewablePages( $fileHandle );
51            fclose( $fileHandle );
52        } else {
53            $this->fatalError( "No purge list action specified." );
54        }
55    }
56
57    /**
58     * @param resource $fileHandle
59     */
60    private function listReviewablePages( $fileHandle ) {
61        $this->output( "Building list of all reviewable pages to purge ...\n" );
62        $config = $this->getConfig();
63        $reviewNamespaces = $config->get( 'FlaggedRevsNamespaces' );
64        if ( !$config->get( MainConfigNames::UseCdn ) && !$config->get( MainConfigNames::UseFileCache ) ) {
65            $this->output( "CDN/file cache not enabled ... nothing to purge.\n" );
66            return;
67        } elseif ( !$reviewNamespaces ) {
68            $this->output( "There are no reviewable namespaces ... nothing to purge.\n" );
69            return;
70        }
71
72        $db = $this->getPrimaryDB();
73
74        $start = $db->newSelectQueryBuilder()
75            ->select( 'MIN(page_id)' )
76            ->from( 'page' )
77            ->caller( __METHOD__ )
78            ->fetchField();
79        $end = $db->newSelectQueryBuilder()
80            ->select( 'MAX(page_id)' )
81            ->from( 'page' )
82            ->caller( __METHOD__ )
83            ->fetchField();
84        if ( $start === null || $end === null ) {
85            $this->output( "... page table seems to be empty.\n" );
86            return;
87        }
88        # Do remaining chunk
89        $end += $this->mBatchSize - 1;
90        $blockStart = (int)$start;
91        $blockEnd = (int)( $start + $this->mBatchSize - 1 );
92
93        $count = 0;
94        while ( $blockEnd <= $end ) {
95            $this->output( "... doing page_id from $blockStart to $blockEnd\n" );
96            $res = $db->newSelectQueryBuilder()
97                ->select( '*' )
98                ->from( 'page' )
99                ->where( [
100                    $db->expr( 'page_id', '>=', $blockEnd ),
101                    $db->expr( 'page_id', '<=', $blockEnd ),
102                    'page_namespace' => $reviewNamespaces,
103                ] )
104                ->caller( __METHOD__ )
105                ->fetchResultSet();
106            # Go through and append each purgeable page...
107            foreach ( $res as $row ) {
108                $title = Title::newFromRow( $row );
109                $fa = FlaggableWikiPage::getTitleInstance( $title );
110                if ( $fa->isReviewable() ) {
111                    # Need to purge this page - add to list
112                    fwrite( $fileHandle, $title->getPrefixedDBkey() . "\n" );
113                    $count++;
114                }
115            }
116            $blockStart += $this->mBatchSize - 1;
117            $blockEnd += $this->mBatchSize - 1;
118            $this->waitForReplication();
119        }
120        $this->output( "List of reviewable pages to purge complete ... {$count} pages\n" );
121    }
122
123    /**
124     * @param resource $fileHandle
125     */
126    private function purgeReviewablePages( $fileHandle ) {
127        $this->output( "Purging CDN cache for list of pages to purge ...\n" );
128        $config = $this->getConfig();
129        if ( !$config->get( MainConfigNames::UseCdn ) && !$config->get( MainConfigNames::UseFileCache ) ) {
130            $this->output( "CDN/file cache not enabled ... nothing to purge.\n" );
131            return;
132        }
133
134        $services = $this->getServiceContainer();
135        $htmlCache = $services->getHtmlCacheUpdater();
136
137        $count = 0;
138        while ( !feof( $fileHandle ) ) {
139            $dbKey = trim( fgets( $fileHandle ) );
140            if ( $dbKey == '' ) {
141                continue; // last line?
142            }
143            $title = Title::newFromDBkey( $dbKey );
144            if ( $title ) {
145                // send PURGE
146                $htmlCache->purgeTitleUrls( $title, $htmlCache::PURGE_INTENT_TXROUND_REFLECTED );
147                // purge poor-mans's CDN
148                HTMLFileCache::clearFileCache( $title );
149                $this->output( "... $dbKey\n" );
150
151                $count++;
152                if ( ( $count % $this->mBatchSize ) == 0 ) {
153                    $this->waitForReplication();
154                }
155            } else {
156                $this->output( "Invalid title - cannot purge: $dbKey\n" );
157            }
158        }
159        $this->output( "CDN/file cache purge of page list complete ... {$count} pages\n" );
160    }
161}
162
163$maintClass = PurgeReviewablePages::class;
164require_once RUN_MAINTENANCE_IF_MAIN;