/**
  * Update problem contents
  *
  * @param Request $r
  * @throws ApiException
  * @throws InvalidDatabaseOperationException
  */
 public static function apiUpdate(Request $r)
 {
     self::authenticateRequest($r);
     self::validateCreateOrUpdate($r, true);
     // Validate commit message.
     Validators::isStringNonEmpty($r['message'], 'message');
     // Update the Problem object
     $valueProperties = array('public', 'title', 'validator' => array('important' => true), 'time_limit' => array('important' => true), 'validator_time_limit' => array('important' => true), 'overall_wall_time_limit' => array('important' => true), 'extra_wall_time' => array('important' => true), 'memory_limit' => array('important' => true), 'output_limit' => array('important' => true), 'stack_limit' => array('important' => true), 'email_clarifications', 'source', 'order', 'languages');
     $problem = $r['problem'];
     $requiresRejudge = self::updateValueProperties($r, $problem, $valueProperties);
     $r['problem'] = $problem;
     $response = array('rejudged' => false);
     $problemDeployer = new ProblemDeployer($problem->alias, ProblemDeployer::UPDATE_CASES);
     // Insert new problem
     try {
         //Begin transaction
         ProblemsDAO::transBegin();
         if (isset($_FILES['problem_contents']) && FileHandler::GetFileUploader()->IsUploadedFile($_FILES['problem_contents']['tmp_name'])) {
             // DeployProblemZip requires alias => problem_alias
             $r['alias'] = $r['problem_alias'];
             $problemDeployer->deploy();
             if ($problemDeployer->hasValidator) {
                 $problem->validator = 'custom';
             } elseif ($problem->validator == 'custom') {
                 throw new ProblemDeploymentFailedException('problemDeployerValidatorRequired');
             }
             // This must come before the commit in case isSlow throws an exception.
             $problem->slow = $problemDeployer->isSlow($problem);
             // Calculate output limit.
             $output_limit = $problemDeployer->getOutputLimit();
             if ($output_limit != -1) {
                 $r['problem']->setOutputLimit($output_limit);
             }
             $response['uploaded_files'] = $problemDeployer->filesToUnzip;
             $problemDeployer->commit($r['message'], $r['current_user']);
             $requiresRejudge |= $problemDeployer->requiresRejudge;
         } else {
             $problem->slow = $problemDeployer->isSlow($problem);
         }
         // Save the contest object with data sent by user to the database
         ProblemsDAO::save($problem);
         //End transaction
         ProblemsDAO::transEnd();
     } catch (ApiException $e) {
         // Operation failed in the data layer, rollback transaction
         ProblemsDAO::transRollback();
         throw $e;
     } catch (Exception $e) {
         // Operation failed in the data layer, rollback transaction
         ProblemsDAO::transRollback();
         self::$log->error('Failed to update problem');
         self::$log->error($e);
         throw new InvalidDatabaseOperationException($e);
     } finally {
         $problemDeployer->cleanup();
     }
     if ($requiresRejudge == true && OMEGAUP_ENABLE_REJUDGE_ON_PROBLEM_UPDATE == true) {
         self::$log->info('Calling ProblemController::apiRejudge');
         try {
             self::apiRejudge($r);
             $response['rejudged'] = true;
         } catch (Exception $e) {
             self::$log->error('Best efort ProblemController::apiRejudge failed', $e);
         }
     }
     if ($r['redirect'] === true) {
         header('Location: ' . $_SERVER['HTTP_REFERER']);
     }
     // All clear
     $response['status'] = 'ok';
     // Invalidar problem statement cache @todo invalidar todos los lenguajes
     foreach ($problemDeployer->getUpdatedLanguages() as $lang) {
         Cache::deleteFromCache(Cache::PROBLEM_STATEMENT, $r['problem']->getAlias() . '-' . $lang . 'html');
         Cache::deleteFromCache(Cache::PROBLEM_STATEMENT, $r['problem']->getAlias() . '-' . $lang . 'markdown');
     }
     Cache::deleteFromCache(Cache::PROBLEM_SAMPLE, $r['problem']->getAlias() . '-sample.in');
     return $response;
 }
