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