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 }