/** * factory method to create a rpc server instance by either passing an server * instance in first parameter or string with server driver name, e.g. "json" * or null value which will return the last added instance. will return instance * of Xapp_Rpc_Server in all cases * * @error 13901 * @param null|string|Xapp_Rpc_Server $mixed expects value as explained above * @param null|array|object $options expects optional options to pass to server instance when constructing * @return Xapp_Rpc_Server * @throws Xapp_Rpc_Exception */ public static final function server($mixed = null, $options = null) { if ($mixed !== null) { self::getServer(); if ($mixed instanceof Xapp_Rpc_Server) { $driver = strtolower(substr($mixed, strrpos($mixed, '_') + 1)); if (!array_key_exists($driver, self::$_instances)) { self::$_instances[$driver] = $mixed; } return self::$_instances[$driver]; } else { $driver = strtolower(trim($mixed)); if (!array_key_exists($driver, self::$_instances)) { $class = 'Xapp_Rpc_Server_' . ucfirst($driver); if (class_exists($class, true)) { self::$_instances[$driver] = new $class($options); } else { throw new Xapp_Rpc_Exception(xapp_sprintf(_("rpc server class: %s does not exist"), $class), 1390101); } } return self::$_instances[$driver]; } } else { return self::$_instances[sizeof(self::$_instances) - 1]; } }
/** * get and create static driver instance. if the first parameter is null will try to get * the current active instance created regardless of the driver. will throw error if no instance has * been created yet. if the second parameter is a driver string like "file" or "apc" will check * if instance has already been created and if not will do so with the passed options in second * parameter. this method is the preferred way to create cache instances when using multiple instances * with different namespaces and/or driver since the factory method will create an instance but not get * it at a later stage. the first parameter can be null meaning no namespace identifier which equals to * current instance - should only be used when using one instance! * * @error 15301 * @param null|string $ns expects optional instance namespace identifier * @param null|string $driver expects the cache driver string * @param null|mixed $options expects xapp option array or object * @return Xapp_Cache_Driver concrete xapp cache driver implementation instance * @throws Xapp_Cache_Exception */ public static function instance($ns = null, $driver = null, $options = null) { if (func_num_args() > 0) { //setting if ($driver !== null) { self::factory($driver, $options, $ns); } //getting if ($ns !== null) { if (array_key_exists($ns, self::$_instances)) { return self::$_instances[trim((string) $ns)]; } else { throw new Xapp_Cache_Exception(xapp_sprintf(_("no cache instance under ns: %s registered"), $ns), 1530102); } } else { return self::$_instance; } } else { //getting if (self::$_instance !== null) { return self::$_instance; } else { throw new Xapp_Cache_Exception(_("can not get current cache class instance since no instance has been set yet"), 1530101); } } }
/** * class constructor sets std flag to init valid str resource. std * flag can be err, out * * @error 12001 * @param string $type expects the std flag * @throws Xapp_Log_Writer_Exception */ public function __construct($type = 'err') { $type = 'STD' . strtoupper(trim((string) $type)); if (defined($type)) { $this->_std = constant($type); } else { throw new Xapp_Log_Writer_Exception(xapp_sprintf(_("std type: %s is not defined"), $type), 1200101); } }
/** * load config from php array of php file containing a single array like: * * return array * ( * "foo" => 1, * "test" => "test", * ... * ); * * @error 12701 * @param array|string $php expects php array or php file pointer * @return array * @throws Xapp_Config_Exception */ public static function load($php) { if (!is_array($php) && (bool) preg_match('/\\.phtml|\\.php([0-9]{1,})?|\\.inc$/i', $php)) { if (is_file($php)) { $php = (require $php); if ($php === 1) { $php = array_slice(get_defined_vars(), 1); } } else { throw new Xapp_Config_Exception(xapp_sprintf(_("unable to load php config file: %s"), $php), 1270101); } } return (array) $php; }
/** * init class instance by validating cache directory for being readable and writable * * @error 16202 * @return void * @throws Xapp_Cache_Driver_Exception */ protected function init() { try { $dir = new SplFileInfo(xapp_get_option(self::PATH, $this)); if (!$dir->isReadable()) { throw new Xapp_Cache_Driver_Exception(_("cache directory is not readable"), 1620201); } if (!$dir->isWritable()) { throw new Xapp_Cache_Driver_Exception(_("cache directory is not writable"), 1620202); } xapp_set_option(self::PATH, rtrim($dir->getRealPath(), DS) . DS, $this); } catch (Exception $e) { throw new Xapp_Cache_Driver_Exception(xapp_sprintf(_("cache directory file info error: %d, %s"), $e->getCode(), $e->getMessage()), 1620203); } }
/** * load xml config structure from xml string or xml file pointer converting the xml * to json and back to array to get xml to array result * * @error 12801 * @param string $xml expects xml string or xml file pointer * @return array * @throws Xapp_Config_Exception */ public static function load($xml) { if ((bool) preg_match('/\\.xml$/i', $xml)) { if (is_file($xml) && ($xml = simplexml_load_file($xml, 'SimpleXMLElement', LIBXML_NOBLANKS | LIBXML_NOCDATA)) === false) { throw new Xapp_Config_Exception(xapp_sprintf(_("unable to load xml config from file: %s, error: %s"), $xml, libxml_get_last_error()), 1280101); } } else { if (($xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOBLANKS | LIBXML_NOCDATA)) === false) { throw new Xapp_Config_Exception(xapp_sprintf(_("unable to load xml config from string, error: %s"), libxml_get_last_error()), 1280102); } } if (($json = json_encode($xml)) !== false) { return json_decode($json, true); } else { throw new Xapp_Config_Exception(xapp_sprintf(_("unable to parse xml config: %s"), json_last_error()), 1280103); } }
/** * load and parse json format string or file pointer and return cleaned * array * * @error 12601 * @param string $json expects a encoded json string or json file pointer * @return array * @throws Xapp_Config_Exception */ public static function load($json) { $_json = json_decode(self::clean($json), true); if ($_json !== false && $_json !== null) { return $_json; } else { if (is_file($json)) { $json = json_decode(self::clean(file_get_contents($json)), true); if ($json !== false && $json !== null) { throw new Xapp_Config_Exception(xapp_sprintf(_("unable to load and decode json from: %s"), $json), 1260102); } else { return $json; } } else { throw new Xapp_Config_Exception(xapp_sprintf(_("passed json file: %s is neither json string not json file pointer"), $json), 1260101); } } }
/** * save object encoded to file passed in first parameter which is expected to be a valid file pointer. will throw * exception if file is not writeable * * @error 17026 * @param string $file expects absolute file path to store object at * @return bool * @throws Xapp_Util_Std_Exception */ public function saveTo($file) { if (file_put_contents($file, self::encode($this->_object), LOCK_EX)) { return true; } else { throw new Xapp_Util_Std_Exception(xapp_sprintf(_("unable to save to file: %s"), $file), 1702601); } }
/** * log to console directly with this method passing only the first required parameter and to change * the log type the third parameter according to allowed log types. pass a lable for second parameter * to describe the message send to console. * * @error 10908 * @param null|mixed $mixed expects the message of any type to send to console * @param null|string $label expects the optional label to describe the first parameter * @param string $type expects the log type - see log type array * @param array $options expects optional parameters * @return void * @throws Xapp_Error */ public function log($mixed = null, $label = null, $type = 'info', array $options = array()) { $type = strtolower((string) $type); if (array_key_exists($type, self::$_typeMap)) { if ($type === 'ini') { $this->ini($mixed, $label, $options); } if ($label !== null) { $label = trim(trim($label), ':') . ':'; } switch ($this->_driver) { case 'chromephp': switch ($type) { case $type === 'ungroup' || $mixed === null: $this->console->groupEnd(); break; case 'group': $this->console->group($mixed); break; case 'trace': $this->console->log((string) $label, $mixed, 'info'); break; default: $this->console->log((string) $label, $mixed, self::$_typeMap[$type]); } break; case 'firephp': switch ($type) { case $type === 'ungroup' || $mixed === null: $this->console->groupEnd(); break; case 'group': $this->console->group($mixed, $options); break; case 'trace': $this->console->trace($label); break; default: $this->console->{$type}($mixed, (string) $label, $options); } break; } } else { throw new Xapp_Error(xapp_sprintf(_("xapp console log type: %s not supported"), $type), 1090801); } }
/** * get component from url as you would do with phps native function parse url expecting * the component flag in second argument which also cab be -1 returning all components as array. * if first parameter is not set will get url from current request. the url will not include * everything after the path variable * * @error 14420 * @param null|string $url expects the optional url to parse * @param null|int $component expects optional php parse_url component flag * @return null|string|array * @throws Xapp_Rpc_Request_Exception */ public static function url($url = null, $component = null) { $tmp = array(); if ($url === null) { if (strtolower(php_sapi_name()) !== 'cli') { if ((int) $_SERVER['SERVER_PORT'] === 443 || !empty($_SERVER['HTTPS']) && strtolower(trim($_SERVER['HTTPS'])) == 'on') { $tmp[] = 'https://'; } else { $tmp[] = 'http://'; } if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW'])) { $tmp[] = $_SERVER['PHP_AUTH_USER'] . ':' . $_SERVER['PHP_AUTH_PW'] . '@'; } if (!empty($_SERVER['SERVER_NAME'])) { $tmp[] = $_SERVER['SERVER_NAME']; } else { $tmp[] = $_SERVER['HTTP_HOST']; } if (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] !== 80) { $tmp[] = ':' . (int) $_SERVER['SERVER_PORT']; } $tmp[] = '/' . ltrim($_SERVER['REQUEST_URI'], '/ '); } $url = implode('', $tmp); } if ($component !== null) { if (($u = parse_url($url, (int) $component)) !== false) { return $u; } else { throw new Xapp_Rpc_Request_Exception(xapp_sprintf(_("url: %s is not a valid url"), $url), 1442001); } } else { return $url; } }
/** * will preload passed directories to map class name (with optional namespace) to full path to class file * so autoload function will include class by looking into cached map called by this function instead of * iterating though all directories anew. see further explanation in class constructor. function will * return the class map as key => value array. * * @error 01705 * @param null|array|string $dir expects valid dir * @return array * @throws Xapp_Error */ public function preload($dir = null) { $separator = xapp_get_option(self::PATH_SEPARATOR, $this); $extensions = xapp_get_option(self::INCLUDE_EXTENSIONS, $this); $classes = xapp_get_option(self::EXCLUDE_CLASSES, $this); if ($dir === null) { $dir = $this->_dirs; } foreach ((array) $dir as $k => $v) { $v = (array) $v; if (is_dir($v[0])) { try { $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($v[0]), RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $i) { if (stripos($i->__toString(), '.svn') === false && stripos($i->__toString(), 'branches') === false) { if (!$i->isDir()) { //for xapp ext package limit iteration to first level only if (stripos($i->__toString(), 'Xapp' . DS . 'Ext' . DS . 'src') !== false && substr($i->__toString(), strrpos($i->__toString(), DS) - 3, 3) !== 'src') { continue; } $class = ''; $file = trim($i->__toString()); $path = trim((string) substr(substr($file, 0, strrpos($file, DS)), strlen($v[0])), DS); $paths = explode(DS, str_replace(DS . 'src', '', $path)); $name = substr(basename($file), 0, strpos(basename($file), '.')); $ext = strtolower(substr($file, strrpos($file, '.') + 1)); $div = isset($v[2]) ? strtolower(trim($v[2])) : $separator; $ns = isset($v[1]) && !empty($v[1]) ? trim(trim($v[1]), $div) : ''; if (empty($path)) { $class = (!empty($ns) && $name !== 'xapp' ? $ns . $div : '') . $name; } else { $class .= !empty($ns) && $ns !== array_shift($paths) ? $ns . $div : ''; $paths = explode(DS, str_replace(DS . 'src', '', $path)); if (end($paths) === $name) { $class .= implode($div, $paths); } else { $class .= implode($div, array_merge($paths, array($name))); } } $class = strtolower($class); if (in_array($ext, $extensions) && !in_array($class, (array) $classes)) { if (!isset($this->_classes[$k])) { $this->_classes[$k] = array(); } if (!array_key_exists($class, $this->_classes[$k])) { $this->_classes[$k][$class] = $file; } } } } } } catch (Exception $e) { throw new Xapp_Error(xapp_sprintf(_("iterator exception: %d, %s"), $e->getCode(), $e->getMessage()), 0170501); } } else { throw new Xapp_Error(xapp_sprintf(_("unable to preload dir: %s since dir is not valid"), $v[0]), 0170501); } } return $this->_classes; }
/** * json implementation of saveTo method, see Xapp_Util_Std_Store::saveTo for more details * * @error 16905 * @param string $file expects absolute file path to store object at * @param bool $pretty expects boolean value whether to store json string pretty or non pretty * @return bool * @throws Xapp_Util_Json_Exception */ public function saveTo($file, $pretty = true) { $result = null; if ((bool) $pretty) { $result = file_put_contents($file, Xapp_Util_Json::prettify(Xapp_Util_Json::encode($this->_object)), LOCK_EX); } else { $result = file_put_contents($file, Xapp_Util_Json::encode($this->_object), LOCK_EX); } if ($result !== false) { $result = null; return true; } else { throw new Xapp_Util_Json_Exception(xapp_sprintf(_("unable to save to file: %s"), $file), 1690501); } }
/** * get the smd target path in absolute or relative mode for services or base url for smd * output if first parameter is not set. this function will return target in htaccess rewrite * style if the option REWRITE_URL is set. this option can be either boolean true let the smd * resolve the rewrite pattern automatically which is nothing but extending the base path of * the url to contain the service class and function parameter like: "/base/rpc/index.php" * becomes "/base/rpc/class.function" or "/base/rpc/function" because rewrite will remap this * rule to "/base/rpc/index.php?service=class.function". you can also pass a string with your * rewrite rule as "/base/rpc/foo/{$class}/{$function}" with {($|%)} $ or % placeholder values. * always make sure your htaccess rule reflects the rewrite rule and vice versa and that service * values are always rewritten to $_GET "service" parameter. the second parameter defines whether * to return the url as relative or absolute or if not set will look for global option RELATIVE_TARGETS * * @error 14113 * @param null|string $service expects optional the service method/function and class in dot notation * @param null|bool $relative defined whether to return path absolute or relative * @return string * @throws Xapp_Rpc_Smd_Exception */ protected function getTarget($service = null, $relative = null) { $class = null; $function = null; $separator = xapp_get_option(self::CLASS_METHOD_SEPARATOR, $this); $url = Xapp_Rpc_Request::url(null, -1); $host = rtrim($url['host'], '/ '); $path = trim($url['path'], '/ '); if (preg_match('/(\\.([^\\/]+|$))/i', $path, $m, PREG_OFFSET_CAPTURE)) { if (isset($m[1]) && is_array($m[1])) { $path = substr($path, 0, $m[1][1] + strlen($m[1][0])); } } if (xapp_is_option(self::REWRITE_URL, $this) && strpos($path, 'index.') !== false) { $path = substr($path, 0, strpos($path, 'index.')); } if ($service !== null) { if (strpos($service, $separator) !== false) { $class = substr($service, 0, strpos($service, $separator)); $function = substr($service, strpos($service, $separator) + 1); } else { $class = null; $function = $service; } } if ($service !== null) { if (xapp_is_option(self::REWRITE_URL, $this)) { $_url = xapp_get_option(self::REWRITE_URL, $this); if (is_bool($_url) && $_url) { $_url = rtrim($path, '/') . '/{$class}{$separator}{$function}'; } $_url = trim($_url, '/ '); if (($_url = parse_url($_url)) !== false) { $path = trim(preg_replace(array('/\\{(?:\\$|\\%)([^\\}]+)\\}/ie', '/\\/+/'), array("\$\$1", '/'), $_url['path']), '/ '); } else { throw new Xapp_Rpc_Smd_Exception(xapp_sprintf(_("smd rewrite rule: %s is not a valid url or url path value"), $_url), 1411301); } } else { $path = $path . "?service={$service}"; } } if ($relative === null) { $relative = xapp_get_option(self::RELATIVE_TARGETS, $this); } if ((bool) $relative) { return '/' . ltrim($path, '/ '); } else { return $url['scheme'] . '://' . $host . (isset($url['port']) && !empty($url['port']) ? ':' . $url['port'] : '') . '/' . $path; } }
/** * invoke class/method or function via rpc or outside rpc functionality for testing purposes. the first parameter * thus can be a valid callable when used outside of rpc service or the internal array containing all call parameters * from concrete rpc server implementation. throws exception with extended exception properties if in debug mode. * summarizes all caught applications exceptions when invoking callable to a general application error so sensitive * error messages can be omitted. when invoked with named parameters will reorder parameters to reflect * order of method/function call since call_user_func_array needs to pass parameter named or unnamed in * correct order * * @error 14211 * @param array|callable $call expects either valid callable or array with all call parameters * @param array $params expects the parameters to pass to function/method to invoke * @return mixed * @throws Xapp_Rpc_Server_Exception * @throws Xapp_Rpc_Fault * @throws Exception */ public function invoke($call, $params = null) { $key = null; $hash = null; $class = null; $return = null; $result = null; $callable = null; try { //invoke from outside of rpc service if (is_callable($call)) { $callable = $call; if (is_array($call)) { $call = array(null, $call[1], is_object($call[0]) ? get_class($call[0]) : $call[0]); $class = new ReflectionClass($call[2]); } else { if (strpos((string) $call, '::') !== false) { $call = array(null, substr($call, strpos($call, '::') + 2), substr($call, 0, strpos($call, '::'))); $class = new ReflectionClass($call[2]); } else { $call = array(null, $call, $call); $class = null; } } } else { if (is_array($call)) { if ($call[2] !== null) { if (xapp_get_option(self::NAMESPACE_IDENTIFIER, $this) === NAMESPACE_SEPARATOR) { if (strpos($call[2], NAMESPACE_SEPARATOR) !== false) { $call[2] = NAMESPACE_SEPARATOR . str_replace(array('\\', '/', '_', '.'), xapp_get_option(self::NAMESPACE_IDENTIFIER, $this), trim($call[2], ' ' . NAMESPACE_SEPARATOR)); } else { $call[2] = str_replace(array('/', '_', '.'), xapp_get_option(self::NAMESPACE_IDENTIFIER, $this), trim($call[2])); } } else { $call[2] = str_replace(array('\\', '/', '_', '.'), xapp_get_option(self::NAMESPACE_IDENTIFIER, $this), trim($call[2])); } $key = "{$call[2]}.{$call[1]}"; try { if (array_key_exists(strtolower($call[2]), $this->_objects)) { $class = new ReflectionClass($this->_objects[strtolower($call[2])]); } else { $class = new ReflectionClass($call[2]); } if ($class->hasMethod($call[1])) { $method = $class->getMethod($call[1]); if ($method->isPublic()) { if ($method->isStatic()) { $callable = array($class->getName(), $call[1]); } else { $callable = array(array_key_exists(strtolower($call[2]), $this->_objects) ? $this->_objects[strtolower($call[2])] : $class->newInstance(), $call[1]); } } else { Xapp_Rpc_Fault::t("method: {$call[1]} of class: {$call[2]} is not public", array(1421105, -32601)); } } else { Xapp_Rpc_Fault::t("method: {$call[1]} of class: {$call[2]} does not exist", array(1421104, -32601)); } } catch (ReflectionException $e) { throw new Xapp_Rpc_Server_Exception(xapp_sprintf(_("unable to initialize class due to reflection error: %d, %s"), $e->getCode(), $e->getMessage()), 1421103); } } else { $key = $call[1]; $callable = $call[1]; } } else { throw new Xapp_Rpc_Server_Exception(_("invalid callable passed to invoke method"), 1421106); } } if (is_callable($callable)) { if (is_array($callable) && is_object($callable[0])) { $this->_class = $callable[0]; } if (!is_null($key) && !is_null($params) && array_values((array) $params) !== (array) $params) { $tmp = array(); $arr = (array) $params; $map = $this->smd()->get($key); if (!is_null($map)) { foreach ((array) $map->parameters as $p) { if (array_key_exists($p->name, $arr)) { $tmp[$p->name] = $arr[$p->name]; } } } $params = $tmp; $tmp = null; $arr = null; $map = null; } if (!is_null($key) && xapp_is_option(self::CACHE, $this) && preg_match(Xapp_Rpc::regex(xapp_get_option(self::CACHE_SERVICES, $this)), $call[0])) { if (xapp_get_option(self::CACHE_BY_TRANSACTION_ID, $this)) { $hash = $call[3]['id']; } else { $hash = Xapp_Cache::hash(serialize($call[0]) . serialize($params)); } if (xapp_get_option(self::CACHE, $this)->has($hash)) { return xapp_get_option(self::CACHE, $this)->get($hash); } } if (!xapp_get_option(self::PARAMS_AS_ARRAY, $this)) { $params = xapp_array_to_object($params); } xapp_event('xapp.rpc.server.beforeCall', array($this, array(&$result, $call[1], $call[2], $params))); if ($this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) { $return = $this->getClass()->onBeforeCall($this, array(&$result, $call[1], $call[2], &$params)); } if ($return !== false && $result === null) { $this->response()->result($result = call_user_func_array($callable, (array) $params)); } if ($return === false && $this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) { $return = $this->getClass()->onAbort($this, array(&$result, $call[1], $call[2], &$params)); } else { $return = null; } if ($return !== null) { $result = $return; } if ($this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) { $return = $this->getClass()->onAfterCall($this, array(&$result)); } if ($return !== null) { $result = $return; } xapp_event('xapp.rpc.server.afterCall', array($this, array(&$result))); if (!is_null($hash)) { if (!xapp_get_option(self::CACHE, $this)->has($hash)) { xapp_get_option(self::CACHE, $this)->set($hash, $result); } } $callable = null; $return = null; $params = null; $class = null; $hash = null; return $result; } else { throw new Xapp_Rpc_Server_Exception(_("unable to invoke function since first argument is not a callable"), 1421102); } } catch (Exception $e) { if ($this->hasClass() && $class->implementsInterface('Xapp_Rpc_Interface_Callable')) { $error = $this->getClass()->onError($this, $e); if ($error instanceof Exception) { $e = $error; $error = null; } } if (!$e instanceof Xapp_Rpc_Server_Exception) { $data = array(); $debug = xapp_get_option(self::DEBUG, $this); if (is_bool($debug) && $debug === true || is_int($debug) && $debug === 1) { $data['message'] = $e->getMessage(); $data['code'] = $e->getCode(); $data['class'] = get_class($e); $data['file'] = $e->getFile(); $data['line'] = $e->getLine(); if ($e instanceof ErrorException) { $data['severity'] = $e->getSeverity(); } if ($e instanceof Xapp_Rpc_Fault && $e->hasData()) { $data['data'] = $e->getData(); } } else { if (is_int($debug) && $debug === 2) { $data['message'] = $e->getMessage(); $data['code'] = $e->getCode(); if ($e instanceof ErrorException) { $data['severity'] = $e->getSeverity(); } if ($e instanceof Xapp_Rpc_Fault && $e->hasData()) { $data['data'] = $e->getData(); } } } if (xapp_is_option(self::APPLICATION_ERROR, $this)) { if ($e instanceof Xapp_Rpc_Fault && $e->hasFault()) { $f = $e->getFault(); } else { $f = -32500; } if (($code = (int) $e->getCode()) !== 0) { Xapp_Rpc_Fault::t(xapp_sprintf("application error: %d", array($code)), array(1421101, $f), XAPP_ERROR_IGNORE, $data); } else { Xapp_Rpc_Fault::t("application error", array(1421101, $f), XAPP_ERROR_IGNORE, $data); } } else { if ((bool) $debug) { Xapp_Rpc_Fault::t($e->getMessage(), $e->getCode(), XAPP_ERROR_IGNORE, $data); } else { throw $e; } } } else { throw $e; } } return null; }
/** * init instance by checking for memcached extension and validating server options * * @error 15801 * @return void * @throws Xapp_Cache_Driver_Exception */ protected function init() { if (!extension_loaded('memcached')) { throw new Xapp_Cache_Driver_Exception(_("memcached is not supported by this system"), 1580101); } if (xapp_is_option(self::COMPRESS, $this)) { xapp_set_option(self::OPTIONS, array(Memcached::OPT_COMPRESSION => xapp_get_option(self::COMPRESS, $this)), $this); } if (xapp_is_option(self::CONNECTION_TIMEOUT, $this)) { xapp_set_option(self::OPTIONS, array(Memcached::OPT_CONNECT_TIMEOUT => xapp_get_option(self::CONNECTION_TIMEOUT, $this)), $this); } if (xapp_is_option(self::INSTANCE, $this)) { $this->_memcached = xapp_get_option(self::INSTANCE, $this); } else { if (xapp_is_option(self::PERSISTENT_ID, $this)) { $this->_memcached = new Memcached(xapp_get_option(self::PERSISTENT_ID, $this)); } else { $this->_memcached = new Memcached(); } if (xapp_is_option(self::OPTIONS, $this)) { foreach (xapp_get_option(self::OPTIONS, $this) as $k => $v) { if (!$this->_memcached->setOption((int) $k, $v)) { throw new Xapp_Cache_Driver_Exception(xapp_sprintf(_("unable to set memcached option: %s"), $k), 1580102); } } } $server = xapp_get_option(self::SERVER, $this); if (is_object($server)) { xapp_set_option(self::SERVER, array($server), $this, true); } else { if (is_array($server) && !array_key_exists(0, $server)) { xapp_set_option(self::SERVER, array($server), $this, true); } } foreach ((array) xapp_get_option(self::SERVER, $this) as $server) { $server = (array) $server; if (!array_key_exists('host', $server)) { throw new Xapp_Cache_Driver_Exception(_("memcached parameter: host must be set"), 1580103); } if (!array_key_exists('port', $server)) { throw new Xapp_Cache_Driver_Exception(_("memcached parameter: port must be set"), 1580104); } if (!$this->_memcached->addServer($server['host'], (int) $server['port'], array_key_exists('weight', $server) ? (int) $server['weight'] : 0)) { throw new Xapp_Cache_Driver_Exception(xapp_sprintf(_("unable to add server for host: %s and port: %d"), array($server['host'], $server['port'])), 1580105); } } } }
/** * use overloading for all methods that are supported by ArrayAccess interface * * @see ArrayAccess * @error 10306 * @param string $name expects overload function name * @param null|array $args expects overloading function arguments * @return null|mixed * @throws Xapp_Error */ public function __call($name, $args = null) { $name = strtolower(trim($name)); if (in_array($name, array('get', 'set', 'unset', 'exists'))) { return call_user_func_array(array('parent', 'offset' . ucfirst($name)), (array) $args); } else { throw new Xapp_Error(xapp_sprintf(_("unable to overload class with: %s"), $name), 1030601); } }
/** * use the static create function to create a config instance of subclass implementation for * config handling. using the static method will ensure static access at any point of the application * or script. there are two ways of using config handling with namespace and public/protected access * 1) use namespace "global" or leave ns blank. by doing so all loaded config structures (key => value pairs) are loaded * into the same global public available namespace array. all values are shared and can be set/get by anyone. * this is the default behaviour * 2) use your own namespace. by doing so access to config values (set/get) is only possible if you know the namespace * identifier since all config values are stored in protected array only for that namespace. access is not possible * unless you know the namespace * If you pass the third parameter a config structure type hint is expected, e.g. json to load config with json loader * multiple config values can be passes in first parameter array merging multiple config files/buffers. NOTE: when using * multiple config values use different keys since in merging array keys will be merged! * * @error 12402 * @param string|array|mixed $config expects config structure as buffer, file pointer or any other readable value or array of multiple of the same * @param string $ns expects the namespace as explained above * @param null|string $type expects optional config type hint * @return array|null * @throws Xapp_Config_Exception */ public static function create($config, $ns = 'global', $type = null) { if ($type != null) { $type = strtolower(trim($type)); } else { if (is_array($config)) { $type = 'php'; } else { if ((bool) preg_match('/\\.([a-z0-9]{2,4})$/i', $config, $m)) { $type = strtolower(trim($m[1])); } else { $type = self::detect($config); } } } $class = __CLASS__ . '_' . $type; if (class_exists($class, true)) { if (strtolower($ns) === 'global') { if (array_key_exists(0, $config) && is_array($config[0])) { foreach ($config as $c) { self::$_globalConfig = array_merge_recursive(self::$_globalConfig, (array) $class::load($c)); } } else { self::$_globalConfig = (array) $class::load($config); } return self::$_globalConfig; } else { if (!array_key_exists($ns, self::$_instances)) { self::$_instances[$ns] = new $class($config); } return self::$_instances[$ns]; } } else { throw new Xapp_Config_Exception(xapp_sprintf(_("config class: %s does not exist"), $class), 1240201); } }
/** * validate jsonp request testing for request parameter to be valid and checking all * additional parameters * * @error 14705 * @param array $call expects the call to validate * @return void * @throws Xapp_Rpc_Fault */ protected function validate($call) { $get = $this->request()->getGet(); $service = null; if ($this->smd()->has($call[2], $call[1])) { if ($call[2] !== null) { $service = $this->smd()->get($call[2] . '.' . $call[1]); } else { $service = $this->smd()->get($call[1]); } } else { Xapp_Rpc_Fault::t("method or function is not registered as service", array(1470501, -32601)); } if (!empty($service->parameters)) { foreach ($service->parameters as $k => $v) { if (!$v->optional && (!array_key_exists($v->name, $get) || !xapp_is_value($get[$v->name]))) { Xapp_Rpc_Fault::t(xapp_sprintf("param: %s must be set", array($v->name)), array(1470503, -32602)); } if (isset($v->type) && array_key_exists($v->name, $get) && !in_array('mixed', (array) $v->type) && !in_array(xapp_type($get[$v->name], true), (array) $v->type)) { Xapp_Rpc_Fault::t(xapp_sprintf("param: %s must be of the following types: %s", array($v->name, implode('|', (array) $v->type))), array(1470504, -32602)); } } } if (xapp_is_option(self::ADDITIONAL_PARAMETERS, $this)) { foreach (xapp_get_option(self::ADDITIONAL_PARAMETERS, $this) as $k => $v) { $type = isset($v[0]) ? (array) $v[0] : false; $optional = isset($v[1]) ? (bool) $v[1] : true; if (!$optional && !array_key_exists($k, $get)) { Xapp_Rpc_Fault::t(xapp_sprintf("additional param: %s must be set", array($k)), array(1470505, -32602)); } if ($type && !in_array('mixed', $type) && !in_array(xapp_type($get[$k], true), $type)) { Xapp_Rpc_Fault::t(xapp_sprintf("additional param: %s must be of the following types: %s", array($k, implode('|', $type))), array(1470506, -32602)); } } } }
/** * factory method to create new response instance defined by first parameter driver * which must contain a string with the driver name, e.g. "json" * * @error 14502 * @param string $driver expects the driver name * @param null $options expects optional options to pass to class instance * @return Xapp_Rpc_Response * @throws Xapp_Rpc_Response_Exception */ public static function factory($driver, $options = null) { $class = __CLASS__ . '_' . ucfirst(strtolower(trim($driver))); if (class_exists($class, true)) { return new $class($options); } else { throw new Xapp_Rpc_Response_Exception(xapp_sprintf(_("rpc response class: %s does not exist"), $class), 1450201); } }
/** * write a message to all registered log writers or a specific log writer in pool by passing an alias. pass optional * parameters to log writer instance write method. see log writer implementation for more info. the $message parameter * can be string or array/object (std) with key => values pairs. the log writer will try to construct a valid loggable * message formatting the incoming message. the function will return whatever the log writer in stack return - either * a single value or array if calling all registered writers. * * @error 11510 * @param string|array|object $message expects message object see explanation above * @param null|string $alias expects optional alias to just write to specific writer * @param null|mixed $params expects optional options object * @return array|mixed the result of the log writers write function * @throws Xapp_Log_Exception */ public function write($message, $alias = null, $params = null) { $return = array(); if ($alias !== null) { $alias = strtolower(trim((string) $alias)); if (array_key_exists($alias, $this->_writer)) { return $this->_writer[$alias]->write($message, $params); } else { throw new Xapp_Log_Exception(xapp_sprintf(_("log writer for alias: %s does not exist"), $alias), 1151001); } } else { foreach ($this->_writer as $k => $writer) { $return[$k] = $writer->write($message, $params); } } return $return; }
/** * get value from registry by key for the passed namespace ns or * get whole registry for ns if key is passed null * * @error 11103 * @param null|string $key expects optional key to retrieve value for * @param null|string $ns expects the optional ns * @return null|mixed value for key * @throws Xapp_Error */ public static function get($key = null, $ns = null) { $self = self::instance(); if ($ns !== null) { $ns = strtolower(trim((string) $ns)); } else { $ns = xapp_get_option(self::DEFAULT_NS, $self); } if (isset($self->_registry[$ns])) { if ($key !== null && array_key_exists($key, $self->_registry[$ns])) { return $self->_registry[$ns][$key]; } else { return $self->_registry[$ns]; } } else { throw new Xapp_Error(xapp_sprintf(_("unable to get registry since namespace: %s does not exist"), $ns), 1110301); } }
/** * retrieve constant value or constant values for class. pass the class name as string or instance * of class in first parameter. expects either no value to return all constants or the constant * name to return the value of that constant. when passing a constant to get value for will look * for constant regardless of upper/lower case. * * @error 10605 * @param string|object $class expects class name as string or instance of class * @param null $const expects optional constant name or no value to get all constants * @return null|string|array * @throws Xapp_Error */ public static final function constantFactory($class = null, $const = null) { try { $_class = is_object($class) ? get_class($class) : $class; if (!is_object($class)) { $class = (string) $class; } $obj = new ReflectionClass($class); if ($const !== null) { $const = trim((string) $const); if ($obj->hasConstant(strtolower($const)) || $obj->hasConstant(strtoupper($const))) { if ($obj->hasConstant(strtolower($const))) { return $obj->getConstant(strtolower($const)); } if ($obj->hasConstant(strtoupper($const))) { return $obj->getConstant(strtoupper($const)); } } else { throw new Xapp_Error(xapp_sprintf(_("const: %s does not exist in class: %s"), $const, $_class), 1060502); } } else { return $obj->getConstants(); } } catch (ReflectionException $e) { throw new Xapp_Error($e, 1060501); } return null; }
/** * init class instance by validating cache directory for being readable and writable * * @error 15502 * @return void * @throws Xapp_Cache_Driver_Exception */ protected function init() { try { $dir = new SplFileInfo(xapp_get_option(self::PATH, $this)); if (!$dir->isReadable()) { throw new Xapp_Cache_Driver_Exception("cache directory is not readable", 1550201); } if (!$dir->isWritable()) { throw new Xapp_Cache_Driver_Exception("cache directory is not writable", 1550202); } xo_set(self::PATH, rtrim($dir->getRealPath(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, $this); $complete_path = xo_get(self::PATH, $this) . DIRECTORY_SEPARATOR . xo_get(self::SUBPATH, $this); if (!is_dir($complete_path)) { @mkdir($complete_path); } $subpath = xo_get(self::SUBPATH, $this) . DS; xo_set(self::SUBPATH, $subpath, $this); } catch (Exception $e) { throw new Xapp_Cache_Driver_Exception(xapp_sprintf("cache directory file info error: %d - %s", $e->getCode(), $e->getMessage()), 1550203); } }
/** * resets the whole event listener storage array, all listeners for one event or * listeners for an event at a specific index. the index can be a numerical index or * a value "first" for shifting array one down, or "last" to pop of last. * NOTE: resetting instead of overriding can accidently lead to mal function of xapp * * @error 10405 * @param null|string $event expects event name * @param null|int|string $index expects index value as explained above * @return void * @throws Xapp_Error */ public static function reset($event = null, $index = null) { if ($event !== null) { if (isset(self::$_events[$event])) { if ($index !== null) { if (is_int($index) && array_key_exists($index, self::$_events[$event])) { self::$_events[$event][$index] = array(); } else { if (strtolower((string) $index) === 'first') { array_shift(self::$_events[$event]); } else { if (strtolower((string) $index) === 'last') { array_pop(self::$_events[$event]); } else { throw new Xapp_Error(xapp_sprintf(_("unable to reset listener for event name and index: %s"), $index), 1040501); } } } } else { self::$_events[$event] = array(); } } } else { self::$_events = array(); } }
/** * validate json request object testing all request object parameters for validity. also checking all additional * parameters for validity and throwing fault if necessary * * @error 14604 * @param array $call expects the call to validate * @return void * @throws Xapp_Rpc_Fault */ protected function validate($call) { if (!xapp_get_option(self::VALIDATE, $this)) { return; } if ($this->request()->isPost()) { if ($this->request()->getRaw() === "") { Xapp_Rpc_Fault::t("empty or invalid request object", array(1460401, -32600)); } if ($this->request()->getVersion($call[3]) != xapp_get_option(self::VERSION, $this)) { Xapp_Rpc_Fault::t("rpc version not set or version miss match", array(1460402, -32013)); } if (!xapp_get_option(self::ALLOW_NOTIFICATIONS, $this) || array_key_exists('id', $call[3])) { if (!array_key_exists('id', $call[3])) { Xapp_Rpc_Fault::t("rpc transaction id must be set", array(1460405, -32015)); } if (!is_numeric($call[3]['id']) && !is_string($call[3]['id'])) { Xapp_Rpc_Fault::t("rpc transaction id must be string or integer", array(1460406, -32016)); } if (xapp_is_option(self::TRANSACTION_ID_REGEX, $this) && !preg_match(trim((string) xapp_get_option(self::TRANSACTION_ID_REGEX, $this)), $call[3]['id'])) { Xapp_Rpc_Fault::t("rpc transaction id does not match transaction id regex pattern", array(1460411, -32017)); } } if (!xapp_get_option(self::ALLOW_FUNCTIONS, $this) && empty($call[2])) { Xapp_Rpc_Fault::t("php functions as service are not supported by this rpc service", 1460412, -32018); } if (!array_key_exists('method', $call[3])) { Xapp_Rpc_Fault::t("rpc method must be set", array(1460403, -32014)); } if (!$this->smd()->has($call[2], $call[1])) { Xapp_Rpc_Fault::t("method or function is not registered as service", array(1460404, -32601)); } if (!is_null($call[2])) { $service = $this->smd()->get($call[2] . '.' . $call[1]); } else { $service = $this->smd()->get($call[1]); } if (!empty($service->parameters)) { $params = array_key_exists('params', $call[3]) ? $call[3]['params'] : null; $p = (array) $params; $k = is_null($params) || array_values($p) !== $p ? 'n' : 'i'; $i = 0; foreach ($service->parameters as $v) { $n = $v->name; if (!$v->optional && (!array_key_exists(${$k}, $p) || !xapp_is_value($p[${$k}]))) { Xapp_Rpc_Fault::t(xapp_sprintf("param: %s must be set", array(${$k})), array(1460407, -32602)); } if (isset($v->type) && array_key_exists(${$k}, $p) && !in_array('mixed', (array) $v->type) && !in_array(xapp_type($p[${$k}]), (array) $v->type)) { Xapp_Rpc_Fault::t(xapp_sprintf("param: %s must be of the following types: %s", array(${$k}, implode('|', (array) $v->type))), array(1460408, -32602)); } $i++; } } if (xapp_is_option(self::ADDITIONAL_PARAMETERS, $this)) { foreach (xapp_get_option(self::ADDITIONAL_PARAMETERS, $this) as $k => $v) { $type = isset($v[0]) ? (array) $v[0] : false; $optional = isset($v[1]) ? (bool) $v[1] : true; if (!$optional && !$this->request()->hasParam($k)) { Xapp_Rpc_Fault::t(xapp_sprintf("additional param: %s must be set", array($k)), array(1460409, -32602)); } if ($type && !in_array('mixed', $type) && !in_array(xapp_type($this->request()->getParam($k)), $type)) { Xapp_Rpc_Fault::t(xapp_sprintf("additional param: %s must be of the following types: %s", array($k, implode('|', $type))), array(1460410, -32602)); } } } } }