1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Jim Winstead <jimw@php.net> |
16 : +----------------------------------------------------------------------+
17 : */
18 : /* $Id: url.c 290199 2009-11-04 13:44:10Z iliaa $ */
19 :
20 : #include <stdlib.h>
21 : #include <string.h>
22 : #include <ctype.h>
23 : #include <sys/types.h>
24 :
25 : #include "php.h"
26 :
27 : #include "url.h"
28 : #include "file.h"
29 : #ifdef _OSD_POSIX
30 : #ifndef APACHE
31 : #error On this EBCDIC platform, PHP is only supported as an Apache module.
32 : #else /*APACHE*/
33 : #ifndef CHARSET_EBCDIC
34 : #define CHARSET_EBCDIC /* this machine uses EBCDIC, not ASCII! */
35 : #endif
36 : #include "ebcdic.h"
37 : #endif /*APACHE*/
38 : #endif /*_OSD_POSIX*/
39 :
40 : /* {{{ free_url
41 : */
42 : PHPAPI void php_url_free(php_url *theurl)
43 995 : {
44 995 : if (theurl->scheme)
45 741 : efree(theurl->scheme);
46 995 : if (theurl->user)
47 122 : efree(theurl->user);
48 995 : if (theurl->pass)
49 73 : efree(theurl->pass);
50 995 : if (theurl->host)
51 623 : efree(theurl->host);
52 995 : if (theurl->path)
53 859 : efree(theurl->path);
54 995 : if (theurl->query)
55 234 : efree(theurl->query);
56 995 : if (theurl->fragment)
57 123 : efree(theurl->fragment);
58 995 : efree(theurl);
59 995 : }
60 : /* }}} */
61 :
62 : /* {{{ php_replace_controlchars
63 : */
64 : PHPAPI char *php_replace_controlchars_ex(char *str, int len)
65 3192 : {
66 3192 : unsigned char *s = (unsigned char *)str;
67 3192 : unsigned char *e = (unsigned char *)str + len;
68 :
69 3192 : if (!str) {
70 0 : return (NULL);
71 : }
72 :
73 33323 : while (s < e) {
74 :
75 26939 : if (iscntrl(*s)) {
76 0 : *s='_';
77 : }
78 26939 : s++;
79 : }
80 :
81 3192 : return (str);
82 : }
83 : /* }}} */
84 :
85 : PHPAPI char *php_replace_controlchars(char *str)
86 0 : {
87 0 : return php_replace_controlchars_ex(str, strlen(str));
88 : }
89 :
90 : PHPAPI php_url *php_url_parse(char const *str)
91 315 : {
92 315 : return php_url_parse_ex(str, strlen(str));
93 : }
94 :
95 : /* {{{ php_url_parse
96 : */
97 : PHPAPI php_url *php_url_parse_ex(char const *str, int length)
98 1367 : {
99 : char port_buf[6];
100 1367 : php_url *ret = ecalloc(1, sizeof(php_url));
101 : char const *s, *e, *p, *pp, *ue;
102 :
103 1367 : s = str;
104 1367 : ue = s + length;
105 :
106 : /* parse scheme */
107 2322 : if ((e = memchr(s, ':', length)) && (e - s)) {
108 : /* validate scheme */
109 1153 : p = s;
110 7129 : while (p < e) {
111 : /* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */
112 4823 : if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') {
113 0 : if (e + 1 < ue) {
114 0 : goto parse_port;
115 : } else {
116 0 : goto just_path;
117 : }
118 : }
119 4823 : p++;
120 : }
121 :
122 1153 : if (*(e + 1) == '\0') { /* only scheme is available */
123 11 : ret->scheme = estrndup(s, (e - s));
124 11 : php_replace_controlchars_ex(ret->scheme, (e - s));
125 11 : goto end;
126 : }
127 :
128 : /*
129 : * certain schemas like mailto: and zlib: may not have any / after them
130 : * this check ensures we support those.
131 : */
132 1142 : if (*(e+1) != '/') {
133 : /* check if the data we get is a port this allows us to
134 : * correctly parse things like a.com:80
135 : */
136 91 : p = e + 1;
137 332 : while (isdigit(*p)) {
138 150 : p++;
139 : }
140 :
141 91 : if ((*p == '\0' || *p == '/') && (p - e) < 7) {
142 40 : goto parse_port;
143 : }
144 :
145 51 : ret->scheme = estrndup(s, (e-s));
146 51 : php_replace_controlchars_ex(ret->scheme, (e - s));
147 :
148 51 : length -= ++e - s;
149 51 : s = e;
150 51 : goto just_path;
151 : } else {
152 1051 : ret->scheme = estrndup(s, (e-s));
153 1051 : php_replace_controlchars_ex(ret->scheme, (e - s));
154 :
155 1051 : if (*(e+2) == '/') {
156 1020 : s = e + 3;
157 1020 : if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
158 76 : if (*(e + 3) == '/') {
159 : /* support windows drive letters as in:
160 : file:///c:/somedir/file.txt
161 : */
162 65 : if (*(e + 5) == ':') {
163 27 : s = e + 4;
164 : }
165 65 : goto nohost;
166 : }
167 : }
168 : } else {
169 31 : if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
170 10 : s = e + 1;
171 10 : goto nohost;
172 : } else {
173 21 : length -= ++e - s;
174 21 : s = e;
175 21 : goto just_path;
176 : }
177 : }
178 : }
179 214 : } else if (e) { /* no scheme, look for port */
180 40 : parse_port:
181 40 : p = e + 1;
182 40 : pp = p;
183 :
184 160 : while (pp-p < 6 && isdigit(*pp)) {
185 80 : pp++;
186 : }
187 :
188 40 : if (pp-p < 6 && (*pp == '/' || *pp == '\0')) {
189 40 : memcpy(port_buf, p, (pp-p));
190 40 : port_buf[pp-p] = '\0';
191 40 : ret->port = atoi(port_buf);
192 : } else {
193 : goto just_path;
194 : }
195 : } else {
196 286 : just_path:
197 286 : ue = s + length;
198 286 : goto nohost;
199 : }
200 :
201 995 : e = ue;
202 :
203 995 : if (!(p = memchr(s, '/', (ue - s)))) {
204 : char *query, *fragment;
205 :
206 461 : query = memchr(s, '?', (ue - s));
207 461 : fragment = memchr(s, '#', (ue - s));
208 :
209 461 : if (query && fragment) {
210 0 : if (query > fragment) {
211 0 : p = e = fragment;
212 : } else {
213 0 : p = e = query;
214 : }
215 461 : } else if (query) {
216 55 : p = e = query;
217 406 : } else if (fragment) {
218 10 : p = e = fragment;
219 : }
220 : } else {
221 534 : e = p;
222 : }
223 :
224 : /* check for login and password */
225 995 : if ((p = zend_memrchr(s, '@', (e-s)))) {
226 168 : if ((pp = memchr(s, ':', (p-s)))) {
227 92 : if ((pp-s) > 0) {
228 82 : ret->user = estrndup(s, (pp-s));
229 82 : php_replace_controlchars_ex(ret->user, (pp - s));
230 : }
231 :
232 92 : pp++;
233 92 : if (p-pp > 0) {
234 82 : ret->pass = estrndup(pp, (p-pp));
235 82 : php_replace_controlchars_ex(ret->pass, (p-pp));
236 : }
237 : } else {
238 76 : ret->user = estrndup(s, (p-s));
239 76 : php_replace_controlchars_ex(ret->user, (p-s));
240 : }
241 :
242 168 : s = p + 1;
243 : }
244 :
245 : /* check for port */
246 1004 : if (*s == '[' && *(e-1) == ']') {
247 : /* Short circuit portscan,
248 : we're dealing with an
249 : IPv6 embedded address */
250 9 : p = s;
251 : } else {
252 : /* memrchr is a GNU specific extension
253 : Emulate for wide compatability */
254 986 : for(p = e; *p != ':' && p >= s; p--);
255 : }
256 :
257 1445 : if (p >= s && *p == ':') {
258 468 : if (!ret->port) {
259 428 : p++;
260 428 : if (e-p > 5) { /* port cannot be longer then 5 characters */
261 18 : STR_FREE(ret->scheme);
262 18 : STR_FREE(ret->user);
263 18 : STR_FREE(ret->pass);
264 18 : efree(ret);
265 18 : return NULL;
266 410 : } else if (e - p > 0) {
267 328 : memcpy(port_buf, p, (e-p));
268 328 : port_buf[e-p] = '\0';
269 328 : ret->port = atoi(port_buf);
270 : }
271 410 : p--;
272 : }
273 : } else {
274 527 : p = e;
275 : }
276 :
277 : /* check if we have a valid host, if we don't reject the string as url */
278 977 : if ((p-s) < 1) {
279 354 : STR_FREE(ret->scheme);
280 354 : STR_FREE(ret->user);
281 354 : STR_FREE(ret->pass);
282 354 : efree(ret);
283 354 : return NULL;
284 : }
285 :
286 623 : ret->host = estrndup(s, (p-s));
287 623 : php_replace_controlchars_ex(ret->host, (p - s));
288 :
289 623 : if (e == ue) {
290 87 : return ret;
291 : }
292 :
293 536 : s = e;
294 :
295 897 : nohost:
296 :
297 897 : if ((p = memchr(s, '?', (ue - s)))) {
298 321 : pp = strchr(s, '#');
299 :
300 321 : if (pp && pp < p) {
301 0 : p = pp;
302 0 : goto label_parse;
303 : }
304 :
305 321 : if (p - s) {
306 293 : ret->path = estrndup(s, (p-s));
307 293 : php_replace_controlchars_ex(ret->path, (p - s));
308 : }
309 :
310 321 : if (pp) {
311 113 : if (pp - ++p) {
312 103 : ret->query = estrndup(p, (pp-p));
313 103 : php_replace_controlchars_ex(ret->query, (pp - p));
314 : }
315 113 : p = pp;
316 113 : goto label_parse;
317 208 : } else if (++p - ue) {
318 131 : ret->query = estrndup(p, (ue-p));
319 131 : php_replace_controlchars_ex(ret->query, (ue - p));
320 : }
321 576 : } else if ((p = memchr(s, '#', (ue - s)))) {
322 20 : if (p - s) {
323 10 : ret->path = estrndup(s, (p-s));
324 10 : php_replace_controlchars_ex(ret->path, (p - s));
325 : }
326 :
327 133 : label_parse:
328 133 : p++;
329 :
330 133 : if (ue - p) {
331 123 : ret->fragment = estrndup(p, (ue-p));
332 123 : php_replace_controlchars_ex(ret->fragment, (ue - p));
333 : }
334 : } else {
335 556 : ret->path = estrndup(s, (ue-s));
336 556 : php_replace_controlchars_ex(ret->path, (ue - s));
337 : }
338 908 : end:
339 908 : return ret;
340 : }
341 : /* }}} */
342 :
343 : /* {{{ proto mixed parse_url(string url, [int url_component])
344 : Parse a URL and return its components */
345 : PHP_FUNCTION(parse_url)
346 1033 : {
347 : char *str;
348 : int str_len;
349 : php_url *resource;
350 1033 : long key = -1;
351 :
352 1033 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &key) == FAILURE) {
353 18 : return;
354 : }
355 :
356 1015 : resource = php_url_parse_ex(str, str_len);
357 1015 : if (resource == NULL) {
358 117 : php_error_docref1(NULL TSRMLS_CC, str, E_WARNING, "Unable to parse URL");
359 117 : RETURN_FALSE;
360 : }
361 :
362 898 : if (key > -1) {
363 716 : switch (key) {
364 : case PHP_URL_SCHEME:
365 96 : if (resource->scheme != NULL) RETVAL_STRING(resource->scheme, 1);
366 96 : break;
367 : case PHP_URL_HOST:
368 90 : if (resource->host != NULL) RETVAL_STRING(resource->host, 1);
369 90 : break;
370 : case PHP_URL_PORT:
371 88 : if (resource->port != 0) RETVAL_LONG(resource->port);
372 88 : break;
373 : case PHP_URL_USER:
374 88 : if (resource->user != NULL) RETVAL_STRING(resource->user, 1);
375 88 : break;
376 : case PHP_URL_PASS:
377 88 : if (resource->pass != NULL) RETVAL_STRING(resource->pass, 1);
378 88 : break;
379 : case PHP_URL_PATH:
380 88 : if (resource->path != NULL) RETVAL_STRING(resource->path, 1);
381 88 : break;
382 : case PHP_URL_QUERY:
383 88 : if (resource->query != NULL) RETVAL_STRING(resource->query, 1);
384 88 : break;
385 : case PHP_URL_FRAGMENT:
386 88 : if (resource->fragment != NULL) RETVAL_STRING(resource->fragment, 1);
387 88 : break;
388 : default:
389 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid URL component identifier %ld", key);
390 2 : RETVAL_FALSE;
391 : }
392 716 : goto done;
393 : }
394 :
395 : /* allocate an array for return */
396 182 : array_init(return_value);
397 :
398 : /* add the various elements to the array */
399 182 : if (resource->scheme != NULL)
400 133 : add_assoc_string(return_value, "scheme", resource->scheme, 1);
401 182 : if (resource->host != NULL)
402 117 : add_assoc_string(return_value, "host", resource->host, 1);
403 182 : if (resource->port != 0)
404 64 : add_assoc_long(return_value, "port", resource->port);
405 182 : if (resource->user != NULL)
406 22 : add_assoc_string(return_value, "user", resource->user, 1);
407 182 : if (resource->pass != NULL)
408 13 : add_assoc_string(return_value, "pass", resource->pass, 1);
409 182 : if (resource->path != NULL)
410 155 : add_assoc_string(return_value, "path", resource->path, 1);
411 182 : if (resource->query != NULL)
412 45 : add_assoc_string(return_value, "query", resource->query, 1);
413 182 : if (resource->fragment != NULL)
414 23 : add_assoc_string(return_value, "fragment", resource->fragment, 1);
415 898 : done:
416 898 : php_url_free(resource);
417 : }
418 : /* }}} */
419 :
420 : /* {{{ php_htoi
421 : */
422 : static int php_htoi(char *s)
423 118 : {
424 : int value;
425 : int c;
426 :
427 118 : c = ((unsigned char *)s)[0];
428 118 : if (isupper(c))
429 2 : c = tolower(c);
430 118 : value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
431 :
432 118 : c = ((unsigned char *)s)[1];
433 118 : if (isupper(c))
434 40 : c = tolower(c);
435 118 : value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
436 :
437 118 : return (value);
438 : }
439 : /* }}} */
440 :
441 : /* rfc1738:
442 :
443 : ...The characters ";",
444 : "/", "?", ":", "@", "=" and "&" are the characters which may be
445 : reserved for special meaning within a scheme...
446 :
447 : ...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
448 : reserved characters used for their reserved purposes may be used
449 : unencoded within a URL...
450 :
451 : For added safety, we only leave -_. unencoded.
452 : */
453 :
454 : static unsigned char hexchars[] = "0123456789ABCDEF";
455 :
456 : /* {{{ php_url_encode
457 : */
458 : PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
459 631 : {
460 : register unsigned char c;
461 : unsigned char *to, *start;
462 : unsigned char const *from, *end;
463 :
464 631 : from = s;
465 631 : end = s + len;
466 631 : start = to = (unsigned char *) safe_emalloc(3, len, 1);
467 :
468 12133 : while (from < end) {
469 10871 : c = *from++;
470 :
471 10871 : if (c == ' ') {
472 10 : *to++ = '+';
473 : #ifndef CHARSET_EBCDIC
474 10987 : } else if ((c < '0' && c != '-' && c != '.') ||
475 : (c < 'A' && c > '9') ||
476 : (c > 'Z' && c < 'a' && c != '_') ||
477 : (c > 'z')) {
478 126 : to[0] = '%';
479 126 : to[1] = hexchars[c >> 4];
480 126 : to[2] = hexchars[c & 15];
481 126 : to += 3;
482 : #else /*CHARSET_EBCDIC*/
483 : } else if (!isalnum(c) && strchr("_-.", c) == NULL) {
484 : /* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
485 : to[0] = '%';
486 : to[1] = hexchars[os_toascii[c] >> 4];
487 : to[2] = hexchars[os_toascii[c] & 15];
488 : to += 3;
489 : #endif /*CHARSET_EBCDIC*/
490 : } else {
491 10735 : *to++ = c;
492 : }
493 : }
494 631 : *to = 0;
495 631 : if (new_length) {
496 119 : *new_length = to - start;
497 : }
498 631 : return (char *) start;
499 : }
500 : /* }}} */
501 :
502 : /* {{{ proto string urlencode(string str)
503 : URL-encodes string */
504 : PHP_FUNCTION(urlencode)
505 89 : {
506 : char *in_str, *out_str;
507 : int in_str_len, out_str_len;
508 :
509 89 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
510 : &in_str_len) == FAILURE) {
511 8 : return;
512 : }
513 :
514 81 : out_str = php_url_encode(in_str, in_str_len, &out_str_len);
515 81 : RETURN_STRINGL(out_str, out_str_len, 0);
516 : }
517 : /* }}} */
518 :
519 : /* {{{ proto string urldecode(string str)
520 : Decodes URL-encoded string */
521 : PHP_FUNCTION(urldecode)
522 31 : {
523 : char *in_str, *out_str;
524 : int in_str_len, out_str_len;
525 :
526 31 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
527 : &in_str_len) == FAILURE) {
528 8 : return;
529 : }
530 :
531 23 : out_str = estrndup(in_str, in_str_len);
532 23 : out_str_len = php_url_decode(out_str, in_str_len);
533 :
534 23 : RETURN_STRINGL(out_str, out_str_len, 0);
535 : }
536 : /* }}} */
537 :
538 : /* {{{ php_url_decode
539 : */
540 : PHPAPI int php_url_decode(char *str, int len)
541 638 : {
542 638 : char *dest = str;
543 638 : char *data = str;
544 :
545 6011 : while (len--) {
546 4735 : if (*data == '+') {
547 34 : *dest = ' ';
548 : }
549 4788 : else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1))
550 : && isxdigit((int) *(data + 2))) {
551 : #ifndef CHARSET_EBCDIC
552 87 : *dest = (char) php_htoi(data + 1);
553 : #else
554 : *dest = os_toebcdic[(char) php_htoi(data + 1)];
555 : #endif
556 87 : data += 2;
557 87 : len -= 2;
558 : } else {
559 4614 : *dest = *data;
560 : }
561 4735 : data++;
562 4735 : dest++;
563 : }
564 638 : *dest = '\0';
565 638 : return dest - str;
566 : }
567 : /* }}} */
568 :
569 : /* {{{ php_raw_url_encode
570 : */
571 : PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
572 21 : {
573 : register int x, y;
574 : unsigned char *str;
575 :
576 21 : str = (unsigned char *) safe_emalloc(3, len, 1);
577 209 : for (x = 0, y = 0; len--; x++, y++) {
578 188 : str[y] = (unsigned char) s[x];
579 : #ifndef CHARSET_EBCDIC
580 188 : if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
581 : (str[y] < 'A' && str[y] > '9') ||
582 : (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
583 : (str[y] > 'z')) {
584 37 : str[y++] = '%';
585 37 : str[y++] = hexchars[(unsigned char) s[x] >> 4];
586 37 : str[y] = hexchars[(unsigned char) s[x] & 15];
587 : #else /*CHARSET_EBCDIC*/
588 : if (!isalnum(str[y]) && strchr("_-.", str[y]) != NULL) {
589 : str[y++] = '%';
590 : str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
591 : str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
592 : #endif /*CHARSET_EBCDIC*/
593 : }
594 : }
595 21 : str[y] = '\0';
596 21 : if (new_length) {
597 21 : *new_length = y;
598 : }
599 21 : return ((char *) str);
600 : }
601 : /* }}} */
602 :
603 : /* {{{ proto string rawurlencode(string str)
604 : URL-encodes string */
605 : PHP_FUNCTION(rawurlencode)
606 29 : {
607 : char *in_str, *out_str;
608 : int in_str_len, out_str_len;
609 :
610 29 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
611 : &in_str_len) == FAILURE) {
612 8 : return;
613 : }
614 :
615 21 : out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
616 21 : RETURN_STRINGL(out_str, out_str_len, 0);
617 : }
618 : /* }}} */
619 :
620 : /* {{{ proto string rawurldecode(string str)
621 : Decodes URL-encodes string */
622 : PHP_FUNCTION(rawurldecode)
623 28 : {
624 : char *in_str, *out_str;
625 : int in_str_len, out_str_len;
626 :
627 28 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
628 : &in_str_len) == FAILURE) {
629 8 : return;
630 : }
631 :
632 20 : out_str = estrndup(in_str, in_str_len);
633 20 : out_str_len = php_raw_url_decode(out_str, in_str_len);
634 :
635 20 : RETURN_STRINGL(out_str, out_str_len, 0);
636 : }
637 : /* }}} */
638 :
639 : /* {{{ php_raw_url_decode
640 : */
641 : PHPAPI int php_raw_url_decode(char *str, int len)
642 20 : {
643 20 : char *dest = str;
644 20 : char *data = str;
645 :
646 187 : while (len--) {
647 178 : if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1))
648 : && isxdigit((int) *(data + 2))) {
649 : #ifndef CHARSET_EBCDIC
650 31 : *dest = (char) php_htoi(data + 1);
651 : #else
652 : *dest = os_toebcdic[(char) php_htoi(data + 1)];
653 : #endif
654 31 : data += 2;
655 31 : len -= 2;
656 : } else {
657 116 : *dest = *data;
658 : }
659 147 : data++;
660 147 : dest++;
661 : }
662 20 : *dest = '\0';
663 20 : return dest - str;
664 : }
665 : /* }}} */
666 :
667 : /* {{{ proto array get_headers(string url[, int format])
668 : fetches all the headers sent by the server in response to a HTTP request */
669 : PHP_FUNCTION(get_headers)
670 5 : {
671 : char *url;
672 : int url_len;
673 : php_stream_context *context;
674 : php_stream *stream;
675 5 : zval **prev_val, **hdr = NULL, **h;
676 : HashPosition pos;
677 : HashTable *hashT;
678 5 : long format = 0;
679 :
680 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &url, &url_len, &format) == FAILURE) {
681 5 : return;
682 : }
683 0 : context = FG(default_context) ? FG(default_context) : (FG(default_context) = php_stream_context_alloc());
684 :
685 0 : if (!(stream = php_stream_open_wrapper_ex(url, "r", REPORT_ERRORS | STREAM_USE_URL | STREAM_ONLY_GET_HEADERS, NULL, context))) {
686 0 : RETURN_FALSE;
687 : }
688 :
689 0 : if (!stream->wrapperdata || Z_TYPE_P(stream->wrapperdata) != IS_ARRAY) {
690 0 : php_stream_close(stream);
691 0 : RETURN_FALSE;
692 : }
693 :
694 0 : array_init(return_value);
695 :
696 : /* check for curl-wrappers that provide headers via a special "headers" element */
697 0 : if (zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h) != FAILURE && Z_TYPE_PP(h) == IS_ARRAY) {
698 : /* curl-wrappers don't load data until the 1st read */
699 0 : if (!Z_ARRVAL_PP(h)->nNumOfElements) {
700 0 : php_stream_getc(stream);
701 : }
702 0 : zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h);
703 0 : hashT = Z_ARRVAL_PP(h);
704 : } else {
705 0 : hashT = HASH_OF(stream->wrapperdata);
706 : }
707 :
708 0 : zend_hash_internal_pointer_reset_ex(hashT, &pos);
709 0 : while (zend_hash_get_current_data_ex(hashT, (void**)&hdr, &pos) != FAILURE) {
710 0 : if (!hdr || Z_TYPE_PP(hdr) != IS_STRING) {
711 0 : zend_hash_move_forward_ex(hashT, &pos);
712 0 : continue;
713 : }
714 0 : if (!format) {
715 0 : no_name_header:
716 0 : add_next_index_stringl(return_value, Z_STRVAL_PP(hdr), Z_STRLEN_PP(hdr), 1);
717 : } else {
718 : char c;
719 : char *s, *p;
720 :
721 0 : if ((p = strchr(Z_STRVAL_PP(hdr), ':'))) {
722 0 : c = *p;
723 0 : *p = '\0';
724 0 : s = p + 1;
725 0 : while (isspace((int)*(unsigned char *)s)) {
726 0 : s++;
727 : }
728 :
729 0 : if (zend_hash_find(HASH_OF(return_value), Z_STRVAL_PP(hdr), (p - Z_STRVAL_PP(hdr) + 1), (void **) &prev_val) == FAILURE) {
730 0 : add_assoc_stringl_ex(return_value, Z_STRVAL_PP(hdr), (p - Z_STRVAL_PP(hdr) + 1), s, (Z_STRLEN_PP(hdr) - (s - Z_STRVAL_PP(hdr))), 1);
731 : } else { /* some headers may occur more then once, therefor we need to remake the string into an array */
732 0 : convert_to_array(*prev_val);
733 0 : add_next_index_stringl(*prev_val, s, (Z_STRLEN_PP(hdr) - (s - Z_STRVAL_PP(hdr))), 1);
734 : }
735 :
736 0 : *p = c;
737 : } else {
738 0 : goto no_name_header;
739 : }
740 : }
741 0 : zend_hash_move_forward_ex(hashT, &pos);
742 : }
743 :
744 0 : php_stream_close(stream);
745 : }
746 : /* }}} */
747 :
748 : /*
749 : * Local variables:
750 : * tab-width: 4
751 : * c-basic-offset: 4
752 : * End:
753 : * vim600: sw=4 ts=4 fdm=marker
754 : * vim<600: sw=4 ts=4
755 : */
|