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' => 'publish', 'status' => Status::newGood())); $upload = new UploadFromStash($user); // @todo initialize() causes a GET, ideally we could frontload the antivirus // checks and anything else to the stash stage (which includes concatenation and // the local file is thus already there). That way, instead of GET+PUT, there could // just be a COPY operation from the stash to the public zone. $upload->initialize($this->params['filekey'], $this->params['filename']); // Check if the local file checks out (this is generally a no-op) $verification = $upload->verifyUpload(); if ($verification['status'] !== UploadBase::OK) { $status = Status::newFatal('verification-error'); $status->value = array('verification' => $verification); UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'publish', 'status' => $status)); $this->setLastError("Could not verify upload."); return false; } // Upload the stashed file to a permanent location $status = $upload->performUpload($this->params['comment'], $this->params['text'], $this->params['watch'], $user); if (!$status->isGood()) { UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'publish', 'status' => $status)); $this->setLastError($status->getWikiText()); return false; } // 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' => 'publish', 'filename' => $upload->getLocalFile()->getName(), 'imageinfo' => $imageInfo, 'status' => Status::newGood())); } catch (MWException $e) { UploadBase::setSessionStatus($this->params['filekey'], array('result' => 'Failure', 'stage' => 'publish', 'status' => Status::newFatal('api-error-publishfailed'))); $this->setLastError(get_class($e) . ": " . $e->getText()); // To prevent potential database referential integrity issues. // See bug 32551. 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' => 'publish', 'status' => Status::newGood()]); $upload = new UploadFromStash($user); // @todo initialize() causes a GET, ideally we could frontload the antivirus // checks and anything else to the stash stage (which includes concatenation and // the local file is thus already there). That way, instead of GET+PUT, there could // just be a COPY operation from the stash to the public zone. $upload->initialize($this->params['filekey'], $this->params['filename']); // Check if the local file checks out (this is generally a no-op) $verification = $upload->verifyUpload(); if ($verification['status'] !== UploadBase::OK) { $status = Status::newFatal('verification-error'); $status->value = ['verification' => $verification]; UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Failure', 'stage' => 'publish', 'status' => $status]); $this->setLastError("Could not verify upload."); return false; } // Upload the stashed file to a permanent location $status = $upload->performUpload($this->params['comment'], $this->params['text'], $this->params['watch'], $user, isset($this->params['tags']) ? $this->params['tags'] : []); if (!$status->isGood()) { UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Failure', 'stage' => 'publish', 'status' => $status]); $this->setLastError($status->getWikiText(false, false, 'en')); return false; } // 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' => 'publish', 'filename' => $upload->getLocalFile()->getName(), 'imageinfo' => $imageInfo, 'status' => Status::newGood()]); } catch (Exception $e) { UploadBase::setSessionStatus($user, $this->params['filekey'], ['result' => 'Failure', 'stage' => 'publish', 'status' => Status::newFatal('api-error-publishfailed')]); $this->setLastError(get_class($e) . ": " . $e->getMessage()); // To prevent potential database referential integrity issues. // See bug 32551. 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; } 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; }
/** * Perform the actual upload. Returns a suitable result array on success; * dies on failure. * * @param array $warnings Array of Api upload warnings * @return array */ protected function performUpload($warnings) { // Use comment as initial page text by default if (is_null($this->mParams['text'])) { $this->mParams['text'] = $this->mParams['comment']; } /** @var $file File */ $file = $this->mUpload->getLocalFile(); // For preferences mode, we want to watch if 'watchdefault' is set, // or if the *file* doesn't exist, and either 'watchuploads' or // 'watchcreations' is set. But getWatchlistValue()'s automatic // handling checks if the *title* exists or not, so we need to check // all three preferences manually. $watch = $this->getWatchlistValue($this->mParams['watchlist'], $file->getTitle(), 'watchdefault'); if (!$watch && $this->mParams['watchlist'] == 'preferences' && !$file->exists()) { $watch = $this->getWatchlistValue('preferences', $file->getTitle(), 'watchuploads') || $this->getWatchlistValue('preferences', $file->getTitle(), 'watchcreations'); } // Deprecated parameters if ($this->mParams['watch']) { $watch = true; } if ($this->mParams['tags']) { $status = ChangeTags::canAddTagsAccompanyingChange($this->mParams['tags'], $this->getUser()); if (!$status->isOK()) { $this->dieStatus($status); } } // No errors, no warnings: do the upload if ($this->mParams['async']) { $progress = UploadBase::getSessionStatus($this->getUser(), $this->mParams['filekey']); if ($progress && $progress['result'] === 'Poll') { $this->dieUsage('Upload from stash already in progress.', 'publishfailed'); } UploadBase::setSessionStatus($this->getUser(), $this->mParams['filekey'], ['result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood()]); JobQueueGroup::singleton()->push(new PublishStashedFileJob(Title::makeTitle(NS_FILE, $this->mParams['filename']), ['filename' => $this->mParams['filename'], 'filekey' => $this->mParams['filekey'], 'comment' => $this->mParams['comment'], 'tags' => $this->mParams['tags'], 'text' => $this->mParams['text'], 'watch' => $watch, 'session' => $this->getContext()->exportSession()])); $result['result'] = 'Poll'; $result['stage'] = 'queued'; } else { /** @var $status Status */ $status = $this->mUpload->performUpload($this->mParams['comment'], $this->mParams['text'], $watch, $this->getUser(), $this->mParams['tags']); if (!$status->isGood()) { $error = $status->getErrorsArray(); ApiResult::setIndexedTagName($error, 'error'); $this->dieUsage('An internal error occurred', 'internal-error', 0, $error); } $result['result'] = 'Success'; } $result['filename'] = $file->getName(); if ($warnings && count($warnings) > 0) { $result['warnings'] = $warnings; } return $result; }
/** * Perform the actual upload. Returns a suitable result array on success; * dies on failure. * * @param array $warnings Array of Api upload warnings * @return array */ protected function performUpload($warnings) { // Use comment as initial page text by default if (is_null($this->mParams['text'])) { $this->mParams['text'] = $this->mParams['comment']; } /** @var $file File */ $file = $this->mUpload->getLocalFile(); // For preferences mode, we want to watch if 'watchdefault' is set or // if the *file* doesn't exist and 'watchcreations' is set. But // getWatchlistValue()'s automatic handling checks if the *title* // exists or not, so we need to check both prefs manually. $watch = $this->getWatchlistValue($this->mParams['watchlist'], $file->getTitle(), 'watchdefault'); if (!$watch && $this->mParams['watchlist'] == 'preferences' && !$file->exists()) { $watch = $this->getWatchlistValue($this->mParams['watchlist'], $file->getTitle(), 'watchcreations'); } // Deprecated parameters if ($this->mParams['watch']) { $this->logFeatureUsage('action=upload&watch'); $watch = true; } // No errors, no warnings: do the upload if ($this->mParams['async']) { $progress = UploadBase::getSessionStatus($this->getUser(), $this->mParams['filekey']); if ($progress && $progress['result'] === 'Poll') { $this->dieUsage("Upload from stash already in progress.", 'publishfailed'); } UploadBase::setSessionStatus($this->getUser(), $this->mParams['filekey'], array('result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood())); JobQueueGroup::singleton()->push(new PublishStashedFileJob(Title::makeTitle(NS_FILE, $this->mParams['filename']), array('filename' => $this->mParams['filename'], 'filekey' => $this->mParams['filekey'], 'comment' => $this->mParams['comment'], 'text' => $this->mParams['text'], 'watch' => $watch, 'session' => $this->getContext()->exportSession()))); $result['result'] = 'Poll'; $result['stage'] = 'queued'; } else { /** @var $status Status */ $status = $this->mUpload->performUpload($this->mParams['comment'], $this->mParams['text'], $watch, $this->getUser()); if (!$status->isGood()) { $error = $status->getErrorsArray(); if (count($error) == 1 && $error[0][0] == 'async') { // The upload can not be performed right now, because the user // requested so return array('result' => 'Queued', 'statuskey' => $error[0][1]); } ApiResult::setIndexedTagName($error, 'error'); $this->dieUsage('An internal error occurred', 'internal-error', 0, $error); } $result['result'] = 'Success'; } $result['filename'] = $file->getName(); if ($warnings && count($warnings) > 0) { $result['warnings'] = $warnings; } return $result; }
/** * Perform the actual upload. Returns a suitable result array on success; * dies on failure. * * @param array $warnings Array of Api upload warnings * @return array */ protected function performUpload( $warnings ) { // Use comment as initial page text by default if ( is_null( $this->mParams['text'] ) ) { $this->mParams['text'] = $this->mParams['comment']; } /** @var $file File */ $file = $this->mUpload->getLocalFile(); $watch = $this->getWatchlistValue( $this->mParams['watchlist'], $file->getTitle() ); // Deprecated parameters if ( $this->mParams['watch'] ) { $watch = true; } // No errors, no warnings: do the upload if ( $this->mParams['async'] ) { $progress = UploadBase::getSessionStatus( $this->mParams['filekey'] ); if ( $progress && $progress['result'] === 'Poll' ) { $this->dieUsage( "Upload from stash already in progress.", 'publishfailed' ); } UploadBase::setSessionStatus( $this->mParams['filekey'], array( 'result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood() ) ); $ok = JobQueueGroup::singleton()->push( new PublishStashedFileJob( Title::makeTitle( NS_FILE, $this->mParams['filename'] ), array( 'filename' => $this->mParams['filename'], 'filekey' => $this->mParams['filekey'], 'comment' => $this->mParams['comment'], 'text' => $this->mParams['text'], 'watch' => $watch, 'session' => $this->getContext()->exportSession() ) ) ); if ( $ok ) { $result['result'] = 'Poll'; } else { UploadBase::setSessionStatus( $this->mParams['filekey'], false ); $this->dieUsage( "Failed to start PublishStashedFile.php", 'publishfailed' ); } } else { /** @var $status Status */ $status = $this->mUpload->performUpload( $this->mParams['comment'], $this->mParams['text'], $watch, $this->getUser() ); if ( !$status->isGood() ) { $error = $status->getErrorsArray(); if ( count( $error ) == 1 && $error[0][0] == 'async' ) { // The upload can not be performed right now, because the user // requested so return array( 'result' => 'Queued', 'statuskey' => $error[0][1], ); } else { $this->getResult()->setIndexedTagName( $error, 'error' ); $this->dieUsage( 'An internal error occurred', 'internal-error', 0, $error ); } } $result['result'] = 'Success'; } $result['filename'] = $file->getName(); if ( $warnings && count( $warnings ) > 0 ) { $result['warnings'] = $warnings; } return $result; }