openrat-cms

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

APIOutput.class.php (3173B)


      1 <?php
      2 
      3 namespace cms\output;
      4 
      5 use BadMethodCallException;
      6 use cms\action\RequestParams;
      7 use cms\base\Startup;
      8 use Exception;
      9 use util\exception\ClientException;
     10 use util\Session;
     11 
     12 /**
     13  * Entrypoint for all API requests.
     14  */
     15 abstract class APIOutput extends BaseOutput
     16 {
     17     /**
     18      * Converting an exception to an array.
     19      *
     20      * This will contain all exceptions out of the exception chain.
     21      *
     22      * @param $e Exception
     23      */
     24     private static function exceptionToArray($e)
     25     {
     26         $data = array(
     27             'error'      => get_class($e),
     28             'description'=> $e->getMessage(),
     29             'code'       => $e->getCode(),
     30 
     31             'trace'=>array_merge( array( array(
     32                 'file'     => $e->getFile(),
     33                 'line'     => $e->getLine(),
     34                 'function' => '',
     35                 'class'    => '',
     36                 )), self::removeArgsFromTrace($e->getTrace()))
     37         );
     38 
     39         // the cause of the exception is another exception.
     40         if   ( $e->getPrevious() )
     41             $data['cause'] = self::exceptionToArray($e->getPrevious() );
     42 
     43         return $data;
     44     }
     45 
     46 	/**
     47 	 * This method is executed before the dispatcher is called.
     48 	 * Subclasses may override this to prepare the response.
     49 	 * @param $request RequestParams
     50 	 * @return void
     51 	 */
     52 	protected function beforeAction( $request )
     53 	{
     54 		if   ( ! $request->action )
     55 			throw new ClientException('no action set');
     56 		if   ( ! $request->method )
     57 			throw new ClientException('no subaction set');
     58 	}
     59 
     60 
     61     /**
     62      * Removing the call argument from the trace.
     63      *
     64      * This is because of security reasons. The arguments could be an information leak.
     65      *
     66      * @param $trace array
     67      * @return array
     68      */
     69     private static function removeArgsFromTrace($trace)
     70     {
     71         foreach( $trace as &$t )
     72         {
     73             unset($t['args']);
     74         }
     75 
     76         return $trace;
     77     }
     78 
     79 	protected function outputData($request, $data)
     80 	{
     81 		$data += [
     82 			'session' => [
     83 				'name'  => session_name(),
     84 				'id'    => session_id(),
     85 				'token' => Session::token()
     86 			],
     87 			'version' => Startup::VERSION,
     88 			'api'     => Startup::API_LEVEL,
     89 		];
     90 
     91 		$output = $this->renderOutput( $data );
     92 
     93 		// HTTP Spec:
     94 		// "Applications SHOULD use this field to indicate the transfer-length of the
     95 		//  message-body, unless this is prohibited by the rules in section 4.4."
     96 		//
     97 		// And the overhead of 'Transfer-Encoding: chunked' is eliminated...
     98 		header('Content-Length: ' . strlen($output));
     99 		echo $output;
    100 	}
    101 
    102 	abstract protected function renderOutput( $data );
    103 
    104 	/**
    105 	 * @param string $text
    106 	 * @param Exception $cause
    107 	 */
    108 	protected function setError($text, $cause)
    109 	{
    110 		$data = [
    111 			'message' => $text,
    112 			'notices' => [
    113 				[
    114 					'status'=> 'error',
    115 					'text'  => $text,
    116 					'log'   => (!defined('DEVELOPMENT') || DEVELOPMENT) ? $cause->getMessage() : '',
    117 				]
    118 			],
    119 			'errors'  => [],
    120 		];
    121 
    122 		// Traces only in DEVELOPMENT mode
    123 		// for security reasons, because traces may contain sensitive information.
    124 		if (!defined('DEVELOPMENT') || DEVELOPMENT)
    125 			$data['cause'] = $this->exceptionToArray($cause);
    126 
    127 		$this->outputData(null,$data);
    128 	}
    129 
    130 }