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-2007, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
15 #define HTTP_WANT_SAPI
16 #define HTTP_WANT_NETDB
20 #include "php_output.h"
21 #include "ext/standard/php_string.h"
23 #include "php_http_api.h"
24 #include "php_http_querystring_api.h"
25 #include "php_http_url_api.h"
27 static inline char *localhostname(void)
29 char hostname
[1024] = {0};
32 if (SUCCESS
== gethostname(hostname
, lenof(hostname
))) {
33 return estrdup(hostname
);
35 #elif defined(HAVE_GETHOSTNAME)
36 if (SUCCESS
== gethostname(hostname
, lenof(hostname
))) {
37 # if defined(HAVE_GETDOMAINNAME)
38 size_t hlen
= strlen(hostname
);
39 if (hlen
<= lenof(hostname
) - lenof("(none)")) {
40 hostname
[hlen
++] = '.';
41 if (SUCCESS
== getdomainname(&hostname
[hlen
], lenof(hostname
) - hlen
)) {
42 if (!strcmp(&hostname
[hlen
], "(none)")) {
43 hostname
[hlen
- 1] = '\0';
45 return estrdup(hostname
);
49 if (strcmp(hostname
, "(none)")) {
50 return estrdup(hostname
);
54 return estrndup("localhost", lenof("localhost"));
57 PHP_MINIT_FUNCTION(http_url
)
59 HTTP_LONG_CONSTANT("HTTP_URL_REPLACE", HTTP_URL_REPLACE
);
60 HTTP_LONG_CONSTANT("HTTP_URL_JOIN_PATH", HTTP_URL_JOIN_PATH
);
61 HTTP_LONG_CONSTANT("HTTP_URL_JOIN_QUERY", HTTP_URL_JOIN_QUERY
);
62 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_USER", HTTP_URL_STRIP_USER
);
63 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PASS", HTTP_URL_STRIP_PASS
);
64 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_AUTH", HTTP_URL_STRIP_AUTH
);
65 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PORT", HTTP_URL_STRIP_PORT
);
66 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_PATH", HTTP_URL_STRIP_PATH
);
67 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_QUERY", HTTP_URL_STRIP_QUERY
);
68 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_FRAGMENT", HTTP_URL_STRIP_FRAGMENT
);
69 HTTP_LONG_CONSTANT("HTTP_URL_STRIP_ALL", HTTP_URL_STRIP_ALL
);
70 HTTP_LONG_CONSTANT("HTTP_URL_FROM_ENV", HTTP_URL_FROM_ENV
);
74 PHP_HTTP_API
char *_http_absolute_url_ex(const char *url
, int flags TSRMLS_DC
)
80 purl
= php_url_parse(abs
= estrdup(url
));
83 http_error_ex(HE_WARNING
, HTTP_E_URL
, "Could not parse URL (%s)", url
);
88 http_build_url(flags
, purl
, NULL
, NULL
, &abs
, NULL
);
97 /* {{{ void http_build_url(int flags, const php_url *, const php_url *, php_url **, char **, size_t *) */
98 PHP_HTTP_API
void _http_build_url(int flags
, const php_url
*old_url
, const php_url
*new_url
, php_url
**url_ptr
, char **url_str
, size_t *url_len TSRMLS_DC
)
100 #if defined(HAVE_GETSERVBYPORT) || defined(HAVE_GETSERVBYNAME)
103 php_url
*url
= ecalloc(1, sizeof(php_url
));
105 #define __URLSET(u,n) \
107 #define __URLCPY(n) \
108 url->n = __URLSET(new_url,n) ? estrdup(new_url->n) : (__URLSET(old_url,n) ? estrdup(old_url->n) : NULL)
110 if (!(flags
& HTTP_URL_STRIP_PORT
)) {
111 url
->port
= __URLSET(new_url
, port
) ? new_url
->port
: ((old_url
) ? old_url
->port
: 0);
113 if (!(flags
& HTTP_URL_STRIP_USER
)) {
116 if (!(flags
& HTTP_URL_STRIP_PASS
)) {
123 if (!(flags
& HTTP_URL_STRIP_PATH
)) {
124 if ((flags
& HTTP_URL_JOIN_PATH
) && __URLSET(old_url
, path
) && __URLSET(new_url
, path
) && *new_url
->path
!= '/') {
125 size_t old_path_len
= strlen(old_url
->path
), new_path_len
= strlen(new_url
->path
);
127 url
->path
= ecalloc(1, old_path_len
+ new_path_len
+ 1 + 1);
129 strcat(url
->path
, old_url
->path
);
130 if (url
->path
[old_path_len
- 1] != '/') {
131 php_dirname(url
->path
, old_path_len
);
132 strcat(url
->path
, "/");
134 strcat(url
->path
, new_url
->path
);
139 if (!(flags
& HTTP_URL_STRIP_QUERY
)) {
140 if ((flags
& HTTP_URL_JOIN_QUERY
) && __URLSET(new_url
, query
) && __URLSET(old_url
, query
)) {
147 ZVAL_STRING(&qstr
, old_url
->query
, 0);
148 http_querystring_modify(&qarr
, &qstr
);
149 ZVAL_STRING(&qstr
, new_url
->query
, 0);
150 http_querystring_modify(&qarr
, &qstr
);
153 http_querystring_update(&qarr
, &qstr
);
154 url
->query
= Z_STRVAL(qstr
);
160 if (!(flags
& HTTP_URL_STRIP_FRAGMENT
)) {
165 if (flags
& HTTP_URL_FROM_ENV
) {
166 zval
*https
= http_get_server_var("HTTPS", 1);
167 if (https
&& !strcasecmp(Z_STRVAL_P(https
), "ON")) {
168 url
->scheme
= estrndup("https", lenof("https"));
169 } else switch (url
->port
) {
171 url
->scheme
= estrndup("https", lenof("https"));
174 #ifndef HAVE_GETSERVBYPORT
178 url
->scheme
= estrndup("http", lenof("http"));
181 #ifdef HAVE_GETSERVBYPORT
183 if ((se
= getservbyport(htons(url
->port
), "tcp")) && se
->s_name
) {
184 url
->scheme
= estrdup(se
->s_name
);
186 url
->scheme
= estrndup("http", lenof("http"));
192 url
->scheme
= estrndup("http", lenof("http"));
197 if (flags
& HTTP_URL_FROM_ENV
) {
200 if ((((zhost
= http_get_server_var("HTTP_HOST", 1)) ||
201 (zhost
= http_get_server_var("SERVER_NAME", 1)))) && Z_STRLEN_P(zhost
)) {
202 url
->host
= estrndup(Z_STRVAL_P(zhost
), Z_STRLEN_P(zhost
));
204 url
->host
= localhostname();
207 url
->host
= estrndup("localhost", lenof("localhost"));
212 if ((flags
& HTTP_URL_FROM_ENV
) && SG(request_info
).request_uri
&& SG(request_info
).request_uri
[0]) {
213 const char *q
= strchr(SG(request_info
).request_uri
, '?');
216 url
->path
= estrndup(SG(request_info
).request_uri
, q
- SG(request_info
).request_uri
);
218 url
->path
= estrdup(SG(request_info
).request_uri
);
221 url
->path
= estrndup("/", 1);
223 } else if (url
->path
[0] != '/') {
224 if ((flags
& HTTP_URL_FROM_ENV
) && SG(request_info
).request_uri
&& SG(request_info
).request_uri
[0]) {
225 size_t ulen
= strlen(SG(request_info
).request_uri
);
226 size_t plen
= strlen(url
->path
);
229 if (SG(request_info
).request_uri
[ulen
-1] != '/') {
230 for (--ulen
; ulen
&& SG(request_info
).request_uri
[ulen
- 1] != '/'; --ulen
);
233 path
= emalloc(ulen
+ plen
+ 1);
234 memcpy(path
, SG(request_info
).request_uri
, ulen
);
235 memcpy(path
+ ulen
, url
->path
, plen
);
236 path
[ulen
+ plen
] = '\0';
237 STR_SET(url
->path
, path
);
239 size_t plen
= strlen(url
->path
);
240 char *path
= emalloc(plen
+ 1 + 1);
243 memcpy(&path
[1], url
->path
, plen
+ 1);
244 STR_SET(url
->path
, path
);
247 /* replace directory references if path is not a single slash */
248 if (url
->path
[0] && (url
->path
[0] != '/' || url
->path
[1])) {
249 char *ptr
, *end
= url
->path
+ strlen(url
->path
) + 1;
251 for (ptr
= strstr(url
->path
, "/."); ptr
; ptr
= strstr(ptr
, "/.")) {
258 memmove(&ptr
[1], &ptr
[3], end
- &ptr
[3]);
264 while (ptr
!= url
->path
) {
269 memmove(&ptr
[1], pos
, end
- pos
);
271 } else if (!ptr
[3]) {
286 if ( ((url
->port
== 80) && !strcmp(url
->scheme
, "http"))
287 || ((url
->port
==443) && !strcmp(url
->scheme
, "https"))
288 #ifdef HAVE_GETSERVBYNAME
289 || ((se
= getservbyname(url
->scheme
, "tcp")) && se
->s_port
&&
290 (url
->port
== ntohs(se
->s_port
)))
300 *url_str
= emalloc(HTTP_URL_MAXLEN
+ 1);
303 strlcat(*url_str
, url
->scheme
, HTTP_URL_MAXLEN
);
304 strlcat(*url_str
, "://", HTTP_URL_MAXLEN
);
306 if (url
->user
&& *url
->user
) {
307 strlcat(*url_str
, url
->user
, HTTP_URL_MAXLEN
);
308 if (url
->pass
&& *url
->pass
) {
309 strlcat(*url_str
, ":", HTTP_URL_MAXLEN
);
310 strlcat(*url_str
, url
->pass
, HTTP_URL_MAXLEN
);
312 strlcat(*url_str
, "@", HTTP_URL_MAXLEN
);
315 strlcat(*url_str
, url
->host
, HTTP_URL_MAXLEN
);
320 snprintf(port_str
, sizeof(port_str
), "%d", (int) url
->port
);
321 strlcat(*url_str
, ":", HTTP_URL_MAXLEN
);
322 strlcat(*url_str
, port_str
, HTTP_URL_MAXLEN
);
325 strlcat(*url_str
, url
->path
, HTTP_URL_MAXLEN
);
327 if (url
->query
&& *url
->query
) {
328 strlcat(*url_str
, "?", HTTP_URL_MAXLEN
);
329 strlcat(*url_str
, url
->query
, HTTP_URL_MAXLEN
);
332 if (url
->fragment
&& *url
->fragment
) {
333 strlcat(*url_str
, "#", HTTP_URL_MAXLEN
);
334 strlcat(*url_str
, url
->fragment
, HTTP_URL_MAXLEN
);
337 if (HTTP_URL_MAXLEN
== (len
= strlen(*url_str
))) {
338 http_error(HE_NOTICE
, HTTP_E_URL
, "Length of URL exceeds HTTP_URL_MAXLEN");
353 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
354 PHP_HTTP_API STATUS
_http_urlencode_hash_ex(HashTable
*hash
, zend_bool override_argsep
,
355 char *pre_encoded_data
, size_t pre_encoded_len
,
356 char **encoded_data
, size_t *encoded_len TSRMLS_DC
)
360 phpstr
*qstr
= phpstr_new();
362 if (override_argsep
|| !(arg_sep_len
= strlen(arg_sep
= INI_STR("arg_separator.output")))) {
363 arg_sep
= HTTP_URL_ARGSEP
;
364 arg_sep_len
= lenof(HTTP_URL_ARGSEP
);
367 if (pre_encoded_len
&& pre_encoded_data
) {
368 phpstr_append(qstr
, pre_encoded_data
, pre_encoded_len
);
371 if (SUCCESS
!= http_urlencode_hash_recursive(hash
, qstr
, arg_sep
, arg_sep_len
, NULL
, 0)) {
376 phpstr_data(qstr
, encoded_data
, encoded_len
);
383 /* {{{ http_urlencode_hash_recursive */
384 PHP_HTTP_API STATUS
_http_urlencode_hash_recursive(HashTable
*ht
, phpstr
*str
, const char *arg_sep
, size_t arg_sep_len
, const char *prefix
, size_t prefix_len TSRMLS_DC
)
386 HashKey key
= initHashKey(0);
391 http_error(HE_WARNING
, HTTP_E_INVALID_PARAM
, "Invalid parameters");
394 if (ht
->nApplyCount
> 0) {
398 FOREACH_HASH_KEYVAL(pos
, ht
, key
, data
) {
403 if (!data
|| !*data
) {
408 if (key
.type
== HASH_KEY_IS_STRING
) {
410 /* only public properties */
413 if (key
.len
&& key
.str
[key
.len
- 1] == '\0') {
416 encoded_key
= php_url_encode(key
.str
, key
.len
, &encoded_len
);
418 encoded_len
= spprintf(&encoded_key
, 0, "%ld", key
.num
);
422 phpstr_init(&new_prefix
);
423 if (prefix
&& prefix_len
) {
424 phpstr_append(&new_prefix
, prefix
, prefix_len
);
425 phpstr_appends(&new_prefix
, "%5B");
428 phpstr_append(&new_prefix
, encoded_key
, encoded_len
);
431 if (prefix
&& prefix_len
) {
432 phpstr_appends(&new_prefix
, "%5D");
434 phpstr_fix(&new_prefix
);
437 if (Z_TYPE_PP(data
) == IS_ARRAY
|| Z_TYPE_PP(data
) == IS_OBJECT
) {
440 status
= http_urlencode_hash_recursive(HASH_OF(*data
), str
, arg_sep
, arg_sep_len
, PHPSTR_VAL(&new_prefix
), PHPSTR_LEN(&new_prefix
));
442 if (SUCCESS
!= status
) {
443 phpstr_dtor(&new_prefix
);
448 zval
*val
= zval_copy(IS_STRING
, *data
);
450 if (PHPSTR_LEN(str
)) {
451 phpstr_append(str
, arg_sep
, arg_sep_len
);
453 phpstr_append(str
, PHPSTR_VAL(&new_prefix
), PHPSTR_LEN(&new_prefix
));
454 phpstr_appends(str
, "=");
456 if (Z_STRLEN_P(val
) && Z_STRVAL_P(val
)) {
460 encoded_val
= php_url_encode(Z_STRVAL_P(val
), Z_STRLEN_P(val
), &encoded_len
);
461 phpstr_append(str
, encoded_val
, encoded_len
);
467 phpstr_dtor(&new_prefix
);
478 * vim600: noet sw=4 ts=4 fdm=marker
479 * vim<600: noet sw=4 ts=4