Esempio n. 2
0
 /**
  * Entry point for zip validation
  * Determines the type of problem we are deploying
  *
  * @return boolean
  * @throws InvalidParameterException
  */
 private function validateZip()
 {
     $this->log->info('Validating zip...');
     if (!array_key_exists('problem_contents', $_FILES)) {
         $this->log->error('\\$_FILES global does not contain problem_contents.');
         throw new InvalidParameterException('parameterEmpty', 'problem_contents');
     }
     if (isset($_FILES['problem_contents']) && !FileHandler::GetFileUploader()->IsUploadedFile($_FILES['problem_contents']['tmp_name'])) {
         $this->log->error("GetFileUploader()->IsUploadedFile() check failed for \$_FILES['problem_contents']['tmp_name'].");
         throw new InvalidParameterException('parameterEmpty', 'problem_contents');
     }
     $this->filesToUnzip = array();
     $this->imageHashes = array();
     $this->casesFiles = array();
     $this->zipPath = $_FILES['problem_contents']['tmp_name'];
     $this->log->info("Opening {$this->zipPath}...");
     $zip = new ZipArchive();
     $resource = $zip->open($this->zipPath);
     $size = 0;
     if ($resource !== true) {
         $this->log->error('Unable to open zip file: ' . ZipHandler::ErrorMessage($resource));
         throw new InvalidParameterException('problemDeployerCorruptZip');
     }
     // Get list of files
     for ($i = 0; $i < $zip->numFiles; $i++) {
         $this->log->info("Found inside zip: '" . $zip->getNameIndex($i) . "'");
         $zipFilesArray[] = $zip->getNameIndex($i);
         // Sum up the size
         $statI = $zip->statIndex($i);
         $size += $statI['size'];
         // If the file is THE validator for custom outputs...
         if (stripos($zip->getNameIndex($i), 'validator.') === 0) {
             $this->hasValidator = true;
             $this->filesToUnzip[] = $zip->getNameIndex($i);
             $this->log->info('Validator found: ' . $zip->getNameIndex($i));
         }
         // Interactive problems.
         if (stripos($zip->getNameIndex($i), 'interactive/') === 0) {
             $this->filesToUnzip[] = $zip->getNameIndex($i);
             $this->isInteractive = true;
             if (ProblemDeployer::endsWith($zip->getNameIndex($i), '.idl', true)) {
                 $this->log->info('.idl file found: ' . $zip->getNameIndex($i));
                 $this->idlFile = $zip->getNameIndex($i);
             }
         }
         // Example inputs.
         if (stripos($zip->getNameIndex($i), 'examples/') === 0 && ProblemDeployer::endsWith($zip->getNameIndex($i), '.in', true)) {
             $this->filesToUnzip[] = $zip->getNameIndex($i);
         }
     }
     $this->checkedForInteractive = true;
     if ($this->isInteractive) {
         if ($this->idlFile == null) {
             throw new InvalidParameterException('problemDeployerIdlMissing');
         } elseif (!in_array('interactive/examples/sample.in', $this->filesToUnzip)) {
             throw new InvalidParameterException('problemDeployerInteractiveSampleMissing');
         }
     }
     if ($this->isInteractive && $size > ProblemDeployer::MAX_INTERACTIVE_ZIP_FILESIZE) {
         throw new InvalidParameterException('problemDeployerExceededZipSizeLimit', null, array('size' => $size, 'max_size' => ProblemDeployer::MAX_INTERACTIVE_ZIP_FILESIZE));
     } elseif ($size > ProblemDeployer::MAX_ZIP_FILESIZE) {
         throw new InvalidParameterException('problemDeployerExceededZipSizeLimit', null, array('size' => $size, 'max_size' => ProblemDeployer::MAX_ZIP_FILESIZE));
     }
     try {
         // Look for testplan
         if (in_array('testplan', $zipFilesArray)) {
             $returnValue = $this->checkCasesWithTestplan($zip, $zipFilesArray);
             $this->log->info('testplan found, checkCasesWithTestPlan=' . $returnValue);
             $this->filesToUnzip[] = 'testplan';
         } else {
             $this->log->info('testplan not found');
             $this->checkCases($zip, $zipFilesArray);
         }
         // Log files to unzip
         $this->log->info('Files to unzip: ');
         foreach ($this->filesToUnzip as $file) {
             $this->log->info($file);
         }
         // Look for statements
         $returnValue = $this->checkProblemStatements($zipFilesArray, $zip);
         $this->log->info('checkProblemStatements=' . $returnValue . '.');
     } finally {
         // Close zip
         $this->log->info('closing zip');
         $zip->close();
     }
     return $returnValue;
 }