2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
25 #include "php_output.h"
26 #include "ext/standard/url.h"
29 #include "php_http_api.h"
30 #include "php_http_url_api.h"
31 #include "php_http_std_defs.h"
33 #include "phpstr/phpstr.h"
36 # include <winsock2.h>
37 #elif defined(HAVE_NETDB_H)
41 ZEND_EXTERN_MODULE_GLOBALS(http
);
43 /* {{{ char *http_absolute_url(char *) */
44 PHP_HTTP_API
char *_http_absolute_url_ex(
45 const char *url
, size_t url_len
,
46 const char *proto
, size_t proto_len
,
47 const char *host
, size_t host_len
,
48 unsigned port TSRMLS_DC
)
50 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
53 php_url
*purl
= NULL
, furl
;
56 char *scheme
= NULL
, *uri
, *URL
= ecalloc(1, HTTP_URI_MAXLEN
+ 1);
58 if ((!url
|| !url_len
) && (
59 (!(url
= SG(request_info
).request_uri
)) ||
60 (!(url_len
= strlen(SG(request_info
).request_uri
))))) {
61 http_error(E_WARNING
, HTTP_E_PARAM
, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty");
65 uri
= estrndup(url
, url_len
);
66 if (!(purl
= php_url_parse(uri
))) {
67 http_error_ex(E_WARNING
, HTTP_E_PARSE
, "Could not parse supplied URL: %s", url
);
71 furl
.user
= purl
->user
;
72 furl
.pass
= purl
->pass
;
73 furl
.path
= purl
->path
;
74 furl
.query
= purl
->query
;
75 furl
.fragment
= purl
->fragment
;
77 if (proto
&& proto_len
) {
78 furl
.scheme
= scheme
= estrdup(proto
);
79 } else if (purl
->scheme
) {
80 furl
.scheme
= purl
->scheme
;
81 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
82 } else if (port
&& (se
= getservbyport(port
, "tcp"))) {
83 furl
.scheme
= (scheme
= estrdup(se
->s_name
));
91 } else if (purl
->port
) {
92 furl
.port
= purl
->port
;
93 } else if (strncmp(furl
.scheme
, "http", 4)) {
94 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
95 if (se
= getservbyname(furl
.scheme
, "tcp")) {
96 furl
.port
= se
->s_port
;
100 furl
.port
= (furl
.scheme
[4] == 's') ? 443 : 80;
104 furl
.host
= (char *) host
;
105 } else if (purl
->host
) {
106 furl
.host
= purl
->host
;
107 } else if ( (zhost
= http_get_server_var("HTTP_HOST")) ||
108 (zhost
= http_get_server_var("SERVER_NAME"))) {
109 furl
.host
= Z_STRVAL_P(zhost
);
111 furl
.host
= "localhost";
114 #define HTTP_URI_STRLCATS(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, sizeof(add_string)-1)
115 #define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string))
116 #define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \
117 if ((full_len += add_len) > HTTP_URI_MAXLEN) { \
118 http_error_ex(E_NOTICE, HTTP_E_URL, \
119 "Absolute URI would have exceeded max URI length (%d bytes) - " \
120 "tried to add %d bytes ('%s')", \
121 HTTP_URI_MAXLEN, add_len, add_string); \
125 php_url_free(purl); \
129 strcat(URL, add_string); \
132 HTTP_URI_STRLCATL(URL
, full_len
, furl
.scheme
);
133 HTTP_URI_STRLCATS(URL
, full_len
, "://");
136 HTTP_URI_STRLCATL(URL
, full_len
, furl
.user
);
138 HTTP_URI_STRLCATS(URL
, full_len
, ":");
139 HTTP_URI_STRLCATL(URL
, full_len
, furl
.pass
);
141 HTTP_URI_STRLCATS(URL
, full_len
, "@");
144 HTTP_URI_STRLCATL(URL
, full_len
, furl
.host
);
146 if ( (!strcmp(furl
.scheme
, "http") && (furl
.port
!= 80)) ||
147 (!strcmp(furl
.scheme
, "https") && (furl
.port
!= 443))) {
148 char port_string
[8] = {0};
149 snprintf(port_string
, 7, ":%u", furl
.port
);
150 HTTP_URI_STRLCATL(URL
, full_len
, port_string
);
154 if (furl
.path
[0] != '/') {
155 HTTP_URI_STRLCATS(URL
, full_len
, "/");
157 HTTP_URI_STRLCATL(URL
, full_len
, furl
.path
);
159 HTTP_URI_STRLCATS(URL
, full_len
, "/");
163 HTTP_URI_STRLCATS(URL
, full_len
, "?");
164 HTTP_URI_STRLCATL(URL
, full_len
, furl
.query
);
168 HTTP_URI_STRLCATS(URL
, full_len
, "#");
169 HTTP_URI_STRLCATL(URL
, full_len
, furl
.fragment
);
182 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
183 PHP_HTTP_API STATUS
_http_urlencode_hash_ex(HashTable
*hash
, zend_bool override_argsep
,
184 char *pre_encoded_data
, size_t pre_encoded_len
,
185 char **encoded_data
, size_t *encoded_len TSRMLS_DC
)
188 phpstr
*qstr
= phpstr_new();
190 if (override_argsep
|| !strlen(arg_sep
= INI_STR("arg_separator.output"))) {
191 arg_sep
= HTTP_URL_ARGSEP
;
194 if (pre_encoded_len
&& pre_encoded_data
) {
195 phpstr_append(qstr
, pre_encoded_data
, pre_encoded_len
);
198 if (SUCCESS
!= http_urlencode_hash_implementation(hash
, qstr
, arg_sep
)) {
203 phpstr_data(qstr
, encoded_data
, encoded_len
);
210 /* {{{ http_urlencode_hash_implementation
211 Original Author: Sara Golemon <pollita@php.net> */
212 PHP_HTTP_API STATUS
_http_urlencode_hash_implementation_ex(
213 HashTable
*ht
, phpstr
*formstr
, char *arg_sep
,
214 const char *num_prefix
, int num_prefix_len
,
215 const char *key_prefix
, int key_prefix_len
,
216 const char *key_suffix
, int key_suffix_len
,
217 zval
*type TSRMLS_DC
)
219 char *key
= NULL
, *ekey
, *newprefix
, *p
;
220 int arg_sep_len
, key_len
, ekey_len
, key_type
, newprefix_len
;
222 zval
**zdata
= NULL
, *copyzval
;
224 if (!ht
|| !formstr
) {
225 http_error(E_WARNING
, HTTP_E_PARAM
, "Invalid parameters");
229 if (ht
->nApplyCount
> 0) {
230 /* Prevent recursion */
234 if (!arg_sep
|| !strlen(arg_sep
)) {
235 arg_sep
= HTTP_URL_ARGSEP
;
237 arg_sep_len
= strlen(arg_sep
);
239 for (zend_hash_internal_pointer_reset(ht
);
240 (key_type
= zend_hash_get_current_key_ex(ht
, &key
, &key_len
, &idx
, 0, NULL
)) != HASH_KEY_NON_EXISTANT
;
241 zend_hash_move_forward(ht
)
243 if (key_type
== HASH_KEY_IS_STRING
&& key_len
&& key
[key_len
-1] == '\0') {
244 /* We don't want that trailing NULL */
249 /* handling for private & protected object properties */
250 if (key
&& *key
== '\0' && type
!= NULL
) {
253 zend_object
*zobj
= zend_objects_get_address(type TSRMLS_CC
);
254 if (zend_check_property_access(zobj
, key TSRMLS_CC
) != SUCCESS
) {
255 /* private or protected property access outside of the class */
258 zend_unmangle_property_name(key
, &tmp
, &key
);
259 key_len
= strlen(key
);
263 if (zend_hash_get_current_data_ex(ht
, (void **)&zdata
, NULL
) == FAILURE
|| !zdata
|| !(*zdata
)) {
264 http_error(E_WARNING
, HTTP_E_ENCODE
, "Error traversing form data array.");
267 if (Z_TYPE_PP(zdata
) == IS_ARRAY
|| Z_TYPE_PP(zdata
) == IS_OBJECT
) {
268 if (key_type
== HASH_KEY_IS_STRING
) {
269 ekey
= php_url_encode(key
, key_len
, &ekey_len
);
270 newprefix_len
= key_suffix_len
+ ekey_len
+ key_prefix_len
+ 1;
271 newprefix
= emalloc(newprefix_len
+ 1);
275 memcpy(p
, key_prefix
, key_prefix_len
);
279 memcpy(p
, ekey
, ekey_len
);
284 memcpy(p
, key_suffix
, key_suffix_len
);
291 /* Is an integer key */
292 ekey_len
= spprintf(&ekey
, 12, "%ld", idx
);
293 newprefix_len
= key_prefix_len
+ num_prefix_len
+ ekey_len
+ key_suffix_len
+ 1;
294 newprefix
= emalloc(newprefix_len
+ 1);
298 memcpy(p
, key_prefix
, key_prefix_len
);
302 memcpy(p
, num_prefix
, num_prefix_len
);
305 memcpy(p
, ekey
, ekey_len
);
310 memcpy(p
, key_suffix
, key_suffix_len
);
317 http_urlencode_hash_implementation_ex(HASH_OF(*zdata
), formstr
, arg_sep
,
318 NULL
, 0, newprefix
, newprefix_len
, "]", 1, (Z_TYPE_PP(zdata
) == IS_OBJECT
? *zdata
: NULL
));
321 } else if (Z_TYPE_PP(zdata
) == IS_NULL
|| Z_TYPE_PP(zdata
) == IS_RESOURCE
) {
322 /* Skip these types */
326 phpstr_append(formstr
, arg_sep
, arg_sep_len
);
328 /* Simple key=value */
329 phpstr_append(formstr
, key_prefix
, key_prefix_len
);
330 if (key_type
== HASH_KEY_IS_STRING
) {
331 ekey
= php_url_encode(key
, key_len
, &ekey_len
);
332 phpstr_append(formstr
, ekey
, ekey_len
);
337 phpstr_append(formstr
, num_prefix
, num_prefix_len
);
339 ekey_len
= spprintf(&ekey
, 12, "%ld", idx
);
340 phpstr_append(formstr
, ekey
, ekey_len
);
343 phpstr_append(formstr
, key_suffix
, key_suffix_len
);
344 phpstr_appends(formstr
, "=");
345 switch (Z_TYPE_PP(zdata
)) {
347 ekey
= php_url_encode(Z_STRVAL_PP(zdata
), Z_STRLEN_PP(zdata
), &ekey_len
);
351 ekey_len
= spprintf(&ekey
, 12, "%ld", Z_LVAL_PP(zdata
));
354 ekey_len
= spprintf(&ekey
, 48, "%.*G", (int) EG(precision
), Z_DVAL_PP(zdata
));
357 /* fall back on convert to string */
358 MAKE_STD_ZVAL(copyzval
);
360 zval_copy_ctor(copyzval
);
361 convert_to_string_ex(©zval
);
362 ekey
= php_url_encode(Z_STRVAL_P(copyzval
), Z_STRLEN_P(copyzval
), &ekey_len
);
363 zval_ptr_dtor(©zval
);
365 phpstr_append(formstr
, ekey
, ekey_len
);
379 * vim600: noet sw=4 ts=4 fdm=marker
380 * vim<600: noet sw=4 ts=4