diff options
Diffstat (limited to 'includes/filerepo/LocalRepo.php')
-rw-r--r-- | includes/filerepo/LocalRepo.php | 195 |
1 files changed, 177 insertions, 18 deletions
diff --git a/includes/filerepo/LocalRepo.php b/includes/filerepo/LocalRepo.php index 9b62243b..926fd0b8 100644 --- a/includes/filerepo/LocalRepo.php +++ b/includes/filerepo/LocalRepo.php @@ -29,16 +29,27 @@ * @ingroup FileRepo */ class LocalRepo extends FileRepo { - var $fileFactory = array( 'LocalFile' , 'newFromTitle' ); - var $fileFactoryKey = array( 'LocalFile' , 'newFromKey' ); - var $fileFromRowFactory = array( 'LocalFile' , 'newFromRow' ); - var $oldFileFactory = array( 'OldLocalFile', 'newFromTitle' ); - var $oldFileFactoryKey = array( 'OldLocalFile', 'newFromKey' ); - var $oldFileFromRowFactory = array( 'OldLocalFile', 'newFromRow' ); + /** @var array */ + protected $fileFactory = array( 'LocalFile', 'newFromTitle' ); + + /** @var array */ + protected $fileFactoryKey = array( 'LocalFile', 'newFromKey' ); + + /** @var array */ + protected $fileFromRowFactory = array( 'LocalFile', 'newFromRow' ); + + /** @var array */ + protected $oldFileFromRowFactory = array( 'OldLocalFile', 'newFromRow' ); + + /** @var array */ + protected $oldFileFactory = array( 'OldLocalFile', 'newFromTitle' ); + + /** @var array */ + protected $oldFileFactoryKey = array( 'OldLocalFile', 'newFromKey' ); /** * @throws MWException - * @param $row + * @param stdClass $row * @return LocalFile */ function newFileFromRow( $row ) { @@ -52,8 +63,8 @@ class LocalRepo extends FileRepo { } /** - * @param $title - * @param $archiveName + * @param Title $title + * @param string $archiveName * @return OldLocalFile */ function newFromArchiveName( $title, $archiveName ) { @@ -66,7 +77,7 @@ class LocalRepo extends FileRepo { * interleave database locks with file operations, which is potentially a * remote operation. * - * @param $storageKeys array + * @param array $storageKeys * * @return FileRepoStatus */ @@ -80,7 +91,7 @@ class LocalRepo extends FileRepo { $hashPath = $this->getDeletedHashPath( $key ); $path = "$root/$hashPath$key"; $dbw->begin( __METHOD__ ); - // Check for usage in deleted/hidden files and pre-emptively + // Check for usage in deleted/hidden files and preemptively // lock the key to avoid any future use until we are finished. $deleted = $this->deletedFileHasKey( $key, 'lock' ); $hidden = $this->hiddenFileHasKey( $key, 'lock' ); @@ -97,6 +108,7 @@ class LocalRepo extends FileRepo { } $dbw->commit( __METHOD__ ); } + return $status; } @@ -111,6 +123,7 @@ class LocalRepo extends FileRepo { $options = ( $lock === 'lock' ) ? array( 'FOR UPDATE' ) : array(); $dbw = $this->getMasterDB(); + return (bool)$dbw->selectField( 'filearchive', '1', array( 'fa_storage_group' => 'deleted', 'fa_storage_key' => $key ), __METHOD__, $options @@ -131,6 +144,7 @@ class LocalRepo extends FileRepo { $ext = File::normalizeExtension( substr( $key, strcspn( $key, '.' ) + 1 ) ); $dbw = $this->getMasterDB(); + return (bool)$dbw->selectField( 'oldimage', '1', array( 'oi_sha1' => $sha1, 'oi_archive_name ' . $dbw->buildLike( $dbw->anyString(), ".$ext" ), @@ -152,8 +166,8 @@ class LocalRepo extends FileRepo { /** * Checks if there is a redirect named as $title * - * @param $title Title of file - * @return bool + * @param Title $title Title of file + * @return bool|Title */ function checkRedirect( Title $title ) { global $wgMemc; @@ -178,6 +192,7 @@ class LocalRepo extends FileRepo { $id = $this->getArticleID( $title ); if ( !$id ) { $wgMemc->add( $memcKey, " ", $expiry ); + return false; } $dbr = $this->getSlaveDB(); @@ -191,9 +206,11 @@ class LocalRepo extends FileRepo { if ( $row && $row->rd_namespace == NS_FILE ) { $targetTitle = Title::makeTitle( $row->rd_namespace, $row->rd_title ); $wgMemc->add( $memcKey, $targetTitle->getDBkey(), $expiry ); + return $targetTitle; } else { $wgMemc->add( $memcKey, '', $expiry ); + return false; } } @@ -202,7 +219,7 @@ class LocalRepo extends FileRepo { * Function link Title::getArticleID(). * We can't say Title object, what database it should use, so we duplicate that function here. * - * @param $title Title + * @param Title $title * @return bool|int|mixed */ protected function getArticleID( $title ) { @@ -219,15 +236,141 @@ class LocalRepo extends FileRepo { ), __METHOD__ //Function name ); + return $id; } + public function findFiles( array $items, $flags = 0 ) { + $finalFiles = array(); // map of (DB key => corresponding File) for matches + + $searchSet = array(); // map of (normalized DB key => search params) + foreach ( $items as $item ) { + 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(); + } + } + } + + $fileMatchesSearch = function ( File $file, array $search ) { + // Note: file name comparison done elsewhere (to handle redirects) + $user = ( !empty( $search['private'] ) && $search['private'] instanceof User ) + ? $search['private'] + : null; + + return ( + $file->exists() && + ( + ( empty( $search['time'] ) && !$file->isOld() ) || + ( !empty( $search['time'] ) && $search['time'] === $file->getTimestamp() ) + ) && + ( !empty( $search['private'] ) || !$file->isDeleted( File::DELETED_FILE ) ) && + $file->userCan( File::DELETED_FILE, $user ) + ); + }; + + $repo = $this; + $applyMatchingFiles = function ( ResultWrapper $res, &$searchSet, &$finalFiles ) + use ( $repo, $fileMatchesSearch, $flags ) + { + global $wgContLang; + $info = $repo->getInfo(); + foreach ( $res as $row ) { + $file = $repo->newFileFromRow( $row ); + // 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 ) { + if ( isset( $searchSet[$dbKey] ) + && $fileMatchesSearch( $file, $searchSet[$dbKey] ) + ) { + $finalFiles[$dbKey] = ( $flags & FileRepo::NAME_AND_TIME_ONLY ) + ? array( 'title' => $dbKey, 'timestamp' => $file->getTimestamp() ) + : $file; + unset( $searchSet[$dbKey] ); + } + } + } + }; + + $dbr = $this->getSlaveDB(); + + // Query image table + $imgNames = array(); + foreach ( array_keys( $searchSet ) as $dbKey ) { + $imgNames[] = $this->getNameFromTitle( File::normalizeTitle( $dbKey ) ); + } + + 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 ) { + if ( isset( $search['time'] ) ) { + $oiConds[] = $dbr->makeList( + array( + 'oi_name' => $this->getNameFromTitle( File::normalizeTitle( $dbKey ) ), + 'oi_timestamp' => $dbr->timestamp( $search['time'] ) + ), + LIST_AND + ); + } + } + + 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; + } + + $title = File::normalizeTitle( $dbKey ); + $redir = $this->checkRedirect( $title ); // hopefully hits memcached + + if ( $redir && $redir->getNamespace() == NS_FILE ) { + $file = $this->newFile( $redir ); + if ( $file && $fileMatchesSearch( $file, $search ) ) { + $file->redirectedFrom( $title->getDBkey() ); + if ( $flags & FileRepo::NAME_AND_TIME_ONLY ) { + $finalFiles[$dbKey] = array( + 'title' => $file->getTitle()->getDBkey(), + 'timestamp' => $file->getTimestamp() + ); + } else { + $finalFiles[$dbKey] = $file; + } + } + } + } + + return $finalFiles; + } + /** * Get an array or iterator of file objects for files that have a given * SHA-1 content hash. * - * @param string $hash a sha1 hash to look for - * @return Array + * @param string $hash A sha1 hash to look for + * @return File[] */ function findBySha1( $hash ) { $dbr = $this->getSlaveDB(); @@ -299,13 +442,14 @@ class LocalRepo extends FileRepo { 'img_name ' . $dbr->buildLike( $prefix, $dbr->anyString() ), __METHOD__, $selectOptions - ); + ); // Build file objects $files = array(); foreach ( $res as $row ) { $files[] = $this->newFileFromRow( $row ); } + return $files; } @@ -334,13 +478,14 @@ class LocalRepo extends FileRepo { */ function getSharedCacheKey( /*...*/ ) { $args = func_get_args(); + return call_user_func_array( 'wfMemcKey', $args ); } /** * Invalidates image redirect cache related to that image * - * @param $title Title of page + * @param Title $title Title of page * @return void */ function invalidateImageRedirect( Title $title ) { @@ -354,4 +499,18 @@ class LocalRepo extends FileRepo { $wgMemc->set( $memcKey, ' PURGED', 12 ); } } + + /** + * Return information about the repository. + * + * @return array + * @since 1.22 + */ + function getInfo() { + global $wgFavicon; + + return array_merge( parent::getInfo(), array( + 'favicon' => wfExpandUrl( $wgFavicon ), + ) ); + } } |