protected function body()
 {
     if (!$this->userHasPrivileges(User::pluginsAdd)) {
         return false;
     }
     $inputs = array('name' => array('isName', 'isNotEmpty'));
     if (!$this->isInputValid($inputs)) {
         return false;
     }
     $name = $this->getParams('name');
     $existingPluginsWithSameName = Repositories::getRepository(Repositories::Plugin)->findBy(['name' => $name]);
     if (count($existingPluginsWithSameName) > 0) {
         return $this->death(StringID::PluginNameAlreadyExists);
     }
     $pluginFile = $this->getUploadedFile('plugin');
     if (!$pluginFile) {
         return false;
     }
     $pluginFolder = Config::get('paths', 'plugins') . $name;
     if (file_exists($pluginFolder)) {
         return $this->death(StringID::PluginFolderAlreadyExists);
     }
     if (!Filesystem::createDir($pluginFolder)) {
         return $this->death(StringID::FileSystemError);
     }
     if (!Compression::unzip($pluginFile, $pluginFolder)) {
         $this->death(StringID::UnzipUnsuccessful);
         goto cleanup_error;
     }
     $manifestFile = $pluginFolder . DIRECTORY_SEPARATOR . 'manifest.xml';
     $manifest = null;
     if (!($manifest = $this->parsePluginManifest($manifestFile))) {
         $this->death(StringID::BadlyFormedPlugin);
         goto cleanup_error;
     }
     if (!file_exists($pluginFolder . DIRECTORY_SEPARATOR . $manifest['mainFile'])) {
         $this->death(StringID::BadlyFormedPlugin);
         goto cleanup_error;
     }
     $plugin = new \Plugin();
     $plugin->setIdentifier($manifest['identifier']);
     $plugin->setDescription($manifest['description']);
     $plugin->setConfig($manifest['arguments']);
     $plugin->setMainfile($name . '/' . $manifest['mainFile']);
     $plugin->setName($name);
     $plugin->setType($manifest['type']);
     Repositories::persistAndFlush($plugin);
     Filesystem::removeFile($pluginFile);
     return true;
     cleanup_error:
     Filesystem::removeDir($pluginFolder);
     Filesystem::removeFile($pluginFile);
     return false;
 }
 protected function body()
 {
     $plugins = Repositories::getRepository(Repositories::Plugin)->findAll();
     $errors = [];
     foreach ($plugins as $plugin) {
         /** @var $plugin \Plugin */
         $dbPhpFile = $plugin->getMainfile();
         $dbDescription = $plugin->getDescription();
         $dbIdentifier = $plugin->getIdentifier();
         $pluginDirectory = $this->getMainDirectory($dbPhpFile);
         if ($pluginDirectory === false) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_InvalidFolder);
             continue;
         }
         $manifestFile = Filesystem::combinePaths(Config::get('paths', 'plugins'), $pluginDirectory, "manifest.xml");
         $xml = new \DOMDocument();
         $success = $xml->load(realpath($manifestFile));
         if ($success === false) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_MalformedXmlOrFileMissing);
             continue;
         }
         $fileDescription = $xml->getElementsByTagName('description')->item(0);
         $fileArguments = $xml->getElementsByTagName('argument');
         $fileIdentifier = $xml->getElementsByTagName('identifier')->item(0);
         $fileArgumentsArray = [];
         for ($i = 0; $i < $fileArguments->length; $i++) {
             $fileArgumentsArray[] = trim($fileArguments->item($i)->nodeValue);
         }
         $fileArgumentsString = implode(';', $fileArgumentsArray);
         if ($dbDescription !== trim($fileDescription->nodeValue)) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_DescriptionMismatch);
             $plugin->setDescription(trim($fileDescription->nodeValue));
             Repositories::persist($plugin);
         }
         if ($dbIdentifier !== trim($fileIdentifier->nodeValue)) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_IdentifierMismatch);
             $plugin->setIdentifier(trim($fileIdentifier->nodeValue));
             Repositories::persist($plugin);
         }
         if ($plugin->getConfig() !== $fileArgumentsString) {
             $errors[] = $plugin->getName() . ": " . Language::get(StringID::ReloadManifests_ArgumentsMismatch);
             $plugin->setConfig($fileArgumentsString);
             Repositories::persist($plugin);
         }
     }
     Repositories::flushAll();
     if (count($errors) === 0) {
         $this->addOutput("text", Language::get(StringID::ReloadManifests_DatabaseCorrespondsToManifests));
     } else {
         $this->addOutput("text", implode('<br>', $errors));
     }
     return true;
 }
 public function testRotation()
 {
     if (file_exists('log')) {
         rmdir('log');
     }
     mkdir("log");
     $logger = Logger::create("log")->setDatetimeFormat("")->setEntrySeparator("")->setLineSeparator("")->setPrefix("l")->setSuffix("")->setMaxFileCount(4)->setMaxFileSize(10)->setHeader("");
     // Header is therefore one space that separates the (empty) date from the (empty) header text
     $logger->log("A23456789");
     $logger->flush();
     $logger->log("B23456789");
     $logger->flush();
     $logger->log("C23456789");
     $logger->flush();
     $logger->log("D23456789");
     $logger->flush();
     $logger->log("E23456789");
     $logger->flush();
     $logger->log("F23456789");
     $logger->flush();
     $logger->log("G23456789");
     $logger->flush();
     // We have filled 7 files, and maximum file count is 4.
     // It should have gone:
     // A l0
     // B l0, l1
     // C l0, l1, l2
     // D l0, l1, l2, l3
     // E l1, l2, l3, l4
     // F l0, l2, l3, l4
     // G l0, l1, l3, l4, where l1 is newest and l3 oldest
     $this->assertFileExists('log/l0');
     $this->assertFileExists('log/l1');
     $this->assertFileNotExists('log/l2');
     $this->assertFileExists('log/l3');
     $this->assertFileExists('log/l4');
     $this->assertFileNotExists('log/l5');
     $this->assertFileNotExists('log/l6');
     $this->assertFileNotExists('log/l7');
     $this->assertSame(' D23456789', file_get_contents('log/l3'));
     $this->assertSame(' E23456789', file_get_contents('log/l4'));
     $this->assertSame(' F23456789', file_get_contents('log/l0'));
     $this->assertSame(' G23456789', file_get_contents('log/l1'));
     \asm\utils\Filesystem::removeDir("log");
 }
 protected function body()
 {
     if (!$this->isInputValid(array('id' => 'isIndex'))) {
         return false;
     }
     $id = $this->getParams('id');
     /**
      * @var $attachment \Attachment
      */
     $attachment = Repositories::findEntity(Repositories::Attachment, $id);
     if (!$this->authorizedToManageLecture($attachment->getLecture())) {
         return false;
     }
     $folder = Config::get('paths', 'attachments');
     $file = $attachment->getFile();
     RemovalManager::deleteAttachmentById($id);
     Filesystem::removeFile($folder . $file);
     return true;
 }
 protected function body()
 {
     if (!$this->userHasPrivileges(User::pluginsRemove)) {
         return false;
     }
     if (!$this->isInputValid(array('id' => 'isIndex'))) {
         return false;
     }
     $id = $this->getParams('id');
     /**
      * @var $plugin \Plugin
      */
     $plugin = Repositories::findEntity(Repositories::Plugin, $id);
     $pluginFolder = Filesystem::combinePaths(Config::get('paths', 'plugins'), $plugin->getName());
     if (!Filesystem::removeDir($pluginFolder)) {
         return $this->death(StringID::FileSystemError);
     }
     RemovalManager::deletePluginById($id);
     return true;
 }
 function run($array)
 {
     $zipFile = $array[0];
     if (count($array) !== 2) {
         throw new InvalidArgumentException("This must receive 2 parameters in the array exactly.");
     }
     $launcher = new \asm\core\JavaLauncher();
     $pluginResults = "";
     $response = null;
     $error = $launcher->launch(Filesystem::combinePaths(CheckerRunner::$xmlCheckRoot, "/files/plugins/XML XQuery/XQueryPlugin.jar"), array($zipFile, $array[1]), $responseString);
     if (!$error) {
         if (isset($responseString)) {
             try {
                 $response = \asm\plugin\PluginResponse::fromXmlString($responseString);
             } catch (Exception $ex) {
                 $response = \asm\plugin\PluginResponse::createError('Internal error. Plugin did not supply valid response XML and this error occured: ' . $ex->getMessage() . '. Plugin instead supplied this response string: ' . $responseString);
             }
         }
     } else {
         $response = \asm\plugin\PluginResponse::createError('Plugin cannot be launched (' . $error . ').');
     }
     return $response;
 }
