2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #define HTTP_WANT_CURL
20 #include "php_http_api.h"
21 #include "php_http_url_api.h"
22 #include "php_http_request_body_api.h"
25 typedef struct curl_httppost
*post_data
[2];
26 static STATUS
recursive_fields(post_data http_post_data
, HashTable
*fields
, const char *prefix TSRMLS_DC
);
27 static STATUS
recursive_files(post_data http_post_data
, HashTable
*files
, const char *prefix TSRMLS_DC
);
30 /* {{{ http_request_body *http_request_body_new() */
31 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
)
34 body
= emalloc_rel(sizeof(http_request_body
));
47 /* {{{ http_request_body *http_request_body_fill(http_request_body *body, HashTable *, HashTable *) */
48 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
)
50 if (files
&& (zend_hash_num_elements(files
) > 0)) {
51 struct curl_httppost
*http_post_data
[2] = {NULL
, NULL
};
53 if (fields
&& SUCCESS
!= recursive_fields(http_post_data
, fields
, NULL TSRMLS_CC
)) {
56 if (SUCCESS
!= recursive_files(http_post_data
, files
, NULL TSRMLS_CC
)) {
59 return http_request_body_init_rel(body
, HTTP_REQUEST_BODY_CURLPOST
, http_post_data
[0], 0, 1);
64 if (SUCCESS
!= http_urlencode_hash_ex(fields
, 1, NULL
, 0, &encoded
, &encoded_len
)) {
65 http_error(HE_WARNING
, HTTP_E_ENCODING
, "Could not encode post data");
69 return http_request_body_init_rel(body
, HTTP_REQUEST_BODY_CSTRING
, encoded
, encoded_len
, 1);
71 return http_request_body_init_rel(body
, HTTP_REQUEST_BODY_CSTRING
, estrndup("", 0), 0, 1);
75 /* STATUS http_request_body_encode(http_request_body *, char**, size_t *) */
76 PHP_HTTP_API STATUS
_http_request_body_encode(http_request_body
*body
, char **buf
, size_t *len TSRMLS_DC
)
79 case HTTP_REQUEST_BODY_CURLPOST
:
81 #ifdef HAVE_CURL_FORMGET
84 phpstr_init_ex(&str
, 0x8000, 0);
85 if (curl_formget(body
->data
, &str
, (curl_formget_callback
) phpstr_append
)) {
89 *buf
= PHPSTR_VAL(&str
);
90 *len
= PHPSTR_LEN(&str
);
97 case HTTP_REQUEST_BODY_CSTRING
:
98 *buf
= estrndup(body
->data
, *len
= body
->size
);
108 /* {{{ void http_request_body_dtor(http_request_body *) */
109 PHP_HTTP_API
void _http_request_body_dtor(http_request_body
*body TSRMLS_DC
)
113 switch (body
->type
) {
114 case HTTP_REQUEST_BODY_CSTRING
:
120 case HTTP_REQUEST_BODY_CURLPOST
:
121 curl_formfree(body
->data
);
124 case HTTP_REQUEST_BODY_UPLOADFILE
:
125 php_stream_close(body
->data
);
129 memset(body
, 0, sizeof(http_request_body
));
134 /* {{{ void http_request_body_free(http_request_body *) */
135 PHP_HTTP_API
void _http_request_body_free(http_request_body
**body TSRMLS_DC
)
138 http_request_body_dtor(*body
);
145 static inline char *format_key(uint type
, char *str
, ulong num
, const char *prefix
, int numeric_key_for_empty_prefix
) {
146 char *new_key
= NULL
;
148 if (prefix
&& *prefix
) {
149 if (type
== HASH_KEY_IS_STRING
) {
150 spprintf(&new_key
, 0, "%s[%s]", prefix
, str
);
152 spprintf(&new_key
, 0, "%s[%lu]", prefix
, num
);
154 } else if (type
== HASH_KEY_IS_STRING
) {
155 new_key
= estrdup(str
);
156 } else if (numeric_key_for_empty_prefix
) {
157 spprintf(&new_key
, 0, "%lu", num
);
163 /* {{{ static STATUS recursive_fields(post_data d, HashTable *f, const char *p TSRMLS_DC) */
164 static STATUS
recursive_fields(post_data http_post_data
, HashTable
*fields
, const char *prefix TSRMLS_DC
) {
165 HashKey key
= initHashKey(0);
168 char *new_key
= NULL
;
171 if (fields
&& !fields
->nApplyCount
) {
172 FOREACH_HASH_KEYVAL(pos
, fields
, key
, data_ptr
) {
173 if (key
.type
!= HASH_KEY_IS_STRING
|| *key
.str
) {
174 new_key
= format_key(key
.type
, key
.str
, key
.num
, prefix
, 1);
176 switch (Z_TYPE_PP(data_ptr
)) {
181 ++fields
->nApplyCount
;
182 status
= recursive_fields(http_post_data
, HASH_OF(*data_ptr
), new_key TSRMLS_CC
);
183 --fields
->nApplyCount
;
185 if (SUCCESS
!= status
) {
192 zval
*data
= http_zsep(IS_STRING
, *data_ptr
);
194 err
= curl_formadd(&http_post_data
[0], &http_post_data
[1],
195 CURLFORM_COPYNAME
, new_key
,
196 CURLFORM_COPYCONTENTS
, Z_STRVAL_P(data
),
197 CURLFORM_CONTENTSLENGTH
, (long) Z_STRLEN_P(data
),
201 zval_ptr_dtor(&data
);
203 if (CURLE_OK
!= err
) {
220 if (http_post_data
[0]) {
221 curl_formfree(http_post_data
[0]);
224 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not encode post fields: %s", curl_easy_strerror(err
));
226 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not encode post fields: unknown error");
232 /* {{{ static STATUS recursive_files(post_data d, HashTable *f, const char *p TSRMLS_DC) */
233 static STATUS
recursive_files(post_data http_post_data
, HashTable
*files
, const char *prefix TSRMLS_DC
) {
234 HashKey key
= initHashKey(0);
237 char *new_key
= NULL
;
240 if (files
&& !files
->nApplyCount
) {
241 FOREACH_HASH_KEYVAL(pos
, files
, key
, data_ptr
) {
242 zval
**file_ptr
, **type_ptr
, **name_ptr
;
244 if (key
.type
!= HASH_KEY_IS_STRING
|| *key
.str
) {
245 new_key
= format_key(key
.type
, key
.str
, key
.num
, prefix
, 0);
247 if (Z_TYPE_PP(data_ptr
) != IS_ARRAY
&& Z_TYPE_PP(data_ptr
) != IS_OBJECT
) {
248 if (new_key
|| key
.type
== HASH_KEY_IS_STRING
) {
249 http_error_ex(HE_NOTICE
, HTTP_E_INVALID_PARAM
, "Unrecognized type of post file array entry '%s'", new_key
? new_key
: key
.str
);
251 http_error_ex(HE_NOTICE
, HTTP_E_INVALID_PARAM
, "Unrecognized type of post file array entry '%lu'", key
.num
);
253 } else if ( SUCCESS
!= zend_hash_find(HASH_OF(*data_ptr
), "name", sizeof("name"), (void *) &name_ptr
) ||
254 SUCCESS
!= zend_hash_find(HASH_OF(*data_ptr
), "type", sizeof("type"), (void *) &type_ptr
) ||
255 SUCCESS
!= zend_hash_find(HASH_OF(*data_ptr
), "file", sizeof("file"), (void *) &file_ptr
)) {
258 ++files
->nApplyCount
;
259 status
= recursive_files(http_post_data
, HASH_OF(*data_ptr
), new_key TSRMLS_CC
);
260 --files
->nApplyCount
;
262 if (SUCCESS
!= status
) {
267 zval
*file
= http_zsep(IS_STRING
, *file_ptr
);
268 zval
*type
= http_zsep(IS_STRING
, *type_ptr
);
269 zval
*name
= http_zsep(IS_STRING
, *name_ptr
);
271 HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_P(file
), goto error
);
273 /* this is blatant but should be sufficient for most cases */
274 if (strncasecmp(Z_STRVAL_P(file
), "file://", lenof("file://"))) {
275 path
= Z_STRVAL_P(file
);
277 path
= Z_STRVAL_P(file
) + lenof("file://");
281 char *tmp_key
= format_key(HASH_KEY_IS_STRING
, Z_STRVAL_P(name
), 0, new_key
, 0);
282 STR_SET(new_key
, tmp_key
);
285 err
= curl_formadd(&http_post_data
[0], &http_post_data
[1],
286 CURLFORM_COPYNAME
, new_key
? new_key
: Z_STRVAL_P(name
),
288 CURLFORM_CONTENTTYPE
, Z_STRVAL_P(type
),
292 zval_ptr_dtor(&file
);
293 zval_ptr_dtor(&type
);
294 zval_ptr_dtor(&name
);
296 if (CURLE_OK
!= err
) {
311 if (http_post_data
[0]) {
312 curl_formfree(http_post_data
[0]);
315 http_error_ex(HE_WARNING
, HTTP_E_ENCODING
, "Could not encode post files: %s", curl_easy_strerror(err
));
317 http_error(HE_WARNING
, HTTP_E_ENCODING
, "Could not encode post files: unknown error");
323 #endif /* HTTP_HAVE_CURL */
330 * vim600: noet sw=4 ts=4 fdm=marker
331 * vim<600: noet sw=4 ts=4