Esempio n. 1
0
 /**
  * Get the result of a chunk upload.
  * @param array $warnings Array of Api upload warnings
  * @return array
  */
 private function getChunkResult($warnings)
 {
     $result = array();
     $result['result'] = 'Continue';
     if ($warnings && count($warnings) > 0) {
         $result['warnings'] = $warnings;
     }
     $request = $this->getMain()->getRequest();
     $chunkPath = $request->getFileTempname('chunk');
     $chunkSize = $request->getUpload('chunk')->getSize();
     if ($this->mParams['offset'] == 0) {
         try {
             $filekey = $this->performStash();
         } catch (UploadStashException $e) {
             $this->handleStashException($e);
         } catch (Exception $e) {
             // FIXME: Error handling here is wrong/different from rest of this
             $this->dieUsage($e->getMessage(), 'stashfailed');
         }
     } else {
         $filekey = $this->mParams['filekey'];
         $status = $this->mUpload->addChunk($chunkPath, $chunkSize, $this->mParams['offset']);
         if (!$status->isGood()) {
             $extradata = array('offset' => $this->mUpload->getOffset());
             $this->dieUsage($status->getWikiText(), 'stashfailed', 0, $extradata);
             return array();
         }
     }
     // Check we added the last chunk:
     if ($this->mParams['offset'] + $chunkSize == $this->mParams['filesize']) {
         if ($this->mParams['async']) {
             $progress = UploadBase::getSessionStatus($this->getUser(), $filekey);
             if ($progress && $progress['result'] === 'Poll') {
                 $this->dieUsage("Chunk assembly already in progress.", 'stashfailed');
             }
             UploadBase::setSessionStatus($this->getUser(), $filekey, array('result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood()));
             JobQueueGroup::singleton()->push(new AssembleUploadChunksJob(Title::makeTitle(NS_FILE, $filekey), array('filename' => $this->mParams['filename'], 'filekey' => $filekey, 'session' => $this->getContext()->exportSession())));
             $result['result'] = 'Poll';
             $result['stage'] = 'queued';
         } else {
             $status = $this->mUpload->concatenateChunks();
             if (!$status->isGood()) {
                 $this->dieUsage($status->getWikiText(), 'stashfailed');
                 return array();
             }
             // The fully concatenated file has a new filekey. So remove
             // the old filekey and fetch the new one.
             $this->mUpload->stash->removeFile($filekey);
             $filekey = $this->mUpload->getLocalFile()->getFileKey();
             $result['result'] = 'Success';
         }
     }
     $result['filekey'] = $filekey;
     $result['offset'] = $this->mParams['offset'] + $chunkSize;
     return $result;
 }
 public function run()
 {
     $scope = RequestContext::importScopedSession($this->params['session']);
     $context = RequestContext::getMain();
     try {
         $user = $context->getUser();
         if (!$user->isLoggedIn()) {
             $this->setLastError("Could not load the author user from session.");
             return false;
         }
         if (count($_SESSION) === 0) {
             // Empty session probably indicates that we didn't associate
             // with the session correctly. Note that being able to load
             // the user does not necessarily mean the session was loaded.
             // Most likely cause by suhosin.session.encrypt = On.
             $this->setLastError("Error associating with user session. " . "Try setting suhosin.session.encrypt = Off");
             return false;
         }
         UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Poll', 'stage' => 'assembling', 'status' => Status::newGood()));
         $upload = new UploadFromChunks($user);
         $upload->continueChunks($this->params['filename'], $this->params['filekey'], $context->getRequest());
         // Combine all of the chunks into a local file and upload that to a new stash file
         $status = $upload->concatenateChunks();
         if (!$status->isGood()) {
             UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'assembling', 'status' => $status));
             $this->setLastError($status->getWikiText());
             return false;
         }
         // We have a new filekey for the fully concatenated file
         $newFileKey = $upload->getLocalFile()->getFileKey();
         // Remove the old stash file row and first chunk file
         $upload->stash->removeFileNoAuth($this->params['filekey']);
         // Build the image info array while we have the local reference handy
         $apiMain = new ApiMain();
         // dummy object (XXX)
         $imageInfo = $upload->getImageInfo($apiMain->getResult());
         // Cleanup any temporary local file
         $upload->cleanupTempFile();
         // Cache the info so the user doesn't have to wait forever to get the final info
         UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Success', 'stage' => 'assembling', 'filekey' => $newFileKey, 'imageinfo' => $imageInfo, 'status' => Status::newGood()));
     } catch (MWException $e) {
         UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'assembling', 'status' => Status::newFatal('api-error-stashfailed')));
         $this->setLastError(get_class($e) . ": " . $e->getText());
         // To be extra robust.
         MWExceptionHandler::rollbackMasterChangesAndLog($e);
         return false;
     }
     return true;
 }
 public function run()
 {
     $scope = RequestContext::importScopedSession($this->params['session']);
     $this->addTeardownCallback(function () use(&$scope) {
         ScopedCallback::consume($scope);
         // T126450
     });
     $context = RequestContext::getMain();
     $user = $context->getUser();
     try {
         if (!$user->isLoggedIn()) {
             $this->setLastError("Could not load the author user from session.");
             return false;
         }
         UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Poll', 'stage' => 'assembling', 'status' => Status::newGood()]);
         $upload = new UploadFromChunks($user);
         $upload->continueChunks($this->params['filename'], $this->params['filekey'], new WebRequestUpload($context->getRequest(), 'null'));
         // Combine all of the chunks into a local file and upload that to a new stash file
         $status = $upload->concatenateChunks();
         if (!$status->isGood()) {
             UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Failure', 'stage' => 'assembling', 'status' => $status]);
             $this->setLastError($status->getWikiText(false, false, 'en'));
             return false;
         }
         // We can only get warnings like 'duplicate' after concatenating the chunks
         $status = Status::newGood();
         $status->value = ['warnings' => $upload->checkWarnings()];
         // We have a new filekey for the fully concatenated file
         $newFileKey = $upload->getStashFile()->getFileKey();
         // Remove the old stash file row and first chunk file
         $upload->stash->removeFileNoAuth($this->params['filekey']);
         // Build the image info array while we have the local reference handy
         $apiMain = new ApiMain();
         // dummy object (XXX)
         $imageInfo = $upload->getImageInfo($apiMain->getResult());
         // Cleanup any temporary local file
         $upload->cleanupTempFile();
         // Cache the info so the user doesn't have to wait forever to get the final info
         UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Success', 'stage' => 'assembling', 'filekey' => $newFileKey, 'imageinfo' => $imageInfo, 'status' => $status]);
     } catch (Exception $e) {
         UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Failure', 'stage' => 'assembling', 'status' => Status::newFatal('api-error-stashfailed')]);
         $this->setLastError(get_class($e) . ": " . $e->getMessage());
         // To be extra robust.
         MWExceptionHandler::rollbackMasterChangesAndLog($e);
         return false;
     }
     return true;
 }
 public function run()
 {
     $scope = RequestContext::importScopedSession($this->params['session']);
     $context = RequestContext::getMain();
     try {
         $user = $context->getUser();
         if (!$user->isLoggedIn()) {
             $this->setLastError("Could not load the author user from session.");
             return false;
         }
         UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Poll', 'stage' => 'assembling', 'status' => Status::newGood()));
         $upload = new UploadFromChunks($user);
         $upload->continueChunks($this->params['filename'], $this->params['filekey'], $context->getRequest());
         // Combine all of the chunks into a local file and upload that to a new stash file
         $status = $upload->concatenateChunks();
         if (!$status->isGood()) {
             UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'assembling', 'status' => $status));
             $this->setLastError($status->getWikiText());
             return false;
         }
         // We have a new filekey for the fully concatenated file
         $newFileKey = $upload->getLocalFile()->getFileKey();
         // Remove the old stash file row and first chunk file
         $upload->stash->removeFileNoAuth($this->params['filekey']);
         // Build the image info array while we have the local reference handy
         $apiMain = new ApiMain();
         // dummy object (XXX)
         $imageInfo = $upload->getImageInfo($apiMain->getResult());
         // Cleanup any temporary local file
         $upload->cleanupTempFile();
         // Cache the info so the user doesn't have to wait forever to get the final info
         UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Success', 'stage' => 'assembling', 'filekey' => $newFileKey, 'imageinfo' => $imageInfo, 'status' => Status::newGood()));
     } catch (MWException $e) {
         UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'assembling', 'status' => Status::newFatal('api-error-stashfailed')));
         $this->setLastError(get_class($e) . ": " . $e->getText());
         return false;
     }
     return true;
 }
