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

1.1     ! misho       1: /*
        !             2:    +----------------------------------------------------------------------+
        !             3:    | PHP Version 5                                                        |
        !             4:    +----------------------------------------------------------------------+
        !             5:    | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:    +----------------------------------------------------------------------+
        !             7:    | This source file is subject to version 3.01 of the PHP license,      |
        !             8:    | that is bundled with this package in the file LICENSE, and is        |
        !             9:    | available through the world-wide-web at the following url:           |
        !            10:    | http://www.php.net/license/3_01.txt                                  |
        !            11:    | If you did not receive a copy of the PHP license and are unable to   |
        !            12:    | obtain it through the world-wide-web, please send a note to          |
        !            13:    | license@php.net so we can mail you a copy immediately.               |
        !            14:    +----------------------------------------------------------------------+
        !            15:    | Author: Jim Winstead <jimw@php.net>                                  |
        !            16:    +----------------------------------------------------------------------+
        !            17:  */
        !            18: /* $Id: url.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            19: 
        !            20: #include <stdlib.h>
        !            21: #include <string.h>
        !            22: #include <ctype.h>
        !            23: #include <sys/types.h>
        !            24: 
        !            25: #include "php.h"
        !            26: 
        !            27: #include "url.h"
        !            28: #include "file.h"
        !            29: #ifdef _OSD_POSIX
        !            30: #ifndef APACHE
        !            31: #error On this EBCDIC platform, PHP is only supported as an Apache module.
        !            32: #else /*APACHE*/
        !            33: #ifndef CHARSET_EBCDIC
        !            34: #define CHARSET_EBCDIC /* this machine uses EBCDIC, not ASCII! */
        !            35: #endif
        !            36: #include "ebcdic.h"
        !            37: #endif /*APACHE*/
        !            38: #endif /*_OSD_POSIX*/
        !            39: 
        !            40: /* {{{ free_url
        !            41:  */
        !            42: PHPAPI void php_url_free(php_url *theurl)
        !            43: {
        !            44:        if (theurl->scheme)
        !            45:                efree(theurl->scheme);
        !            46:        if (theurl->user)
        !            47:                efree(theurl->user);
        !            48:        if (theurl->pass)
        !            49:                efree(theurl->pass);
        !            50:        if (theurl->host)
        !            51:                efree(theurl->host);
        !            52:        if (theurl->path)
        !            53:                efree(theurl->path);
        !            54:        if (theurl->query)
        !            55:                efree(theurl->query);
        !            56:        if (theurl->fragment)
        !            57:                efree(theurl->fragment);
        !            58:        efree(theurl);
        !            59: }
        !            60: /* }}} */
        !            61: 
        !            62: /* {{{ php_replace_controlchars
        !            63:  */
        !            64: PHPAPI char *php_replace_controlchars_ex(char *str, int len)
        !            65: {
        !            66:        unsigned char *s = (unsigned char *)str;
        !            67:        unsigned char *e = (unsigned char *)str + len;
        !            68:        
        !            69:        if (!str) {
        !            70:                return (NULL);
        !            71:        }
        !            72:        
        !            73:        while (s < e) {
        !            74:            
        !            75:                if (iscntrl(*s)) {
        !            76:                        *s='_';
        !            77:                }       
        !            78:                s++;
        !            79:        }
        !            80:        
        !            81:        return (str);
        !            82: } 
        !            83: /* }}} */
        !            84: 
        !            85: PHPAPI char *php_replace_controlchars(char *str)
        !            86: {
        !            87:        return php_replace_controlchars_ex(str, strlen(str));
        !            88: } 
        !            89: 
        !            90: PHPAPI php_url *php_url_parse(char const *str)
        !            91: {
        !            92:        return php_url_parse_ex(str, strlen(str));
        !            93: }
        !            94: 
        !            95: /* {{{ php_url_parse
        !            96:  */
        !            97: PHPAPI php_url *php_url_parse_ex(char const *str, int length)
        !            98: {
        !            99:        char port_buf[6];
        !           100:        php_url *ret = ecalloc(1, sizeof(php_url));
        !           101:        char const *s, *e, *p, *pp, *ue;
        !           102:                
        !           103:        s = str;
        !           104:        ue = s + length;
        !           105: 
        !           106:        /* parse scheme */
        !           107:        if ((e = memchr(s, ':', length)) && (e - s)) {
        !           108:                /* validate scheme */
        !           109:                p = s;
        !           110:                while (p < e) {
        !           111:                        /* scheme = 1*[ lowalpha | digit | "+" | "-" | "." ] */
        !           112:                        if (!isalpha(*p) && !isdigit(*p) && *p != '+' && *p != '.' && *p != '-') {
        !           113:                                if (e + 1 < ue) {
        !           114:                                        goto parse_port;
        !           115:                                } else {
        !           116:                                        goto just_path;
        !           117:                                }
        !           118:                        }
        !           119:                        p++;
        !           120:                }
        !           121:        
        !           122:                if (*(e + 1) == '\0') { /* only scheme is available */
        !           123:                        ret->scheme = estrndup(s, (e - s));
        !           124:                        php_replace_controlchars_ex(ret->scheme, (e - s));
        !           125:                        goto end;
        !           126:                }
        !           127: 
        !           128:                /* 
        !           129:                 * certain schemas like mailto: and zlib: may not have any / after them
        !           130:                 * this check ensures we support those.
        !           131:                 */
        !           132:                if (*(e+1) != '/') {
        !           133:                        /* check if the data we get is a port this allows us to 
        !           134:                         * correctly parse things like a.com:80
        !           135:                         */
        !           136:                        p = e + 1;
        !           137:                        while (isdigit(*p)) {
        !           138:                                p++;
        !           139:                        }
        !           140:                        
        !           141:                        if ((*p == '\0' || *p == '/') && (p - e) < 7) {
        !           142:                                goto parse_port;
        !           143:                        }
        !           144:                        
        !           145:                        ret->scheme = estrndup(s, (e-s));
        !           146:                        php_replace_controlchars_ex(ret->scheme, (e - s));
        !           147:                        
        !           148:                        length -= ++e - s;
        !           149:                        s = e;
        !           150:                        goto just_path;
        !           151:                } else {
        !           152:                        ret->scheme = estrndup(s, (e-s));
        !           153:                        php_replace_controlchars_ex(ret->scheme, (e - s));
        !           154:                
        !           155:                        if (*(e+2) == '/') {
        !           156:                                s = e + 3;
        !           157:                                if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
        !           158:                                        if (*(e + 3) == '/') {
        !           159:                                                /* support windows drive letters as in:
        !           160:                                                   file:///c:/somedir/file.txt
        !           161:                                                */
        !           162:                                                if (*(e + 5) == ':') {
        !           163:                                                        s = e + 4;
        !           164:                                                }
        !           165:                                                goto nohost;
        !           166:                                        }
        !           167:                                }
        !           168:                        } else {
        !           169:                                if (!strncasecmp("file", ret->scheme, sizeof("file"))) {
        !           170:                                        s = e + 1;
        !           171:                                        goto nohost;
        !           172:                                } else {
        !           173:                                        length -= ++e - s;
        !           174:                                        s = e;
        !           175:                                        goto just_path;
        !           176:                                }       
        !           177:                        }
        !           178:                }       
        !           179:        } else if (e) { /* no scheme; starts with colon: look for port */
        !           180:                parse_port:
        !           181:                p = e + 1;
        !           182:                pp = p;
        !           183: 
        !           184:                while (pp-p < 6 && isdigit(*pp)) {
        !           185:                        pp++;
        !           186:                }
        !           187: 
        !           188:                if (pp - p > 0 && pp - p < 6 && (*pp == '/' || *pp == '\0')) {
        !           189:                        long port;
        !           190:                        memcpy(port_buf, p, (pp - p));
        !           191:                        port_buf[pp - p] = '\0';
        !           192:                        port = strtol(port_buf, NULL, 10);
        !           193:                        if (port > 0 && port <= 65535) {
        !           194:                                ret->port = (unsigned short) port;
        !           195:                        } else {
        !           196:                                STR_FREE(ret->scheme);
        !           197:                                efree(ret);
        !           198:                                return NULL;
        !           199:                        }
        !           200:                } else if (p == pp && *pp == '\0') {
        !           201:                        STR_FREE(ret->scheme);
        !           202:                        efree(ret);
        !           203:                        return NULL;
        !           204:                } else {
        !           205:                        goto just_path;
        !           206:                }
        !           207:        } else {
        !           208:                just_path:
        !           209:                ue = s + length;
        !           210:                goto nohost;
        !           211:        }
        !           212:        
        !           213:        e = ue;
        !           214:        
        !           215:        if (!(p = memchr(s, '/', (ue - s)))) {
        !           216:                char *query, *fragment;
        !           217: 
        !           218:                query = memchr(s, '?', (ue - s));
        !           219:                fragment = memchr(s, '#', (ue - s));
        !           220: 
        !           221:                if (query && fragment) {
        !           222:                        if (query > fragment) {
        !           223:                                p = e = fragment;
        !           224:                        } else {
        !           225:                                p = e = query;
        !           226:                        }
        !           227:                } else if (query) {
        !           228:                        p = e = query;
        !           229:                } else if (fragment) {
        !           230:                        p = e = fragment;
        !           231:                }
        !           232:        } else {
        !           233:                e = p;
        !           234:        }       
        !           235:                
        !           236:        /* check for login and password */
        !           237:        if ((p = zend_memrchr(s, '@', (e-s)))) {
        !           238:                if ((pp = memchr(s, ':', (p-s)))) {
        !           239:                        if ((pp-s) > 0) {
        !           240:                                ret->user = estrndup(s, (pp-s));
        !           241:                                php_replace_controlchars_ex(ret->user, (pp - s));
        !           242:                        }       
        !           243:                
        !           244:                        pp++;
        !           245:                        if (p-pp > 0) {
        !           246:                                ret->pass = estrndup(pp, (p-pp));
        !           247:                                php_replace_controlchars_ex(ret->pass, (p-pp));
        !           248:                        }       
        !           249:                } else {
        !           250:                        ret->user = estrndup(s, (p-s));
        !           251:                        php_replace_controlchars_ex(ret->user, (p-s));
        !           252:                }
        !           253:                
        !           254:                s = p + 1;
        !           255:        }
        !           256: 
        !           257:        /* check for port */
        !           258:        if (*s == '[' && *(e-1) == ']') {
        !           259:                /* Short circuit portscan, 
        !           260:                   we're dealing with an 
        !           261:                   IPv6 embedded address */
        !           262:                p = s;
        !           263:        } else {
        !           264:                /* memrchr is a GNU specific extension
        !           265:                   Emulate for wide compatability */
        !           266:                for(p = e; *p != ':' && p >= s; p--);
        !           267:        }
        !           268: 
        !           269:        if (p >= s && *p == ':') {
        !           270:                if (!ret->port) {
        !           271:                        p++;
        !           272:                        if (e-p > 5) { /* port cannot be longer then 5 characters */
        !           273:                                STR_FREE(ret->scheme);
        !           274:                                STR_FREE(ret->user);
        !           275:                                STR_FREE(ret->pass);
        !           276:                                efree(ret);
        !           277:                                return NULL;
        !           278:                        } else if (e - p > 0) {
        !           279:                                long port;
        !           280:                                memcpy(port_buf, p, (e - p));
        !           281:                                port_buf[e - p] = '\0';
        !           282:                                port = strtol(port_buf, NULL, 10);
        !           283:                                if (port > 0 && port <= 65535) {
        !           284:                                        ret->port = (unsigned short)port;
        !           285:                                } else {
        !           286:                                        STR_FREE(ret->scheme);
        !           287:                                        STR_FREE(ret->user);
        !           288:                                        STR_FREE(ret->pass);
        !           289:                                        efree(ret);
        !           290:                                        return NULL;
        !           291:                                }
        !           292:                        }
        !           293:                        p--;
        !           294:                }       
        !           295:        } else {
        !           296:                p = e;
        !           297:        }
        !           298:        
        !           299:        /* check if we have a valid host, if we don't reject the string as url */
        !           300:        if ((p-s) < 1) {
        !           301:                STR_FREE(ret->scheme);
        !           302:                STR_FREE(ret->user);
        !           303:                STR_FREE(ret->pass);
        !           304:                efree(ret);
        !           305:                return NULL;
        !           306:        }
        !           307: 
        !           308:        ret->host = estrndup(s, (p-s));
        !           309:        php_replace_controlchars_ex(ret->host, (p - s));
        !           310:        
        !           311:        if (e == ue) {
        !           312:                return ret;
        !           313:        }
        !           314:        
        !           315:        s = e;
        !           316:        
        !           317:        nohost:
        !           318:        
        !           319:        if ((p = memchr(s, '?', (ue - s)))) {
        !           320:                pp = strchr(s, '#');
        !           321: 
        !           322:                if (pp && pp < p) {
        !           323:                        if (pp - s) {
        !           324:                                ret->path = estrndup(s, (pp-s));
        !           325:                                php_replace_controlchars_ex(ret->path, (pp - s));
        !           326:                        }
        !           327:                        p = pp;
        !           328:                        goto label_parse;
        !           329:                }
        !           330:        
        !           331:                if (p - s) {
        !           332:                        ret->path = estrndup(s, (p-s));
        !           333:                        php_replace_controlchars_ex(ret->path, (p - s));
        !           334:                }       
        !           335:        
        !           336:                if (pp) {
        !           337:                        if (pp - ++p) { 
        !           338:                                ret->query = estrndup(p, (pp-p));
        !           339:                                php_replace_controlchars_ex(ret->query, (pp - p));
        !           340:                        }
        !           341:                        p = pp;
        !           342:                        goto label_parse;
        !           343:                } else if (++p - ue) {
        !           344:                        ret->query = estrndup(p, (ue-p));
        !           345:                        php_replace_controlchars_ex(ret->query, (ue - p));
        !           346:                }
        !           347:        } else if ((p = memchr(s, '#', (ue - s)))) {
        !           348:                if (p - s) {
        !           349:                        ret->path = estrndup(s, (p-s));
        !           350:                        php_replace_controlchars_ex(ret->path, (p - s));
        !           351:                }       
        !           352:                
        !           353:                label_parse:
        !           354:                p++;
        !           355:                
        !           356:                if (ue - p) {
        !           357:                        ret->fragment = estrndup(p, (ue-p));
        !           358:                        php_replace_controlchars_ex(ret->fragment, (ue - p));
        !           359:                }       
        !           360:        } else {
        !           361:                ret->path = estrndup(s, (ue-s));
        !           362:                php_replace_controlchars_ex(ret->path, (ue - s));
        !           363:        }
        !           364: end:
        !           365:        return ret;
        !           366: }
        !           367: /* }}} */
        !           368: 
        !           369: /* {{{ proto mixed parse_url(string url, [int url_component])
        !           370:    Parse a URL and return its components */
        !           371: PHP_FUNCTION(parse_url)
        !           372: {
        !           373:        char *str;
        !           374:        int str_len;
        !           375:        php_url *resource;
        !           376:        long key = -1;
        !           377: 
        !           378:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &key) == FAILURE) {
        !           379:                return;
        !           380:        }
        !           381: 
        !           382:        resource = php_url_parse_ex(str, str_len);
        !           383:        if (resource == NULL) {
        !           384:                /* @todo Find a method to determine why php_url_parse_ex() failed */
        !           385:                RETURN_FALSE;
        !           386:        }
        !           387: 
        !           388:        if (key > -1) {
        !           389:                switch (key) {
        !           390:                        case PHP_URL_SCHEME:
        !           391:                                if (resource->scheme != NULL) RETVAL_STRING(resource->scheme, 1);
        !           392:                                break;
        !           393:                        case PHP_URL_HOST:
        !           394:                                if (resource->host != NULL) RETVAL_STRING(resource->host, 1);
        !           395:                                break;
        !           396:                        case PHP_URL_PORT:
        !           397:                                if (resource->port != 0) RETVAL_LONG(resource->port);
        !           398:                                break;
        !           399:                        case PHP_URL_USER:
        !           400:                                if (resource->user != NULL) RETVAL_STRING(resource->user, 1);
        !           401:                                break;
        !           402:                        case PHP_URL_PASS:
        !           403:                                if (resource->pass != NULL) RETVAL_STRING(resource->pass, 1);
        !           404:                                break;
        !           405:                        case PHP_URL_PATH:
        !           406:                                if (resource->path != NULL) RETVAL_STRING(resource->path, 1);
        !           407:                                break;
        !           408:                        case PHP_URL_QUERY:
        !           409:                                if (resource->query != NULL) RETVAL_STRING(resource->query, 1);
        !           410:                                break;
        !           411:                        case PHP_URL_FRAGMENT:
        !           412:                                if (resource->fragment != NULL) RETVAL_STRING(resource->fragment, 1);
        !           413:                                break;
        !           414:                        default:
        !           415:                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid URL component identifier %ld", key);
        !           416:                                RETVAL_FALSE;
        !           417:                }
        !           418:                goto done;
        !           419:        }
        !           420: 
        !           421:        /* allocate an array for return */
        !           422:        array_init(return_value);
        !           423: 
        !           424:     /* add the various elements to the array */
        !           425:        if (resource->scheme != NULL)
        !           426:                add_assoc_string(return_value, "scheme", resource->scheme, 1);
        !           427:        if (resource->host != NULL)
        !           428:                add_assoc_string(return_value, "host", resource->host, 1);
        !           429:        if (resource->port != 0)
        !           430:                add_assoc_long(return_value, "port", resource->port);
        !           431:        if (resource->user != NULL)
        !           432:                add_assoc_string(return_value, "user", resource->user, 1);
        !           433:        if (resource->pass != NULL)
        !           434:                add_assoc_string(return_value, "pass", resource->pass, 1);
        !           435:        if (resource->path != NULL)
        !           436:                add_assoc_string(return_value, "path", resource->path, 1);
        !           437:        if (resource->query != NULL)
        !           438:                add_assoc_string(return_value, "query", resource->query, 1);
        !           439:        if (resource->fragment != NULL)
        !           440:                add_assoc_string(return_value, "fragment", resource->fragment, 1);
        !           441: done:  
        !           442:        php_url_free(resource);
        !           443: }
        !           444: /* }}} */
        !           445: 
        !           446: /* {{{ php_htoi
        !           447:  */
        !           448: static int php_htoi(char *s)
        !           449: {
        !           450:        int value;
        !           451:        int c;
        !           452: 
        !           453:        c = ((unsigned char *)s)[0];
        !           454:        if (isupper(c))
        !           455:                c = tolower(c);
        !           456:        value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
        !           457: 
        !           458:        c = ((unsigned char *)s)[1];
        !           459:        if (isupper(c))
        !           460:                c = tolower(c);
        !           461:        value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
        !           462: 
        !           463:        return (value);
        !           464: }
        !           465: /* }}} */
        !           466: 
        !           467: /* rfc1738:
        !           468: 
        !           469:    ...The characters ";",
        !           470:    "/", "?", ":", "@", "=" and "&" are the characters which may be
        !           471:    reserved for special meaning within a scheme...
        !           472: 
        !           473:    ...Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
        !           474:    reserved characters used for their reserved purposes may be used
        !           475:    unencoded within a URL...
        !           476: 
        !           477:    For added safety, we only leave -_. unencoded.
        !           478:  */
        !           479: 
        !           480: static unsigned char hexchars[] = "0123456789ABCDEF";
        !           481: 
        !           482: /* {{{ php_url_encode
        !           483:  */
        !           484: PHPAPI char *php_url_encode(char const *s, int len, int *new_length)
        !           485: {
        !           486:        register unsigned char c;
        !           487:        unsigned char *to, *start;
        !           488:        unsigned char const *from, *end;
        !           489:        
        !           490:        from = (unsigned char *)s;
        !           491:        end = (unsigned char *)s + len;
        !           492:        start = to = (unsigned char *) safe_emalloc(3, len, 1);
        !           493: 
        !           494:        while (from < end) {
        !           495:                c = *from++;
        !           496: 
        !           497:                if (c == ' ') {
        !           498:                        *to++ = '+';
        !           499: #ifndef CHARSET_EBCDIC
        !           500:                } else if ((c < '0' && c != '-' && c != '.') ||
        !           501:                                   (c < 'A' && c > '9') ||
        !           502:                                   (c > 'Z' && c < 'a' && c != '_') ||
        !           503:                                   (c > 'z')) {
        !           504:                        to[0] = '%';
        !           505:                        to[1] = hexchars[c >> 4];
        !           506:                        to[2] = hexchars[c & 15];
        !           507:                        to += 3;
        !           508: #else /*CHARSET_EBCDIC*/
        !           509:                } else if (!isalnum(c) && strchr("_-.", c) == NULL) {
        !           510:                        /* Allow only alphanumeric chars and '_', '-', '.'; escape the rest */
        !           511:                        to[0] = '%';
        !           512:                        to[1] = hexchars[os_toascii[c] >> 4];
        !           513:                        to[2] = hexchars[os_toascii[c] & 15];
        !           514:                        to += 3;
        !           515: #endif /*CHARSET_EBCDIC*/
        !           516:                } else {
        !           517:                        *to++ = c;
        !           518:                }
        !           519:        }
        !           520:        *to = 0;
        !           521:        if (new_length) {
        !           522:                *new_length = to - start;
        !           523:        }
        !           524:        return (char *) start;
        !           525: }
        !           526: /* }}} */
        !           527: 
        !           528: /* {{{ proto string urlencode(string str)
        !           529:    URL-encodes string */
        !           530: PHP_FUNCTION(urlencode)
        !           531: {
        !           532:        char *in_str, *out_str;
        !           533:        int in_str_len, out_str_len;
        !           534: 
        !           535:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
        !           536:                                                          &in_str_len) == FAILURE) {
        !           537:                return;
        !           538:        }
        !           539: 
        !           540:        out_str = php_url_encode(in_str, in_str_len, &out_str_len);
        !           541:        RETURN_STRINGL(out_str, out_str_len, 0);
        !           542: }
        !           543: /* }}} */
        !           544: 
        !           545: /* {{{ proto string urldecode(string str)
        !           546:    Decodes URL-encoded string */
        !           547: PHP_FUNCTION(urldecode)
        !           548: {
        !           549:        char *in_str, *out_str;
        !           550:        int in_str_len, out_str_len;
        !           551: 
        !           552:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
        !           553:                                                          &in_str_len) == FAILURE) {
        !           554:                return;
        !           555:        }
        !           556: 
        !           557:        out_str = estrndup(in_str, in_str_len);
        !           558:        out_str_len = php_url_decode(out_str, in_str_len);
        !           559: 
        !           560:     RETURN_STRINGL(out_str, out_str_len, 0);
        !           561: }
        !           562: /* }}} */
        !           563: 
        !           564: /* {{{ php_url_decode
        !           565:  */
        !           566: PHPAPI int php_url_decode(char *str, int len)
        !           567: {
        !           568:        char *dest = str;
        !           569:        char *data = str;
        !           570: 
        !           571:        while (len--) {
        !           572:                if (*data == '+') {
        !           573:                        *dest = ' ';
        !           574:                }
        !           575:                else if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) 
        !           576:                                 && isxdigit((int) *(data + 2))) {
        !           577: #ifndef CHARSET_EBCDIC
        !           578:                        *dest = (char) php_htoi(data + 1);
        !           579: #else
        !           580:                        *dest = os_toebcdic[(char) php_htoi(data + 1)];
        !           581: #endif
        !           582:                        data += 2;
        !           583:                        len -= 2;
        !           584:                } else {
        !           585:                        *dest = *data;
        !           586:                }
        !           587:                data++;
        !           588:                dest++;
        !           589:        }
        !           590:        *dest = '\0';
        !           591:        return dest - str;
        !           592: }
        !           593: /* }}} */
        !           594: 
        !           595: /* {{{ php_raw_url_encode
        !           596:  */
        !           597: PHPAPI char *php_raw_url_encode(char const *s, int len, int *new_length)
        !           598: {
        !           599:        register int x, y;
        !           600:        unsigned char *str;
        !           601: 
        !           602:        str = (unsigned char *) safe_emalloc(3, len, 1);
        !           603:        for (x = 0, y = 0; len--; x++, y++) {
        !           604:                str[y] = (unsigned char) s[x];
        !           605: #ifndef CHARSET_EBCDIC
        !           606:                if ((str[y] < '0' && str[y] != '-' && str[y] != '.') ||
        !           607:                        (str[y] < 'A' && str[y] > '9') ||
        !           608:                        (str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
        !           609:                        (str[y] > 'z' && str[y] != '~')) {
        !           610:                        str[y++] = '%';
        !           611:                        str[y++] = hexchars[(unsigned char) s[x] >> 4];
        !           612:                        str[y] = hexchars[(unsigned char) s[x] & 15];
        !           613: #else /*CHARSET_EBCDIC*/
        !           614:                if (!isalnum(str[y]) && strchr("_-.~", str[y]) != NULL) {
        !           615:                        str[y++] = '%';
        !           616:                        str[y++] = hexchars[os_toascii[(unsigned char) s[x]] >> 4];
        !           617:                        str[y] = hexchars[os_toascii[(unsigned char) s[x]] & 15];
        !           618: #endif /*CHARSET_EBCDIC*/
        !           619:                }
        !           620:        }
        !           621:        str[y] = '\0';
        !           622:        if (new_length) {
        !           623:                *new_length = y;
        !           624:        }
        !           625:        return ((char *) str);
        !           626: }
        !           627: /* }}} */
        !           628: 
        !           629: /* {{{ proto string rawurlencode(string str)
        !           630:    URL-encodes string */
        !           631: PHP_FUNCTION(rawurlencode)
        !           632: {
        !           633:        char *in_str, *out_str;
        !           634:        int in_str_len, out_str_len;
        !           635: 
        !           636:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
        !           637:                                                          &in_str_len) == FAILURE) {
        !           638:                return;
        !           639:        }
        !           640: 
        !           641:        out_str = php_raw_url_encode(in_str, in_str_len, &out_str_len);
        !           642:        RETURN_STRINGL(out_str, out_str_len, 0);
        !           643: }
        !           644: /* }}} */
        !           645: 
        !           646: /* {{{ proto string rawurldecode(string str)
        !           647:    Decodes URL-encodes string */
        !           648: PHP_FUNCTION(rawurldecode)
        !           649: {
        !           650:        char *in_str, *out_str;
        !           651:        int in_str_len, out_str_len;
        !           652: 
        !           653:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &in_str,
        !           654:                                                          &in_str_len) == FAILURE) {
        !           655:                return;
        !           656:        }
        !           657: 
        !           658:        out_str = estrndup(in_str, in_str_len);
        !           659:        out_str_len = php_raw_url_decode(out_str, in_str_len);
        !           660: 
        !           661:     RETURN_STRINGL(out_str, out_str_len, 0);
        !           662: }
        !           663: /* }}} */
        !           664: 
        !           665: /* {{{ php_raw_url_decode
        !           666:  */
        !           667: PHPAPI int php_raw_url_decode(char *str, int len)
        !           668: {
        !           669:        char *dest = str;
        !           670:        char *data = str;
        !           671: 
        !           672:        while (len--) {
        !           673:                if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) 
        !           674:                        && isxdigit((int) *(data + 2))) {
        !           675: #ifndef CHARSET_EBCDIC
        !           676:                        *dest = (char) php_htoi(data + 1);
        !           677: #else
        !           678:                        *dest = os_toebcdic[(char) php_htoi(data + 1)];
        !           679: #endif
        !           680:                        data += 2;
        !           681:                        len -= 2;
        !           682:                } else {
        !           683:                        *dest = *data;
        !           684:                }
        !           685:                data++;
        !           686:                dest++;
        !           687:        }
        !           688:        *dest = '\0';
        !           689:        return dest - str;
        !           690: }
        !           691: /* }}} */
        !           692: 
        !           693: /* {{{ proto array get_headers(string url[, int format])
        !           694:    fetches all the headers sent by the server in response to a HTTP request */
        !           695: PHP_FUNCTION(get_headers)
        !           696: {
        !           697:        char *url;
        !           698:        int url_len;
        !           699:        php_stream_context *context;
        !           700:        php_stream *stream;
        !           701:        zval **prev_val, **hdr = NULL, **h;
        !           702:        HashPosition pos;
        !           703:        HashTable *hashT;
        !           704:        long format = 0;
        !           705:                 
        !           706:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &url, &url_len, &format) == FAILURE) {
        !           707:                return;
        !           708:        }
        !           709:        context = FG(default_context) ? FG(default_context) : (FG(default_context) = php_stream_context_alloc());
        !           710: 
        !           711:        if (!(stream = php_stream_open_wrapper_ex(url, "r", REPORT_ERRORS | STREAM_USE_URL | STREAM_ONLY_GET_HEADERS, NULL, context))) {
        !           712:                RETURN_FALSE;
        !           713:        }
        !           714: 
        !           715:        if (!stream->wrapperdata || Z_TYPE_P(stream->wrapperdata) != IS_ARRAY) {
        !           716:                php_stream_close(stream);
        !           717:                RETURN_FALSE;
        !           718:        }
        !           719: 
        !           720:        array_init(return_value);
        !           721: 
        !           722:        /* check for curl-wrappers that provide headers via a special "headers" element */
        !           723:        if (zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h) != FAILURE && Z_TYPE_PP(h) == IS_ARRAY) {
        !           724:                /* curl-wrappers don't load data until the 1st read */ 
        !           725:                if (!Z_ARRVAL_PP(h)->nNumOfElements) {
        !           726:                        php_stream_getc(stream);
        !           727:                }
        !           728:                zend_hash_find(HASH_OF(stream->wrapperdata), "headers", sizeof("headers"), (void **)&h);
        !           729:                hashT = Z_ARRVAL_PP(h); 
        !           730:        } else {
        !           731:                hashT = HASH_OF(stream->wrapperdata);
        !           732:        }
        !           733: 
        !           734:        zend_hash_internal_pointer_reset_ex(hashT, &pos);
        !           735:        while (zend_hash_get_current_data_ex(hashT, (void**)&hdr, &pos) != FAILURE) {
        !           736:                if (!hdr || Z_TYPE_PP(hdr) != IS_STRING) {
        !           737:                        zend_hash_move_forward_ex(hashT, &pos);
        !           738:                        continue;
        !           739:                }
        !           740:                if (!format) {
        !           741: no_name_header:
        !           742:                        add_next_index_stringl(return_value, Z_STRVAL_PP(hdr), Z_STRLEN_PP(hdr), 1);
        !           743:                } else {
        !           744:                        char c;
        !           745:                        char *s, *p;
        !           746: 
        !           747:                        if ((p = strchr(Z_STRVAL_PP(hdr), ':'))) {
        !           748:                                c = *p;
        !           749:                                *p = '\0';
        !           750:                                s = p + 1;
        !           751:                                while (isspace((int)*(unsigned char *)s)) {
        !           752:                                        s++;
        !           753:                                }
        !           754: 
        !           755:                                if (zend_hash_find(HASH_OF(return_value), Z_STRVAL_PP(hdr), (p - Z_STRVAL_PP(hdr) + 1), (void **) &prev_val) == FAILURE) {
        !           756:                                        add_assoc_stringl_ex(return_value, Z_STRVAL_PP(hdr), (p - Z_STRVAL_PP(hdr) + 1), s, (Z_STRLEN_PP(hdr) - (s - Z_STRVAL_PP(hdr))), 1);
        !           757:                                } else { /* some headers may occur more then once, therefor we need to remake the string into an array */
        !           758:                                        convert_to_array(*prev_val);
        !           759:                                        add_next_index_stringl(*prev_val, s, (Z_STRLEN_PP(hdr) - (s - Z_STRVAL_PP(hdr))), 1);
        !           760:                                }
        !           761: 
        !           762:                                *p = c;
        !           763:                        } else {
        !           764:                                goto no_name_header;
        !           765:                        }
        !           766:                }
        !           767:                zend_hash_move_forward_ex(hashT, &pos);
        !           768:        }
        !           769: 
        !           770:        php_stream_close(stream);
        !           771: }
        !           772: /* }}} */
        !           773: 
        !           774: /*
        !           775:  * Local variables:
        !           776:  * tab-width: 4
        !           777:  * c-basic-offset: 4
        !           778:  * End:
        !           779:  * vim600: sw=4 ts=4 fdm=marker
        !           780:  * vim<600: sw=4 ts=4
        !           781:  */

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