<?php if (!defined('VB_ENTRY')) die('Access denied.'); class vB_Api_Wrapper { use vB_Trait_NoSerialize; protected $controller; protected $api; public function __construct($controller, $api) { $this->controller = $controller; $this->api = $api; } protected function validateCall($controller, $method, $arguments) { if (get_class($controller) == 'vB_Api_Null') { return 0; } if (method_exists($controller, $method)) { $reflection = new ReflectionMethod($controller, $method); } else { return 0; } if ($reflection->isStatic()) { return 2; } if ($reflection->isConstructor()) { return 3; } if ($reflection->isDestructor()) { return 4; } $index = 0; foreach ($reflection->getParameters() AS $param) { if (!isset($arguments[$index])) { if (!$param->allowsNull() AND !$param->isDefaultValueAvailable()) { throw new vB_Exception_Api('invalid_data_w_x_y_z', ['null', $param->getName(), get_class($controller), $method]); } } else { $type = $param->getType(); if ($type AND $type->getName() == 'array' AND !is_array($arguments[$index])) { throw new vB_Exception_Api('invalid_data_w_x_y_z', [strval($arguments[$index]), $param->getName(), get_class($controller), $method]); } } $index++; } return 1; } public function callNamed($method, $args) { if (!is_callable([$this->api, $method])) { return $this->callInternal('callNamed', [$method, $args]); } $reflection = new ReflectionMethod($this->api, $method); if ( $reflection->isConstructor() OR $reflection->isDestructor() OR $reflection->isStatic() OR !$reflection->isPublic() OR $method == "callNamed" ) { return; } $php_args = []; foreach ($reflection->getParameters() as $param) { if (array_key_exists($param->getName(), $args)) { $php_args[] = &$args[$param->getName()]; } else { if ($param->isDefaultValueAvailable()) { $php_args[] = $param->getDefaultValue(); } else { throw new Exception('Required argument missing: ' . htmlspecialchars($param->getName())); } } } return call_user_func_array([$this, $method], $php_args); } public function __call($method, $arguments) { if (method_exists('vB_Api', $method)) { return null; } return $this->callInternal($method, $arguments); } private function callInternal($method, $arguments) { try { if ( !in_array($method, ['callNamed', 'getRoute', 'checkBeforeView']) AND !($this->controller === 'state' AND $method === 'checkCSRF') ) { if (!$this->api->checkApiState($method)) { return false; } } $result = null; $type = $this->validateCall($this->api, $method, $arguments); if ($type == 1) { if (is_callable([$this->api, $method])) { $call = call_user_func_array([&$this->api, $method], $arguments); if ($call !== null) { $result = $call; } } } else if ($type != 0) { return null; } $elist = vB_Api_Extensions::getExtensions($this->controller); if ($elist) { foreach ($elist AS $class) { if (is_callable([$class, $method])) { $args = $arguments; array_unshift($args, $result); $call = call_user_func_array([$class, $method], $args); if ($call !== null) { $result = $call; } } } } } catch (vB_Exception_Api | vB_Utility_Exception_Phrase $e) { $errors = $e->getErrors(); if (vB::isDebug()) { $errors[] = ['exception_trace', vB_Exception::getFullTrace($e)]; } $result = ['errors' => $errors]; try { $result['userid'] = vB::getCurrentSession()->get('userid'); } catch(Throwable $e){} } catch (vB_Exception_Database $e) { $usercontext = vB::getUserContext(); if (vB::isDebug() OR ($usercontext AND $usercontext->hasAdminPermission('cancontrolpanel'))) { $errors = ['Error ' . $e->getMessage()]; $errors[] = ['exception_trace', vB_Exception::getFullTrace($e)]; $result = ['errors' => $errors]; } else { $result = ['errors' => [['There has been a database error, and the current page cannot be displayed. Site staff have been notified.']]]; } } catch (Throwable $e) { $errors = [['unexpected_error', $e->getMessage()]]; if (vB::isDebug()) { $errors[] = ['exception_trace', vB_Exception::getFullTrace($e)]; } $result = ['errors' => $errors]; } return $result; } } 