openrat-cms

# OpenRat Content Management System
git clone http://git.code.weiherhei.de/openrat-cms.git
Log | Files | Refs

API.class.php (7559B)


      1 <?php
      2 
      3 namespace cms_api;
      4 
      5 use BadMethodCallException;
      6 use cms\action\RequestParams;
      7 use cms\Dispatcher;
      8 use Exception;
      9 use Http;
     10 use JSON;
     11 use Logger;
     12 use ObjectNotFoundException;
     13 use OpenRatException;
     14 use SecurityException;
     15 use XML;
     16 
     17 define('CMS_API_REQ_PARAM_SUBACTION', 'subaction');
     18 define('CMS_API_REQ_PARAM_ACTION', 'action');
     19 
     20 define('CMS_API_OUTPUT_PHPARRAY', 1);
     21 define('CMS_API_OUTPUT_PHPSERIALIZE', 2);
     22 define('CMS_API_OUTPUT_JSON', 3);
     23 define('CMS_API_OUTPUT_XML', 4);
     24 define('CMS_API_OUTPUT_YAML', 5);
     25 define('CMS_API_OUTPUT_HTML', 6);
     26 
     27 class API
     28 {
     29     /**
     30      * Führt einen API-Request durch.
     31      */
     32     public static function execute()
     33     {
     34         try {
     35             $request = new RequestParams();
     36 
     37             $dispatcher = new Dispatcher();
     38 
     39             $dispatcher->request = $request;
     40 
     41             $data = $dispatcher->doAction();
     42 
     43         } catch (BadMethodCallException $e) {
     44             Logger::warn($e);
     45 
     46             API::sendHTTPStatus(204, 'Method not found');
     47             $data = array('status' => 204) + API::exceptionToArray( $e );
     48         } catch (ObjectNotFoundException $e) {
     49             Logger::warn($e);
     50 
     51             API::sendHTTPStatus(204, 'Object not found');
     52             $data = array('status' => 204)+ API::exceptionToArray( $e );
     53         } catch (OpenRatException $e) {
     54             Logger::warn($e);
     55 
     56             API::sendHTTPStatus(500, 'Internal CMS Error');
     57             $data = array('status' => 500)+ API::exceptionToArray( $e );
     58         } catch (SecurityException $e) {
     59             Logger::warn($e);
     60             //Logger::info('API request not allowed: ' . $e->getMessage());
     61             API::sendHTTPStatus(403, 'Forbidden');
     62             $data = array('status' => 403)+ API::exceptionToArray( $e );
     63         } catch (Exception $e) {
     64             Logger::warn($e);
     65             API::sendHTTPStatus(500, 'Internal Server Error');
     66             $data = array('status' => 500)+ API::exceptionToArray( $e );
     67         }
     68 
     69 
     70         if (Logger::$level >= LOGGER_LOG_TRACE)
     71             Logger::trace('Output' . "\n" . print_r($data, true));
     72 
     73         // Weitere Variablen anreichern.
     74         $data['session'] = array('name' => session_name(), 'id' => session_id(), 'token' => token());
     75         $data['version'] = OR_VERSION;
     76         $data['api'] = '2';
     77 
     78 
     79         switch (API::discoverOutputType()) {
     80 
     81             case CMS_API_OUTPUT_PHPARRAY:
     82                 header('Content-Type: application/php-array; charset=UTF-8');
     83                 $output = print_r($data, true);
     84                 break;
     85 
     86             case CMS_API_OUTPUT_PHPSERIALIZE:
     87                 header('Content-Type: application/php-serialized; charset=UTF-8');
     88                 $output = serialize($data);
     89                 break;
     90 
     91             case CMS_API_OUTPUT_JSON:
     92                 header('Content-Type: application/json; charset=UTF-8');
     93                 if (function_exists('json_encode'))
     94                 {
     95                     // Native Methode ist schneller..
     96                     if ( version_compare(PHP_VERSION, '5.5', '>=' ) )
     97                         $jsonOptions = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK | JSON_PARTIAL_OUTPUT_ON_ERROR;
     98                     else
     99                         $jsonOptions = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK;
    100 
    101                     $output = json_encode($data, $jsonOptions);
    102                 }
    103                 else
    104                 {
    105                     // Fallback, falls json_encode() nicht existiert...
    106                     $json = new JSON();
    107                     $output = $json->encode($data);
    108                 }
    109                 break;
    110 
    111             case CMS_API_OUTPUT_XML:
    112                 require_once(OR_SERVICECLASSES_DIR . "XML.class." . PHP_EXT);
    113                 $xml = new XML();
    114                 $xml->root = 'server'; // Name des XML-root-Elementes
    115                 header('Content-Type: application/xml; charset=UTF-8');
    116                 $output = $xml->encode($data);
    117                 break;
    118 
    119             case CMS_API_OUTPUT_HTML:
    120                 header('Content-Type: text/html; charset=UTF-8');
    121                 $output  = '<html><body><h1>API response:</h1><hr /><pre>';
    122                 $output .= print_r($data,true);
    123                 $output .= '</pre></body></html>';
    124                 break;
    125 
    126             case CMS_API_OUTPUT_YAML:
    127                 header('Content-Type: application/yaml; charset=UTF-8');
    128                 $output = \YAML::dump($data);
    129                 break;
    130         }
    131 
    132 
    133         if (!headers_sent())
    134             // HTTP Spec:
    135             // Applications SHOULD use this field to indicate the transfer-length of the message-body, unless this is prohibited by the rules in section 4.4.
    136             //
    137             // And the overhead of Transfer-Encoding chunked is eliminated...
    138             header('Content-Length: ' . strlen($output));
    139 
    140         echo $output;
    141     }
    142 
    143     /**
    144      * Discovering the output-type for this API-request
    145      *
    146      * @return int constant of CMS_API_OUTPUT_*
    147      */
    148     private static function discoverOutputType()
    149     {
    150         $types = Http::getAccept();
    151 
    152         $reqOutput = @$_REQUEST['output'];
    153 
    154         if (in_array('application/php-array', $types) || $reqOutput == 'php-array')
    155             return CMS_API_OUTPUT_PHPARRAY;
    156 
    157         if (in_array('application/php-serialized', $types) || $reqOutput == 'php')
    158             return CMS_API_OUTPUT_PHPSERIALIZE;
    159 
    160         if (in_array('application/json', $types) || $reqOutput == 'json')
    161             return CMS_API_OUTPUT_JSON;
    162 
    163         if (in_array('application/xml', $types) || $reqOutput == 'xml')
    164             return CMS_API_OUTPUT_XML;
    165 
    166         if (in_array('application/yaml', $types) || $reqOutput == 'yaml')
    167             return CMS_API_OUTPUT_YAML;
    168 
    169         if (in_array('text/html', $types))
    170             return CMS_API_OUTPUT_HTML;  // normally an ordinary browser.
    171 
    172         return CMS_API_OUTPUT_YAML;
    173     }
    174 
    175     /**
    176      * @param $status int HTTP-Status
    177      * @param $text string Statustext
    178      */
    179     private static function sendHTTPStatus($status, $text)
    180     {
    181         if (headers_sent()) {
    182             //echo "$status $text";
    183             ; // There is nothing we can do. Every output would destroy the JSON, XML, whatever.
    184         } else {
    185             header('HTTP/1.0 ' . intval($status) . ' ' . $text);
    186         }
    187     }
    188 
    189     /**
    190      * Converting an exception to an array.
    191      *
    192      * This will contain all exceptions out of the exception chain.
    193      *
    194      * @param $e Exception
    195      */
    196     private static function exceptionToArray($e)
    197     {
    198         $data = array(
    199             'error'=>get_class($e),
    200             'description'=>$e->getMessage(),
    201             'code'=>$e->getCode(),
    202 
    203             'trace'=>array_merge( array( array(
    204                 'file'=>$e->getFile(),
    205                 'line'=>$e->getLine(),
    206                 'function'=>'',
    207                 'class'   => ''
    208                 )), API::removeArgsFromTrace($e->getTrace()))
    209         );
    210 
    211         // the cause of the exception is another exception.
    212         if   ( $e->getPrevious() != null )
    213             $data['previous'] = API::exceptionToArray($e->getPrevious() );
    214 
    215         return $data;
    216     }
    217 
    218 
    219     /**
    220      * Removing the call argument from the trace.
    221      *
    222      * This is because of security reasons. The arguments could be an information leak.
    223      *
    224      * @param $trace array
    225      * @return array
    226      */
    227     private static function removeArgsFromTrace($trace)
    228     {
    229         foreach( $trace as &$t )
    230         {
    231             unset($t['args']);
    232         }
    233 
    234         return $trace;
    235     }
    236 }