commit b9d16a7751f404a4fe143e117fe69316a2e597ec
parent a42ca771f59c691027c74078b1d8a0960ce79a0b
Author: dankert <openrat@jandankert.de>
Date: Wed, 2 Feb 2022 01:12:42 +0100
Better support for API requests.
Diffstat:
7 files changed, 74 insertions(+), 27 deletions(-)
diff --git a/index.php b/index.php
@@ -7,7 +7,6 @@ require('modules/autoload.php'); // Autoloading all classes
use cms\base\Startup;
use cms\output\OutputFactory;
-use cms\ui\UI;
// - Validating the environment
// - Initialize all constants
diff --git a/modules/cms/base/Startup.class.php b/modules/cms/base/Startup.class.php
@@ -149,6 +149,10 @@ class Startup {
// It is not possibile to throw an exception out of a shutdown function!
// PHP will exit the request directly after executing this method, so a
// Exception would never reach a caller.
+
+ header('HTTP/1.0 503 Internal CMS fatal error');
+ header('Content-Type: text/html; charset=utf-8');
+ echo "<h1>Fatal error</h1><pre>$errstr</pre><hr />".Startup::TITLE;
}
};
diff --git a/modules/cms/output/APIOutput.class.php b/modules/cms/output/APIOutput.class.php
@@ -4,19 +4,10 @@ namespace cms\output;
use BadMethodCallException;
use cms\action\RequestParams;
-use cms\api\API;
use cms\base\Startup;
-use cms\Dispatcher;
use Exception;
-use util\Http;
-use logger\Logger;
-use \util\exception\ObjectNotFoundException;
-use util\exception\UIException;
-use util\exception\SecurityException;
-use util\json\JSON;
+use util\exception\ClientException;
use util\Session;
-use util\XML;
-use util\YAML;
/**
* Entrypoint for all API requests.
@@ -52,6 +43,21 @@ abstract class APIOutput extends BaseOutput
return $data;
}
+ /**
+ * This method is executed before the dispatcher is called.
+ * Subclasses may override this to prepare the response.
+ * @param $request RequestParams
+ * @return void
+ */
+ protected function beforeAction( $request )
+ {
+ if ( ! $request->action )
+ throw new ClientException('no action set');
+ if ( ! $request->method )
+ throw new ClientException('no subaction set');
+ }
+
+
/**
* Removing the call argument from the trace.
*
@@ -107,7 +113,7 @@ abstract class APIOutput extends BaseOutput
if (!defined('DEVELOPMENT') || DEVELOPMENT)
$data['cause'] = $this->exceptionToArray($cause);
- $this->outputData($data);
+ $this->outputData(null,$data);
}
}
diff --git a/modules/cms/output/BaseOutput.class.php b/modules/cms/output/BaseOutput.class.php
@@ -5,19 +5,13 @@ namespace cms\output;
use BadMethodCallException;
use cms\action\RequestParams;
use cms\base\Language as L;
-use cms\base\Startup;
use cms\Dispatcher;
use Exception;
-use template_engine\engine\TemplateRunner;
use util\Http;
use logger\Logger;
-use LogicException;
use \util\exception\ObjectNotFoundException;
use util\exception\UIException;
use util\exception\SecurityException;
-use template_engine\engine\TemplateEngine;
-use util\Session;
-use util\text\TextMessage;
/**
@@ -58,7 +52,7 @@ abstract class BaseOutput implements Output
$this->setError(L::lang($e->key,$e->params),$e);
} catch (SecurityException $e) {
Logger::info($e);
- Http::notAuthorized();
+ Http::forbidden();
$this->setError("You are not allowed to execute this action.",$e);
} catch (Exception $e) {
Logger::warn( $e );
diff --git a/modules/cms/output/OutputFactory.class.php b/modules/cms/output/OutputFactory.class.php
@@ -24,7 +24,8 @@ class OutputFactory {
'json' => self::OUTPUT_JSON,
'xml' => self::OUTPUT_XML,
'yaml' => self::OUTPUT_YAML,
- 'plain' => self::OUTPUT_PLAIN
+ 'plain' => self::OUTPUT_PLAIN,
+ 'html' => self::OUTPUT_HTML,
];
/**
@@ -33,10 +34,14 @@ class OutputFactory {
const MAP_ACCEPT = [
'application/php-array' => self::OUTPUT_PHPARRAY,
'application/php-serialized' => self::OUTPUT_PHPSERIALIZE,
+ 'text/json' => self::OUTPUT_JSON,
'application/json' => self::OUTPUT_JSON,
+ 'text/xml' => self::OUTPUT_XML,
'application/xml' => self::OUTPUT_XML,
'application/yaml' => self::OUTPUT_YAML,
+ 'application/xhtml+xml' => self::OUTPUT_HTML,
'text/html' => self::OUTPUT_HTML,
+ '*/*' => self::OUTPUT_HTML,
];
@@ -81,16 +86,29 @@ class OutputFactory {
$reqOutput = strtolower(@$_REQUEST['output']);
// Try 1: Checking the 'output' request parameter.
- if ( $reqOutput && array_key_exists( $reqOutput, self::MAP_OUTPUT ) )
+ if ( $reqOutput ) {
+ if ( ! array_key_exists( $reqOutput, self::MAP_OUTPUT ) )
+ {
+ Http::notAcceptable();
+ header('Content-Type: text/plain');
+ echo "Accepted output types are: ".implode(",",array_keys(self::MAP_OUTPUT));
+ exit;
+ }
+
return self::MAP_OUTPUT[ $reqOutput ];
+ }
// Try 2: Lets check the HTTP request "Accept" header.
+ //print_r(Http::getAccept());
foreach( Http::getAccept() as $acceptType )
if ( array_key_exists( $acceptType, self::MAP_ACCEPT ) )
return self::MAP_ACCEPT[ $acceptType ];
// Fallback
- return self::OUTPUT_HTML;
+ Http::notAcceptable();
+ header('Content-Type: text/plain');
+ echo "Accepted types are: ".implode(",",array_keys(self::MAP_ACCEPT));
+ exit;
}
}
\ No newline at end of file
diff --git a/modules/util/Http.class.php b/modules/util/Http.class.php
@@ -382,6 +382,19 @@ class Http
}
+
+ public static function badRequest() {
+ self::sendStatus('400','Bad Request');
+ }
+
+ public static function methodNotAllowed() {
+ self::sendStatus('405','Bad Request');
+ }
+
+ public static function notAcceptable() {
+ self::sendStatus('406','Not Acceptable');
+ }
+
/**
* Server-Fehlermeldung anzeigen.<br>
*
@@ -408,7 +421,7 @@ class Http
//error_log( $e->__toString() );
}*/
- self::sendStatus(501, 'Internal Server Error');
+ self::sendStatus(500, 'Internal Server Error');
}
@@ -421,9 +434,9 @@ class Http
* @param String $text Text
* @param String $message Eigener Hinweistext
*/
- public static function notAuthorized()
+ public static function forbidden()
{
- Http::sendStatus(403, 'Not authorized');
+ Http::sendStatus(403, 'Forbidden');
}
@@ -457,7 +470,7 @@ class Http
* @param Integer $status HTTP-Status (ganzzahlig) (Default: 501)
* @param String $text HTTP-Meldung (Default: 'Internal Server Error')
*/
- private static function sendStatus($status = 501, $text = 'Internal Server Error')
+ private static function sendStatus($status = 500, $text = 'Internal Server Error')
{
if (headers_sent()) {
echo "$status $text";
@@ -476,7 +489,10 @@ class Http
public static function getAccept()
{
$httpAccept = getenv('HTTP_ACCEPT');
- return $types = explode(',', $httpAccept);
+ return array_map( function($accept) {
+ return explode(';',$accept)[0];
+ }, explode(',', $httpAccept)
+ );
}
diff --git a/modules/util/exception/ClientException.class.php b/modules/util/exception/ClientException.class.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace util\exception;
+
+use Exception;
+
+class ClientException extends Exception
+{
+}
+