Esempio n. 5
0
 /**
  * Get the result of a chunk upload.
  * @param array $warnings Array of Api upload warnings
  * @return array
  */
 private function getChunkResult($warnings)
 {
     $result = [];
     if ($warnings && count($warnings) > 0) {
         $result['warnings'] = $warnings;
     }
     $request = $this->getMain()->getRequest();
     $chunkPath = $request->getFileTempname('chunk');
     $chunkSize = $request->getUpload('chunk')->getSize();
     $totalSoFar = $this->mParams['offset'] + $chunkSize;
     $minChunkSize = $this->getConfig()->get('MinUploadChunkSize');
     // Sanity check sizing
     if ($totalSoFar > $this->mParams['filesize']) {
         $this->dieUsage('Offset plus current chunk is greater than claimed file size', 'invalid-chunk');
     }
     // Enforce minimum chunk size
     if ($totalSoFar != $this->mParams['filesize'] && $chunkSize < $minChunkSize) {
         $this->dieUsage("Minimum chunk size is {$minChunkSize} bytes for non-final chunks", 'chunk-too-small');
     }
     if ($this->mParams['offset'] == 0) {
         try {
             $filekey = $this->performStash();
         } catch (UploadStashException $e) {
             $this->handleStashException($e);
         } catch (Exception $e) {
             // FIXME: Error handling here is wrong/different from rest of this
             $this->dieUsage($e->getMessage(), 'stashfailed');
         }
     } else {
         $filekey = $this->mParams['filekey'];
         // Don't allow further uploads to an already-completed session
         $progress = UploadBase::getSessionStatus($this->getUser(), $filekey);
         if (!$progress) {
             // Probably can't get here, but check anyway just in case
             $this->dieUsage('No chunked upload session with this key', 'stashfailed');
         } elseif ($progress['result'] !== 'Continue' || $progress['stage'] !== 'uploading') {
             $this->dieUsage('Chunked upload is already completed, check status for details', 'stashfailed');
         }
         $status = $this->mUpload->addChunk($chunkPath, $chunkSize, $this->mParams['offset']);
         if (!$status->isGood()) {
             $extradata = ['offset' => $this->mUpload->getOffset()];
             $this->dieUsage($status->getWikiText(false, false, 'en'), 'stashfailed', 0, $extradata);
         }
     }
     // Check we added the last chunk:
     if ($totalSoFar == $this->mParams['filesize']) {
         if ($this->mParams['async']) {
             UploadBase::setSessionStatus($this->getUser(), $filekey, ['result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood()]);
             JobQueueGroup::singleton()->push(new AssembleUploadChunksJob(Title::makeTitle(NS_FILE, $filekey), ['filename' => $this->mParams['filename'], 'filekey' => $filekey, 'session' => $this->getContext()->exportSession()]));
             $result['result'] = 'Poll';
             $result['stage'] = 'queued';
         } else {
             $status = $this->mUpload->concatenateChunks();
             if (!$status->isGood()) {
                 UploadBase::setSessionStatus($this->getUser(), $filekey, ['result' => 'Failure', 'stage' => 'assembling', 'status' => $status]);
                 $this->dieUsage($status->getWikiText(false, false, 'en'), 'stashfailed');
             }
             // The fully concatenated file has a new filekey. So remove
             // the old filekey and fetch the new one.
             UploadBase::setSessionStatus($this->getUser(), $filekey, false);
             $this->mUpload->stash->removeFile($filekey);
             $filekey = $this->mUpload->getLocalFile()->getFileKey();
             $result['result'] = 'Success';
         }
     } else {
         UploadBase::setSessionStatus($this->getUser(), $filekey, ['result' => 'Continue', 'stage' => 'uploading', 'offset' => $totalSoFar, 'status' => Status::newGood()]);
         $result['result'] = 'Continue';
         $result['offset'] = $totalSoFar;
     }
     $result['filekey'] = $filekey;
     return $result;
 }