Annotation of embedaddon/php/ext/standard/url.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>