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-2005, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
22 #include "php_output.h"
23 #include "ext/standard/url.h"
26 #include "php_http_api.h"
27 #include "php_http_url_api.h"
28 #include "php_http_std_defs.h"
30 #include "phpstr/phpstr.h"
33 # include <winsock2.h>
34 #elif defined(HAVE_NETDB_H)
38 ZEND_EXTERN_MODULE_GLOBALS(http
);
40 /* {{{ char *http_absolute_url(char *) */
41 PHP_HTTP_API
char *_http_absolute_url_ex(
42 const char *url
, size_t url_len
,
43 const char *proto
, size_t proto_len
,
44 const char *host
, size_t host_len
,
45 unsigned port TSRMLS_DC
)
47 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
50 php_url
*purl
= NULL
, furl
;
53 char *scheme
= NULL
, *uri
, *URL
;
55 if ((!url
|| !url_len
) && (
56 (!(url
= SG(request_info
).request_uri
)) ||
57 (!(url_len
= strlen(SG(request_info
).request_uri
))))) {
58 http_error(HE_WARNING
, HTTP_E_RUNTIME
, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty");
62 URL
= ecalloc(1, HTTP_URI_MAXLEN
+ 1);
63 uri
= estrndup(url
, url_len
);
64 if (!(purl
= php_url_parse(uri
))) {
65 http_error_ex(HE_WARNING
, HTTP_E_URL
, "Could not parse supplied URL: %s", url
);
69 furl
.user
= purl
->user
;
70 furl
.pass
= purl
->pass
;
71 furl
.path
= purl
->path
;
72 furl
.query
= purl
->query
;
73 furl
.fragment
= purl
->fragment
;
75 if (proto
&& proto_len
) {
76 furl
.scheme
= scheme
= estrdup(proto
);
77 } else if (purl
->scheme
) {
78 furl
.scheme
= purl
->scheme
;
79 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
80 } else if (port
&& (se
= getservbyport(port
, "tcp"))) {
81 furl
.scheme
= (scheme
= estrdup(se
->s_name
));
89 } else if (purl
->port
) {
90 furl
.port
= purl
->port
;
91 } else if (strncmp(furl
.scheme
, "http", 4)) {
92 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
93 if (se
= getservbyname(furl
.scheme
, "tcp")) {
94 furl
.port
= se
->s_port
;
98 furl
.port
= (furl
.scheme
[4] == 's') ? 443 : 80;
102 furl
.host
= (char *) host
;
103 } else if (purl
->host
) {
104 furl
.host
= purl
->host
;
105 } else if ( (zhost
= http_get_server_var("HTTP_HOST")) ||
106 (zhost
= http_get_server_var("SERVER_NAME"))) {
107 furl
.host
= Z_STRVAL_P(zhost
);
109 furl
.host
= "localhost";
112 #define HTTP_URI_STRLCATS(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, sizeof(add_string)-1)
113 #define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string))
114 #define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \
115 if ((full_len += add_len) > HTTP_URI_MAXLEN) { \
116 http_error_ex(HE_NOTICE, HTTP_E_URL, \
117 "Absolute URI would have exceeded max URI length (%d bytes) - " \
118 "tried to add %d bytes ('%s')", \
119 HTTP_URI_MAXLEN, add_len, add_string); \
123 php_url_free(purl); \
127 strcat(URL, add_string); \
130 HTTP_URI_STRLCATL(URL
, full_len
, furl
.scheme
);
131 HTTP_URI_STRLCATS(URL
, full_len
, "://");
134 HTTP_URI_STRLCATL(URL
, full_len
, furl
.user
);
136 HTTP_URI_STRLCATS(URL
, full_len
, ":");
137 HTTP_URI_STRLCATL(URL
, full_len
, furl
.pass
);
139 HTTP_URI_STRLCATS(URL
, full_len
, "@");
142 HTTP_URI_STRLCATL(URL
, full_len
, furl
.host
);
144 if ( (!strcmp(furl
.scheme
, "http") && (furl
.port
!= 80)) ||
145 (!strcmp(furl
.scheme
, "https") && (furl
.port
!= 443))) {
146 char port_string
[8] = {0};
147 snprintf(port_string
, 7, ":%u", furl
.port
);
148 HTTP_URI_STRLCATL(URL
, full_len
, port_string
);
152 if (furl
.path
[0] != '/') {
153 HTTP_URI_STRLCATS(URL
, full_len
, "/");
155 HTTP_URI_STRLCATL(URL
, full_len
, furl
.path
);
157 HTTP_URI_STRLCATS(URL
, full_len
, "/");
161 HTTP_URI_STRLCATS(URL
, full_len
, "?");
162 HTTP_URI_STRLCATL(URL
, full_len
, furl
.query
);
166 HTTP_URI_STRLCATS(URL
, full_len
, "#");
167 HTTP_URI_STRLCATL(URL
, full_len
, furl
.fragment
);
180 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
181 PHP_HTTP_API STATUS
_http_urlencode_hash_ex(HashTable
*hash
, zend_bool override_argsep
,
182 char *pre_encoded_data
, size_t pre_encoded_len
,
183 char **encoded_data
, size_t *encoded_len TSRMLS_DC
)
186 phpstr
*qstr
= phpstr_new();
188 if (override_argsep
|| !strlen(arg_sep
= INI_STR("arg_separator.output"))) {
189 arg_sep
= HTTP_URL_ARGSEP
;
192 if (pre_encoded_len
&& pre_encoded_data
) {
193 phpstr_append(qstr
, pre_encoded_data
, pre_encoded_len
);
196 if (SUCCESS
!= http_urlencode_hash_implementation(hash
, qstr
, arg_sep
)) {
201 phpstr_data(qstr
, encoded_data
, encoded_len
);
208 /* {{{ http_urlencode_hash_implementation
209 Original Author: Sara Golemon <pollita@php.net> */
210 PHP_HTTP_API STATUS
_http_urlencode_hash_implementation_ex(
211 HashTable
*ht
, phpstr
*formstr
, char *arg_sep
,
212 const char *num_prefix
, int num_prefix_len
,
213 const char *key_prefix
, int key_prefix_len
,
214 const char *key_suffix
, int key_suffix_len
,
215 zval
*type TSRMLS_DC
)
217 char *key
= NULL
, *ekey
, *newprefix
, *p
;
218 int arg_sep_len
, ekey_len
, key_type
, newprefix_len
;
221 zval
**zdata
= NULL
, *copyzval
;
223 if (!ht
|| !formstr
) {
224 http_error(HE_WARNING
, HTTP_E_INVALID_PARAM
, "Invalid parameters");
228 if (ht
->nApplyCount
> 0) {
229 /* Prevent recursion */
233 if (!arg_sep
|| !strlen(arg_sep
)) {
234 arg_sep
= HTTP_URL_ARGSEP
;
236 arg_sep_len
= strlen(arg_sep
);
238 for (zend_hash_internal_pointer_reset(ht
);
239 (key_type
= zend_hash_get_current_key_ex(ht
, &key
, &key_len
, &idx
, 0, NULL
)) != HASH_KEY_NON_EXISTANT
;
240 zend_hash_move_forward(ht
)
242 if (key_type
== HASH_KEY_IS_STRING
&& key_len
&& key
[key_len
-1] == '\0') {
243 /* We don't want that trailing NULL */
248 /* handling for private & protected object properties */
249 if (key
&& *key
== '\0' && type
!= NULL
) {
252 zend_object
*zobj
= zend_objects_get_address(type TSRMLS_CC
);
253 if (zend_check_property_access(zobj
, key TSRMLS_CC
) != SUCCESS
) {
254 /* private or protected property access outside of the class */
257 zend_unmangle_property_name(key
, &tmp
, &key
);
258 key_len
= strlen(key
);
262 if (zend_hash_get_current_data_ex(ht
, (void **)&zdata
, NULL
) == FAILURE
|| !zdata
|| !(*zdata
)) {
263 http_error(HE_WARNING
, HTTP_E_ENCODING
, "Error traversing form data array.");
266 if (Z_TYPE_PP(zdata
) == IS_ARRAY
|| Z_TYPE_PP(zdata
) == IS_OBJECT
) {
267 if (key_type
== HASH_KEY_IS_STRING
) {
268 ekey
= php_url_encode(key
, key_len
, &ekey_len
);
269 newprefix_len
= key_suffix_len
+ ekey_len
+ key_prefix_len
+ 1;
270 newprefix
= emalloc(newprefix_len
+ 1);
274 memcpy(p
, key_prefix
, key_prefix_len
);
278 memcpy(p
, ekey
, ekey_len
);
283 memcpy(p
, key_suffix
, key_suffix_len
);
290 /* Is an integer key */
291 ekey_len
= spprintf(&ekey
, 12, "%ld", idx
);
292 newprefix_len
= key_prefix_len
+ num_prefix_len
+ ekey_len
+ key_suffix_len
+ 1;
293 newprefix
= emalloc(newprefix_len
+ 1);
297 memcpy(p
, key_prefix
, key_prefix_len
);
301 memcpy(p
, num_prefix
, num_prefix_len
);
304 memcpy(p
, ekey
, ekey_len
);
309 memcpy(p
, key_suffix
, key_suffix_len
);
316 http_urlencode_hash_implementation_ex(HASH_OF(*zdata
), formstr
, arg_sep
,
317 NULL
, 0, newprefix
, newprefix_len
, "]", 1, (Z_TYPE_PP(zdata
) == IS_OBJECT
? *zdata
: NULL
));
320 } else if (Z_TYPE_PP(zdata
) == IS_NULL
|| Z_TYPE_PP(zdata
) == IS_RESOURCE
) {
321 /* Skip these types */
325 phpstr_append(formstr
, arg_sep
, arg_sep_len
);
327 /* Simple key=value */
328 phpstr_append(formstr
, key_prefix
, key_prefix_len
);
329 if (key_type
== HASH_KEY_IS_STRING
) {
330 ekey
= php_url_encode(key
, key_len
, &ekey_len
);
331 phpstr_append(formstr
, ekey
, ekey_len
);
336 phpstr_append(formstr
, num_prefix
, num_prefix_len
);
338 ekey_len
= spprintf(&ekey
, 12, "%ld", idx
);
339 phpstr_append(formstr
, ekey
, ekey_len
);
342 phpstr_append(formstr
, key_suffix
, key_suffix_len
);
343 phpstr_appends(formstr
, "=");
344 switch (Z_TYPE_PP(zdata
)) {
346 ekey
= php_url_encode(Z_STRVAL_PP(zdata
), Z_STRLEN_PP(zdata
), &ekey_len
);
350 ekey_len
= spprintf(&ekey
, 12, "%ld", Z_LVAL_PP(zdata
));
353 ekey_len
= spprintf(&ekey
, 48, "%.*G", (int) EG(precision
), Z_DVAL_PP(zdata
));
356 /* fall back on convert to string */
357 MAKE_STD_ZVAL(copyzval
);
359 zval_copy_ctor(copyzval
);
360 convert_to_string_ex(©zval
);
361 ekey
= php_url_encode(Z_STRVAL_P(copyzval
), Z_STRLEN_P(copyzval
), &ekey_len
);
362 zval_ptr_dtor(©zval
);
364 phpstr_append(formstr
, ekey
, ekey_len
);
378 * vim600: noet sw=4 ts=4 fdm=marker
379 * vim<600: noet sw=4 ts=4