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

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

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