Return to url.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / standard |
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: */