- FOREACH macros now require a HashPosition argument
authorMichael Wallner <mike@php.net>
Tue, 8 Nov 2005 10:03:14 +0000 (10:03 +0000)
committerMichael Wallner <mike@php.net>
Tue, 8 Nov 2005 10:03:14 +0000 (10:03 +0000)
12 files changed:
http.c
http_functions.c
http_headers_api.c
http_message_api.c
http_request_api.c
http_request_method_api.c
http_request_object.c
http_response_object.c
http_send_api.c
http_url_api.c
php_http.h
php_http_std_defs.h

diff --git a/http.c b/http.c
index 859e21c0c522794a0b144db21f1fd8b0b23f66c7..888a1cf0c487533a6b25bafa43c0fdee6aa247c5 100644 (file)
--- a/http.c
+++ b/http.c
@@ -429,6 +429,7 @@ PHP_MINFO_FUNCTION(http)
        php_info_print_table_colspan_header(2, "Request Methods");
        {
                unsigned i;
+               HashPosition pos;
                zval **custom_method;
                phpstr *known_request_methods = phpstr_new();
                phpstr *custom_request_methods = phpstr_new();
@@ -437,7 +438,7 @@ PHP_MINFO_FUNCTION(http)
                        phpstr_appendl(known_request_methods, http_request_method_name(i));
                        phpstr_appends(known_request_methods, ", ");
                }
