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