Example #7
0
 /**
  * Resolves supplied partial path using supplied base.
  * @param string $parent base for @c $child
  * @param string $child partial path to be resolved
  * @return string absolute path of @c $child appended to @c $parent with
  *        OS-dependent directory separators replaced by UNIX-style slashes (or
  * @throws Exception when the combined paths don't point to an actual file on the filesystem
  */
 private function resolvePath($parent, $child)
 {
     $realPath = realpath(Filesystem::combinePaths($parent, $child));
     if ($realPath !== false) {
         $realPath = str_replace('\\', '/', $realPath);
         return is_dir($realPath) ? $realPath . '/' : $realPath;
     } else {
         throw new Exception("The parent path '{$parent}' and the child path '{$child}' combined do not point to any file on the filesystem. Perhaps your internal.ini file is wrong?'");
     }
 }
Example #8
0
 /**
  * (Creates and) sets folder for log files to be saved in.
  * @param string $folder logfile folder
  */
 private function __construct($folder)
 {
     Filesystem::createDir($folder, 0700);
     $this->folder = realpath($folder);
 }
 public function testGetFiles()
 {
     $this->assertEquals(['a.txt', 'b.txt'], Filesystem::getFiles(self::TEST_DIRECTORY));
 }
Example #10
0
    /**
     * Evaluates XPath expressions on XML and outputs results to files.
     * @param DOMDocument $xmlDom source XML
     * @param array $expressions XPath expressions
     * @param array $comments XPath comments belonging to @a $expressions
     * @return bool true on success
     */
    protected function evaluateXpathExpressions($xmlDom, $expressions, $comments)
    {
        $evaluator = new DOMXpath($xmlDom);
        $exprNumber = 0;
        for ($i = 0; $i < count($expressions); ++$i) {
            $expr = $expressions[$i];
            $this->useLibxmlErrors();
            $result = $evaluator->query($expr);
            $errors = $this->getLibxmlErrors();
            if ($errors) {
                return $this->failGoal(self::goalValidXpath, "XPath expression is invalid ({$expr}).");
            }
            $exprComments = !isset($comments[$i]) || empty($comments[$i]) ? '' : <<<COMMENTS
#\tComments from expression file:

{$comments[$i]}

COMMENTS;
            $output = <<<HEADER
#\tResults for XPath expression: {$expr}
{$exprComments}
#\tFound {$result->length} matching DOM nodes.
HEADER;
            $delimiter = "\n\n#\t%s result:\n\n";
            for ($j = 0; $j < $result->length; ++$j) {
                $output .= sprintf($delimiter, "Result " . ($j + 1)) . $xmlDom->saveXML($result->item($j));
            }
            Filesystem::stringToFile(sprintf($this->params[self::outputXpathMask], ++$exprNumber), $output);
        }
        return $this->reachGoal(self::goalValidXpath);
    }
