1<?php
2/**
3 * Dump a the list of files uploaded, for feeding to tar or similar.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup Maintenance
22 */
23
24use MediaWiki\MediaWikiServices;
25
26require_once __DIR__ . '/Maintenance.php';
27
28/**
29 * Maintenance script to dump a the list of files uploaded,
30 * for feeding to tar or similar.
31 *
32 * @ingroup Maintenance
33 */
34class DumpUploads extends Maintenance {
35	/** @var string */
36	private $mBasePath;
37
38	public function __construct() {
39		parent::__construct();
40		$this->addDescription( 'Generates list of uploaded files which can be fed to tar or similar.
41By default, outputs relative paths against the parent directory of $wgUploadDirectory.' );
42		$this->addOption( 'base', 'Set base relative path instead of wiki include root', false, true );
43		$this->addOption( 'local', 'List all local files, used or not. No shared files included' );
44		$this->addOption( 'used', 'Skip local images that are not used' );
45		$this->addOption( 'shared', 'Include images used from shared repository' );
46	}
47
48	public function execute() {
49		global $IP;
50		$this->mBasePath = $this->getOption( 'base', $IP );
51		$shared = false;
52		$sharedSupplement = false;
53
54		if ( $this->hasOption( 'shared' ) ) {
55			if ( $this->hasOption( 'used' ) ) {
56				// Include shared-repo files in the used check
57				$shared = true;
58			} else {
59				// Grab all local *plus* used shared
60				$sharedSupplement = true;
61			}
62		}
63
64		if ( $this->hasOption( 'local' ) ) {
65			$this->fetchLocal( $shared );
66		} elseif ( $this->hasOption( 'used' ) ) {
67			$this->fetchUsed( $shared );
68		} else {
69			$this->fetchLocal( $shared );
70		}
71
72		if ( $sharedSupplement ) {
73			$this->fetchUsed( true );
74		}
75	}
76
77	/**
78	 * Fetch a list of used images from a particular image source.
79	 *
80	 * @param bool $shared True to pass shared-dir settings to hash func
81	 */
82	private function fetchUsed( $shared ) {
83		$dbr = $this->getDB( DB_REPLICA );
84		$image = $dbr->tableName( 'image' );
85		$imagelinks = $dbr->tableName( 'imagelinks' );
86
87		$sql = "SELECT DISTINCT il_to, img_name
88			FROM $imagelinks
89			LEFT JOIN $image
90			ON il_to=img_name";
91		$result = $dbr->query( $sql, __METHOD__ );
92
93		foreach ( $result as $row ) {
94			$this->outputItem( $row->il_to, $shared );
95		}
96	}
97
98	/**
99	 * Fetch a list of all images from a particular image source.
100	 *
101	 * @param bool $shared True to pass shared-dir settings to hash func
102	 */
103	private function fetchLocal( $shared ) {
104		$dbr = $this->getDB( DB_REPLICA );
105		$result = $dbr->select( 'image',
106			[ 'img_name' ],
107			'',
108			__METHOD__ );
109
110		foreach ( $result as $row ) {
111			$this->outputItem( $row->img_name, $shared );
112		}
113	}
114
115	private function outputItem( $name, $shared ) {
116		$file = MediaWikiServices::getInstance()->getRepoGroup()->findFile( $name );
117		if ( $file && $this->filterItem( $file, $shared ) ) {
118			$filename = $file->getLocalRefPath();
119			$rel = wfRelativePath( $filename, $this->mBasePath );
120			$this->output( "$rel\n" );
121		} else {
122			wfDebug( __METHOD__ . ": base file? $name" );
123		}
124	}
125
126	private function filterItem( $file, $shared ) {
127		return $shared || $file->isLocal();
128	}
129}
130
131$maintClass = DumpUploads::class;
132require_once RUN_MAINTENANCE_IF_MAIN;
133