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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 #include "php_http_api.h"
15 #if PHP_HTTP_HAVE_LIBIDN
18 #if PHP_HTTP_HAVE_LIBIDN2
21 #if PHP_HTTP_HAVE_LIBICU
22 # include <unicode/uchar.h>
23 # include <unicode/uidna.h>
25 #if PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2
27 # include <idn/result.h>
30 #if PHP_HTTP_HAVE_WCHAR
36 # include <arpa/inet.h>
39 #include "php_http_utf8.h"
41 static inline char *localhostname(void)
43 char hostname
[1024] = {0};
46 if (SUCCESS
== gethostname(hostname
, lenof(hostname
))) {
47 return estrdup(hostname
);
49 #elif HAVE_GETHOSTNAME
50 if (SUCCESS
== gethostname(hostname
, lenof(hostname
))) {
51 # if HAVE_GETDOMAINNAME
52 size_t hlen
= strlen(hostname
);
53 if (hlen
<= lenof(hostname
) - lenof("(none)")) {
54 hostname
[hlen
++] = '.';
55 if (SUCCESS
== getdomainname(&hostname
[hlen
], lenof(hostname
) - hlen
)) {
56 if (!strcmp(&hostname
[hlen
], "(none)")) {
57 hostname
[hlen
- 1] = '\0';
59 return estrdup(hostname
);
63 if (strcmp(hostname
, "(none)")) {
64 return estrdup(hostname
);
68 return estrndup("localhost", lenof("localhost"));
71 #define url(buf) ((php_http_url_t *) (buf).data)
73 static php_http_url_t
*php_http_url_from_env(void)
75 zval
*https
, *zhost
, *zport
;
77 php_http_buffer_t buf
;
79 php_http_buffer_init_ex(&buf
, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE
, sizeof(php_http_url_t
)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC
);
80 php_http_buffer_account(&buf
, sizeof(php_http_url_t
));
81 memset(buf
.data
, 0, buf
.used
);
84 url(buf
)->scheme
= &buf
.data
[buf
.used
];
85 https
= php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1);
86 if (https
&& !strcasecmp(Z_STRVAL_P(https
), "ON")) {
87 php_http_buffer_append(&buf
, "https", sizeof("https"));
89 php_http_buffer_append(&buf
, "http", sizeof("http"));
93 url(buf
)->host
= &buf
.data
[buf
.used
];
94 if ((((zhost
= php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1)) ||
95 (zhost
= php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1)) ||
96 (zhost
= php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1)))) && Z_STRLEN_P(zhost
)) {
97 size_t stop_at
= strspn(Z_STRVAL_P(zhost
), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-.");
99 php_http_buffer_append(&buf
, Z_STRVAL_P(zhost
), stop_at
);
100 php_http_buffer_append(&buf
, "", 1);
102 char *host_str
= localhostname();
104 php_http_buffer_append(&buf
, host_str
, strlen(host_str
) + 1);
109 zport
= php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1);
110 if (zport
&& IS_LONG
== is_numeric_string(Z_STRVAL_P(zport
), Z_STRLEN_P(zport
), &port
, NULL
, 0)) {
111 url(buf
)->port
= port
;
115 if (SG(request_info
).request_uri
&& SG(request_info
).request_uri
[0]) {
116 const char *q
= strchr(SG(request_info
).request_uri
, '?');
118 url(buf
)->path
= &buf
.data
[buf
.used
];
121 php_http_buffer_append(&buf
, SG(request_info
).request_uri
, q
- SG(request_info
).request_uri
);
122 php_http_buffer_append(&buf
, "", 1);
124 php_http_buffer_append(&buf
, SG(request_info
).request_uri
, strlen(SG(request_info
).request_uri
) + 1);
129 if (SG(request_info
).query_string
&& SG(request_info
).query_string
[0]) {
130 url(buf
)->query
= &buf
.data
[buf
.used
];
131 php_http_buffer_append(&buf
, SG(request_info
).query_string
, strlen(SG(request_info
).query_string
) + 1);
137 #define url_isset(u,n) \
139 #define url_append(buf, append) do { \
140 char *_ptr = (buf)->data; \
141 php_http_url_t *_url = (php_http_url_t *) _ptr, _mem = *_url; \
144 if (_ptr != (buf)->data) { \
145 ptrdiff_t diff = (buf)->data - _ptr; \
146 _url = (php_http_url_t *) (buf)->data; \
147 if (_mem.scheme) _url->scheme += diff; \
148 if (_mem.user) _url->user += diff; \
149 if (_mem.pass) _url->pass += diff; \
150 if (_mem.host) _url->host += diff; \
151 if (_mem.path) _url->path += diff; \
152 if (_mem.query) _url->query += diff; \
153 if (_mem.fragment) _url->fragment += diff; \
156 #define url_copy(n) do { \
157 if (url_isset(new_url, n)) { \
158 url(buf)->n = &buf.data[buf.used]; \
159 url_append(&buf, php_http_buffer_append(&buf, new_url->n, strlen(new_url->n) + 1)); \
160 } else if (url_isset(old_url, n)) { \
161 url(buf)->n = &buf.data[buf.used]; \
162 url_append(&buf, php_http_buffer_append(&buf, old_url->n, strlen(old_url->n) + 1)); \
166 php_http_url_t
*php_http_url_mod(const php_http_url_t
*old_url
, const php_http_url_t
*new_url
, unsigned flags
)
168 php_http_url_t
*tmp_url
= NULL
;
169 php_http_buffer_t buf
;
171 php_http_buffer_init_ex(&buf
, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE
, sizeof(php_http_url_t
)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC
);
172 php_http_buffer_account(&buf
, sizeof(php_http_url_t
));
173 memset(buf
.data
, 0, buf
.used
);
175 /* set from env if requested */
176 if (flags
& PHP_HTTP_URL_FROM_ENV
) {
177 php_http_url_t
*env_url
= php_http_url_from_env();
179 old_url
= tmp_url
= php_http_url_mod(env_url
, old_url
, flags
^ PHP_HTTP_URL_FROM_ENV
);
180 php_http_url_free(&env_url
);
185 if (!(flags
& PHP_HTTP_URL_STRIP_USER
)) {
189 if (!(flags
& PHP_HTTP_URL_STRIP_PASS
)) {
195 if (!(flags
& PHP_HTTP_URL_STRIP_PORT
)) {
196 url(buf
)->port
= url_isset(new_url
, port
) ? new_url
->port
: ((old_url
) ? old_url
->port
: 0);
199 if (!(flags
& PHP_HTTP_URL_STRIP_PATH
)) {
200 if ((flags
& PHP_HTTP_URL_JOIN_PATH
) && url_isset(old_url
, path
) && url_isset(new_url
, path
) && *new_url
->path
!= '/') {
201 size_t old_path_len
= strlen(old_url
->path
), new_path_len
= strlen(new_url
->path
);
202 char *path
= ecalloc(1, old_path_len
+ new_path_len
+ 1 + 1);
204 strcat(path
, old_url
->path
);
205 if (path
[old_path_len
- 1] != '/') {
206 php_dirname(path
, old_path_len
);
209 strcat(path
, new_url
->path
);
211 url(buf
)->path
= &buf
.data
[buf
.used
];
212 if (path
[0] != '/') {
213 url_append(&buf
, php_http_buffer_append(&buf
, "/", 1));
215 url_append(&buf
, php_http_buffer_append(&buf
, path
, strlen(path
) + 1));
218 const char *path
= NULL
;
220 if (url_isset(new_url
, path
)) {
221 path
= new_url
->path
;
222 } else if (url_isset(old_url
, path
)) {
223 path
= old_url
->path
;
227 url(buf
)->path
= &buf
.data
[buf
.used
];
229 url_append(&buf
, php_http_buffer_append(&buf
, path
, strlen(path
) + 1));
236 if (!(flags
& PHP_HTTP_URL_STRIP_QUERY
)) {
237 if ((flags
& PHP_HTTP_URL_JOIN_QUERY
) && url_isset(new_url
, query
) && url_isset(old_url
, query
)) {
242 ZVAL_STRING(&qstr
, old_url
->query
);
243 php_http_querystring_update(&qarr
, &qstr
, NULL
);
244 zval_ptr_dtor(&qstr
);
245 ZVAL_STRING(&qstr
, new_url
->query
);
246 php_http_querystring_update(&qarr
, &qstr
, NULL
);
247 zval_ptr_dtor(&qstr
);
250 php_http_querystring_update(&qarr
, NULL
, &qstr
);
252 url(buf
)->query
= &buf
.data
[buf
.used
];
253 url_append(&buf
, php_http_buffer_append(&buf
, Z_STRVAL(qstr
), Z_STRLEN(qstr
) + 1));
262 if (!(flags
& PHP_HTTP_URL_STRIP_FRAGMENT
)) {
266 /* done with copy & combine & strip */
268 if (flags
& PHP_HTTP_URL_FROM_ENV
) {
269 /* free old_url we tainted above */
270 php_http_url_free(&tmp_url
);
273 /* replace directory references if path is not a single slash */
274 if ((flags
& PHP_HTTP_URL_SANITIZE_PATH
)
276 && url(buf
)->path
[0] && url(buf
)->path
[1]) {
277 char *ptr
, *end
= url(buf
)->path
+ strlen(url(buf
)->path
) + 1;
279 for (ptr
= strchr(url(buf
)->path
, '/'); ptr
; ptr
= strchr(ptr
, '/')) {
282 memmove(&ptr
[1], &ptr
[2], end
- &ptr
[2]);
292 memmove(&ptr
[1], &ptr
[3], end
- &ptr
[3]);
298 while (ptr
!= url(buf
)->path
) {
303 memmove(&ptr
[1], pos
, end
- pos
);
305 } else if (!ptr
[3]) {
324 /* unset default ports */
325 if (url(buf
)->port
) {
326 if ( ((url(buf
)->port
== 80) && url(buf
)->scheme
&& !strcmp(url(buf
)->scheme
, "http"))
327 || ((url(buf
)->port
==443) && url(buf
)->scheme
&& !strcmp(url(buf
)->scheme
, "https"))
336 char *php_http_url_to_string(const php_http_url_t
*url
, char **url_str
, size_t *url_len
, zend_bool persistent
)
338 php_http_buffer_t buf
;
340 php_http_buffer_init_ex(&buf
, PHP_HTTP_BUFFER_DEFAULT_SIZE
, persistent
?
341 PHP_HTTP_BUFFER_INIT_PERSISTENT
: 0);
343 if (url
->scheme
&& *url
->scheme
) {
344 php_http_buffer_appendl(&buf
, url
->scheme
);
345 php_http_buffer_appends(&buf
, "://");
346 } else if ((url
->user
&& *url
->user
) || (url
->host
&& *url
->host
)) {
347 php_http_buffer_appends(&buf
, "//");
350 if (url
->user
&& *url
->user
) {
351 php_http_buffer_appendl(&buf
, url
->user
);
352 if (url
->pass
&& *url
->pass
) {
353 php_http_buffer_appends(&buf
, ":");
354 php_http_buffer_appendl(&buf
, url
->pass
);
356 php_http_buffer_appends(&buf
, "@");
359 if (url
->host
&& *url
->host
) {
360 php_http_buffer_appendl(&buf
, url
->host
);
362 php_http_buffer_appendf(&buf
, ":%hu", url
->port
);
366 if (url
->path
&& *url
->path
) {
367 if (*url
->path
!= '/') {
368 php_http_buffer_appends(&buf
, "/");
370 php_http_buffer_appendl(&buf
, url
->path
);
371 } else if (buf
.used
) {
372 php_http_buffer_appends(&buf
, "/");
375 if (url
->query
&& *url
->query
) {
376 php_http_buffer_appends(&buf
, "?");
377 php_http_buffer_appendl(&buf
, url
->query
);
380 if (url
->fragment
&& *url
->fragment
) {
381 php_http_buffer_appends(&buf
, "#");
382 php_http_buffer_appendl(&buf
, url
->fragment
);
385 php_http_buffer_shrink(&buf
);
386 php_http_buffer_fix(&buf
);
399 char *php_http_url_authority_to_string(const php_http_url_t
*url
, char **url_str
, size_t *url_len
)
401 php_http_buffer_t buf
;
403 php_http_buffer_init(&buf
);
405 if (url
->user
&& *url
->user
) {
406 php_http_buffer_appendl(&buf
, url
->user
);
407 if (url
->pass
&& *url
->pass
) {
408 php_http_buffer_appends(&buf
, ":");
409 php_http_buffer_appendl(&buf
, url
->pass
);
411 php_http_buffer_appends(&buf
, "@");
414 if (url
->host
&& *url
->host
) {
415 php_http_buffer_appendl(&buf
, url
->host
);
417 php_http_buffer_appendf(&buf
, ":%hu", url
->port
);
421 php_http_buffer_shrink(&buf
);
422 php_http_buffer_fix(&buf
);
435 php_http_url_t
*php_http_url_from_zval(zval
*value
, unsigned flags
)
438 php_http_url_t
*purl
;
440 switch (Z_TYPE_P(value
)) {
443 purl
= php_http_url_from_struct(HASH_OF(value
));
447 zs
= zval_get_string(value
);
448 purl
= php_http_url_parse(zs
->val
, zs
->len
, flags
);
449 zend_string_release(zs
);
455 php_http_url_t
*php_http_url_from_struct(HashTable
*ht
)
458 php_http_buffer_t buf
;
460 php_http_buffer_init_ex(&buf
, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE
, sizeof(php_http_url_t
)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC
);
461 php_http_buffer_account(&buf
, sizeof(php_http_url_t
));
462 memset(buf
.data
, 0, buf
.used
);
464 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("scheme")))) {
465 zend_string
*zs
= zval_get_string(e
);
466 url(buf
)->scheme
= &buf
.data
[buf
.used
];
467 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
468 zend_string_release(zs
);
470 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("user")))) {
471 zend_string
*zs
= zval_get_string(e
);
472 url(buf
)->user
= &buf
.data
[buf
.used
];
473 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
474 zend_string_release(zs
);
476 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("pass")))) {
477 zend_string
*zs
= zval_get_string(e
);
478 url(buf
)->pass
= &buf
.data
[buf
.used
];
479 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
480 zend_string_release(zs
);
482 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("host")))) {
483 zend_string
*zs
= zval_get_string(e
);
484 url(buf
)->host
= &buf
.data
[buf
.used
];
485 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
486 zend_string_release(zs
);
488 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("port")))) {
489 url(buf
)->port
= (unsigned short) zval_get_long(e
);
491 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("path")))) {
492 zend_string
*zs
= zval_get_string(e
);
493 url(buf
)->path
= &buf
.data
[buf
.used
];
494 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
495 zend_string_release(zs
);
497 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("query")))) {
498 zend_string
*zs
= zval_get_string(e
);
499 url(buf
)->query
= &buf
.data
[buf
.used
];
500 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
501 zend_string_release(zs
);
503 if ((e
= zend_hash_str_find_ind(ht
, ZEND_STRL("fragment")))) {
504 zend_string
*zs
= zval_get_string(e
);
505 url(buf
)->fragment
= &buf
.data
[buf
.used
];
506 url_append(&buf
, php_http_buffer_append(&buf
, zs
->val
, zs
->len
+ 1));
507 zend_string_release(zs
);
513 HashTable
*php_http_url_to_struct(const php_http_url_t
*url
, zval
*strct
)
515 HashTable
*ht
= NULL
;
519 switch (Z_TYPE_P(strct
)) {
531 zend_hash_init(ht
, 8, NULL
, ZVAL_PTR_DTOR
, 0);
534 #define url_struct_add(part) \
535 if (!strct || Z_TYPE_P(strct) == IS_ARRAY) { \
536 zend_hash_str_update(ht, part, lenof(part), &tmp); \
538 zend_update_property(Z_OBJCE_P(strct), strct, part, lenof(part), &tmp); \
539 zval_ptr_dtor(&tmp); \
544 ZVAL_STRING(&tmp
, url
->scheme
);
545 url_struct_add("scheme");
548 ZVAL_STRING(&tmp
, url
->user
);
549 url_struct_add("user");
552 ZVAL_STRING(&tmp
, url
->pass
);
553 url_struct_add("pass");
556 ZVAL_STRING(&tmp
, url
->host
);
557 url_struct_add("host");
560 ZVAL_LONG(&tmp
, url
->port
);
561 url_struct_add("port");
564 ZVAL_STRING(&tmp
, url
->path
);
565 url_struct_add("path");
568 ZVAL_STRING(&tmp
, url
->query
);
569 url_struct_add("query");
572 ZVAL_STRING(&tmp
, url
->fragment
);
573 url_struct_add("fragment");
580 ZEND_RESULT_CODE
php_http_url_encode_hash(HashTable
*hash
, const char *pre_encoded_str
, size_t pre_encoded_len
, char **encoded_str
, size_t *encoded_len
)
582 const char *arg_sep_str
= "&";
583 size_t arg_sep_len
= 1;
584 php_http_buffer_t
*qstr
= php_http_buffer_new();
586 php_http_url_argsep(&arg_sep_str
, &arg_sep_len
);
588 if (SUCCESS
!= php_http_url_encode_hash_ex(hash
, qstr
, arg_sep_str
, arg_sep_len
, "=", 1, pre_encoded_str
, pre_encoded_len
)) {
589 php_http_buffer_free(&qstr
);
593 php_http_buffer_data(qstr
, encoded_str
, encoded_len
);
594 php_http_buffer_free(&qstr
);
599 ZEND_RESULT_CODE
php_http_url_encode_hash_ex(HashTable
*hash
, php_http_buffer_t
*qstr
, const char *arg_sep_str
, size_t arg_sep_len
, const char *val_sep_str
, size_t val_sep_len
, const char *pre_encoded_str
, size_t pre_encoded_len
)
601 if (pre_encoded_len
&& pre_encoded_str
) {
602 php_http_buffer_append(qstr
, pre_encoded_str
, pre_encoded_len
);
605 if (!php_http_params_to_string(qstr
, hash
, arg_sep_str
, arg_sep_len
, "", 0, val_sep_str
, val_sep_len
, PHP_HTTP_PARAMS_QUERY
)) {
619 char buffer
[1]; /* last member */
622 void php_http_url_free(php_http_url_t
**url
)
630 php_http_url_t
*php_http_url_copy(const php_http_url_t
*url
, zend_bool persistent
)
633 const char *end
= NULL
, *url_ptr
= (const char *) url
;
636 end
= MAX(url
->scheme
, end
);
637 end
= MAX(url
->pass
, end
);
638 end
= MAX(url
->user
, end
);
639 end
= MAX(url
->host
, end
);
640 end
= MAX(url
->path
, end
);
641 end
= MAX(url
->query
, end
);
642 end
= MAX(url
->fragment
, end
);
645 end
+= strlen(end
) + 1;
646 cpy_ptr
= pecalloc(1, end
- url_ptr
, persistent
);
647 cpy
= (php_http_url_t
*) cpy_ptr
;
649 memcpy(cpy_ptr
+ sizeof(*cpy
), url_ptr
+ sizeof(*url
), end
- url_ptr
- sizeof(*url
));
651 cpy
->scheme
= url
->scheme
? cpy_ptr
+ (url
->scheme
- url_ptr
) : NULL
;
652 cpy
->pass
= url
->pass
? cpy_ptr
+ (url
->pass
- url_ptr
) : NULL
;
653 cpy
->user
= url
->user
? cpy_ptr
+ (url
->user
- url_ptr
) : NULL
;
654 cpy
->host
= url
->host
? cpy_ptr
+ (url
->host
- url_ptr
) : NULL
;
655 cpy
->path
= url
->path
? cpy_ptr
+ (url
->path
- url_ptr
) : NULL
;
656 cpy
->query
= url
->query
? cpy_ptr
+ (url
->query
- url_ptr
) : NULL
;
657 cpy
->fragment
= url
->fragment
? cpy_ptr
+ (url
->fragment
- url_ptr
) : NULL
;
659 cpy
= ecalloc(1, sizeof(*url
));
662 cpy
->port
= url
->port
;
667 static inline size_t parse_mb_utf8(unsigned *wc
, const char *ptr
, const char *end
)
670 size_t consumed
= utf8towc(&wchar
, (const unsigned char *) ptr
, end
- ptr
);
672 if (!consumed
|| consumed
== (size_t) -1) {
682 #if PHP_HTTP_HAVE_WCHAR
683 static inline size_t parse_mb_loc(unsigned *wc
, const char *ptr
, const char *end
)
690 memset(&ps
, 0, sizeof(ps
));
691 consumed
= mbrtowc(&wchar
, ptr
, end
- ptr
, &ps
);
693 consumed
= mbtowc(&wchar
, ptr
, end
- ptr
);
696 if (!consumed
|| consumed
== (size_t) -1) {
707 typedef enum parse_mb_what
{
716 static const char * const parse_what
[] = {
725 static const char parse_xdigits
[] = "0123456789ABCDEF";
727 static inline size_t parse_mb(struct parse_state
*state
, parse_mb_what_t what
, const char *ptr
, const char *end
, const char *begin
, zend_bool force_silent
)
732 if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
733 consumed
= parse_mb_utf8(&wchar
, ptr
, end
);
735 #if PHP_HTTP_HAVE_WCHAR
736 else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
737 consumed
= parse_mb_loc(&wchar
, ptr
, end
);
742 if (!(state
->flags
& PHP_HTTP_URL_PARSE_TOPCT
) || what
== PARSE_HOSTINFO
|| what
== PARSE_SCHEME
) {
743 if (what
== PARSE_HOSTINFO
&& (state
->flags
& PHP_HTTP_URL_PARSE_TOIDN
)) {
745 } else if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
746 #if PHP_HTTP_HAVE_LIBICU
747 if (!u_isalnum(wchar
)) {
749 if (!isualnum(wchar
)) {
753 #if PHP_HTTP_HAVE_WCHAR
754 } else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
755 if (!iswalnum(wchar
)) {
761 memcpy(&state
->buffer
[state
->offset
], ptr
, consumed
);
762 state
->offset
+= consumed
;
766 for (i
= 0; i
< consumed
; ++i
) {
767 state
->buffer
[state
->offset
++] = '%';
768 state
->buffer
[state
->offset
++] = parse_xdigits
[((unsigned char) ptr
[i
]) >> 4];
769 state
->buffer
[state
->offset
++] = parse_xdigits
[((unsigned char) ptr
[i
]) & 0xf];
776 if (!force_silent
&& !(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
778 php_error_docref(NULL
, E_WARNING
,
779 "Failed to parse %s; unexpected multibyte sequence 0x%x at pos %u in '%s'",
780 parse_what
[what
], wchar
, (unsigned) (ptr
- begin
), begin
);
782 php_error_docref(NULL
, E_WARNING
,
783 "Failed to parse %s; unexpected byte 0x%02x at pos %u in '%s'",
784 parse_what
[what
], (unsigned char) *ptr
, (unsigned) (ptr
- begin
), begin
);
788 if (state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
) {
789 state
->buffer
[state
->offset
++] = *ptr
;
796 static ZEND_RESULT_CODE
parse_userinfo(struct parse_state
*state
, const char *ptr
)
799 const char *password
= NULL
, *end
= state
->ptr
, *tmp
= ptr
;
801 state
->url
.user
= &state
->buffer
[state
->offset
];
807 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
808 php_error_docref(NULL
, E_WARNING
,
809 "Failed to parse password; duplicate ':' at pos %u in '%s'",
810 (unsigned) (ptr
- tmp
), tmp
);
812 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
815 state
->buffer
[state
->offset
++] = *ptr
;
819 state
->buffer
[state
->offset
++] = 0;
820 state
->url
.pass
= &state
->buffer
[state
->offset
];
824 if (ptr
[1] != '%' && (end
- ptr
<= 2 || !isxdigit(*(ptr
+1)) || !isxdigit(*(ptr
+2)))) {
825 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
826 php_error_docref(NULL
, E_WARNING
,
827 "Failed to parse userinfo; invalid percent encoding at pos %u in '%s'",
828 (unsigned) (ptr
- tmp
), tmp
);
830 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
833 state
->buffer
[state
->offset
++] = *ptr
++;
836 state
->buffer
[state
->offset
++] = *ptr
++;
837 state
->buffer
[state
->offset
++] = *ptr
++;
838 state
->buffer
[state
->offset
++] = *ptr
;
842 if ((mb
= parse_mb(state
, PARSE_USERINFO
, ptr
, end
, tmp
, 0))) {
846 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
850 case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
851 case '+': case ',': case ';': case '=': /* sub-delims */
852 case '-': case '.': case '_': case '~': /* unreserved */
853 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
854 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
855 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
856 case 'V': case 'W': case 'X': case 'Y': case 'Z':
857 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
858 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
859 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
860 case 'v': case 'w': case 'x': case 'y': case 'z':
861 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
862 case '7': case '8': case '9':
864 state
->buffer
[state
->offset
++] = *ptr
;
868 } while(++ptr
< end
);
871 state
->buffer
[state
->offset
++] = 0;
876 #if PHP_WIN32 || HAVE_UIDNA_IDNTOASCII
877 typedef size_t (*parse_mb_func
)(unsigned *wc
, const char *ptr
, const char *end
);
878 static ZEND_RESULT_CODE
to_utf16(parse_mb_func fn
, const char *u8
, uint16_t **u16
, size_t *len
)
880 size_t offset
= 0, u8_len
= strlen(u8
);
882 *u16
= ecalloc(4 * sizeof(uint16_t), u8_len
+ 1);
885 while (offset
< u8_len
) {
887 uint16_t buf
[2], *ptr
= buf
;
888 size_t consumed
= fn(&wc
, &u8
[offset
], &u8
[u8_len
]);
892 php_error_docref(NULL
, E_WARNING
, "Failed to parse UTF-8 at pos %zu of '%s'", offset
, u8
);
898 switch (wctoutf16(buf
, wc
)) {
900 (*u16
)[(*len
)++] = *ptr
++;
903 (*u16
)[(*len
)++] = *ptr
++;
908 php_error_docref(NULL
, E_WARNING
, "Failed to convert UTF-32 'U+%X' to UTF-16", wc
);
917 #if PHP_HTTP_HAVE_LIBIDN2
919 __attribute__ ((unused
))
921 static ZEND_RESULT_CODE
parse_gidn_2008(struct parse_state
*state
, size_t prev_len
)
926 if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
927 rv
= idn2_lookup_u8((const unsigned char *) state
->url
.host
, (unsigned char **) &idn
, IDN2_NFC_INPUT
);
929 # if PHP_HTTP_HAVE_WCHAR
930 else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
931 rv
= idn2_lookup_ul(state
->url
.host
, &idn
, 0);
935 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
936 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN (IDNA2008); %s", idn2_strerror(rv
));
938 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
942 size_t idnlen
= strlen(idn
);
943 memcpy(state
->url
.host
, idn
, idnlen
+ 1);
945 state
->offset
+= idnlen
- prev_len
;
951 #if PHP_HTTP_HAVE_LIBIDN
953 __attribute__ ((unused
))
955 static ZEND_RESULT_CODE
parse_gidn_2003(struct parse_state
*state
, size_t prev_len
)
960 if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
961 rv
= idna_to_ascii_8z(state
->url
.host
, &idn
, IDNA_ALLOW_UNASSIGNED
);
963 # if PHP_HTTP_HAVE_WCHAR
964 else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
965 rv
= idna_to_ascii_lz(state
->url
.host
, &idn
, IDNA_ALLOW_UNASSIGNED
);
968 if (rv
!= IDNA_SUCCESS
) {
969 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
970 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN (IDNA2003); %s", idna_strerror(rv
));
972 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
976 size_t idnlen
= strlen(idn
);
977 memcpy(state
->url
.host
, idn
, idnlen
+ 1);
979 state
->offset
+= idnlen
- prev_len
;
985 #if HAVE_UIDNA_IDNTOASCII
986 # if !PHP_HTTP_HAVE_LIBICU
987 typedef uint16_t UChar
;
988 typedef enum { U_ZERO_ERROR
= 0 } UErrorCode
;
989 int32_t uidna_IDNToASCII(const UChar
*src
, int32_t srcLength
, UChar
*dest
, int32_t destCapacity
, int32_t options
, void *parseError
, UErrorCode
*status
);
991 static ZEND_RESULT_CODE
parse_uidn_2003(struct parse_state
*state
, size_t prev_len
)
993 char ebuf
[64] = {0}, *error
= NULL
;
994 uint16_t *uhost_str
, ahost_str
[256];
995 size_t uhost_len
, ahost_len
;
996 UErrorCode rc
= U_ZERO_ERROR
;
998 if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
999 if (SUCCESS
!= to_utf16(parse_mb_utf8
, state
->url
.host
, &uhost_str
, &uhost_len
)) {
1000 error
= "failed to convert to UTF-16";
1003 #if PHP_HTTP_HAVE_WCHAR
1004 } else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
1005 if (SUCCESS
!= to_utf16(parse_mb_loc
, state
->url
.host
, &uhost_str
, &uhost_len
)) {
1006 error
= "failed to convert to UTF-16";
1011 error
= "codepage not specified";
1016 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1018 ahost_len
= uidna_IDNToASCII(uhost_str
, uhost_len
, ahost_str
, 256, 3, NULL
, &rc
);
1020 # pragma GCC diagnostic pop
1024 if (error
> U_ZERO_ERROR
) {
1028 state
->url
.host
[ahost_len
] = '\0';
1029 state
->offset
+= ahost_len
- prev_len
;
1030 while (ahost_len
--) {
1031 state
->url
.host
[ahost_len
] = ahost_str
[ahost_len
];
1038 slprintf(ebuf
, sizeof(ebuf
)-1, "errorcode: %d", rc
);
1041 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN (ICU IDNA2003); %s", error
);
1047 #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
1048 static ZEND_RESULT_CODE
parse_uidn_2008(struct parse_state
*state
, size_t prev_len
)
1050 char *error
= NULL
, ebuf
[64] = {0};
1051 UErrorCode rc
= U_ZERO_ERROR
;
1052 UIDNAInfo info
= UIDNA_INFO_INITIALIZER
;
1053 UIDNA
*uidna
= uidna_openUTS46(UIDNA_ALLOW_UNASSIGNED
, &rc
);
1055 if (!uidna
|| U_FAILURE(rc
)) {
1059 if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
1060 char ahost_str
[256];
1061 size_t ahost_len
= uidna_nameToASCII_UTF8(uidna
, state
->url
.host
, -1, ahost_str
, sizeof(ahost_str
)-1, &info
, &rc
);
1063 if (U_FAILURE(rc
) || info
.errors
) {
1067 memcpy(state
->url
.host
, ahost_str
, ahost_len
);
1068 state
->url
.host
[ahost_len
] = '\0';
1069 state
->offset
+= ahost_len
- prev_len
;
1071 #if PHP_HTTP_HAVE_WCHAR
1072 } else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
1073 uint16_t *uhost_str
, whost_str
[256];
1074 size_t uhost_len
, whost_len
;
1076 if (SUCCESS
!= to_utf16(parse_mb_loc
, state
->url
.host
, &uhost_str
, &uhost_len
)) {
1077 error
= "could not convert to UTF-16";
1081 whost_len
= uidna_nameToASCII(uidna
, uhost_str
, uhost_len
, whost_str
, sizeof(whost_str
)-1, &info
, &rc
);
1084 if (U_FAILURE(rc
) || info
.errors
) {
1088 state
->url
.host
[whost_len
] = '\0';
1089 state
->offset
+= whost_len
- prev_len
;
1090 while (whost_len
--) {
1091 state
->url
.host
[whost_len
] = whost_str
[whost_len
];
1095 error
= "codepage not specified";
1104 if (U_FAILURE(rc
)) {
1105 slprintf(ebuf
, sizeof(ebuf
)-1, "%s", u_errorName(rc
));
1107 } else if (info
.errors
) {
1108 slprintf(ebuf
, sizeof(ebuf
)-1, "ICU IDNA error codes: 0x%x", info
.errors
);
1111 error
= "unknown error";
1114 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN (ICU IDNA2008); %s", error
);
1121 #if PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2
1123 __attribute__ ((unused
))
1125 static ZEND_RESULT_CODE
parse_kidn(struct parse_state
*state
, size_t prev_len
)
1128 #if PHP_HTTP_HAVE_LIBIDNKIT
1129 int actions
= IDN_DELIMMAP
|IDN_LOCALMAP
|IDN_NAMEPREP
|IDN_IDNCONV
|IDN_LENCHECK
;
1130 #elif PHP_HTTP_HAVE_LIBIDNKIT2
1131 int actions
= IDN_MAP
|IDN_ASCLOWER
|IDN_RTCONV
|IDN_PROHCHECK
|IDN_NFCCHECK
|IDN_PREFCHECK
|IDN_COMBCHECK
|IDN_CTXOLITECHECK
|IDN_BIDICHECK
|IDN_LOCALCHECK
|IDN_IDNCONV
|IDN_LENCHECK
|IDN_RTCHECK
;
1133 char ahost_str
[256] = {0};
1135 if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
1136 #if PHP_HTTP_HAVE_LIBIDNKIT
1137 actions
|= IDN_LOCALCONV
;
1138 #elif PHP_HTTP_HAVE_LIBIDNKIT2
1139 actions
|= IDN_UNICODECONV
;
1143 rc
= idn_encodename(actions
, state
->url
.host
, ahost_str
, 256);
1144 if (rc
== idn_success
) {
1145 size_t ahost_len
= strlen(ahost_str
);
1147 memcpy(state
->url
.host
, ahost_str
, ahost_len
+ 1);
1148 state
->offset
+= ahost_len
- prev_len
;
1152 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN; %s", idn_result_tostring(rc
));
1159 static ZEND_RESULT_CODE
parse_widn_2003(struct parse_state
*state
, size_t prev_len
)
1162 uint16_t *uhost_str
, ahost_str
[256];
1163 size_t uhost_len
, ahost_len
;
1165 if (state
->flags
& PHP_HTTP_URL_PARSE_MBUTF8
) {
1166 if (SUCCESS
!= to_utf16(parse_mb_utf8
, state
->url
.host
, &uhost_str
, &uhost_len
)) {
1167 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN");
1170 #if PHP_HTTP_HAVE_WCHAR
1171 } else if (state
->flags
& PHP_HTTP_URL_PARSE_MBLOC
) {
1172 if (SUCCESS
!= to_utf16(parse_mb_loc
, state
->url
.host
, &uhost_str
, &uhost_len
)) {
1173 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN");
1178 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN");
1182 if (!IdnToAscii(IDN_ALLOW_UNASSIGNED
, uhost_str
, uhost_len
, ahost_str
, 256)) {
1184 php_error_docref(NULL
, E_WARNING
, "Failed to parse IDN");
1189 ahost_len
= wcslen(ahost_str
);
1190 state
->url
.host
[ahost_len
] = '\0';
1191 state
->offset
+= ahost_len
- prev_len
;
1192 while (ahost_len
--) {
1193 state
->url
.host
[ahost_len
] = ahost_str
[ahost_len
];
1200 static ZEND_RESULT_CODE
parse_idna(struct parse_state
*state
, size_t len
)
1202 #if PHP_HTTP_HAVE_IDNA2008
1203 if ((state
->flags
& PHP_HTTP_URL_PARSE_TOIDN_2008
) == PHP_HTTP_URL_PARSE_TOIDN_2008
1204 # if PHP_HTTP_HAVE_IDNA2003
1205 || (state
->flags
& PHP_HTTP_URL_PARSE_TOIDN_2003
) != PHP_HTTP_URL_PARSE_TOIDN_2003
1208 #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
1209 return parse_uidn_2008(state
, len
);
1210 #elif PHP_HTTP_HAVE_LIBIDN2
1211 return parse_gidn_2008(state
, len
);
1212 #elif PHP_HTTP_HAVE_LIBIDNKIT2
1213 return parse_kidn(state
, len
);
1218 #if PHP_HTTP_HAVE_IDNA2003
1219 if ((state
->flags
& PHP_HTTP_URL_PARSE_TOIDN_2003
) == PHP_HTTP_URL_PARSE_TOIDN_2003
1220 # if PHP_HTTP_HAVE_IDNA2008
1221 || (state
->flags
& PHP_HTTP_URL_PARSE_TOIDN_2008
) != PHP_HTTP_URL_PARSE_TOIDN_2008
1224 #if HAVE_UIDNA_IDNTOASCII
1225 return parse_uidn_2003(state
, len
);
1226 #elif PHP_HTTP_HAVE_LIBIDN
1227 return parse_gidn_2003(state
, len
);
1228 #elif PHP_HTTP_HAVE_LIBIDNKIT
1229 return parse_kidn(state
, len
);
1235 return parse_widn_2003(state
, len
);
1238 #if PHP_HTTP_HAVE_LIBICU && HAVE_UIDNA_NAMETOASCII_UTF8
1239 return parse_uidn_2008(state
, len
);
1240 #elif PHP_HTTP_HAVE_LIBIDN2
1241 return parse_gidn_2008(state
, len
);
1242 #elif PHP_HTTP_HAVE_LIBIDNKIT2
1243 return parse_kidn(state
, len
);
1244 #elif HAVE_UIDNA_IDNTOASCII
1245 return parse_uidn_2003(state
, len
);
1246 #elif PHP_HTTP_HAVE_LIBIDN
1247 return parse_gidn_2003(state
, len
);
1248 #elif PHP_HTTP_HAVE_LIBIDNKIT
1249 return parse_kidn(state
, len
);
1256 static const char *parse_ip6(struct parse_state
*state
, const char *ptr
)
1259 const char *error
= NULL
, *end
= state
->ptr
, *tmp
= memchr(ptr
, ']', end
- ptr
);
1262 size_t addrlen
= tmp
- ptr
+ 1;
1263 char buf
[16], *addr
= estrndup(ptr
+ 1, addrlen
- 2);
1264 int rv
= inet_pton(AF_INET6
, addr
, buf
);
1267 state
->buffer
[state
->offset
] = '[';
1268 state
->url
.host
= &state
->buffer
[state
->offset
];
1269 inet_ntop(AF_INET6
, buf
, state
->url
.host
+ 1, state
->maxlen
- state
->offset
);
1270 state
->offset
+= strlen(state
->url
.host
);
1271 state
->buffer
[state
->offset
++] = ']';
1272 state
->buffer
[state
->offset
++] = 0;
1274 } else if (rv
== -1) {
1276 error
= strerror(errno
);
1278 error
= "unexpected '['";
1283 error
= "expected ']'";
1287 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1288 php_error_docref(NULL
, E_WARNING
, "Failed to parse hostinfo; %s at pos %u in '%s'", error
, pos
, ptr
);
1297 static ZEND_RESULT_CODE
parse_hostinfo(struct parse_state
*state
, const char *ptr
)
1299 size_t mb
, len
= state
->offset
;
1300 const char *end
= state
->ptr
, *tmp
= ptr
, *port
= NULL
, *label
= NULL
;
1303 if (*ptr
== '[' && !(ptr
= parse_ip6(state
, ptr
))) {
1304 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1311 if (ptr
!= end
) do {
1315 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1316 php_error_docref(NULL
, E_WARNING
,
1317 "Failed to parse port; unexpected ':' at pos %u in '%s'",
1318 (unsigned) (ptr
- tmp
), tmp
);
1320 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1328 if (ptr
[1] != '%' && (end
- ptr
<= 2 || !isxdigit(*(ptr
+1)) || !isxdigit(*(ptr
+2)))) {
1329 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1330 php_error_docref(NULL
, E_WARNING
,
1331 "Failed to parse hostinfo; invalid percent encoding at pos %u in '%s'",
1332 (unsigned) (ptr
- tmp
), tmp
);
1334 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1337 state
->buffer
[state
->offset
++] = *ptr
++;
1340 state
->buffer
[state
->offset
++] = *ptr
++;
1341 state
->buffer
[state
->offset
++] = *ptr
++;
1342 state
->buffer
[state
->offset
++] = *ptr
;
1346 if (port
|| !label
) {
1347 /* sort of a compromise, just ensure we don't end up
1348 * with a dot at the beginning or two consecutive dots
1350 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1351 php_error_docref(NULL
, E_WARNING
,
1352 "Failed to parse %s; unexpected '%c' at pos %u in '%s'",
1353 port
? "port" : "host",
1354 (unsigned char) *ptr
, (unsigned) (ptr
- tmp
), tmp
);
1356 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1361 state
->buffer
[state
->offset
++] = *ptr
;
1367 /* sort of a compromise, just ensure we don't end up
1368 * with a hyphen at the beginning
1370 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1371 php_error_docref(NULL
, E_WARNING
,
1372 "Failed to parse %s; unexpected '%c' at pos %u in '%s'",
1373 port
? "port" : "host",
1374 (unsigned char) *ptr
, (unsigned) (ptr
- tmp
), tmp
);
1376 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1382 case '_': case '~': /* unreserved */
1383 case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
1384 case '+': case ',': case ';': case '=': /* sub-delims */
1385 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1386 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1387 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1388 case 'V': case 'W': case 'X': case 'Y': case 'Z':
1389 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1390 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1391 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1392 case 'v': case 'w': case 'x': case 'y': case 'z':
1394 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1395 php_error_docref(NULL
, E_WARNING
,
1396 "Failed to parse port; unexpected char '%c' at pos %u in '%s'",
1397 (unsigned char) *ptr
, (unsigned) (ptr
- tmp
), tmp
);
1399 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1405 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
1406 case '7': case '8': case '9':
1409 state
->url
.port
*= 10;
1410 state
->url
.port
+= *ptr
- '0';
1413 state
->buffer
[state
->offset
++] = *ptr
;
1421 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1422 php_error_docref(NULL
, E_WARNING
,
1423 "Failed to parse port; unexpected byte 0x%02x at pos %u in '%s'",
1424 (unsigned char) *ptr
, (unsigned) (ptr
- tmp
), tmp
);
1426 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1430 } else if (!(mb
= parse_mb(state
, PARSE_HOSTINFO
, ptr
, end
, tmp
, 0))) {
1431 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1439 } while (++ptr
< end
);
1441 if (!state
->url
.host
) {
1442 len
= state
->offset
- len
;
1443 state
->url
.host
= &state
->buffer
[state
->offset
- len
];
1444 state
->buffer
[state
->offset
++] = 0;
1447 if (state
->flags
& PHP_HTTP_URL_PARSE_TOIDN
) {
1448 return parse_idna(state
, len
);
1454 static const char *parse_authority(struct parse_state
*state
)
1456 const char *tmp
= state
->ptr
, *host
= NULL
;
1459 switch (*state
->ptr
) {
1461 /* userinfo delimiter */
1463 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1464 php_error_docref(NULL
, E_WARNING
,
1465 "Failed to parse userinfo; unexpected '@'");
1467 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1472 host
= state
->ptr
+ 1;
1473 if (tmp
!= state
->ptr
&& SUCCESS
!= parse_userinfo(state
, tmp
)) {
1476 tmp
= state
->ptr
+ 1;
1484 /* host delimiter */
1485 if (tmp
!= state
->ptr
&& SUCCESS
!= parse_hostinfo(state
, tmp
)) {
1490 } while (++state
->ptr
<= state
->end
);
1496 static const char *parse_path(struct parse_state
*state
)
1501 /* is there actually a path to parse? */
1506 state
->url
.path
= &state
->buffer
[state
->offset
];
1509 switch (*state
->ptr
) {
1515 if (state
->ptr
[1] != '%' && (state
->end
- state
->ptr
<= 2 || !isxdigit(*(state
->ptr
+1)) || !isxdigit(*(state
->ptr
+2)))) {
1516 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1517 php_error_docref(NULL
, E_WARNING
,
1518 "Failed to parse path; invalid percent encoding at pos %u in '%s'",
1519 (unsigned) (state
->ptr
- tmp
), tmp
);
1521 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1524 state
->buffer
[state
->offset
++] = *state
->ptr
;
1527 state
->buffer
[state
->offset
++] = *state
->ptr
++;
1528 state
->buffer
[state
->offset
++] = *state
->ptr
++;
1529 state
->buffer
[state
->offset
++] = *state
->ptr
;
1532 case '/': /* yeah, well */
1533 case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
1534 case '+': case ',': case ';': case '=': /* sub-delims */
1535 case '-': case '.': case '_': case '~': /* unreserved */
1536 case ':': case '@': /* pchar */
1537 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1538 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1539 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1540 case 'V': case 'W': case 'X': case 'Y': case 'Z':
1541 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1542 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1543 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1544 case 'v': case 'w': case 'x': case 'y': case 'z':
1545 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
1546 case '7': case '8': case '9':
1548 state
->buffer
[state
->offset
++] = *state
->ptr
;
1552 if (!(mb
= parse_mb(state
, PARSE_PATH
, state
->ptr
, state
->end
, tmp
, 0))) {
1553 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1558 state
->ptr
+= mb
- 1;
1560 } while (++state
->ptr
< state
->end
);
1563 /* did we have any path component ? */
1564 if (tmp
!= state
->ptr
) {
1565 state
->buffer
[state
->offset
++] = 0;
1567 state
->url
.path
= NULL
;
1572 static const char *parse_query(struct parse_state
*state
)
1575 const char *tmp
= state
->ptr
+ !!*state
->ptr
;
1577 /* is there actually a query to parse? */
1578 if (*state
->ptr
!= '?') {
1582 /* skip initial '?' */
1584 state
->url
.query
= &state
->buffer
[state
->offset
];
1586 while (state
->ptr
< state
->end
) {
1587 switch (*state
->ptr
) {
1592 if (state
->ptr
[1] != '%' && (state
->end
- state
->ptr
<= 2 || !isxdigit(*(state
->ptr
+1)) || !isxdigit(*(state
->ptr
+2)))) {
1593 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1594 php_error_docref(NULL
, E_WARNING
,
1595 "Failed to parse query; invalid percent encoding at pos %u in '%s'",
1596 (unsigned) (state
->ptr
- tmp
), tmp
);
1598 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1601 /* fallthrough, pct-encode the percent sign */
1603 state
->buffer
[state
->offset
++] = *state
->ptr
++;
1604 state
->buffer
[state
->offset
++] = *state
->ptr
++;
1605 state
->buffer
[state
->offset
++] = *state
->ptr
;
1612 case '|': case '\\': case '^': case '`': case '"': case ' ':
1613 /* RFC1738 unsafe */
1614 if (state
->flags
& PHP_HTTP_URL_PARSE_TOPCT
) {
1615 state
->buffer
[state
->offset
++] = '%';
1616 state
->buffer
[state
->offset
++] = parse_xdigits
[((unsigned char) *state
->ptr
) >> 4];
1617 state
->buffer
[state
->offset
++] = parse_xdigits
[((unsigned char) *state
->ptr
) & 0xf];
1622 case '?': case '/': /* yeah, well */
1623 case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
1624 case '+': case ',': case ';': case '=': /* sub-delims */
1625 case '-': case '.': case '_': case '~': /* unreserved */
1626 case ':': case '@': /* pchar */
1627 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1628 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1629 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1630 case 'V': case 'W': case 'X': case 'Y': case 'Z':
1631 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1632 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1633 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1634 case 'v': case 'w': case 'x': case 'y': case 'z':
1635 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
1636 case '7': case '8': case '9':
1638 state
->buffer
[state
->offset
++] = *state
->ptr
;
1642 if (!(mb
= parse_mb(state
, PARSE_QUERY
, state
->ptr
, state
->end
, tmp
, 0))) {
1643 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1648 state
->ptr
+= mb
- 1;
1655 state
->buffer
[state
->offset
++] = 0;
1659 static const char *parse_fragment(struct parse_state
*state
)
1664 /* is there actually a fragment to parse? */
1665 if (*state
->ptr
!= '#') {
1669 /* skip initial '#' */
1671 state
->url
.fragment
= &state
->buffer
[state
->offset
];
1674 switch (*state
->ptr
) {
1676 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1677 php_error_docref(NULL
, E_WARNING
,
1678 "Failed to parse fragment; invalid fragment identifier at pos %u in '%s'",
1679 (unsigned) (state
->ptr
- tmp
), tmp
);
1681 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1684 state
->buffer
[state
->offset
++] = *state
->ptr
;
1688 if (state
->ptr
[1] != '%' && (state
->end
- state
->ptr
<= 2 || !isxdigit(*(state
->ptr
+1)) || !isxdigit(*(state
->ptr
+2)))) {
1689 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1690 php_error_docref(NULL
, E_WARNING
,
1691 "Failed to parse fragment; invalid percent encoding at pos %u in '%s'",
1692 (unsigned) (state
->ptr
- tmp
), tmp
);
1694 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1699 state
->buffer
[state
->offset
++] = *state
->ptr
++;
1700 state
->buffer
[state
->offset
++] = *state
->ptr
++;
1701 state
->buffer
[state
->offset
++] = *state
->ptr
;
1709 case '|': case '\\': case '^': case '`': case '"': case ' ':
1710 /* RFC1738 unsafe */
1711 if (state
->flags
& PHP_HTTP_URL_PARSE_TOPCT
) {
1712 state
->buffer
[state
->offset
++] = '%';
1713 state
->buffer
[state
->offset
++] = parse_xdigits
[((unsigned char) *state
->ptr
) >> 4];
1714 state
->buffer
[state
->offset
++] = parse_xdigits
[((unsigned char) *state
->ptr
) & 0xf];
1720 case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
1721 case '+': case ',': case ';': case '=': /* sub-delims */
1722 case '-': case '.': case '_': case '~': /* unreserved */
1723 case ':': case '@': /* pchar */
1724 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1725 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1726 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1727 case 'V': case 'W': case 'X': case 'Y': case 'Z':
1728 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1729 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1730 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1731 case 'v': case 'w': case 'x': case 'y': case 'z':
1732 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
1733 case '7': case '8': case '9':
1735 state
->buffer
[state
->offset
++] = *state
->ptr
;
1739 if (!(mb
= parse_mb(state
, PARSE_FRAGMENT
, state
->ptr
, state
->end
, tmp
, 0))) {
1740 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1745 state
->ptr
+= mb
- 1;
1747 } while (++state
->ptr
< state
->end
);
1749 state
->buffer
[state
->offset
++] = 0;
1753 static const char *parse_hier(struct parse_state
*state
)
1755 if (*state
->ptr
== '/') {
1756 if (state
->end
- state
->ptr
> 1) {
1757 if (*(state
->ptr
+ 1) == '/') {
1759 if (!(state
->ptr
= parse_authority(state
))) {
1765 return parse_path(state
);
1768 static const char *parse_scheme(struct parse_state
*state
)
1771 const char *tmp
= state
->ptr
;
1774 switch (*state
->ptr
) {
1776 /* scheme delimiter */
1777 state
->url
.scheme
= &state
->buffer
[0];
1778 state
->buffer
[state
->offset
++] = 0;
1779 return ++state
->ptr
;
1781 case '0': case '1': case '2': case '3': case '4': case '5': case '6':
1782 case '7': case '8': case '9':
1783 case '+': case '-': case '.':
1784 if (state
->ptr
== tmp
) {
1788 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
1789 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
1790 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
1791 case 'V': case 'W': case 'X': case 'Y': case 'Z':
1792 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1793 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1794 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1795 case 'v': case 'w': case 'x': case 'y': case 'z':
1797 state
->buffer
[state
->offset
++] = *state
->ptr
;
1801 if (!(mb
= parse_mb(state
, PARSE_SCHEME
, state
->ptr
, state
->end
, tmp
, 1))) {
1804 state
->ptr
+= mb
- 1;
1806 } while (++state
->ptr
< state
->end
);
1810 return state
->ptr
= tmp
;
1813 php_http_url_t
*php_http_url_parse(const char *str
, size_t len
, unsigned flags
)
1815 size_t maxlen
= 3 * len
+ 8 /* null bytes for all components */;
1816 struct parse_state
*state
= ecalloc(1, sizeof(*state
) + maxlen
);
1818 state
->end
= str
+ len
;
1820 state
->flags
= flags
;
1821 state
->maxlen
= maxlen
;
1823 if (!parse_scheme(state
)) {
1824 if (!(flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1825 php_error_docref(NULL
, E_WARNING
, "Failed to parse URL scheme: '%s'", state
->ptr
);
1831 if (!parse_hier(state
)) {
1836 if (!parse_query(state
)) {
1837 if (!(flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1838 php_error_docref(NULL
, E_WARNING
, "Failed to parse URL query: '%s'", state
->ptr
);
1844 if (!parse_fragment(state
)) {
1845 if (!(flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1846 php_error_docref(NULL
, E_WARNING
, "Failed to parse URL fragment: '%s'", state
->ptr
);
1852 return (php_http_url_t
*) state
;
1855 php_http_url_t
*php_http_url_parse_authority(const char *str
, size_t len
, unsigned flags
)
1857 size_t maxlen
= 3 * len
;
1858 struct parse_state
*state
= ecalloc(1, sizeof(*state
) + maxlen
);
1860 state
->end
= str
+ len
;
1862 state
->flags
= flags
;
1863 state
->maxlen
= maxlen
;
1865 if (!(state
->ptr
= parse_authority(state
))) {
1870 if (state
->ptr
!= state
->end
) {
1871 if (!(state
->flags
& PHP_HTTP_URL_SILENT_ERRORS
)) {
1872 php_error_docref(NULL
, E_WARNING
,
1873 "Failed to parse URL authority, unexpected character at pos %u in '%s'",
1874 (unsigned) (state
->ptr
- str
), str
);
1876 if (!(state
->flags
& PHP_HTTP_URL_IGNORE_ERRORS
)) {
1882 return (php_http_url_t
*) state
;
1885 static zend_class_entry
*php_http_url_class_entry
;
1886 static zend_class_entry
*php_http_env_url_class_entry
;
1888 zend_class_entry
*php_http_url_get_class_entry(void)
1890 return php_http_url_class_entry
;
1893 zend_class_entry
*php_http_get_env_url_class_entry(void)
1895 return php_http_env_url_class_entry
;
1898 ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl___construct
, 0, 0, 0)
1899 ZEND_ARG_INFO(0, old_url
)
1900 ZEND_ARG_INFO(0, new_url
)
1901 ZEND_ARG_INFO(0, flags
)
1902 ZEND_END_ARG_INFO();
1903 PHP_METHOD(HttpUrl
, __construct
)
1905 zval
*new_url
= NULL
, *old_url
= NULL
;
1906 zend_long flags
= 0;
1907 zend_error_handling zeh
;
1909 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "|z!z!l", &old_url
, &new_url
, &flags
), invalid_arg
, return);
1911 /* always set http\Url::FROM_ENV for instances of http\Env\Url */
1912 if (instanceof_function(Z_OBJCE_P(getThis()), php_http_env_url_class_entry
)) {
1913 flags
|= PHP_HTTP_URL_FROM_ENV
;
1916 if (flags
& (PHP_HTTP_URL_SILENT_ERRORS
|PHP_HTTP_URL_IGNORE_ERRORS
)) {
1917 zend_replace_error_handling(EH_NORMAL
, NULL
, &zeh
);
1919 zend_replace_error_handling(EH_THROW
, php_http_get_exception_bad_url_class_entry(), &zeh
);
1922 php_http_url_t
*res_purl
, *new_purl
= NULL
, *old_purl
= NULL
;
1925 new_purl
= php_http_url_from_zval(new_url
, flags
);
1927 zend_restore_error_handling(&zeh
);
1932 old_purl
= php_http_url_from_zval(old_url
, flags
);
1935 php_http_url_free(&new_purl
);
1937 zend_restore_error_handling(&zeh
);
1942 res_purl
= php_http_url_mod(old_purl
, new_purl
, flags
);
1943 php_http_url_to_struct(res_purl
, getThis());
1945 php_http_url_free(&res_purl
);
1947 php_http_url_free(&old_purl
);
1950 php_http_url_free(&new_purl
);
1953 zend_restore_error_handling(&zeh
);
1956 ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_mod
, 0, 0, 1)
1957 ZEND_ARG_INFO(0, more_url_parts
)
1958 ZEND_ARG_INFO(0, flags
)
1959 ZEND_END_ARG_INFO();
1960 PHP_METHOD(HttpUrl
, mod
)
1962 zval
*new_url
= NULL
;
1963 zend_long flags
= PHP_HTTP_URL_JOIN_PATH
| PHP_HTTP_URL_JOIN_QUERY
| PHP_HTTP_URL_SANITIZE_PATH
;
1964 zend_error_handling zeh
;
1966 php_http_expect(SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "z!|l", &new_url
, &flags
), invalid_arg
, return);
1968 if (flags
& (PHP_HTTP_URL_SILENT_ERRORS
|PHP_HTTP_URL_IGNORE_ERRORS
)) {
1969 zend_replace_error_handling(EH_NORMAL
, NULL
, &zeh
);
1971 zend_replace_error_handling(EH_THROW
, php_http_get_exception_bad_url_class_entry(), &zeh
);
1974 php_http_url_t
*new_purl
= NULL
, *old_purl
= NULL
;
1977 new_purl
= php_http_url_from_zval(new_url
, flags
);
1979 zend_restore_error_handling(&zeh
);
1984 if ((old_purl
= php_http_url_from_struct(HASH_OF(getThis())))) {
1985 php_http_url_t
*res_purl
;
1987 ZVAL_OBJ(return_value
, zend_objects_clone_obj(getThis()));
1989 res_purl
= php_http_url_mod(old_purl
, new_purl
, flags
);
1990 php_http_url_to_struct(res_purl
, return_value
);
1992 php_http_url_free(&res_purl
);
1993 php_http_url_free(&old_purl
);
1996 php_http_url_free(&new_purl
);
1999 zend_restore_error_handling(&zeh
);
2002 ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toString
, 0, 0, 0)
2003 ZEND_END_ARG_INFO();
2004 PHP_METHOD(HttpUrl
, toString
)
2006 if (SUCCESS
== zend_parse_parameters_none()) {
2007 php_http_url_t
*purl
;
2009 if ((purl
= php_http_url_from_struct(HASH_OF(getThis())))) {
2013 php_http_url_to_string(purl
, &str
, &len
, 0);
2014 php_http_url_free(&purl
);
2015 RETURN_STR(php_http_cs2zs(str
, len
));
2018 RETURN_EMPTY_STRING();
2021 ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toArray
, 0, 0, 0)
2022 ZEND_END_ARG_INFO();
2023 PHP_METHOD(HttpUrl
, toArray
)
2025 php_http_url_t
*purl
;
2027 if (SUCCESS
!= zend_parse_parameters_none()) {
2031 /* strip any non-URL properties */
2032 purl
= php_http_url_from_struct(HASH_OF(getThis()));
2033 php_http_url_to_struct(purl
, return_value
);
2034 php_http_url_free(&purl
);
2037 static zend_function_entry php_http_url_methods
[] = {
2038 PHP_ME(HttpUrl
, __construct
, ai_HttpUrl___construct
, ZEND_ACC_PUBLIC
)
2039 PHP_ME(HttpUrl
, mod
, ai_HttpUrl_mod
, ZEND_ACC_PUBLIC
)
2040 PHP_ME(HttpUrl
, toString
, ai_HttpUrl_toString
, ZEND_ACC_PUBLIC
)
2041 ZEND_MALIAS(HttpUrl
, __toString
, toString
, ai_HttpUrl_toString
, ZEND_ACC_PUBLIC
)
2042 PHP_ME(HttpUrl
, toArray
, ai_HttpUrl_toArray
, ZEND_ACC_PUBLIC
)
2043 EMPTY_FUNCTION_ENTRY
2046 PHP_MINIT_FUNCTION(http_url
)
2048 zend_class_entry ce
= {0};
2050 INIT_NS_CLASS_ENTRY(ce
, "http", "Url", php_http_url_methods
);
2051 php_http_url_class_entry
= zend_register_internal_class(&ce
);
2053 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC
);
2054 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("user"), ZEND_ACC_PUBLIC
);
2055 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("pass"), ZEND_ACC_PUBLIC
);
2056 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("host"), ZEND_ACC_PUBLIC
);
2057 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("port"), ZEND_ACC_PUBLIC
);
2058 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("path"), ZEND_ACC_PUBLIC
);
2059 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("query"), ZEND_ACC_PUBLIC
);
2060 zend_declare_property_null(php_http_url_class_entry
, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC
);
2062 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE
);
2063 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH
);
2064 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY
);
2065 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER
);
2066 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS
);
2067 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH
);
2068 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT
);
2069 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH
);
2070 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY
);
2071 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT
);
2072 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL
);
2073 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV
);
2074 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("SANITIZE_PATH"), PHP_HTTP_URL_SANITIZE_PATH
);
2076 #if PHP_HTTP_HAVE_WCHAR
2077 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("PARSE_MBLOC"), PHP_HTTP_URL_PARSE_MBLOC
);
2079 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("PARSE_MBUTF8"), PHP_HTTP_URL_PARSE_MBUTF8
);
2080 #if PHP_HTTP_HAVE_LIBIDN2 || PHP_HTTP_HAVE_LIBIDN || PHP_HTTP_HAVE_LIBIDNKIT || PHP_HTTP_HAVE_LIBIDNKIT2 || HAVE_UIDNA_IDNTOASCII || HAVE_UIDNA_NAMETOASCII_UTF8
2081 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("PARSE_TOIDN"), PHP_HTTP_URL_PARSE_TOIDN
);
2082 # if PHP_HTTP_HAVE_IDNA2003
2083 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("PARSE_TOIDN_2003"), PHP_HTTP_URL_PARSE_TOIDN_2003
);
2085 # if PHP_HTTP_HAVE_IDNA2008
2086 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("PARSE_TOIDN_2008"), PHP_HTTP_URL_PARSE_TOIDN_2008
);
2089 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("PARSE_TOPCT"), PHP_HTTP_URL_PARSE_TOPCT
);
2091 INIT_NS_CLASS_ENTRY(ce
, "http\\Env", "Url", php_http_url_methods
);
2092 php_http_env_url_class_entry
= zend_register_internal_class_ex(&ce
, php_http_url_class_entry
);
2094 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("IGNORE_ERRORS"), PHP_HTTP_URL_IGNORE_ERRORS
);
2095 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("SILENT_ERRORS"), PHP_HTTP_URL_SILENT_ERRORS
);
2097 zend_declare_class_constant_long(php_http_url_class_entry
, ZEND_STRL("STDFLAGS"), PHP_HTTP_URL_STDFLAGS
);
2108 * vim600: noet sw=4 ts=4 fdm=marker
2109 * vim<600: noet sw=4 ts=4