2012-03-01 17:37:16 +00:00
< ? php
2015-11-16 14:59:34 +00:00
2013-07-07 18:58:56 +00:00
/**
* Expose image information for a page via a new prop = pageimages API .
2015-11-16 14:59:34 +00:00
*
* @ see https :// www . mediawiki . org / wiki / Extension : PageImages #API
*
* @ license WTFPL 2.0
2015-11-17 08:54:24 +00:00
* @ author Max Semenik
2015-11-16 14:59:34 +00:00
* @ author Ryan Kaldari
* @ author Yuvi Panda
* @ author Sam Smith
2013-07-07 18:58:56 +00:00
*/
2012-03-01 17:37:16 +00:00
class ApiQueryPageImages extends ApiQueryBase {
2015-11-16 14:59:34 +00:00
2016-11-10 00:02:00 +00:00
/**
* @ const API parameter value for free images
*/
const PARAM_LICENSE_FREE = 'free' ;
/**
* @ const API parameter value for images with any type of license
*/
const PARAM_LICENSE_ANY = 'any' ;
2016-03-07 08:47:51 +00:00
/**
* @ param ApiQuery $query
* @ param string $moduleName
*/
public function __construct ( ApiQuery $query , $moduleName ) {
2012-03-01 17:37:16 +00:00
parent :: __construct ( $query , $moduleName , 'pi' );
}
2015-10-02 08:58:54 +00:00
/**
* Gets the set of titles to get page images for .
*
* Note well that the set of titles comprises the set of " good " titles
* ( see { @ see ApiPageSet :: getGoodTitles }) union the set of " missing "
* titles in the File namespace that might correspond to foreign files .
* The latter are included because titles in the File namespace are
* expected to be found with { @ see wfFindFile } .
*
2015-10-31 01:30:18 +00:00
* @ return Title [] A map of page ID , which will be negative in the case
2015-10-02 08:58:54 +00:00
* of missing titles in the File namespace , to Title object
*/
protected function getTitles () {
$pageSet = $this -> getPageSet ();
$titles = $pageSet -> getGoodTitles ();
// T98791: We want foreign files to be treated like local files
// in #execute, so include the set of missing filespace pages,
// which were initially rejected in ApiPageSet#execute.
$missingTitles = $pageSet -> getMissingTitlesByNamespace ();
$missingFileTitles = isset ( $missingTitles [ NS_FILE ] )
? $missingTitles [ NS_FILE ]
2016-11-21 23:29:28 +00:00
: [];
2015-10-02 08:58:54 +00:00
// $titles is a map of ID to title object, which is ideal,
// whereas $missingFileTitles is a map of title text to ID.
$missingFileTitles = array_map ( function ( $text ) {
return Title :: newFromText ( $text , NS_FILE );
}, array_flip ( $missingFileTitles ) );
// N.B. We can't use array_merge here as it doesn't preserve
// keys.
foreach ( $missingFileTitles as $id => $title ) {
$titles [ $id ] = $title ;
2015-10-01 21:23:23 +00:00
}
2015-10-02 08:58:54 +00:00
return $titles ;
}
public function execute () {
2012-03-01 17:37:16 +00:00
$params = $this -> extractRequestParams ();
$prop = array_flip ( $params [ 'prop' ] );
2012-03-05 21:36:43 +00:00
if ( ! count ( $prop ) ) {
2016-12-02 00:49:13 +00:00
if ( is_callable ( [ $this , 'dieWithError' ] ) ) {
2016-11-03 19:16:56 +00:00
$this -> dieWithError (
2016-12-02 00:49:13 +00:00
[ 'apierror-paramempty' , $this -> encodeParamName ( 'prop' ) ], 'noprop'
2016-11-03 19:16:56 +00:00
);
} else {
$this -> dieUsage ( 'No properties selected' , '_noprop' );
}
2012-03-05 21:36:43 +00:00
}
2012-03-01 17:37:16 +00:00
2015-10-02 08:58:54 +00:00
$allTitles = $this -> getTitles ();
if ( count ( $allTitles ) === 0 ) {
return ;
}
2013-07-07 18:58:56 +00:00
// Find the offset based on the continue param
$offset = 0 ;
2012-03-05 21:36:43 +00:00
if ( isset ( $params [ 'continue' ] ) ) {
2013-07-07 18:58:56 +00:00
// Get the position (not the key) of the 'continue' page within the
// array of titles. Set this as the offset.
$pageIds = array_keys ( $allTitles );
$offset = array_search ( intval ( $params [ 'continue' ] ), $pageIds );
// If the 'continue' page wasn't found, die with error
2016-11-03 19:16:56 +00:00
$this -> dieContinueUsageIf ( ! $offset );
2012-03-05 21:36:43 +00:00
}
2013-07-07 18:58:56 +00:00
2016-11-10 00:02:00 +00:00
$limit = $params [ 'limit' ];
2013-07-07 18:58:56 +00:00
// Slice the part of the array we want to find images for
$titles = array_slice ( $allTitles , $offset , $limit , true );
// Get the next item in the title array and use it to set the continue value
$nextItemArray = array_slice ( $allTitles , $offset + $limit , 1 , true );
if ( $nextItemArray ) {
$this -> setContinueEnumParameter ( 'continue' , key ( $nextItemArray ) );
}
// Find any titles in the file namespace so we can handle those separately
2016-11-21 23:29:28 +00:00
$filePageTitles = [];
2013-07-07 18:58:56 +00:00
foreach ( $titles as $id => $title ) {
if ( $title -> inNamespace ( NS_FILE ) ) {
$filePageTitles [ $id ] = $title ;
unset ( $titles [ $id ] );
2012-05-08 21:42:07 +00:00
}
2013-07-07 18:58:56 +00:00
}
2016-11-10 00:02:00 +00:00
$size = $params [ 'thumbsize' ];
2013-07-07 18:58:56 +00:00
// Extract page images from the page_props table
if ( count ( $titles ) > 0 ) {
$this -> addTables ( 'page_props' );
2016-11-21 23:29:28 +00:00
$this -> addFields ( [ 'pp_page' , 'pp_propname' , 'pp_value' ] );
$this -> addWhere ( [ 'pp_page' => array_keys ( $titles ),
'pp_propname' => self :: getPropNames ( $params [ 'license' ] ) ] );
2013-07-07 18:58:56 +00:00
$res = $this -> select ( __METHOD__ );
2016-11-10 00:02:00 +00:00
$buffer = [];
$propNameAny = PageImages :: getPropName ( false );
2013-07-07 18:58:56 +00:00
foreach ( $res as $row ) {
$pageId = $row -> pp_page ;
2016-11-10 00:02:00 +00:00
if ( ! array_key_exists ( $pageId , $buffer ) || $row -> pp_propname === $propNameAny ) {
$buffer [ $pageId ] = $row ;
}
}
foreach ( $buffer as $pageId => $row ) {
2013-07-07 18:58:56 +00:00
$fileName = $row -> pp_value ;
$this -> setResultValues ( $prop , $pageId , $fileName , $size );
2012-05-08 21:42:07 +00:00
}
2016-11-10 00:02:00 +00:00
2013-07-07 18:58:56 +00:00
} // End page props image extraction
// Extract images from file namespace pages. In this case we just use
// the file itself rather than searching for a page_image. (Bug 50252)
foreach ( $filePageTitles as $pageId => $title ) {
$fileName = $title -> getDBkey ();
$this -> setResultValues ( $prop , $pageId , $fileName , $size );
2012-03-01 17:37:16 +00:00
}
}
2016-11-10 00:02:00 +00:00
/**
* Get property names used in page_props table
*
* If the license is free , then only the free property name will be returned ,
* otherwise both free and non - free property names will be returned . That ' s
* because we save the image name only once if it ' s free and the best image .
*
* @ param string $license
* @ return string | array
*/
protected static function getPropNames ( $license ) {
if ( $license === self :: PARAM_LICENSE_FREE ) {
return PageImages :: getPropName ( true );
}
return [ PageImages :: getPropName ( true ), PageImages :: getPropName ( false ) ];
}
2014-03-29 11:47:53 +00:00
public function getCacheMode ( $params ) {
return 'public' ;
}
2013-07-07 18:58:56 +00:00
/**
* For a given page , set API return values for thumbnail and pageimage as needed
*
* @ param array $prop The prop values from the API request
2015-10-31 01:30:18 +00:00
* @ param int $pageId The ID of the page
2013-07-07 18:58:56 +00:00
* @ param string $fileName The name of the file to transform
2015-10-31 01:30:18 +00:00
* @ param int $size The thumbsize value from the API request
2013-07-07 18:58:56 +00:00
*/
2015-10-31 01:30:18 +00:00
protected function setResultValues ( array $prop , $pageId , $fileName , $size ) {
2016-11-21 23:29:28 +00:00
$vals = [];
2015-04-03 19:11:28 +00:00
if ( isset ( $prop [ 'thumbnail' ] ) || isset ( $prop [ 'original' ] ) ) {
2013-07-07 18:58:56 +00:00
$file = wfFindFile ( $fileName );
2016-11-03 18:27:32 +00:00
if ( $file ) {
2016-12-02 22:09:55 +00:00
$vals [ 'thumbnail' ] = [];
2016-11-03 18:27:32 +00:00
if ( isset ( $prop [ 'thumbnail' ] ) ) {
2016-11-21 23:29:28 +00:00
$thumb = $file -> transform ( [ 'width' => $size , 'height' => $size ] );
2015-04-02 23:06:16 +00:00
if ( $thumb && $thumb -> getUrl () ) {
2016-02-27 19:27:11 +00:00
// You can request a thumb 1000x larger than the original
// which (in case of bitmap original) will return a Thumb object
// that will lie about its size but have the original as an image.
$reportedSize = $thumb -> fileIsSource () ? $file : $thumb ;
2016-11-21 23:29:28 +00:00
$vals [ 'thumbnail' ] = [
2015-04-02 23:06:16 +00:00
'source' => wfExpandUrl ( $thumb -> getUrl (), PROTO_CURRENT ),
2016-02-27 19:27:11 +00:00
'width' => $reportedSize -> getWidth (),
'height' => $reportedSize -> getHeight (),
2016-11-21 23:29:28 +00:00
];
2015-04-02 23:06:16 +00:00
}
2013-07-07 18:58:56 +00:00
}
2015-04-02 23:06:16 +00:00
2016-11-03 18:27:32 +00:00
if ( isset ( $prop [ 'original' ] ) ) {
$original_url = wfExpandUrl ( $file -> getUrl (), PROTO_CURRENT );
2016-12-02 22:09:55 +00:00
$vals [ 'original' ] = [
'source' => $original_url ,
'width' => $file -> getWidth (),
'height' => $file -> getHeight ()
];
// DEPRECATED: The original image URL was originally provided as a property of
// the "thumbnail" object, but we now provide the original image info in its own
// object on the same level as the thumbnail.
//
// Remove this functionality, and the warning, after a reasonable amount of time
// has passed since December 2016.
if ( is_callable ( [ $this , 'addWarning' ] ) ) {
$this -> addWarning ( 'apiwarn-query+pageimages-original-in-thumbnail-deprecated' );
2016-11-03 18:27:32 +00:00
} else {
2016-12-02 22:09:55 +00:00
$this -> setWarning ( " The original image's source URL is now provided with its dimensions in its own property for the page object. It will be removed from the 'thumbnail' property in a future release. " );
2016-11-03 18:27:32 +00:00
}
2016-12-02 22:09:55 +00:00
$vals [ 'thumbnail' ][ 'original' ] = $original_url ;
2015-04-03 19:11:28 +00:00
}
2015-04-02 23:06:16 +00:00
}
2013-07-07 18:58:56 +00:00
}
2015-04-02 23:06:16 +00:00
2013-07-07 18:58:56 +00:00
if ( isset ( $prop [ 'name' ] ) ) {
$vals [ 'pageimage' ] = $fileName ;
}
2015-04-02 23:06:16 +00:00
2016-11-21 23:29:28 +00:00
$this -> getResult () -> addValue ( [ 'query' , 'pages' ], $pageId , $vals );
2013-07-07 18:58:56 +00:00
}
2014-10-29 18:20:55 +00:00
/**
* @ deprecated since MediaWiki core 1.25
*/
2012-03-05 21:36:43 +00:00
public function getDescription () {
return 'Returns information about images on the page such as thumbnail and presence of photos.' ;
}
2012-03-01 17:37:16 +00:00
public function getAllowedParams () {
2016-11-21 23:29:28 +00:00
return [
'prop' => [
ApiBase :: PARAM_TYPE => [ 'thumbnail' , 'name' , 'original' ],
2012-03-01 17:37:16 +00:00
ApiBase :: PARAM_ISMULTI => true ,
2012-12-17 19:22:13 +00:00
ApiBase :: PARAM_DFLT => 'thumbnail|name' ,
2016-11-21 23:29:28 +00:00
],
'thumbsize' => [
2012-03-01 17:37:16 +00:00
ApiBase :: PARAM_TYPE => 'integer' ,
2016-11-10 00:02:00 +00:00
ApiBase :: PARAM_DFLT => 50 ,
2016-11-21 23:29:28 +00:00
],
'limit' => [
2012-03-05 21:36:43 +00:00
ApiBase :: PARAM_DFLT => 1 ,
ApiBase :: PARAM_TYPE => 'limit' ,
ApiBase :: PARAM_MIN => 1 ,
2012-12-17 19:22:13 +00:00
ApiBase :: PARAM_MAX => 50 ,
ApiBase :: PARAM_MAX2 => 100 ,
2016-11-21 23:29:28 +00:00
],
2016-11-10 00:02:00 +00:00
'license' => [
ApiBase :: PARAM_TYPE => [ self :: PARAM_LICENSE_FREE , self :: PARAM_LICENSE_ANY ],
ApiBase :: PARAM_ISMULTI => false ,
2017-01-19 20:20:00 +00:00
ApiBase :: PARAM_DFLT => self :: PARAM_LICENSE_FREE ,
2016-11-10 00:02:00 +00:00
],
2016-11-21 23:29:28 +00:00
'continue' => [
2012-03-05 21:36:43 +00:00
ApiBase :: PARAM_TYPE => 'integer' ,
2016-11-21 23:29:28 +00:00
/**
* @ todo
* Once support for MediaWiki < 1.25 is dropped , just use
* ApiBase :: PARAM_HELP_MSG directly
*/
defined ( 'ApiBase::PARAM_HELP_MSG' )
? ApiBase :: PARAM_HELP_MSG : '' => 'api-help-param-continue' ,
],
];
2012-03-01 17:37:16 +00:00
}
2014-10-29 18:20:55 +00:00
/**
* @ deprecated since MediaWiki core 1.25
*/
2012-03-01 19:55:02 +00:00
public function getParamDescription () {
2016-11-21 23:29:28 +00:00
return [
'prop' => [ 'What information to return' ,
2012-03-01 19:55:02 +00:00
' thumbnail - URL and dimensions of image associated with page, if any' ,
2015-04-02 23:06:16 +00:00
' name - image title' ,
2016-12-02 22:09:55 +00:00
' original - URL and dimensions of the original image' ,
2016-11-21 23:29:28 +00:00
],
2013-12-10 14:12:36 +00:00
'thumbsize' => 'Maximum thumbnail dimension' ,
2012-03-05 21:36:43 +00:00
'limit' => 'Properties of how many pages to return' ,
'continue' => 'When more results are available, use this to continue' ,
2016-11-21 23:29:28 +00:00
];
2012-03-05 21:36:43 +00:00
}
2015-02-09 21:06:49 +00:00
/**
* @ see ApiBase :: getExamplesMessages ()
*/
protected function getExamplesMessages () {
2016-11-21 23:29:28 +00:00
return [
2015-02-09 21:06:49 +00:00
'action=query&prop=pageimages&titles=Albert%20Einstein&pithumbsize=100' =>
'apihelp-query+pageimages-example-1' ,
2016-11-21 23:29:28 +00:00
];
2015-02-09 21:06:49 +00:00
}
2016-12-02 18:39:07 +00:00
public function getHelpUrls () {
return " https://www.mediawiki.org/wiki/Special:MyLanguage/Extension:PageImages#API " ;
}
2013-07-07 18:58:56 +00:00
}