X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fupload%2FUploadStash.php;h=23a7a3a8fe46c0695a1178fad26161c78c3e5645;hb=1a8daf2c07e31337d83ee39b42873373023c8d40;hp=ad2196da7d3a35839e32422e10dceed0c34d0602;hpb=d51e149c763a166ad4d042c6a416e5f4ac938cb1;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/upload/UploadStash.php b/includes/upload/UploadStash.php index ad2196da7d..23a7a3a8fe 100644 --- a/includes/upload/UploadStash.php +++ b/includes/upload/UploadStash.php @@ -23,26 +23,35 @@ /** * UploadStash is intended to accomplish a few things: - * - enable applications to temporarily stash files without publishing them to the wiki. - * - Several parts of MediaWiki do this in similar ways: UploadBase, UploadWizard, and FirefoggChunkedExtension - * And there are several that reimplement stashing from scratch, in idiosyncratic ways. The idea is to unify them all here. - * Mostly all of them are the same except for storing some custom fields, which we subsume into the data array. - * - enable applications to find said files later, as long as the db table or temp files haven't been purged. - * - enable the uploading user (and *ONLY* the uploading user) to access said files, and thumbnails of said files, via a URL. - * We accomplish this using a database table, with ownership checking as you might expect. See SpecialUploadStash, which - * implements a web interface to some files stored this way. + * - Enable applications to temporarily stash files without publishing them to + * the wiki. + * - Several parts of MediaWiki do this in similar ways: UploadBase, + * UploadWizard, and FirefoggChunkedExtension. + * And there are several that reimplement stashing from scratch, in + * idiosyncratic ways. The idea is to unify them all here. + * Mostly all of them are the same except for storing some custom fields, + * which we subsume into the data array. + * - Enable applications to find said files later, as long as the db table or + * temp files haven't been purged. + * - Enable the uploading user (and *ONLY* the uploading user) to access said + * files, and thumbnails of said files, via a URL. We accomplish this using + * a database table, with ownership checking as you might expect. See + * SpecialUploadStash, which implements a web interface to some files stored + * this way. * - * UploadStash right now is *mostly* intended to show you one user's slice of the entire stash. The user parameter is only optional - * because there are few cases where we clean out the stash from an automated script. In the future we might refactor this. + * UploadStash right now is *mostly* intended to show you one user's slice of + * the entire stash. The user parameter is only optional because there are few + * cases where we clean out the stash from an automated script. In the future we + * might refactor this. * * UploadStash represents the entire stash of temporary files. * UploadStashFile is a filestore for the actual physical disk files. - * UploadFromStash extends UploadBase, and represents a single stashed file as it is moved from the stash to the regular file repository + * UploadFromStash extends UploadBase, and represents a single stashed file as + * it is moved from the stash to the regular file repository * * @ingroup Upload */ class UploadStash { - // Format of the key for files -- has to be suitable as a filename itself (e.g. ab12cd34ef.jpg) const KEY_FORMAT_REGEX = '/^[\w-\.]+\.\w*$/'; @@ -71,8 +80,8 @@ class UploadStash { * Designed to be compatible with the session stashing code in UploadBase * (should replace it eventually). * - * @param $repo FileRepo - * @param $user User (default null) + * @param FileRepo $repo + * @param User $user (default null) */ public function __construct( FileRepo $repo, $user = null ) { // this might change based on wiki's configuration. @@ -95,10 +104,11 @@ class UploadStash { /** * Get a file and its metadata from the stash. - * The noAuth param is a bit janky but is required for automated scripts which clean out the stash. + * The noAuth param is a bit janky but is required for automated scripts + * which clean out the stash. * - * @param string $key key under which file information is stored - * @param $noAuth Boolean (optional) Don't check authentication. Used by maintenance scripts. + * @param string $key Key under which file information is stored + * @param bool $noAuth (optional) Don't check authentication. Used by maintenance scripts. * @throws UploadStashFileNotFoundException * @throws UploadStashNotLoggedInException * @throws UploadStashWrongOwnerException @@ -106,7 +116,7 @@ class UploadStash { * @return UploadStashFile */ public function getFile( $key, $noAuth = false ) { - if ( ! preg_match( self::KEY_FORMAT_REGEX, $key ) ) { + if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) { throw new UploadStashBadPathException( "key '$key' is not in a proper format" ); } @@ -117,7 +127,8 @@ class UploadStash { if ( !isset( $this->fileMetadata[$key] ) ) { if ( !$this->fetchFileMetadata( $key ) ) { - // If nothing was received, it's likely due to replication lag. Check the master to see if the record is there. + // If nothing was received, it's likely due to replication lag. + // Check the master to see if the record is there. $this->fetchFileMetadata( $key, DB_MASTER ); } @@ -138,14 +149,15 @@ class UploadStash { } } - if ( ! $this->files[$key]->exists() ) { + if ( !$this->files[$key]->exists() ) { wfDebug( __METHOD__ . " tried to get file at $key, but it doesn't exist\n" ); throw new UploadStashBadPathException( "path doesn't exist" ); } if ( !$noAuth ) { if ( $this->fileMetadata[$key]['us_user'] != $this->userId ) { - throw new UploadStashWrongOwnerException( "This file ($key) doesn't belong to the current user." ); + throw new UploadStashWrongOwnerException( "This file ($key) doesn't " + . "belong to the current user." ); } } @@ -155,30 +167,34 @@ class UploadStash { /** * Getter for file metadata. * - * @param string $key key under which file information is stored - * @return Array + * @param string $key Key under which file information is stored + * @return array */ public function getMetadata( $key ) { $this->getFile( $key ); + return $this->fileMetadata[$key]; } /** * Getter for fileProps * - * @param string $key key under which file information is stored - * @return Array + * @param string $key Key under which file information is stored + * @return array */ public function getFileProps( $key ) { $this->getFile( $key ); + return $this->fileProps[$key]; } /** - * Stash a file in a temp directory and record that we did this in the database, along with other metadata. + * Stash a file in a temp directory and record that we did this in the + * database, along with other metadata. * * @param string $path Path to file you want stashed - * @param string $sourceType The type of upload that generated this file (currently, I believe, 'file' or null) + * @param string $sourceType The type of upload that generated this file + * (currently, I believe, 'file' or null) * @throws UploadStashBadPathException * @throws UploadStashFileException * @throws UploadStashNotLoggedInException @@ -201,10 +217,11 @@ class UploadStash { $pathWithGoodExtension = $path; } - // If no key was supplied, make one. a mysql insertid would be totally reasonable here, except - // that for historical reasons, the key is this random thing instead. At least it's not guessable. + // If no key was supplied, make one. a mysql insertid would be totally + // reasonable here, except that for historical reasons, the key is this + // random thing instead. At least it's not guessable. // - // some things that when combined will make a suitably unique key. + // Some things that when combined will make a suitably unique key. // see: http://www.jwz.org/doc/mid.html list( $usec, $sec ) = explode( ' ', microtime() ); $usec = substr( $usec, 2 ); @@ -215,7 +232,7 @@ class UploadStash { $this->fileProps[$key] = $fileProps; - if ( ! preg_match( self::KEY_FORMAT_REGEX, $key ) ) { + if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) { throw new UploadStashBadPathException( "key '$key' is not in a proper format" ); } @@ -224,30 +241,36 @@ class UploadStash { // if not already in a temporary area, put it there $storeStatus = $this->repo->storeTemp( basename( $pathWithGoodExtension ), $path ); - if ( ! $storeStatus->isOK() ) { - // It is a convention in MediaWiki to only return one error per API exception, even if multiple errors - // are available. We use reset() to pick the "first" thing that was wrong, preferring errors to warnings. - // This is a bit lame, as we may have more info in the $storeStatus and we're throwing it away, but to fix it means + if ( !$storeStatus->isOK() ) { + // It is a convention in MediaWiki to only return one error per API + // exception, even if multiple errors are available. We use reset() + // to pick the "first" thing that was wrong, preferring errors to + // warnings. This is a bit lame, as we may have more info in the + // $storeStatus and we're throwing it away, but to fix it means // redesigning API errors significantly. - // $storeStatus->value just contains the virtual URL (if anything) which is probably useless to the caller + // $storeStatus->value just contains the virtual URL (if anything) + // which is probably useless to the caller. $error = $storeStatus->getErrorsArray(); $error = reset( $error ); - if ( ! count( $error ) ) { + if ( !count( $error ) ) { $error = $storeStatus->getWarningsArray(); $error = reset( $error ); - if ( ! count( $error ) ) { + if ( !count( $error ) ) { $error = array( 'unknown', 'no error recorded' ); } } - // at this point, $error should contain the single "most important" error, plus any parameters. + // At this point, $error should contain the single "most important" + // error, plus any parameters. $errorMsg = array_shift( $error ); - throw new UploadStashFileException( "Error storing file in '$path': " . wfMessage( $errorMsg, $error )->text() ); + throw new UploadStashFileException( "Error storing file in '$path': " + . wfMessage( $errorMsg, $error )->text() ); } $stashPath = $storeStatus->value; // fetch the current user ID if ( !$this->isLoggedIn ) { - throw new UploadStashNotLoggedInException( __METHOD__ . ' No user is logged in, files must belong to users' ); + throw new UploadStashNotLoggedInException( __METHOD__ + . ' No user is logged in, files must belong to users' ); } // insert the file metadata into the db. @@ -279,7 +302,8 @@ class UploadStash { __METHOD__ ); - // store the insertid in the class variable so immediate retrieval (possibly laggy) isn't necesary. + // store the insertid in the class variable so immediate retrieval + // (possibly laggy) isn't necesary. $this->fileMetadata[$key]['us_id'] = $dbw->insertId(); # create the UploadStashFile object for this file. @@ -293,11 +317,12 @@ class UploadStash { * Does not clean up files in the repo, just the record of them. * * @throws UploadStashNotLoggedInException - * @return bool success + * @return bool Success */ public function clear() { if ( !$this->isLoggedIn ) { - throw new UploadStashNotLoggedInException( __METHOD__ . ' No user is logged in, files must belong to users' ); + throw new UploadStashNotLoggedInException( __METHOD__ + . ' No user is logged in, files must belong to users' ); } wfDebug( __METHOD__ . ' clearing all rows for user ' . $this->userId . "\n" ); @@ -319,18 +344,20 @@ class UploadStash { * Remove a particular file from the stash. Also removes it from the repo. * * @param string $key - * @throws UploadStashNoSuchKeyException|UploadStashNotLoggedInException|UploadStashWrongOwnerException + * @throws UploadStashNoSuchKeyException|UploadStashNotLoggedInException + * @throws UploadStashWrongOwnerException * @return bool Success */ public function removeFile( $key ) { if ( !$this->isLoggedIn ) { - throw new UploadStashNotLoggedInException( __METHOD__ . ' No user is logged in, files must belong to users' ); + throw new UploadStashNotLoggedInException( __METHOD__ + . ' No user is logged in, files must belong to users' ); } $dbw = $this->repo->getMasterDb(); - // this is a cheap query. it runs on the master so that this function still works when there's lag. - // it won't be called all that often. + // this is a cheap query. it runs on the master so that this function + // still works when there's lag. It won't be called all that often. $row = $dbw->selectRow( 'uploadstash', 'us_user', @@ -343,7 +370,8 @@ class UploadStash { } if ( $row->us_user != $this->userId ) { - throw new UploadStashWrongOwnerException( "Can't delete: the file ($key) doesn't belong to this user." ); + throw new UploadStashWrongOwnerException( "Can't delete: " + . "the file ($key) doesn't belong to this user." ); } return $this->removeFileNoAuth( $key ); @@ -369,8 +397,9 @@ class UploadStash { __METHOD__ ); - // TODO: look into UnregisteredLocalFile and find out why the rv here is sometimes wrong (false when file was removed) - // for now, ignore. + /** @todo Look into UnregisteredLocalFile and find out why the rv here is + * sometimes wrong (false when file was removed). For now, ignore. + */ $this->files[$key]->remove(); unset( $this->files[$key] ); @@ -383,11 +412,12 @@ class UploadStash { * List all files in the stash. * * @throws UploadStashNotLoggedInException - * @return Array + * @return array */ public function listFiles() { if ( !$this->isLoggedIn ) { - throw new UploadStashNotLoggedInException( __METHOD__ . ' No user is logged in, files must belong to users' ); + throw new UploadStashNotLoggedInException( __METHOD__ + . ' No user is logged in, files must belong to users' ); } $dbr = $this->repo->getSlaveDb(); @@ -418,7 +448,7 @@ class UploadStash { * with an extension. * XXX this is somewhat redundant with the checks that ApiUpload.php does with incoming * uploads versus the desired filename. Maybe we can get that passed to us... - * @param $path + * @param string $path * @throws UploadStashFileException * @return string */ @@ -451,6 +481,7 @@ class UploadStash { // put it in a web accesible directory. return ''; } + return $extension; } @@ -459,7 +490,7 @@ class UploadStash { * * @param string $key * @param int $readFromDB Constant (default: DB_SLAVE) - * @return boolean + * @return bool */ protected function fetchFileMetadata( $key, $readFromDB = DB_SLAVE ) { // populate $fileMetadata[$key] @@ -492,7 +523,7 @@ class UploadStash { /** * Helper function: Initialize the UploadStashFile for a given file. * - * @param string $key key under which to store the object + * @param string $key Key under which to store the object * @throws UploadStashZeroLengthFileException * @return bool */ @@ -502,6 +533,7 @@ class UploadStash { throw new UploadStashZeroLengthFileException( "File is zero length" ); } $this->files[$key] = $file; + return true; } } @@ -512,8 +544,10 @@ class UploadStashFile extends UnregisteredLocalFile { protected $url; /** - * A LocalFile wrapper around a file that has been temporarily stashed, so we can do things like create thumbnails for it - * Arguably UnregisteredLocalFile should be handling its own file repo but that class is a bit retarded currently + * A LocalFile wrapper around a file that has been temporarily stashed, + * so we can do things like create thumbnails for it. Arguably + * UnregisteredLocalFile should be handling its own file repo but that + * class is a bit retarded currently. * * @param FileRepo $repo Repository where we should find the path * @param string $path Path to file @@ -528,18 +562,21 @@ class UploadStashFile extends UnregisteredLocalFile { if ( $repo->isVirtualUrl( $path ) ) { $path = $repo->resolveVirtualUrl( $path ); } else { - - // check if path appears to be sane, no parent traversals, and is in this repo's temp zone. + // check if path appears to be sane, no parent traversals, + // and is in this repo's temp zone. $repoTempPath = $repo->getZonePath( 'temp' ); - if ( ( ! $repo->validateFilename( $path ) ) || - ( strpos( $path, $repoTempPath ) !== 0 ) ) { - wfDebug( "UploadStash: tried to construct an UploadStashFile from a file that should already exist at '$path', but path is not valid\n" ); + if ( ( !$repo->validateFilename( $path ) ) || + ( strpos( $path, $repoTempPath ) !== 0 ) + ) { + wfDebug( "UploadStash: tried to construct an UploadStashFile " + . "from a file that should already exist at '$path', but path is not valid\n" ); throw new UploadStashBadPathException( 'path is not valid' ); } // check if path exists! and is a plain file. - if ( ! $repo->fileExists( $path ) ) { - wfDebug( "UploadStash: tried to construct an UploadStashFile from a file that should already exist at '$path', but path is not found\n" ); + if ( !$repo->fileExists( $path ) ) { + wfDebug( "UploadStash: tried to construct an UploadStashFile from " + . "a file that should already exist at '$path', but path is not found\n" ); throw new UploadStashFileNotFoundException( 'cannot find path, or not a plain file' ); } } @@ -552,8 +589,8 @@ class UploadStashFile extends UnregisteredLocalFile { /** * A method needed by the file transforming and scaling routines in File.php * We do not necessarily care about doing the description at this point - * However, we also can't return the empty string, as the rest of MediaWiki demands this (and calls to imagemagick - * convert require it to be there) + * However, we also can't return the empty string, as the rest of MediaWiki + * demands this (and calls to imagemagick convert require it to be there) * * @return string Dummy value */ @@ -566,14 +603,17 @@ class UploadStashFile extends UnregisteredLocalFile { * The actual argument is the result of thumbName although we seem to have * buggy code elsewhere that expects a boolean 'suffix' * - * @param string $thumbName Name of thumbnail (e.g. "120px-123456.jpg" ), or false to just get the path - * @return string Path thumbnail should take on filesystem, or containing directory if thumbname is false + * @param string $thumbName Name of thumbnail (e.g. "120px-123456.jpg" ), + * or false to just get the path + * @return string Path thumbnail should take on filesystem, or containing + * directory if thumbname is false */ public function getThumbPath( $thumbName = false ) { $path = dirname( $this->path ); if ( $thumbName !== false ) { $path .= "/$thumbName"; } + return $path; } @@ -591,7 +631,8 @@ class UploadStashFile extends UnregisteredLocalFile { } /** - * Helper function -- given a 'subpage', return the local URL e.g. /wiki/Special:UploadStash/subpage + * Helper function -- given a 'subpage', return the local URL, + * e.g. /wiki/Special:UploadStash/subpage * @param string $subPage * @return string Local URL for this subpage in the Special:UploadStash space. */ @@ -602,14 +643,16 @@ class UploadStashFile extends UnregisteredLocalFile { /** * Get a URL to access the thumbnail * This is required because the model of how files work requires that - * the thumbnail urls be predictable. However, in our model the URL is not based on the filename - * (that's hidden in the db) + * the thumbnail urls be predictable. However, in our model the URL is + * not based on the filename (that's hidden in the db) * - * @param string $thumbName Basename of thumbnail file -- however, we don't want to use the file exactly + * @param string $thumbName Basename of thumbnail file -- however, we don't + * want to use the file exactly * @return string URL to access thumbnail, or URL with partial path */ public function getThumbUrl( $thumbName = false ) { wfDebug( __METHOD__ . " getting for $thumbName \n" ); + return $this->getSpecialUrl( 'thumb/' . $this->getUrlName() . '/' . $thumbName ); } @@ -620,9 +663,10 @@ class UploadStashFile extends UnregisteredLocalFile { * @return string Base url name, like '120px-123456.jpg' */ public function getUrlName() { - if ( ! $this->urlName ) { + if ( !$this->urlName ) { $this->urlName = $this->fileKey; } + return $this->urlName; } @@ -636,12 +680,14 @@ class UploadStashFile extends UnregisteredLocalFile { if ( !isset( $this->url ) ) { $this->url = $this->getSpecialUrl( 'file/' . $this->getUrlName() ); } + return $this->url; } /** - * Parent classes use this method, for no obvious reason, to return the path (relative to wiki root, I assume). - * But with this class, the URL is unrelated to the path. + * Parent classes use this method, for no obvious reason, to return the path + * (relative to wiki root, I assume). But with this class, the URL is + * unrelated to the path. * * @return string Url */ @@ -650,7 +696,8 @@ class UploadStashFile extends UnregisteredLocalFile { } /** - * Getter for file key (the unique id by which this file's location & metadata is stored in the db) + * Getter for file key (the unique id by which this file's location & + * metadata is stored in the db) * * @return string File key */ @@ -674,15 +721,32 @@ class UploadStashFile extends UnregisteredLocalFile { public function exists() { return $this->repo->fileExists( $this->path ); } +} + +class UploadStashException extends MWException { +} + +class UploadStashNotAvailableException extends UploadStashException { +} + +class UploadStashFileNotFoundException extends UploadStashException { +} + +class UploadStashBadPathException extends UploadStashException { +} + +class UploadStashFileException extends UploadStashException { +} + +class UploadStashZeroLengthFileException extends UploadStashException { +} + +class UploadStashNotLoggedInException extends UploadStashException { +} + +class UploadStashWrongOwnerException extends UploadStashException { +} +class UploadStashNoSuchKeyException extends UploadStashException { } -class UploadStashException extends MWException {}; -class UploadStashNotAvailableException extends UploadStashException {}; -class UploadStashFileNotFoundException extends UploadStashException {}; -class UploadStashBadPathException extends UploadStashException {}; -class UploadStashFileException extends UploadStashException {}; -class UploadStashZeroLengthFileException extends UploadStashException {}; -class UploadStashNotLoggedInException extends UploadStashException {}; -class UploadStashWrongOwnerException extends UploadStashException {}; -class UploadStashNoSuchKeyException extends UploadStashException {};