Example #11
0
 /**
  * Runs plugin with supplied arguments.
  *
  * @li First element in @c $args must be a path to ZIP archive with input data.
  * @li Plugin execution is stopped on all triggered errors or uncaught exceptions
  *		and plugin error is returned.
  * @li setUp() and execute() methods are run respectively after input is
  *		unpacked and output folder is created.
  * @li Plugin creates and later removes two temporary folders. It can also create
  *		one ZIP archive with plugin output (path is returned in plugin results).
  * 
  * @param array $args simple array with plugin arguments
  * @return PluginResponse plugin results or error
  */
 public final function run(array $args)
 {
     set_error_handler(array('asm\\utils\\Utils', 'turnErrorToException'));
     $cwd = getcwd();
     try {
         if ($args == null || count($args) < 1) {
             throw new PluginUseException('Data file argument missing');
         }
         $this->dataFolder = Filesystem::tempDir();
         $dataFile = array_shift($args);
         if (!Compression::unzip($dataFile, $this->dataFolder, $unzipMessage)) {
             $response = PluginResponse::createError("ZIP extraction failed (" . $unzipMessage . ").\n\nPerhaps you did not submit a ZIP file " . "or that file was corrupted during upload. You may try again. Extraction was attempted to folder " . str_replace("\\", "/", $this->dataFolder));
         } else {
             $this->outputFolder = Filesystem::tempDir();
             chdir($this->dataFolder);
             $this->setUp($args);
             $this->execute();
             chdir($cwd);
             $outputFile = $this->packOutput();
             $outputPath = $outputFile != null ? realpath($outputFile) : null;
             $response = PluginResponse::create($this->results, $outputPath);
         }
     } catch (PluginException $e) {
         $response = PluginResponse::createError($e->getMessage());
     } catch (Exception $e) {
         $response = PluginResponse::createError('Runtime error: ' . $e->getMessage() . " (file " . $e->getFile() . ", line " . $e->getLine());
     }
     // If an exception occurred during $this->setUp or $this->execute, we must still change the current directory back,
     // in case more plugins are to be run (in a test case battery)
     chdir($cwd);
     restore_error_handler();
     if ($this->dataFolder != null) {
         Filesystem::removeDir($this->dataFolder);
     }
     if ($this->outputFolder != null) {
         Filesystem::removeDir($this->outputFolder);
     }
     return $response;
 }
