root/ext/standard/url.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_url_free
  2. php_replace_controlchars_ex
  3. php_replace_controlchars
  4. php_url_parse
  5. php_url_parse_ex
  6. PHP_FUNCTION
  7. php_htoi
  8. php_url_encode
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. php_url_decode
  12. php_raw_url_encode
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. php_raw_url_decode
  16. PHP_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */