openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit b9d16a7751f404a4fe143e117fe69316a2e597ec
parent a42ca771f59c691027c74078b1d8a0960ce79a0b
Author: dankert <openrat@jandankert.de>
Date:   Wed,  2 Feb 2022 01:12:42 +0100

Better support for API requests.

Diffstat:
Mindex.php | 1-
Mmodules/cms/base/Startup.class.php | 4++++
Mmodules/cms/output/APIOutput.class.php | 28+++++++++++++++++-----------
Mmodules/cms/output/BaseOutput.class.php | 8+-------
Mmodules/cms/output/OutputFactory.class.php | 24+++++++++++++++++++++---
Mmodules/util/Http.class.php | 26+++++++++++++++++++++-----
Amodules/util/exception/ClientException.class.php | 10++++++++++
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 +{ +} +