diff options
Diffstat (limited to '474.patch')
-rw-r--r-- | 474.patch | 1402 |
1 files changed, 1402 insertions, 0 deletions
diff --git a/474.patch b/474.patch new file mode 100644 index 0000000..6f109e6 --- /dev/null +++ b/474.patch @@ -0,0 +1,1402 @@ +From 2096982a8022527e2820ab9cc78a238cc07f4289 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Tue, 19 Jan 2021 16:16:30 +0100 +Subject: [PATCH 01/16] fix MemcachedServer + +related: #418, m6w6/libmemcached#94 +--- + php_memcached.c | 3 ++ + php_memcached_server.c | 80 +++++++++++++++++++++++------------ + server-example/run-server.php | 2 +- + 3 files changed, 56 insertions(+), 29 deletions(-) + +diff --git a/php_memcached.c b/php_memcached.c +index 1e218a00..adf2348d 100644 +--- a/php_memcached.c ++++ b/php_memcached.c +@@ -3502,6 +3502,8 @@ static + void php_memc_server_free_storage(zend_object *object) + { + php_memc_server_t *intern = php_memc_server_fetch_object(object); ++ ++ php_memc_proto_handler_destroy(&intern->handler); + zend_object_std_dtor(&intern->zo); + } + +@@ -3515,6 +3517,7 @@ zend_object *php_memc_server_new(zend_class_entry *ce) + object_properties_init(&intern->zo, ce); + + intern->zo.handlers = &memcached_server_object_handlers; ++ intern->handler = php_memc_proto_handler_new(); + + return &intern->zo; + } +diff --git a/php_memcached_server.c b/php_memcached_server.c +index 870209c1..e816b90d 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -17,13 +17,16 @@ + #include "php_memcached.h" + #include "php_memcached_private.h" + #include "php_memcached_server.h" ++#include "php_network.h" + + #include <event2/listener.h> + +-#undef NDEBUG +-#undef _NDEBUG + #include <assert.h> + ++#if HAVE_ARPA_INET_H ++# include <arpa/inet.h> ++#endif ++ + #define MEMC_GET_CB(cb_type) (MEMC_SERVER_G(callbacks)[cb_type]) + #define MEMC_HAS_CB(cb_type) (MEMC_GET_CB(cb_type).fci.size > 0) + +@@ -58,9 +61,9 @@ typedef struct { + static + long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t param_count) + { +- zval *retval = NULL; ++ zval retval; + +- cb->fci.retval = retval; ++ cb->fci.retval = &retval; + cb->fci.params = params; + cb->fci.param_count = param_count; + #if PHP_VERSION_ID < 80000 +@@ -73,7 +76,7 @@ long s_invoke_php_callback (php_memc_server_cb_t *cb, zval *params, ssize_t para + efree (buf); + } + +- return retval == NULL ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(retval); ++ return Z_ISUNDEF(retval) ? PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND : zval_get_long(&retval); + } + + // memcached protocol callbacks +@@ -96,6 +99,7 @@ protocol_binary_response_status s_add_handler(const void *cookie, const void *ke + ZVAL_LONG(&zflags, flags); + ZVAL_LONG(&zexptime, exptime); + ZVAL_NULL(&zresult_cas); ++ ZVAL_MAKE_REF(&zresult_cas); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +@@ -142,6 +146,7 @@ protocol_binary_response_status s_append_prepend_handler (php_memc_event_t event + ZVAL_STRINGL(&zvalue, data, data_len); + ZVAL_DOUBLE(&zcas, cas); + ZVAL_NULL(&zresult_cas); ++ ZVAL_MAKE_REF(&zresult_cas); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +@@ -198,11 +203,13 @@ protocol_binary_response_status s_incr_decr_handler (php_memc_event_t event, con + MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + + ZVAL_STRINGL(&zkey, key, key_len); +- ZVAL_LONG(&zdelta, (long) delta); +- ZVAL_LONG(&zinital, (long) initial); +- ZVAL_LONG(&zexpiration, (long) expiration); ++ ZVAL_LONG(&zdelta, (zend_long) delta); ++ ZVAL_LONG(&zinital, (zend_long) initial); ++ ZVAL_LONG(&zexpiration, (zend_long) expiration); + ZVAL_LONG(&zresult, 0); ++ ZVAL_MAKE_REF(&zresult); + ZVAL_NULL(&zresult_cas); ++ ZVAL_MAKE_REF(&zresult_cas); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +@@ -322,6 +329,13 @@ protocol_binary_response_status s_get_handler (const void *cookie, const void *k + } + + MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ++ ZVAL_STRINGL(&zkey, key, key_len); ++ ZVAL_NULL(&zvalue); ++ ZVAL_MAKE_REF(&zvalue); ++ ZVAL_NULL(&zflags); ++ ZVAL_MAKE_REF(&zflags); ++ ZVAL_NULL(&zresult_cas); ++ ZVAL_MAKE_REF(&zresult_cas); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +@@ -436,11 +450,12 @@ protocol_binary_response_status s_set_replace_handler (php_memc_event_t event, c + MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + + ZVAL_STRINGL(&zkey, key, key_len); +- ZVAL_STRINGL(&zdata, ((char *) data), (int) data_len); +- ZVAL_LONG(&zflags, (long) flags); +- ZVAL_LONG(&zexpiration, (long) expiration); ++ ZVAL_STRINGL(&zdata, data, data_len); ++ ZVAL_LONG(&zflags, (zend_long) flags); ++ ZVAL_LONG(&zexpiration, (zend_long) expiration); + ZVAL_DOUBLE(&zcas, (double) cas); + ZVAL_NULL(&zresult_cas); ++ ZVAL_MAKE_REF(&zresult_cas); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +@@ -504,6 +519,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + + ZVAL_STRINGL(&zkey, key, key_len); + ZVAL_NULL(&zbody); ++ ZVAL_MAKE_REF(&zbody); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +@@ -584,17 +600,27 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) + zval zremoteip, zremoteport; + zval params[2]; + protocol_binary_response_status retval; +- +- struct sockaddr_in addr_in; +- socklen_t addr_in_len = sizeof(addr_in); +- +- if (getpeername (fd, (struct sockaddr *) &addr_in, &addr_in_len) == 0) { +- ZVAL_STRING(&zremoteip, inet_ntoa (addr_in.sin_addr)); +- ZVAL_LONG(&zremoteport, ntohs (addr_in.sin_port)); ++ struct sockaddr_storage ss; ++ socklen_t ss_len = sizeof(ss); ++ ++ ZVAL_NULL(&zremoteip); ++ ZVAL_NULL(&zremoteport); ++ ++ if (getpeername (fd, (struct sockaddr *) &ss, &ss_len) == 0) { ++ char addr_buf[0x100]; ++ ++ switch (ss.ss_family) { ++ case AF_INET6: ++ ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in6 *) &ss)->sin6_addr, addr_buf, sizeof(addr_buf))); ++ ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in6 *) &ss)->sin6_port)); ++ break; ++ case AF_INET: ++ ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in *) &ss)->sin_addr, addr_buf, sizeof(addr_buf))); ++ ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in *) &ss)->sin_port)); ++ break; ++ } + } else { + php_error_docref(NULL, E_WARNING, "getpeername failed: %s", strerror (errno)); +- ZVAL_NULL(&zremoteip); +- ZVAL_NULL(&zremoteport); + } + + ZVAL_COPY(¶ms[0], &zremoteip); +@@ -714,22 +740,20 @@ php_memc_proto_handler_t *php_memc_proto_handler_new () + } + + static +-evutil_socket_t s_create_listening_socket (const char *spec) ++evutil_socket_t s_create_listening_socket (const zend_string *spec) + { + evutil_socket_t sock; + struct sockaddr_storage addr; +- int addr_len; +- ++ socklen_t addr_len; + int rc; + + addr_len = sizeof (struct sockaddr); +- rc = evutil_parse_sockaddr_port (spec, (struct sockaddr *) &addr, &addr_len); +- if (rc != 0) { +- php_error_docref(NULL, E_WARNING, "Failed to parse bind address"); ++ if (SUCCESS != php_network_parse_network_address_with_port(spec->val, spec->len, (struct sockaddr *) &addr, &addr_len)) { ++ php_error_docref(NULL, E_WARNING, "Failed to parse bind address: %s", spec->val); + return -1; + } + +- sock = socket (AF_INET, SOCK_STREAM, 0); ++ sock = socket (addr.ss_family, SOCK_STREAM, 0); + if (sock < 0) { + php_error_docref(NULL, E_WARNING, "socket failed: %s", strerror (errno)); + return -1; +@@ -770,7 +794,7 @@ evutil_socket_t s_create_listening_socket (const char *spec) + zend_bool php_memc_proto_handler_run (php_memc_proto_handler_t *handler, zend_string *address) + { + struct event *accept_event; +- evutil_socket_t sock = s_create_listening_socket (address->val); ++ evutil_socket_t sock = s_create_listening_socket (address); + + if (sock == -1) { + return 0; +From 277ce3b20ec9753b994d63f4e99c2506ca2cdd5f Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Tue, 19 Jan 2021 16:32:52 +0100 +Subject: [PATCH 02/16] use php_network_get_peer_name + +--- + php_memcached_server.c | 38 ++++++++++------------------------- + server-example/run-server.php | 4 ++-- + 2 files changed, 13 insertions(+), 29 deletions(-) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index e816b90d..fee8d28d 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -597,41 +597,25 @@ void s_handle_memcached_event (evutil_socket_t fd, short what, void *arg) + + if (!client->on_connect_invoked) { + if (MEMC_HAS_CB(MEMC_SERVER_ON_CONNECT)) { +- zval zremoteip, zremoteport; +- zval params[2]; ++ zend_string *zremoteaddr_str; ++ zval zremoteaddr; ++ zval params[1]; + protocol_binary_response_status retval; +- struct sockaddr_storage ss; +- socklen_t ss_len = sizeof(ss); +- +- ZVAL_NULL(&zremoteip); +- ZVAL_NULL(&zremoteport); +- +- if (getpeername (fd, (struct sockaddr *) &ss, &ss_len) == 0) { +- char addr_buf[0x100]; +- +- switch (ss.ss_family) { +- case AF_INET6: +- ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in6 *) &ss)->sin6_addr, addr_buf, sizeof(addr_buf))); +- ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in6 *) &ss)->sin6_port)); +- break; +- case AF_INET: +- ZVAL_STRING(&zremoteip, inet_ntop(ss.ss_family, &((struct sockaddr_in *) &ss)->sin_addr, addr_buf, sizeof(addr_buf))); +- ZVAL_LONG(&zremoteport, ntohs(((struct sockaddr_in *) &ss)->sin_port)); +- break; +- } ++ ++ ZVAL_NULL(&zremoteaddr); ++ ++ if (SUCCESS == php_network_get_peer_name (fd, &zremoteaddr_str, NULL, NULL)) { ++ ZVAL_STR(&zremoteaddr, zremoteaddr_str); + } else { + php_error_docref(NULL, E_WARNING, "getpeername failed: %s", strerror (errno)); + } + +- ZVAL_COPY(¶ms[0], &zremoteip); +- ZVAL_COPY(¶ms[1], &zremoteport); ++ ZVAL_COPY(¶ms[0], &zremoteaddr); + +- retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 2); ++ retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_CONNECT), params, 1); + + zval_ptr_dtor(¶ms[0]); +- zval_ptr_dtor(¶ms[1]); +- zval_ptr_dtor(&zremoteip); +- zval_ptr_dtor(&zremoteport); ++ zval_ptr_dtor(&zremoteaddr); + + if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { + memcached_protocol_client_destroy (client->protocol_client); +From f7731bfe65c9f9312e11018035e7a560e7dde702 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Tue, 19 Jan 2021 16:34:08 +0100 +Subject: [PATCH 03/16] remove unused include again + +--- + php_memcached_server.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index fee8d28d..ce93a2bf 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -23,10 +23,6 @@ + + #include <assert.h> + +-#if HAVE_ARPA_INET_H +-# include <arpa/inet.h> +-#endif +- + #define MEMC_GET_CB(cb_type) (MEMC_SERVER_G(callbacks)[cb_type]) + #define MEMC_HAS_CB(cb_type) (MEMC_GET_CB(cb_type).fci.size > 0) + + +From c7a2084ac958e93a094866889b56a7b37698ef40 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Tue, 19 Jan 2021 16:57:39 +0100 +Subject: [PATCH 04/16] as per + https://github.com/php-memcached-dev/php-memcached/pull/474#issuecomment-762934191 + +--- + php_memcached_server.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index ce93a2bf..1f28d936 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -299,6 +299,7 @@ protocol_binary_response_status s_flush_handler(const void *cookie, uint32_t whe + } + + MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); ++ ZVAL_LONG(&zwhen, when); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zwhen); + +From 09d0f27b6298e525e0bae45db8d915fa1d140466 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 20 Jan 2021 10:54:13 +0100 +Subject: [PATCH 05/16] add 1 test for MemcachedServer + +--- + tests/memcachedserver.phpt | 58 +++++++++++++++++++++++ + tests/server.inc | 78 +++++++++++++++++++++++++++++++ + tests/server.php | 94 ++++++++++++++++++++++++++++++++++++++ + 3 files changed, 230 insertions(+) + create mode 100644 tests/memcachedserver.phpt + create mode 100644 tests/server.inc + create mode 100644 tests/server.php + +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +new file mode 100644 +index 00000000..54b7fe45 +--- /dev/null ++++ b/tests/memcachedserver.phpt +@@ -0,0 +1,58 @@ ++--TEST-- ++Memcached::get() with cache callback ++--SKIPIF-- ++<?php ++if (!extension_loaded("memcached")) { ++ die("skip memcached is not loaded\n"); ++} ++?> ++--FILE-- ++<?php ++include __DIR__ . '/server.inc'; ++$server = memcached_server_start(); ++ ++$cache = new Memcached(); ++$cache->setOption(Memcached::OPT_BINARY_PROTOCOL, true); ++$cache->setOption(Memcached::OPT_COMPRESSION, false); ++$cache->addServer('127.0.0.1', 3434); ++ ++$cache->add("add_key", "hello", 500); ++$cache->append("append_key", "world"); ++$cache->prepend("prepend_key", "world"); ++ ++$cache->increment("incr", 2, 1, 500); ++$cache->decrement("decr", 2, 1, 500); ++ ++$cache->delete("delete_k"); ++$cache->flush(1); ++ ++var_dump($cache->get('get_this')); ++ ++$cache->set ('set_key', 'value 1', 100); ++$cache->replace ('replace_key', 'value 2', 200); ++ ++var_dump($cache->getStats()); ++ ++$cache->quit(); ++ ++memcached_server_stop($server); ++?> ++Done ++--EXPECTF-- ++Listening on 127.0.0.1:3434 ++Incoming connection from 127.0.0.1:%s ++Incoming connection from 127.0.0.1:%s ++client_id=[%s]: Add key=[add_key], value=[hello], flags=[0], expiration=[500] ++client_id=[%s]: Append key=[append_key], value=[world], cas=[0] ++client_id=[%s]: Prepend key=[prepend_key], value=[world], cas=[0] ++client_id=[%s]: Incrementing key=[incr], delta=[2], initial=[1], expiration=[500] ++client_id=[%s]: Decrementing key=[decr], delta=[2], initial=[1], expiration=[500] ++client_id=[%s]: Delete key=[delete_k], cas=[0] ++client_id=[%s]: Flush when=[1] ++client_id=[%s]: Get key=[get_this] ++client_id=[%s]: Noop ++string(20) "Hello to you client!" ++client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] ++client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] ++bool(false) ++Done +diff --git a/tests/server.inc b/tests/server.inc +new file mode 100644 +index 00000000..96cc942f +--- /dev/null ++++ b/tests/server.inc +@@ -0,0 +1,78 @@ ++<?php ++function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port = 3434) { ++ $php_executable = getenv('TEST_PHP_EXECUTABLE') ?? PHP_BINARY; ++ $php_args = getenv('TEST_PHP_ARGS') ?? ''; ++ ++ $descriptorspec = array( ++ 0 => STDIN, ++ 1 => STDOUT, ++ 2 => STDERR, ++ ); ++ ++ $cmd = "{$php_executable} {$php_args} {$code} {$host}:{$port} "; ++ if (substr(PHP_OS, 0, 3) == 'WIN') { ++ $cmd = "{$php_executable} {$php_args} {$code} {$host}:{$port} "; ++ ++ $handle = proc_open(addslashes($cmd), $descriptorspec, $pipes, __DIR__, NULL, array("bypass_shell" => true, "suppress_errors" => true)); ++ } else { ++ $cmd = "exec {$cmd} 2>/dev/null"; ++ ++ $handle = proc_open($cmd, $descriptorspec, $pipes, __DIR__); ++ } ++ ++ // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.' ++ // it might not be listening yet...need to wait until fsockopen() call returns ++ $error = "Unable to connect to server\n"; ++ for ($i=0; $i < 60; $i++) { ++ usleep(50000); // 50ms per try ++ $status = proc_get_status($handle); ++ $fp = @fsockopen($host, $port); ++ // Failure, the server is no longer running ++ if (!($status && $status['running'])) { ++ $error = "Server is not running\n"; ++ break; ++ } ++ // Success, Connected to servers ++ if ($fp) { ++ $error = ''; ++ break; ++ } ++ } ++ ++ if ($fp) { ++ fclose($fp); ++ } ++ ++ if ($error) { ++ echo $error; ++ proc_terminate($handle); ++ exit(1); ++ } ++ ++ register_shutdown_function( ++ function($handle) { ++ proc_terminate($handle); ++ }, ++ $handle ++ ); ++ ++ return $handle; ++} ++ ++function memcached_server_stop($handle) { ++ $success = FALSE; ++ if ($handle) { ++ proc_terminate($handle); ++ /* Wait for server to shutdown */ ++ for ($i = 0; $i < 60; $i++) { ++ $status = proc_get_status($handle); ++ if (!($status && $status['running'])) { ++ $success = TRUE; ++ break; ++ } ++ usleep(50000); ++ } ++ } ++ return $success; ++} ++ +diff --git a/tests/server.php b/tests/server.php +new file mode 100644 +index 00000000..674f91ac +--- /dev/null ++++ b/tests/server.php +@@ -0,0 +1,94 @@ ++<?php ++ ++$server = new MemcachedServer(); ++ ++$server->on (Memcached::ON_CONNECT, ++ function ($remote_addr) { ++ echo "Incoming connection from {$remote_addr}" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_ADD, ++ function ($client_id, $key, $value, $flags, $expiration, &$cas) { ++ echo "client_id=[$client_id]: Add key=[$key], value=[$value], flags=[$flags], expiration=[$expiration]" . PHP_EOL; ++ $cas = 15; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_APPEND, ++ function ($client_id, $key, $value, $cas, &$result_cas) { ++ echo "client_id=[$client_id]: Append key=[$key], value=[$value], cas=[$cas]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_PREPEND, ++ function ($client_id, $key, $value, $cas, &$result_cas) { ++ echo "client_id=[$client_id]: Prepend key=[$key], value=[$value], cas=[$cas]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_INCREMENT, ++ function ($client_id, $key, $delta, $initial, $expiration, &$result, &$result_cas) { ++ echo "client_id=[$client_id]: Incrementing key=[$key], delta=[$delta], initial=[$initial], expiration=[$expiration]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_DECREMENT, ++ function ($client_id, $key, $delta, $initial, $expiration, &$result, &$result_cas) { ++ echo "client_id=[$client_id]: Decrementing key=[$key], delta=[$delta], initial=[$initial], expiration=[$expiration]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_DELETE, ++ function ($client_id, $key, $cas) { ++ echo "client_id=[$client_id]: Delete key=[$key], cas=[$cas]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_FLUSH, ++ function ($client_id, $when) { ++ echo "client_id=[$client_id]: Flush when=[$when]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_GET, ++ function ($client_id, $key, &$value, &$flags, &$cas) { ++ echo "client_id=[$client_id]: Get key=[$key]" . PHP_EOL; ++ $value = "Hello to you client!"; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_NOOP, ++ function ($client_id) { ++ echo "client_id=[$client_id]: Noop" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_REPLACE, ++ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { ++ echo "client_id=[$client_id]: Replace key=[$key], value=[$value], flags=[$flags], expiration=[$expiration], cas=[$cas]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_SET, ++ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { ++ echo "client_id=[$client_id]: Set key=[$key], value=[$value], flags=[$flags], expiration=[$expiration], cas=[$cas]" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_STAT, ++ function ($client_id, $key, &$value) { ++ echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; ++ $value = "Stat reply"; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_QUIT, ++ function ($client_id) { ++ echo "client_id=[$client_id]: Client quit" . PHP_EOL; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$addr = ($_SERVER['argv'][1] ?? "127.0.0.1:3434"); ++echo "Listening on $addr" . PHP_EOL; ++$server->run($addr); + +From 2b32140d08acb64bc087de37ea17c8ba2d99092a Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 20 Jan 2021 12:08:53 +0100 +Subject: [PATCH 06/16] minor fix for version handler + +--- + php_memcached_server.c | 1 + + tests/memcachedserver.phpt | 5 +++-- + tests/server.php | 7 +++++++ + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index 1f28d936..57cb749b 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -560,6 +560,7 @@ protocol_binary_response_status s_version_handler (const void *cookie, + MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + + ZVAL_NULL(&zversion); ++ ZVAL_MAKE_REF(&zversion); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zversion); +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index 54b7fe45..6d4abb9d 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -31,7 +31,8 @@ var_dump($cache->get('get_this')); + $cache->set ('set_key', 'value 1', 100); + $cache->replace ('replace_key', 'value 2', 200); + +-var_dump($cache->getStats()); ++// TODO var_dump($cache->getVersion()); ++// TODO var_dump($cache->getStats()); + + $cache->quit(); + +@@ -54,5 +55,5 @@ client_id=[%s]: Noop + string(20) "Hello to you client!" + client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] + client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] +-bool(false) ++client_id=[%s]: Client quit + Done +diff --git a/tests/server.php b/tests/server.php +index 674f91ac..c39b04e8 100644 +--- a/tests/server.php ++++ b/tests/server.php +@@ -79,6 +79,13 @@ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { + $server->on (Memcached::ON_STAT, + function ($client_id, $key, &$value) { + echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; ++ $value = "Stat reply for $key"; ++ return Memcached::RESPONSE_SUCCESS; ++ }); ++ ++$server->on (Memcached::ON_VERSION, ++ function ($client_id, &$value) { ++ echo "client_id=[$client_id]: Version" . PHP_EOL; + $value = "Stat reply"; + return Memcached::RESPONSE_SUCCESS; + }); + +From 7562317131d7ef75cf35abf982ca3efa44c5e495 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Wed, 20 Jan 2021 16:43:57 +0100 +Subject: [PATCH 07/16] handle empty STATS key + +--- + php_memcached_server.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index 57cb749b..d1e903a1 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -514,7 +514,11 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + + MEMC_MAKE_ZVAL_COOKIE(zcookie, cookie); + +- ZVAL_STRINGL(&zkey, key, key_len); ++ if (key && key_len) { ++ ZVAL_STRINGL(&zkey, key, key_len); ++ } else { ++ ZVAL_NULL(&zkey); ++ } + ZVAL_NULL(&zbody); + ZVAL_MAKE_REF(&zbody); + +@@ -566,7 +570,6 @@ protocol_binary_response_status s_version_handler (const void *cookie, + ZVAL_COPY(¶ms[1], &zversion); + + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_VERSION), params, 2); +- + if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { + if (Z_TYPE(zversion) != IS_STRING) { + convert_to_string(&zversion); + +From a3f9b928b65abc3daa743c709b6404e038b5af7b Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Wed, 20 Jan 2021 16:51:34 +0100 +Subject: [PATCH 08/16] fix running the server from command line + +--- + tests/server.inc | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/tests/server.inc b/tests/server.inc +index 96cc942f..5700a9d2 100644 +--- a/tests/server.inc ++++ b/tests/server.inc +@@ -1,7 +1,7 @@ + <?php + function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port = 3434) { +- $php_executable = getenv('TEST_PHP_EXECUTABLE') ?? PHP_BINARY; +- $php_args = getenv('TEST_PHP_ARGS') ?? ''; ++ $php_executable = getenv('TEST_PHP_EXECUTABLE') ?: PHP_BINARY; ++ $php_args = getenv('TEST_PHP_ARGS') ?: ''; + + $descriptorspec = array( + 0 => STDIN, +@@ -29,7 +29,7 @@ function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port + $fp = @fsockopen($host, $port); + // Failure, the server is no longer running + if (!($status && $status['running'])) { +- $error = "Server is not running\n"; ++ $error = "Server is not running {$status['command']}\n"; + break; + } + // Success, Connected to servers +@@ -75,4 +75,3 @@ function memcached_server_stop($handle) { + } + return $success; + } +- + +From c18e8bb36ff634f1dc9f6927fd98b1a20029f50f Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Wed, 20 Jan 2021 16:52:31 +0100 +Subject: [PATCH 09/16] add stats/version tests + +--- + tests/memcachedserver.phpt | 31 ++++++++++++++++++++++++++++--- + tests/server.php | 2 +- + 2 files changed, 29 insertions(+), 4 deletions(-) + +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index 6d4abb9d..82601e12 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -1,10 +1,13 @@ + --TEST-- +-Memcached::get() with cache callback ++MemcachedServer + --SKIPIF-- + <?php + if (!extension_loaded("memcached")) { + die("skip memcached is not loaded\n"); + } ++if (!class_exists("MemcachedServer")) { ++ die("skip memcached not built with libmemcachedprotocol support\n"); ++} + ?> + --FILE-- + <?php +@@ -31,8 +34,9 @@ var_dump($cache->get('get_this')); + $cache->set ('set_key', 'value 1', 100); + $cache->replace ('replace_key', 'value 2', 200); + +-// TODO var_dump($cache->getVersion()); +-// TODO var_dump($cache->getStats()); ++var_dump($cache->getVersion()); ++var_dump($cache->getStats()); ++var_dump($cache->getStats("foobar")); + + $cache->quit(); + +@@ -55,5 +59,26 @@ client_id=[%s]: Noop + string(20) "Hello to you client!" + client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] + client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] ++client_id=[%s]: Version ++array(1) { ++ ["127.0.0.1:3434"]=> ++ string(5) "1.1.1" ++} ++client_id=[%s]: Stat key=[] ++array(1) { ++ ["127.0.0.1:3434"]=> ++ array(1) { ++ [""]=> ++ string(15) "Stat reply for " ++ } ++} ++client_id=[%s]: Stat key=[foobar] ++array(1) { ++ ["127.0.0.1:3434"]=> ++ array(1) { ++ ["foobar"]=> ++ string(21) "Stat reply for foobar" ++ } ++} + client_id=[%s]: Client quit + Done +diff --git a/tests/server.php b/tests/server.php +index c39b04e8..b6ab1cf6 100644 +--- a/tests/server.php ++++ b/tests/server.php +@@ -86,7 +86,7 @@ function ($client_id, $key, &$value) { + $server->on (Memcached::ON_VERSION, + function ($client_id, &$value) { + echo "client_id=[$client_id]: Version" . PHP_EOL; +- $value = "Stat reply"; ++ $value = "1.1.1"; + return Memcached::RESPONSE_SUCCESS; + }); + + +From 4cb3b015e05018fccc17d4e40e065ab307e35f22 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Wed, 20 Jan 2021 17:42:58 +0100 +Subject: [PATCH 10/16] expect an array as STATS value and reply foreach + key/value + +--- + php_memcached_server.c | 36 +++++++++++++++++++++++++----------- + tests/memcachedserver.phpt | 16 ++++++++++------ + tests/server.php | 7 +++++-- + 3 files changed, 40 insertions(+), 19 deletions(-) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index d1e903a1..a166051e 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -506,7 +506,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + { + zval params[3]; + protocol_binary_response_status retval = PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND; +- zval zcookie, zkey, zbody; ++ zval zcookie, zkey, zstats; + + if (!MEMC_HAS_CB(MEMC_SERVER_ON_STAT)) { + return retval; +@@ -519,24 +519,38 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + } else { + ZVAL_NULL(&zkey); + } +- ZVAL_NULL(&zbody); +- ZVAL_MAKE_REF(&zbody); ++ ZVAL_NULL(&zstats); ++ ZVAL_MAKE_REF(&zstats); + + ZVAL_COPY(¶ms[0], &zcookie); + ZVAL_COPY(¶ms[1], &zkey); +- ZVAL_COPY(¶ms[2], &zbody); ++ ZVAL_COPY(¶ms[2], &zstats); + + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3); + + if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { +- if (Z_TYPE(zbody) == IS_NULL) { ++ if (Z_ISNULL(zstats)) { + retval = response_handler(cookie, NULL, 0, NULL, 0); +- } +- else { +- if (Z_TYPE(zbody) != IS_STRING) { +- convert_to_string(&zbody); ++ } else { ++ zval *zarray = &zstats; ++ zend_string *key; ++ zval *val; ++ ++ ZVAL_DEREF(zarray); ++ if (Z_TYPE_P(zarray) != IS_ARRAY) { ++ convert_to_array(zarray); ++ } ++ ++ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zarray), key, val) ++ { ++ zend_string *val_str = zval_get_string(val); ++ retval = response_handler(cookie, key->val, key->len, val_str->val, val_str->len); ++ if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { ++ break; ++ } ++ zend_string_release(val_str); + } +- retval = response_handler(cookie, key, key_len, Z_STRVAL(zbody), (uint32_t) Z_STRLEN(zbody)); ++ ZEND_HASH_FOREACH_END(); + } + } + +@@ -545,7 +559,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor (&zcookie); + zval_ptr_dtor (&zkey); +- zval_ptr_dtor (&zbody); ++ zval_ptr_dtor (&zstats); + return retval; + } + +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index 82601e12..d47dd73b 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -67,17 +67,21 @@ array(1) { + client_id=[%s]: Stat key=[] + array(1) { + ["127.0.0.1:3434"]=> +- array(1) { +- [""]=> +- string(15) "Stat reply for " ++ array(2) { ++ ["key"]=> ++ string(0) "" ++ ["foo"]=> ++ string(3) "bar" + } + } + client_id=[%s]: Stat key=[foobar] + array(1) { + ["127.0.0.1:3434"]=> +- array(1) { +- ["foobar"]=> +- string(21) "Stat reply for foobar" ++ array(2) { ++ ["key"]=> ++ string(6) "foobar" ++ ["foo"]=> ++ string(3) "bar" + } + } + client_id=[%s]: Client quit +diff --git a/tests/server.php b/tests/server.php +index b6ab1cf6..f5ff2f6a 100644 +--- a/tests/server.php ++++ b/tests/server.php +@@ -77,9 +77,12 @@ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { + }); + + $server->on (Memcached::ON_STAT, +- function ($client_id, $key, &$value) { ++ function ($client_id, $key, array &$values = null) { + echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; +- $value = "Stat reply for $key"; ++ $values = [ ++ "key" => $key, ++ "foo" => "bar", ++ ]; + return Memcached::RESPONSE_SUCCESS; + }); + + +From 3de2b4d7e27c61be0e4f0017b0b5528d0500b56c Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Wed, 20 Jan 2021 18:00:52 +0100 +Subject: [PATCH 11/16] valgrind + +--- + php_memcached.c | 5 ++++- + tests/server.inc | 9 +++++++-- + 2 files changed, 11 insertions(+), 3 deletions(-) + +diff --git a/php_memcached.c b/php_memcached.c +index adf2348d..8f464283 100644 +--- a/php_memcached.c ++++ b/php_memcached.c +@@ -3907,7 +3907,6 @@ static + PHP_GINIT_FUNCTION(php_memcached) + { + #ifdef HAVE_MEMCACHED_SESSION +- + php_memcached_globals->session.lock_enabled = 0; + php_memcached_globals->session.lock_wait_max = 150; + php_memcached_globals->session.lock_wait_min = 150; +@@ -3926,8 +3925,12 @@ PHP_GINIT_FUNCTION(php_memcached) + php_memcached_globals->session.persistent_enabled = 0; + php_memcached_globals->session.sasl_username = NULL; + php_memcached_globals->session.sasl_password = NULL; ++#endif + ++#ifdef HAVE_MEMCACHED_PROTOCOL ++ memset(&php_memcached_globals->server, 0, sizeof(php_memcached_globals->server)); + #endif ++ + php_memcached_globals->memc.serializer_name = NULL; + php_memcached_globals->memc.serializer_type = SERIALIZER_DEFAULT; + php_memcached_globals->memc.compression_name = NULL; +diff --git a/tests/server.inc b/tests/server.inc +index 5700a9d2..9678f043 100644 +--- a/tests/server.inc ++++ b/tests/server.inc +@@ -23,7 +23,7 @@ function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port + // note: even when server prints 'Listening on localhost:8964...Press Ctrl-C to quit.' + // it might not be listening yet...need to wait until fsockopen() call returns + $error = "Unable to connect to server\n"; +- for ($i=0; $i < 60; $i++) { ++ for ($i=0; $i < getenv("VALGRIND") ? 1000 : 60; $i++) { + usleep(50000); // 50ms per try + $status = proc_get_status($handle); + $fp = @fsockopen($host, $port); +@@ -46,12 +46,16 @@ function memcached_server_start($code = 'server.php', $host = "127.0.0.1", $port + if ($error) { + echo $error; + proc_terminate($handle); ++ proc_close($handle); + exit(1); + } + + register_shutdown_function( + function($handle) { +- proc_terminate($handle); ++ if (is_resource($handle)) { ++ proc_terminate($handle); ++ proc_close($handle); ++ } + }, + $handle + ); +@@ -72,6 +76,7 @@ function memcached_server_stop($handle) { + } + usleep(50000); + } ++ proc_close($handle); + } + return $success; + } + +From cebd8513bd1cb0a5a67642072cc4dad1907a2e5e Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Mon, 25 Jan 2021 14:45:03 +0100 +Subject: [PATCH 13/16] implement stats callback suggestions by Remi + +--- + php_memcached_server.c | 45 +++++++++++++++++++++----------------- + tests/memcachedserver.phpt | 22 +++++++++++++++++++ + tests/server.php | 19 ++++++++++------ + 3 files changed, 59 insertions(+), 27 deletions(-) + +diff --git a/php_memcached_server.c b/php_memcached_server.c +index a166051e..24c328f8 100644 +--- a/php_memcached_server.c ++++ b/php_memcached_server.c +@@ -519,7 +519,7 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + } else { + ZVAL_NULL(&zkey); + } +- ZVAL_NULL(&zstats); ++ array_init(&zstats); + ZVAL_MAKE_REF(&zstats); + + ZVAL_COPY(¶ms[0], &zcookie); +@@ -529,29 +529,34 @@ protocol_binary_response_status s_stat_handler (const void *cookie, const void * + retval = s_invoke_php_callback (&MEMC_GET_CB(MEMC_SERVER_ON_STAT), params, 3); + + if (retval == PROTOCOL_BINARY_RESPONSE_SUCCESS) { +- if (Z_ISNULL(zstats)) { +- retval = response_handler(cookie, NULL, 0, NULL, 0); +- } else { +- zval *zarray = &zstats; +- zend_string *key; +- zval *val; +- +- ZVAL_DEREF(zarray); +- if (Z_TYPE_P(zarray) != IS_ARRAY) { +- convert_to_array(zarray); +- } ++ zval *zarray = &zstats; ++ zend_string *key; ++ zend_long idx; ++ zval *val; ++ ++ ZVAL_DEREF(zarray); ++ if (Z_TYPE_P(zarray) != IS_ARRAY) { ++ convert_to_array(zarray); ++ } + +- ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(zarray), key, val) +- { +- zend_string *val_str = zval_get_string(val); ++ ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zarray), idx, key, val) ++ { ++ zend_string *val_str = zval_get_string(val); ++ ++ if (key) { + retval = response_handler(cookie, key->val, key->len, val_str->val, val_str->len); +- if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { +- break; +- } +- zend_string_release(val_str); ++ } else { ++ char buf[0x20], *ptr, *end = &buf[sizeof(buf) - 1]; ++ ptr = zend_print_long_to_buf(end, idx); ++ retval = response_handler(cookie, ptr, end - ptr, val_str->val, val_str->len); ++ } ++ zend_string_release(val_str); ++ ++ if (retval != PROTOCOL_BINARY_RESPONSE_SUCCESS) { ++ break; + } +- ZEND_HASH_FOREACH_END(); + } ++ ZEND_HASH_FOREACH_END(); + } + + zval_ptr_dtor(¶ms[0]); +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index d47dd73b..8d6bf222 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -37,6 +37,8 @@ $cache->replace ('replace_key', 'value 2', 200); + var_dump($cache->getVersion()); + var_dump($cache->getStats()); + var_dump($cache->getStats("foobar")); ++var_dump($cache->getStats("scalar")); ++var_dump($cache->getStats("numeric array")); + + $cache->quit(); + +@@ -84,5 +86,25 @@ array(1) { + string(3) "bar" + } + } ++client_id=[%s]: Stat key=[scalar] ++array(1) { ++ ["127.0.0.1:3434"]=> ++ array(1) { ++ [0]=> ++ string(%d) "you want it, you get it" ++ } ++} ++client_id=[%s]: Stat key=[numeric array] ++array(1) { ++ ["127.0.0.1:3434"]=> ++ array(3) { ++ [-1]=> ++ string(3) "one" ++ [0]=> ++ string(3) "two" ++ [1]=> ++ string(5) "three" ++ } ++} + client_id=[%s]: Client quit + Done +diff --git a/tests/server.php b/tests/server.php +index f5ff2f6a..bce4c0bf 100644 +--- a/tests/server.php ++++ b/tests/server.php +@@ -77,13 +77,18 @@ function ($client_id, $key, $value, $flags, $expiration, $cas, &$result_cas) { + }); + + $server->on (Memcached::ON_STAT, +- function ($client_id, $key, array &$values = null) { +- echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; +- $values = [ +- "key" => $key, +- "foo" => "bar", +- ]; +- return Memcached::RESPONSE_SUCCESS; ++ function ($client_id, $key, array &$values) { ++ echo "client_id=[$client_id]: Stat key=[$key]" . PHP_EOL; ++ ++ if ($key === "scalar") { ++ $values = "you want it, you get it"; ++ } elseif ($key === "numeric array") { ++ $values = [-1 => "one", "two", "three"]; ++ } else { ++ $values["key"] = $key; ++ $values["foo"] = "bar"; ++ } ++ return Memcached::RESPONSE_SUCCESS; + }); + + $server->on (Memcached::ON_VERSION, + +From af7ffcf0a11d653e427d3b2dacd4fdef1623daa6 Mon Sep 17 00:00:00 2001 +From: Michael Wallner <mike@php.net> +Date: Mon, 25 Jan 2021 14:54:24 +0100 +Subject: [PATCH 14/16] skip test with libmemcached < 1.1.0 + +--- + tests/memcachedserver.phpt | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index 8d6bf222..145acfba 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -8,6 +8,10 @@ if (!extension_loaded("memcached")) { + if (!class_exists("MemcachedServer")) { + die("skip memcached not built with libmemcachedprotocol support\n"); + } ++ ++if (Memcached::LIBMEMCACHED_VERSION_HEX < 0x1001000) { ++ die("skip needs at least libmemcached 1.1.0\n"); ++} + ?> + --FILE-- + <?php + +From 1134c661f092f4a54af73b30fa1d458ab4eca637 Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 26 Jan 2021 11:38:12 +0100 +Subject: [PATCH 15/16] add IPv6 test + +--- + tests/memcachedserver.phpt | 4 ++ + tests/memcachedserver6.phpt | 114 ++++++++++++++++++++++++++++++++++++ + tests/server.php | 2 + + 3 files changed, 120 insertions(+) + create mode 100644 tests/memcachedserver6.phpt + +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index 8d6bf222..c4fdd7c6 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -36,6 +36,7 @@ $cache->replace ('replace_key', 'value 2', 200); + + var_dump($cache->getVersion()); + var_dump($cache->getStats()); ++var_dump($cache->getStats("empty")); + var_dump($cache->getStats("foobar")); + var_dump($cache->getStats("scalar")); + var_dump($cache->getStats("numeric array")); +@@ -76,6 +77,9 @@ array(1) { + string(3) "bar" + } + } ++client_id=[%s]: Stat key=[empty] ++array(0) { ++} + client_id=[%s]: Stat key=[foobar] + array(1) { + ["127.0.0.1:3434"]=> +diff --git a/tests/memcachedserver6.phpt b/tests/memcachedserver6.phpt +new file mode 100644 +index 00000000..8ae0b362 +--- /dev/null ++++ b/tests/memcachedserver6.phpt +@@ -0,0 +1,114 @@ ++--TEST-- ++MemcachedServer ++--SKIPIF-- ++<?php ++if (!extension_loaded("memcached")) { ++ die("skip memcached is not loaded\n"); ++} ++if (!class_exists("MemcachedServer")) { ++ die("skip memcached not built with libmemcachedprotocol support\n"); ++} ++?> ++--FILE-- ++<?php ++include __DIR__ . '/server.inc'; ++$server = memcached_server_start('server.php', '[::1]', 3434); ++ ++$cache = new Memcached(); ++$cache->setOption(Memcached::OPT_BINARY_PROTOCOL, true); ++$cache->setOption(Memcached::OPT_COMPRESSION, false); ++$cache->addServer('[::1]', 3434); ++ ++$cache->add("add_key", "hello", 500); ++$cache->append("append_key", "world"); ++$cache->prepend("prepend_key", "world"); ++ ++$cache->increment("incr", 2, 1, 500); ++$cache->decrement("decr", 2, 1, 500); ++ ++$cache->delete("delete_k"); ++$cache->flush(1); ++ ++var_dump($cache->get('get_this')); ++ ++$cache->set ('set_key', 'value 1', 100); ++$cache->replace ('replace_key', 'value 2', 200); ++ ++var_dump($cache->getVersion()); ++var_dump($cache->getStats()); ++var_dump($cache->getStats("empty")); ++var_dump($cache->getStats("foobar")); ++var_dump($cache->getStats("scalar")); ++var_dump($cache->getStats("numeric array")); ++ ++$cache->quit(); ++ ++memcached_server_stop($server); ++?> ++Done ++--EXPECTF-- ++Listening on [::1]:3434 ++Incoming connection from [::1]:%s ++Incoming connection from [::1]:%s ++client_id=[%s]: Add key=[add_key], value=[hello], flags=[0], expiration=[500] ++client_id=[%s]: Append key=[append_key], value=[world], cas=[0] ++client_id=[%s]: Prepend key=[prepend_key], value=[world], cas=[0] ++client_id=[%s]: Incrementing key=[incr], delta=[2], initial=[1], expiration=[500] ++client_id=[%s]: Decrementing key=[decr], delta=[2], initial=[1], expiration=[500] ++client_id=[%s]: Delete key=[delete_k], cas=[0] ++client_id=[%s]: Flush when=[1] ++client_id=[%s]: Get key=[get_this] ++client_id=[%s]: Noop ++string(20) "Hello to you client!" ++client_id=[%s]: Set key=[set_key], value=[value 1], flags=[0], expiration=[100], cas=[0] ++client_id=[%s]: Replace key=[replace_key], value=[value 2], flags=[0], expiration=[200], cas=[0] ++client_id=[%s]: Version ++array(1) { ++ ["[::1]:3434"]=> ++ string(5) "1.1.1" ++} ++client_id=[%s]: Stat key=[] ++array(1) { ++ ["[::1]:3434"]=> ++ array(2) { ++ ["key"]=> ++ string(0) "" ++ ["foo"]=> ++ string(3) "bar" ++ } ++} ++client_id=[%s]: Stat key=[empty] ++array(0) { ++} ++client_id=[%s]: Stat key=[foobar] ++array(1) { ++ ["[::1]:3434"]=> ++ array(2) { ++ ["key"]=> ++ string(6) "foobar" ++ ["foo"]=> ++ string(3) "bar" ++ } ++} ++client_id=[%s]: Stat key=[scalar] ++array(1) { ++ ["[::1]:3434"]=> ++ array(1) { ++ [0]=> ++ string(%d) "you want it, you get it" ++ } ++} ++client_id=[%s]: Stat key=[numeric array] ++array(1) { ++ ["[::1]:3434"]=> ++ array(3) { ++ [-1]=> ++ string(3) "one" ++ [0]=> ++ string(3) "two" ++ [1]=> ++ string(5) "three" ++ } ++} ++client_id=[%s]: Client quit ++Done +diff --git a/tests/server.php b/tests/server.php +index bce4c0bf..9a50eb06 100644 +--- a/tests/server.php ++++ b/tests/server.php +@@ -84,6 +84,8 @@ function ($client_id, $key, array &$values) { + $values = "you want it, you get it"; + } elseif ($key === "numeric array") { + $values = [-1 => "one", "two", "three"]; ++ } elseif ($key === "empty") { ++ $values = []; + } else { + $values["key"] = $key; + $values["foo"] = "bar"; + +From abf4add8a1761a319e533197cf65b9b6abdc028a Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Tue, 26 Jan 2021 11:42:37 +0100 +Subject: [PATCH 16/16] small sleep to avoid loosing message from subprocess + +--- + tests/memcachedserver.phpt | 1 + + tests/memcachedserver6.phpt | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/tests/memcachedserver.phpt b/tests/memcachedserver.phpt +index c4fdd7c6..c46a4ccd 100644 +--- a/tests/memcachedserver.phpt ++++ b/tests/memcachedserver.phpt +@@ -42,6 +42,7 @@ var_dump($cache->getStats("scalar")); + var_dump($cache->getStats("numeric array")); + + $cache->quit(); ++usleep(50000); + + memcached_server_stop($server); + ?> +diff --git a/tests/memcachedserver6.phpt b/tests/memcachedserver6.phpt +index 8ae0b362..a2277b4a 100644 +--- a/tests/memcachedserver6.phpt ++++ b/tests/memcachedserver6.phpt +@@ -42,6 +42,7 @@ var_dump($cache->getStats("scalar")); + var_dump($cache->getStats("numeric array")); + + $cache->quit(); ++usleep(50000); + + memcached_server_stop($server); + ?> |