Example #12
0
 /**
  * Attempts to find an XML and an XSL filename in the given folder and adds an error if it cannot find them.
  * @param $fromWhere string directory from where to load the files
  * @param $xmlFile string The found XML filename.
  * @param $xslFile string The found XSL filename.
  */
 private function loadFiles($fromWhere, &$xmlFile, &$xslFile)
 {
     $xmlFile = false;
     $xslFile = false;
     $files = \asm\utils\Filesystem::getFiles($fromWhere);
     foreach ($files as $file) {
         if (Utils::endsWith(strtolower($file), ".xml")) {
             if ($xmlFile === false) {
                 $xmlFile = \asm\utils\Filesystem::combinePaths($fromWhere, $file);
             } else {
                 $this->addError("There are two or more .xml files in your submission. There must only be one.");
             }
         }
         if (Utils::endsWith(strtolower($file), ".xsl")) {
             if ($xslFile === false) {
                 $xslFile = \asm\utils\Filesystem::combinePaths($fromWhere, $file);
             } else {
                 $this->addError("There are two or more .xsl files in your submission. There must only be one.");
             }
         }
     }
     if ($xmlFile === false) {
         $this->addError("Your submission must contain an XML file ending with '.xml'.");
     }
     if ($xslFile === false) {
         $this->addError("Your submission must contain an XSL file ending with '.xsl'.");
     }
 }
 protected function tearDown()
 {
     \asm\utils\Filesystem::removeFile("myconfig.ini");
     \asm\utils\Filesystem::removeFile("myconfig2.ini");
 }
 private function runSchemaTest($zipFile, $fulfillment = null, $details = "")
 {
     $result = CheckerRunner::runChecker(new XmlSchemaChecker(), Filesystem::combinePaths(CheckerRunner::$testCasesRoot, "SCHEMA", $zipFile), []);
     CheckerRunner::assert($this, $zipFile, $result, $fulfillment, $details);
 }
Example #15
0
 private function runXsltTest($zipFile, $templateCount, $fulfillment = null, $details = "")
 {
     $result = CheckerRunner::runChecker(new XsltChecker(), Filesystem::combinePaths(CheckerRunner::$testCasesRoot, "XSLT", $zipFile), [$templateCount]);
     CheckerRunner::assert($this, $zipFile, $result, $fulfillment, $details);
 }
<?php

namespace asm\unittests;

