ApiQueryImageInfo.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <?php
  2. /*
  3. * Created on July 6, 2007
  4. *
  5. * API for MediaWiki 1.8+
  6. *
  7. * Copyright (C) 2006 Yuri Astrakhan <Firstname><Lastname>@gmail.com
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, write to the Free Software Foundation, Inc.,
  21. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22. * http://www.gnu.org/copyleft/gpl.html
  23. */
  24. if (!defined('MEDIAWIKI')) {
  25. // Eclipse helper - will be ignored in production
  26. require_once ('ApiQueryBase.php');
  27. }
  28. /**
  29. * A query action to get image information and upload history.
  30. *
  31. * @ingroup API
  32. */
  33. class ApiQueryImageInfo extends ApiQueryBase {
  34. public function __construct($query, $moduleName) {
  35. parent :: __construct($query, $moduleName, 'ii');
  36. }
  37. public function execute() {
  38. $params = $this->extractRequestParams();
  39. $prop = array_flip($params['prop']);
  40. if($params['urlheight'] != -1 && $params['urlwidth'] == -1)
  41. $this->dieUsage("iiurlheight cannot be used without iiurlwidth", 'iiurlwidth');
  42. if ( $params['urlwidth'] != -1 ) {
  43. $scale = array();
  44. $scale['width'] = $params['urlwidth'];
  45. $scale['height'] = $params['urlheight'];
  46. } else {
  47. $scale = null;
  48. }
  49. $pageIds = $this->getPageSet()->getAllTitlesByNamespace();
  50. if ( !empty( $pageIds[NS_FILE] ) ) {
  51. $titles = array_keys($pageIds[NS_FILE]);
  52. asort($titles); // Ensure the order is always the same
  53. $skip = false;
  54. if(!is_null($params['continue']))
  55. {
  56. $skip = true;
  57. $cont = explode('|', $params['continue']);
  58. if(count($cont) != 2)
  59. $this->dieUsage("Invalid continue param. You should pass the original " .
  60. "value returned by the previous query", "_badcontinue");
  61. $fromTitle = strval($cont[0]);
  62. $fromTimestamp = $cont[1];
  63. // Filter out any titles before $fromTitle
  64. foreach($titles as $key => $title)
  65. if($title < $fromTitle)
  66. unset($titles[$key]);
  67. else
  68. break;
  69. }
  70. $result = $this->getResult();
  71. $images = RepoGroup::singleton()->findFiles( $titles );
  72. foreach ( $images as $img ) {
  73. $start = $skip ? $fromTimestamp : $params['start'];
  74. $pageId = $pageIds[NS_IMAGE][ $img->getOriginalTitle()->getDBkey() ];
  75. $fit = $result->addValue(
  76. array('query', 'pages', intval($pageId)),
  77. 'imagerepository', $img->getRepoName()
  78. );
  79. if(!$fit)
  80. {
  81. if(count($pageIds[NS_IMAGE]) == 1)
  82. # The user is screwed. imageinfo can't be solely
  83. # responsible for exceeding the limit in this case,
  84. # so set a query-continue that just returns the same
  85. # thing again. When the violating queries have been
  86. # out-continued, the result will get through
  87. $this->setContinueEnumParameter('start',
  88. wfTimestamp(TS_ISO_8601, $img->getTimestamp()));
  89. else
  90. $this->setContinueEnumParameter('continue',
  91. $this->getContinueStr($img));
  92. break;
  93. }
  94. // Get information about the current version first
  95. // Check that the current version is within the start-end boundaries
  96. $gotOne = false;
  97. if((is_null($start) || $img->getTimestamp() <= $start) &&
  98. (is_null($params['end']) || $img->getTimestamp() >= $params['end'])) {
  99. $gotOne = true;
  100. $fit = $this->addPageSubItem($pageId,
  101. self::getInfo( $img, $prop, $result, $scale));
  102. if(!$fit)
  103. {
  104. if(count($pageIds[NS_IMAGE]) == 1)
  105. # See the 'the user is screwed' comment above
  106. $this->setContinueEnumParameter('start',
  107. wfTimestamp(TS_ISO_8601, $img->getTimestamp()));
  108. else
  109. $this->setContinueEnumParameter('continue',
  110. $this->getContinueStr($img));
  111. break;
  112. }
  113. }
  114. // Now get the old revisions
  115. // Get one more to facilitate query-continue functionality
  116. $count = ($gotOne ? 1 : 0);
  117. $oldies = $img->getHistory($params['limit'] - $count + 1, $start, $params['end']);
  118. foreach($oldies as $oldie) {
  119. if(++$count > $params['limit']) {
  120. // We've reached the extra one which shows that there are additional pages to be had. Stop here...
  121. // Only set a query-continue if there was only one title
  122. if(count($pageIds[NS_FILE]) == 1)
  123. {
  124. $this->setContinueEnumParameter('start',
  125. wfTimestamp(TS_ISO_8601, $oldie->getTimestamp()));
  126. }
  127. break;
  128. }
  129. $fit = $this->addPageSubItem($pageId,
  130. self::getInfo($oldie, $prop, $result));
  131. if(!$fit)
  132. {
  133. if(count($pageIds[NS_IMAGE]) == 1)
  134. $this->setContinueEnumParameter('start',
  135. wfTimestamp(TS_ISO_8601, $oldie->getTimestamp()));
  136. else
  137. $this->setContinueEnumParameter('continue',
  138. $this->getContinueStr($oldie));
  139. break;
  140. }
  141. }
  142. if(!$fit)
  143. break;
  144. $skip = false;
  145. }
  146. $missing = array_diff( array_keys( $pageIds[NS_FILE] ), array_keys( $images ) );
  147. foreach ($missing as $title) {
  148. $result->addValue(
  149. array('query', 'pages', intval($pageIds[NS_FILE][$title])),
  150. 'imagerepository', ''
  151. );
  152. // The above can't fail because it doesn't increase the result size
  153. }
  154. }
  155. }
  156. /**
  157. * Get result information for an image revision
  158. * @param File f The image
  159. * @return array Result array
  160. */
  161. static function getInfo($file, $prop, $result, $scale = null) {
  162. $vals = array();
  163. if( isset( $prop['timestamp'] ) )
  164. $vals['timestamp'] = wfTimestamp(TS_ISO_8601, $file->getTimestamp());
  165. if( isset( $prop['user'] ) ) {
  166. $vals['user'] = $file->getUser();
  167. if( !$file->getUser( 'id' ) )
  168. $vals['anon'] = '';
  169. }
  170. if( isset( $prop['size'] ) || isset( $prop['dimensions'] ) ) {
  171. $vals['size'] = intval( $file->getSize() );
  172. $vals['width'] = intval( $file->getWidth() );
  173. $vals['height'] = intval( $file->getHeight() );
  174. }
  175. if( isset( $prop['url'] ) ) {
  176. if( !is_null( $scale ) && !$file->isOld() ) {
  177. $mto = $file->transform( array( 'width' => $scale['width'], 'height' => $scale['height'] ) );
  178. if( $mto && !$mto->isError() )
  179. {
  180. $vals['thumburl'] = $mto->getUrl();
  181. $vals['thumbwidth'] = intval( $mto->getWidth() );
  182. $vals['thumbheight'] = intval( $mto->getHeight() );
  183. }
  184. }
  185. $vals['url'] = $file->getFullURL();
  186. $vals['descriptionurl'] = wfExpandUrl( $file->getDescriptionUrl() );
  187. }
  188. if( isset( $prop['comment'] ) )
  189. $vals['comment'] = $file->getDescription();
  190. if( isset( $prop['sha1'] ) )
  191. $vals['sha1'] = wfBaseConvert( $file->getSha1(), 36, 16, 40 );
  192. if( isset( $prop['metadata'] ) ) {
  193. $metadata = $file->getMetadata();
  194. $vals['metadata'] = $metadata ? self::processMetaData( unserialize( $metadata ), $result ) : null;
  195. }
  196. if( isset( $prop['mime'] ) )
  197. $vals['mime'] = $file->getMimeType();
  198. if( isset( $prop['archivename'] ) && $file->isOld() )
  199. $vals['archivename'] = $file->getArchiveName();
  200. if( isset( $prop['bitdepth'] ) )
  201. $vals['bitdepth'] = $file->getBitDepth();
  202. return $vals;
  203. }
  204. public static function processMetaData($metadata, $result)
  205. {
  206. $retval = array();
  207. if ( is_array( $metadata ) ) {
  208. foreach($metadata as $key => $value)
  209. {
  210. $r = array('name' => $key);
  211. if(is_array($value))
  212. $r['value'] = self::processMetaData($value, $result);
  213. else
  214. $r['value'] = $value;
  215. $retval[] = $r;
  216. }
  217. }
  218. $result->setIndexedTagName($retval, 'metadata');
  219. return $retval;
  220. }
  221. private function getContinueStr($img)
  222. {
  223. return $img->getOriginalTitle()->getText() .
  224. '|' . $img->getTimestamp();
  225. }
  226. public function getAllowedParams() {
  227. return array (
  228. 'prop' => array (
  229. ApiBase :: PARAM_ISMULTI => true,
  230. ApiBase :: PARAM_DFLT => 'timestamp|user',
  231. ApiBase :: PARAM_TYPE => array (
  232. 'timestamp',
  233. 'user',
  234. 'comment',
  235. 'url',
  236. 'size',
  237. 'sha1',
  238. 'mime',
  239. 'metadata',
  240. 'archivename',
  241. 'bitdepth',
  242. )
  243. ),
  244. 'limit' => array(
  245. ApiBase :: PARAM_TYPE => 'limit',
  246. ApiBase :: PARAM_DFLT => 1,
  247. ApiBase :: PARAM_MIN => 1,
  248. ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
  249. ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
  250. ),
  251. 'start' => array(
  252. ApiBase :: PARAM_TYPE => 'timestamp'
  253. ),
  254. 'end' => array(
  255. ApiBase :: PARAM_TYPE => 'timestamp'
  256. ),
  257. 'urlwidth' => array(
  258. ApiBase :: PARAM_TYPE => 'integer',
  259. ApiBase :: PARAM_DFLT => -1
  260. ),
  261. 'urlheight' => array(
  262. ApiBase :: PARAM_TYPE => 'integer',
  263. ApiBase :: PARAM_DFLT => -1
  264. ),
  265. 'continue' => null,
  266. );
  267. }
  268. public function getParamDescription() {
  269. return array (
  270. 'prop' => 'What image information to get.',
  271. 'limit' => 'How many image revisions to return',
  272. 'start' => 'Timestamp to start listing from',
  273. 'end' => 'Timestamp to stop listing at',
  274. 'urlwidth' => array('If iiprop=url is set, a URL to an image scaled to this width will be returned.',
  275. 'Only the current version of the image can be scaled.'),
  276. 'urlheight' => 'Similar to iiurlwidth. Cannot be used without iiurlwidth',
  277. 'continue' => 'When more results are available, use this to continue',
  278. );
  279. }
  280. public function getDescription() {
  281. return array (
  282. 'Returns image information and upload history'
  283. );
  284. }
  285. protected function getExamples() {
  286. return array (
  287. 'api.php?action=query&titles=File:Albert%20Einstein%20Head.jpg&prop=imageinfo',
  288. 'api.php?action=query&titles=File:Test.jpg&prop=imageinfo&iilimit=50&iiend=20071231235959&iiprop=timestamp|user|url',
  289. );
  290. }
  291. public function getVersion() {
  292. return __CLASS__ . ': $Id: ApiQueryImageInfo.php 50097 2009-05-01 06:35:57Z tstarling $';
  293. }
  294. }