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