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