use asm\core\Config;
use asm\utils\Filesystem;
$xmlcheckRoot = "../../www";
require_once $xmlcheckRoot . "/vendor/autoload.php";
Config::init(Filesystem::combinePaths($xmlcheckRoot, "core/config.ini"), Filesystem::combinePaths($xmlcheckRoot, "core/internal.ini"));
class CheckerRunner
{
    public static $xmlCheckRoot = "../../www";
    public static $testCasesRoot = "../plugins/cases";
    /**
     * @param $checker mixed A class with a run() method
     * @param $zipFile string The path to the zip file with the test case
     * @param $arguments array Configuration of the plugin
     * @return \asm\plugin\PluginResponse
     */
    public static function runChecker($checker, $zipFile, $arguments)
    {
        $testResult = $checker->run(array_merge([$zipFile], $arguments));
        return $testResult;
    }
    /**
     * @param $testCase PHPUnit_Framework_TestCase
     * @param $result \asm\plugin\PluginResponse
     * @param $fulfillment int
     * @param $details string
     */
    public static function assert($testCase, $filename, $result, $fulfillment = null, $details = "")
Example #17
0
 /**
  * Save pre-uploaded file to permanent storage [stopping].
  * @param string $id file ID
  * @param string $destination destination to which the file is to be moved
  * @return bool success
  * @see getUploadedFile()
  * @see UploadManager
  */
 protected final function saveUploadedFile($id, $destination)
 {
     $src = $this->getUploadedFile($id);
     if (!$src) {
         return false;
     }
     if (!rename($src, Filesystem::realPath($destination))) {
         return $this->stop(Language::get(StringID::UploadUnsuccessful));
     }
     return true;
 }
 /**
  * Deletes test with supplied ID (with input & output files).
  * @param int $id test ID
  * @return array error properties provided by removalError() or retrievalError(),
  * or false in case of success
  */
 public static function deleteTestById($id)
 {
     /**
      * @var $test \PluginTest
      */
     $test = Repositories::findEntity(Repositories::PluginTest, $id);
     $testFolder = Config::get('paths', 'tests');
     // Delete input solution file
     if (is_file(Filesystem::combinePaths($testFolder, $test->getInput()))) {
         Filesystem::removeFile(Filesystem::combinePaths($testFolder, $test->getInput()));
     }
     // Delete plugin test output
     if (is_file(Filesystem::combinePaths($testFolder, $test->getOutput()))) {
         Filesystem::removeFile(Filesystem::combinePaths($testFolder, $test->getOutput()));
     }
     Repositories::remove($test);
     return false;
 }
Example #19
0
 private function runDtdTest($zipFile, $fulfillment = null, $details = "")
 {
     $result = CheckerRunner::runChecker(new Dtd2014Checker(), Filesystem::combinePaths(CheckerRunner::$testCasesRoot, "DTD", $zipFile), [0, 0]);
     CheckerRunner::assert($this, $zipFile, $result, $fulfillment, $details);
 }
 /**
  * Unpack ZIP archive to specified folder.
  * If it contains only a single directory and nothing else, its contents are extracted instead of the entire ZIP file. This also happens if the only other directory is the "__MACOSX" metadata folder that Macintosh operating systems add to generated ZIP files.
  *
  * This function is a security vulnerability. Possible attacks include a very large ZIP file, such as a ZIP bomb, or putting in a file with a relative path such as '../etc/passwd'.
  *
  *
  * @param string $archive source archive path
  * @param string $destination destination folder path
  * @param [out]string $errorMessage why did the extraction fail?
  * @return true on success
  */
 public static function unzip($archive, $destination, &$errorMessage = null)
 {
     $zip = new ZipArchive();
     $errorCode = $zip->open($archive);
     if ($errorCode !== true) {
         $errorMessage = "could not open ZIP file (error code " . $errorCode . ")";
         return false;
     }
     // Otherwise, this is a normal ZIP file.
     if (!$zip->extractTo($destination)) {
         $zip->close();
         $errorMessage = "extraction failed";
         return false;
     }
     $zip->close();
     // Now, we'll check if the ZIP file contains only a single folder. If so,
     // then we'll copy its contests to the root temporary folder, then remove the original folder.
     $files = scandir($destination);
     if ($files === false) {
         $errorMessage = "scanning the temporary directory failed";
         return false;
     }
     // On Linux, scandir returns the "." and ".." pseudofolders we are not interested in
     $files = array_diff($files, [".", ".."]);
     // For ZIP files generated on Mac OS X, we are not interested in the metadata folder.
     $files = array_diff($files, ["__MACOSX"]);
     if (count($files) === 0) {
         $errorMessage = "the ZIP file is empty";
         return false;
     } elseif (count($files) === 1) {
         // We renumber the remaining file/directory so that it is at index 0. It might not have been because of the subtraction of "." and ".."
         $files = array_values($files);
         $soleDirectory = Filesystem::combinePaths($destination, $files[0]);
         if (is_dir($soleDirectory)) {
             if (Filesystem::copyIntoDirectory($soleDirectory, $destination)) {
                 Filesystem::removeDir($soleDirectory);
                 return true;
             } else {
                 $errorMessage = "the ZIP file contained a single directory, but copying its contents to temporary directory failed";
                 return false;
             }
         }
     }
     return true;
 }
Example #21
0
 private function runXPathTest($zipFile, $fulfillment = null, $details = "")
 {
     $result = CheckerRunner::runChecker(new XpathChecker(), Filesystem::combinePaths(CheckerRunner::$testCasesRoot, "XPATH", $zipFile), [5]);
     CheckerRunner::assert($this, $zipFile, $result, $fulfillment, $details);
 }