summaryrefslogtreecommitdiff
path: root/includes/filerepo/ForeignAPIRepo.php
diff options
context:
space:
mode:
authorPierre Schmitz <pierre@archlinux.de>2011-06-22 11:28:20 +0200
committerPierre Schmitz <pierre@archlinux.de>2011-06-22 11:28:20 +0200
commit9db190c7e736ec8d063187d4241b59feaf7dc2d1 (patch)
tree46d1a0dee7febef5c2d57a9f7b972be16a163b3d /includes/filerepo/ForeignAPIRepo.php
parent78677c7bbdcc9739f6c10c75935898a20e1acd9e (diff)
update to MediaWiki 1.17.0
Diffstat (limited to 'includes/filerepo/ForeignAPIRepo.php')
-rw-r--r--includes/filerepo/ForeignAPIRepo.php258
1 files changed, 193 insertions, 65 deletions
diff --git a/includes/filerepo/ForeignAPIRepo.php b/includes/filerepo/ForeignAPIRepo.php
index 264cb920..e4188d6b 100644
--- a/includes/filerepo/ForeignAPIRepo.php
+++ b/includes/filerepo/ForeignAPIRepo.php
@@ -1,9 +1,13 @@
<?php
+/**
+ * Foreign repository accessible through api.php requests.
+ *
+ * @file
+ * @ingroup FileRepo
+ */
/**
* A foreign repository with a remote MediaWiki with an API thingy
- * Very hacky and inefficient
- * do not use except for testing :D
*
* Example config:
*
@@ -18,17 +22,37 @@
* @ingroup FileRepo
*/
class ForeignAPIRepo extends FileRepo {
+ /* This version string is used in the user agent for requests and will help
+ * server maintainers in identify ForeignAPI usage.
+ * Update the version every time you make breaking or significant changes. */
+ const VERSION = "2.0";
+
var $fileFactory = array( 'ForeignAPIFile', 'newFromTitle' );
+ /* Check back with Commons after a day */
var $apiThumbCacheExpiry = 86400;
+ /* Redownload thumbnail files after a month */
+ var $fileCacheExpiry = 2629743;
+ /* Local image directory */
+ var $directory;
+ var $thumbDir;
+
protected $mQueryCache = array();
protected $mFileExists = array();
function __construct( $info ) {
parent::__construct( $info );
- $this->mApiBase = $info['apibase']; // http://commons.wikimedia.org/w/api.php
+ global $wgUploadDirectory;
+
+ // http://commons.wikimedia.org/w/api.php
+ $this->mApiBase = isset( $info['apibase'] ) ? $info['apibase'] : null;
+ $this->directory = isset( $info['directory'] ) ? $info['directory'] : $wgUploadDirectory;
+
if( isset( $info['apiThumbCacheExpiry'] ) ) {
$this->apiThumbCacheExpiry = $info['apiThumbCacheExpiry'];
}
+ if( isset( $info['fileCacheExpiry'] ) ) {
+ $this->fileCacheExpiry = $info['fileCacheExpiry'];
+ }
if( !$this->scriptDirUrl ) {
// hack for description fetches
$this->scriptDirUrl = dirname( $this->mApiBase );
@@ -41,6 +65,11 @@ class ForeignAPIRepo extends FileRepo {
if( $this->canCacheThumbs() && !$this->thumbUrl ) {
$this->thumbUrl = $this->url . '/thumb';
}
+ if ( isset( $info['thumbDir'] ) ) {
+ $this->thumbDir = $info['thumbDir'];
+ } else {
+ $this->thumbDir = "{$this->directory}/thumb";
+ }
}
/**
@@ -89,7 +118,7 @@ class ForeignAPIRepo extends FileRepo {
}
}
- $results = $this->fetchImageQuery( array( 'titles' => implode( $files, '|' ),
+ $data = $this->fetchImageQuery( array( 'titles' => implode( $files, '|' ),
'prop' => 'imageinfo' ) );
if( isset( $data['query']['pages'] ) ) {
$i = 0;
@@ -98,40 +127,32 @@ class ForeignAPIRepo extends FileRepo {
$i++;
}
}
+ return $results;
}
function getFileProps( $virtualUrl ) {
return false;
}
- protected function queryImage( $query ) {
- $data = $this->fetchImageQuery( $query );
-
- if( isset( $data['query']['pages'] ) ) {
- foreach( $data['query']['pages'] as $pageid => $info ) {
- if( isset( $info['imageinfo'][0] ) ) {
- return $info['imageinfo'][0];
- }
- }
- }
- return false;
- }
-
- protected function fetchImageQuery( $query ) {
+ function fetchImageQuery( $query ) {
global $wgMemc;
- $url = $this->mApiBase .
- '?' .
- wfArrayToCgi(
- array_merge( $query,
- array(
- 'format' => 'json',
- 'action' => 'query' ) ) );
+ $query = array_merge( $query,
+ array(
+ 'format' => 'json',
+ 'action' => 'query',
+ 'redirects' => 'true'
+ ) );
+ if ( $this->mApiBase ) {
+ $url = wfAppendQuery( $this->mApiBase, $query );
+ } else {
+ $url = $this->makeUrl( $query, 'api' );
+ }
if( !isset( $this->mQueryCache[$url] ) ) {
$key = $this->getLocalCacheKey( 'ForeignAPIRepo', 'Metadata', md5( $url ) );
$data = $wgMemc->get( $key );
if( !$data ) {
- $data = Http::get( $url );
+ $data = self::httpGet( $url );
if ( !$data ) {
return null;
}
@@ -147,81 +168,141 @@ class ForeignAPIRepo extends FileRepo {
return FormatJson::decode( $this->mQueryCache[$url], true );
}
- function getImageInfo( $title, $time = false ) {
- return $this->queryImage( array(
- 'titles' => 'Image:' . $title->getText(),
- 'iiprop' => 'timestamp|user|comment|url|size|sha1|metadata|mime',
- 'prop' => 'imageinfo' ) );
+ function getImageInfo( $data ) {
+ if( $data && isset( $data['query']['pages'] ) ) {
+ foreach( $data['query']['pages'] as $info ) {
+ if( isset( $info['imageinfo'][0] ) ) {
+ return $info['imageinfo'][0];
+ }
+ }
+ }
+ return false;
}
function findBySha1( $hash ) {
$results = $this->fetchImageQuery( array(
'aisha1base36' => $hash,
- 'aiprop' => 'timestamp|user|comment|url|size|sha1|metadata|mime',
+ 'aiprop' => ForeignAPIFile::getProps(),
'list' => 'allimages', ) );
$ret = array();
if ( isset( $results['query']['allimages'] ) ) {
foreach ( $results['query']['allimages'] as $img ) {
+ // 1.14 was broken, doesn't return name attribute
+ if( !isset( $img['name'] ) ) {
+ continue;
+ }
$ret[] = new ForeignAPIFile( Title::makeTitle( NS_FILE, $img['name'] ), $this, $img );
}
}
return $ret;
}
- function getThumbUrl( $name, $width=-1, $height=-1 ) {
- $info = $this->queryImage( array(
- 'titles' => 'Image:' . $name,
- 'iiprop' => 'url',
+ function getThumbUrl( $name, $width=-1, $height=-1, &$result=NULL ) {
+ $data = $this->fetchImageQuery( array(
+ 'titles' => 'File:' . $name,
+ 'iiprop' => 'url|timestamp',
'iiurlwidth' => $width,
'iiurlheight' => $height,
'prop' => 'imageinfo' ) );
- if( $info && $info['thumburl'] ) {
+ $info = $this->getImageInfo( $data );
+
+ if( $data && $info && isset( $info['thumburl'] ) ) {
wfDebug( __METHOD__ . " got remote thumb " . $info['thumburl'] . "\n" );
+ $result = $info;
return $info['thumburl'];
} else {
return false;
}
}
+ /*
+ * Return the imageurl from cache if possible
+ *
+ * If the url has been requested today, get it from cache
+ * Otherwise retrieve remote thumb url, check for local file.
+ *
+ * @param $name String is a dbkey form of a title
+ * @param $width
+ * @param $height
+ */
function getThumbUrlFromCache( $name, $width, $height ) {
- global $wgMemc, $wgUploadPath, $wgServer, $wgUploadDirectory;
+ global $wgMemc;
if ( !$this->canCacheThumbs() ) {
return $this->getThumbUrl( $name, $width, $height );
}
-
$key = $this->getLocalCacheKey( 'ForeignAPIRepo', 'ThumbUrl', $name );
- if ( $thumbUrl = $wgMemc->get($key) ) {
- wfDebug("Got thumb from local cache. $thumbUrl \n");
- return $thumbUrl;
- }
- else {
- $foreignUrl = $this->getThumbUrl( $name, $width, $height );
- if( !$foreignUrl ) {
- wfDebug( __METHOD__ . " Could not find thumburl\n" );
- return false;
- }
- $thumb = Http::get( $foreignUrl );
- if( !$thumb ) {
- wfDebug( __METHOD__ . " Could not download thumb\n" );
- return false;
+ $sizekey = "$width:$height";
+
+ /* Get the array of urls that we already know */
+ $knownThumbUrls = $wgMemc->get($key);
+ if( !$knownThumbUrls ) {
+ /* No knownThumbUrls for this file */
+ $knownThumbUrls = array();
+ } else {
+ if( isset( $knownThumbUrls[$sizekey] ) ) {
+ wfDebug("Got thumburl from local cache. {$knownThumbUrls[$sizekey]} \n");
+ return $knownThumbUrls[$sizekey];
}
- // We need the same filename as the remote one :)
- $fileName = rawurldecode( pathinfo( $foreignUrl, PATHINFO_BASENAME ) );
- $path = 'thumb/' . $this->getHashPath( $name ) . $name . "/";
- if ( !is_dir($wgUploadDirectory . '/' . $path) ) {
- wfMkdirParents($wgUploadDirectory . '/' . $path);
+ /* This size is not yet known */
+ }
+
+ $metadata = null;
+ $foreignUrl = $this->getThumbUrl( $name, $width, $height, $metadata );
+
+ if( !$foreignUrl ) {
+ wfDebug( __METHOD__ . " Could not find thumburl\n" );
+ return false;
+ }
+
+ // We need the same filename as the remote one :)
+ $fileName = rawurldecode( pathinfo( $foreignUrl, PATHINFO_BASENAME ) );
+ if( !$this->validateFilename( $fileName ) ) {
+ wfDebug( __METHOD__ . " The deduced filename $fileName is not safe\n" );
+ return false;
+ }
+ $localPath = $this->getZonePath( 'thumb' ) . "/" . $this->getHashPath( $name ) . $name;
+ $localFilename = $localPath . "/" . $fileName;
+ $localUrl = $this->getZoneUrl( 'thumb' ) . "/" . $this->getHashPath( $name ) . rawurlencode( $name ) . "/" . rawurlencode( $fileName );
+
+ if( file_exists( $localFilename ) && isset( $metadata['timestamp'] ) ) {
+ wfDebug( __METHOD__ . " Thumbnail was already downloaded before\n" );
+ $modified = filemtime( $localFilename );
+ $remoteModified = strtotime( $metadata['timestamp'] );
+ $current = time();
+ $diff = abs( $modified - $current );
+ if( $remoteModified < $modified && $diff < $this->fileCacheExpiry ) {
+ /* Use our current and already downloaded thumbnail */
+ $knownThumbUrls["$width:$height"] = $localUrl;
+ $wgMemc->set( $key, $knownThumbUrls, $this->apiThumbCacheExpiry );
+ return $localUrl;
}
- $localUrl = $wgServer . $wgUploadPath . '/' . $path . $fileName;
- # FIXME: Delete old thumbs that aren't being used. Maintenance script?
- if( !file_put_contents($wgUploadDirectory . '/' . $path . $fileName, $thumb ) ) {
- wfDebug( __METHOD__ . " could not write to thumb path\n" );
+ /* There is a new Commons file, or existing thumbnail older than a month */
+ }
+ $thumb = self::httpGet( $foreignUrl );
+ if( !$thumb ) {
+ wfDebug( __METHOD__ . " Could not download thumb\n" );
+ return false;
+ }
+ if ( !is_dir($localPath) ) {
+ if( !wfMkdirParents($localPath) ) {
+ wfDebug( __METHOD__ . " could not create directory $localPath for thumb\n" );
return $foreignUrl;
}
- $wgMemc->set( $key, $localUrl, $this->apiThumbCacheExpiry );
- wfDebug( __METHOD__ . " got local thumb $localUrl, saving to cache \n" );
- return $localUrl;
}
+
+ # FIXME: Delete old thumbs that aren't being used. Maintenance script?
+ wfSuppressWarnings();
+ if( !file_put_contents( $localFilename, $thumb ) ) {
+ wfRestoreWarnings();
+ wfDebug( __METHOD__ . " could not write to thumb path\n" );
+ return $foreignUrl;
+ }
+ wfRestoreWarnings();
+ $knownThumbUrls[$sizekey] = $localUrl;
+ $wgMemc->set( $key, $knownThumbUrls, $this->apiThumbCacheExpiry );
+ wfDebug( __METHOD__ . " got local thumb $localUrl, saving to cache \n" );
+ return $localUrl;
}
/**
@@ -239,10 +320,57 @@ class ForeignAPIRepo extends FileRepo {
}
/**
+ * Get the local directory corresponding to one of the three basic zones
+ */
+ function getZonePath( $zone ) {
+ switch ( $zone ) {
+ case 'public':
+ return $this->directory;
+ case 'thumb':
+ return $this->thumbDir;
+ default:
+ return false;
+ }
+ }
+
+ /**
* Are we locally caching the thumbnails?
* @return bool
*/
public function canCacheThumbs() {
return ( $this->apiThumbCacheExpiry > 0 );
}
+
+ /**
+ * The user agent the ForeignAPIRepo will use.
+ */
+ public static function getUserAgent() {
+ return Http::userAgent() . " ForeignAPIRepo/" . self::VERSION;
+ }
+
+ /**
+ * Like a Http:get request, but with custom User-Agent.
+ * @see Http:get
+ */
+ public static function httpGet( $url, $timeout = 'default', $options = array() ) {
+ $options['timeout'] = $timeout;
+ /* Http::get */
+ $url = wfExpandUrl( $url );
+ wfDebug( "ForeignAPIRepo: HTTP GET: $url\n" );
+ $options['method'] = "GET";
+
+ if ( !isset( $options['timeout'] ) ) {
+ $options['timeout'] = 'default';
+ }
+
+ $req = MWHttpRequest::factory( $url, $options );
+ $req->setUserAgent( ForeignAPIRepo::getUserAgent() );
+ $status = $req->execute();
+
+ if ( $status->isOK() ) {
+ return $req->getContent();
+ } else {
+ return false;
+ }
+ }
}