Merge "(bug 19195) Make user IDs more readily available with the API"
[lhc/web/wiklou.git] / includes / filerepo / file / ForeignAPIFile.php
1 <?php
2 /**
3 * Foreign file accessible through api.php requests.
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 FileAbstraction
22 */
23
24 /**
25 * Foreign file accessible through api.php requests.
26 * Very hacky and inefficient, do not use :D
27 *
28 * @ingroup FileAbstraction
29 */
30 class ForeignAPIFile extends File {
31 private $mExists;
32
33 protected $repoClass = 'ForeignApiRepo';
34
35 /**
36 * @param $title
37 * @param $repo ForeignApiRepo
38 * @param $info
39 * @param bool $exists
40 */
41 function __construct( $title, $repo, $info, $exists = false ) {
42 parent::__construct( $title, $repo );
43
44 $this->mInfo = $info;
45 $this->mExists = $exists;
46
47 $this->assertRepoDefined();
48 }
49
50 /**
51 * @param $title Title
52 * @param $repo ForeignApiRepo
53 * @return ForeignAPIFile|null
54 */
55 static function newFromTitle( Title $title, $repo ) {
56 $data = $repo->fetchImageQuery( array(
57 'titles' => 'File:' . $title->getDBKey(),
58 'iiprop' => self::getProps(),
59 'prop' => 'imageinfo',
60 'iimetadataversion' => MediaHandler::getMetadataVersion()
61 ) );
62
63 $info = $repo->getImageInfo( $data );
64
65 if( $info ) {
66 $lastRedirect = isset( $data['query']['redirects'] )
67 ? count( $data['query']['redirects'] ) - 1
68 : -1;
69 if( $lastRedirect >= 0 ) {
70 $newtitle = Title::newFromText( $data['query']['redirects'][$lastRedirect]['to']);
71 $img = new self( $newtitle, $repo, $info, true );
72 if( $img ) {
73 $img->redirectedFrom( $title->getDBkey() );
74 }
75 } else {
76 $img = new self( $title, $repo, $info, true );
77 }
78 return $img;
79 } else {
80 return null;
81 }
82 }
83
84 /**
85 * Get the property string for iiprop and aiprop
86 * @return string
87 */
88 static function getProps() {
89 return 'timestamp|user|comment|url|size|sha1|metadata|mime';
90 }
91
92 // Dummy functions...
93 public function exists() {
94 return $this->mExists;
95 }
96
97 public function getPath() {
98 return false;
99 }
100
101 function transform( $params, $flags = 0 ) {
102 if( !$this->canRender() ) {
103 // show icon
104 return parent::transform( $params, $flags );
105 }
106
107 // Note, the this->canRender() check above implies
108 // that we have a handler, and it can do makeParamString.
109 $otherParams = $this->handler->makeParamString( $params );
110
111 $thumbUrl = $this->repo->getThumbUrlFromCache(
112 $this->getName(),
113 isset( $params['width'] ) ? $params['width'] : -1,
114 isset( $params['height'] ) ? $params['height'] : -1,
115 $otherParams );
116 return $this->handler->getTransform( $this, 'bogus', $thumbUrl, $params );
117 }
118
119 // Info we can get from API...
120 public function getWidth( $page = 1 ) {
121 return isset( $this->mInfo['width'] ) ? intval( $this->mInfo['width'] ) : 0;
122 }
123
124 /**
125 * @param $page int
126 * @return int
127 */
128 public function getHeight( $page = 1 ) {
129 return isset( $this->mInfo['height'] ) ? intval( $this->mInfo['height'] ) : 0;
130 }
131
132 public function getMetadata() {
133 if ( isset( $this->mInfo['metadata'] ) ) {
134 return serialize( self::parseMetadata( $this->mInfo['metadata'] ) );
135 }
136 return null;
137 }
138
139 public static function parseMetadata( $metadata ) {
140 if( !is_array( $metadata ) ) {
141 return $metadata;
142 }
143 $ret = array();
144 foreach( $metadata as $meta ) {
145 $ret[ $meta['name'] ] = self::parseMetadata( $meta['value'] );
146 }
147 return $ret;
148 }
149
150 public function getSize() {
151 return isset( $this->mInfo['size'] ) ? intval( $this->mInfo['size'] ) : null;
152 }
153
154 public function getUrl() {
155 return isset( $this->mInfo['url'] ) ? strval( $this->mInfo['url'] ) : null;
156 }
157
158 public function getUser( $method='text' ) {
159 return isset( $this->mInfo['user'] ) ? strval( $this->mInfo['user'] ) : null;
160 }
161
162 public function getDescription() {
163 return isset( $this->mInfo['comment'] ) ? strval( $this->mInfo['comment'] ) : null;
164 }
165
166 function getSha1() {
167 return isset( $this->mInfo['sha1'] )
168 ? wfBaseConvert( strval( $this->mInfo['sha1'] ), 16, 36, 31 )
169 : null;
170 }
171
172 function getTimestamp() {
173 return wfTimestamp( TS_MW,
174 isset( $this->mInfo['timestamp'] )
175 ? strval( $this->mInfo['timestamp'] )
176 : null
177 );
178 }
179
180 function getMimeType() {
181 if( !isset( $this->mInfo['mime'] ) ) {
182 $magic = MimeMagic::singleton();
183 $this->mInfo['mime'] = $magic->guessTypesForExtension( $this->getExtension() );
184 }
185 return $this->mInfo['mime'];
186 }
187
188 /// @todo FIXME: May guess wrong on file types that can be eg audio or video
189 function getMediaType() {
190 $magic = MimeMagic::singleton();
191 return $magic->getMediaType( null, $this->getMimeType() );
192 }
193
194 function getDescriptionUrl() {
195 return isset( $this->mInfo['descriptionurl'] )
196 ? $this->mInfo['descriptionurl']
197 : false;
198 }
199
200 /**
201 * Only useful if we're locally caching thumbs anyway...
202 * @return null|string
203 */
204 function getThumbPath( $suffix = '' ) {
205 if ( $this->repo->canCacheThumbs() ) {
206 $path = $this->repo->getZonePath('thumb') . '/' . $this->getHashPath( $this->getName() );
207 if ( $suffix ) {
208 $path = $path . $suffix . '/';
209 }
210 return $path;
211 } else {
212 return null;
213 }
214 }
215
216 function getThumbnails() {
217 $dir = $this->getThumbPath( $this->getName() );
218 $iter = $this->repo->getBackend()->getFileList( array( 'dir' => $dir ) );
219
220 $files = array();
221 foreach ( $iter as $file ) {
222 $files[] = $file;
223 }
224
225 return $files;
226 }
227
228 /**
229 * @see File::purgeCache()
230 */
231 function purgeCache( $options = array() ) {
232 $this->purgeThumbnails( $options );
233 $this->purgeDescriptionPage();
234 }
235
236 function purgeDescriptionPage() {
237 global $wgMemc, $wgContLang;
238
239 $url = $this->repo->getDescriptionRenderUrl( $this->getName(), $wgContLang->getCode() );
240 $key = $this->repo->getLocalCacheKey( 'RemoteFileDescription', 'url', md5($url) );
241
242 $wgMemc->delete( $key );
243 }
244
245 function purgeThumbnails( $options = array() ) {
246 global $wgMemc;
247
248 $key = $this->repo->getLocalCacheKey( 'ForeignAPIRepo', 'ThumbUrl', $this->getName() );
249 $wgMemc->delete( $key );
250
251 $files = $this->getThumbnails();
252 // Give media handler a chance to filter the purge list
253 $handler = $this->getHandler();
254 if ( $handler ) {
255 $handler->filterThumbnailPurgeList( $files, $options );
256 }
257
258 $dir = $this->getThumbPath( $this->getName() );
259 $purgeList = array();
260 foreach ( $files as $file ) {
261 $purgeList[] = "{$dir}{$file}";
262 }
263
264 # Delete the thumbnails
265 $this->repo->quickPurgeBatch( $purgeList );
266 # Clear out the thumbnail directory if empty
267 $this->repo->quickCleanDir( $dir );
268 }
269 }