2007-05-30 21:02:32 +00:00
|
|
|
<?php
|
2010-09-04 18:13:18 +00:00
|
|
|
/**
|
|
|
|
|
* Local repository that stores files in the local filesystem and registers them
|
|
|
|
|
* in the wiki's own database.
|
|
|
|
|
*
|
2012-05-07 07:11:33 +00:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
|
*
|
2010-09-04 18:13:18 +00:00
|
|
|
* @file
|
|
|
|
|
* @ingroup FileRepo
|
|
|
|
|
*/
|
|
|
|
|
|
2007-05-30 21:02:32 +00:00
|
|
|
/**
|
|
|
|
|
* A repository that stores files in the local filesystem and registers them
|
|
|
|
|
* in the wiki's own database. This is the most commonly used repository class.
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
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-05-30 21:02:32 +00:00
|
|
|
*/
|
2011-12-20 03:52:06 +00:00
|
|
|
class LocalRepo extends FileRepo {
|
2013-12-04 16:18:05 +00:00
|
|
|
/** @var array */
|
2013-11-24 09:44:10 +00:00
|
|
|
protected $fileFactory = array( 'LocalFile', 'newFromTitle' );
|
2013-12-04 16:18:05 +00:00
|
|
|
|
|
|
|
|
/** @var array */
|
2013-11-24 09:44:10 +00:00
|
|
|
protected $fileFactoryKey = array( 'LocalFile', 'newFromKey' );
|
2013-12-04 16:18:05 +00:00
|
|
|
|
|
|
|
|
/** @var array */
|
2013-11-24 09:44:10 +00:00
|
|
|
protected $fileFromRowFactory = array( 'LocalFile', 'newFromRow' );
|
2013-12-04 16:18:05 +00:00
|
|
|
|
|
|
|
|
/** @var array */
|
2013-11-29 16:47:43 +00:00
|
|
|
protected $oldFileFromRowFactory = array( 'OldLocalFile', 'newFromRow' );
|
2013-12-04 16:18:05 +00:00
|
|
|
|
|
|
|
|
/** @var array */
|
2013-11-24 09:44:10 +00:00
|
|
|
protected $oldFileFactory = array( 'OldLocalFile', 'newFromTitle' );
|
2013-12-04 16:18:05 +00:00
|
|
|
|
|
|
|
|
/** @var array */
|
2013-11-24 09:44:10 +00:00
|
|
|
protected $oldFileFactoryKey = array( 'OldLocalFile', 'newFromKey' );
|
2007-05-30 21:02:32 +00:00
|
|
|
|
2011-03-07 14:59:41 +00:00
|
|
|
/**
|
|
|
|
|
* @throws MWException
|
2013-12-04 16:18:05 +00:00
|
|
|
* @param array $row
|
2012-05-10 07:55:33 +00:00
|
|
|
* @return LocalFile
|
2011-03-07 14:59:41 +00:00
|
|
|
*/
|
2007-05-30 21:02:32 +00:00
|
|
|
function newFileFromRow( $row ) {
|
|
|
|
|
if ( isset( $row->img_name ) ) {
|
2008-05-30 13:16:08 +00:00
|
|
|
return call_user_func( $this->fileFromRowFactory, $row, $this );
|
2007-05-30 21:02:32 +00:00
|
|
|
} elseif ( isset( $row->oi_name ) ) {
|
2008-05-30 13:16:08 +00:00
|
|
|
return call_user_func( $this->oldFileFromRowFactory, $row, $this );
|
2007-05-30 21:02:32 +00:00
|
|
|
} else {
|
2013-04-13 11:36:24 +00:00
|
|
|
throw new MWException( __METHOD__ . ': invalid row' );
|
2007-05-30 21:02:32 +00:00
|
|
|
}
|
|
|
|
|
}
|
2008-04-14 07:45:50 +00:00
|
|
|
|
2011-05-28 18:59:42 +00:00
|
|
|
/**
|
2013-12-04 16:18:05 +00:00
|
|
|
* @param Title $title
|
|
|
|
|
* @param string $archiveName
|
2011-05-28 18:59:42 +00:00
|
|
|
* @return OldLocalFile
|
|
|
|
|
*/
|
2007-05-31 00:35:07 +00:00
|
|
|
function newFromArchiveName( $title, $archiveName ) {
|
|
|
|
|
return OldLocalFile::newFromArchiveName( $title, $this, $archiveName );
|
|
|
|
|
}
|
2007-07-22 14:45:12 +00:00
|
|
|
|
|
|
|
|
/**
|
2008-04-14 07:45:50 +00:00
|
|
|
* Delete files in the deleted directory if they are not referenced in the
|
|
|
|
|
* filearchive table. This needs to be done in the repo because it needs to
|
|
|
|
|
* interleave database locks with file operations, which is potentially a
|
2007-07-22 14:45:12 +00:00
|
|
|
* remote operation.
|
2011-05-29 14:24:27 +00:00
|
|
|
*
|
2013-12-04 16:18:05 +00:00
|
|
|
* @param array $storageKeys
|
2011-05-29 14:24:27 +00:00
|
|
|
*
|
2007-07-22 14:45:12 +00:00
|
|
|
* @return FileRepoStatus
|
|
|
|
|
*/
|
2012-04-05 04:10:50 +00:00
|
|
|
function cleanupDeletedBatch( array $storageKeys ) {
|
2011-12-20 03:52:06 +00:00
|
|
|
$backend = $this->backend; // convenience
|
2007-07-22 14:45:12 +00:00
|
|
|
$root = $this->getZonePath( 'deleted' );
|
|
|
|
|
$dbw = $this->getMasterDB();
|
|
|
|
|
$status = $this->newGood();
|
2011-05-29 14:24:27 +00:00
|
|
|
$storageKeys = array_unique( $storageKeys );
|
2007-07-22 14:45:12 +00:00
|
|
|
foreach ( $storageKeys as $key ) {
|
|
|
|
|
$hashPath = $this->getDeletedHashPath( $key );
|
|
|
|
|
$path = "$root/$hashPath$key";
|
2012-02-24 17:00:52 +00:00
|
|
|
$dbw->begin( __METHOD__ );
|
2011-10-15 17:07:53 +00:00
|
|
|
// Check for usage in deleted/hidden files and pre-emptively
|
|
|
|
|
// lock the key to avoid any future use until we are finished.
|
|
|
|
|
$deleted = $this->deletedFileHasKey( $key, 'lock' );
|
|
|
|
|
$hidden = $this->hiddenFileHasKey( $key, 'lock' );
|
|
|
|
|
if ( !$deleted && !$hidden ) { // not in use now
|
2007-07-23 17:22:09 +00:00
|
|
|
wfDebug( __METHOD__ . ": deleting $key\n" );
|
2011-12-20 03:52:06 +00:00
|
|
|
$op = array( 'op' => 'delete', 'src' => $path );
|
|
|
|
|
if ( !$backend->doOperation( $op )->isOK() ) {
|
2007-07-23 17:22:09 +00:00
|
|
|
$status->error( 'undelete-cleanup-error', $path );
|
|
|
|
|
$status->failCount++;
|
|
|
|
|
}
|
2007-07-22 14:45:12 +00:00
|
|
|
} else {
|
2007-07-23 17:22:09 +00:00
|
|
|
wfDebug( __METHOD__ . ": $key still in use\n" );
|
2007-07-22 14:45:12 +00:00
|
|
|
$status->successCount++;
|
|
|
|
|
}
|
2012-02-24 17:00:52 +00:00
|
|
|
$dbw->commit( __METHOD__ );
|
2007-07-22 14:45:12 +00:00
|
|
|
}
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2007-07-22 14:45:12 +00:00
|
|
|
return $status;
|
|
|
|
|
}
|
2011-03-06 20:05:41 +00:00
|
|
|
|
2011-10-15 17:07:53 +00:00
|
|
|
/**
|
|
|
|
|
* Check if a deleted (filearchive) file has this sha1 key
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $key File storage key (base-36 sha1 key with file extension)
|
|
|
|
|
* @param string|null $lock Use "lock" to lock the row via FOR UPDATE
|
2011-10-15 17:07:53 +00:00
|
|
|
* @return bool File with this key is in use
|
|
|
|
|
*/
|
|
|
|
|
protected function deletedFileHasKey( $key, $lock = null ) {
|
|
|
|
|
$options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array();
|
|
|
|
|
|
|
|
|
|
$dbw = $this->getMasterDB();
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2011-10-15 17:07:53 +00:00
|
|
|
return (bool)$dbw->selectField( 'filearchive', '1',
|
|
|
|
|
array( 'fa_storage_group' => 'deleted', 'fa_storage_key' => $key ),
|
|
|
|
|
__METHOD__, $options
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if a hidden (revision delete) file has this sha1 key
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $key File storage key (base-36 sha1 key with file extension)
|
|
|
|
|
* @param string|null $lock Use "lock" to lock the row via FOR UPDATE
|
2011-10-15 17:07:53 +00:00
|
|
|
* @return bool File with this key is in use
|
|
|
|
|
*/
|
|
|
|
|
protected function hiddenFileHasKey( $key, $lock = null ) {
|
|
|
|
|
$options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array();
|
|
|
|
|
|
|
|
|
|
$sha1 = self::getHashFromKey( $key );
|
|
|
|
|
$ext = File::normalizeExtension( substr( $key, strcspn( $key, '.' ) + 1 ) );
|
|
|
|
|
|
|
|
|
|
$dbw = $this->getMasterDB();
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2011-10-15 17:07:53 +00:00
|
|
|
return (bool)$dbw->selectField( 'oldimage', '1',
|
|
|
|
|
array( 'oi_sha1' => $sha1,
|
|
|
|
|
'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(), ".$ext" ),
|
|
|
|
|
$dbw->bitAnd( 'oi_deleted', File::DELETED_FILE ) => File::DELETED_FILE ),
|
2012-01-01 23:31:20 +00:00
|
|
|
__METHOD__, $options
|
2011-10-15 17:07:53 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-06 20:05:41 +00:00
|
|
|
/**
|
|
|
|
|
* Gets the SHA1 hash from a storage key
|
|
|
|
|
*
|
|
|
|
|
* @param string $key
|
|
|
|
|
* @return string
|
|
|
|
|
*/
|
|
|
|
|
public static function getHashFromKey( $key ) {
|
|
|
|
|
return strtok( $key, '.' );
|
|
|
|
|
}
|
2012-05-10 07:55:33 +00:00
|
|
|
|
2009-04-20 03:06:49 +00:00
|
|
|
/**
|
|
|
|
|
* Checks if there is a redirect named as $title
|
|
|
|
|
*
|
2013-12-04 16:18:05 +00:00
|
|
|
* @param Title $title Title of file
|
2011-11-17 03:14:05 +00:00
|
|
|
* @return bool
|
2009-04-20 03:06:49 +00:00
|
|
|
*/
|
2011-11-04 23:49:03 +00:00
|
|
|
function checkRedirect( Title $title ) {
|
2009-04-20 03:06:49 +00:00
|
|
|
global $wgMemc;
|
|
|
|
|
|
2011-11-04 23:49:03 +00:00
|
|
|
$title = File::normalizeTitle( $title, 'exception' );
|
2009-04-20 03:06:49 +00:00
|
|
|
|
2009-10-06 20:23:12 +00:00
|
|
|
$memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
|
2009-06-17 07:31:00 +00:00
|
|
|
if ( $memcKey === false ) {
|
2009-10-06 20:23:12 +00:00
|
|
|
$memcKey = $this->getLocalCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
|
2009-06-17 07:31:00 +00:00
|
|
|
$expiry = 300; // no invalidation, 5 minutes
|
|
|
|
|
} else {
|
|
|
|
|
$expiry = 86400; // has invalidation, 1 day
|
|
|
|
|
}
|
2009-04-20 03:06:49 +00:00
|
|
|
$cachedValue = $wgMemc->get( $memcKey );
|
2013-03-07 16:50:43 +00:00
|
|
|
if ( $cachedValue === ' ' || $cachedValue === '' ) {
|
2009-06-17 07:31:00 +00:00
|
|
|
// Does not exist
|
2009-04-20 03:06:49 +00:00
|
|
|
return false;
|
2013-08-07 20:26:52 +00:00
|
|
|
} elseif ( strval( $cachedValue ) !== '' && $cachedValue !== ' PURGED' ) {
|
2009-10-06 20:23:12 +00:00
|
|
|
return Title::newFromText( $cachedValue, NS_FILE );
|
2009-06-17 07:31:00 +00:00
|
|
|
} // else $cachedValue is false or null: cache miss
|
2009-04-20 03:06:49 +00:00
|
|
|
|
|
|
|
|
$id = $this->getArticleID( $title );
|
2013-04-20 17:18:13 +00:00
|
|
|
if ( !$id ) {
|
2013-08-07 20:26:52 +00:00
|
|
|
$wgMemc->add( $memcKey, " ", $expiry );
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2009-04-20 03:06:49 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
$dbr = $this->getSlaveDB();
|
|
|
|
|
$row = $dbr->selectRow(
|
|
|
|
|
'redirect',
|
|
|
|
|
array( 'rd_title', 'rd_namespace' ),
|
|
|
|
|
array( 'rd_from' => $id ),
|
|
|
|
|
__METHOD__
|
|
|
|
|
);
|
|
|
|
|
|
2013-04-20 17:18:13 +00:00
|
|
|
if ( $row && $row->rd_namespace == NS_FILE ) {
|
2009-06-17 07:31:00 +00:00
|
|
|
$targetTitle = Title::makeTitle( $row->rd_namespace, $row->rd_title );
|
2013-08-07 20:26:52 +00:00
|
|
|
$wgMemc->add( $memcKey, $targetTitle->getDBkey(), $expiry );
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
return $targetTitle;
|
|
|
|
|
} else {
|
2013-08-07 20:26:52 +00:00
|
|
|
$wgMemc->add( $memcKey, '', $expiry );
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2009-04-20 03:06:49 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-16 18:27:43 +00:00
|
|
|
/**
|
|
|
|
|
* Function link Title::getArticleID().
|
|
|
|
|
* We can't say Title object, what database it should use, so we duplicate that function here.
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
2013-12-04 16:18:05 +00:00
|
|
|
* @param Title $title
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return bool|int|mixed
|
2008-01-16 18:27:43 +00:00
|
|
|
*/
|
2008-04-06 10:18:47 +00:00
|
|
|
protected function getArticleID( $title ) {
|
2013-04-20 17:18:13 +00:00
|
|
|
if ( !$title instanceof Title ) {
|
2008-01-16 18:27:43 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
$dbr = $this->getSlaveDB();
|
|
|
|
|
$id = $dbr->selectField(
|
2011-12-20 03:52:06 +00:00
|
|
|
'page', // Table
|
2013-02-03 19:42:08 +00:00
|
|
|
'page_id', //Field
|
|
|
|
|
array( //Conditions
|
2008-01-16 18:27:43 +00:00
|
|
|
'page_namespace' => $title->getNamespace(),
|
2009-05-24 08:29:10 +00:00
|
|
|
'page_title' => $title->getDBkey(),
|
2008-01-16 18:27:43 +00:00
|
|
|
),
|
2013-03-07 16:50:43 +00:00
|
|
|
__METHOD__ //Function name
|
2008-01-16 18:27:43 +00:00
|
|
|
);
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2008-01-16 18:27:43 +00:00
|
|
|
return $id;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-05 21:40:14 +00:00
|
|
|
public function findFiles( array $items, $flags = 0 ) {
|
2013-11-27 18:39:50 +00:00
|
|
|
$finalFiles = array(); // map of (DB key => corresponding File) for matches
|
|
|
|
|
|
2013-12-09 20:24:32 +00:00
|
|
|
$searchSet = array(); // map of (normalized DB key => search params)
|
2013-11-27 18:39:50 +00:00
|
|
|
foreach ( $items as $item ) {
|
2013-12-09 20:24:32 +00:00
|
|
|
if ( is_array( $item ) ) {
|
|
|
|
|
$title = File::normalizeTitle( $item['title'] );
|
|
|
|
|
if ( $title ) {
|
|
|
|
|
$searchSet[$title->getDBkey()] = $item;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$title = File::normalizeTitle( $item );
|
|
|
|
|
if ( $title ) {
|
|
|
|
|
$searchSet[$title->getDBkey()] = array();
|
|
|
|
|
}
|
2013-11-27 18:39:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-05 11:02:29 +00:00
|
|
|
$fileMatchesSearch = function ( File $file, array $search ) {
|
2013-11-27 18:39:50 +00:00
|
|
|
// Note: file name comparison done elsewhere (to handle redirects)
|
2014-01-17 16:42:45 +00:00
|
|
|
$user = ( !empty( $search['private'] ) && $search['private'] instanceof User )
|
|
|
|
|
? $search['private']
|
|
|
|
|
: null;
|
2014-02-05 11:02:29 +00:00
|
|
|
|
2013-11-27 18:39:50 +00:00
|
|
|
return (
|
|
|
|
|
$file->exists() &&
|
|
|
|
|
(
|
|
|
|
|
( empty( $search['time'] ) && !$file->isOld() ) ||
|
|
|
|
|
( !empty( $search['time'] ) && $search['time'] === $file->getTimestamp() )
|
|
|
|
|
) &&
|
|
|
|
|
( !empty( $search['private'] ) || !$file->isDeleted( File::DELETED_FILE ) ) &&
|
2014-01-17 16:42:45 +00:00
|
|
|
$file->userCan( File::DELETED_FILE, $user )
|
2013-11-27 18:39:50 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$repo = $this;
|
2014-02-05 11:02:29 +00:00
|
|
|
$applyMatchingFiles = function ( ResultWrapper $res, &$searchSet, &$finalFiles )
|
2013-12-05 21:40:14 +00:00
|
|
|
use ( $repo, $fileMatchesSearch, $flags )
|
2013-11-27 18:39:50 +00:00
|
|
|
{
|
2013-12-17 21:09:21 +00:00
|
|
|
global $wgContLang;
|
|
|
|
|
$info = $repo->getInfo();
|
2013-11-27 18:39:50 +00:00
|
|
|
foreach ( $res as $row ) {
|
2013-12-05 21:40:14 +00:00
|
|
|
$file = $repo->newFileFromRow( $row );
|
2013-12-17 21:09:21 +00:00
|
|
|
// There must have been a search for this DB key, but this has to handle the
|
|
|
|
|
// cases were title capitalization is different on the client and repo wikis.
|
|
|
|
|
$dbKeysLook = array( str_replace( ' ', '_', $file->getName() ) );
|
|
|
|
|
if ( !empty( $info['initialCapital'] ) ) {
|
|
|
|
|
// Search keys for "hi.png" and "Hi.png" should use the "Hi.png file"
|
|
|
|
|
$dbKeysLook[] = $wgContLang->lcfirst( $file->getName() );
|
|
|
|
|
}
|
|
|
|
|
foreach ( $dbKeysLook as $dbKey ) {
|
2014-02-05 11:02:29 +00:00
|
|
|
if ( isset( $searchSet[$dbKey] )
|
2013-12-17 21:09:21 +00:00
|
|
|
&& $fileMatchesSearch( $file, $searchSet[$dbKey] )
|
|
|
|
|
) {
|
|
|
|
|
$finalFiles[$dbKey] = ( $flags & FileRepo::NAME_AND_TIME_ONLY )
|
|
|
|
|
? array( 'title' => $dbKey, 'timestamp' => $file->getTimestamp() )
|
|
|
|
|
: $file;
|
|
|
|
|
unset( $searchSet[$dbKey] );
|
|
|
|
|
}
|
2013-11-27 18:39:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
$dbr = $this->getSlaveDB();
|
|
|
|
|
|
|
|
|
|
// Query image table
|
2013-12-09 20:24:32 +00:00
|
|
|
$imgNames = array();
|
|
|
|
|
foreach ( array_keys( $searchSet ) as $dbKey ) {
|
|
|
|
|
$imgNames[] = $this->getNameFromTitle( File::normalizeTitle( $dbKey ) );
|
|
|
|
|
}
|
2014-02-05 11:02:29 +00:00
|
|
|
|
2013-11-27 18:39:50 +00:00
|
|
|
if ( count( $imgNames ) ) {
|
|
|
|
|
$res = $dbr->select( 'image',
|
|
|
|
|
LocalFile::selectFields(), array( 'img_name' => $imgNames ), __METHOD__ );
|
|
|
|
|
$applyMatchingFiles( $res, $searchSet, $finalFiles );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Query old image table
|
|
|
|
|
$oiConds = array(); // WHERE clause array for each file
|
|
|
|
|
foreach ( $searchSet as $dbKey => $search ) {
|
2014-01-17 16:42:01 +00:00
|
|
|
if ( isset( $search['time'] ) ) {
|
2013-12-09 20:24:32 +00:00
|
|
|
$oiConds[] = $dbr->makeList(
|
|
|
|
|
array(
|
|
|
|
|
'oi_name' => $this->getNameFromTitle( File::normalizeTitle( $dbKey ) ),
|
2014-01-17 16:42:01 +00:00
|
|
|
'oi_timestamp' => $dbr->timestamp( $search['time'] )
|
2013-12-09 20:24:32 +00:00
|
|
|
),
|
|
|
|
|
LIST_AND
|
|
|
|
|
);
|
2013-11-27 18:39:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-02-05 11:02:29 +00:00
|
|
|
|
2013-11-27 18:39:50 +00:00
|
|
|
if ( count( $oiConds ) ) {
|
|
|
|
|
$res = $dbr->select( 'oldimage',
|
|
|
|
|
OldLocalFile::selectFields(), $dbr->makeList( $oiConds, LIST_OR ), __METHOD__ );
|
|
|
|
|
$applyMatchingFiles( $res, $searchSet, $finalFiles );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for redirects...
|
|
|
|
|
foreach ( $searchSet as $dbKey => $search ) {
|
|
|
|
|
if ( !empty( $search['ignoreRedirect'] ) ) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2014-02-05 11:02:29 +00:00
|
|
|
|
2013-11-27 18:39:50 +00:00
|
|
|
$title = File::normalizeTitle( $dbKey );
|
|
|
|
|
$redir = $this->checkRedirect( $title ); // hopefully hits memcached
|
2014-02-05 11:02:29 +00:00
|
|
|
|
2013-11-27 18:39:50 +00:00
|
|
|
if ( $redir && $redir->getNamespace() == NS_FILE ) {
|
2013-12-05 21:40:14 +00:00
|
|
|
$file = $this->newFile( $redir );
|
|
|
|
|
if ( $file && $fileMatchesSearch( $file, $search ) ) {
|
|
|
|
|
$file->redirectedFrom( $title->getDBkey() );
|
2013-12-09 20:24:32 +00:00
|
|
|
if ( $flags & FileRepo::NAME_AND_TIME_ONLY ) {
|
|
|
|
|
$finalFiles[$dbKey] = array(
|
2014-02-05 11:02:29 +00:00
|
|
|
'title' => $file->getTitle()->getDBkey(),
|
2013-12-09 20:24:32 +00:00
|
|
|
'timestamp' => $file->getTimestamp()
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
$finalFiles[$dbKey] = $file;
|
|
|
|
|
}
|
2013-11-27 18:39:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $finalFiles;
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
/**
|
2012-02-01 20:53:38 +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.
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param string $hash a sha1 hash to look for
|
2013-12-04 16:18:05 +00:00
|
|
|
* @return array
|
2009-06-17 07:31:00 +00:00
|
|
|
*/
|
2008-05-14 15:11:48 +00:00
|
|
|
function findBySha1( $hash ) {
|
|
|
|
|
$dbr = $this->getSlaveDB();
|
|
|
|
|
$res = $dbr->select(
|
|
|
|
|
'image',
|
|
|
|
|
LocalFile::selectFields(),
|
2012-06-22 22:40:20 +00:00
|
|
|
array( 'img_sha1' => $hash ),
|
2012-07-08 08:45:21 +00:00
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'img_name' )
|
2008-05-14 15:11:48 +00:00
|
|
|
);
|
2012-10-19 20:03:05 +00:00
|
|
|
|
2008-05-14 15:11:48 +00:00
|
|
|
$result = array();
|
2010-10-13 23:11:40 +00:00
|
|
|
foreach ( $res as $row ) {
|
2008-05-14 15:11:48 +00:00
|
|
|
$result[] = $this->newFileFromRow( $row );
|
2010-10-13 23:11:40 +00:00
|
|
|
}
|
2010-11-06 11:30:21 +00:00
|
|
|
$res->free();
|
2010-10-13 23:11:40 +00:00
|
|
|
|
2008-05-14 15:11:48 +00:00
|
|
|
return $result;
|
|
|
|
|
}
|
2009-06-17 07:31:00 +00:00
|
|
|
|
2012-07-23 16:45:38 +00:00
|
|
|
/**
|
|
|
|
|
* Get an array of arrays or iterators of file objects for files that
|
|
|
|
|
* have the given SHA-1 content hashes.
|
|
|
|
|
*
|
|
|
|
|
* Overrides generic implementation in FileRepo for performance reason
|
|
|
|
|
*
|
2013-03-11 17:15:01 +00:00
|
|
|
* @param array $hashes An array of hashes
|
2012-07-23 16:45:38 +00:00
|
|
|
* @return array An Array of arrays or iterators of file objects and the hash as key
|
|
|
|
|
*/
|
|
|
|
|
function findBySha1s( array $hashes ) {
|
2013-04-20 17:18:13 +00:00
|
|
|
if ( !count( $hashes ) ) {
|
2012-07-23 16:45:38 +00:00
|
|
|
return array(); //empty parameter
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$dbr = $this->getSlaveDB();
|
|
|
|
|
$res = $dbr->select(
|
|
|
|
|
'image',
|
|
|
|
|
LocalFile::selectFields(),
|
|
|
|
|
array( 'img_sha1' => $hashes ),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
array( 'ORDER BY' => 'img_name' )
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$result = array();
|
|
|
|
|
foreach ( $res as $row ) {
|
|
|
|
|
$file = $this->newFileFromRow( $row );
|
|
|
|
|
$result[$file->getSha1()][] = $file;
|
|
|
|
|
}
|
|
|
|
|
$res->free();
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-13 11:36:24 +00:00
|
|
|
/**
|
|
|
|
|
* Return an array of files where the name starts with $prefix.
|
|
|
|
|
*
|
|
|
|
|
* @param string $prefix The prefix to search for
|
|
|
|
|
* @param int $limit The maximum amount of files to return
|
|
|
|
|
* @return array
|
|
|
|
|
*/
|
2013-02-06 20:15:07 +00:00
|
|
|
public function findFilesByPrefix( $prefix, $limit ) {
|
|
|
|
|
$selectOptions = array( 'ORDER BY' => 'img_name', 'LIMIT' => intval( $limit ) );
|
|
|
|
|
|
2013-04-13 11:36:24 +00:00
|
|
|
// Query database
|
2013-02-06 20:15:07 +00:00
|
|
|
$dbr = $this->getSlaveDB();
|
|
|
|
|
$res = $dbr->select(
|
|
|
|
|
'image',
|
|
|
|
|
LocalFile::selectFields(),
|
|
|
|
|
'img_name ' . $dbr->buildLike( $prefix, $dbr->anyString() ),
|
|
|
|
|
__METHOD__,
|
|
|
|
|
$selectOptions
|
2013-11-23 20:00:11 +00:00
|
|
|
);
|
2013-02-06 20:15:07 +00:00
|
|
|
|
|
|
|
|
// Build file objects
|
|
|
|
|
$files = array();
|
|
|
|
|
foreach ( $res as $row ) {
|
|
|
|
|
$files[] = $this->newFileFromRow( $row );
|
|
|
|
|
}
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2013-04-13 11:36:24 +00:00
|
|
|
return $files;
|
2013-02-06 20:15:07 +00:00
|
|
|
}
|
|
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
/**
|
|
|
|
|
* Get a connection to the slave DB
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return DatabaseBase
|
2009-06-17 07:31:00 +00:00
|
|
|
*/
|
|
|
|
|
function getSlaveDB() {
|
|
|
|
|
return wfGetDB( DB_SLAVE );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a connection to the master DB
|
2012-02-09 21:33:27 +00:00
|
|
|
* @return DatabaseBase
|
2009-06-17 07:31:00 +00:00
|
|
|
*/
|
|
|
|
|
function getMasterDB() {
|
|
|
|
|
return wfGetDB( DB_MASTER );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a key on the primary cache for this repository.
|
2012-10-19 20:03:05 +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().
|
2011-12-20 03:52:06 +00:00
|
|
|
*
|
2011-11-17 03:14:05 +00:00
|
|
|
* @return string
|
2009-06-17 07:31:00 +00:00
|
|
|
*/
|
|
|
|
|
function getSharedCacheKey( /*...*/ ) {
|
|
|
|
|
$args = func_get_args();
|
2013-11-23 20:00:11 +00:00
|
|
|
|
2009-06-17 07:31:00 +00:00
|
|
|
return call_user_func_array( 'wfMemcKey', $args );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Invalidates image redirect cache related to that image
|
|
|
|
|
*
|
2013-12-04 16:18:05 +00:00
|
|
|
* @param Title $title Title of page
|
2012-01-12 19:41:18 +00:00
|
|
|
* @return void
|
2010-03-26 21:55:13 +00:00
|
|
|
*/
|
2011-11-04 23:33:53 +00:00
|
|
|
function invalidateImageRedirect( Title $title ) {
|
2009-06-17 07:31:00 +00:00
|
|
|
global $wgMemc;
|
2009-10-06 20:23:12 +00:00
|
|
|
$memcKey = $this->getSharedCacheKey( 'image_redirect', md5( $title->getDBkey() ) );
|
2009-06-17 07:31:00 +00:00
|
|
|
if ( $memcKey ) {
|
2013-08-07 20:26:52 +00:00
|
|
|
// Set a temporary value for the cache key, to ensure
|
|
|
|
|
// that this value stays purged long enough so that
|
|
|
|
|
// it isn't refreshed with a stale value due to a
|
|
|
|
|
// lagged slave.
|
|
|
|
|
$wgMemc->set( $memcKey, ' PURGED', 12 );
|
2009-06-17 07:31:00 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-01-15 20:38:11 +00:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return information about the repository.
|
|
|
|
|
*
|
|
|
|
|
* @return array
|
|
|
|
|
* @since 1.22
|
|
|
|
|
*/
|
|
|
|
|
function getInfo() {
|
|
|
|
|
global $wgFavicon;
|
2014-02-05 11:02:29 +00:00
|
|
|
|
2014-01-15 20:38:11 +00:00
|
|
|
return array_merge( parent::getInfo(), array(
|
|
|
|
|
'favicon' => wfExpandUrl( $wgFavicon ),
|
|
|
|
|
) );
|
|
|
|
|
}
|
2007-05-30 21:02:32 +00:00
|
|
|
}
|