Merge "Fix Ifb93e49b"
[lhc/web/wiklou.git] / includes / api / ApiUpload.php
index a0da765..f2733bd 100644 (file)
@@ -37,6 +37,8 @@ class ApiUpload extends ApiBase {
        protected $mParams;
 
        public function execute() {
+               global $wgEnableAsyncUploads;
+
                // Check whether upload is enabled
                if ( !UploadBase::isEnabled() ) {
                        $this->dieUsageMsg( 'uploaddisabled' );
@@ -47,9 +49,8 @@ class ApiUpload extends ApiBase {
                // Parameter handling
                $this->mParams = $this->extractRequestParams();
                $request = $this->getMain()->getRequest();
-               // Check if async mode is actually supported
-               $this->mParams['async'] = ( $this->mParams['async'] && !wfIsWindows() );
-               $this->mParams['async'] = false; // XXX: disabled per bug 44080
+               // Check if async mode is actually supported (jobs done in cli mode)
+               $this->mParams['async'] = ( $this->mParams['async'] && $wgEnableAsyncUploads );
                // Add the uploaded file to the params array
                $this->mParams['file'] = $request->getFileName( 'file' );
                $this->mParams['chunk'] = $request->getFileName( 'chunk' );
@@ -70,6 +71,7 @@ class ApiUpload extends ApiBase {
                $this->checkPermissions( $user );
 
                // Fetch the file (usually a no-op)
+               /** @var $status Status */
                $status = $this->mUpload->fetchFile();
                if ( !$status->isGood() ) {
                        $errors = $status->getErrorsArray();
@@ -115,13 +117,13 @@ class ApiUpload extends ApiBase {
        }
 
        /**
-        * Get an uplaod result based on upload context
+        * Get an upload result based on upload context
         * @return array
         */
        private function getContextResult() {
                $warnings = $this->getApiWarnings();
                if ( $warnings && !$this->mParams['ignorewarnings'] ) {
-                       // Get warnings formated in result array format
+                       // Get warnings formatted in result array format
                        return $this->getWarningsResult( $warnings );
                } elseif ( $this->mParams['chunk'] ) {
                        // Add chunk, and get result
@@ -136,8 +138,8 @@ class ApiUpload extends ApiBase {
        }
 
        /**
-        * Get Stash Result, throws an expetion if the file could not be stashed.
-        * @param $warnings array Array of Api upload warnings
+        * Get Stash Result, throws an exception if the file could not be stashed.
+        * @param array $warnings Array of Api upload warnings
         * @return array
         */
        private function getStashResult( $warnings ) {
@@ -159,7 +161,7 @@ class ApiUpload extends ApiBase {
 
        /**
         * Get Warnings Result
-        * @param $warnings array Array of Api upload warnings
+        * @param array $warnings Array of Api upload warnings
         * @return array
         */
        private function getWarningsResult( $warnings ) {
@@ -179,12 +181,10 @@ class ApiUpload extends ApiBase {
 
        /**
         * Get the result of a chunk upload.
-        * @param $warnings array Array of Api upload warnings
+        * @param array $warnings Array of Api upload warnings
         * @return array
         */
        private function getChunkResult( $warnings ) {
-               global $IP;
-
                $result = array();
 
                $result['result'] = 'Continue';
@@ -195,69 +195,62 @@ class ApiUpload extends ApiBase {
                $chunkPath = $request->getFileTempname( 'chunk' );
                $chunkSize = $request->getUpload( 'chunk' )->getSize();
                if ( $this->mParams['offset'] == 0 ) {
-                       $result['filekey'] = $this->performStash();
+                       $filekey = $this->performStash();
                } else {
+                       $filekey = $this->mParams['filekey'];
+                       /** @var $status Status */
                        $status = $this->mUpload->addChunk(
                                $chunkPath, $chunkSize, $this->mParams['offset'] );
                        if ( !$status->isGood() ) {
                                $this->dieUsage( $status->getWikiText(), 'stashfailed' );
                                return array();
                        }
+               }
 
-                       // Check we added the last chunk:
-                       if( $this->mParams['offset'] + $chunkSize == $this->mParams['filesize'] ) {
-                               if ( $this->mParams['async'] && !wfIsWindows() ) {
-                                       $progress = UploadBase::getSessionStatus( $this->mParams['filekey'] );
-                                       if ( $progress && $progress['result'] === 'Poll' ) {
-                                               $this->dieUsage( "Chunk assembly already in progress.", 'stashfailed' );
-                                       }
-                                       UploadBase::setSessionStatus(
-                                               $this->mParams['filekey'],
-                                               array( 'result' => 'Poll',
-                                                       'stage' => 'queued', 'status' => Status::newGood() )
-                                       );
-                                       $retVal = 1;
-                                       $cmd = wfShellWikiCmd(
-                                               "$IP/includes/upload/AssembleUploadChunks.php",
-                                               array(
-                                                       '--wiki', wfWikiID(),
-                                                       '--filename', $this->mParams['filename'],
-                                                       '--filekey', $this->mParams['filekey'],
-                                                       '--userid', $this->getUser()->getId(),
-                                                       '--sessionid', session_id(),
-                                                       '--quiet'
-                                               )
-                                       ) . " < " . wfGetNull() . " > " . wfGetNull() . " 2>&1 &";
-                                       // Start a process in the background. Enforce the time limits via PHP
-                                       // since ulimit4.sh seems to often not work for this particular usage.
-                                       wfShellExec( $cmd, $retVal, array(), array( 'time' => 0, 'memory' => 0 ) );
-                                       if ( $retVal == 0 ) {
-                                               $result['result'] = 'Poll';
-                                       } else {
-                                               UploadBase::setSessionStatus( $this->mParams['filekey'], false );
-                                               $this->dieUsage(
-                                                       "Failed to start AssembleUploadChunks.php", 'stashfailed' );
-                                       }
+               // Check we added the last chunk:
+               if ( $this->mParams['offset'] + $chunkSize == $this->mParams['filesize'] ) {
+                       if ( $this->mParams['async'] ) {
+                               $progress = UploadBase::getSessionStatus( $this->mParams['filekey'] );
+                               if ( $progress && $progress['result'] === 'Poll' ) {
+                                       $this->dieUsage( "Chunk assembly already in progress.", 'stashfailed' );
+                               }
+                               UploadBase::setSessionStatus(
+                                       $this->mParams['filekey'],
+                                       array( 'result' => 'Poll',
+                                               'stage' => 'queued', 'status' => Status::newGood() )
+                               );
+                               $ok = JobQueueGroup::singleton()->push( new AssembleUploadChunksJob(
+                                       Title::makeTitle( NS_FILE, $this->mParams['filekey'] ),
+                                       array(
+                                               'filename'  => $this->mParams['filename'],
+                                               'filekey'   => $this->mParams['filekey'],
+                                               'session'   => $this->getRequest()->exportUserSession(),
+                                               'userid'    => $this->getUser()->getId()
+                                       )
+                               ) );
+                               if ( $ok ) {
+                                       $result['result'] = 'Poll';
                                } else {
-                                       $status = $this->mUpload->concatenateChunks();
-                                       if ( !$status->isGood() ) {
-                                               $this->dieUsage( $status->getWikiText(), 'stashfailed' );
-                                               return array();
-                                       }
-
-                                       // We have a new filekey for the fully concatenated file.
-                                       $result['filekey'] = $this->mUpload->getLocalFile()->getFileKey();
-
-                                       // Remove chunk from stash. (Checks against user ownership of chunks.)
-                                       $this->mUpload->stash->removeFile( $this->mParams['filekey'] );
-
-                                       $result['result'] = 'Success';
+                                       UploadBase::setSessionStatus( $this->mParams['filekey'], false );
+                                       $this->dieUsage(
+                                               "Failed to start AssembleUploadChunks.php", 'stashfailed' );
                                }
                        } else {
-                               // Continue passing through the filekey for adding further chunks.
-                               $result['filekey'] = $this->mParams['filekey'];
+                               $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;
        }
@@ -288,9 +281,9 @@ class ApiUpload extends ApiBase {
         * Throw an error that the user can recover from by providing a better
         * value for $parameter
         *
-        * @param $error array Error array suitable for passing to dieUsageMsg()
-        * @param $parameter string Parameter that needs revising
-        * @param $data array Optional extra data to pass to the user
+        * @param array $error Error array suitable for passing to dieUsageMsg()
+        * @param string $parameter Parameter that needs revising
+        * @param array $data Optional extra data to pass to the user
         * @throws UsageException
         */
        private function dieRecoverableError( $error, $parameter, $data = array() ) {
@@ -524,7 +517,6 @@ class ApiUpload extends ApiBase {
                }
        }
 
-
        /**
         * Check warnings.
         * Returns a suitable array for inclusion into API results if there were warnings
@@ -562,22 +554,20 @@ class ApiUpload extends ApiBase {
                return $warnings;
        }
 
-
        /**
         * Perform the actual upload. Returns a suitable result array on success;
         * dies on failure.
         *
-        * @param $warnings array Array of Api upload warnings
+        * @param array $warnings Array of Api upload warnings
         * @return array
         */
        protected function performUpload( $warnings ) {
-               global $IP;
-
                // 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() );
 
@@ -596,25 +586,19 @@ class ApiUpload extends ApiBase {
                                $this->mParams['filekey'],
                                array( 'result' => 'Poll', 'stage' => 'queued', 'status' => Status::newGood() )
                        );
-                       $retVal = 1;
-                       $cmd = wfShellWikiCmd(
-                               "$IP/includes/upload/PublishStashedFile.php",
+                       $ok = JobQueueGroup::singleton()->push( new PublishStashedFileJob(
+                               Title::makeTitle( NS_FILE, $this->mParams['filename'] ),
                                array(
-                                       '--wiki', wfWikiID(),
-                                       '--filename', $this->mParams['filename'],
-                                       '--filekey', $this->mParams['filekey'],
-                                       '--userid', $this->getUser()->getId(),
-                                       '--comment', $this->mParams['comment'],
-                                       '--text', $this->mParams['text'],
-                                       '--watch', $watch,
-                                       '--sessionid', session_id(),
-                                       '--quiet'
+                                       'filename'  => $this->mParams['filename'],
+                                       'filekey'   => $this->mParams['filekey'],
+                                       'comment'   => $this->mParams['comment'],
+                                       'text'      => $this->mParams['text'],
+                                       'watch'     => $watch,
+                                       'session'   => $this->getRequest()->exportUserSession(),
+                                       'userid'    => $this->getUser()->getId()
                                )
-                       ) . " < " . wfGetNull() . " > " . wfGetNull() . " 2>&1 &";
-                       // Start a process in the background. Enforce the time limits via PHP
-                       // since ulimit4.sh seems to often not work for this particular usage.
-                       wfShellExec( $cmd, $retVal, array(), array( 'time' => 0, 'memory' => 0 ) );
-                       if ( $retVal == 0 ) {
+                       ) );
+                       if ( $ok ) {
                                $result['result'] = 'Poll';
                        } else {
                                UploadBase::setSessionStatus( $this->mParams['filekey'], false );
@@ -622,6 +606,7 @@ class ApiUpload extends ApiBase {
                                        "Failed to start PublishStashedFile.php", 'publishfailed' );
                        }
                } else {
+                       /** @var $status Status */
                        $status = $this->mUpload->performUpload( $this->mParams['comment'],
                                $this->mParams['text'], $watch, $this->getUser() );
 
@@ -696,7 +681,9 @@ class ApiUpload extends ApiBase {
                                ),
                        ),
                        'ignorewarnings' => false,
-                       'file' => null,
+                       'file' => array(
+                               ApiBase::PARAM_TYPE => 'upload',
+                       ),
                        'url' => null,
                        'filekey' => null,
                        'sessionkey' => array(
@@ -707,7 +694,9 @@ class ApiUpload extends ApiBase {
 
                        'filesize' => null,
                        'offset' => null,
-                       'chunk' => null,
+                       'chunk' => array(
+                               ApiBase::PARAM_TYPE => 'upload',
+                       ),
 
                        'async' => false,
                        'asyncdownload' => false,