From ebf03950ffaea849b931adf83b6c20ac9fb7ef33 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 6 Jun 2006 21:43:22 +0000 Subject: [PATCH] - allow to avoid deps on shared extensions on build time - upgrade xmlrpc tools --- config.m4 | 9 ++ http.c | 8 +- http_functions.c | 4 +- http_message_object.c | 6 +- http_querystring_api.c | 4 +- http_querystring_object.c | 6 +- lib/XmlRpcClient.php | 167 ++++++++++++------------ lib/XmlRpcServer.php | 237 ++++++++++++++++++++++++++++++++++ php_http.h | 2 + php_http_cache_api.h | 24 ++-- php_http_querystring_api.h | 2 +- php_http_querystring_object.h | 2 +- 12 files changed, 362 insertions(+), 109 deletions(-) create mode 100644 lib/XmlRpcServer.php diff --git a/config.m4 b/config.m4 index 0339acc..0fc8c7f 100644 --- a/config.m4 +++ b/config.m4 @@ -13,6 +13,9 @@ PHP_ARG_WITH([http-zlib-compression], [whether to enable zlib encodings support] PHP_ARG_WITH([http-magic-mime], [whether to enable response content type guessing], [ --with-http-magic-mime[=LIBMAGICDIR] HTTP: with magic mime response content type guessing], "no", "no") +PHP_ARG_WITH([http-shared-deps], [whether to depend on shared extensions], +[ --with-http-shared-deps HTTP: disable to not depend on shared extensions + like SPL, hash, iconv and session], $PHP_HTTP, $PHP_HTTP) if test "$PHP_HTTP" != "no"; then @@ -31,6 +34,12 @@ if test "$PHP_HTTP" != "no"; then ]) ]) + if test "PHP_HTTP_SHARED_DEPS" != "no"; then + AC_DEFINE([HTTP_SHARED_DEPS], [1], [ ]) + else + AC_DEFINE([HTTP_SHARED_DEPS], [0], [ ]) + endif + dnl ------- dnl HEADERS dnl ------- diff --git a/http.c b/http.c index 9322e3f..843db22 100644 --- a/http.c +++ b/http.c @@ -137,16 +137,16 @@ PHP_MINFO_FUNCTION(http); /* {{{ http_module_dep */ #if ZEND_EXTENSION_API_NO >= 220050617 static zend_module_dep http_module_deps[] = { -# ifdef HAVE_SPL +# if defined(HAVE_SPL) && !HTTP_SHARED_EXT(SPL) ZEND_MOD_REQUIRED("spl") # endif -# ifdef HTTP_HAVE_EXT_HASH +# if defined(HTTP_HAVE_EXT_HASH) && !HTTP_SHARED_EXT(HASH) ZEND_MOD_REQUIRED("hash") # endif -# ifdef HAVE_PHP_SESSION +# if defined(HAVE_PHP_SESSION) && !HTTP_SHARED_EXT(PHP_SESSION) ZEND_MOD_REQUIRED("session") # endif -# ifdef HAVE_ICONV +# if defined(HAVE_ICONV) && !HTTP_SHARED_EXT(ICONV) ZEND_MOD_REQUIRED("iconv") # endif {NULL, NULL, NULL, 0} diff --git a/http_functions.c b/http_functions.c index 0462c3b..bdd021b 100644 --- a/http_functions.c +++ b/http_functions.c @@ -21,7 +21,7 @@ #include "ext/standard/php_string.h" #include "zend_operators.h" -#ifdef HAVE_PHP_SESSION +#ifdef HAVE_PHP_SESSION && !HTTP_SHARED_EXT(PHP_SESSION) # include "ext/session/php_session.h" #endif @@ -728,7 +728,7 @@ PHP_FUNCTION(http_redirect) RETURN_FALSE; } -#ifdef HAVE_PHP_SESSION +#ifdef HAVE_PHP_SESSION && !HTTP_SHARED_EXT(PHP_SESSION) /* append session info */ if (session) { if (!params) { diff --git a/http_message_object.c b/http_message_object.c index 5e03e1e..824745f 100644 --- a/http_message_object.c +++ b/http_message_object.c @@ -32,11 +32,9 @@ #include "php_http_request_api.h" #include "php_http_request_object.h" -#ifndef WONKY -# ifdef HAVE_SPL +#if defined(HAVE_SPL) && !HTTP_SHARED_EXT(SPL) && !defined(WONKY) /* SPL doesn't install its headers */ extern PHPAPI zend_class_entry *spl_ce_Countable; -# endif #endif #define HTTP_BEGIN_ARGS(method, req_args) HTTP_BEGIN_ARGS_EX(HttpMessage, method, 0, req_args) @@ -187,7 +185,7 @@ PHP_MINIT_FUNCTION(http_message_object) HTTP_REGISTER_CLASS_EX(HttpMessage, http_message_object, NULL, 0); #ifndef WONKY -# ifdef HAVE_SPL +# if defined(HAVE_SPL) && !HTTP_SHARED_EXT(SPL) zend_class_implements(http_message_object_ce TSRMLS_CC, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator); # else zend_class_implements(http_message_object_ce TSRMLS_CC, 2, zend_ce_serializable, zend_ce_iterator); diff --git a/http_querystring_api.c b/http_querystring_api.c index 45aa5ac..b367c20 100644 --- a/http_querystring_api.c +++ b/http_querystring_api.c @@ -16,7 +16,7 @@ #include "php_http.h" #include "php_variables.h" -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) # undef PHP_ATOM_INC # include "ext/iconv/php_iconv.h" # include "ext/standard/url.h" @@ -38,7 +38,7 @@ static inline int _http_querystring_modify_array_ex(zval *qarray, int key_type, static inline int _http_querystring_modify_array(zval *qarray, zval *params TSRMLS_DC); -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC) { HashPosition pos; diff --git a/http_querystring_object.c b/http_querystring_object.c index d0eed53..73ef9d5 100644 --- a/http_querystring_object.c +++ b/http_querystring_object.c @@ -61,7 +61,7 @@ HTTP_BEGIN_ARGS(__getter, 1) HTTP_ARG_VAL(delete, 0) HTTP_END_ARGS; -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) HTTP_BEGIN_ARGS(xlate, 2) HTTP_ARG_VAL(from_encoding, 0) HTTP_ARG_VAL(to_encoding, 0) @@ -95,7 +95,7 @@ zend_function_entry http_querystring_object_fe[] = { #ifndef WONKY HTTP_QUERYSTRING_ME(singleton, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) #endif -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) HTTP_QUERYSTRING_ME(xlate, ZEND_ACC_PUBLIC) #endif @@ -431,7 +431,7 @@ HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY); HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT); /* }}} */ -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) /* {{{ proto bool HttpQueryString::xlate(string ie, string oe) * * Converts the query string from the source encoding ie to the target encoding oe. diff --git a/lib/XmlRpcClient.php b/lib/XmlRpcClient.php index 9cdc7bb..83a154e 100644 --- a/lib/XmlRpcClient.php +++ b/lib/XmlRpcClient.php @@ -9,10 +9,10 @@ * Usage: * * options = array(array('compress' => true)); + * $rpc = new XmlRpcClient('http://mike:secret@example.com/cgi-bin/vpop-xmlrpc'); + * $rpc->__request->setOptions(array('compress' => true)); * try { - * print_r($rpc->listdomain(array('domain' => 'example.com'))); + * print_r($rpc->vpop->listdomain(array('domain' => 'example.com'))); * } catch (Exception $ex) { * echo $ex; * } @@ -22,87 +22,92 @@ * @copyright Michael Wallner, * @license BSD, revised * @package pecl/http - * @version $Revision$ + * @version $Revision$ */ class XmlRpcClient { - /** - * RPC namespace - * - * @var string - */ - public $namespace; - - /** - * HttpRequest instance - * - * @var HttpRequest - */ - public $request; - - /** - * Constructor - * - * @param string $url RPC endpoint - * @param string $namespace RPC namespace - */ - public function __construct($url, $namespace = '') - { - $this->namespace = $namespace; - $this->request = new HttpRequest($url, HTTP_METH_POST); - $this->request->setContentType('text/xml'); - } - - /** - * RPC method proxy - * - * @param string $method RPC method name - * @param array $params RPC method arguments - * @return mixed decoded RPC response - * @throws Exception - */ - public function __call($method, array $params) - { - if ($this->namespace) { - $method = $this->namespace .'.'. $method; - } - - $data = xmlrpc_encode_request($method, $params); - $this->request->setRawPostData($data); - - $response = $this->request->send(); - if ($response->getResponseCode() != 200) { - throw new Exception( - $response->getResponseStatus(), - $response->getResponseCode() - ); - } - $data = xmlrpc_decode($response->getBody(), 'utf-8'); - - if (isset($data['faultCode'], $data['faultString'])) { - throw new Exception( - $data['faultString'], - $data['faultCode'] - ); - } - - return $data; - } - - public function __set($what, $params) - { - return call_user_func_array( - array($this->request, "set$what"), - $params - ); - } - - public function __get($what) - { - return call_user_func( - array($this->request, "get$what") - ); - } + /** + * RPC namespace + * + * @var string + */ + public $__namespace; + + /** + * HttpRequest instance + * + * @var HttpRequest + */ + public $__request; + + /** + * Client charset + * + * @var string + */ + public $__encoding = "iso-8859-1"; + + /** + * Constructor + * + * @param string $url RPC endpoint + * @param string $namespace RPC namespace + * @param array $options HttpRequest options + */ + public function __construct($url, $namespace = '', array $options = null) + { + $this->__request = new HttpRequest($url, HTTP_METH_POST); + $this->__request->setOptions($options); + $this->__namespace = $namespace; + } + + /** + * RPC method proxy + * + * @param string $method RPC method name + * @param array $params RPC method arguments + * @return mixed decoded RPC response + * @throws Exception + */ + public function __call($method, array $params) + { + if ($this->__namespace) { + $method = $this->__namespace .'.'. $method; + } + $this->__request->setContentType("text/xml; charset=". $this->__encoding); + $request = xmlrpc_encode_request($method, $params, array("encoding" => $this->__encoding)); + $this->__request->setRawPostData($request); + $this->__request->send(); + $response = $this->__request->getResponseMessage(); + if ($response->getResponseCode() != 200) { + throw new Exception( + $response->getResponseStatus(), + $response->getResponseCode() + ); + } + + $data = xmlrpc_decode($response->getBody(), $this->__encoding); + if (xmlrpc_is_fault($data)) { + throw new Exception( + (string) $data['faultString'], + (int) $data['faultCode'] + ); + } + + return $data; + } + + /** + * Returns self, where namespace is set to variable name + * + * @param string $ns + * @return XmlRpcRequest + */ + public function __get($ns) + { + $this->__namespace = $ns; + return $this; + } } ?> diff --git a/lib/XmlRpcServer.php b/lib/XmlRpcServer.php new file mode 100644 index 0000000..e77910f --- /dev/null +++ b/lib/XmlRpcServer.php @@ -0,0 +1,237 @@ + + * registerHandler(new Handler); + * XmlRpcServer::run(); + * } catch (Exception $ex) { + * XmlRpcServer::error($ex->getCode(), $ex->getMessage()); + * } + * + * + * @copyright Michael Wallner, + * @license BSD, revised + * @package pecl/http + * @version $Revision$ + */ + +class XmlRpcServer extends HttpResponse +{ + /** + * Server charset + * + * @var string + */ + public static $encoding = "iso-8859-1"; + + /** + * RPC namespace + * + * @var string + */ + public $namespace; + + /** + * RPC handler attached to this server instance + * + * @var XmlRpcRequestHandler + */ + protected $handler; + + private static $xmlreq; + private static $xmlrpc; + private static $refcnt = 0; + private static $handle = array(); + + /** + * Create a new XmlRpcServer instance + * + * @param string $namespace + * @param string $encoding + */ + public function __construct($namespace) { + $this->namespace = $namespace; + self::initialize(); + } + + /** + * Destructor + */ + public function __destruct() { + if (self::$refcnt && !--self::$refcnt) { + xmlrpc_server_destroy(self::$xmlrpc); + } + } + + /** + * Static factory + * + * @param string $namespace + * @return XmlRpcServer + */ + public static function factory($namespace) { + return new XmlRpcServer($namespace); + } + + /** + * Run all servers and send response + * + * @param array $options + */ + public static function run(array $options = null) { + self::initialize(false, true); + HttpResponse::setContentType("text/xml; charset=". self::$encoding); + echo xmlrpc_server_call_method(self::$xmlrpc, self::$xmlreq, null, + array("encoding" => self::$encoding) + (array) $options); + } + + /** + * Test hook; call instead of XmlRpcServer::run() + * + * @param string $method + * @param array $params + * @param array $options + */ + public static function test($method, array $params, array $options = null) { + self::$xmlreq = xmlrpc_encode_request($method, $params); + self::run(); + } + + /** + * Optional XMLRPC error handler + * + * @param int $code + * @param string $msg + */ + public static function error($code, $msg) { + echo xmlrpc_encode(array("faultCode" => $code, "faultString" => $msg)); + } + + /** + * Register a single method + * + * @param string $name + * @param mixed $callback + * @param mixed $dispatch + * @param array $spec + */ + public function registerMethod($name, $callback, $dispatch = null, array $spec = null) { + if (!is_callable($callback, false, $cb_name)) { + throw new Exception("$cb_name is not a valid callback"); + } + if (isset($dispatch)) { + if (!is_callable($dispatch, false, $cb_name)) { + throw new Exception("$cb_name is not a valid callback"); + } + xmlrpc_server_register_method(self::$xmlrpc, $name, $dispatch); + self::$handle[$name] = $callback; + } else { + xmlrpc_server_register_method(self::$xmlrpc, $name, $callback); + } + + if (isset($spec)) { + xmlrpc_server_add_introspection_data(self::$xmlrpc, $spec); + } + } + + /** + * Register an XmlRpcRequestHandler for this server instance + * + * @param XmlRpcRequestHandler $handler + */ + public function registerHandler(XmlRpcRequestHandler $handler) { + $this->handler = $handler; + + foreach (get_class_methods($handler) as $method) { + if (!strncmp($method, "xmlrpc", 6)) { + $this->registerMethod( + $this->method($method, $handler->getNamespace()), + array($handler, $method), array($this, "dispatch")); + } + } + + $handler->getIntrospectionData($spec); + if (is_array($spec)) { + xmlrpc_server_add_introspection_data(self::$xmlrpc, $spec); + } + } + + private function method($method, $namespace = null) { + if (!strlen($namespace)) { + $namespace = strlen($this->namespace) ? $this->namespace : "xmlrpc"; + } + return $namespace .".". strtolower($method[6]) . substr($method, 7); + } + + private function dispatch($method, array $params = null) { + if (array_key_exists($method, self::$handle)) { + return call_user_func(self::$handle[$method], $params); + } + throw new Exception("Unknown XMLRPC method: $method"); + } + + private static function initialize($server = true, $data = false) { + if ($data) { + if (!self::$xmlreq && !(self::$xmlreq = http_get_request_body())) { + throw new Exception("Failed to fetch XMLRPC request body"); + } + } + if ($server) { + if (!self::$xmlrpc && !(self::$xmlrpc = xmlrpc_server_create())) { + throw new Exception("Failed to initialize XMLRPC server"); + } + ++self::$refcnt; + } + } +} + +/** + * XmlRpcRequestHandler + * + * Define XMLRPC methods with an "xmlrpc" prefix, eg: + * + * class IntOp implements XmlRpcRequestHandler { + * public function getNamespace() { + * return "int"; + * } + * public function getInstrospectionData(array &$spec = null) { + * } + * // XMLRPC method name: int.sumValues + * public function xmlrpcSumValues(array $values) { + * return array_sum($values); + * } + * } + * + */ +interface XmlRpcRequestHandler { + public function getNamespace(); + public function getIntrospectionData(array &$spec = null); +} + +/** + * XmlRpcRequestHandlerStub + */ +abstract class XmlRpcRequestHandlerStub implements XmlRpcRequestHandler { + public function getNamespace() { + } + public function getIntrospectionData(array &$spec = null) { + } +} + +?> diff --git a/php_http.h b/php_http.h index ab53b85..f3574d3 100644 --- a/php_http.h +++ b/php_http.h @@ -144,6 +144,8 @@ ZEND_EXTERN_MODULE_GLOBALS(http); # define HTTP_G (&http_globals) #endif +#define HTTP_SHARED_EXT(EXT) (COMPILE_DL_##EXT && !HTTP_SHARED_DEPS) + PHP_FUNCTION(http_test); PHP_FUNCTION(http_date); PHP_FUNCTION(http_build_url); diff --git a/php_http_cache_api.h b/php_http_cache_api.h index 6efe1d8..dbbe0a2 100644 --- a/php_http_cache_api.h +++ b/php_http_cache_api.h @@ -20,14 +20,16 @@ #include "ext/standard/crc32.h" #include "ext/standard/sha1.h" #include "ext/standard/md5.h" -#if defined(HTTP_HAVE_EXT_HASH) -# include "php_hash.h" -#elif defined(HTTP_HAVE_HASH_EXT_HASH) -# define HTTP_HAVE_EXT_HASH -# include "hash/php_hash.h" -#elif defined(HTTP_HAVE_EXT_HASH_EXT_HASH) -# define HTTP_HAVE_EXT_HASH -# include "ext/hash/php_hash.h" +#if !HTTP_SHARED_EXT(HASH) +# if defined(HTTP_HAVE_EXT_HASH) +# include "php_hash.h" +# elif defined(HTTP_HAVE_HASH_EXT_HASH) +# define HTTP_HAVE_EXT_HASH +# include "hash/php_hash.h" +# elif defined(HTTP_HAVE_EXT_HASH_EXT_HASH) +# define HTTP_HAVE_EXT_HASH +# include "ext/hash/php_hash.h" +# endif #endif #define http_etag_digest(d, l) _http_etag_digest((d), (l)) @@ -53,7 +55,7 @@ static inline void *_http_etag_init(TSRMLS_D) void *ctx = NULL; char *mode = HTTP_G->etag.mode; -#ifdef HTTP_HAVE_EXT_HASH +#if defined(HTTP_HAVE_EXT_HASH) && !HTTP_SHARED_EXT(HASH) php_hash_ops *eho = NULL; if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { @@ -79,7 +81,7 @@ static inline char *_http_etag_finish(void *ctx TSRMLS_DC) unsigned char digest[128] = {0}; char *etag = NULL, *mode = HTTP_G->etag.mode; -#ifdef HTTP_HAVE_EXT_HASH +#if defined(HTTP_HAVE_EXT_HASH) && !HTTP_SHARED_EXT(HASH) php_hash_ops *eho = NULL; if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { @@ -106,7 +108,7 @@ static inline char *_http_etag_finish(void *ctx TSRMLS_DC) static inline void _http_etag_update(void *ctx, const char *data_ptr, size_t data_len TSRMLS_DC) { char *mode = HTTP_G->etag.mode; -#ifdef HTTP_HAVE_EXT_HASH +#if defined(HTTP_HAVE_EXT_HASH) && !HTTP_SHARED_EXT(HASH) php_hash_ops *eho = NULL; if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) { diff --git a/php_http_querystring_api.h b/php_http_querystring_api.h index ed86920..d5be364 100644 --- a/php_http_querystring_api.h +++ b/php_http_querystring_api.h @@ -15,7 +15,7 @@ #ifndef PHP_HTTP_QUERYSTRING_API_H #define PHP_HTTP_QUERYSTRING_API_H -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) #define http_querystring_xlate(a, p, ie, oe) _http_querystring_xlate((a), (p), (ie), (oe) TSRMLS_CC) PHP_HTTP_API int _http_querystring_xlate(zval *array, zval *param, const char *ie, const char *oe TSRMLS_DC); #endif diff --git a/php_http_querystring_object.h b/php_http_querystring_object.h index 0b77c3d..4a60d12 100644 --- a/php_http_querystring_object.h +++ b/php_http_querystring_object.h @@ -50,7 +50,7 @@ PHP_METHOD(HttpQueryString, getFloat); PHP_METHOD(HttpQueryString, getString); PHP_METHOD(HttpQueryString, getArray); PHP_METHOD(HttpQueryString, getObject); -#ifdef HAVE_ICONV +#ifdef HAVE_ICONV && !HTTP_SHARED_EXT(ICONV) PHP_METHOD(HttpQueryString, xlate); #endif #ifndef WONKY -- 2.30.2