#include "php_http_url_api.h"
#include "php_http_request_body_api.h"
+/* {{{ */
+typedef struct curl_httppost *post_data[2];
+static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC);
+static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC);
+/* }}} */
+
/* {{{ http_request_body *http_request_body_new() */
PHP_HTTP_API http_request_body *_http_request_body_init_ex(http_request_body *body, int type, void *data, size_t size, zend_bool free ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
{
PHP_HTTP_API http_request_body *_http_request_body_fill(http_request_body *body, HashTable *fields, HashTable *files ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC TSRMLS_DC)
{
if (files && (zend_hash_num_elements(files) > 0)) {
- HashKey key = initHashKey(0);
- zval **data_ptr;
- HashPosition pos;
struct curl_httppost *http_post_data[2] = {NULL, NULL};
- /* normal data */
- if (fields) {
- FOREACH_HASH_KEYVAL(pos, fields, key, data_ptr) {
- if (key.type == HASH_KEY_IS_STRING) {
- CURLcode err;
- zval *data = http_zsep(IS_STRING, *data_ptr);
-
- err = curl_formadd(&http_post_data[0], &http_post_data[1],
- CURLFORM_COPYNAME, key.str,
- CURLFORM_COPYCONTENTS, Z_STRVAL_P(data),
- CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_P(data),
- CURLFORM_END
- );
-
- 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]);
- return NULL;
- }
- }
- }
+ if (fields && SUCCESS != recursive_fields(http_post_data, fields, NULL TSRMLS_CC)) {
+ return NULL;
}
-
- /* file data */
- FOREACH_HASH_VAL(pos, files, data_ptr) {
- zval **file_ptr, **type_ptr, **name_ptr;
-
- if (Z_TYPE_PP(data_ptr) != 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_ptr), "name", sizeof("name"), (void *) &name_ptr) ||
- SUCCESS != zend_hash_find(Z_ARRVAL_PP(data_ptr), "type", sizeof("type"), (void *) &type_ptr) ||
- SUCCESS != zend_hash_find(Z_ARRVAL_PP(data_ptr), "file", sizeof("file"), (void *) &file_ptr)) {
- http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Post file array entry misses either 'name', 'type' or 'file' entry");
- } else {
- CURLcode err;
- const char *path;
- zval *file = http_zsep(IS_STRING, *file_ptr);
- zval *type = http_zsep(IS_STRING, *type_ptr);
- zval *name = http_zsep(IS_STRING, *name_ptr);
-
- HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(file), curl_formfree(http_post_data[0]); return NULL);
-
- /* this is blatant but should be sufficient for most cases */
- if (strncasecmp(Z_STRVAL_P(file), "file://", lenof("file://"))) {
- path = Z_STRVAL_P(file);
- } else {
- path = Z_STRVAL_P(file) + lenof("file://");
- }
-
- err = curl_formadd(&http_post_data[0], &http_post_data[1],
- CURLFORM_COPYNAME, Z_STRVAL_P(name),
- CURLFORM_FILE, path,
- CURLFORM_CONTENTTYPE, Z_STRVAL_P(type),
- CURLFORM_END
- );
-
- zval_ptr_dtor(&file);
- zval_ptr_dtor(&type);
- zval_ptr_dtor(&name);
-
- if (CURLE_OK != err) {
- http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
- curl_formfree(http_post_data[0]);
- return NULL;
- }
- }
+ if (SUCCESS != recursive_files(http_post_data, files, NULL TSRMLS_CC)) {
+ return NULL;
}
-
return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CURLPOST, http_post_data[0], 0, 1);
-
} else if (fields) {
char *encoded;
size_t encoded_len;
}
/* }}} */
+static inline char *format_key(uint type, char *str, ulong num, const char *prefix, int numeric_key_for_empty_prefix) {
+ char *new_key = NULL;
+
+ if (prefix && *prefix) {
+ if (type == HASH_KEY_IS_STRING) {
+ spprintf(&new_key, 0, "%s[%s]", prefix, str);
+ } else {
+ spprintf(&new_key, 0, "%s[%lu]", prefix, num);
+ }
+ } else if (type == HASH_KEY_IS_STRING) {
+ new_key = estrdup(str);
+ } else if (numeric_key_for_empty_prefix) {
+ spprintf(&new_key, 0, "%lu", num);
+ }
+
+ return new_key;
+}
+
+/* {{{ static STATUS recursive_fields(post_data d, HashTable *f, const char *p TSRMLS_DC) */
+static STATUS recursive_fields(post_data http_post_data, HashTable *fields, const char *prefix TSRMLS_DC) {
+ HashKey key = initHashKey(0);
+ zval **data_ptr;
+ HashPosition pos;
+ char *new_key = NULL;
+ CURLcode err = 0;
+
+ if (fields && !fields->nApplyCount) {
+ FOREACH_HASH_KEYVAL(pos, fields, key, data_ptr) {
+ if (key.type != HASH_KEY_IS_STRING || *key.str) {
+ new_key = format_key(key.type, key.str, key.num, prefix, 1);
+
+ switch (Z_TYPE_PP(data_ptr)) {
+ case IS_ARRAY:
+ case IS_OBJECT: {
+ STATUS status;
+
+ ++fields->nApplyCount;
+ status = recursive_fields(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
+ --fields->nApplyCount;
+
+ if (SUCCESS != status) {
+ goto error;
+ }
+ break;
+ }
+
+ default: {
+ zval *data = http_zsep(IS_STRING, *data_ptr);
+
+ err = curl_formadd(&http_post_data[0], &http_post_data[1],
+ CURLFORM_COPYNAME, new_key,
+ CURLFORM_COPYCONTENTS, Z_STRVAL_P(data),
+ CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_P(data),
+ CURLFORM_END
+ );
+
+ zval_ptr_dtor(&data);
+
+ if (CURLE_OK != err) {
+ goto error;
+ }
+ break;
+ }
+ }
+ STR_FREE(new_key);
+ }
+ }
+ }
+
+ return SUCCESS;
+
+error:
+ if (new_key) {
+ efree(new_key);
+ }
+ if (http_post_data[0]) {
+ curl_formfree(http_post_data[0]);
+ }
+ if (err) {
+ http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
+ } else {
+ http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: unknown error");
+ }
+ return FAILURE;
+}
+/* }}} */
+
+/* {{{ static STATUS recursive_files(post_data d, HashTable *f, const char *p TSRMLS_DC) */
+static STATUS recursive_files(post_data http_post_data, HashTable *files, const char *prefix TSRMLS_DC) {
+ HashKey key = initHashKey(0);
+ zval **data_ptr;
+ HashPosition pos;
+ char *new_key = NULL;
+ CURLcode err = 0;
+
+ if (files && !files->nApplyCount) {
+ FOREACH_HASH_KEYVAL(pos, files, key, data_ptr) {
+ zval **file_ptr, **type_ptr, **name_ptr;
+
+ if (key.type != HASH_KEY_IS_STRING || *key.str) {
+ new_key = format_key(key.type, key.str, key.num, prefix, 0);
+
+ if (Z_TYPE_PP(data_ptr) != IS_ARRAY && Z_TYPE_PP(data_ptr) != IS_OBJECT) {
+ if (new_key || key.type == HASH_KEY_IS_STRING) {
+ http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%s'", new_key ? new_key : key.str);
+ } else {
+ http_error_ex(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry '%lu'", key.num);
+ }
+ } else if ( SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "name", sizeof("name"), (void *) &name_ptr) ||
+ SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "type", sizeof("type"), (void *) &type_ptr) ||
+ SUCCESS != zend_hash_find(HASH_OF(*data_ptr), "file", sizeof("file"), (void *) &file_ptr)) {
+ STATUS status;
+
+ ++files->nApplyCount;
+ status = recursive_files(http_post_data, HASH_OF(*data_ptr), new_key TSRMLS_CC);
+ --files->nApplyCount;
+
+ if (SUCCESS != status) {
+ goto error;
+ }
+ } else {
+ const char *path;
+ zval *file = http_zsep(IS_STRING, *file_ptr);
+ zval *type = http_zsep(IS_STRING, *type_ptr);
+ zval *name = http_zsep(IS_STRING, *name_ptr);
+
+ HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(file), goto error);
+
+ /* this is blatant but should be sufficient for most cases */
+ if (strncasecmp(Z_STRVAL_P(file), "file://", lenof("file://"))) {
+ path = Z_STRVAL_P(file);
+ } else {
+ path = Z_STRVAL_P(file) + lenof("file://");
+ }
+
+ if (new_key) {
+ char *tmp_key = format_key(HASH_KEY_IS_STRING, Z_STRVAL_P(name), 0, new_key, 0);
+ STR_SET(new_key, tmp_key);
+ }
+
+ err = curl_formadd(&http_post_data[0], &http_post_data[1],
+ CURLFORM_COPYNAME, new_key ? new_key : Z_STRVAL_P(name),
+ CURLFORM_FILE, path,
+ CURLFORM_CONTENTTYPE, Z_STRVAL_P(type),
+ CURLFORM_END
+ );
+
+ zval_ptr_dtor(&file);
+ zval_ptr_dtor(&type);
+ zval_ptr_dtor(&name);
+
+ if (CURLE_OK != err) {
+ goto error;
+ }
+ }
+ STR_FREE(new_key);
+ }
+ }
+ }
+
+ return SUCCESS;
+
+error:
+ if (new_key) {
+ efree(new_key);
+ }
+ if (http_post_data[0]) {
+ curl_formfree(http_post_data[0]);
+ }
+ if (err) {
+ http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
+ } else {
+ http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: unknown error");
+ }
+ return FAILURE;
+}
+/* }}} */
+
#endif /* HTTP_HAVE_CURL */
/*