1 : /*
2 : +--------------------------------------------------------------------+
3 : | PECL :: http |
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-2007, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : /* $Id: http_request_body_api.c,v 1.17 2007/02/07 11:50:27 mike Exp $ */
14 :
15 : #define HTTP_WANT_CURL
16 : #include "php_http.h"
17 :
18 : #ifdef HTTP_HAVE_CURL
19 :
20 : #include "php_http_api.h"
21 : #include "php_http_url_api.h"
22 : #include "php_http_request_body_api.h"
23 :
24 : #if defined(HAVE_CURL_GETFORMDATA) && !defined(HAVE_CURL_FORMGET)
25 : struct FormData {
26 : struct FormData *next;
27 : int type;
28 : char *line;
29 : size_t length;
30 : };
31 :
32 : CURLcode Curl_getFormData(struct FormData **, struct curl_httppost *post, curl_off_t *size);
33 :
34 : static char *file_get_contents(char *file, size_t *len TSRMLS_DC)
35 : {
36 : php_stream *s = NULL;
37 : char *buf = NULL;
38 :
39 : if ((s = php_stream_open_wrapper_ex(file, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL, HTTP_DEFAULT_STREAM_CONTEXT))) {
40 : *len = php_stream_copy_to_mem(s, &buf, (size_t) -1, 0);
41 : php_stream_close(s);
42 : } else {
43 : *len = 0;
44 : }
45 : return buf;
46 : }
47 :
48 : static int curl_formget(struct FormData *post, phpstr *str TSRMLS_DC)
49 : {
50 : int fgc_error = 0;
51 : char *fdata;
52 : size_t fsize;
53 : struct FormData *next, *pptr = post;
54 :
55 : while (pptr) {
56 : next = pptr->next;
57 :
58 : if (!fgc_error) {
59 : if (pptr->type) {
60 : if ((fdata = file_get_contents(pptr->line, &fsize TSRMLS_CC))) {
61 : phpstr_append(str, fdata, fsize);
62 : efree(fdata);
63 : } else {
64 : fgc_error = 1;
65 : }
66 : } else {
67 : phpstr_append(str, pptr->line, pptr->length);
68 : }
69 : }
70 :
71 : curl_free(pptr->line);
72 : curl_free(pptr);
73 : pptr = next;
74 : }
75 :
76 : return fgc_error;
77 : }
78 : #endif
79 :
80 :
81 : /* {{{ http_request_body *http_request_body_new() */
82 : 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)
83 9 : {
84 9 : if (!body) {
85 6 : body = emalloc_rel(sizeof(http_request_body));
86 : }
87 :
88 9 : body->type = type;
89 9 : body->free = free;
90 9 : body->priv = 0;
91 9 : body->data = data;
92 9 : body->size = size;
93 :
94 9 : return body;
95 : }
96 : /* }}} */
97 :
98 : /* {{{ http_request_body *http_request_body_fill(http_request_body *body, HashTable *, HashTable *) */
99 : 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)
100 6 : {
101 6 : if (files && (zend_hash_num_elements(files) > 0)) {
102 2 : HashKey key = initHashKey(0);
103 : zval **data;
104 : HashPosition pos;
105 2 : struct curl_httppost *http_post_data[2] = {NULL, NULL};
106 :
107 : /* normal data */
108 2 : if (fields) {
109 3 : FOREACH_HASH_KEYVAL(pos, fields, key, data) {
110 2 : if (key.type == HASH_KEY_IS_STRING) {
111 : CURLcode err;
112 2 : zval *orig = *data;
113 :
114 2 : convert_to_string_ex(data);
115 2 : err = curl_formadd(&http_post_data[0], &http_post_data[1],
116 : CURLFORM_COPYNAME, key.str,
117 : CURLFORM_COPYCONTENTS, Z_STRVAL_PP(data),
118 : CURLFORM_CONTENTSLENGTH, (long) Z_STRLEN_PP(data),
119 : CURLFORM_END
120 : );
121 :
122 2 : if (orig != *data) {
123 0 : zval_ptr_dtor(data);
124 : }
125 :
126 2 : if (CURLE_OK != err) {
127 0 : http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post fields: %s", curl_easy_strerror(err));
128 0 : curl_formfree(http_post_data[0]);
129 0 : return NULL;
130 : }
131 : }
132 : }
133 : }
134 :
135 : /* file data */
136 4 : FOREACH_HASH_VAL(pos, files, data) {
137 : zval **file, **type, **name;
138 :
139 2 : if (Z_TYPE_PP(data) != IS_ARRAY) {
140 0 : http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Unrecognized type of post file array entry");
141 2 : } else if ( SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "name", sizeof("name"), (void *) &name) ||
142 : SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "type", sizeof("type"), (void *) &type) ||
143 : SUCCESS != zend_hash_find(Z_ARRVAL_PP(data), "file", sizeof("file"), (void *) &file)) {
144 0 : http_error(HE_NOTICE, HTTP_E_INVALID_PARAM, "Post file array entry misses either 'name', 'type' or 'file' entry");
145 : } else {
146 : CURLcode err;
147 : const char *path;
148 2 : zval *ofile = *file, *otype = *type, *oname = *name;
149 :
150 2 : convert_to_string_ex(file);
151 2 : convert_to_string_ex(type);
152 2 : convert_to_string_ex(name);
153 :
154 2 : HTTP_CHECK_OPEN_BASEDIR(Z_STRVAL_PP(file), curl_formfree(http_post_data[0]); return NULL);
155 :
156 : /* this is blatant but should be sufficient for most cases */
157 2 : if (strncasecmp(Z_STRVAL_PP(file), "file://", lenof("file://"))) {
158 2 : path = Z_STRVAL_PP(file);
159 : } else {
160 0 : path = Z_STRVAL_PP(file) + lenof("file://");
161 : }
162 :
163 2 : err = curl_formadd(&http_post_data[0], &http_post_data[1],
164 : CURLFORM_COPYNAME, Z_STRVAL_PP(name),
165 : CURLFORM_FILE, path,
166 : CURLFORM_CONTENTTYPE, Z_STRVAL_PP(type),
167 : CURLFORM_END
168 : );
169 :
170 2 : if (ofile != *file) zval_ptr_dtor(file);
171 2 : if (otype != *type) zval_ptr_dtor(type);
172 2 : if (oname != *name) zval_ptr_dtor(name);
173 :
174 2 : if (CURLE_OK != err) {
175 0 : http_error_ex(HE_WARNING, HTTP_E_ENCODING, "Could not encode post files: %s", curl_easy_strerror(err));
176 0 : curl_formfree(http_post_data[0]);
177 0 : return NULL;
178 : }
179 : }
180 : }
181 :
182 2 : return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CURLPOST, http_post_data[0], 0, 1);
183 :
184 4 : } else if (fields) {
185 : char *encoded;
186 : size_t encoded_len;
187 :
188 4 : if (SUCCESS != http_urlencode_hash_ex(fields, 1, NULL, 0, &encoded, &encoded_len)) {
189 0 : http_error(HE_WARNING, HTTP_E_ENCODING, "Could not encode post data");
190 0 : return NULL;
191 : }
192 :
193 4 : return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, encoded, encoded_len, 1);
194 : } else {
195 0 : return http_request_body_init_rel(body, HTTP_REQUEST_BODY_CSTRING, estrndup("", 0), 0, 1);
196 : }
197 : }
198 :
199 : /* STATUS http_request_body_encode(http_request_body *, char**, size_t *) */
200 : PHP_HTTP_API STATUS _http_request_body_encode(http_request_body *body, char **buf, size_t *len TSRMLS_DC)
201 0 : {
202 0 : switch (body->type) {
203 : case HTTP_REQUEST_BODY_CURLPOST:
204 : {
205 : #if defined(HAVE_CURL_FORMGET)
206 : phpstr str;
207 :
208 : phpstr_init_ex(&str, 0x8000, 0);
209 : if (curl_formget(body->data, &str, (curl_formget_callback) phpstr_append)) {
210 : phpstr_dtor(&str);
211 : } else {
212 : phpstr_fix(&str);
213 : *buf = PHPSTR_VAL(&str);
214 : *len = PHPSTR_LEN(&str);
215 : return SUCCESS;
216 : }
217 : #elif defined(HAVE_CURL_GETFORMDATA)
218 : struct FormData *data;
219 : curl_off_t size;
220 :
221 : if (!Curl_getFormData(&data, body->data, &size)) {
222 : phpstr str;
223 :
224 : phpstr_init_ex(&str, (size_t) size, 0);
225 : if (curl_formget(data, &str TSRMLS_CC)) {
226 : phpstr_dtor(&str);
227 : } else {
228 : phpstr_fix(&str);
229 : *buf = PHPSTR_VAL(&str);
230 : *len = PHPSTR_LEN(&len);
231 : return SUCCESS;
232 : }
233 : }
234 : #endif
235 0 : break;
236 : }
237 :
238 : case HTTP_REQUEST_BODY_CSTRING:
239 0 : *buf = estrndup(body->data, *len = body->size);
240 0 : return SUCCESS;
241 :
242 : default:
243 : break;
244 : }
245 0 : return FAILURE;
246 : }
247 : /* }}} */
248 :
249 : /* {{{ void http_request_body_dtor(http_request_body *) */
250 : PHP_HTTP_API void _http_request_body_dtor(http_request_body *body TSRMLS_DC)
251 182 : {
252 182 : if (body) {
253 10 : if (body->free) {
254 8 : switch (body->type) {
255 : case HTTP_REQUEST_BODY_CSTRING:
256 5 : if (body->data) {
257 5 : efree(body->data);
258 : }
259 5 : break;
260 :
261 : case HTTP_REQUEST_BODY_CURLPOST:
262 2 : curl_formfree(body->data);
263 2 : break;
264 :
265 : case HTTP_REQUEST_BODY_UPLOADFILE:
266 1 : php_stream_close(body->data);
267 : break;
268 : }
269 : }
270 10 : memset(body, 0, sizeof(http_request_body));
271 : }
272 182 : }
273 : /* }}} */
274 :
275 : /* {{{ void http_request_body_free(http_request_body *) */
276 : PHP_HTTP_API void _http_request_body_free(http_request_body **body TSRMLS_DC)
277 85 : {
278 85 : if (*body) {
279 6 : http_request_body_dtor(*body);
280 6 : efree(*body);
281 6 : *body = NULL;
282 : }
283 85 : }
284 : /* }}} */
285 :
286 : #endif /* HTTP_HAVE_CURL */
287 :
288 : /*
289 : * Local variables:
290 : * tab-width: 4
291 : * c-basic-offset: 4
292 : * End:
293 : * vim600: noet sw=4 ts=4 fdm=marker
294 : * vim<600: noet sw=4 ts=4
295 : */
|