X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Ffilerepo%2FFile.php;h=1469668e87800bb64f4f9bb727cbf909ad2ed6ad;hb=fa9f92d21a4d5514a9ebd1e200e72fd572288e64;hp=78157223234be730cf4c4094d31433bd607cb97d;hpb=81fac3246dafcc6ecb3725a2bf375bb86266d7a3;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/filerepo/File.php b/includes/filerepo/File.php index 7815722323..1469668e87 100644 --- a/includes/filerepo/File.php +++ b/includes/filerepo/File.php @@ -17,7 +17,7 @@ * The convenience functions wfLocalFile() and wfFindFile() should be sufficient * in most cases. * - * @addtogroup FileRepo + * @ingroup FileRepo */ abstract class File { const DELETED_FILE = 1; @@ -46,7 +46,7 @@ abstract class File { /** * The following member variables are not lazy-initialised */ - var $repo, $title, $lastError, $redirected; + var $repo, $title, $lastError, $redirected, $redirectedTitle; /** * Call this constructor from child classes @@ -79,7 +79,8 @@ abstract class File { 'htm' => 'html', 'jpeg' => 'jpg', 'mpeg' => 'mpg', - 'tiff' => 'tif' ); + 'tiff' => 'tif', + 'ogv' => 'ogg' ); if( isset( $squish[$lower] ) ) { return $squish[$lower]; } elseif( preg_match( '/^[0-9a-z]+$/', $lower ) ) { @@ -89,6 +90,21 @@ abstract class File { } } + /** + * Checks if file extensions are compatible + * + * @param $old File Old file + * @param $new string New name + */ + static function checkExtensionCompatibility( File $old, $new ) { + $oldMime = $old->getMimeType(); + $n = strrpos( $new, '.' ); + $newExt = self::normalizeExtension( + $n ? substr( $new, $n + 1 ) : '' ); + $mimeMagic = MimeMagic::singleton(); + return $mimeMagic->isMatchingExtension( $newExt, $oldMime ); + } + /** * Upgrade the database row if there is one * Called by ImagePage @@ -137,6 +153,15 @@ abstract class File { * Return the associated title object */ public function getTitle() { return $this->title; } + + /** + * Return the title used to find this file + */ + public function getOriginalTitle() { + if ( $this->redirected ) + return $this->getRedirectedTitle(); + return $this->title; + } /** * Return the URL of the file @@ -152,7 +177,8 @@ abstract class File { * Return a fully-qualified URL to the file. * Upload URL paths _may or may not_ be fully qualified, so * we check. Local paths are assumed to belong on $wgServer. - * @return string + * + * @return String */ public function getFullUrl() { return wfExpandUrl( $this->getUrl() ); @@ -239,7 +265,14 @@ abstract class File { * Overridden by LocalFile, UnregisteredLocalFile * STUB */ - function getMetadata() { return false; } + public function getMetadata() { return false; } + + /** + * Return the bit depth of the file + * Overridden by LocalFile + * STUB + */ + public function getBitDepth() { return 0; } /** * Return the size of the image file, in bytes @@ -405,26 +438,21 @@ abstract class File { /** * Get a ThumbnailImage which is the same size as the source */ - function getUnscaledThumb( $page = false ) { + function getUnscaledThumb( $handlerParams = array() ) { + $hp =& $handlerParams; + $page = isset( $hp['page'] ) ? $hp['page'] : false; $width = $this->getWidth( $page ); if ( !$width ) { return $this->iconThumb(); } - if ( $page ) { - $params = array( - 'page' => $page, - 'width' => $this->getWidth( $page ) - ); - } else { - $params = array( 'width' => $this->getWidth() ); - } - return $this->transform( $params ); + $hp['width'] = $width; + return $this->transform( $hp ); } /** * Return the file name of a thumbnail with the specified parameters * - * @param array $params Handler-specific parameters + * @param $params Array: handler-specific parameters * @private -ish */ function thumbName( $params ) { @@ -432,7 +460,7 @@ abstract class File { return null; } $extension = $this->getExtension(); - list( $thumbExt, $thumbMime ) = $this->handler->getThumbType( $extension, $this->getMimeType() ); + list( $thumbExt, $thumbMime ) = $this->handler->getThumbType( $extension, $this->getMimeType(), $params ); $thumbName = $this->handler->makeParamString( $params ) . '-' . $this->getName(); if ( $thumbExt != $extension ) { $thumbName .= ".$thumbExt"; @@ -452,8 +480,8 @@ abstract class File { * specified, the generated image will be no bigger than width x height, * and will also have correct aspect ratio. * - * @param integer $width maximum width of the generated thumbnail - * @param integer $height maximum height of the image (optional) + * @param $width Integer: maximum width of the generated thumbnail + * @param $height Integer: maximum height of the image (optional) */ public function createThumb( $width, $height = -1 ) { $params = array( 'width' => $width ); @@ -468,14 +496,13 @@ abstract class File { /** * As createThumb, but returns a ThumbnailImage object. This can * provide access to the actual file, the real size of the thumb, - * and can produce a convenient tag for you. + * and can produce a convenient \ tag for you. * * For non-image formats, this may return a filetype-specific icon. * - * @param integer $width maximum width of the generated thumbnail - * @param integer $height maximum height of the image (optional) - * @param boolean $render True to render the thumbnail if it doesn't exist, - * false to just return the URL + * @param $width Integer: maximum width of the generated thumbnail + * @param $height Integer: maximum height of the image (optional) + * @param $render Integer: Deprecated * * @return ThumbnailImage or null on failure * @@ -486,20 +513,19 @@ abstract class File { if ( $height != -1 ) { $params['height'] = $height; } - $flags = $render ? self::RENDER_NOW : 0; - return $this->transform( $params, $flags ); + return $this->transform( $params, 0 ); } /** * Transform a media file * - * @param array $params An associative array of handler-specific parameters. Typical - * keys are width, height and page. - * @param integer $flags A bitfield, may contain self::RENDER_NOW to force rendering + * @param $params Array: an associative array of handler-specific parameters. + * Typical keys are width, height and page. + * @param $flags Integer: a bitfield, may contain self::RENDER_NOW to force rendering * @return MediaTransformOutput */ function transform( $params, $flags = 0 ) { - global $wgUseSquid, $wgIgnoreImageErrors; + global $wgUseSquid, $wgIgnoreImageErrors, $wgThumbnailEpoch, $wgServer; wfProfileIn( __METHOD__ ); do { @@ -509,6 +535,12 @@ abstract class File { break; } + // Get the descriptionUrl to embed it as comment into the thumbnail. Bug 19791. + $descriptionUrl = $this->getDescriptionUrl(); + if ( $descriptionUrl ) { + $params['descriptionUrl'] = $wgServer . $descriptionUrl; + } + $script = $this->getTransformScript(); if ( $script && !($flags & self::RENDER_NOW) ) { // Use a script to transform on client request, if possible @@ -531,9 +563,14 @@ abstract class File { wfDebug( __METHOD__.": Doing stat for $thumbPath\n" ); $this->migrateThumbFile( $thumbName ); - if ( file_exists( $thumbPath ) ) { - $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); - break; + if ( file_exists( $thumbPath )) { + $thumbTime = filemtime( $thumbPath ); + if ( $thumbTime !== FALSE && + gmdate( 'YmdHis', $thumbTime ) >= $wgThumbnailEpoch ) { + + $thumb = $this->handler->getTransform( $this, $thumbPath, $thumbUrl, $params ); + break; + } } $thumb = $this->handler->doTransform( $this, $thumbPath, $thumbUrl, $params ); @@ -550,13 +587,13 @@ abstract class File { // Purge. Useful in the event of Core -> Squid connection failure or squid // purge collisions from elsewhere during failure. Don't keep triggering for // "thumbs" which have the main image URL though (bug 13776) - if ( $wgUseSquid && !$thumb->isError() && $thumb->getUrl() != $this->getURL() ) { + if ( $wgUseSquid && ( !$thumb || $thumb->isError() || $thumb->getUrl() != $this->getURL()) ) { SquidUpdate::purge( array( $thumbUrl ) ); } } while (false); wfProfileOut( __METHOD__ ); - return $thumb; + return is_object( $thumb ) ? $thumb : false; } /** @@ -653,9 +690,10 @@ abstract class File { * @param $limit integer Limit of rows to return * @param $start timestamp Only revisions older than $start will be returned * @param $end timestamp Only revisions newer than $end will be returned + * @param $inc bool Include the endpoints of the time range */ - function getHistory($limit = null, $start = null, $end = null) { - return false; + function getHistory($limit = null, $start = null, $end = null, $inc=true) { + return array(); } /** @@ -715,15 +753,6 @@ abstract class File { return $path; } - /** Get relative path for a thumbnail file */ - function getThumbRel( $suffix = false ) { - $path = 'thumb/' . $this->getRel(); - if ( $suffix !== false ) { - $path .= '/' . $suffix; - } - return $path; - } - /** Get the path of the archive directory, or a particular file if $suffix is specified */ function getArchivePath( $suffix = false ) { return $this->repo->getZonePath('public') . '/' . $this->getArchiveRel( $suffix ); @@ -731,7 +760,11 @@ abstract class File { /** Get the path of the thumbnail directory, or a particular file if $suffix is specified */ function getThumbPath( $suffix = false ) { - return $this->repo->getZonePath('public') . '/' . $this->getThumbRel( $suffix ); + $path = $this->repo->getZonePath('thumb') . '/' . $this->getRel(); + if ( $suffix !== false ) { + $path .= '/' . $suffix; + } + return $path; } /** Get the URL of the archive directory, or a particular file if $suffix is specified */ @@ -747,7 +780,7 @@ abstract class File { /** Get the URL of the thumbnail directory, or a particular file if $suffix is specified */ function getThumbUrl( $suffix = false ) { - $path = $this->repo->getZoneUrl('public') . '/thumb/' . $this->getUrlRel(); + $path = $this->repo->getZoneUrl('thumb') . '/' . $this->getUrlRel(); if ( $suffix !== false ) { $path .= '/' . rawurlencode( $suffix ); } @@ -767,7 +800,7 @@ abstract class File { /** Get the virtual URL for a thumbnail file or directory */ function getThumbVirtualUrl( $suffix = false ) { - $path = $this->repo->getVirtualUrl() . '/public/thumb/' . $this->getUrlRel(); + $path = $this->repo->getVirtualUrl() . '/thumb/' . $this->getUrlRel(); if ( $suffix !== false ) { $path .= '/' . rawurlencode( $suffix ); } @@ -805,19 +838,18 @@ abstract class File { /** * Move or copy a file to its public location. If a file exists at the - * destination, move it to an archive. Returns the archive name on success - * or an empty string if it was a new file, and a wikitext-formatted - * WikiError object on failure. + * destination, move it to an archive. Returns a FileRepoStatus object with + * the archive name in the "value" member on success. * * The archive name should be passed through to recordUpload for database * registration. * - * @param string $sourcePath Local filesystem path to the source image - * @param integer $flags A bitwise combination of: + * @param $srcPath String: local filesystem path to the source image + * @param $flags Integer: a bitwise combination of: * File::DELETE_SOURCE Delete the source file, i.e. move * rather than copy - * @return The archive name on success or an empty string if it was a new - * file, and a wikitext-formatted WikiError object on failure. + * @return FileRepoStatus object. On success, the value member contains the + * archive name, or an empty string if it was a new file. * * STUB * Overridden by LocalFile @@ -834,28 +866,29 @@ abstract class File { * * @deprecated Use HTMLCacheUpdate, this function uses too much memory */ - function getLinksTo( $options = '' ) { + function getLinksTo( $options = array() ) { wfProfileIn( __METHOD__ ); // Note: use local DB not repo DB, we want to know local links - if ( $options ) { + if ( count( $options ) > 0 ) { $db = wfGetDB( DB_MASTER ); } else { $db = wfGetDB( DB_SLAVE ); } $linkCache = LinkCache::singleton(); - list( $page, $imagelinks ) = $db->tableNamesN( 'page', 'imagelinks' ); $encName = $db->addQuotes( $this->getName() ); - $sql = "SELECT page_namespace,page_title,page_id,page_len,page_is_redirect, - FROM $page,$imagelinks WHERE page_id=il_from AND il_to=$encName $options"; - $res = $db->query( $sql, __METHOD__ ); + $res = $db->select( array( 'page', 'imagelinks'), + array( 'page_namespace', 'page_title', 'page_id', 'page_len', 'page_is_redirect', 'page_latest' ), + array( 'page_id' => 'il_from', 'il_to' => $encName ), + __METHOD__, + $options ); $retVal = array(); if ( $db->numRows( $res ) ) { while ( $row = $db->fetchObject( $res ) ) { if ( $titleObj = Title::newFromRow( $row ) ) { - $linkCache->addGoodLinkObj( $row->page_id, $titleObj, $row->page_len, $row->page_is_redirect ); + $linkCache->addGoodLinkObj( $row->page_id, $titleObj, $row->page_len, $row->page_is_redirect, $row->page_latest ); $retVal[] = $titleObj; } } @@ -878,7 +911,8 @@ abstract class File { * @return bool */ function isLocal() { - return $this->getRepoName() == 'local'; + $repo = $this->getRepo(); + return $repo && $repo->isLocal(); } /** @@ -889,6 +923,12 @@ abstract class File { function getRepoName() { return $this->repo ? $this->repo->getName() : 'unknown'; } + /* + * Returns the repository + */ + function getRepo() { + return $this->repo; + } /** * Returns true if the image is an old version @@ -905,6 +945,14 @@ abstract class File { function isDeleted( $field ) { return false; } + + /** + * Return the deletion bitfield + * STUB + */ + function getVisibility() { + return 0; + } /** * Was this file ever deleted from the wiki? @@ -913,9 +961,25 @@ abstract class File { */ function wasDeleted() { $title = $this->getTitle(); - return $title && $title->isDeleted() > 0; + return $title && $title->isDeletedQuick(); } + /** + * Move file to the new title + * + * Move current, old version and all thumbnails + * to the new filename. Old file is deleted. + * + * Cache purging is done; checks for validity + * and logging are caller's responsibility + * + * @param $target Title New file name + * @return FileRepoStatus object. + */ + function move( $target ) { + $this->readOnlyError(); + } + /** * Delete all versions of the file. * @@ -924,8 +988,8 @@ abstract class File { * * Cache purging is done; logging is caller's responsibility. * - * @param $reason - * @param $suppress, hide content from sysops? + * @param $reason String + * @param $suppress Boolean: hide content from sysops? * @return true on success, false on some kind of failure * STUB * Overridden by LocalFile @@ -942,7 +1006,7 @@ abstract class File { * * @param $versions set of record ids of deleted items to restore, * or empty to restore all revisions. - * @param $unsuppress, remove restrictions on content upon restoration? + * @param $unsuppress remove restrictions on content upon restoration? * @return the number of file revisions restored if successful, * or false on failure * STUB @@ -953,8 +1017,9 @@ abstract class File { } /** - * Returns 'true' if this image is a multipage document, e.g. a DJVU - * document. + * Returns 'true' if this file is a type which supports multiple pages, + * e.g. DJVU or PDF. Note that this may be true even if the file in + * question only has a single page. * * @return Bool */ @@ -990,11 +1055,11 @@ abstract class File { } /** - * Get an image size array like that returned by getimagesize(), or false if it + * Get an image size array like that returned by getImageSize(), or false if it * can't be determined. * - * @param string $fileName The filename - * @return array + * @param $fileName String: The filename + * @return Array */ function getImageSize( $fileName ) { if ( !$this->getHandler() ) { @@ -1015,13 +1080,29 @@ abstract class File { * Get the HTML text of the description page, if available */ function getDescriptionText() { + global $wgMemc, $wgLang; if ( !$this->repo->fetchDescription ) { return false; } - $renderUrl = $this->repo->getDescriptionRenderUrl( $this->getName() ); + $renderUrl = $this->repo->getDescriptionRenderUrl( $this->getName(), $wgLang->getCode() ); if ( $renderUrl ) { + if ( $this->repo->descriptionCacheExpiry > 0 ) { + wfDebug("Attempting to get the description from cache..."); + $key = $this->repo->getLocalCacheKey( 'RemoteFileDescription', 'url', $wgLang->getCode(), + $this->getName() ); + $obj = $wgMemc->get($key); + if ($obj) { + wfDebug("success!\n"); + return $obj; + } + wfDebug("miss\n"); + } wfDebug( "Fetching shared description from $renderUrl\n" ); - return Http::get( $renderUrl ); + $res = Http::get( $renderUrl ); + if ( $res && $this->repo->descriptionCacheExpiry > 0 ) { + $wgMemc->set( $key, $res, $this->repo->descriptionCacheExpiry ); + } + return $res; } else { return false; } @@ -1054,12 +1135,25 @@ abstract class File { return self::sha1Base36( $this->getPath() ); } + /** + * Get the deletion archive key, . + */ + function getStorageKey() { + $hash = $this->getSha1(); + if ( !$hash ) { + return false; + } + $ext = $this->getExtension(); + $dotExt = $ext === '' ? '' : ".$ext"; + return $hash . $dotExt; + } + /** * Determine if the current user is allowed to view a particular * field of this file, if it's marked as deleted. * STUB - * @param int $field - * @return bool + * @param $field Integer + * @return Boolean */ function userCan( $field ) { return true; @@ -1068,9 +1162,9 @@ abstract class File { /** * Get an associative array containing information about a file in the local filesystem. * - * @param string $path Absolute local filesystem path - * @param mixed $ext The file extension, or true to extract it from the filename. - * Set it to false to ignore the extension. + * @param $path String: absolute local filesystem path + * @param $ext Mixed: the file extension, or true to extract it from the filename. + * Set it to false to ignore the extension. */ static function getPropsFromPath( $path, $ext = true ) { wfProfileIn( __METHOD__ ); @@ -1103,7 +1197,7 @@ abstract class File { wfDebug(__METHOD__.": $path loaded, {$info['size']} bytes, {$info['mime']}.\n"); } else { - $info['mime'] = NULL; + $info['mime'] = null; $info['media_type'] = MEDIATYPE_UNKNOWN; $info['metadata'] = ''; $info['sha1'] = ''; @@ -1152,7 +1246,7 @@ abstract class File { if ( $handler ) { return $handler->getLongDesc( $this ); } else { - return MediaHandler::getLongDesc( $this ); + return MediaHandler::getGeneralLongDesc( $this ); } } @@ -1161,7 +1255,7 @@ abstract class File { if ( $handler ) { return $handler->getShortDesc( $this ); } else { - return MediaHandler::getShortDesc( $this ); + return MediaHandler::getGeneralShortDesc( $this ); } } @@ -1177,10 +1271,22 @@ abstract class File { function getRedirected() { return $this->redirected; } + + function getRedirectedTitle() { + if ( $this->redirected ) { + if ( !$this->redirectTitle ) + $this->redirectTitle = Title::makeTitle( NS_FILE, $this->redirected ); + return $this->redirectTitle; + } + } function redirectedFrom( $from ) { $this->redirected = $from; } + + function isMissing() { + return false; + } } /** * Aliases for backwards compatibility with 1.6