2007-06-16 02:55:25 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Base class for file repositories
|
|
|
|
|
* Do not instantiate, use a derived class.
|
WARNING: HUGE COMMIT
Doxygen documentation update:
* Changed alls @addtogroup to @ingroup. @addtogroup adds the comment to the group description, but doesn't add the file, class, function, ... to the group like @ingroup does. See for example http://svn.wikimedia.org/doc/group__SpecialPage.html where it's impossible to see related files, classes, ... that should belong to that group.
* Added @file to file description, it seems that it should be explicitely decalred for file descriptions, otherwise doxygen will think that the comment document the first class, variabled, function, ... that is in that file.
* Removed some empty comments
* Removed some ?>
Added following groups:
* ExternalStorage
* JobQueue
* MaintenanceLanguage
One more thing: there are still a lot of warnings when generating the doc.
2008-05-20 17:13:28 +00:00
|
|
|
* @ingroup FileRepo
|
2007-06-16 02:55:25 +00:00
|
|
|
*/
|
|
|
|
|
abstract class FileRepo {
|
2009-03-29 13:42:29 +00:00
|
|
|
const FILES_ONLY = 1;
|
2007-06-16 02:55:25 +00:00
|
|
|
const DELETE_SOURCE = 1;
|
2007-07-22 14:45:12 +00:00
|
|
|
const OVERWRITE = 2;
|
|
|
|
|
const OVERWRITE_SAME = 4;
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
var $thumbScriptUrl, $transformVia404;
|
|
|
|
|
var $descBaseUrl, $scriptDirUrl, $articleUrl, $fetchDescription, $initialCapital;
|
2007-07-22 14:45:12 +00:00
|
|
|
var $pathDisclosureProtection = 'paranoid';
|
2009-10-09 11:41:38 +00:00
|
|
|
var $descriptionCacheExpiry, $hashLevels, $url, $thumbUrl;
|
2007-06-16 02:55:25 +00:00
|
|
|
|
2008-04-14 07:45:50 +00:00
|
|
|
/**
|
2007-06-16 02:55:25 +00:00
|
|
|
* Factory functions for creating new files
|
|
|
|
|
* Override these in the base class
|
|
|
|
|
*/
|
|
|
|
|
var $fileFactory = false, $oldFileFactory = false;
|
2008-05-20 02:58:40 +00:00
|
|
|
var $fileFactoryKey = false, $oldFileFactoryKey = false;
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
function __construct( $info ) {
|
|
|
|
|
// Required settings
|
|
|
|
|
$this->name = $info['name'];
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2007-06-16 02:55:25 +00:00
|
|
|
// Optional settings
|
2009-10-09 12:52:16 +00:00
|
|
|
$this->initialCapital = MWNamespace::isCapitalized( NS_FILE );
|
2008-04-14 07:45:50 +00:00
|
|
|
foreach ( array( 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription',
|
2010-02-10 10:36:11 +00:00
|
|
|
'thumbScriptUrl', 'initialCapital', 'pathDisclosureProtection',
|
2009-10-09 11:41:38 +00:00
|
|
|
'descriptionCacheExpiry', 'hashLevels', 'url', 'thumbUrl' ) as $var )
|
2007-06-16 02:55:25 +00:00
|
|
|
{
|
|
|
|
|
if ( isset( $info[$var] ) ) {
|
|
|
|
|
$this->$var = $info[$var];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->transformVia404 = !empty( $info['transformVia404'] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if a string is an mwrepo:// URL
|
|
|
|
|
*/
|
|
|
|
|
static function isVirtualUrl( $url ) {
|
|
|
|
|
return substr( $url, 0, 9 ) == 'mwrepo://';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new File object from the local repository
|
|
|
|
|
* @param mixed $title Title object or string
|
2008-04-14 07:45:50 +00:00
|
|
|
* @param mixed $time Time at which the image was uploaded.
|
|
|
|
|
* If this is specified, the returned object will be an
|
2007-06-16 02:55:25 +00:00
|
|
|
* instance of the repository's old file class instead of
|
2008-04-14 07:45:50 +00:00
|
|
|
* a current file. Repositories not supporting version
|
2007-06-16 02:55:25 +00:00
|
|
|
* control should return false if this parameter is set.
|
|
|
|
|
*/
|
|
|
|
|
function newFile( $title, $time = false ) {
|
|
|
|
|
if ( !($title instanceof Title) ) {
|
2008-12-01 17:14:30 +00:00
|
|
|
$title = Title::makeTitleSafe( NS_FILE, $title );
|
2007-06-16 02:55:25 +00:00
|
|
|
if ( !is_object( $title ) ) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( $time ) {
|
|
|
|
|
if ( $this->oldFileFactory ) {
|
|
|
|
|
return call_user_func( $this->oldFileFactory, $title, $this, $time );
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return call_user_func( $this->fileFactory, $title, $this );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-04-05 15:38:08 +00:00
|
|
|
* Find an instance of the named file created at the specified time
|
2008-04-14 07:45:50 +00:00
|
|
|
* Returns false if the file does not exist. Repositories not supporting
|
2007-06-16 02:55:25 +00:00
|
|
|
* version control should return false if the time is specified.
|
|
|
|
|
*
|
2008-04-06 10:18:47 +00:00
|
|
|
* @param mixed $title Title object or string
|
2009-08-15 09:59:59 +00:00
|
|
|
* @param $options Associative array of options:
|
|
|
|
|
* time: requested time for an archived image, or false for the
|
|
|
|
|
* current version. An image object will be returned which was
|
|
|
|
|
* created at the specified time.
|
|
|
|
|
*
|
|
|
|
|
* ignoreRedirect: If true, do not follow file redirects
|
|
|
|
|
*
|
2010-02-10 10:36:11 +00:00
|
|
|
* private: If true, return restricted (deleted) files if the current
|
2009-08-15 09:59:59 +00:00
|
|
|
* user is allowed to view them. Otherwise, such files will not
|
|
|
|
|
* be found.
|
2007-06-16 02:55:25 +00:00
|
|
|
*/
|
2009-08-15 09:59:59 +00:00
|
|
|
function findFile( $title, $options = array() ) {
|
|
|
|
|
if ( !is_array( $options ) ) {
|
|
|
|
|
// MW 1.15 compat
|
|
|
|
|
$time = $options;
|
|
|
|
|
} else {
|
|
|
|
|
$time = isset( $options['time'] ) ? $options['time'] : false;
|
|
|
|
|
}
|
2008-04-06 10:18:47 +00:00
|
|
|
if ( !($title instanceof Title) ) {
|
2008-12-01 17:14:30 +00:00
|
|
|
$title = Title::makeTitleSafe( NS_FILE, $title );
|
2008-04-06 10:18:47 +00:00
|
|
|
if ( !is_object( $title ) ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
# First try the current version of the file to see if it precedes the timestamp
|
|
|
|
|
$img = $this->newFile( $title );
|
2007-10-01 19:50:25 +00:00
|
|
|
if ( !$img ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2008-02-04 08:18:55 +00:00
|
|
|
if ( $img->exists() && ( !$time || $img->getTimestamp() == $time ) ) {
|
2007-06-16 02:55:25 +00:00
|
|
|
return $img;
|
|
|
|
|
}
|
|
|
|
|
# Now try an old version of the file
|
2008-05-07 03:39:35 +00:00
|
|
|
if ( $time !== false ) {
|
|
|
|
|
$img = $this->newFile( $title, $time );
|
2008-09-07 00:38:57 +00:00
|
|
|
if ( $img && $img->exists() ) {
|
2008-05-07 03:39:35 +00:00
|
|
|
if ( !$img->isDeleted(File::DELETED_FILE) ) {
|
|
|
|
|
return $img;
|
2009-08-15 09:59:59 +00:00
|
|
|
} else if ( !empty( $options['private'] ) && $img->userCan(File::DELETED_FILE) ) {
|
2008-05-07 03:39:35 +00:00
|
|
|
return $img;
|
|
|
|
|
}
|
2008-03-09 03:10:28 +00:00
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2008-01-16 18:27:43 +00:00
|
|
|
# Now try redirects
|
2009-08-15 09:59:59 +00:00
|
|
|
if ( !empty( $options['ignoreRedirect'] ) ) {
|
2008-05-20 02:58:40 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
$redir = $this->checkRedirect( $title );
|
2008-12-01 17:14:30 +00:00
|
|
|
if( $redir && $redir->getNamespace() == NS_FILE) {
|
2008-01-16 18:27:43 +00:00
|
|
|
$img = $this->newFile( $redir );
|
|
|
|
|
if( !$img ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if( $img->exists() ) {
|
2008-05-08 20:55:13 +00:00
|
|
|
$img->redirectedFrom( $title->getDBkey() );
|
2008-01-16 18:27:43 +00:00
|
|
|
return $img;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-03-09 03:10:28 +00:00
|
|
|
return false;
|
2007-06-16 02:55:25 +00:00
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2008-05-20 17:05:57 +00:00
|
|
|
/*
|
2010-02-10 10:36:11 +00:00
|
|
|
* Find many files at once.
|
2009-08-15 09:59:59 +00:00
|
|
|
* @param array $items, an array of titles, or an array of findFile() options with
|
|
|
|
|
* the "title" option giving the title. Example:
|
|
|
|
|
*
|
|
|
|
|
* $findItem = array( 'title' => $title, 'private' => true );
|
|
|
|
|
* $findBatch = array( $findItem );
|
|
|
|
|
* $repo->findFiles( $findBatch );
|
2008-05-20 17:05:57 +00:00
|
|
|
*/
|
2009-08-15 09:59:59 +00:00
|
|
|
function findFiles( $items ) {
|
2008-05-20 17:05:57 +00:00
|
|
|
$result = array();
|
2009-08-15 09:59:59 +00:00
|
|
|
foreach ( $items as $index => $item ) {
|
|
|
|
|
if ( is_array( $item ) ) {
|
|
|
|
|
$title = $item['title'];
|
|
|
|
|
$options = $item;
|
|
|
|
|
unset( $options['title'] );
|
|
|
|
|
} else {
|
|
|
|
|
$title = $item;
|
|
|
|
|
$options = array();
|
|
|
|
|
}
|
|
|
|
|
$file = $this->findFile( $title, $options );
|
2008-05-30 13:16:08 +00:00
|
|
|
if ( $file )
|
2008-05-20 17:05:57 +00:00
|
|
|
$result[$file->getTitle()->getDBkey()] = $file;
|
|
|
|
|
}
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2008-05-20 02:58:40 +00:00
|
|
|
/**
|
|
|
|
|
* Create a new File object from the local repository
|
|
|
|
|
* @param mixed $sha1 SHA-1 key
|
|
|
|
|
* @param mixed $time Time at which the image was uploaded.
|
|
|
|
|
* If this is specified, the returned object will be an
|
|
|
|
|
* instance of the repository's old file class instead of
|
|
|
|
|
* a current file. Repositories not supporting version
|
|
|
|
|
* control should return false if this parameter is set.
|
|
|
|
|
*/
|
|
|
|
|
function newFileFromKey( $sha1, $time = false ) {
|
|
|
|
|
if ( $time ) {
|
|
|
|
|
if ( $this->oldFileFactoryKey ) {
|
|
|
|
|
return call_user_func( $this->oldFileFactoryKey, $sha1, $this, $time );
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return call_user_func( $this->fileFactoryKey, $sha1, $this );
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2008-05-20 02:58:40 +00:00
|
|
|
/**
|
|
|
|
|
* Find an instance of the file with this key, created at the specified time
|
|
|
|
|
* Returns false if the file does not exist. Repositories not supporting
|
|
|
|
|
* version control should return false if the time is specified.
|
|
|
|
|
*
|
|
|
|
|
* @param string $sha1 string
|
2010-02-10 10:36:11 +00:00
|
|
|
* @param array $options Option array, same as findFile().
|
2008-05-20 02:58:40 +00:00
|
|
|
*/
|
2009-08-15 09:59:59 +00:00
|
|
|
function findFileFromKey( $sha1, $options = array() ) {
|
|
|
|
|
if ( !is_array( $options ) ) {
|
|
|
|
|
# MW 1.15 compat
|
|
|
|
|
$time = $options;
|
|
|
|
|
} else {
|
|
|
|
|
$time = isset( $options['time'] ) ? $options['time'] : false;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-20 02:58:40 +00:00
|
|
|
# First try the current version of the file to see if it precedes the timestamp
|
|
|
|
|
$img = $this->newFileFromKey( $sha1 );
|
|
|
|
|
if ( !$img ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ( $img->exists() && ( !$time || $img->getTimestamp() == $time ) ) {
|
|
|
|
|
return $img;
|
|
|
|
|
}
|
|
|
|
|
# Now try an old version of the file
|
|
|
|
|
if ( $time !== false ) {
|
|
|
|
|
$img = $this->newFileFromKey( $sha1, $time );
|
|
|
|
|
if ( $img->exists() ) {
|
|
|
|
|
if ( !$img->isDeleted(File::DELETED_FILE) ) {
|
|
|
|
|
return $img;
|
2009-08-15 09:59:59 +00:00
|
|
|
} else if ( !empty( $options['private'] ) && $img->userCan(File::DELETED_FILE) ) {
|
2008-05-20 02:58:40 +00:00
|
|
|
return $img;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the URL of thumb.php
|
|
|
|
|
*/
|
|
|
|
|
function getThumbScriptUrl() {
|
|
|
|
|
return $this->thumbScriptUrl;
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2009-10-09 11:41:38 +00:00
|
|
|
/**
|
|
|
|
|
* Get the URL corresponding to one of the four basic zones
|
|
|
|
|
* @param String $zone One of: public, deleted, temp, thumb
|
|
|
|
|
* @return String or false
|
|
|
|
|
*/
|
|
|
|
|
function getZoneUrl( $zone ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if the repository can transform files via a 404 handler
|
|
|
|
|
*/
|
|
|
|
|
function canTransformVia404() {
|
|
|
|
|
return $this->transformVia404;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the name of an image from its title object
|
|
|
|
|
*/
|
|
|
|
|
function getNameFromTitle( $title ) {
|
|
|
|
|
global $wgCapitalLinks;
|
2009-10-09 12:52:16 +00:00
|
|
|
if ( $this->initialCapital != MWNamespace::isCapitalized( NS_FILE ) ) {
|
2007-06-16 02:55:25 +00:00
|
|
|
global $wgContLang;
|
|
|
|
|
$name = $title->getUserCaseDBKey();
|
|
|
|
|
if ( $this->initialCapital ) {
|
|
|
|
|
$name = $wgContLang->ucfirst( $name );
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$name = $title->getDBkey();
|
|
|
|
|
}
|
|
|
|
|
return $name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static function getHashPathForLevel( $name, $levels ) {
|
|
|
|
|
if ( $levels == 0 ) {
|
|
|
|
|
return '';
|
|
|
|
|
} else {
|
|
|
|
|
$hash = md5( $name );
|
|
|
|
|
$path = '';
|
|
|
|
|
for ( $i = 1; $i <= $levels; $i++ ) {
|
|
|
|
|
$path .= substr( $hash, 0, $i ) . '/';
|
|
|
|
|
}
|
|
|
|
|
return $path;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2008-11-08 22:20:23 +00:00
|
|
|
/**
|
|
|
|
|
* Get a relative path including trailing slash, e.g. f/fa/
|
|
|
|
|
* If the repo is not hashed, returns an empty string
|
|
|
|
|
*/
|
|
|
|
|
function getHashPath( $name ) {
|
|
|
|
|
return self::getHashPathForLevel( $name, $this->hashLevels );
|
|
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the name of this repository, as specified by $info['name]' to the constructor
|
|
|
|
|
*/
|
|
|
|
|
function getName() {
|
|
|
|
|
return $this->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the URL of an image description page. May return false if it is
|
2008-04-14 07:45:50 +00:00
|
|
|
* unknown or not applicable. In general this should only be called by the
|
|
|
|
|
* File class, since it may return invalid results for certain kinds of
|
2007-06-16 02:55:25 +00:00
|
|
|
* repositories. Use File::getDescriptionUrl() in user code.
|
|
|
|
|
*
|
|
|
|
|
* In particular, it uses the article paths as specified to the repository
|
|
|
|
|
* constructor, whereas local repositories use the local Title functions.
|
|
|
|
|
*/
|
|
|
|
|
function getDescriptionUrl( $name ) {
|
2008-12-10 22:07:04 +00:00
|
|
|
$encName = wfUrlencode( $name );
|
|
|
|
|
if ( !is_null( $this->descBaseUrl ) ) {
|
|
|
|
|
# "http://example.com/wiki/Image:"
|
|
|
|
|
return $this->descBaseUrl . $encName;
|
2007-06-16 02:55:25 +00:00
|
|
|
}
|
2008-12-10 22:07:04 +00:00
|
|
|
if ( !is_null( $this->articleUrl ) ) {
|
|
|
|
|
# "http://example.com/wiki/$1"
|
|
|
|
|
#
|
|
|
|
|
# We use "Image:" as the canonical namespace for
|
|
|
|
|
# compatibility across all MediaWiki versions.
|
|
|
|
|
return str_replace( '$1',
|
|
|
|
|
"Image:$encName", $this->articleUrl );
|
|
|
|
|
}
|
|
|
|
|
if ( !is_null( $this->scriptDirUrl ) ) {
|
|
|
|
|
# "http://example.com/w"
|
|
|
|
|
#
|
|
|
|
|
# We use "Image:" as the canonical namespace for
|
|
|
|
|
# compatibility across all MediaWiki versions,
|
|
|
|
|
# and just sort of hope index.php is right. ;)
|
|
|
|
|
return $this->scriptDirUrl .
|
|
|
|
|
"/index.php?title=Image:$encName";
|
|
|
|
|
}
|
|
|
|
|
return false;
|
2007-06-16 02:55:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
* Get the URL of the content-only fragment of the description page. For
|
|
|
|
|
* MediaWiki this means action=render. This should only be called by the
|
|
|
|
|
* repository's file class, since it may return invalid results. User code
|
2007-06-16 02:55:25 +00:00
|
|
|
* should use File::getDescriptionText().
|
2009-01-27 19:34:21 +00:00
|
|
|
* @param string $name Name of image to fetch
|
|
|
|
|
* @param string $lang Language to fetch it in, if any.
|
2007-06-16 02:55:25 +00:00
|
|
|
*/
|
2009-01-27 19:34:21 +00:00
|
|
|
function getDescriptionRenderUrl( $name, $lang = null ) {
|
|
|
|
|
$query = 'action=render';
|
|
|
|
|
if ( !is_null( $lang ) ) {
|
|
|
|
|
$query .= '&uselang=' . $lang;
|
|
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
if ( isset( $this->scriptDirUrl ) ) {
|
2008-04-14 07:45:50 +00:00
|
|
|
return $this->scriptDirUrl . '/index.php?title=' .
|
2008-12-04 18:23:52 +00:00
|
|
|
wfUrlencode( 'Image:' . $name ) .
|
2009-01-27 19:34:21 +00:00
|
|
|
"&$query";
|
2007-06-16 02:55:25 +00:00
|
|
|
} else {
|
2008-12-10 22:07:04 +00:00
|
|
|
$descUrl = $this->getDescriptionUrl( $name );
|
|
|
|
|
if ( $descUrl ) {
|
2009-01-27 19:34:21 +00:00
|
|
|
return wfAppendQuery( $descUrl, $query );
|
2007-06-16 02:55:25 +00:00
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Store a file to a given destination.
|
2007-07-22 14:45:12 +00:00
|
|
|
*
|
|
|
|
|
* @param string $srcPath Source path or virtual URL
|
|
|
|
|
* @param string $dstZone Destination zone
|
|
|
|
|
* @param string $dstRel Destination relative path
|
|
|
|
|
* @param integer $flags Bitwise combination of the following flags:
|
|
|
|
|
* self::DELETE_SOURCE Delete the source file after upload
|
|
|
|
|
* self::OVERWRITE Overwrite an existing destination file instead of failing
|
2008-04-14 07:45:50 +00:00
|
|
|
* self::OVERWRITE_SAME Overwrite the file if the destination exists and has the
|
2007-07-22 14:45:12 +00:00
|
|
|
* same contents as the source
|
|
|
|
|
* @return FileRepoStatus
|
|
|
|
|
*/
|
|
|
|
|
function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
|
|
|
|
|
$status = $this->storeBatch( array( array( $srcPath, $dstZone, $dstRel ) ), $flags );
|
|
|
|
|
if ( $status->successCount == 0 ) {
|
|
|
|
|
$status->ok = false;
|
|
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Store a batch of files
|
|
|
|
|
*
|
|
|
|
|
* @param array $triplets (src,zone,dest) triplets as per store()
|
|
|
|
|
* @param integer $flags Flags as per store
|
2007-06-16 02:55:25 +00:00
|
|
|
*/
|
2007-07-22 14:45:12 +00:00
|
|
|
abstract function storeBatch( $triplets, $flags = 0 );
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Pick a random name in the temp zone and store a file to it.
|
2007-07-22 14:45:12 +00:00
|
|
|
* Returns a FileRepoStatus object with the URL in the value.
|
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
* @param string $originalName The base name of the file as specified
|
2007-06-16 02:55:25 +00:00
|
|
|
* by the user. The file extension will be maintained.
|
|
|
|
|
* @param string $srcPath The current location of the file.
|
|
|
|
|
*/
|
|
|
|
|
abstract function storeTemp( $originalName, $srcPath );
|
|
|
|
|
|
2010-02-10 11:08:39 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Append the contents of the source path to the given file.
|
|
|
|
|
* @param $srcPath string location of the source file
|
|
|
|
|
* @param $toAppendPath string path to append to.
|
2010-02-22 02:15:30 +00:00
|
|
|
* @param $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
|
|
|
|
|
* that the source file should be deleted if possible
|
2010-02-10 11:08:39 +00:00
|
|
|
* @return mixed Status or false
|
|
|
|
|
*/
|
2010-02-22 12:24:50 +00:00
|
|
|
abstract function append( $srcPath, $toAppendPath, $flags = 0 );
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2007-06-16 02:55:25 +00:00
|
|
|
/**
|
|
|
|
|
* Remove a temporary file or mark it for garbage collection
|
|
|
|
|
* @param string $virtualUrl The virtual URL returned by storeTemp
|
|
|
|
|
* @return boolean True on success, false on failure
|
|
|
|
|
* STUB
|
|
|
|
|
*/
|
|
|
|
|
function freeTemp( $virtualUrl ) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Copy or move a file either from the local filesystem or from an mwrepo://
|
|
|
|
|
* virtual URL, into this repository at the specified destination location.
|
|
|
|
|
*
|
2007-07-22 14:45:12 +00:00
|
|
|
* Returns a FileRepoStatus object. On success, the value contains "new" or
|
2008-04-14 07:45:50 +00:00
|
|
|
* "archived", to indicate whether the file was new with that name.
|
2007-07-22 14:45:12 +00:00
|
|
|
*
|
2007-06-16 02:55:25 +00:00
|
|
|
* @param string $srcPath The source path or URL
|
|
|
|
|
* @param string $dstRel The destination relative path
|
|
|
|
|
* @param string $archiveRel The relative path where the existing file is to
|
|
|
|
|
* be archived, if there is one. Relative to the public zone root.
|
|
|
|
|
* @param integer $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
|
|
|
|
|
* that the source file should be deleted if possible
|
|
|
|
|
*/
|
2007-07-22 14:45:12 +00:00
|
|
|
function publish( $srcPath, $dstRel, $archiveRel, $flags = 0 ) {
|
|
|
|
|
$status = $this->publishBatch( array( array( $srcPath, $dstRel, $archiveRel ) ), $flags );
|
|
|
|
|
if ( $status->successCount == 0 ) {
|
|
|
|
|
$status->ok = false;
|
|
|
|
|
}
|
|
|
|
|
if ( isset( $status->value[0] ) ) {
|
|
|
|
|
$status->value = $status->value[0];
|
|
|
|
|
} else {
|
|
|
|
|
$status->value = false;
|
|
|
|
|
}
|
|
|
|
|
return $status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Publish a batch of files
|
|
|
|
|
* @param array $triplets (source,dest,archive) triplets as per publish()
|
|
|
|
|
* @param integer $flags Bitfield, may be FileRepo::DELETE_SOURCE to indicate
|
|
|
|
|
* that the source files should be deleted if possible
|
|
|
|
|
*/
|
|
|
|
|
abstract function publishBatch( $triplets, $flags = 0 );
|
|
|
|
|
|
2009-06-08 15:10:08 +00:00
|
|
|
function fileExists( $file, $flags = 0 ) {
|
|
|
|
|
$result = $this->fileExistsBatch( array( $file ), $flags );
|
2009-06-10 01:47:58 +00:00
|
|
|
return $result[0];
|
2009-06-08 15:10:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks existence of an array of files.
|
|
|
|
|
*
|
|
|
|
|
* @param array $files URLs (or paths) of files to check
|
|
|
|
|
* @param integer $flags Bitwise combination of the following flags:
|
|
|
|
|
* self::FILES_ONLY Mark file as existing only if it is a file (not directory)
|
|
|
|
|
* @return Either array of files and existence flags, or false
|
|
|
|
|
*/
|
|
|
|
|
abstract function fileExistsBatch( $files, $flags = 0 );
|
|
|
|
|
|
2007-07-22 14:45:12 +00:00
|
|
|
/**
|
|
|
|
|
* Move a group of files to the deletion archive.
|
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
* If no valid deletion archive is configured, this may either delete the
|
2007-07-22 14:45:12 +00:00
|
|
|
* file or throw an exception, depending on the preference of the repository.
|
|
|
|
|
*
|
|
|
|
|
* The overwrite policy is determined by the repository -- currently FSRepo
|
2008-04-14 07:45:50 +00:00
|
|
|
* assumes a naming scheme in the deleted zone based on content hash, as
|
2007-07-22 14:45:12 +00:00
|
|
|
* opposed to the public zone which is assumed to be unique.
|
|
|
|
|
*
|
2008-04-14 07:45:50 +00:00
|
|
|
* @param array $sourceDestPairs Array of source/destination pairs. Each element
|
2007-07-22 14:45:12 +00:00
|
|
|
* is a two-element array containing the source file path relative to the
|
2008-04-14 07:45:50 +00:00
|
|
|
* public root in the first element, and the archive file path relative
|
2007-07-22 14:45:12 +00:00
|
|
|
* to the deleted zone root in the second element.
|
|
|
|
|
* @return FileRepoStatus
|
|
|
|
|
*/
|
|
|
|
|
abstract function deleteBatch( $sourceDestPairs );
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Move a file to the deletion archive.
|
2008-04-14 07:45:50 +00:00
|
|
|
* If no valid deletion archive exists, this may either delete the file
|
2007-07-22 14:45:12 +00:00
|
|
|
* or throw an exception, depending on the preference of the repository
|
|
|
|
|
* @param mixed $srcRel Relative path for the file to be deleted
|
2008-04-14 07:45:50 +00:00
|
|
|
* @param mixed $archiveRel Relative path for the archive location.
|
2007-07-22 14:45:12 +00:00
|
|
|
* Relative to a private archive directory.
|
|
|
|
|
* @return WikiError object (wikitext-formatted), or true for success
|
|
|
|
|
*/
|
|
|
|
|
function delete( $srcRel, $archiveRel ) {
|
|
|
|
|
return $this->deleteBatch( array( array( $srcRel, $archiveRel ) ) );
|
|
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get properties of a file with a given virtual URL
|
|
|
|
|
* The virtual URL must refer to this repo
|
|
|
|
|
* Properties should ultimately be obtained via File::getPropsFromPath()
|
|
|
|
|
*/
|
|
|
|
|
abstract function getFileProps( $virtualUrl );
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Call a callback function for every file in the repository
|
|
|
|
|
* May use either the database or the filesystem
|
|
|
|
|
* STUB
|
|
|
|
|
*/
|
|
|
|
|
function enumFiles( $callback ) {
|
|
|
|
|
throw new MWException( 'enumFiles is not supported by ' . get_class( $this ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Determine if a relative path is valid, i.e. not blank or involving directory traveral
|
|
|
|
|
*/
|
|
|
|
|
function validateFilename( $filename ) {
|
|
|
|
|
if ( strval( $filename ) == '' ) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ( wfIsWindows() ) {
|
|
|
|
|
$filename = strtr( $filename, '\\', '/' );
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Use the same traversal protection as Title::secureAndSplit()
|
|
|
|
|
*/
|
|
|
|
|
if ( strpos( $filename, '.' ) !== false &&
|
|
|
|
|
( $filename === '.' || $filename === '..' ||
|
|
|
|
|
strpos( $filename, './' ) === 0 ||
|
|
|
|
|
strpos( $filename, '../' ) === 0 ||
|
|
|
|
|
strpos( $filename, '/./' ) !== false ||
|
|
|
|
|
strpos( $filename, '/../' ) !== false ) )
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-07-22 14:45:12 +00:00
|
|
|
|
|
|
|
|
/**#@+
|
|
|
|
|
* Path disclosure protection functions
|
|
|
|
|
*/
|
|
|
|
|
function paranoidClean( $param ) { return '[hidden]'; }
|
|
|
|
|
function passThrough( $param ) { return $param; }
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a callback function to use for cleaning error message parameters
|
|
|
|
|
*/
|
|
|
|
|
function getErrorCleanupFunction() {
|
|
|
|
|
switch ( $this->pathDisclosureProtection ) {
|
|
|
|
|
case 'none':
|
|
|
|
|
$callback = array( $this, 'passThrough' );
|
|
|
|
|
break;
|
|
|
|
|
default: // 'paranoid'
|
|
|
|
|
$callback = array( $this, 'paranoidClean' );
|
|
|
|
|
}
|
|
|
|
|
return $callback;
|
|
|
|
|
}
|
|
|
|
|
/**#@-*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new fatal error
|
|
|
|
|
*/
|
|
|
|
|
function newFatal( $message /*, parameters...*/ ) {
|
|
|
|
|
$params = func_get_args();
|
|
|
|
|
array_unshift( $params, $this );
|
|
|
|
|
return call_user_func_array( array( 'FileRepoStatus', 'newFatal' ), $params );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a new good result
|
|
|
|
|
*/
|
|
|
|
|
function newGood( $value = null ) {
|
|
|
|
|
return FileRepoStatus::newGood( $this, $value );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete files in the deleted directory if they are not referenced in the filearchive table
|
|
|
|
|
* STUB
|
|
|
|
|
*/
|
|
|
|
|
function cleanupDeletedBatch( $storageKeys ) {}
|
2008-01-16 18:27:43 +00:00
|
|
|
|
|
|
|
|
/**
|
2009-04-20 03:06:49 +00:00
|
|
|
* Checks if there is a redirect named as $title. If there is, return the
|
|
|
|
|
* title object. If not, return false.
|
|
|
|
|
* STUB
|
2008-01-16 18:27:43 +00:00
|
|
|
*
|
|
|
|
|
* @param Title $title Title of image
|
|
|
|
|
*/
|
|
|
|
|
function checkRedirect( $title ) {
|
2009-04-20 03:06:49 +00:00
|
|
|
return false;
|
2008-01-16 18:27:43 +00:00
|
|
|
}
|
2008-04-12 18:04:46 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Invalidates image redirect cache related to that image
|
2009-06-17 07:31:00 +00:00
|
|
|
* Doesn't do anything for repositories that don't support image redirects.
|
2010-02-10 10:36:11 +00:00
|
|
|
*
|
2009-06-17 07:31:00 +00:00
|
|
|
* STUB
|
2008-04-12 18:04:46 +00:00
|
|
|
* @param Title $title Title of image
|
2010-02-10 10:36:11 +00:00
|
|
|
*/
|
2009-06-17 07:31:00 +00:00
|
|
|
function invalidateImageRedirect( $title ) {}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
/**
|
2010-02-10 10:36:11 +00:00
|
|
|
* Get an array or iterator of file objects for files that have a given
|
2009-06-17 07:31:00 +00:00
|
|
|
* SHA-1 content hash.
|
|
|
|
|
*
|
|
|
|
|
* STUB
|
|
|
|
|
*/
|
2008-05-14 15:11:48 +00:00
|
|
|
function findBySha1( $hash ) {
|
|
|
|
|
return array();
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2009-02-17 22:27:10 +00:00
|
|
|
/**
|
2010-02-10 10:36:11 +00:00
|
|
|
* Get the human-readable name of the repo.
|
2009-02-17 22:27:10 +00:00
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public function getDisplayName() {
|
|
|
|
|
// We don't name our own repo, return nothing
|
|
|
|
|
if ( $this->name == 'local' ) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2009-02-17 22:34:22 +00:00
|
|
|
$repoName = wfMsg( 'shared-repo-name-' . $this->name );
|
|
|
|
|
if ( !wfEmptyMsg( 'shared-repo-name-' . $this->name, $repoName ) ) {
|
2009-02-17 22:27:10 +00:00
|
|
|
return $repoName;
|
|
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
return wfMsg( 'shared-repo' );
|
2009-02-17 22:27:10 +00:00
|
|
|
}
|
2010-02-10 10:36:11 +00:00
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get a key on the primary cache for this repository.
|
2010-02-10 10:36:11 +00:00
|
|
|
* Returns false if the repository's cache is not accessible at this site.
|
2009-06-17 07:31:00 +00:00
|
|
|
* The parameters are the parts of the key, as for wfMemcKey().
|
|
|
|
|
*
|
|
|
|
|
* STUB
|
|
|
|
|
*/
|
|
|
|
|
function getSharedCacheKey( /*...*/ ) {
|
|
|
|
|
return false;
|
2009-03-18 05:17:49 +00:00
|
|
|
}
|
2009-04-16 20:16:21 +00:00
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
/**
|
2010-02-10 10:36:11 +00:00
|
|
|
* Get a key for this repo in the local cache domain. These cache keys are
|
2009-06-17 07:31:00 +00:00
|
|
|
* not shared with remote instances of the repo.
|
|
|
|
|
* The parameters are the parts of the key, as for wfMemcKey().
|
|
|
|
|
*/
|
|
|
|
|
function getLocalCacheKey( /*...*/ ) {
|
|
|
|
|
$args = func_get_args();
|
|
|
|
|
array_unshift( $args, 'filerepo', $this->getName() );
|
|
|
|
|
return call_user_func_array( 'wfMemcKey', $args );
|
2009-04-16 20:16:21 +00:00
|
|
|
}
|
2007-06-16 02:55:25 +00:00
|
|
|
}
|