Back to index

php5  5.3.10
url.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Jim Winstead <jimw@php.net>                                  |
00016    +----------------------------------------------------------------------+
00017  */
00018 /* $Id: url.c 321634 2012-01-01 13:15:04Z felipe $ */
00019 
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <ctype.h>
00023 #include <sys/types.h>
00024 
00025 #include "php.h"
00026 
00027 #include "url.h"
00028 #include "file.h"
00029 #ifdef _OSD_POSIX
00030 #ifndef APACHE
00031 #error On this EBCDIC platform, PHP is only supported as an Apache module.
00032 #else /*APACHE*/
00033 #ifndef CHARSET_EBCDIC
00034 #define CHARSET_EBCDIC /* this machine uses EBCDIC, not ASCII! */
00035 #endif
00036 #include "ebcdic.h"
00037 #endif /*APACHE*/
00038 #endif /*_OSD_POSIX*/
00039 
00040 /* {{{ free_url
00041  */
00042 PHPAPI void php_url_free(php_url *theurl)
00043 {
00044        if (theurl->scheme)
00045               efree(theurl->scheme);
00046        if (theurl->user)
00047               efree(theurl->user);
00048        if (theurl->pass)
00049               efree(theurl->pass);
00050        if (theurl->host)
00051               efree(theurl->host);
00052        if (theurl->path)
00053               efree(theurl->path);
00054        if (theurl->query)
00055               efree(theurl->query);
00056        if (theurl->fragment)
00057               efree(theurl->fragment);
00058        efree(theurl);
00059 }
00060 /* }}} */
00061 
00062 /* {{{ php_replace_controlchars
00063  */
00064 PHPAPI char *php_replace_controlchars_ex(char *str, int len)
00065 {
00066        unsigned char *s = (unsigned char *)str;
00067        unsigned char *e = (unsigned char *)str + len;
00068        
00069        if (!str) {
00070               return (NULL);
00071        }
00072        
00073        while (s < e) {
00074            
00075               if (iscntrl(*s)) {
00076                      *s='_';
00077               }      
00078               s++;
00079        }
00080        
00081        return (str);
00082 } 
00083 /* }}} */
00084 
00085 PHPAPI char *php_replace_controlchars(char *str)
00086 {
00087        return php_replace_controlchars_ex(str, strlen(str));
00088 } 
00089 
00090 PHPAPI php_url *php_url_parse(char const *str)
00091 {
00092        return php_url_parse_ex(str, strlen(str));
00093 }
00094 
00095 /* {{{ php_url_parse
00096  */
00097 PHPAPI php_url *php_url_parse_ex(char const *str, int length)
00098 {
00099        char port_buf[6];
00100        php_url *ret = ecalloc(1, sizeof(php_url));
00101        char const *s, *e, *p, *pp, *ue;
00102               
00103        s = str;
00104        ue = s + length;
00105 
00106        /* parse scheme */
00107        if ((e = memchr(s, ':', length)) && (e - s)) {
00108               /* validate scheme */
00109               p = s;
00110               while (p < e) {
00111                      /* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */
00112                      if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') {
00113                             if (e + 1 < ue) {
00114                                    goto parse_port;
00115                             } else {
00116                                    goto just_path;
00117                             }
00118                      }
00119                      p++;
00120               }
00121        
00122               if (*(e + 1) == '\0') { /* only scheme is available */
00123                      ret->scheme = estrndup(s, (e - s));
00124                      php_replace_controlchars_ex(ret->scheme, (e - s));
00125                      goto end;
00126               }
00127 
00128               /* 
00129                * certain schemas like mailto: and zlib: may not have any / after them
00130                * this check ensures we support those.
00131                */
00132               if (*(e+1) != '/') {
00133                      /* check if the data we get is a port this allows us to 
00134                       * correctly parse things like a.com:80
00135                       */
00136                      p = e + 1;
00137                      while (isdigit(*p)) {
00138                             p++;
00139                      }
00140                      
00141                      if ((*p == '\0' || *p == '/') && (p - e) < 7) {
00142                             goto parse_port;
00143                      }
00144                      
00145                      ret->scheme = estrndup(s, (e-s));
00146                      php_replace_controlchars_ex(ret->scheme, (e - s));
00147                      
00148                      length -= ++e - s;
00149                      s = e;
00150                      goto just_path;
00151               } else {
00152                      ret->scheme = estrndup(s, (e-s));
00153                      php_replace_controlchars_ex(ret->scheme, (e - s));
00154               
00155                      if (*(e+2) == '/') {
00156                             s = e + 3;
00157                             if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
00158                                    if (*(e + 3) == '/') {
00159                                           /* support windows drive letters as in:
00160                                              file:///c:/somedir/file.txt
00161                                           */
00162                                           if (*(e + 5) == ':') {
00163                                                  s = e + 4;
00164                                           }
00165                                           goto nohost;
00166                                    }
00167                             }
00168                      } else {
00169                             if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
00170                                    s = e + 1;
00171                                    goto nohost;
00172                             } else {
00173                                    length -= ++e - s;
00174                                    s = e;
00175                                    goto just_path;
00176                             }      
00177                      }
00178               }      
00179        } else if (e) { /* no scheme; starts with colon: look for port */
00180               parse_port:
00181               p = e + 1;
00182               pp = p;
00183 
00184               while (pp-p < 6 && isdigit(*pp)) {
00185                      pp++;
00186               }
00187 
00188               if (pp - p > 0 && pp - p < 6 && (*pp == '/' || *pp == '\0')) {
00189                      long port;
00190                      memcpy(port_buf, p, (pp - p));
00191                      port_buf[pp - p] = '\0';
00192                      port = strtol(port_buf, NULL, 10);
00193                      if (port > 0 && port <= 65535) {
00194                             ret->port = (unsigned short) port;
00195                      } else {
00196                             STR_FREE(ret->scheme);
00197                             efree(ret);
00198                             return NULL;
00199                      }
00200               } else if (p == pp && *pp == '\0') {
00201                      STR_FREE(ret->scheme);
00202                      efree(ret);
00203                      return NULL;
00204               } else {
00205                      goto just_path;
00206               }
00207        } else {
00208               just_path:
00209               ue = s + length;
00210               goto nohost;
00211        }
00212        
00213        e = ue;
00214        
00215        if (!(p = memchr(s, '/', (ue - s)))) {
00216               char *query, *fragment;
00217 
00218               query = memchr(s, '?', (ue - s));
00219               fragment = memchr(s, '#', (ue - s));
00220 
00221               if (query && fragment) {
00222                      if (query > fragment) {
00223                             p = e = fragment;
00224                      } else {
00225                             p = e = query;
00226                      }
00227               } else if (query) {
00228                      p = e = query;
00229               } else if (fragment) {
00230                      p = e = fragment;
00231               }
00232        } else {
00233               e = p;
00234        }      
00235               
00236        /* check for login and password */
00237        if ((p = zend_memrchr(s, '@', (e-s)))) {
00238               if ((pp = memchr(s, ':', (p-s)))) {
00239                      if ((pp-s) > 0) {
00240                             ret->user = estrndup(s, (pp-s));
00241                             php_replace_controlchars_ex(ret->user, (pp - s));
00242                      }      
00243               
00244                      pp++;
00245                      if (p-pp > 0) {
00246                             ret->pass = estrndup(pp, (p-pp));
00247                             php_replace_controlchars_ex(ret->pass, (p-pp));
00248                      }      
00249               } else {
00250                      ret->user = estrndup(s, (p-s));
00251                      php_replace_controlchars_ex(ret->user, (p-s));
00252               }
00253               
00254               s = p + 1;
00255        }
00256 
00257        /* check for port */
00258        if (*s == '[' && *(e-1) == ']') {
00259               /* Short circuit portscan, 
00260                  we're dealing with an 
00261                  IPv6 embedded address */
00262               p = s;
00263        } else {
00264               /* memrchr is a GNU specific extension
00265                  Emulate for wide compatability */
00266               for(p = e; *p != ':' && p >= s; p--);
00267        }
00268 
00269        if (p >= s && *p == ':') {
00270               if (!ret->port) {
00271                      p++;
00272                      if (e-p > 5) { /* port cannot be longer then 5 characters */
00273                             STR_FREE(ret->scheme);
00274                             STR_FREE(ret->user);
00275                             STR_FREE(ret->pass);
00276                             efree(ret);
00277                             return NULL;
00278                      } else if (e - p > 0) {
00279                             long port;
00280                             memcpy(port_buf, p, (e - p));
00281                             port_buf[e - p] = '\0';
00282                             port = strtol(port_buf, NULL, 10);
00283                             if (port > 0 && port <= 65535) {
00284                                    ret->port = (unsigned short)port;
00285                             } else {
00286                                    STR_FREE(ret->scheme);
00287                                    STR_FREE(ret->user);
00288                                    STR_FREE(ret->pass);
00289                                    efree(ret);
00290                                    return NULL;
00291                             }
00292                      }
00293                      p--;
00294               }      
00295        } else {
00296               p = e;
00297        }
00298        
00299        /* check if we have a valid host, if we don't reject the string as url */
00300        if ((p-s) < 1) {
00301               STR_FREE(ret->scheme);
00302               STR_FREE(ret->user);
00303               STR_FREE(ret->pass);
00304               efree(ret);
00305               return NULL;
00306        }
00307 
00308        ret->host = estrndup(s, (p-s));
00309        php_replace_controlchars_ex(ret->host, (p - s));
00310        
00311        if (e == ue) {
00312               return ret;
00313        }
00314        
00315        s = e;
00316        
00317        nohost:
00318        
00319        if ((p = memchr(s, '?', (ue - s)))) {
00320               pp = strchr(s, '#');
00321 
00322               if (pp && pp < p) {
00323                      if (pp - s) {
00324                             ret->path = estrndup(s, (pp-s));
00325                             php_replace_controlchars_ex(ret->path, (pp - s));
00326                      }
00327                      p = pp;
00328                      goto label_parse;
00329               }
00330        
00331               if (p - s) {
00332                      ret->path = estrndup(s, (p-s));
00333                      php_replace_controlchars_ex(ret->path, (p - s));
00334               }      
00335        
00336               if (pp) {
00337                      if (pp - ++p) { 
00338                             ret->query = estrndup(p, (pp-p));
00339                             php_replace_controlchars_ex(ret->query, (pp - p));
00340                      }
00341                      p = pp;
00342                      goto label_parse;
00343               } else if (++p - ue) {
00344                      ret->query = estrndup(p, (ue-p));
00345                      php_replace_controlchars_ex(ret->query, (ue - p));
00346               }
00347        } else if ((p = memchr(s, '#', (ue - s)))) {
00348               if (p - s) {
00349                      ret->path = estrndup(s, (p-s));
00350                      php_replace_controlchars_ex(ret->path, (p - s));
00351               }      
00352               
00353               label_parse:
00354               p++;
00355               
00356               if (ue - p) {
00357                      ret->fragment = estrndup(p, (ue-p));
00358                      php_replace_controlchars_ex(ret->fragment, (ue - p));
00359               }      
00360        } else {
00361               ret->path = estrndup(s, (ue-s));
00362               php_replace_controlchars_ex(ret->path, (ue - s));
00363        }
00364 end:
00365        return ret;
00366 }
00367 /* }}} */
00368 
00369 /* {{{ proto mixed parse_url(string url, [int url_component])
00370    Parse a URL and return its components */
00371 PHP_FUNCTION(parse_url)
00372 {
00373        char *str;
00374        int str_len;
00375        php_url *resource;
00376        long key = -1;
00377 
00378        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &key) == FAILURE) {
00379               return;
00380        }
00381 
00382        resource = php_url_parse_ex(str, str_len);
00383        if (resource == NULL) {
00384               /* @todo Find a method to determine why php_url_parse_ex() failed */
00385               RETURN_FALSE;
00386        }
00387 
00388        if (key > -1) {
00389               switch (key) {
00390                      case PHP_URL_SCHEME:
00391                             if (resource->scheme != NULL) RETVAL_STRING(resource->scheme, 1);
00392                             break;
00393                      case PHP_URL_HOST:
00394                             if (resource->host != NULL) RETVAL_STRING(resource->host, 1);
00395                             break;
00396                      case PHP_URL_PORT:
00397                             if (resource->port != 0) RETVAL_LONG(resource->port);
00398                             break;
00399                      case PHP_URL_USER:
00400                             if (resource->user != NULL) RETVAL_STRING(resource->user, 1);
00401                             break;
00402                      case PHP_URL_PASS:
00403                             if (resource->pass != NULL) RETVAL_STRING(resource->pass, 1);
00404                             break;
00405                      case PHP_URL_PATH:
00406                             if (resource->path != NULL) RETVAL_STRING(resource->path, 1);
00407                             break;
00408                      case PHP_URL_QUERY:
00409                             if (resource->query != NULL) RETVAL_STRING(resource->query, 1);
00410                             break;
00411                      case PHP_URL_FRAGMENT:
00412                             if (resource->fragment != NULL) RETVAL_STRING(resource->fragment, 1);
00413                             break;
00414                      default:
00415                             php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid URL component identifier %ld", key);
00416                             RETVAL_FALSE;
00417               }
00418               goto done;
00419        }
00420 
00421        /* allocate an array for return */
00422        array_init(return_value);
00423 
00424     /* add the various elements to the array */
00425        if (resource->scheme != NULL)
00426               add_assoc_string(return_value, "scheme", resource->scheme, 1);
00427        if (resource->host != NULL)
00428               add_assoc_string(return_value, "host", resource->host, 1);
00429        if (resource->port != 0)
00430               add_assoc_long(return_value, "port", resource->port);
00431        if (resource->user != NULL)
00432               add_assoc_string(return_value, "user", resource->user, 1);
00433        if (resource->pass != NULL)
00434               add_assoc_string(return_value, "pass", resource->pass, 1);
00435        if (resource->path != NULL)
00436               add_assoc_string(return_value, "path", resource->path, 1);
00437        if (resource->query != NULL)
00438               add_assoc_string(return_value, "query", resource->query, 1);
00439        if (resource->fragment != NULL)
00440               add_assoc_string(return_value, "fragment", resource->fragment, 1);
00441 done:  
00442        php_url_free(resource);
00443 }
00444 /* }}} */
00445 
00446 /* {{{ php_htoi
00447  */
00448 static int php_htoi(char *s)
00449 {
00450        int value;
00451        int c;
00452 
00453        c = ((unsigned char *)s)[0];
00454        if (isupper(c))
00455               c = tolower(c);
00456        value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
00457 
00458        c = ((unsigned char *)s)[1];
00459        if (isupper(c))
00460               c = tolower(c);
00461        value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
00462 
00463        return (value);
00464 }
00465 /* }}} */
00466 
00467 /* rfc1738:
00468 
00469    ...The characters ";",
00470    "/", "?", ":", "@", "=" and "&" are the characters which may be
00471    reserved for special meaning within a scheme...
00472 
00473    ...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
00474    reserved characters used for their reserved purposes may be used
00475    unencoded within a URL...
00476 
00477    For added safety, we only leave -_. unencoded.
00478  */
00479 
00480 static unsigned char hexchars[] = "0123456789ABCDEF";
00481 
00482 /* {{{ php_url_encode
00483  */
00484 PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
00485 {
00486        register unsigned char c;
00487        unsigned char *to, *start;
00488        unsigned char const *from, *end;
00489        
00490        from = (unsigned char *)s;
00491        end = (unsigned char *)s + len;
00492        start = to = (unsigned char *) safe_emalloc(3, len, 1);
00493 
00494        while (from < end) {
00495               c = *from++;
00496 
00497               if (c == ' ') {
00498                      *to++ = '+';
00499 #ifndef CHARSET_EBCDIC
00500               } else if ((c < '0' && c != '-' && c != '.') ||
00501                                (c < 'A' && c > '9') ||
00502                                (c > 'Z' && c < 'a' && c != '_') ||
00503                                (c > 'z')) {
00504                      to[0] = '%';
00505                      to[1] = hexchars[c >> 4];
00506                      to[2] = hexchars[c & 15];
00507                      to += 3;
00508 #else /*CHARSET_EBCDIC*/
00509               } else if (!isalnum(c) && strchr("_-.", c) == NULL) {
00510                      /* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
00511                      to[0] = '%';
00512                      to[1] = hexchars[os_toascii[c] >> 4];
00513                      to[2] = hexchars[os_toascii[c] & 15];
00514                      to += 3;
00515 #endif /*CHARSET_EBCDIC*/
00516               } else {
00517                      *to++ = c;
00518               }
00519        }
00520        *to = 0;
00521        if (new_length) {
00522               *new_length = to - start;
00523        }
00524        return (char *) start;
00525 }
00526 /* }}} */
00527 
00528 /* {{{ proto string urlencode(string str)
00529    URL-encodes string */
00530 PHP_FUNCTION(urlencode)
00531 {
00532        char *in_str, *out_str;
00533        int in_str_len, out_str_len;
00534 
00535        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
00536                                                    &in_str_len) == FAILURE) {
00537               return;
00538        }
00539 
00540        out_str = php_url_encode(in_str, in_str_len, &out_str_len);
00541        RETURN_STRINGL(out_str, out_str_len, 0);
00542 }
00543 /* }}} */
00544 
00545 /* {{{ proto string urldecode(string str)
00546    Decodes URL-encoded string */
00547 PHP_FUNCTION(urldecode)
00548 {
00549        char *in_str, *out_str;
00550        int in_str_len, out_str_len;
00551 
00552        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
00553                                                    &in_str_len) == FAILURE) {
00554               return;
00555        }
00556 
00557        out_str = estrndup(in_str, in_str_len);
00558        out_str_len = php_url_decode(out_str, in_str_len);
00559 
00560     RETURN_STRINGL(out_str, out_str_len, 0);
00561 }
00562 /* }}} */
00563 
00564 /* {{{ php_url_decode
00565  */
00566 PHPAPI int php_url_decode(char *str, int len)
00567 {
00568        char *dest = str;
00569        char *data = str;
00570 
00571        while (len--) {
00572               if (*data == '+') {
00573                      *dest = ' ';
00574               }
00575               else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) 
00576                              && isxdigit((int) *(data + 2))) {
00577 #ifndef CHARSET_EBCDIC
00578                      *dest = (char) php_htoi(data + 1);
00579 #else
00580                      *dest = os_toebcdic[(char) php_htoi(data + 1)];
00581 #endif
00582                      data += 2;
00583                      len -= 2;
00584               } else {
00585                      *dest = *data;
00586               }
00587               data++;
00588               dest++;
00589        }
00590        *dest = '\0';
00591        return dest - str;
00592 }
00593 /* }}} */
00594 
00595 /* {{{ php_raw_url_encode
00596  */
00597 PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
00598 {
00599        register int x, y;
00600        unsigned char *str;
00601 
00602        str = (unsigned char *) safe_emalloc(3, len, 1);
00603        for (x = 0, y = 0; len--; x++, y++) {
00604               str[y] = (unsigned char) s[x];
00605 #ifndef CHARSET_EBCDIC
00606               if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
00607                      (str[y] < 'A' && str[y] > '9') ||
00608                      (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
00609                      (str[y] > 'z' && str[y] != '~')) {
00610                      str[y++] = '%';
00611                      str[y++] = hexchars[(unsigned char) s[x] >> 4];
00612                      str[y] = hexchars[(unsigned char) s[x] & 15];
00613 #else /*CHARSET_EBCDIC*/
00614               if (!isalnum(str[y]) && strchr("_-.~", str[y]) != NULL) {
00615                      str[y++] = '%';
00616                      str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
00617                      str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
00618 #endif /*CHARSET_EBCDIC*/
00619               }
00620        }
00621        str[y] = '\0';
00622        if (new_length) {
00623               *new_length = y;
00624        }
00625        return ((char *) str);
00626 }
00627 /* }}} */
00628 
00629 /* {{{ proto string rawurlencode(string str)
00630    URL-encodes string */
00631 PHP_FUNCTION(rawurlencode)
00632 {
00633        char *in_str, *out_str;
00634        int in_str_len, out_str_len;
00635 
00636        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
00637                                                    &in_str_len) == FAILURE) {
00638               return;
00639        }
00640 
00641        out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
00642        RETURN_STRINGL(out_str, out_str_len, 0);
00643 }
00644 /* }}} */
00645 
00646 /* {{{ proto string rawurldecode(string str)
00647    Decodes URL-encodes string */
00648 PHP_FUNCTION(rawurldecode)
00649 {
00650        char *in_str, *out_str;
00651        int in_str_len, out_str_len;
00652 
00653        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
00654                                                    &in_str_len) == FAILURE) {
00655               return;
00656        }
00657 
00658        out_str = estrndup(in_str, in_str_len);
00659        out_str_len = php_raw_url_decode(out_str, in_str_len);
00660 
00661     RETURN_STRINGL(out_str, out_str_len, 0);
00662 }
00663 /* }}} */
00664 
00665 /* {{{ php_raw_url_decode
00666  */
00667 PHPAPI int php_raw_url_decode(char *str, int len)
00668 {
00669        char *dest = str;
00670        char *data = str;
00671 
00672        while (len--) {
00673               if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) 
00674                      && isxdigit((int) *(data + 2))) {
00675 #ifndef CHARSET_EBCDIC
00676                      *dest = (char) php_htoi(data + 1);
00677 #else
00678                      *dest = os_toebcdic[(char) php_htoi(data + 1)];
00679 #endif
00680                      data += 2;
00681                      len -= 2;
00682               } else {
00683                      *dest = *data;
00684               }
00685               data++;
00686               dest++;
00687        }
00688        *dest = '\0';
00689        return dest - str;
00690 }
00691 /* }}} */
00692 
00693 /* {{{ proto array get_headers(string url[, int format])
00694    fetches all the headers sent by the server in response to a HTTP request */
00695 PHP_FUNCTION(get_headers)
00696 {
00697        char *url;
00698        int url_len;
00699        php_stream_context *context;
00700        php_stream *stream;
00701        zval **prev_val, **hdr = NULL, **h;
00702        HashPosition pos;
00703        HashTable *hashT;
00704        long format = 0;
00705                 
00706        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &url, &url_len, &format) == FAILURE) {
00707               return;
00708        }
00709        context = FG(default_context) ? FG(default_context) : (FG(default_context) = php_stream_context_alloc());
00710 
00711        if (!(stream = php_stream_open_wrapper_ex(url, "r", REPORT_ERRORS | STREAM_USE_URL | STREAM_ONLY_GET_HEADERS, NULL, context))) {
00712               RETURN_FALSE;
00713        }
00714 
00715        if (!stream->wrapperdata || Z_TYPE_P(stream->wrapperdata) != IS_ARRAY) {
00716               php_stream_close(stream);
00717               RETURN_FALSE;
00718        }
00719 
00720        array_init(return_value);
00721 
00722        /* check for curl-wrappers that provide headers via a special "headers" element */
00723        if (zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h) != FAILURE && Z_TYPE_PP(h) == IS_ARRAY) {
00724               /* curl-wrappers don't load data until the 1st read */ 
00725               if (!Z_ARRVAL_PP(h)->nNumOfElements) {
00726                      php_stream_getc(stream);
00727               }
00728               zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h);
00729               hashT = Z_ARRVAL_PP(h);     
00730        } else {
00731               hashT = HASH_OF(stream->wrapperdata);
00732        }
00733 
00734        zend_hash_internal_pointer_reset_ex(hashT, &pos);
00735        while (zend_hash_get_current_data_ex(hashT, (void**)&hdr, &pos) != FAILURE) {
00736               if (!hdr || Z_TYPE_PP(hdr) != IS_STRING) {
00737                      zend_hash_move_forward_ex(hashT, &pos);
00738                      continue;
00739               }
00740               if (!format) {
00741 no_name_header:
00742                      add_next_index_stringl(return_value, Z_STRVAL_PP(hdr), Z_STRLEN_PP(hdr), 1);
00743               } else {
00744                      char c;
00745                      char *s, *p;
00746 
00747                      if ((p = strchr(Z_STRVAL_PP(hdr), ':'))) {
00748                             c = *p;
00749                             *p = '\0';
00750                             s = p + 1;
00751                             while (isspace((int)*(unsigned char *)s)) {
00752                                    s++;
00753                             }
00754 
00755                             if (zend_hash_find(HASH_OF(return_value), Z_STRVAL_PP(hdr), (p - Z_STRVAL_PP(hdr) + 1), (void **) &prev_val) == FAILURE) {
00756                                    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);
00757                             } else { /* some headers may occur more then once, therefor we need to remake the string into an array */
00758                                    convert_to_array(*prev_val);
00759                                    add_next_index_stringl(*prev_val, s, (Z_STRLEN_PP(hdr) - (s - Z_STRVAL_PP(hdr))), 1);
00760                             }
00761 
00762                             *p = c;
00763                      } else {
00764                             goto no_name_header;
00765                      }
00766               }
00767               zend_hash_move_forward_ex(hashT, &pos);
00768        }
00769 
00770        php_stream_close(stream);
00771 }
00772 /* }}} */
00773 
00774 /*
00775  * Local variables:
00776  * tab-width: 4
00777  * c-basic-offset: 4
00778  * End:
00779  * vim600: sw=4 ts=4 fdm=marker
00780  * vim<600: sw=4 ts=4
00781  */