-               FOREACH_HASH_VAL(&HTTP_G(request).methods.custom, custom_method) {
+               FOREACH_HASH_VAL(pos, &HTTP_G(request).methods.custom, custom_method) {
                        phpstr_append(custom_request_methods, Z_STRVAL_PP(custom_method), Z_STRLEN_PP(custom_method));
                        phpstr_appends(custom_request_methods, ", ");
                }
index 469dd946d6227d886625c455220796982d3fa24a..de673a724061383a2ad7eb52812dcb38169185e7 100644 (file)
@@ -137,9 +137,10 @@ PHP_FUNCTION(http_build_uri)
                } \
                \
                if (rs_array) { \
+                       HashPosition pos; \
                        zval **value; \
                         \
-                       FOREACH_VAL(supported, value) { \
+                       FOREACH_VAL(pos, supported, value) { \
                                convert_to_string_ex(value); \
                                add_assoc_double(rs_array, Z_STRVAL_PP(value), 1.0); \
                        } \
index 9decaad38309af56bc910e0aff3587b01c62b3db..0be9b2c018c763b2a6ad002d780ba64ce696174a 100644 (file)
@@ -69,9 +69,10 @@ static int http_sort_q(const void *a, const void *b TSRMLS_DC)
 char *_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
 {
        zval **value;
+       HashPosition pos;
        const char *dash_test;
        
-       FOREACH_HASH_VAL(supported, value) {
+       FOREACH_HASH_VAL(pos, supported, value) {
 #if HTTP_DBG_NEG
                fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
 #endif
@@ -82,7 +83,7 @@ char *_http_negotiate_language_func(const char *test, double *quality, HashTable
        
        /* no distinct match found, so try primaries */
        if (dash_test = strchr(test, '-')) {
-               FOREACH_HASH_VAL(supported, value) {
+               FOREACH_HASH_VAL(pos, supported, value) {
                        int len = dash_test - test;
 #if HTTP_DBG_NEG
                        fprintf(stderr, "strncascmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len);
@@ -104,8 +105,9 @@ char *_http_negotiate_language_func(const char *test, double *quality, HashTable
 char *_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
 {
        zval **value;
+       HashPosition pos;
        
-       FOREACH_HASH_VAL(supported, value) {
+       FOREACH_HASH_VAL(pos, supported, value) {
 #if HTTP_DBG_NEG
                fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
 #endif
@@ -144,12 +146,13 @@ PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *support
                
                if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) {
                        int i = 0;
+                       HashPosition pos;
                        zval **entry, array;
                        
                        INIT_PZVAL(&array);
                        array_init(&array);
                        
-                       FOREACH_HASH_VAL(Z_ARRVAL(ex_arr), entry) {
+                       FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) {
                                double quality;
                                char *selected, *identifier;
                                const char *separator;
@@ -431,11 +434,12 @@ PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool pre
        char *key = NULL;
        ulong idx = 0;
        zval array, **hsv;
+       HashPosition pos;
 
        Z_ARRVAL(array) = headers;
 
        if (SUCCESS == zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &hsv)) {
-               FOREACH_KEY(*hsv, key, idx) {
+               FOREACH_KEY(pos, *hsv, key, idx) {
                        if (key && !strncmp(key, "HTTP_", 5)) {
                                zval **header;
        
@@ -444,7 +448,7 @@ PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool pre
                                        key = pretty_key(key, strlen(key), 1, 1);
                                }
        
-                               zend_hash_get_current_data(Z_ARRVAL_PP(hsv), (void **) &header);
+                               zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv), (void **) &header, &pos);
                                add_assoc_stringl(&array, key, Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
                                key = NULL;
                        }
@@ -460,16 +464,17 @@ PHP_HTTP_API zend_bool _http_match_request_header_ex(const char *header, const c
        ulong idx;
        zend_bool result = 0;
        HashTable headers;
+       HashPosition pos;
 
        name = pretty_key(estrdup(header), strlen(header), 1, 1);
        zend_hash_init(&headers, 0, NULL, ZVAL_PTR_DTOR, 0);
        http_get_request_headers_ex(&headers, 1);
 
-       FOREACH_HASH_KEY(&headers, key, idx) {
+       FOREACH_HASH_KEY(pos, &headers, key, idx) {
                if (key && (!strcmp(key, name))) {
                        zval **data;
 
-                       if (SUCCESS == zend_hash_get_current_data(&headers, (void **) &data)) {
+                       if (SUCCESS == zend_hash_get_current_data_ex(&headers, (void **) &data, &pos)) {
                                result = (match_case ? strcmp(Z_STRVAL_PP(data), value) : strcasecmp(Z_STRVAL_PP(data), value)) ? 0 : 1;
                        }
                        break;
index 7fe5aecb73d6a7f96aa8188a7c004e1b058f1d0c..fdb0812bf480110edbe593dfdff6b3c102e579a5 100644 (file)
@@ -305,6 +305,7 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_
        char *key, *data;
        ulong idx;
        zval **header;
+       HashPosition pos1;
 
        phpstr_init_ex(&str, 4096, 0);
 
@@ -330,7 +331,7 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_
                break;
        }
 
-       FOREACH_HASH_KEYVAL(&msg->hdrs, key, idx, header) {
+       FOREACH_HASH_KEYVAL(pos1, &msg->hdrs, key, idx, header) {
                if (key) {
                        zval **single_header;
 
@@ -341,9 +342,12 @@ PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_
                                break;
 
                                case IS_ARRAY:
-                                       FOREACH_VAL(*header, single_header) {
+                               {
+                                       HashPosition pos2;
+                                       FOREACH_VAL(pos2, *header, single_header) {
                                                phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(single_header));
                                        }
+                               }
                                break;
                        }
 
@@ -443,14 +447,16 @@ PHP_HTTP_API STATUS _http_message_send(http_message *message TSRMLS_DC)
                        char *key;
                        ulong idx;
                        zval **val;
+                       HashPosition pos1;
 
-                       FOREACH_HASH_KEYVAL(&message->hdrs, key, idx, val) {
+                       FOREACH_HASH_KEYVAL(pos1, &message->hdrs, key, idx, val) {
                                if (key) {
                                        if (Z_TYPE_PP(val) == IS_ARRAY) {
                                                zend_bool first = 1;
                                                zval **data;
+                                               HashPosition pos2;
                                                
-                                               FOREACH_VAL(*val, data) {
+                                               FOREACH_VAL(pos2, *val, data) {
                                                        http_send_header_ex(key, strlen(key), Z_STRVAL_PP(data), Z_STRLEN_PP(data), first, NULL);
                                                        first = 0;
                                                }
index 5214a77c401f025e4bad8bc3a893f2915b082dfb..b92cbfe88b761d874cf3279979758c8f5ca98e5a 100644 (file)
@@ -277,12 +277,15 @@ PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *
                char *key = NULL;
                ulong idx;
                zval **data;
+               HashPosition pos;
                struct curl_httppost *http_post_data[2] = {NULL, NULL};
 
                /* normal data */
-               FOREACH_HASH_KEYVAL(fields, key, idx, data) {
+               FOREACH_HASH_KEYVAL(pos, fields, key, idx, data) {
                        CURLcode err;
                        if (key) {
+                               zval *orig = *data;
+                               
                                convert_to_string_ex(data);
                                err = curl_formadd(&http_post_data[0], &http_post_data[1],
                                        CURLFORM_COPYNAME,                      key,
@@ -290,6 +293,11 @@ PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *
                                        CURLFORM_CONTENTSLENGTH,        (long) Z_STRLEN_PP(data),
                                        CURLFORM_END
                                );
+                               
+                               if (orig != *data) {
+                                       zval_ptr_dtor(data);
+                               }
+                               
                                if (CURLE_OK != err) {
                                        http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
                                        curl_formfree(http_post_data[0]);
@@ -302,12 +310,14 @@ PHP_HTTP_API STATUS _http_request_body_fill(http_request_body *body, HashTable *
                }
 
                /* file data */
-               FOREACH_HASH_VAL(files, data) {
+               FOREACH_HASH_VAL(pos, files, data) {
                        zval **file, **type, **name;
                        
-                       if (    SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) ||
-                                       SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) ||
-                                       SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)) {
+                       if (Z_TYPE_PP(data) != IS_ARRAY) {
+                               http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry");
+                       } else if (     SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void **) &name) ||
+                                               SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void **) &type) ||
+                                               SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void **) &file)) {
                                http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Post file array entry misses either 'name', 'type' or 'file' entry");
                        } else {
                                CURLcode err = curl_formadd(&http_post_data[0], &http_post_data[1],
@@ -493,12 +503,13 @@ PHP_HTTP_API STATUS _http_request_init(CURL *ch, http_request_method meth, char
        if (zoption = http_curl_getopt(options, "headers", IS_ARRAY)) {
                char *header_key;
                ulong header_idx;
+               HashPosition pos;
                struct curl_slist *headers = NULL;
 
-               FOREACH_KEY(zoption, header_key, header_idx) {
+               FOREACH_KEY(pos, zoption, header_key, header_idx) {
                        if (header_key) {
                                zval **header_val;
-                               if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void **) &header_val)) {
+                               if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(zoption), (void **) &header_val, &pos)) {
                                        char header[1024] = {0};
                                        snprintf(header, 1023, "%s: %s", header_key, Z_STRVAL_PP(header_val));
                                        headers = curl_slist_append(headers, http_request_data_copy(COPY_STRING, header));
@@ -518,12 +529,13 @@ PHP_HTTP_API STATUS _http_request_init(CURL *ch, http_request_method meth, char
        if (zoption = http_curl_getopt(options, "cookies", IS_ARRAY)) {
                char *cookie_key = NULL;
                ulong cookie_idx = 0;
+               HashPosition pos;
                phpstr *qstr = phpstr_new();
 
-               FOREACH_KEY(zoption, cookie_key, cookie_idx) {
+               FOREACH_KEY(pos, zoption, cookie_key, cookie_idx) {
                        if (cookie_key) {
                                zval **cookie_val;
-                               if (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(zoption), (void **) &cookie_val)) {
+                               if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_P(zoption), (void **) &cookie_val, &pos)) {
                                        phpstr_appendf(qstr, "%s=%s; ", cookie_key, Z_STRVAL_PP(cookie_val));
                                }
 
@@ -596,8 +608,9 @@ PHP_HTTP_API STATUS _http_request_init(CURL *ch, http_request_method meth, char
                ulong idx;
                char *key = NULL;
                zval **param;
+               HashPosition pos;
 
-               FOREACH_KEYVAL(zoption, key, idx, param) {
+               FOREACH_KEYVAL(pos, zoption, key, idx, param) {
                        if (key) {
                                HTTP_CURL_OPT_SSL_STRING(CERT);
 #if LIBCURL_VERSION_NUM >= 0x070903
index be19f492ce9832609e4028e9c83a8724d2283862..873d5b1df14341aa74432b2399bb688c04d74751 100644 (file)
@@ -148,8 +148,9 @@ PHP_HTTP_API ulong _http_request_method_exists(zend_bool by_name, ulong id, cons
                        zval **data;
                        char *key;
                        ulong idx;
+                       HashPosition pos;
 
-                       FOREACH_HASH_KEYVAL(&HTTP_G(request).methods.custom, key, idx, data) {
+                       FOREACH_HASH_KEYVAL(pos, &HTTP_G(request).methods.custom, key, idx, data) {
                                if (!strcmp(name, Z_STRVAL_PP(data))) {
                                        return idx + HTTP_MAX_REQUEST_METHOD;
                                }
index fbddcc6ec8e470e5f5254b19fe70d91f9ae86db2..73d3718394848ecf3f4ff50aae370110dd86e0a9 100644 (file)
@@ -778,6 +778,7 @@ PHP_METHOD(HttpRequest, setOptions)
 {
        char *key = NULL;
        ulong idx = 0;
+       HashPosition pos;
        zval *opts = NULL, *old_opts, **opt;
        getObject(http_request_object, obj);
 
@@ -795,7 +796,7 @@ PHP_METHOD(HttpRequest, setOptions)
        }
        
        /* some options need extra attention -- thus cannot use array_merge() directly */
-       FOREACH_KEYVAL(opts, key, idx, opt) {
+       FOREACH_KEYVAL(pos, opts, key, idx, opt) {
                if (key) {
                        if (!strcmp(key, "headers")) {
                                zval **headers;
@@ -1664,15 +1665,17 @@ PHP_METHOD(HttpRequest, getResponseCookie)
                        ulong idx = 0;
                        char *key = NULL;
                        zval **header = NULL;
+                       HashPosition pos1;
 
-                       convert_to_array_ex(headers);
-                       FOREACH_HASH_KEYVAL(Z_ARRVAL_PP(headers), key, idx, header) {
+                       convert_to_array(*headers);
+                       FOREACH_HASH_KEYVAL(pos1, Z_ARRVAL_PP(headers), key, idx, header) {
                                if (key && !strcasecmp(key, "Set-Cookie")) {
                                        /* several cookies? */
                                        if (Z_TYPE_PP(header) == IS_ARRAY) {
                                                zval **cookie;
+                                               HashPosition pos2;
 
-                                               FOREACH_HASH_VAL(Z_ARRVAL_PP(header), cookie) {
+                                               FOREACH_HASH_VAL(pos2, Z_ARRVAL_PP(header), cookie) {
                                                        zval *cookie_hash;
                                                        MAKE_STD_ZVAL(cookie_hash);
                                                        array_init(cookie_hash);
index ec67afccb141571fbb58489f61bad99538cbfe9c..2a0cbbd0aaad9db54ec57e4591e469abaf681171 100644 (file)
@@ -293,7 +293,7 @@ PHP_METHOD(HttpResponse, setHeader)
        zend_bool replace = 1;
        char *name;
        int name_len = 0;
-       zval *value = NULL;
+       zval *value = NULL, *orig = NULL;
 
        if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/!|b", &name, &name_len, &value, &replace)) {
                RETURN_FALSE;
@@ -314,20 +314,31 @@ PHP_METHOD(HttpResponse, setHeader)
        /* send multiple header if replace is false and value is an array */
        if (!replace && Z_TYPE_P(value) == IS_ARRAY) {
                zval **data;
+               HashPosition pos;
                
-               FOREACH_VAL(value, data) {
+               FOREACH_VAL(pos, value, data) {
+                       zval *orig = *data;
+                       
                        convert_to_string_ex(data);
                        if (SUCCESS != http_send_header_ex(name, name_len, Z_STRVAL_PP(data), Z_STRLEN_PP(data), 0, NULL)) {
+                               if (orig != *data) {
+                                       zval_ptr_dtor(data);
+                               }
                                RETURN_FALSE;
                        }
+                       if (orig != *data) {
+                               zval_ptr_dtor(data);
+                       }
                }
                RETURN_TRUE;
        }
        /* send standard header */
-       if (Z_TYPE_P(value) != IS_STRING) {
-               convert_to_string_ex(&value);
+       orig = value;
+       convert_to_string_ex(&value);
+       RETVAL_SUCCESS(http_send_header_ex(name, name_len, Z_STRVAL_P(value), Z_STRLEN_P(value), replace, NULL));
+       if (orig != value) {
+               zval_ptr_dtor(&value);
        }
-       RETURN_SUCCESS(http_send_header_ex(name, name_len, Z_STRVAL_P(value), Z_STRLEN_P(value), replace, NULL));
 }
 /* }}} */
 
index 6ab4a2f2f3e1010267d6df019c830188b72d2a2e..e5a66ced540e669c4721df541e0c631ad56e13c0 100644 (file)
@@ -348,6 +348,7 @@ PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_s
                                        }
                                } else {
                                        /* multi range */
+                                       HashPosition pos;
                                        zval **range, **begin, **end;
                                        const char *content_type = HTTP_G(send).content_type;
                                        char boundary_str[32], range_header_str[256];
@@ -363,7 +364,7 @@ PHP_HTTP_API STATUS _http_send_ex(const void *data_ptr, size_t data_size, http_s
                                                content_type = "application/x-octetstream";
                                        }
                                        
-                                       FOREACH_HASH_VAL(&ranges, range) {
+                                       FOREACH_HASH_VAL(pos, &ranges, range) {
                                                if (    SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(range), 0, (void **) &begin) &&
                                                                SUCCESS == zend_hash_index_find(Z_ARRVAL_PP(range), 1, (void **) &end)) {
                                                        char preface_str[512];
index aa0c1f37c835692631866bd1083565604c39a6d6..dd7066085d514e010937b7b88d5fa5d1b67f21bb 100644 (file)
@@ -214,6 +214,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c
        uint len = 0;
        ulong idx = 0;
        zval **data = NULL;
+       HashPosition pos;
 
        if (!ht || !str) {
                http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
@@ -223,7 +224,7 @@ PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, c
                return SUCCESS;
        }
        
-       FOREACH_HASH_KEYLENVAL(ht, key, len, idx, data) {
+       FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) {
                char *encoded_key;
                int encoded_len;
                phpstr new_prefix;
index 56c3a9afc8c85ceaaa6f0e8e0ade5e9753bb2a86..33198fad8e8a287e01ee1a254acf253111e63050 100644 (file)
@@ -34,9 +34,6 @@ extern int http_module_number;
 
 ZEND_BEGIN_MODULE_GLOBALS(http)
 
-#ifdef ZEND_ENGINE_2
-       zend_bool only_exceptions;
-#endif
        struct _http_globals_etag {
                long mode;
                void *ctx;
@@ -78,6 +75,10 @@ ZEND_BEGIN_MODULE_GLOBALS(http)
 #endif /* HTTP_HAVE_CURL */
        } request;
 
+#ifdef ZEND_ENGINE_2
+       zend_bool only_exceptions;
+#endif
+
 ZEND_END_MODULE_GLOBALS(http)
 
 #ifdef ZTS
index b5a5377e524fe19337736382a4876b5a2f8c0d44..558a8ec8d5b53a6fe0e2c02e28d29597ad08fb76 100644 (file)
@@ -129,31 +129,31 @@ typedef int STATUS;
        STD_PHP_INI_ENTRY_EX(entry, default, scope, updater, global, zend_http_globals, http_globals, displayer)
 
 /* {{{ arrays */
-#define FOREACH_VAL(array, val) FOREACH_HASH_VAL(Z_ARRVAL_P(array), val)
-#define FOREACH_HASH_VAL(hash, val) \
-       for (   zend_hash_internal_pointer_reset(hash); \
-                       zend_hash_get_current_data(hash, (void **) &val) == SUCCESS; \
-                       zend_hash_move_forward(hash))
-
-#define FOREACH_KEY(array, strkey, numkey) FOREACH_HASH_KEY(Z_ARRVAL_P(array), strkey, numkey)
-#define FOREACH_HASH_KEY(hash, strkey, numkey) \
-       for (   zend_hash_internal_pointer_reset(hash); \
-                       zend_hash_get_current_key(hash, &strkey, &numkey, 0) != HASH_KEY_NON_EXISTANT; \
-                       zend_hash_move_forward(hash)) \
-
-#define FOREACH_KEYVAL(array, strkey, numkey, val) FOREACH_HASH_KEYVAL(Z_ARRVAL_P(array), strkey, numkey, val)
-#define FOREACH_HASH_KEYVAL(hash, strkey, numkey, val) \
-       for (   zend_hash_internal_pointer_reset(hash); \
-                       zend_hash_get_current_key(hash, &strkey, &numkey, 0) != HASH_KEY_NON_EXISTANT && \
-                       zend_hash_get_current_data(hash, (void **) &val) == SUCCESS; \
-                       zend_hash_move_forward(hash))
-
-#define FOREACH_KEYLENVAL(array, strkey, keylen, numkey, val) FOREACH_HASH_KEYVAL(Z_ARRVAL_P(array), strkey, keylen, numkey, val)
-#define FOREACH_HASH_KEYLENVAL(hash, strkey, keylen, numkey, val) \
-       for (   zend_hash_internal_pointer_reset(hash); \
-                       zend_hash_get_current_key_ex(hash, &strkey, &keylen, &numkey, 0, NULL) != HASH_KEY_NON_EXISTANT && \
-                       zend_hash_get_current_data(hash, (void **) &val) == SUCCESS; \
-                       zend_hash_move_forward(hash))
+#define FOREACH_VAL(pos, array, val) FOREACH_HASH_VAL(pos, Z_ARRVAL_P(array), val)
+#define FOREACH_HASH_VAL(pos, hash, val) \
+       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
+                       zend_hash_get_current_data_ex(hash, (void **) &val, &pos) == SUCCESS; \
+                       zend_hash_move_forward_ex(hash, &pos))
+
+#define FOREACH_KEY(pos, array, strkey, numkey) FOREACH_HASH_KEY(pos, Z_ARRVAL_P(array), strkey, numkey)
+#define FOREACH_HASH_KEY(pos, hash, strkey, numkey) \
+       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
+                       zend_hash_get_current_key_ex(hash, &strkey, NULL, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT; \
+                       zend_hash_move_forward_ex(hash, &pos)) \
+
+#define FOREACH_KEYVAL(pos, array, strkey, numkey, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), strkey, numkey, val)
+#define FOREACH_HASH_KEYVAL(pos, hash, strkey, numkey, val) \
+       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
+                       zend_hash_get_current_key_ex(hash, &strkey, NULL, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT && \
+                       zend_hash_get_current_data_ex(hash, (void **) &val, &pos) == SUCCESS; \
+                       zend_hash_move_forward_ex(hash, &pos))
+
+#define FOREACH_KEYLENVAL(pos, array, strkey, keylen, numkey, val) FOREACH_HASH_KEYVAL(pos, Z_ARRVAL_P(array), strkey, keylen, numkey, val)
+#define FOREACH_HASH_KEYLENVAL(pos, hash, strkey, keylen, numkey, val) \
+       for (   zend_hash_internal_pointer_reset_ex(hash, &pos); \
+                       zend_hash_get_current_key_ex(hash, &strkey, &keylen, &numkey, 0, &pos) != HASH_KEY_NON_EXISTANT && \
+                       zend_hash_get_current_data_ex(hash, (void **) &val, &pos) == SUCCESS; \
+                       zend_hash_move_forward_ex(hash, &pos))
 
 #define array_copy(src, dst)   zend_hash_copy(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *))
 #define array_merge(src, dst)  zend_hash_merge(Z_ARRVAL_P(dst), Z_ARRVAL_P(src), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *), 1)
@@ -163,11 +163,12 @@ typedef int STATUS;
                uint klen; \
                char *key = NULL; \
                zval **data; \
+               HashPosition pos; \
                 \
-               for (   zend_hash_internal_pointer_reset(Z_ARRVAL_P(src)); \
-                               zend_hash_get_current_key_ex(Z_ARRVAL_P(src), &key, &klen, &idx, 0, NULL) != HASH_KEY_NON_EXISTANT && \
-                               zend_hash_get_current_data(Z_ARRVAL_P(src), (void **) &data) == SUCCESS; \
-                               zend_hash_move_forward(Z_ARRVAL_P(src))) \
+               for (   zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(src), &pos); \
+                               zend_hash_get_current_key_ex(Z_ARRVAL_P(src), &key, &klen, &idx, 0, &pos) != HASH_KEY_NON_EXISTANT && \
+                               zend_hash_get_current_data_ex(Z_ARRVAL_P(src), (void **) &data, &pos) == SUCCESS; \
+                               zend_hash_move_forward_ex(Z_ARRVAL_P(src), &pos)) \
                { \
                        if (key) { \
                                zval **tmp; \