Index: branches/uploadwizard/phase3/includes/upload/UploadFromFileToStash.php |
— | — | @@ -18,7 +18,11 @@ |
19 | 19 | * Instead, we store it in the SessionStash, and return metadata about the file |
20 | 20 | * We also create a thumbnail, which is visible only to the uploading user. |
21 | 21 | * |
22 | | - * @return {Status} result |
| 22 | + * @param {String} $comment optional -- should not be used, here for parent class compatibility |
| 23 | + * @param {String} $pageText: optional -- should not be used, here only for parent class compatibility |
| 24 | + * @param {Boolean} $watch: optional -- whether to watchlist this item, should be unused, only here for parent class compatibility |
| 25 | + * @param {User} $uer: optional -- current user, should not be used, only here for parent class compatibility |
| 26 | + * @return {Status} $status |
23 | 27 | */ |
24 | 28 | public function performUpload( $comment, $pageText, $watch, $user ) { |
25 | 29 | $status = new Status(); |
— | — | @@ -31,8 +35,11 @@ |
32 | 36 | 'mFileProps' => $this->mFileProps |
33 | 37 | ); |
34 | 38 | |
| 39 | + if ( ! is_uploaded_file( $this->mLocalFile ) ) { |
| 40 | + throw new MWException( 'badpath' ); |
| 41 | + } |
35 | 42 | // we now change the value of the local file |
36 | | - $this->mLocalFile = $stash->stashFile( false, $this->mTempPath, $data ); |
| 43 | + $this->mLocalFile = $stash->stashFile( $this->mTempPath, $data ); |
37 | 44 | $status->setResult( true, $this->mLocalFile ); |
38 | 45 | |
39 | 46 | } catch ( Exception $e ) { |
Index: branches/uploadwizard/phase3/includes/upload/SessionStash.php |
— | — | @@ -62,29 +62,33 @@ |
63 | 63 | } |
64 | 64 | |
65 | 65 | /** |
66 | | - * Get a file from the stash. |
67 | | - * May throw exception if session data cannot be parsed due to schema change. |
| 66 | + * Get a file and its metadata from the stash. |
| 67 | + * May throw exception if session data cannot be parsed due to schema change, or key not found. |
68 | 68 | * @param {Integer} $key: key |
69 | | - * @return {null|SessionStashItem} null if no such item or item out of date, or the item |
| 69 | + * @throws SessionStashFileNotFoundException |
| 70 | + * @throws MWException |
| 71 | + * @return {SessionStashItem} null if no such item or item out of date, or the item |
70 | 72 | */ |
71 | 73 | public function getFile( $key ) { |
72 | 74 | if ( !isset( $this->files[$key] ) ) { |
73 | 75 | if ( !isset( $_SESSION[UploadBase::SESSION_KEYNAME][$key] ) ) { |
74 | | - return $this->files[$key] = null; |
| 76 | + throw new SessionStashFileNotFoundException(); |
75 | 77 | } |
76 | 78 | |
77 | | - $stashData = $_SESSION[UploadBase::SESSION_KEYNAME][$key]; |
78 | | - |
| 79 | + $data = $_SESSION[UploadBase::SESSION_KEYNAME][$key]; |
| 80 | +wfDebug( "SESSION DATA: \n"); |
| 81 | +wfDebug( print_r( $data, 1 ) ); |
79 | 82 | // guards against PHP class changing while session data doesn't |
80 | | - if ($stashData['version'] !== UploadBase::SESSION_VERSION ) { |
81 | | - return $this->files[$key] = null; |
| 83 | + if ($data['version'] !== UploadBase::SESSION_VERSION ) { |
| 84 | + throw new MWException( 'outdated session version' ); |
82 | 85 | } |
83 | | - |
84 | | - // The path is flattened in with the other random props so we have to dig it out. |
85 | | - $path = $stashData['mTempPath']; |
86 | | - $data = array_diff_key( $data, array( 'mTempPath' => true ) ); |
| 86 | + |
| 87 | + // separate the stashData into the path, and then the rest of the data |
| 88 | + $path = $data['mTempPath']; |
| 89 | + unset( $data['mTempPath'] ); |
87 | 90 | |
88 | 91 | $file = new SessionStashFile( $this, $this->repo, $path, $key, $data ); |
| 92 | +wfDebug( "file = " . print_r( $file, 1 ) ); |
89 | 93 | $this->files[$key] = $file; |
90 | 94 | |
91 | 95 | } |
— | — | @@ -93,64 +97,69 @@ |
94 | 98 | |
95 | 99 | /** |
96 | 100 | * Stash a file in a temp directory and record that we did this in the session, along with other parameters. |
97 | | - * @param {Integer} $key: unique key. Used for directory hashing when storing, otherwise not important |
| 101 | + * We store data in a flat key-val namespace because that's how UploadBase did it. This also means we have to |
| 102 | + * ensure that the key-val pairs in $data do not overwrite other required fields. |
| 103 | + * |
98 | 104 | * @param {String} $path: path to file you want stashed |
99 | | - * @param {Array} $data: other data you want added to the session. Do not use 'mTempPath', 'mFileProps', 'mFileSize', or 'version' as keys here |
| 105 | + * @param {Array} $data: optional, other data you want added to the session. Do not use 'mTempPath', 'mFileProps', 'mFileSize', or 'version' as keys here |
| 106 | + * @param {String} $key: optional, unique key for this session. Used for directory hashing when storing, otherwise not important |
100 | 107 | * @return {null|SessionStashFile} file, or null on failure |
101 | 108 | */ |
102 | | - public function stashFile( $key, $path, $data = array() ) { |
103 | | - if ( !$key ) { |
104 | | - // FIXME: Doesn't sound like a good idea if $key is to be unique |
105 | | - // Also, why is this an integer rather than a string? |
106 | | - $key = mt_rand( 0, 0x7fffffff ); |
| 109 | + public function stashFile( $path, $data = array(), $key = null ) { |
| 110 | + if ( ! file_exists( $path ) ) { |
| 111 | + throw new SessionStashBadPathException(); |
107 | 112 | } |
| 113 | + $fileProps = File::getPropsFromPath( $path ); |
108 | 114 | |
| 115 | + // If no key was supplied, use content hash. Also has the nice property of collapsing multiple identical files |
| 116 | + // uploaded this session, which could happen if uploads had failed. |
| 117 | + if ( is_null( $key ) ) { |
| 118 | + $key = $fileProps['sha1']; |
| 119 | + } |
| 120 | + |
109 | 121 | // if not already in a temporary area, put it there |
110 | 122 | $status = $this->repo->storeTemp( basename($path), $path ); |
111 | 123 | if( !$status->isOK() ) { |
112 | 124 | return null; |
113 | 125 | } |
114 | 126 | $stashPath = $status->value; |
115 | | - |
116 | | - |
117 | | - // get props |
118 | | - $fileProps = File::getPropsFromPath( $path ); |
119 | | - $fileSize = $fileProps['size']; |
120 | 127 | |
121 | | - // standard info we always store. |
| 128 | + // required info we always store. Must trump any other application info in data() |
122 | 129 | // 'mTempPath', 'mFileSize', and 'mFileProps' are arbitrary names |
123 | 130 | // chosen for compatibility with UploadBase's way of doing this. |
124 | | - $stashData = array( |
| 131 | + $requiredData = array( |
125 | 132 | 'mTempPath' => $stashPath, |
126 | | - 'mFileSize' => $fileSize, |
| 133 | + 'mFileSize' => $fileProps['size'], |
127 | 134 | 'mFileProps' => $fileProps, |
128 | 135 | 'version' => UploadBase::SESSION_VERSION |
129 | 136 | ); |
130 | 137 | |
131 | | - // put extended info into the session (this changes from application to application). |
132 | | - // UploadWizard wants different things than say FirefoggChunkedUpload. |
133 | | - // Order is relevant: in case of a key collision, the value from $stashData wins |
134 | | - $_SESSION[UploadBase::SESSION_KEYNAME][$key] = $data + $stashData; |
| 138 | + // now, merge required info and extra data into the session. (The extra data changes from application to application. |
| 139 | + // UploadWizard wants different things than say FirefoggChunkedUpload.) |
| 140 | + $_SESSION[UploadBase::SESSION_KEYNAME][$key] = array_merge( $data, $requiredData ); |
135 | 141 | |
136 | 142 | return $this->getFile( $key ); |
137 | 143 | } |
138 | 144 | } |
139 | 145 | |
140 | 146 | class SessionStashFile extends UnregisteredLocalFile { |
141 | | - public $sessionStash; |
142 | | - public $sessionKey; |
143 | | - public $sessionData; |
| 147 | + private $sessionStash; |
| 148 | + private $sessionKey; |
| 149 | + private $sessionData; |
144 | 150 | private $urlName; |
145 | 151 | |
146 | 152 | /** |
147 | 153 | * A LocalFile wrapper around a file that has been temporarily stashed, so we can do things like create thumbnails for it |
148 | 154 | * Arguably UnregisteredLocalFile should be handling its own file repo but that class is a bit retarded currently |
| 155 | + * @param {SessionStash} $stash: SessionStash, useful for obtaining config, stashing transformed files |
149 | 156 | * @param {FileRepo} $repo: repository where we should find the path |
150 | 157 | * @param {String} $path: path to file |
| 158 | + * @param {String} $key: key to store the path and any stashed data under |
| 159 | + * @param {String} $data: any other data we want stored with this file |
151 | 160 | * @throws SessionStashBadPathException |
152 | 161 | * @throws SessionStashFileNotFoundException |
153 | 162 | */ |
154 | | - public function __construct( $stash, $repo, $path, $key, $data ) { // FIXME: document $stash, $key, $data --RK |
| 163 | + public function __construct( $stash, $repo, $path, $key, $data ) { |
155 | 164 | $this->sessionStash = $stash; |
156 | 165 | $this->sessionKey = $key; |
157 | 166 | $this->sessionData = $data; |
— | — | @@ -269,7 +278,6 @@ |
270 | 279 | */ |
271 | 280 | public function getThumbUrl( $thumbName = false ) { |
272 | 281 | $path = $this->sessionStash->getBaseUrl(); |
273 | | - $extension = $this->getExtension(); // Unused. Should this be appended to $path ? --RK |
274 | 282 | if ( $thumbName !== false ) { |
275 | 283 | $path .= '/' . rawurlencode( $thumbName ); |
276 | 284 | } |
— | — | @@ -279,10 +287,9 @@ |
280 | 288 | /** |
281 | 289 | * The basename for the URL, which we want to not be related to the filename. |
282 | 290 | * Will also be used as the lookup key for a thumbnail file. |
283 | | - * @param {Array} optional transformation parameters |
284 | 291 | * @return {String} base url name, like '120px-123456.jpg' |
285 | 292 | */ |
286 | | - public function getUrlName() { // FIXME: Docs say this has a parameter, but it doesn't --RK |
| 293 | + public function getUrlName() { |
287 | 294 | if ( ! $this->urlName ) { |
288 | 295 | $this->urlName = $this->sessionKey . '.' . $this->getExtension(); |
289 | 296 | } |
— | — | @@ -330,7 +337,6 @@ |
331 | 338 | |
332 | 339 | // returns a ThumbnailImage object containing the url and path. Note. NOT A FILE OBJECT. |
333 | 340 | $thumb = parent::transform( $params, $flags ); |
334 | | - |
335 | 341 | $key = $this->thumbName($params); |
336 | 342 | |
337 | 343 | // remove extension, so it's stored in the session under '120px-123456' |
— | — | @@ -341,7 +347,7 @@ |
342 | 348 | } |
343 | 349 | |
344 | 350 | // stash the thumbnail File, and provide our caller with a way to get at its properties |
345 | | - $stashedThumbFile = $this->sessionStash->stashFile( $key, $thumb->path ); |
| 351 | + $stashedThumbFile = $this->sessionStash->stashFile( $thumb->path, array(), $key ); |
346 | 352 | $thumb->thumbnailFile = $stashedThumbFile; |
347 | 353 | |
348 | 354 | return $thumb; |