Updated all dependencies and prepared for PHP 8

This commit is contained in:
2026-06-19 09:37:22 +00:00
parent 941c9104dc
commit 5f9f6ca2ff
21 changed files with 3334 additions and 2643 deletions
+2
View File
@@ -1,6 +1,8 @@
vendor vendor
build build
cache cache
stacks
config.php
.cache .cache
.config .config
.local .local
+4 -7
View File
@@ -1,13 +1,10 @@
FROM cloudobjects/php-app-base:latest FROM cloudobjects/php-app-base:8.4
# Add application code # Add application code
ADD / /var/www/app/ ADD / /www/
# Add an executable to the Docker container for CLI use # Add an executable to the Docker container for CLI use
RUN mv /var/www/app/phpmae.docker /usr/local/bin/phpmae && chmod +x /usr/local/bin/phpmae RUN mv /www/phpmae.docker /usr/local/bin/phpmae && chmod +x /usr/local/bin/phpmae
# Have default config.php ready for CLI where init may not run # Have default config.php ready for CLI where init may not run
RUN cp /var/www/app/config.php.default /var/www/app/config.php RUN cp /www/config.php.default /www/config.php
# Launch init script
CMD ["/bin/sh", "/var/www/app/init.sh"]
+3 -2
View File
@@ -1,7 +1,8 @@
<?php <?php
use Symfony\Component\Finder\Finder; use Symfony\Component\Finder\Finder;
use CloudObjects\SDK\COIDParser, CloudObjects\SDK\ObjectRetriever; use CloudObjects\SDK\COIDParser, CloudObjects\SDK\ObjectRetriever,
CloudObjects\SDK\Constants;
use Webmozart\Assert\Assert; use Webmozart\Assert\Assert;
/** /**
@@ -182,7 +183,7 @@ class RoboFile extends \Robo\Tasks {
$this->taskWriteToFile($stackDir.'/meta.json') $this->taskWriteToFile($stackDir.'/meta.json')
->text(json_encode([ ->text(json_encode([
'rev' => $stackObject->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue(), 'rev' => $stackObject->getProperty(Constants::PROPERTY_REVISION)->getValue(),
'whitelisted_classes' => $whitelistedClasses 'whitelisted_classes' => $whitelistedClasses
])) ]))
->run(); ->run();
+4 -4
View File
@@ -12,7 +12,7 @@ use DI\Container, DI\FactoryInterface, Invoker\InvokerInterface;
use DI\Definition\Source\DefinitionArray, DI\Definition\Source\SourceChain; use DI\Definition\Source\DefinitionArray, DI\Definition\Source\SourceChain;
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\RequestInterface;
use CloudObjects\SDK\ObjectRetriever, CloudObjects\SDK\COIDParser, use CloudObjects\SDK\ObjectRetriever, CloudObjects\SDK\COIDParser,
CloudObjects\SDK\NodeReader; CloudObjects\SDK\NodeReader, CloudObjects\SDK\Constants;
use CloudObjects\PhpMAE\Exceptions\PhpMAEException; use CloudObjects\PhpMAE\Exceptions\PhpMAEException;
class ClassRepository { class ClassRepository {
@@ -147,8 +147,8 @@ class ClassRepository {
$objectRetriever = $this->container->get(ObjectRetriever::class); $objectRetriever = $this->container->get(ObjectRetriever::class);
// Get revision // Get revision
$revision = $object->getProperty(ObjectRetriever::REVISION_PROPERTY) $revision = $object->getProperty(Constants::PROPERTY_REVISION)
? $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() ? $object->getProperty(Constants::PROPERTY_REVISION)->getValue()
: 'LocalConfig'; : 'LocalConfig';
// Build filename where cached version should exist // Build filename where cached version should exist
@@ -265,7 +265,7 @@ class ClassRepository {
else else
$sourceCode = $objectRetriever->getAttachment($uri, $sourceUrl->getValue()); $sourceCode = $objectRetriever->getAttachment($uri, $sourceUrl->getValue());
} }
// Run source code through validator to ensure sanity // Run source code through validator to ensure sanity
$validator = new ClassValidator; $validator = new ClassValidator;
$validator->validateInterface($sourceCode, $uri); $validator->validateInterface($sourceCode, $uri);
+2 -3
View File
@@ -8,7 +8,7 @@ namespace CloudObjects\PhpMAE;
use CloudObjects\PhpMAE\Sandbox\CustomizedSandbox; use CloudObjects\PhpMAE\Sandbox\CustomizedSandbox;
use PHPSandbox\SandboxWhitelistVisitor, PHPSandbox\ValidatorVisitor; use PHPSandbox\SandboxWhitelistVisitor, PHPSandbox\ValidatorVisitor;
use PhpParser\ParserFactory, PhpParser\NodeTraverser; use PhpParser\ParserFactory, PhpParser\PhpVersion, PhpParser\NodeTraverser;
use ML\IRI\IRI; use ML\IRI\IRI;
use CloudObjects\SDK\COIDParser; use CloudObjects\SDK\COIDParser;
use CloudObjects\PhpMAE\Exceptions\PhpMAEException; use CloudObjects\PhpMAE\Exceptions\PhpMAEException;
@@ -43,7 +43,6 @@ class ClassValidator {
'GuzzleHttp\Client', 'GuzzleHttp\Client',
'GuzzleHttp\HandlerStack', 'GuzzleHttp\Middleware', 'GuzzleHttp\HandlerStack', 'GuzzleHttp\Middleware',
'GuzzleHttp\Handler\CurlHandler', 'GuzzleHttp\Handler\CurlHandler',
'GuzzleHttp\Subscriber\Oauth\Oauth1',
'GuzzleHttp\Promise', 'GuzzleHttp\Promise',
'Dflydev\FigCookies\SetCookie', 'Dflydev\FigCookies\SetCookie',
'Symfony\Component\Mime\Email', 'Symfony\Component\Mime\Email',
@@ -105,7 +104,7 @@ class ClassValidator {
$stack = ClassRepository::DEFAULT_STACK) { $stack = ClassRepository::DEFAULT_STACK) {
// Initialize parser and parse source code // Initialize parser and parse source code
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7); $parser = (new ParserFactory)->createForVersion(PhpVersion::getHostVersion());
$ast = $parser->parse($sourceCode); $ast = $parser->parse($sourceCode);
// Parse and dump use statements // Parse and dump use statements
+1 -1
View File
@@ -14,7 +14,7 @@ use Psr\Http\Message\RequestInterface, Psr\Http\Message\ResponseInterface;
use DI\ContainerBuilder; use DI\ContainerBuilder;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Cache\FilesystemCache; use Doctrine\Common\Cache\FilesystemCache;
use Slim\Http\Response; use Slim\Psr7\Response;
use Symfony\Component\Mailer\MailerInterface, use Symfony\Component\Mailer\MailerInterface,
Symfony\Component\Mailer\Transport, Symfony\Component\Mailer\Mailer; Symfony\Component\Mailer\Transport, Symfony\Component\Mailer\Mailer;
use CloudObjects\SDK\ObjectRetriever, CloudObjects\SDK\NodeReader, CloudObjects\SDK\COIDParser; use CloudObjects\SDK\ObjectRetriever, CloudObjects\SDK\NodeReader, CloudObjects\SDK\COIDParser;
+1 -1
View File
@@ -20,7 +20,7 @@ class SandboxedContainer implements ContainerInterface {
$this->container = $container; $this->container = $container;
} }
public function has($id) { public function has($id) : bool {
return $this->container->has($id); return $this->container->has($id);
} }
@@ -16,7 +16,7 @@ use DI\Definition\Source\DefinitionSource, DI\Definition\Source\Autowiring,
*/ */
class WhitelistReflectionBasedAutowiring extends ReflectionBasedAutowiring implements DefinitionSource, Autowiring { class WhitelistReflectionBasedAutowiring extends ReflectionBasedAutowiring implements DefinitionSource, Autowiring {
public function autowire(string $name, ObjectDefinition $definition = null) { public function autowire(string $name, ?ObjectDefinition $definition = null) : ?ObjectDefinition {
return isset($definition) ? parent::autowire($name, $definition) : null; return isset($definition) ? parent::autowire($name, $definition) : null;
} }
+47 -43
View File
@@ -10,8 +10,9 @@ use Psr\Http\Message\RequestInterface, Psr\Http\Message\ResponseInterface,
Psr\Http\Message\ServerRequestInterface; Psr\Http\Message\ServerRequestInterface;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Server\RequestHandlerInterface;
use Slim\App; use Slim\Psr7\Response;
use Slim\Http\Headers, Slim\Http\Request, Slim\Http\Response, Slim\Http\Environment; use Slim\Factory\ServerRequestCreatorFactory;
use Slim\ResponseEmitter;
use ML\IRI\IRI; use ML\IRI\IRI;
use ML\JsonLD\Node; use ML\JsonLD\Node;
use Tuupola\Middleware\HttpBasicAuthentication, use Tuupola\Middleware\HttpBasicAuthentication,
@@ -27,7 +28,7 @@ use CloudObjects\PhpMAE\Exceptions\PhpMAEException;
class Engine implements RequestHandlerInterface { class Engine implements RequestHandlerInterface {
const SKEY = '__self'; const SKEY = '__self';
const PREPARE_TIME_LIMIT = 2; const PREPARE_TIME_LIMIT = 2;
const CLASS_TIME_LIMIT = 5; const CLASS_TIME_LIMIT = 5;
@@ -35,7 +36,6 @@ class Engine implements RequestHandlerInterface {
private $objectRetriever; private $objectRetriever;
private $classRepository; private $classRepository;
private $slim;
private $container; private $container;
private $reader; private $reader;
@@ -43,12 +43,11 @@ class Engine implements RequestHandlerInterface {
private $runClass; private $runClass;
public function __construct(ObjectRetriever $objectRetriever, public function __construct(ObjectRetriever $objectRetriever,
ClassRepository $classRepository, App $slim, ClassRepository $classRepository,
ErrorHandler $errorHandler, ContainerInterface $container) { ErrorHandler $errorHandler, ContainerInterface $container) {
$this->objectRetriever = $objectRetriever; $this->objectRetriever = $objectRetriever;
$this->classRepository = $classRepository; $this->classRepository = $classRepository;
$this->slim = $slim;
$this->container = $container; $this->container = $container;
$this->reader = new NodeReader([ $this->reader = new NodeReader([
'prefixes' => [ 'prefixes' => [
@@ -62,7 +61,7 @@ class Engine implements RequestHandlerInterface {
}, $errorHandler); // see: http://stackoverflow.com/questions/4410632/handle-fatal-errors-in-php-using-register-shutdown-function }, $errorHandler); // see: http://stackoverflow.com/questions/4410632/handle-fatal-errors-in-php-using-register-shutdown-function
} }
private function isObjectPublic() { private function isObjectPublic() {
return ($this->reader->hasProperty($this->object, 'co:isVisibleTo') return ($this->reader->hasProperty($this->object, 'co:isVisibleTo')
&& $this->reader->getFirstValueIRI($this->object, 'co:isVisibleTo') && $this->reader->getFirstValueIRI($this->object, 'co:isVisibleTo')
->equals(self::CO_PUBLIC) ->equals(self::CO_PUBLIC)
@@ -85,13 +84,13 @@ class Engine implements RequestHandlerInterface {
return new CorsMiddleware($defaultConfig); // every origin is allowed, by class return new CorsMiddleware($defaultConfig); // every origin is allowed, by class
$origins = $this->reader->getAllValuesString($this->object, 'phpmae:allowsCORSOrigin'); $origins = $this->reader->getAllValuesString($this->object, 'phpmae:allowsCORSOrigin');
if ($this->container->has('global_cors_origins')) if ($this->container->has('global_cors_origins'))
$origins = array_merge($origins, explode('|', $this->container->get('global_cors_origins'))); $origins = array_merge($origins, explode('|', $this->container->get('global_cors_origins')));
if (count($origins) == 0 || trim($origins[0]) == '') if (count($origins) == 0 || trim($origins[0]) == '')
return null; // no CORS enabled return null; // no CORS enabled
return new CorsMiddleware(array_merge($defaultConfig, [ return new CorsMiddleware(array_merge($defaultConfig, [
'origin' => $origins 'origin' => $origins
])); // configured CORS middleware ])); // configured CORS middleware
@@ -120,14 +119,14 @@ class Engine implements RequestHandlerInterface {
== SharedSecretAuthentication::RESULT_OK); == SharedSecretAuthentication::RESULT_OK);
if ($authResult != true) if ($authResult != true)
continue; continue;
if (substr($as, 14) == 'runclass') if (substr($as, 14) == 'runclass')
$authenticated = (substr($object->getId(), 7, strlen($args['user']) +1) == $args['user'].'/'); $authenticated = (substr($object->getId(), 7, strlen($args['user']) +1) == $args['user'].'/');
else else
$authenticated = (substr($as, 14) == 'coid://'.$args['user']); $authenticated = (substr($as, 14) == 'coid://'.$args['user']);
} elseif (substr($as, 0, 4) != 'none') } elseif (substr($as, 0, 4) != 'none')
throw new PhpMAEException("Unsupported authentication scheme!"); throw new PhpMAEException("Unsupported authentication scheme!");
if ($authenticated == true) if ($authenticated == true)
break; break;
} }
@@ -149,14 +148,14 @@ class Engine implements RequestHandlerInterface {
if ($this->reader->getFirstValueBool($this->object, 'phpmae:allowsGETRequests')) if ($this->reader->getFirstValueBool($this->object, 'phpmae:allowsGETRequests'))
$input = $request->getQueryParams(); $input = $request->getQueryParams();
else else
return (new Response(405)); return new Response(405);
} elseif ($request->getMethod() == 'POST') { } elseif ($request->getMethod() == 'POST') {
// POST is always allowed // POST is always allowed
$input = $request->getParsedBody(); $input = $request->getParsedBody();
if (!is_array($input)) if (!is_array($input))
$input = []; $input = [];
} else } else
return (new Response(405)); return new Response(405);
set_time_limit($this->container->has('execution_time_limit') set_time_limit($this->container->has('execution_time_limit')
? $this->container->get('execution_time_limit') : self::CLASS_TIME_LIMIT); ? $this->container->get('execution_time_limit') : self::CLASS_TIME_LIMIT);
@@ -171,25 +170,29 @@ class Engine implements RequestHandlerInterface {
*/ */
public function generateResponse($content) { public function generateResponse($content) {
$lowercaseContent = is_string($content) ? strtolower($content) : ''; $lowercaseContent = is_string($content) ? strtolower($content) : '';
if (!isset($content)) if (!isset($content)) {
// Empty response // Empty response
$response = new Response(204); $response = new Response(204);
elseif (is_string($content) && (substr($lowercaseContent, 0, 5) == '<html' || substr($lowercaseContent, 0, 14) == '<!doctype html')) } elseif (is_string($content) && (substr($lowercaseContent, 0, 5) == '<html' || substr($lowercaseContent, 0, 14) == '<!doctype html')) {
// HTML response // HTML response
$response = (new Response)->write($content); $response = new Response(200);
elseif (is_string($content) && (substr($lowercaseContent, 0, 7) == 'http://' || substr($lowercaseContent, 0, 8) == 'https://')) $response->getBody()->write($content);
} elseif (is_string($content) && (substr($lowercaseContent, 0, 7) == 'http://' || substr($lowercaseContent, 0, 8) == 'https://')) {
// Redirect response // Redirect response
$response = (new Response)->withRedirect($content); $response = (new Response(302))->withHeader('Location', $content);
elseif (is_string($content) || is_numeric($content)) } elseif (is_string($content) || is_numeric($content)) {
// Plain text response // Plain text response
$response = (new Response)->withHeader('Content-Type', 'text/plain')->write($content); $response = (new Response(200))->withHeader('Content-Type', 'text/plain');
elseif (is_object($content) && in_array(ResponseInterface::class, class_implements($content))) $response->getBody()->write((string)$content);
} elseif (is_object($content) && in_array(ResponseInterface::class, class_implements($content))) {
// Existing response to pass through // Existing response to pass through
$response = $content; $response = $content;
else } else {
// JSON response (default) // JSON response (default)
$response = (new Response)->withJson($content); $response = (new Response(200))->withHeader('Content-Type', 'application/json');
$response->getBody()->write(json_encode($content));
}
// TODO: add support for XML // TODO: add support for XML
// Add cookies if any // Add cookies if any
@@ -199,7 +202,7 @@ class Engine implements RequestHandlerInterface {
$response = FigResponseCookies::set($response, $cookie); $response = FigResponseCookies::set($response, $cookie);
} }
} }
return $response; return $response;
} }
@@ -219,7 +222,8 @@ class Engine implements RequestHandlerInterface {
* Start execution of a request. * Start execution of a request.
*/ */
public function execute(RequestInterface $request) { public function execute(RequestInterface $request) {
$path = rtrim($request->getUri()->getBasePath().$request->getUri()->getPath(), '/'); $path = $request->getUri()->getPath();
switch ($path) { switch ($path) {
case "": case "":
case "/": case "/":
@@ -227,7 +231,7 @@ class Engine implements RequestHandlerInterface {
$file = ($this->container $file = ($this->container
->get(InteractiveRunController::class) ->get(InteractiveRunController::class)
->isEnabled()) ? 'app.html' : 'app_disabled.html'; ->isEnabled()) ? 'app.html' : 'app_disabled.html';
return $this->generateResponse(file_get_contents(__DIR__.'/../static/'.$file)); return $this->generateResponse(file_get_contents(__DIR__.'/../static/'.$file));
case "/run": case "/run":
// Run interactive code request // Run interactive code request
@@ -243,7 +247,8 @@ class Engine implements RequestHandlerInterface {
if (file_exists(__DIR__.'/../static'.$path)) { if (file_exists(__DIR__.'/../static'.$path)) {
// Proxy for static files // Proxy for static files
$filename = realpath(__DIR__.'/../static'.$path); $filename = realpath(__DIR__.'/../static'.$path);
$response = (new Response)->write(file_get_contents($filename)); $response = new Response(200);
$response->getBody()->write(file_get_contents($filename));
switch (pathinfo($filename, PATHINFO_EXTENSION)) { switch (pathinfo($filename, PATHINFO_EXTENSION)) {
case "css": case "css":
return $response->withHeader('Content-Type', 'text/css'); return $response->withHeader('Content-Type', 'text/css');
@@ -252,12 +257,12 @@ class Engine implements RequestHandlerInterface {
default: default:
return $response; return $response;
} }
} }
$coid = COIDParser::fromString(substr($path, 1)); $coid = COIDParser::fromString(substr($path, 1));
$this->loadRunClass($coid, $request); $this->loadRunClass($coid, $request);
// Process a standard request for a phpMAE class // Process a standard request for a phpMAE class
$queue = [ $queue = [
$this->getCORSMiddleware(), $this->getCORSMiddleware(),
@@ -266,7 +271,7 @@ class Engine implements RequestHandlerInterface {
]; ];
$relay = new Relay( $relay = new Relay(
array_filter($queue, function ($q) { array_filter($queue, function ($q) {
return $q !== null; return $q !== null;
}) })
); );
return $relay->handle($request); return $relay->handle($request);
@@ -278,7 +283,7 @@ class Engine implements RequestHandlerInterface {
*/ */
public function loadRunClass(IRI $coid, RequestInterface $request = null) { public function loadRunClass(IRI $coid, RequestInterface $request = null) {
if (COIDParser::isValidCOID($coid) && COIDParser::getType($coid) != COIDParser::COID_ROOT) { if (COIDParser::isValidCOID($coid) && COIDParser::getType($coid) != COIDParser::COID_ROOT) {
$this->object = $this->objectRetriever->get($coid); $this->object = $this->objectRetriever->getObjectNode($coid);
if (!isset($this->object)) if (!isset($this->object))
throw new PhpMAEException("The object <" . (string)$coid . "> does not exist or this phpMAE instance is not allowed to access it."); throw new PhpMAEException("The object <" . (string)$coid . "> does not exist or this phpMAE instance is not allowed to access it.");
$this->runClass = $this->classRepository->createInstance($this->object, $request); $this->runClass = $this->classRepository->createInstance($this->object, $request);
@@ -315,18 +320,17 @@ class Engine implements RequestHandlerInterface {
public function run() { public function run() {
set_time_limit(self::PREPARE_TIME_LIMIT); set_time_limit(self::PREPARE_TIME_LIMIT);
$env = new Environment($_SERVER); $request = ServerRequestCreatorFactory::create()->createServerRequestFromGlobals();
$request = Request::createFromEnvironment($env);
try { try {
$response = $this->execute($request); $response = $this->execute($request);
} catch (PhpMAEException $e) { } catch (PhpMAEException $e) {
// Create plain-text error response // Create plain-text error response
$response = (new Response(500)) $response = (new Response(500))->withHeader('Content-Type', 'text/plain');
->withHeader('Content-Type', 'text/plain') $response->getBody()->write($e->getMessage());
->write($e->getMessage());
} }
$this->slim->respond($response); (new ResponseEmitter())->emit($response);
} }
} }
+9 -11
View File
@@ -6,27 +6,25 @@
namespace CloudObjects\PhpMAE; namespace CloudObjects\PhpMAE;
use Slim\App; use Slim\Psr7\Response;
use Slim\Http\Response; use Slim\ResponseEmitter;
use ML\JsonLD\Node; use ML\JsonLD\Node;
use CloudObjects\SDK\ObjectRetriever; use CloudObjects\SDK\ObjectRetriever;
class ErrorHandler { class ErrorHandler {
private $classMap = []; private $classMap = [];
private $slim;
private $responseGenerator; private $responseGenerator;
public function __construct(App $slim) { public function __construct() {
$this->slim = $slim; // ini_set("display_errors", 0);
ini_set("display_errors", 0);
$this->setResponseGenerator(function($error, $object) { $this->setResponseGenerator(function($error, $object) {
$message = substr($error['message'], 0, strpos($error['message'], ' in /')); $message = substr($error['message'], 0, strpos($error['message'], ' in /'));
return (new Response(500)) $response = (new Response(500))->withHeader('Content-Type', 'text/plain');
->withHeader('Content-Type', 'text/plain') $response->getBody()->write("Error in implementation of <".$object->getId()."> at revision "
->write("Error in implementation of <".$object->getId()."> at revision "
. $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue() . $object->getProperty(ObjectRetriever::REVISION_PROPERTY)->getValue()
. ":\n".$message); . ":\n".$message);
return $response;
}); });
} }
@@ -42,9 +40,9 @@ class ErrorHandler {
$error = error_get_last(); $error = error_get_last();
if ($error !== null && in_array($error['type'], [ E_ERROR, E_COMPILE_ERROR ]) if ($error !== null && in_array($error['type'], [ E_ERROR, E_COMPILE_ERROR ])
&& isset($this->classMap[$error['file']])) { && isset($this->classMap[$error['file']])) {
$response = call_user_func($this->responseGenerator, $error, $this->classMap[$error['file']]); $response = call_user_func($this->responseGenerator, $error, $this->classMap[$error['file']]);
$this->slim->respond($response); (new ResponseEmitter())->emit($response);
} }
} }
+5 -4
View File
@@ -7,7 +7,7 @@
namespace CloudObjects\PhpMAE; namespace CloudObjects\PhpMAE;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Slim\Http\Response; use Slim\Psr7\Response;
/** /**
* The JsonRPCTransport writes JsonRPC output into a Slim response. * The JsonRPCTransport writes JsonRPC output into a Slim response.
@@ -19,10 +19,11 @@ class JsonRPCTransport {
public function reply($data) { public function reply($data) {
if (is_a($data, ResponseInterface::class)) if (is_a($data, ResponseInterface::class))
$this->response = $data->withHeader('C-PhpMae-Passthru', '1'); $this->response = $data->withHeader('C-PhpMae-Passthru', '1');
else else {
$this->response = (new Response(200)) $this->response = (new Response(200))
->withHeader('Content-Type', 'application/json') ->withHeader('Content-Type', 'application/json');
->write($data); $this->response->getBody()->write($data);
}
} }
public function receive() { public function receive() {
+47 -41
View File
@@ -10,9 +10,11 @@ use InvalidArgumentException;
use Psr\Http\Message\RequestInterface, Psr\Http\Message\ResponseInterface; use Psr\Http\Message\RequestInterface, Psr\Http\Message\ResponseInterface;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Slim\App; use Slim\App;
use Tuupola\Middleware\CorsMiddleware;; use Slim\Factory\AppFactory;
use Slim\Http\Environment, Slim\Http\Uri, Slim\Http\Response, use Slim\Factory\ServerRequestCreatorFactory;
Slim\Http\Request, Slim\Http\Headers; use Slim\ResponseEmitter;
use Slim\Psr7\Response;
use Tuupola\Middleware\CorsMiddleware;
use GuzzleHttp\Client; use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException; use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\Psr7\ServerRequest; use GuzzleHttp\Psr7\ServerRequest;
@@ -34,17 +36,16 @@ class Router {
public function __construct(Engine $engine, ObjectRetriever $objectRetriever, public function __construct(Engine $engine, ObjectRetriever $objectRetriever,
ContainerInterface $container) { ContainerInterface $container) {
$this->engine = $engine; $this->engine = $engine;
$this->objectRetriever = $objectRetriever; $this->objectRetriever = $objectRetriever;
$this->container = $container; $this->container = $container;
} }
private function getRequestHeaders(Request $request) { private function getRequestHeaders(RequestInterface $request) {
$headers = new Headers; // this instance is required to access the "normalizeKey" method
$output = []; $output = [];
foreach (array_keys($request->getHeaders()) as $key) { foreach (array_keys($request->getHeaders()) as $key) {
$key = $headers->normalizeKey($key); $key = strtolower($key);
if (substr($key, 0, 9) == 'c-phpmae-' || $key == 'host') { if (substr($key, 0, 9) == 'c-phpmae-' || $key == 'host') {
// do not forward "Host" header or custom phpMAE headers // do not forward "Host" header or custom phpMAE headers
continue; continue;
@@ -83,14 +84,14 @@ class Router {
$router = $this; $router = $this;
$engine = $this->engine; $engine = $this->engine;
$retriever = $this->getObjectRetriever(new IRI($object->getId())); $retriever = $this->getObjectRetriever(new IRI($object->getId()));
foreach ($routes as $r) { foreach ($routes as $r) {
if (!$reader->hasProperty($r, 'wa:hasVerb') || !$reader->hasProperty($r, 'wa:hasPath')) if (!$reader->hasProperty($r, 'wa:hasVerb') || !$reader->hasProperty($r, 'wa:hasPath'))
throw new PhpMAEException("Incomplete route configuration! Routes must have wa:hasVerb and wa:hasPath."); throw new PhpMAEException("Incomplete route configuration! Routes must have wa:hasVerb and wa:hasPath.");
$app->map([ $reader->getFirstValueString($r, 'wa:hasVerb') ], $app->map([ $reader->getFirstValueString($r, 'wa:hasVerb') ],
$reader->getFirstValueString($r, 'wa:hasPath'), $reader->getFirstValueString($r, 'wa:hasPath'),
function(RequestInterface $request, ResponseInterface $response, $args) use ($r, $reader, $router, $engine, $retriever, $object) { function(RequestInterface $request, ResponseInterface $response, $args) use ($r, $reader, $router, $engine, $retriever, $object) {
if ($reader->hasProperty($r, 'phpmae:runsClass')) { if ($reader->hasProperty($r, 'phpmae:runsClass')) {
try { try {
$params = []; $params = [];
@@ -112,10 +113,13 @@ class Router {
$params = $request->getQueryParams(); $params = $request->getQueryParams();
} }
} catch (InvalidArgumentException $e) { } catch (InvalidArgumentException $e) {
return (new Response(400))->withJson([ $errorResponse = (new Response(400))
->withHeader('Content-Type', 'application/json');
$errorResponse->getBody()->write(json_encode([
'error' => 'InputValidationFailed', 'error' => 'InputValidationFailed',
'message' => $e->getMessage() 'message' => $e->getMessage()
]); ]));
return $errorResponse;
} }
// Add static parameters from Router // Add static parameters from Router
@@ -158,7 +162,10 @@ class Router {
if (isset($rpcResponse['result'])) { if (isset($rpcResponse['result'])) {
return $engine->generateResponse($rpcResponse['result']); return $engine->generateResponse($rpcResponse['result']);
} else { } else {
return (new Response(500))->withJson($rpcResponse); $errResponse = (new Response(500))
->withHeader('Content-Type', 'application/json');
$errResponse->getBody()->write(json_encode($rpcResponse));
return $errResponse;
} }
} else { } else {
// Generic class execution (invokable) // Generic class execution (invokable)
@@ -167,15 +174,16 @@ class Router {
} elseif ($reader->hasProperty($r, 'phpmae:redirectsToURL')) { } elseif ($reader->hasProperty($r, 'phpmae:redirectsToURL')) {
// Route to redirect to a specific external URL // Route to redirect to a specific external URL
return (new Response)->withRedirect($reader->getFirstValueString($r, 'phpmae:redirectsToURL')); return (new Response(302))
->withHeader('Location', $reader->getFirstValueString($r, 'phpmae:redirectsToURL'));
} elseif ($reader->hasProperty($r, 'phpmae:redirectsToBaseURL')) { } elseif ($reader->hasProperty($r, 'phpmae:redirectsToBaseURL')) {
// Route to redirect to an external base URL // Route to redirect to an external base URL
$baseUrl = $reader->getFirstValueIRI($r, 'phpmae:redirectsToBaseURL'); $baseUrl = $reader->getFirstValueIRI($r, 'phpmae:redirectsToBaseURL');
$uri = $request->getUri(); $uri = $request->getUri();
$targetUrl = (string)$baseUrl->resolve(substr($uri->getPath(), 1) . ($uri->getQuery() != '' ? '?'.$uri->getQuery() : '')); $targetUrl = (string)$baseUrl->resolve(substr($uri->getPath(), 1) . ($uri->getQuery() != '' ? '?'.$uri->getQuery() : ''));
return (new Response)->withRedirect($targetUrl); return (new Response(302))->withHeader('Location', $targetUrl);
} elseif ($reader->hasProperty($r, 'phpmae:proxiesRequestsToBaseURL')) { } elseif ($reader->hasProperty($r, 'phpmae:proxiesRequestsToBaseURL')) {
// Route to proxy requests to an external URL // Route to proxy requests to an external URL
@@ -197,25 +205,31 @@ class Router {
// Rule to serve an attached file // Rule to serve an attached file
$etag = '"'.md5($reader->getFirstValueString($object, 'co:isAtRevision') $etag = '"'.md5($reader->getFirstValueString($object, 'co:isAtRevision')
.'+'.$reader->getFirstValueString($r, 'phpmae:servesStaticFileAttachment')).'"'; .'+'.$reader->getFirstValueString($r, 'phpmae:servesStaticFileAttachment')).'"';
if ($request->hasHeader('If-None-Match') && strpos($request->getHeaderLine('If-None-Match'), $etag) > -1) { if ($request->hasHeader('If-None-Match') && strpos($request->getHeaderLine('If-None-Match'), $etag) > -1) {
// Can use cached version // Can use cached version
return (new Response(304))->withHeader('ETag', $etag) return (new Response(304))
->withHeader('ETag', $etag)
->withHeader('Cache-Control', 'max-age='.self::STATIC_CACHE_TTL.', public'); ->withHeader('Cache-Control', 'max-age='.self::STATIC_CACHE_TTL.', public');
} }
$attachmentContent = $retriever->getAttachment(new IRI($object->getId()), $attachmentContent = $retriever->getAttachment(new IRI($object->getId()),
$reader->getFirstValueString($r, 'phpmae:servesStaticFileAttachment')); $reader->getFirstValueString($r, 'phpmae:servesStaticFileAttachment'));
if (!isset($attachmentContent)) if (!isset($attachmentContent)) {
return (new Response(501))->write("Requested static file attachment cannot be found."); $notFoundResponse = new Response(501);
$notFoundResponse->getBody()->write("Requested static file attachment cannot be found.");
return $notFoundResponse;
}
return $engine->generateResponse($attachmentContent) return $engine->generateResponse($attachmentContent)
->withHeader('ETag', $etag) ->withHeader('ETag', $etag)
->withHeader('Cache-Control', 'max-age='.self::STATIC_CACHE_TTL.', public'); ->withHeader('Cache-Control', 'max-age='.self::STATIC_CACHE_TTL.', public');
} else { } else {
// Route has no implementation // Route has no implementation
return (new Response(501))->write("Route implementation not available or no access granted."); $notImplResponse = new Response(501);
$notImplResponse->getBody()->write("Route implementation not available or no access granted.");
return $notImplResponse;
} }
}); });
} }
@@ -235,26 +249,20 @@ class Router {
* Setup and run router. * Setup and run router.
*/ */
public function run() { public function run() {
try { try {
$modes = explode('|', $this->container->get('mode')); $modes = explode('|', $this->container->get('mode'));
$fallback = false; $fallback = false;
$configuration = [ $app = AppFactory::create();
'settings' => [ $serverRequest = ServerRequestCreatorFactory::create()->createServerRequestFromGlobals();
'displayErrorDetails' => true,
],
];
$c = new \Slim\Container($configuration);
$app = new App($c);
$router = null; $router = null;
$env = new Environment($_SERVER);
foreach ($modes as $m) { foreach ($modes as $m) {
switch ($m) { switch ($m) {
case 'router:vhost': case 'router:vhost':
if ($router == null) { if ($router == null) {
$uri = Uri::createFromEnvironment($env); $uri = $serverRequest->getUri();
if ($uri->getHost() == 'localhost' || filter_var($uri->getHost(), FILTER_VALIDATE_IP) !== false) continue; if ($uri->getHost() == 'localhost' || filter_var($uri->getHost(), FILTER_VALIDATE_IP) !== false) break;
$namespace = $this->objectRetriever->get('coid://'.$uri->getHost()); $namespace = $this->objectRetriever->get('coid://'.$uri->getHost());
if (isset($namespace) && $routerCoid = $namespace->getProperty('coid://phpmae.dev/hasRouter')) if (isset($namespace) && $routerCoid = $namespace->getProperty('coid://phpmae.dev/hasRouter'))
@@ -263,9 +271,8 @@ class Router {
break; break;
case 'router:header': case 'router:header':
if ($router == null) { if ($router == null) {
$request = Request::createFromEnvironment($env); if ($serverRequest->hasHeader('C-PhpMae-Router-COID'))
if ($request->hasHeader('C-PhpMae-Router-COID')) $router = $this->getRouter(new IRI($serverRequest->getHeaderLine('C-PhpMae-Router-COID')));
$router = $this->getRouter(new IRI($request->getHeaderLine('C-PhpMae-Router-COID')));
} }
break; break;
case 'default': case 'default':
@@ -281,7 +288,7 @@ class Router {
if (isset($router)) { if (isset($router)) {
$this->configure($app, $router); $this->configure($app, $router);
$response = $app->run(true); $response = $app->handle($serverRequest);
} elseif ($fallback) { } elseif ($fallback) {
$this->container->get(Engine::class) $this->container->get(Engine::class)
->run(); ->run();
@@ -292,11 +299,10 @@ class Router {
} catch (PhpMAEException $e) { } catch (PhpMAEException $e) {
// Create plain-text error response // Create plain-text error response
$response = (new Response(500)) $response = (new Response(500))->withHeader('Content-Type', 'text/plain');
->withHeader('Content-Type', 'text/plain') $response->getBody()->write($e->getMessage());
->write($e->getMessage());
} }
$app->respond($response); (new ResponseEmitter())->emit($response);
} }
} }
+5 -7
View File
@@ -8,7 +8,7 @@ namespace CloudObjects\PhpMAE\Sandbox;
use PHPSandbox\PHPSandbox, PHPSandbox\SandboxWhitelistVisitor, use PHPSandbox\PHPSandbox, PHPSandbox\SandboxWhitelistVisitor,
PHPSandbox\Error; PHPSandbox\Error;
use PhpParser\NodeTraverser, PhpParser\ParserFactory; use PhpParser\NodeTraverser, PhpParser\PhpVersion, PhpParser\ParserFactory;
use PhpParser\PrettyPrinter\Standard; use PhpParser\PrettyPrinter\Standard;
use PhpParser\Error as ParserError; use PhpParser\Error as ParserError;
@@ -38,10 +38,10 @@ class CustomizedSandbox extends PHPSandbox {
]); ]);
} }
public function validate($code) { public function validate($code) : self {
$this->preparsed_code = $this->disassemble($code); $this->preparsed_code = $this->disassemble($code);
$factory = new ParserFactory; $factory = new ParserFactory;
$parser = $factory->create(ParserFactory::PREFER_PHP7); $parser = $factory->createForVersion(PhpVersion::getHostVersion());
try { try {
$this->parsed_ast = $parser->parse($this->preparsed_code); $this->parsed_ast = $parser->parse($this->preparsed_code);
} catch (ParserError $error) { } catch (ParserError $error) {
@@ -55,13 +55,11 @@ class CustomizedSandbox extends PHPSandbox {
($this->allow_traits && $this->auto_whitelist_traits) || ($this->allow_traits && $this->auto_whitelist_traits) ||
($this->allow_globals && $this->auto_whitelist_globals)){ ($this->allow_globals && $this->auto_whitelist_globals)){
$traverser = new NodeTraverser; $traverser = new NodeTraverser;
$whitelister = new SandboxWhitelistVisitor($this); $traverser->addVisitor(new SandboxWhitelistVisitor($this));
$traverser->addVisitor($whitelister);
$traverser->traverse($this->parsed_ast); $traverser->traverse($this->parsed_ast);
} }
$traverser = new NodeTraverser; $traverser = new NodeTraverser;
$validator = new CustomizedValidatorVisitor($this); $traverser->addVisitor(new CustomizedValidatorVisitor($this));
$traverser->addVisitor($validator);
$this->prepared_ast = $traverser->traverse($this->parsed_ast); $this->prepared_ast = $traverser->traverse($this->parsed_ast);
$this->prepared_code = $prettyPrinter->prettyPrint($this->prepared_ast); $this->prepared_code = $prettyPrinter->prettyPrint($this->prepared_ast);
return $this; return $this;
+351 -110
View File
@@ -6,15 +6,50 @@
namespace CloudObjects\PhpMAE\Sandbox; namespace CloudObjects\PhpMAE\Sandbox;
use PhpParser\Node, PhpParser\NodeVisitorAbstract; use PhpParser\Node,
use PHPSandbox\PHPSandbox, PHPSandbox\ValidatorVisitor, PhpParser\NodeTraverser,
PHPSandbox\Error; PhpParser\NodeVisitorAbstract,
Throwable;
class CustomizedValidatorVisitor extends ValidatorVisitor { /**
* Validator class for PHP Sandboxes.
*
* This class takes parsed AST code and checks it against the passed PHPSandbox instance
* configuration for errors, and throws exceptions if they are found
*
* @namespace PHPSandbox
*
* @author Elijah Horton <elijah@corveda.com>
* @version 3.0
*/
class CustomizedValidatorVisitor extends NodeVisitorAbstract {
/** The PHPSandbox instance to check against
* @var PHPSandbox
*/
protected CustomizedSandbox $sandbox;
/** ValidatorVisitor class constructor
*
* This constructor takes a passed PHPSandbox instance to check against for validating sandboxed code.
*
* @param CustomizedSandbox $sandbox The PHPSandbox instance to check against
*/
public function __construct(CustomizedSandbox $sandbox){
$this->sandbox = $sandbox;
}
/** Examine the current PhpParser_Node node against the PHPSandbox configuration for validating sandboxed code
*
* @param Node $node The sandboxed $node to validate
*
* @throws Throwable Throws an exception if validation fails
*
* @return Node|bool|null Return rewritten node, false if node must be removed, or null if no changes to the node are made
*/
public function leaveNode(Node $node){ public function leaveNode(Node $node){
if($node instanceof Node\Arg){ if($node instanceof Node\Arg && $this->sandbox->sandbox_strings){
return new Node\Expr\FuncCall(new Node\Name\FullyQualified(($node->value instanceof Node\Expr\Variable) ? 'PHPSandbox\\wrapByRef' : 'PHPSandbox\\wrap'), [$node, new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox')], $node->getAttributes()); return new Node\Expr\FuncCall(new Node\Name\FullyQualified(($node->value instanceof Node\Expr\Variable) ? 'PHPSandbox\\wrapByRef' : 'PHPSandbox\\wrap'), [$node, new Node\Expr\StaticCall(new Node\Name\FullyQualified("PHPSandbox\\PHPSandbox"), 'getSandbox', [new Node\Arg(new Node\Scalar\String_($this->sandbox->name))])], $node->getAttributes());
} else if($node instanceof Node\Stmt\InlineHTML){ } else if($node instanceof Node\Stmt\InlineHTML){
if(!$this->sandbox->allow_escaping){ if(!$this->sandbox->allow_escaping){
$this->sandbox->validationError("Sandboxed code attempted to escape to HTML!", Error::ESCAPE_ERROR, $node); $this->sandbox->validationError("Sandboxed code attempted to escape to HTML!", Error::ESCAPE_ERROR, $node);
@@ -24,140 +59,140 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
$this->sandbox->validationError("Sandboxed code attempted to cast!", Error::CAST_ERROR, $node); $this->sandbox->validationError("Sandboxed code attempted to cast!", Error::CAST_ERROR, $node);
} }
if($node instanceof Node\Expr\Cast\Int_){ if($node instanceof Node\Expr\Cast\Int_){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_intval', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_intval', [new Node\Arg($node->expr)], $node->getAttributes());
} else if($node instanceof Node\Expr\Cast\Double){ } else if($node instanceof Node\Expr\Cast\Double){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_floatval', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_floatval', [new Node\Arg($node->expr)], $node->getAttributes());
} else if($node instanceof Node\Expr\Cast\Bool_){ } else if($node instanceof Node\Expr\Cast\Bool_){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_boolval', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_boolval', [new Node\Arg($node->expr)], $node->getAttributes());
} else if($node instanceof Node\Expr\Cast\Array_){ } else if($node instanceof Node\Expr\Cast\Array_){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_arrayval', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_arrayval', [new Node\Arg($node->expr)], $node->getAttributes());
} else if($node instanceof Node\Expr\Cast\Object_){ } else if($node instanceof Node\Expr\Cast\Object_){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_objectval', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_objectval', [new Node\Arg($node->expr)], $node->getAttributes());
} }
} else if($node instanceof Node\Expr\FuncCall){ } else if($node instanceof Node\Expr\FuncCall){
if($node->name instanceof Node\Name){ if($node->name instanceof Node\Name){
$name = strtolower($node->name->toString()); $name = strtolower($node->name->toString());
if(!$this->sandbox->checkFunc($name)){ if(!$this->sandbox->checkFunc($name)){
$this->sandbox->validationError("Function failed custom validation!", Error::VALID_FUNC_ERROR, $node); $this->sandbox->validationError('Function failed custom validation!', Error::VALID_FUNC_ERROR, $node);
} }
if($this->sandbox->isDefinedFunc($name)){ if($this->sandbox->isDefinedFunc($name)){
$args = $node->args; $args = $node->args;
array_unshift($args, new Node\Arg(new Node\Scalar\String_($name))); array_unshift($args, new Node\Arg(new Node\Scalar\String_($name)));
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes());
} }
if($this->sandbox->overwrite_defined_funcs && in_array($name, PHPSandbox::$defined_funcs)){ if($this->sandbox->overwrite_defined_funcs && in_array($name, CustomizedSandbox::$defined_funcs)){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name([$name])))], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name([$name])))], $node->getAttributes());
} }
if($this->sandbox->overwrite_sandboxed_string_funcs && in_array($name, PHPSandbox::$sandboxed_string_funcs)){ if($this->sandbox->overwrite_sandboxed_string_funcs && in_array($name, CustomizedSandbox::$sandboxed_string_funcs)){
$args = $node->args; $args = $node->args;
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, $args, $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, $args, $node->getAttributes());
} }
if($this->sandbox->overwrite_func_get_args && in_array($name, PHPSandbox::$arg_funcs)){ if($this->sandbox->overwrite_func_get_args && in_array($name, CustomizedSandbox::$arg_funcs)){
if($name == 'func_get_arg'){ if($name === 'func_get_arg'){
$index = new Node\Arg(new Node\Scalar\LNumber(0)); $index = new Node\Arg(new Node\Scalar\LNumber(0));
if(isset($node->args[0]) && $node->args[0] instanceof Node\Arg){ if(isset($node->args[0]) && $node->args[0] instanceof Node\Arg){
$index = $node->args[0]; $index = $node->args[0];
} }
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args']))), $index], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args']))), $index], $node->getAttributes());
} }
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args'])))], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_' . $name, [new Node\Arg(new Node\Expr\FuncCall(new Node\Name(['func_get_args'])))], $node->getAttributes());
} }
} else { } else {
return new Node\Expr\Ternary( return new Node\Expr\Ternary(
new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'check_func', [new Node\Arg($node->name)], $node->getAttributes()), new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'checkFunc', [new Node\Arg($node->name)], $node->getAttributes()),
$node, $node,
new Node\Expr\ConstFetch(new Node\Name('null')) new Node\Expr\ConstFetch(new Node\Name('null'))
); );
} }
} else if($node instanceof Node\Stmt\Function_){ } else if($node instanceof Node\Stmt\Function_){
if(!$this->sandbox->allow_functions){ if(!$this->sandbox->allow_functions){
$this->sandbox->validationError("Sandboxed code attempted to define function!", Error::DEFINE_FUNC_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to define function!', Error::DEFINE_FUNC_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('function')){ if(!$this->sandbox->checkKeyword('function')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'function'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'function');
} }
if(!$node->name){ if(!$node->name){
$this->sandbox->validationError("Sandboxed code attempted to define unnamed function!", Error::DEFINE_FUNC_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to define unnamed function!', Error::DEFINE_FUNC_ERROR, $node, '');
} }
if($this->sandbox->isDefinedFunc($node->name)){ if($this->sandbox->isDefinedFunc($node->name)){
$this->sandbox->validationError("Sandboxed code attempted to redefine function!", Error::DEFINE_FUNC_ERROR, $node, $node->name); $this->sandbox->validationError('Sandboxed code attempted to redefine function!', Error::DEFINE_FUNC_ERROR, $node, $node->name);
} }
if($node->byRef && !$this->sandbox->allow_references){ if($node->byRef && !$this->sandbox->allow_references){
$this->sandbox->validationError("Sandboxed code attempted to define function return by reference!", Error::BYREF_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to define function return by reference!', Error::BYREF_ERROR, $node);
} }
} else if($node instanceof Node\Expr\Closure){ } else if($node instanceof Node\Expr\Closure){
if(!$this->sandbox->allow_closures){ if(!$this->sandbox->allow_closures){
$this->sandbox->validationError("Sandboxed code attempted to create a closure!", Error::CLOSURE_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to create a closure!', Error::CLOSURE_ERROR, $node);
} }
} else if($node instanceof Node\Stmt\Class_){ } else if($node instanceof Node\Stmt\Class_){
if(!$this->sandbox->allow_classes){ if(!$this->sandbox->allow_classes){
$this->sandbox->validationError("Sandboxed code attempted to define class!", Error::DEFINE_CLASS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to define class!', Error::DEFINE_CLASS_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('class')){ if(!$this->sandbox->checkKeyword('class')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'class'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'class');
} }
if(!$node->name){ if(!$node->name){
$this->sandbox->validationError("Sandboxed code attempted to define unnamed class!", Error::DEFINE_CLASS_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to define unnamed class!', Error::DEFINE_CLASS_ERROR, $node, '');
} }
if(!$this->sandbox->checkClass($node->name)){ if(!$this->sandbox->checkClass($node->name)){
$this->sandbox->validationError("Class failed custom validation!", Error::VALID_CLASS_ERROR, $node, $node->name); $this->sandbox->validationError('Class failed custom validation!', Error::VALID_CLASS_ERROR, $node, $node->name);
} }
if($node->extends instanceof Node\Name){ if($node->extends instanceof Node\Name){
if(!$this->sandbox->checkKeyword('extends')){ if(!$this->sandbox->checkKeyword('extends')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'extends'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'extends');
} }
if(!$node->extends->toString()){ if(!$node->extends->toString()){
$this->sandbox->validationError("Sandboxed code attempted to extend unnamed class!", Error::DEFINE_CLASS_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to extend unnamed class!', Error::DEFINE_CLASS_ERROR, $node, '');
} }
if(!$this->sandbox->checkClass($node->extends->toString(), true)){ if(!$this->sandbox->checkClass($node->extends->toString(), true)){
$this->sandbox->validationError("Class extension failed custom validation!", Error::VALID_CLASS_ERROR, $node, $node->extends->toString()); $this->sandbox->validationError('Class extension failed custom validation!', Error::VALID_CLASS_ERROR, $node, $node->extends->toString());
} }
} }
if(is_array($node->implements)){ if(is_array($node->implements)){
if(!$this->sandbox->checkKeyword('implements')){ if(!$this->sandbox->checkKeyword('implements')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'implements'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'implements');
} }
foreach($node->implements as $implement){ foreach($node->implements as $implement){
/** /**
* @var Node\Name $implement * @var Node\Name $implement
*/ */
if(!$implement->toString()){ if(!$implement->toString()){
$this->sandbox->validationError("Sandboxed code attempted to implement unnamed interface!", Error::DEFINE_INTERFACE_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to implement unnamed interface!', Error::DEFINE_INTERFACE_ERROR, $node, '');
} }
if(!$this->sandbox->checkInterface($implement->toString())){ if(!$this->sandbox->checkInterface($implement->toString())){
$this->sandbox->validationError("Interface failed custom validation!", Error::VALID_INTERFACE_ERROR, $node, $implement->toString()); $this->sandbox->validationError('Interface failed custom validation!', Error::VALID_INTERFACE_ERROR, $node, $implement->toString());
} }
} }
} }
} else if($node instanceof Node\Stmt\Interface_){ } else if($node instanceof Node\Stmt\Interface_){
if(!$this->sandbox->allow_interfaces){ if(!$this->sandbox->allow_interfaces){
$this->sandbox->validationError("Sandboxed code attempted to define interface!", Error::DEFINE_INTERFACE_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to define interface!', Error::DEFINE_INTERFACE_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('interface')){ if(!$this->sandbox->checkKeyword('interface')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'interface'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'interface');
} }
if(!$node->name){ if(!$node->name){
$this->sandbox->validationError("Sandboxed code attempted to define unnamed interface!", Error::DEFINE_INTERFACE_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to define unnamed interface!', Error::DEFINE_INTERFACE_ERROR, $node, '');
} }
if(!$this->sandbox->checkInterface($node->name)){ if(!$this->sandbox->checkInterface($node->name)){
$this->sandbox->validationError("Interface failed custom validation!", Error::VALID_INTERFACE_ERROR, $node, $node->name); $this->sandbox->validationError('Interface failed custom validation!', Error::VALID_INTERFACE_ERROR, $node, $node->name);
} }
} else if($node instanceof Node\Stmt\Trait_){ } else if($node instanceof Node\Stmt\Trait_){
if(!$this->sandbox->allow_traits){ if(!$this->sandbox->allow_traits){
$this->sandbox->validationError("Sandboxed code attempted to define trait!", Error::DEFINE_TRAIT_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to define trait!', Error::DEFINE_TRAIT_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('trait')){ if(!$this->sandbox->checkKeyword('trait')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'trait'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'trait');
} }
if(!$node->name){ if(!$node->name){
$this->sandbox->validationError("Sandboxed code attempted to define unnamed trait!", Error::DEFINE_TRAIT_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to define unnamed trait!', Error::DEFINE_TRAIT_ERROR, $node, '');
} }
if(!$this->sandbox->checkTrait($node->name)){ if(!$this->sandbox->checkTrait($node->name)){
$this->sandbox->validationError("Trait failed custom validation!", Error::VALID_TRAIT_ERROR, $node, $node->name); $this->sandbox->validationError('Trait failed custom validation!', Error::VALID_TRAIT_ERROR, $node, $node->name);
} }
} else if($node instanceof Node\Stmt\TraitUse){ } else if($node instanceof Node\Stmt\TraitUse){
if(!$this->sandbox->checkKeyword('use')){ if(!$this->sandbox->checkKeyword('use')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'use'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'use');
} }
if(is_array($node->traits)){ if(is_array($node->traits)){
foreach($node->traits as $trait){ foreach($node->traits as $trait){
@@ -165,26 +200,26 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
* @var Node\Name $trait * @var Node\Name $trait
*/ */
if(!$trait->toString()){ if(!$trait->toString()){
$this->sandbox->validationError("Sandboxed code attempted to use unnamed trait!", Error::DEFINE_TRAIT_ERROR, $node, ''); $this->sandbox->validationError('Sandboxed code attempted to use unnamed trait!', Error::DEFINE_TRAIT_ERROR, $node, '');
} }
if(!$this->sandbox->checkTrait($trait->toString())){ if(!$this->sandbox->checkTrait($trait->toString())){
$this->sandbox->validationError("Trait failed custom validation!", Error::VALID_TRAIT_ERROR, $node, $trait->toString()); $this->sandbox->validationError('Trait failed custom validation!', Error::VALID_TRAIT_ERROR, $node, $trait->toString());
} }
} }
} }
} else if($node instanceof Node\Expr\Yield_){ } else if($node instanceof Node\Expr\Yield_){
if(!$this->sandbox->allow_generators){ if(!$this->sandbox->allow_generators){
$this->sandbox->validationError("Sandboxed code attempted to create a generator!", Error::GENERATOR_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to create a generator!', Error::GENERATOR_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('yield')){ if(!$this->sandbox->checkKeyword('yield')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'yield'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'yield');
} }
} else if($node instanceof Node\Stmt\Global_){ } else if($node instanceof Node\Stmt\Global_){
if(!$this->sandbox->allow_globals){ if(!$this->sandbox->allow_globals){
$this->sandbox->validationError("Sandboxed code attempted to use global keyword!", Error::GLOBALS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to use global keyword!', Error::GLOBALS_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('global')){ if(!$this->sandbox->checkKeyword('global')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'global'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'global');
} }
foreach($node->vars as $var){ foreach($node->vars as $var){
/** /**
@@ -192,57 +227,57 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
*/ */
if($var instanceof Node\Expr\Variable){ if($var instanceof Node\Expr\Variable){
if(!$this->sandbox->checkGlobal($var->name)){ if(!$this->sandbox->checkGlobal($var->name)){
$this->sandbox->validationError("Global failed custom validation!", Error::VALID_GLOBAL_ERROR, $node, $var->name); $this->sandbox->validationError('Global failed custom validation!', Error::VALID_GLOBAL_ERROR, $node, $var->name);
} }
} else { } else {
$this->sandbox->validationError("Sandboxed code attempted to pass non-variable to global keyword!", Error::DEFINE_GLOBAL_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to pass non-variable to global keyword!', Error::DEFINE_GLOBAL_ERROR, $node);
} }
} }
} else if($node instanceof Node\Expr\Variable){ } else if($node instanceof Node\Expr\Variable){
if(!is_string($node->name)){ if(!is_string($node->name)){
$this->sandbox->validationError("Sandboxed code attempted dynamically-named variable call!", Error::DYNAMIC_VAR_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted dynamically-named variable call!', Error::DYNAMIC_VAR_ERROR, $node);
} }
if($node->name == $this->sandbox->name){ if($node->name == $this->sandbox->name){
$this->sandbox->validationError("Sandboxed code attempted to access the PHPSandbox instance!", Error::SANDBOX_ACCESS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to access the PHPSandbox instance!', Error::SANDBOX_ACCESS_ERROR, $node);
} }
if(in_array($node->name, PHPSandbox::$superglobals)){ if(in_array($node->name, CustomizedSandbox::$superglobals)){
if(!$this->sandbox->checkSuperglobal($node->name)){ if(!$this->sandbox->checkSuperglobal($node->name)){
$this->sandbox->validationError("Superglobal failed custom validation!", Error::VALID_SUPERGLOBAL_ERROR, $node, $node->name); $this->sandbox->validationError('Superglobal failed custom validation!', Error::VALID_SUPERGLOBAL_ERROR, $node, $node->name);
} }
if($this->sandbox->overwrite_superglobals){ if($this->sandbox->overwrite_superglobals){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_get_superglobal', [new Node\Arg(new Node\Scalar\String_($node->name))], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_get_superglobal', [new Node\Arg(new Node\Scalar\String_($node->name))], $node->getAttributes());
} }
} else { } else {
if(!$this->sandbox->checkVar($node->name)){ if(!$this->sandbox->checkVar($node->name)){
$this->sandbox->validationError("Variable failed custom validation!", Error::VALID_VAR_ERROR, $node, $node->name); $this->sandbox->validationError('Variable failed custom validation!', Error::VALID_VAR_ERROR, $node, $node->name);
} }
} }
} else if($node instanceof Node\Stmt\StaticVar){ } else if($node instanceof Node\Stmt\StaticVar){
if(!$this->sandbox->allow_static_variables){ if(!$this->sandbox->allow_static_variables){
$this->sandbox->validationError("Sandboxed code attempted to create static variable!", Error::STATIC_VAR_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to create static variable!', Error::STATIC_VAR_ERROR, $node);
} }
if(!is_string($node->name)){ if(!is_string($node->var->name)){
$this->sandbox->validationError("Sandboxed code attempted dynamically-named static variable call!", Error::DYNAMIC_STATIC_VAR_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted dynamically-named static variable call!', Error::DYNAMIC_STATIC_VAR_ERROR, $node);
} }
if(!$this->sandbox->checkVar($node->name)){ if(!$this->sandbox->checkVar($node->var->name)){
$this->sandbox->validationError("Variable failed custom validation!", Error::VALID_VAR_ERROR, $node, $node->name); $this->sandbox->validationError('Variable failed custom validation!', Error::VALID_VAR_ERROR, $node, $node->var->name);
} }
if($node->default instanceof Node\Expr\New_){ if($node->default instanceof Node\Expr\New_){
$node->default = $node->default->args[0]; $node->default = $node->default->args[0];
} }
} else if($node instanceof Node\Stmt\Const_){ } else if($node instanceof Node\Stmt\Const_){
$this->sandbox->validationError("Sandboxed code cannot use const keyword in the global scope!", Error::GLOBAL_CONST_ERROR, $node); $this->sandbox->validationError('Sandboxed code cannot use const keyword in the global scope!', Error::GLOBAL_CONST_ERROR, $node);
} else if($node instanceof Node\Expr\ConstFetch){ } else if($node instanceof Node\Expr\ConstFetch){
if(!$node->name instanceof Node\Name){ if(!$node->name instanceof Node\Name){
$this->sandbox->validationError("Sandboxed code attempted dynamically-named constant call!", Error::DYNAMIC_CONST_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted dynamically-named constant call!', Error::DYNAMIC_CONST_ERROR, $node);
} }
if(!$this->sandbox->checkConst($node->name->toString())){ if(!$this->sandbox->checkConst($node->name->toString())){
$this->sandbox->validationError("Constant failed custom validation!", Error::VALID_CONST_ERROR, $node, $node->name->toString()); $this->sandbox->validationError('Constant failed custom validation!', Error::VALID_CONST_ERROR, $node, $node->name->toString());
} }
} else if($node instanceof Node\Expr\ClassConstFetch || $node instanceof Node\Expr\StaticCall || $node instanceof Node\Expr\StaticPropertyFetch){ } else if($node instanceof Node\Expr\ClassConstFetch || $node instanceof Node\Expr\StaticCall || $node instanceof Node\Expr\StaticPropertyFetch){
$class = $node->class; $class = $node->class;
if(!$class instanceof Node\Name){ if(!$class instanceof Node\Name){
$this->sandbox->validationError("Sandboxed code attempted dynamically-named class call!", Error::DYNAMIC_CLASS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted dynamically-named class call!', Error::DYNAMIC_CLASS_ERROR, $node);
} }
if($this->sandbox->isDefinedClass($class)){ if($this->sandbox->isDefinedClass($class)){
$node->class = new Node\Name($this->sandbox->getDefinedClass($class)); $node->class = new Node\Name($this->sandbox->getDefinedClass($class));
@@ -251,7 +286,7 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
* @var Node\Name $class * @var Node\Name $class
*/ */
if(!$this->sandbox->checkClass($class->toString())){ if(!$this->sandbox->checkClass($class->toString())){
$this->sandbox->validationError("Class constant failed custom validation!", Error::VALID_CLASS_ERROR, $node, $class->toString()); $this->sandbox->validationError('Class constant failed custom validation!', Error::VALID_CLASS_ERROR, $node, $class->toString());
} }
return $node; return $node;
} else if($node instanceof Node\Param && $node->type instanceof Node\Name){ } else if($node instanceof Node\Param && $node->type instanceof Node\Name){
@@ -262,13 +297,13 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
return $node; return $node;
} else if($node instanceof Node\Expr\New_){ } else if($node instanceof Node\Expr\New_){
if(!$this->sandbox->allow_objects){ if(!$this->sandbox->allow_objects){
$this->sandbox->validationError("Sandboxed code attempted to create object!", Error::CREATE_OBJECT_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to create object!', Error::CREATE_OBJECT_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('new')){ if(!$this->sandbox->checkKeyword('new')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'new'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'new');
} }
if(!$node->class instanceof Node\Name){ if(!$node->class instanceof Node\Name){
$this->sandbox->validationError("Sandboxed code attempted dynamically-named class call!", Error::DYNAMIC_CLASS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted dynamically-named class call!', Error::DYNAMIC_CLASS_ERROR, $node);
} }
$class = $node->class->toString(); $class = $node->class->toString();
if($this->sandbox->isDefinedClass($class)){ if($this->sandbox->isDefinedClass($class)){
@@ -278,25 +313,25 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
return $node; return $node;
} else if($node instanceof Node\Expr\ErrorSuppress){ } else if($node instanceof Node\Expr\ErrorSuppress){
if(!$this->sandbox->allow_error_suppressing){ if(!$this->sandbox->allow_error_suppressing){
$this->sandbox->validationError("Sandboxed code attempted to suppress error!", Error::ERROR_SUPPRESS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to suppress error!', Error::ERROR_SUPPRESS_ERROR, $node);
} }
} else if($node instanceof Node\Expr\AssignRef){ } else if($node instanceof Node\Expr\AssignRef){
if(!$this->sandbox->allow_references){ if(!$this->sandbox->allow_references){
$this->sandbox->validationError("Sandboxed code attempted to assign by reference!", Error::BYREF_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to assign by reference!', Error::BYREF_ERROR, $node);
} }
} else if($node instanceof Node\Stmt\HaltCompiler){ } else if($node instanceof Node\Stmt\HaltCompiler){
if(!$this->sandbox->allow_halting){ if(!$this->sandbox->allow_halting){
$this->sandbox->validationError("Sandboxed code attempted to halt compiler!", Error::HALT_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to halt compiler!', Error::HALT_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('halt')){ if(!$this->sandbox->checkKeyword('halt')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'halt'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'halt');
} }
} else if($node instanceof Node\Stmt\Namespace_){ } else if($node instanceof Node\Stmt\Namespace_){
if(!$this->sandbox->allow_namespaces){ if(!$this->sandbox->allow_namespaces){
$this->sandbox->validationError("Sandboxed code attempted to define namespace!", Error::DEFINE_NAMESPACE_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to define namespace!', Error::DEFINE_NAMESPACE_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('namespace')){ if(!$this->sandbox->checkKeyword('namespace')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'namespace'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'namespace');
} }
if($node->name instanceof Node\Name){ if($node->name instanceof Node\Name){
$namespace = $node->name->toString(); $namespace = $node->name->toString();
@@ -305,99 +340,305 @@ class CustomizedValidatorVisitor extends ValidatorVisitor {
$this->sandbox->defineNamespace($namespace); $this->sandbox->defineNamespace($namespace);
} }
} else { } else {
$this->sandbox->validationError("Sandboxed code attempted use invalid namespace!", Error::DEFINE_NAMESPACE_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted use invalid namespace!', Error::DEFINE_NAMESPACE_ERROR, $node);
} }
return $node->stmts; return $node->stmts;
} else if($node instanceof Node\Stmt\Use_){ } else if($node instanceof Node\Stmt\Use_){
if(!$this->sandbox->allow_aliases){ if(!$this->sandbox->allow_aliases){
$this->sandbox->validationError("Sandboxed code attempted to use namespace and/or alias!", Error::DEFINE_ALIAS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to use namespace and/or alias!', Error::DEFINE_ALIAS_ERROR, $node);
} }
if(!$this->sandbox->checkKeyword('use')){ if(!$this->sandbox->checkKeyword('use')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'use'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'use');
} }
foreach($node->uses as $use){ foreach($node->uses as $use){
/** /**
* @var Node\Stmt\UseUse $use * @var Node\Stmt\UseUse $use
*/ */
if($use instanceof Node\Stmt\UseUse && $use->name instanceof Node\Name && (is_string($use->alias) || is_null($use->alias))){ if($use instanceof Node\Stmt\UseUse && $use->name instanceof Node\Name && (is_string($use->alias) || $use->alias instanceof Node\Identifier || is_null($use->alias))){
$this->sandbox->checkAlias($use->name->toString()); $this->sandbox->checkAlias($use->name->toString());
if($use->alias){ if($use->alias){
if(!$this->sandbox->checkKeyword('as')){ if(!$this->sandbox->checkKeyword('as')){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, 'as'); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, 'as');
} }
} }
$this->sandbox->defineAlias($use->name->toString(), $use->alias); $this->sandbox->whitelistClass($use->getAlias());
$this->sandbox->whitelistType($use->getAlias());
$this->sandbox->defineAlias($use->name->toString(), $use->getAlias());
} else { } else {
$this->sandbox->validationError("Sandboxed code attempted use invalid namespace or alias!", Error::DEFINE_ALIAS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted use invalid namespace or alias!', Error::DEFINE_ALIAS_ERROR, $node);
} }
} }
return false; return NodeTraverser::REMOVE_NODE;
} else if($node instanceof Node\Expr\ShellExec){ } else if($node instanceof Node\Expr\ShellExec){
if($this->sandbox->isDefinedFunc('shell_exec')){ if($this->sandbox->isDefinedFunc('shell_exec')){
$args = [ $args = [
new Node\Arg(new Node\Scalar\String_('shell_exec')), new Node\Arg(new Node\Scalar\String_('shell_exec')),
new Node\Arg(new Node\Scalar\String_(implode('', $node->parts))) new Node\Arg(new Node\Scalar\String_(implode('', $node->parts)))
]; ];
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'call_func', $args, $node->getAttributes());
} }
if($this->sandbox->hasWhitelistedFuncs()){ if($this->sandbox->hasWhitelistedFuncs()){
if(!$this->sandbox->isWhitelistedFunc('shell_exec')){ if(!$this->sandbox->isWhitelistedFunc('shell_exec')){
$this->sandbox->validationError("Sandboxed code attempted to use shell execution backticks when the shell_exec function is not whitelisted!", Error::BACKTICKS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to use shell execution backticks when the shell_exec function is not whitelisted!', Error::BACKTICKS_ERROR, $node);
} }
} else if($this->sandbox->hasBlacklistedFuncs() && $this->sandbox->isBlacklistedFunc('shell_exec')){ } else if($this->sandbox->hasBlacklistedFuncs() && $this->sandbox->isBlacklistedFunc('shell_exec')){
$this->sandbox->validationError("Sandboxed code attempted to use shell execution backticks when the shell_exec function is blacklisted!", Error::BACKTICKS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to use shell execution backticks when the shell_exec function is blacklisted!', Error::BACKTICKS_ERROR, $node);
} }
if(!$this->sandbox->allow_backticks){ if(!$this->sandbox->allow_backticks){
$this->sandbox->validationError("Sandboxed code attempted to use shell execution backticks!", Error::BACKTICKS_ERROR, $node); $this->sandbox->validationError('Sandboxed code attempted to use shell execution backticks!', Error::BACKTICKS_ERROR, $node);
} }
} else if($name = $this->isMagicConst($node)){ } else if($name = $this->isMagicConst($node)){
if(!$this->sandbox->checkMagicConst($name)){ if(!$this->sandbox->checkMagicConst($name)){
$this->sandbox->validationError("Magic constant failed custom validation!", Error::VALID_MAGIC_CONST_ERROR, $node, $name); $this->sandbox->validationError('Magic constant failed custom validation!', Error::VALID_MAGIC_CONST_ERROR, $node, $name);
} }
if($this->sandbox->isDefinedMagicConst($name)){ if($this->sandbox->isDefinedMagicConst($name)){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_get_magic_const', [new Node\Arg(new Node\Scalar\String_($name))], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_get_magic_const', [new Node\Arg(new Node\Scalar\String_($name))], $node->getAttributes());
} else if(($filepath = $this->sandbox->getExecutingFile()) && in_array($name, ['__DIR__', '__FILE__'], true)){
return new Node\Scalar\String_($name === '__DIR__' ? dirname($filepath) : $filepath);
} }
} else if($name = $this->isKeyword($node)){ } else if($name = $this->isKeyword($node)){
if(!$this->sandbox->checkKeyword($name)){ if(!$this->sandbox->checkKeyword($name)){
$this->sandbox->validationError("Keyword failed custom validation!", Error::VALID_KEYWORD_ERROR, $node, $name); $this->sandbox->validationError('Keyword failed custom validation!', Error::VALID_KEYWORD_ERROR, $node, $name);
} }
if($node instanceof Node\Expr\Include_ && !$this->sandbox->allow_includes){ if($node instanceof Node\Expr\Include_ && !$this->sandbox->allow_includes){
$this->sandbox->validationError("Sandboxed code attempted to include files!", Error::INCLUDE_ERROR, $node, $name); $this->sandbox->validationError('Sandboxed code attempted to include files!', Error::INCLUDE_ERROR, $node, $name);
} else if($node instanceof Node\Expr\Include_ && } else if($node instanceof Node\Expr\Include_ &&
( (
($node->type == Node\Expr\Include_::TYPE_INCLUDE && $this->sandbox->isDefinedFunc('include')) ($node->type == Node\Expr\Include_::TYPE_INCLUDE && $this->sandbox->isDefinedFunc('include'))
|| ($node->type == Node\Expr\Include_::TYPE_INCLUDE_ONCE && $this->sandbox->isDefinedFunc('include_once')) || ($node->type == Node\Expr\Include_::TYPE_INCLUDE_ONCE && $this->sandbox->isDefinedFunc('include_once'))
|| ($node->type == Node\Expr\Include_::TYPE_REQUIRE && $this->sandbox->isDefinedFunc('require')) || ($node->type == Node\Expr\Include_::TYPE_REQUIRE && $this->sandbox->isDefinedFunc('require'))
|| ($node->type == Node\Expr\Include_::TYPE_REQUIRE_ONCE && $this->sandbox->isDefinedFunc('require_once')) || ($node->type == Node\Expr\Include_::TYPE_REQUIRE_ONCE && $this->sandbox->isDefinedFunc('require_once'))
)){ )
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), 'call_func', [new Node\Arg(new Node\Scalar\String_($name)), new Node\Arg($node->expr)], $node->getAttributes()); ){
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), 'call_func', [new Node\Arg(new Node\Scalar\String_($name)), new Node\Arg($node->expr)], $node->getAttributes());
} else if($node instanceof Node\Expr\Include_ && $this->sandbox->sandbox_includes){ } else if($node instanceof Node\Expr\Include_ && $this->sandbox->sandbox_includes){
switch($node->type){ switch($node->type){
case Node\Expr\Include_::TYPE_INCLUDE_ONCE: case Node\Expr\Include_::TYPE_INCLUDE_ONCE:
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_include_once', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_include_once', [new Node\Arg($node->expr)], $node->getAttributes());
break;
case Node\Expr\Include_::TYPE_REQUIRE: case Node\Expr\Include_::TYPE_REQUIRE:
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_require', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_require', [new Node\Arg($node->expr)], $node->getAttributes());
break;
case Node\Expr\Include_::TYPE_REQUIRE_ONCE: case Node\Expr\Include_::TYPE_REQUIRE_ONCE:
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_require_once', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_require_once', [new Node\Arg($node->expr)], $node->getAttributes());
break;
case Node\Expr\Include_::TYPE_INCLUDE: case Node\Expr\Include_::TYPE_INCLUDE:
default: default:
return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified("CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox"), 'getGlobalSandbox'), '_include', [new Node\Arg($node->expr)], $node->getAttributes()); return new Node\Expr\MethodCall(new Node\Expr\StaticCall(new Node\Name\FullyQualified('CloudObjects\\PhpMAE\\Sandbox\\CustomizedSandbox'), 'getGlobalSandbox'), '_include', [new Node\Arg($node->expr)], $node->getAttributes());
break;
} }
} }
} else if($name = $this->isOperator($node)){ } else if($name = $this->isOperator($node)){
if(!$this->sandbox->checkOperator($name)){ if(!$this->sandbox->checkOperator($name)){
$this->sandbox->validationError("Operator failed custom validation!", Error::VALID_OPERATOR_ERROR, $node, $name); $this->sandbox->validationError('Operator failed custom validation!', Error::VALID_OPERATOR_ERROR, $node, $name);
} }
} else if($name = $this->isPrimitive($node)){ } else if($name = $this->isPrimitive($node)){
if(!$this->sandbox->checkPrimitive($name)){ if(!$this->sandbox->checkPrimitive($name)){
$this->sandbox->validationError("Primitive failed custom validation!", Error::VALID_PRIMITIVE_ERROR, $node, $name); $this->sandbox->validationError('Primitive failed custom validation!', Error::VALID_PRIMITIVE_ERROR, $node, $name);
} }
} }
return null; return null;
} }
/** Test the current PhpParser_Node node to see if it is a magic constant, and return the name if it is and null if it is not
} *
* @param Node $node The sandboxed $node to test
*
* @return string|null Return string name of node, or null if it is not a magic constant
*/
protected function isMagicConst(Node $node) : ?string {
return ($node instanceof Node\Scalar\MagicConst) ? $node->getName() : null;
}
/** Test the current PhpParser_Node node to see if it is a keyword, and return the name if it is and null if it is not
*
* @param Node $node The sandboxed $node to test
*
* @return string|null Return string name of node, or null if it is not a keyword
*/
protected function isKeyword(Node $node) : ?string {
switch($node->getType()){
case 'Expr_Eval':
return 'eval';
case 'Expr_Exit':
return 'exit';
case 'Expr_Include':
return 'include';
case 'Stmt_Echo':
case 'Expr_Print': //for our purposes print is treated as functionally equivalent to echo
return 'echo';
case 'Expr_Clone':
return 'clone';
case 'Expr_Empty':
return 'empty';
case 'Expr_Yield':
return 'yield';
case 'Stmt_Goto':
case 'Stmt_Label': //no point in using labels without goto
return 'goto';
case 'Stmt_If':
case 'Stmt_Else': //no point in using ifs without else
case 'Stmt_ElseIf': //no point in using ifs without elseif
return 'if';
case 'Stmt_Break':
return 'break';
case 'Stmt_Switch':
case 'Stmt_Case': //no point in using cases without switch
return 'switch';
case 'Stmt_Try':
case 'Stmt_Catch': //no point in using catch without try
case 'Stmt_TryCatch': //no point in using try, catch or finally without try
return 'try';
case 'Stmt_Throw':
return 'throw';
case 'Stmt_Unset':
return 'unset';
case 'Stmt_Return':
return 'return';
case 'Stmt_Static':
return 'static';
case 'Stmt_While':
case 'Stmt_Do': //no point in using do without while
return 'while';
case 'Stmt_Declare':
case 'Stmt_DeclareDeclare': //no point in using declare key=>value without declare
return 'declare';
case 'Stmt_For':
case 'Stmt_Foreach': //no point in using foreach without for
return 'for';
case 'Expr_Instanceof':
return 'instanceof';
case 'Expr_Isset':
return 'isset';
case 'Expr_List':
return 'list';
}
return null;
}
/** Test the current PhpParser_Node node to see if it is an operator, and return the name if it is and null if it is not
*
* @param Node $node The sandboxed $node to test
*
* @return string|null Return string name of node, or null if it is not an operator
*/
protected function isOperator(Node $node) : ?string {
switch($node->getType()){
case 'Expr_Assign':
return '=';
case 'Expr_AssignBitwiseAnd':
return '&=';
case 'Expr_AssignBitwiseOr':
return '|=';
case 'Expr_AssignBitwiseXor':
return '^=';
case 'Expr_AssignConcat':
return '.=';
case 'Expr_AssignDiv':
return '/=';
case 'Expr_AssignMinus':
return '-=';
case 'Expr_AssignMod':
return '%=';
case 'Expr_AssignMul':
return '*=';
case 'Expr_AssignPlus':
return '+=';
case 'Expr_AssignRef':
return '=&';
case 'Expr_AssignShiftLeft':
return '<<=';
case 'Expr_AssignShiftRight':
return '>>=';
case 'Expr_BitwiseAnd':
return '&';
case 'Expr_BitwiseNot':
return '~';
case 'Expr_BitwiseOr':
return '|';
case 'Expr_BitwiseXor':
return '^';
case 'Expr_BooleanAnd':
return '&&';
case 'Expr_BooleanNot':
return '!';
case 'Expr_BooleanOr':
return '||';
case 'Expr_Concat':
return '.';
case 'Expr_Div':
return '/';
case 'Expr_Equal':
return '==';
case 'Expr_Greater':
return '>';
case 'Expr_GreaterOrEqual':
return '>=';
case 'Expr_Identical':
return '===';
case 'Expr_LogicalAnd':
return 'and';
case 'Expr_LogicalOr':
return 'or';
case 'Expr_LogicalXor':
return 'xor';
case 'Expr_Minus':
return '-';
case 'Expr_Mod':
return '%';
case 'Expr_Mul':
return '*';
case 'Expr_NotEqual':
return '!=';
case 'Expr_NotIdentical':
return '!==';
case 'Expr_Plus':
return '+';
case 'Expr_PostDec':
return 'n--';
case 'Expr_PostInc':
return 'n++';
case 'Expr_PreDec':
return '--n';
case 'Expr_PreInc':
return '++n';
case 'Expr_ShiftLeft':
return '<<';
case 'Expr_ShiftRight':
return '>>';
case 'Expr_Smaller':
return '<';
case 'Expr_SmallerOrEqual':
return '<=';
case 'Expr_Ternary':
return '?';
case 'Expr_UnaryMinus':
return '-n';
case 'Expr_UnaryPlus':
return '+n';
}
return null;
}
/** Test the current PhpParser_Node node to see if it is a primitive, and return the name if it is and null if it is not
*
* @param Node $node The sandboxed $node to test
*
* @return string|null Return string name of node, or null if it is not a primitive
*/
protected function isPrimitive(Node $node) : ?string {
switch($node->getType()){
case 'Expr_Cast_Array':
case 'Expr_Array':
return 'array';
case 'Expr_Cast_Bool': //booleans are treated as constants otherwise. . .
return 'bool';
case 'Expr_Cast_String':
case 'Scalar_String':
case 'Scalar_Encapsed':
return 'string';
case 'Expr_Cast_Double':
case 'Scalar_DNumber':
return 'float';
case 'Expr_Cast_Int':
case 'Scalar_LNumber':
return 'int';
case 'Expr_Cast_Object':
return 'object';
}
return null;
}
}
+2 -2
View File
@@ -13,8 +13,8 @@ class TwigTemplate {
public function __construct($key, $content, $cachePath) { public function __construct($key, $content, $cachePath) {
$this->key = $key; $this->key = $key;
$this->environment = new \Twig_Environment( $this->environment = new \Twig\Environment(
new \Twig_Loader_Array([ $key => $content ]), new \Twig\Loader\ArrayLoader([ $key => $content ]),
[ 'cache' => $cachePath ] [ 'cache' => $cachePath ]
); );
} }
+11 -10
View File
@@ -3,12 +3,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public /* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\PhpMAE; namespace CloudObjects\PhpMAE;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Psr\Http\Message\RequestInterface; use Psr\Http\Message\RequestInterface;
use Slim\Http\Response; use Slim\Psr7\Response;
use ML\IRI\IRI; use ML\IRI\IRI;
use ML\JsonLD\JsonLD; use ML\JsonLD\JsonLD;
use CloudObjects\Utilities\RDF\Arc2JsonLdConverter; use CloudObjects\Utilities\RDF\Arc2JsonLdConverter;
@@ -23,14 +23,14 @@ class UploadController {
public function __construct(ContainerInterface $container, ObjectRetriever $objectRetriever, public function __construct(ContainerInterface $container, ObjectRetriever $objectRetriever,
ClassRepository $classRepository) { ClassRepository $classRepository) {
$this->container = $container; $this->container = $container;
$this->objectRetriever = $objectRetriever; $this->objectRetriever = $objectRetriever;
$this->classRepository = $classRepository; $this->classRepository = $classRepository;
} }
private function uploadSource(RequestInterface $request) { private function uploadSource(RequestInterface $request) {
$object = $this->objectRetriever->get($request->getQueryParam('coid')); $object = $this->objectRetriever->get($request->getQueryParams()['coid'] ?? null);
if (!$object) if (!$object)
throw new PhpMAEException("Unable to retrieve object."); throw new PhpMAEException("Unable to retrieve object.");
@@ -42,10 +42,11 @@ class UploadController {
new IRI($object->getId()), new IRI($object->getId()),
TypeChecker::getAdditionalTypes($object)); TypeChecker::getAdditionalTypes($object));
} catch (\Exception $e) { } catch (\Exception $e) {
$response = (new Response(400))->withJson([ $response = (new Response(400))->withHeader('Content-Type', 'application/json');
$response->getBody()->write(json_encode([
'error_code' => get_class($e), 'error_code' => get_class($e),
'error_message' => $e->getMessage() 'error_message' => $e->getMessage()
]); ]));
return $response; return $response;
} }
@@ -67,12 +68,12 @@ class UploadController {
// Validate config // Validate config
if (!isset($jsonLdConfig->{'@id'}) if (!isset($jsonLdConfig->{'@id'})
|| $jsonLdConfig->{'@id'} != $request->getQueryParam('coid')) { || $jsonLdConfig->{'@id'} != ($request->getQueryParams()['coid'] ?? null)) {
throw new PhpMAEException("Uploaded configuration does not correspond to object."); throw new PhpMAEException("Uploaded configuration does not correspond to object.");
} }
// Store configuration // Store configuration
$iri = new IRI($request->getQueryParam('coid')); $iri = new IRI($request->getQueryParams()['coid'] ?? null);
$path = $this->container->get('uploads_dir') $path = $this->container->get('uploads_dir')
.DIRECTORY_SEPARATOR.'config' .DIRECTORY_SEPARATOR.'config'
.DIRECTORY_SEPARATOR.$iri->getHost() .DIRECTORY_SEPARATOR.$iri->getHost()
@@ -91,7 +92,7 @@ class UploadController {
if ($request->getMethod() != 'PUT') if ($request->getMethod() != 'PUT')
throw new PhpMAEException("Must use PUT for uploading to test environment."); throw new PhpMAEException("Must use PUT for uploading to test environment.");
switch ($request->getQueryParam('type')) { switch ($request->getQueryParams()['type'] ?? null) {
case "source": case "source":
return $this->uploadSource($request); return $this->uploadSource($request);
break; break;
+21 -24
View File
@@ -5,38 +5,35 @@
"homepage": "https://github.com/CloudObjects/phpMAE", "homepage": "https://github.com/CloudObjects/phpMAE",
"license": "MPL-2.0", "license": "MPL-2.0",
"require": { "require": {
"symfony/console" : "^4.2.1", "symfony/console" : "^7",
"corveda/php-sandbox": "^2.0.1", "corveda/php-sandbox": "^3.1",
"cloudobjects/sdk" : "dev-main", "cloudobjects/sdk" : "dev-main",
"php-di/php-di": "^6.0", "php-di/php-di": "^7.1.1",
"slim/slim" : "^3.0", "slim/slim" : "^4.0",
"slim/psr7" : "^1.6",
"slim/http" : "^1.3",
"jsonrpc/jsonrpc": "^1.0", "jsonrpc/jsonrpc": "^1.0",
"vlucas/phpdotenv" : "^2.4.0", "vlucas/phpdotenv" : "^5.6.3",
"semsol/arc2" : "~2.3.1", "semsol/arc2" : "~3.0.0",
"cloudobjects/rdfutilities" : "dev-main", "cloudobjects/rdfutilities" : "dev-main",
"tuupola/slim-basic-auth": "^3.2", "jimtools/basic-auth": "^1.0",
"dflydev/fig-cookies": "^1.0", "dflydev/fig-cookies": "^3.2.0",
"doctrine/collections": "^1.5", "doctrine/collections": "^3.0.0",
"twig/twig": "^2.5", "twig/twig": "^3.27.0",
"monolog/monolog": "^1.24", "monolog/monolog": "^3.10.0",
"guzzlehttp/oauth-subscriber": "^0.3.0", "webmozart/assert": "^1.6",
"webmozart/assert": "^1.3", "psr/simple-cache": "^3.0",
"psr/simple-cache": "^1.0", "tuupola/cors-middleware": "^1.5",
"tuupola/cors-middleware": "^1.1", "relay/relay": "^3.0",
"relay/relay": "^2.1", "symfony/mailer": "^8.1.0"
"symfony/mailer": "^5.3"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"CloudObjects\\PhpMAE\\" : "classes" "CloudObjects\\PhpMAE\\" : "classes"
}, }
"files" : [
"vendor/semsol/arc2/ARC2_getFormat.php",
"vendor/semsol/arc2/ARC2_getPreferredFormat.php"
]
}, },
"require-dev" : { "require-dev" : {
"phpunit/phpunit": "~5.7", "phpunit/phpunit": "~8.5",
"consolidation/robo": "~1" "consolidation/robo": "^5.1.1"
} }
} }
Generated
+2814 -2364
View File
File diff suppressed because it is too large Load Diff
+3 -7
View File
@@ -19,12 +19,8 @@ echo "<?php return array(" \
" 'agws.data_cache' => 'file', " \ " 'agws.data_cache' => 'file', " \
" 'log.target' => 'errorlog', " \ " 'log.target' => 'errorlog', " \
" 'log.level' => Monolog\Logger::INFO, " \ " 'log.level' => Monolog\Logger::INFO, " \
" ); " > /var/www/app/config.php " ); " > config.php
# Make cache folder # Make cache folder
mkdir /var/www/app/cache mkdir cache
chown lighttpd:lighttpd /var/www/app/cache chown www-data:www-data cache
# Run start script from parent container
sh /tmp/start.sh
+1 -1
View File
@@ -17,7 +17,7 @@ vendor: composer.lock
robo.phar: robo.phar:
# Get a copy of robo # Get a copy of robo
curl -L -o robo.phar http://robo.li/robo.phar curl -L -o robo.phar https://github.com/consolidation/robo/releases/download/4.0.4/robo.phar
config.php: config.php.default config.php: config.php.default
# Use .default if no other config provided # Use .default if no other config provided
View File