protected function body() { if (!$this->isInputSet(array('email'))) { return false; } $email = $this->getParams('email'); $users = Repositories::getRepository(Repositories::User)->findBy(['email' => $email]); foreach ($users as $user) { /** * @var $user \User */ // Generate reset link. $resetLink = StringUtils::randomString(60); $now = new \DateTime(); $expiryDate = $now->add(new \DateInterval('P1D')); // Add in in the database (replacing any older reset links in the process) $user->setResetLink($resetLink); $user->setResetLinkExpiry($expiryDate); Repositories::persistAndFlush($user); // Send the e-mail $body = "A Password Reset Link was requested for your e-mail address on XMLCheck.\n\nYour name: " . $user->getRealName() . "\nYour login: "******"\n\nClick this link to reset your password: \n\n" . Config::get('roots', 'http') . "#resetPassword#" . $resetLink . "\n\nThe link will be valid for the next 24 hours, until " . $expiryDate->format("Y-m-d H:i:s") . "."; if (!Core::sendEmail($user->getEmail(), "[XMLCheck] Password Reset Link for '" . $user->getRealName() . "'", $body)) { return $this->death(StringID::MailError); } } $this->addOutput('count', count($users)); return true; }
/** * Creates new unique ID for file. * @return string new unique ID (not currently used) */ protected function generateUniqueId() { do { $id = StringUtils::randomString(10); } while (isset($_SESSION[UploadManager::sessionSpace][$id]) || file_exists($this->getFilenameFromId($id))); return $id; }
/** * Strips XPath comments from supplied XPath expression string. * @param string $expr XPath expression * @param[out] array $comments stripped comments * @return string expression @a $expr stripped of comments */ protected function stripXpathComments($expr, &$comments) { $com = array(); $expr = StringUtils::stripComments($expr, '{--', '--}', $com); $expr = StringUtils::stripComments($expr, '(:', ':)', $com); $comments = implode("\n", $com); return $expr; }
/** * Turns test results to plugin criteria or error. * Goal names will be used as criterion names. Criteria will be passed with * 100% fulfillment if goal was reached or failed with goal error as failure * info otherwise. * @throws PluginException in case test finished with error(s), so that the * error is returned as plugin error */ private function createCriteriaFromTest() { if (count($this->results['errors'])) { throw new PluginException("Failure. " . StringUtils::indent(implode("\n", $this->results['errors']))); } foreach ($this->test->getGoals() as $goalId => $goalName) { $this->addCriterion($goalName); $results = $this->results['results'][$goalId]; $passed = $results['reached']; $fulfillment = $passed ? 100 : 0; $details = !$passed && $results['error'] ? StringUtils::indent(trim($results['error'])) . "\n" : ''; $this->updateCriterion($goalName, $passed, $fulfillment, $details); } }
/** * Initializes instance members with supplied data. * @param mixed $data either error message (string) or criteria info (array) * @see create() * @see createError() * @see fromXml() */ protected function __construct($data) { if (!is_array($data)) { $this->error = StringUtils::stripFunctionLinks($data); } else { $this->results = $data; $this->output = func_get_arg(1); $fulfillmentSum = 0; $passedCriteria = 0; $this->details = ''; foreach ($data as $name => $criterion) { $fulfillmentSum += $criterion['fulfillment']; $passedCriteria += (int) $criterion['passed']; $this->details .= $name . ' ... ' . ($criterion['passed'] ? 'PASSED' : 'FAILED') . "\n"; if ($criterion['details']) { $this->details .= $criterion['details'] . "\n"; } } $numCriteria = count($data); $this->details = "Passed {$passedCriteria} out of {$numCriteria} criteria.\n\n{$this->details}"; $this->fulfillment = $numCriteria ? $fulfillmentSum / $numCriteria : 0; } }
protected function main() { // Load the two files $xmlFile = ''; $dtdFile = ''; $this->loadFiles($this->absolutePathToFolder, $xmlFile, $dtdFile); // may add errors to the error list if ($this->hasErrors()) { return; } // Files loaded. $this->addGoals(array(self::goalWellFormedXml => 'XML is well-formed', self::goalValidXml => 'XML is valid to supplied DTD', self::goalValidDtd => 'DTD is valid', self::goalCorrectReferral => 'The XML\'s DOCTYPE declaration refers to the provided DTD.', self::goalCoveredDtd => 'DTD document contains required constructs', self::goalCoveredXml => 'XML document contains required constructs', self::goalCoveredSpecials => 'Documents contain required special constructs')); StringUtils::removeBomFromFile($dtdFile); $dtdString = file_get_contents($dtdFile); $xmlString = file_get_contents($xmlFile); $dtdString = $this->convertToUtf8($dtdString); $xmlString = $this->convertToUtf8($xmlString); if ($xmlString === false) { $this->addError("The XML file must be either in UTF-8 or in UTF-16."); } if ($dtdString === false) { $this->addError("The DTD file must be either in UTF-8 or in UTF-16."); } if ($this->hasErrors()) { return; } if ($this->loadXml($xmlFile, true, $xmlDom, $error)) { $xmlDom->formatOutput = true; /** * @var DOMDocument $xmlDomDocument */ $xmlDomDocument = $xmlDom; if (!$xmlDomDocument->doctype) { $this->failGoal(self::goalCorrectReferral, "The XML does not have a DOCTYPE declaration."); if ($this->checkDTDValidity($dtdString, "", $dtdDoc)) { $this->checkDTDConstructCoverage($dtdDoc); } else { $this->failGoal(self::goalCoveredDtd, 'Document did not pass DTD well-formedness and validity checks.'); } } else { if ($xmlDomDocument->doctype->systemId === basename($dtdFile) || $xmlDomDocument->doctype->systemId === "./" . basename($dtdFile)) { $this->reachGoal(self::goalCorrectReferral); } else { $this->failGoal(self::goalCorrectReferral, "The XML file refers to a different DTD than the one provided."); } $internalSubset = $xmlDomDocument->doctype->internalSubset; if ($this->checkDTDValidity($dtdString, $internalSubset, $dtdDoc)) { $this->checkDTDConstructCoverage($dtdDoc); } else { $this->failGoal(self::goalCoveredDtd, 'Document did not pass DTD well-formedness and validity checks.'); } } $this->reachGoal(self::goalWellFormedXml); $this->checkXMLValidity($xmlDom); $this->checkXMLConstructCoverage($xmlDom); $this->checkSpecialConstructCoverage($xmlString, $dtdString); } else { if ($this->checkDTDValidity($dtdString, "", $dtdDoc)) { $this->checkDTDConstructCoverage($dtdDoc); } else { $this->failGoal(self::goalCoveredDtd, 'Document did not pass DTD well-formedness and validity checks.'); } $this->failGoals(array(self::goalWellFormedXml, self::goalValidXml, self::goalCoveredXml, self::goalCoveredSpecials, self::goalCorrectReferral), $error); } }
/** * Creates message with custom formatting from supplied exception. * @param Exception $e * @return string error message with format: \<message\> (\<file\>:\<line\>) */ protected static function getCustomMessage(Exception $e) { return StringUtils::stripFunctionLinks($e->getMessage()) . ' (' . basename($e->getFile()) . ':' . $e->getLine() . ')'; }
/** * Performs the function of this script. */ protected function body() { if (!$this->userHasPrivileges(User::assignmentsSubmit)) { return; } if (!$this->isInputValid(array('assignmentId' => 'isIndex'))) { return; } $userId = User::instance()->getId(); $assignmentId = $this->getParams('assignmentId'); /** * @var $assignment \Assignment */ $assignment = Repositories::getEntityManager()->find('Assignment', $assignmentId); $query = "SELECT s, a FROM Subscription s, Assignment a WHERE s.group = a.group AND s.user = "******" AND a.id = " . $assignmentId; /** * @var $result \Subscription[] */ $result = Repositories::getEntityManager()->createQuery($query)->getResult(); if (count($result) === 0) { $this->stop(Language::get(StringID::HackerError)); return; } if ($result[0]->getStatus() == \Subscription::STATUS_REQUESTED) { $this->stop(Language::get(StringID::SubscriptionNotYetAccepted)); return; } $submissionsFolder = Config::get('paths', 'submissions'); $file = date('Y-m-d_H-i-s_') . $userId . '_' . StringUtils::randomString(10) . '.zip'; if (!$this->saveUploadedFile('submission', $submissionsFolder . $file)) { return; } // Create submission $newSubmission = new \Submission(); $newSubmission->setAssignment($assignment); $newSubmission->setSubmissionFile($file); $newSubmission->setUser(User::instance()->getEntity()); $newSubmission->setDate(new \DateTime()); // Put into database Repositories::persistAndFlush($newSubmission); // Launch plugin, or set full success if not connected to any plugin if ($assignment->getProblem()->getPlugin() === null) { $newSubmission->setSuccess(100); $newSubmission->setInfo(Language::get(StringID::NoPluginUsed)); $previousSubmissions = Repositories::makeDqlQuery("SELECT s FROM \\Submission s WHERE s.user = :sameUser AND s.assignment = :sameAssignment AND s.status != 'graded' AND s.status != 'deleted'")->setParameter('sameUser', User::instance()->getEntity()->getId())->setParameter('sameAssignment', $assignment->getId())->getResult(); foreach ($previousSubmissions as $previousSubmission) { $previousSubmission->setStatus(\Submission::STATUS_NORMAL); Repositories::getEntityManager()->persist($previousSubmission); } $newSubmission->setStatus(\Submission::STATUS_LATEST); Repositories::getEntityManager()->persist($newSubmission); Repositories::flushAll(); } else { Core::launchPlugin($assignment->getProblem()->getPlugin()->getType(), Config::get('paths', 'plugins') . $assignment->getProblem()->getPlugin()->getMainfile(), $submissionsFolder . $file, false, $newSubmission->getId(), explode(';', $assignment->getProblem()->getConfig())); } // Run checking for plagiarism $similarityJar = Config::get('paths', 'similarity'); if ($similarityJar != null && is_file($similarityJar)) { $arguments = "comparenew"; // Get config file and autoloader file $paths = Config::get('paths'); $vendorAutoload = $paths['composerAutoload']; $java = Config::get('bin', 'java'); $javaArguments = Config::get('bin', 'javaArguments'); $pathToCore = Config::get('paths', 'core'); // This code will be passed, shell-escaped to the PHP CLI $launchCode = <<<LAUNCH_CODE require_once '{$vendorAutoload}'; chdir("{$pathToCore}"); `"{$java}" {$javaArguments} -Dfile.encoding=UTF-8 -jar "{$similarityJar}" {$arguments}`; LAUNCH_CODE; ShellUtils::phpExecInBackground(Config::get('bin', 'phpCli'), $launchCode); } }
/** * Turns managed tests' results to plugin criteria or errors. * For criterion to be passed, all goals specified for that criterion when * @ref addTesterCriterion() "adding it" must be reached. Otherwise the * criterion is failed with fulfillment percentage based on number of failed * goals and failure info created by joining failure information of failed goals. */ private function checkTesterCriteria() { $failedTests = array(); foreach ($this->testerCriteria as $criterionName => $criterionConfig) { $goalCount = 0; $goalsFailed = 0; $details = ''; foreach ($criterionConfig as $testId => $goalIds) { if ($goalIds === null) { $goalIds = $criterionConfig[$testId] = array_keys($this->tests[$testId]->getGoals()); } $goalCount += count($goalIds); $results = $this->testResults[$testId]; foreach ($goalIds as $goalId) { $goal = isset($results['results'][$goalId]) ? $results['results'][$goalId] : array(); if (count($results['errors'])) { ++$goalsFailed; if (!$failedTests[$testId]) { $failedTests[$testId] = true; $details .= $results['name'] . ' didn\'t successfully finish' . "\n" . StringUtils::indent(implode("\n", $results['errors'])); } } elseif (!$goal['reached']) { ++$goalsFailed; $errorStr = $goal['error'] ? StringUtils::indent(trim($goal['error'])) . "\n" : ''; $details .= "{$goal['name']} ({$results['name']}) failed\n" . $errorStr; } } } $fulfillment = $goalCount > 0 ? floor(($goalCount - $goalsFailed) * 100 / $goalCount) : 100; $this->updateCriterion($criterionName, $goalsFailed == 0, $fulfillment, $details); } }