EGOCMS  18.0
EGOTEC Content-Managament-System
Ego_REST_Server.php
gehe zur Dokumentation dieser Datei
1 <?php
12 class Ego_REST_Server_Exception extends Exception {
13  // Unbekannter Fehler
14  const UNKNOWN = 0;
15  const UNKNOWN_TEXT = 'Unknown error';
16 
17  // Nicht authorisiert
18  const NOT_AUTHORIZED = 1;
19  const NOT_AUTHORIZED_TEXT = 'Not authorized';
20 
21  // Ungültiger Benutzer
22  const INVALID_USER = 2;
23  const INVALID_USER_TEXT = 'Invalid user';
24 
25  // Ungültige Methode
26  const INVALID_METHOD = 4;
27  const INVALID_METHOD_TEXT = 'Invalid method';
28 
29  // Ungültige Parameter
30  const INVALID_PARAMS = 8;
31  const INVALID_PARAMS_TEXT = 'Invalid parameters';
32 }
33 
43  const BASE_URI = '/rest/';
44 
50  private $requestMethod;
51 
57  private $requestType = '';
58 
64  private $permissions = array();
65 
71  private $params = array();
72 
78  private $site = null;
79 
83  public function __construct() {
84  $this->requestMethod = strtoupper($_SERVER['REQUEST_METHOD']);
85 
86  // Gesendete Parameter ermitteln
87  $request = file_get_contents('php://input');
88  switch ($this->requestMethod) {
89  case 'PUT':
90  parse_str($request, $_REQUEST);
91  break;
92  default:
93  $_REQUEST = array_merge(array_merge($_GET, $_POST), (array) json_decode($request, true));
94  }
95  if (!is_array($_REQUEST)) {
96  $_REQUEST = array();
97  }
98 
99  // Parameter aus der URL ermitteln
100  $uri = $_SERVER['REQUEST_URI'];
101  if (strpos($uri, self::BASE_URI) === 0) {
102  // Auszuwertenden URL Bestandteil ermitteln
103  $uri = explode('/', substr(parse_url($uri, PHP_URL_PATH), strlen(self::BASE_URI)));
104 
105  if (sizeof($uri) > 1) {
106  // Es gibt mehr als einen Bestandteil, dann herausfinden welches Objekt angesprochen wird
107  switch ($uri[0]) {
108  // User_SQL
109  case '~user':
110  $this->requestType = 'user';
111  $this->params['user_id'] = (string) $uri[1]; // Benutzer ID
112  if (isset($uri[2])) {
113  $this->params['method'] = (string) $uri[2]; // User_SQL Methode
114  }
115  break;
116  // Group_SQL
117  case '~group':
118  $this->requestType = 'group';
119  $this->params['group_id'] = (string) $uri[1]; // Gruppen ID
120  if (isset($uri[2])) {
121  $this->params['method'] = (string) $uri[2]; // Group_SQL Methode
122  }
123  break;
124  // Role_SQL
125  case '~role':
126  $this->requestType = 'role';
127  $this->params['role_id'] = (string) $uri[1]; // Rollen ID
128  if (isset($uri[2])) {
129  $this->params['method'] = (string) $uri[2]; // Role_SQL Methode
130  }
131  break;
132  case '~system':
133  $this->requestType = 'system';
134  if (isset($uri[1])) {
135  $this->params['method'] = (string) $uri[1]; // Ego_System Methode
136  }
137  break;
138  // Site und Page
139  default:
140  $this->requestType = 'site';
141 
142  $this->params['site'] = $uri[0]; // Mandant
143  $this->params['lang'] = $uri[1]; // Sprache
144  if (is_numeric($uri[2])) {
145  $this->requestType = 'page';
146 
147  $this->params['id'] = $uri[2]; // ID
148  if (isset($uri[3])) {
149  $this->params['method'] = (string) $uri[3]; // Page Methode
150  }
151  } else {
152  $this->params['method'] = (string) $uri[2]; // Site Methode
153  }
154  }
155  } else {
156  // Gibt es nur einen Bestandteil, dann ist das eine Methode des Ego_REST Servers
157  $this->params['method'] = $uri[0];
158  }
159 
160  // Rechte Mapping ermitteln
161  if (!$GLOBALS['auth']->isNobody()) {
162  $cache = $GLOBALS['egotec_conf']['cache_dir'].'api-'.$GLOBALS['auth']->user->field['user_id'].'-'.$GLOBALS['auth']->user->extra['api_token'];
163  if (Ego_System::file_exists($cache)) {
164  // Rechte Mapping aus der Cache verwenden
165  $this->permissions = (array) @json_decode(Ego_System::file_get_contents($cache), true);
166  } else {
167  $permissions = array(
168  $GLOBALS['egotec_conf']['lib_dir'].'base/rest.ini',
169  $GLOBALS['egotec_conf']['site_dir'].'_global/rest.ini'
170  );
171  if (!empty($this->params['site'])) {
172  $permissions[] = $GLOBALS['egotec_conf']['site_dir'].$this->params['site'].'/rest.ini';
173 
174  // Rechte Mapping im Theme suchen
175  require_once('base/Site.php');
176  try {
177  $this->site = new Site($this->params['site'], (string) $this->params['lang']);
178  if ($this->site->theme) {
179  $permissions[] = $GLOBALS['egotec_conf']['pub_dir'].'theme/'.$this->site->theme.'/site/rest.ini';
180  }
181  } catch (Site_Exception $e) {
182  $this->sendError();
183  egotec_error_log($e->getMessage());
184  return array(
185  'error' => 'Unexpected error' . (Ego_System::isDevMode() ? ': ' . $e->getMessage() : ''),
186  'code' => -1
187  );
188  }
189  }
190  foreach ($permissions as $file) {
191  if (Ego_System::file_exists($file)) {
192  $data = (array) @parse_ini_file($file, true);
193  if (!empty($data)) {
194  $this->permissions = array_merge_recursive($this->permissions, $data);
195  }
196  }
197  }
198 
199  // Rechte Mapping in die Cache schreiben
200  Ego_System::file_put_contents($cache, json_encode($this->permissions));
201  }
202  }
203  }
204  }
205 
211  public function getResponse() {
212  $result = null;
213  try {
214  if ($this->requestType && $GLOBALS['auth']->isNobody()) {
215  // Wenn ein Objekt angesprochen wird, muss man angemeldet sein
217  }
218  switch ($this->requestType) {
219  // Handling für Site und Page Anfragen
220  case 'site':
221  case 'page':
222  if ($this->site) {
223  // Das Site Objekt ist bereits bekannt
224  $site = $this->site;
225  } else {
226  require_once('base/Site.php');
227  $site = new Site($this->params['site'], (string) $this->params['lang']);
228  }
229  require_once('base/Page.php');
230 
231  if (!$site->hasRight('view')) {
232  // Das Ansichtsrecht der Site wird nicht erfüllt
234  }
235  $page = null;
236  if (!empty($this->params['id'])) {
237  $page_param = [];
238  if (empty($this->params['method'])) {
239  // beim Aufruf von "/demo/de/1" sind alle übergebenen Parameter "param"
240  $page_param = $_REQUEST;
241  } elseif (isset($_REQUEST['page_param'])) {
242  // beim Aufruf von z.B. "/demo/de/1/getChildren" wird "page_param" zu "param"
243  $page_param = $_REQUEST['page_param'];
244  unset($_REQUEST['page_param']);
245  }
246  $page = $site->getPage($this->params['id'], $page_param);
247  if (!$page) {
249  }
250  }
251 
252  switch ($this->requestMethod) {
253  case 'POST':
254  case 'GET':
255  if (!empty($this->params['method'])) {
256  if ($page) {
257  // Eine Page Methode
258  $result = $this->call($page, $this->params['method'], $_REQUEST);
259  } else {
260  // Eine Site Methode
261  $result = $this->call($site, $this->params['method'], $_REQUEST);
262  }
263  } else {
264  switch ($this->requestMethod) {
265  case 'POST':
266  if (!empty($this->params['id'])) {
267  // Page anlegen
268  $result = $this->call($page, 'newChild', $_REQUEST);
269  } else {
270  // Site anlegen
271  if (!$GLOBALS['auth']->hasSuperuserPermission()) {
272  // Mandanten dürfen nur Superuser anlegen
274  }
275  $result = Site::createSite($_REQUEST);
276  }
277  break;
278  case 'GET':
279  if ($page) {
280  // Page zurückliefern
281  if (!$page->hasRights('view')) {
282  // Page ermitteln ist nicht erlaubt
284  }
285  $result = $page;
286  } else {
287  // Site zurückliefern
288  $result = $site;
289  }
290  }
291  }
292  break;
293  case 'PUT':
294  if ($page) {
295  // Page aktualisieren
296  $result = $this->call($page, 'update', $_REQUEST);
297  }
298  break;
299  case 'DELETE':
300  if ($page) {
301  // Page löschen
302  $result = $this->call($page, 'delete', $_REQUEST);
303  }
304  }
305  break;
306 
307  // Handling für Benutzer Anfragen
308  case 'user':
309  require_once('rights/User_SQL.php');
310  $user = new User_SQL($this->params['user_id']);
311 
312  switch ($this->requestMethod) {
313  case 'POST':
314  case 'GET':
315  if (!empty($this->params['method'])) {
316  // Eine User_SQL Methode
317  $result = $this->call($user, $this->params['method'], $_REQUEST);
318  } else {
319  if ($this->requestMethod == 'POST') {
320  // Benutzer anlegen
321  if (!empty($user->field['user_id'])) {
322  $user = new User_SQL();
323  }
324  $this->call($user, 'update', $_REQUEST);
325  }
326 
327  // Benutzer zurückliefern
328  $result = $user;
329  }
330  break;
331  case 'PUT':
332  // Benutzer aktualisieren
333  $result = $this->call($user, 'update', $_REQUEST);
334  break;
335  case 'DELETE':
336  // Benutzer löschen
337  $result = $this->call($user, 'delete', $_REQUEST);
338  }
339  break;
340 
341  // Handling für Gruppen Anfragen
342  case 'group':
343  require_once('rights/Group_SQL.php');
344  $group = new Group_SQL($this->params['group_id']);
345 
346  switch ($this->requestMethod) {
347  case 'POST':
348  case 'GET':
349  if (!empty($this->params['method'])) {
350  // Eine Group_SQL Methode
351  $result = $this->call($group, $this->params['method'], $_REQUEST);
352  } else {
353  if ($this->requestMethod == 'POST') {
354  // Gruppe anlegen
355  $new_group = new Group_SQL();
356  if ($this->call($group, 'addChild', array($new_group))) {
357  $new_group = new Group_SQL($new_group->field['group_id']);
358  $this->call($new_group, 'update', $_REQUEST);
359  $group = $new_group;
360  } else {
362  }
363  }
364 
365  // Gruppe zurückliefern
366  $result = $group;
367  }
368  break;
369  case 'PUT':
370  // Gruppe aktualisieren
371  $result = $this->call($group, 'update', $_REQUEST);
372  break;
373  case 'DELETE':
374  // Gruppe löschen
375  $result = $this->call($group, 'delete', $_REQUEST);
376  }
377  break;
378 
379  // Handling für Rollen Anfragen
380  case 'role':
381  require_once('rights/Role_SQL.php');
382  $role = new Role_SQL($this->params['role_id']);
383 
384  switch ($this->requestMethod) {
385  case 'POST':
386  case 'GET':
387  if (!empty($this->params['method'])) {
388  // Eine Role_SQL Methode
389  $result = $this->call($role, $this->params['method'], $_REQUEST);
390  } else {
391  if ($this->requestMethod == 'POST') {
392  // Rolle anlegen
393  $new_role = new Role_SQL();
394  if ($this->call($role, 'addChild', array($new_role))) {
395  $new_role = new Role_SQL($new_role->field['role_id']);
396  $this->call($new_role, 'update', $_REQUEST);
397  $role = $new_role;
398  } else {
400  }
401  }
402 
403  // Rolle zurückliefern
404  $result = $role;
405  }
406  break;
407  case 'PUT':
408  // Rolle aktualisieren
409  $result = $this->call($role, 'update', $_REQUEST);
410  break;
411  case 'DELETE':
412  // Rolle löschen
413  $result = $this->call($role, 'delete', $_REQUEST);
414  }
415  break;
416 
417  // Handling für Ego_System Anfragen
418  case 'system':
419  // Nur für Superuser zulassen
420  if (!$GLOBALS['auth']->hasSuperuserPermission()) {
422  }
423  $result = $this->call('Ego_System', $this->params['method'], $_REQUEST);
424  break;
425 
426  // Handling für Ego_REST Server Anfragen
427  default:
428  // Ego_REST Server Methode
429  $result = $this->call($this, $this->params['method'], $_REQUEST);
430  }
431  $this->sendSuccess();
432  } catch (Ego_REST_Server_Exception $e) {
433  // Ein Ego_REST Server Fehler wird ausgegeben
434  switch ($e->getCode()) {
436  Ego_System::header(401);
437  exit;
438  default:
439  $this->sendError();
440  }
441  return array(
442  'error' => $e->getMessage(),
443  'code' => $e->getCode()
444  );
445  } catch (Exception $e) {
446  // Jeder andere Fehler wird in die Errorlog geschrieben
447  $this->sendError();
448  egotec_error_log($e->getMessage());
449  return array(
450  'error' => 'Unexpected error' . (Ego_System::isDevMode() ? ': ' . $e->getMessage() : ''),
451  'code' => -1
452  );
453  }
454 
455  return $this->toJSON($result);
456  }
457 
466  private function call($object, $method, $params = array()) {
467  if (empty($method) || !method_exists($object, $method)) {
468  // Ungültiger Aufruf
470  }
471 
472  // Berechtigung prüfen
473  $authorized = true;
474  if (!empty($this->requestType)) {
475  if (isset($this->permissions[$this->requestType]) && isset($this->permissions[$this->requestType][$method])) {
476  $values = explode(':', $this->permissions[$this->requestType][$method]);
477  $methods = explode(',', $values[0]);
478  $perms = explode(',', $values[1]);
479 
480  if (!empty($methods) && !in_array($this->requestMethod, $methods)) {
481  // Request Methode ist für diesen Aufruf nicht erlaubt
482  $authorized = false;
483  }
484 
485  // Prüfen, ob der aktive Benutzer das notwendige Recht für diesen Aufruf besitzt
486  if ($authorized && !empty($perms)) {
487  // Die Site Methode mit diesen Rechten aufrufen
488  if (is_a($object, 'Site')) {
489  $object->setRights($perms);
490  }
491 
492  // Rechte für diese Page prüfen
493  if (is_a($object, 'Page') && !$object->hasRights($perms)) {
494  $authorized = false;
495  }
496  }
497 
498  // Rechte für diesen Benutzer prüfen
499  if (
500  $authorized
501  && (is_a($object, 'User_SQL')
502  || is_a($object, 'Group_SQL')
503  || is_a($object, 'Role_SQL'))
504  && !$GLOBALS['auth']->hasPermissionOn($object)
505  ) {
506  $authorized = false;
507  }
508  } else {
509  // Ist ein Request Typ gesetzt, dann müssen die erlaubten Methoden definiert sein
510  $authorized = false;
511  }
512  if (!$authorized) {
514  }
515  }
516 
517  if (!is_array($params)) {
518  $params = array();
519  }
520  return @call_user_func_array(array($object, $method), $params);
521  }
522 
529  private function toJSON($object) {
530  // Page, User_SQL, Group_SQL und Role_SQL umwandeln
531  if (
532  is_a($object, 'Page')
533  || is_a($object, 'User_SQL')
534  || is_a($object, 'Group_SQL')
535  || is_a($object, 'Role_SQL')
536  ) {
537  return array(
538  'field' => $object->field,
539  'extra' => $object->extra
540  );
541  }
542 
543  // Page_Iterator, User_Iterator, Group_Iterator und Role_Iterator umwandeln
544  if (
545  is_a($object, 'Page_Iterator')
546  || is_a($object, 'User_Iterator')
547  || is_a($object, 'Group_Iterator')
548  || is_a($object, 'Role_Iterator')
549  ) {
550  $results = array();
551  foreach ($object as $item) {
552  $results[] = $this->toJSON($item);
553  }
554  return $results;
555  }
556 
557  return $object;
558  }
559 
565  private function sendSuccess() {
566  switch ($this->requestMethod) {
567  case 'POST':
568  Ego_System::header(201);
569  break;
570  case 'GET':
571  Ego_System::header(200);
572  break;
573  case 'PUT':
574  Ego_System::header(202);
575  break;
576  case 'DELETE':
577  Ego_System::header(204);
578  break;
579  default:
580  Ego_System::header(405);
581  exit;
582  }
583  }
584 
590  private function sendError() {
591  switch ($this->requestMethod) {
592  case 'GET':
593  Ego_System::header(204);
594  break;
595  case 'DELETE':
596  Ego_System::header(400);
597  break;
598  case 'PUT':
599  case 'POST':
600  Ego_System::header(409);
601  break;
602  default:
603  Ego_System::header(405);
604  exit;
605  }
606  }
607 
615  private function startSession($user_id, $token) {
616  $user = new User_SQL($user_id);
617  if (!empty($token) && !empty($user->extra['api_token']) && $user->extra['api_token'] == $token) {
618  // Der Benutzer darf sich über die REST API anmelden
619  Auth_Factory::login($user_id);
620  return !$GLOBALS['auth']->isNobody() ? session_id() : null;
621  } else {
623  }
624  }
625 
631  private function closeSession() {
632  if (!empty($_SESSION['auth_id'])) {
633  Auth_Factory::start($GLOBALS['egotec_conf']['auth']['type'], $_SESSION['auth_id'], false, 'logout');
634  return true;
635  } else {
637  }
638  }
639 }
640 ?>
static isDevMode()
static file_put_contents($filename, $data, $flags=0, $context=null)
static createSite($new_site)
Definition: Site.php:194
static file_exists($file)
static file_get_contents($filename, $utf8=true, $context=null)
static header($header, $replace=true)
Definition: Ego_System.php:833
Definition: Site.php:29