diff --git a/php_memcached.c b/php_memcached.c index c1bce93b..a1a47901 100644 --- a/php_memcached.c +++ b/php_memcached.c @@ -397,6 +397,21 @@ static int php_memc_list_entry(void) return le_memc; } +static int php_memc_valid_key(char *key) +{ + if (!*key) { + return 0; + } + + for ( ; *key; ++key) { + if (iscntrl(*key) || isspace(*key)) { + return 0; + } + } + + return 1; +} + /* {{{ Memcached::__construct([string persistent_id[, callback on_new[, string connection_str]]])) Creates a Memcached object, optionally using persistent memcache connection */ static PHP_METHOD(Memcached, __construct) @@ -576,7 +591,7 @@ static void php_memc_get_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key_len == 0 || !php_memc_valid_key(key)) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FROM_GET; } @@ -1448,7 +1463,7 @@ static void php_memc_store_impl(INTERNAL_FUNCTION_PARAMETERS, int op, zend_bool MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key_len == 0 || !php_memc_valid_key(key)) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1599,7 +1614,7 @@ static void php_memc_cas_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key_len == 0 || !php_memc_valid_key(key)) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1717,7 +1732,7 @@ static void php_memc_delete_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key) MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key_len == 0 || !php_memc_valid_key(key)) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -1817,7 +1832,7 @@ static void php_memc_incdec_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool by_key, MEMC_METHOD_FETCH_OBJECT; i_obj->rescode = MEMCACHED_SUCCESS; - if (key_len == 0 || strchr(key, ' ')) { + if (key_len == 0 || !php_memc_valid_key(key)) { i_obj->rescode = MEMCACHED_BAD_KEY_PROVIDED; RETURN_FALSE; } @@ -4483,6 +4498,7 @@ int php_memc_sess_list_entry(void) return le_memc_sess; } + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(memcached) { diff --git a/php_memcached_private.h b/php_memcached_private.h index 0ec2d76e..143d7753 100644 --- a/php_memcached_private.h +++ b/php_memcached_private.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -189,6 +190,7 @@ typedef struct { } memcached_sess; int php_memc_sess_list_entry(void); +int php_memc_valid_key(char *); char *php_memc_printable_func (zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC); diff --git a/tests/keys.phpt b/tests/keys.phpt index 0ed90896..ac5971a1 100644 --- a/tests/keys.phpt +++ b/tests/keys.phpt @@ -18,6 +18,14 @@ var_dump ($binary->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); var_dump ($ascii->set ('ascii key with spaces', 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); +var_dump ($ascii->set ('', 'this is a test')); +var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); + +for ($i=0;$i<32;$i++) { + var_dump ($ascii->set ('ascii key with non-printable char "' . chr($i) . '"newline', 'this is a test')); + var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); +} + var_dump ($ascii->set (str_repeat ('1234567890', 512), 'this is a test')); var_dump ($ascii->getResultCode () == Memcached::RES_BAD_KEY_PROVIDED); @@ -30,4 +38,70 @@ bool(false) bool(true) bool(false) bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) OK