Annotation of embedaddon/php/main/rfc1867.c, revision 1.1.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:    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
                     16:    |          Jani Taskinen <jani@php.net>                                |
                     17:    +----------------------------------------------------------------------+
                     18:  */
                     19: 
                     20: /* $Id: rfc1867.c 321634 2012-01-01 13:15:04Z felipe $ */
                     21: 
                     22: /*
                     23:  *  This product includes software developed by the Apache Group
                     24:  *  for use in the Apache HTTP server project (http://www.apache.org/).
                     25:  *
                     26:  */
                     27: 
                     28: #include <stdio.h>
                     29: #include "php.h"
                     30: #include "php_open_temporary_file.h"
                     31: #include "zend_globals.h"
                     32: #include "php_globals.h"
                     33: #include "php_variables.h"
                     34: #include "rfc1867.h"
                     35: #include "ext/standard/php_string.h"
                     36: 
                     37: #define DEBUG_FILE_UPLOAD ZEND_DEBUG
                     38: 
                     39: PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
                     40: 
                     41: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                     42: #include "ext/mbstring/mbstring.h"
                     43: 
                     44: static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
                     45: 
                     46: #define SAFE_RETURN { \
                     47:        php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \
                     48:        if (lbuf) efree(lbuf); \
                     49:        if (abuf) efree(abuf); \
                     50:        if (array_index) efree(array_index); \
                     51:        zend_hash_destroy(&PG(rfc1867_protected_variables)); \
                     52:        zend_llist_destroy(&header); \
                     53:        if (mbuff->boundary_next) efree(mbuff->boundary_next); \
                     54:        if (mbuff->boundary) efree(mbuff->boundary); \
                     55:        if (mbuff->buffer) efree(mbuff->buffer); \
                     56:        if (mbuff) efree(mbuff); \
                     57:        return; }
                     58: 
                     59: void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr  TSRMLS_DC) /* {{{ */
                     60: {
                     61:        int i;
                     62:        if (php_mb_encoding_translation(TSRMLS_C)) {
                     63:                if (num_vars > 0 &&
                     64:                        php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
                     65:                        php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC);
                     66:                }
                     67:                for (i = 0; i<num_vars; i += 2) {
                     68:                        safe_php_register_variable(val_list[i], val_list[i+1], len_list[i+1], array_ptr, 0 TSRMLS_CC);
                     69:                        efree(val_list[i]);
                     70:                        efree(val_list[i+1]);
                     71:                }
                     72:                efree(val_list);
                     73:                efree(len_list);
                     74:        }
                     75: }
                     76: /* }}} */
                     77: 
                     78: void php_mb_gpc_realloc_buffer(char ***pval_list, int **plen_list, int *num_vars_max, int inc  TSRMLS_DC) /* {{{ */
                     79: {
                     80:        /* allow only even increments */
                     81:        if (inc & 1) {
                     82:                inc++;
                     83:        }
                     84:        (*num_vars_max) += inc;
                     85:        *pval_list = (char **)erealloc(*pval_list, (*num_vars_max+2)*sizeof(char *));
                     86:        *plen_list = (int *)erealloc(*plen_list, (*num_vars_max+2)*sizeof(int));
                     87: }
                     88: /* }}} */
                     89: 
                     90: void php_mb_gpc_stack_variable(char *param, char *value, char ***pval_list, int **plen_list, int *num_vars, int *num_vars_max TSRMLS_DC) /* {{{ */
                     91: {
                     92:        char **val_list = *pval_list;
                     93:        int *len_list = *plen_list;
                     94: 
                     95:        if (*num_vars >= *num_vars_max) {
                     96:                php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max, 16 TSRMLS_CC);
                     97:                /* in case realloc relocated the buffer */
                     98:                val_list = *pval_list;
                     99:                len_list = *plen_list;
                    100:        }
                    101: 
                    102:        val_list[*num_vars] = (char *)estrdup(param);
                    103:        len_list[*num_vars] = strlen(param);
                    104:        (*num_vars)++;
                    105:        val_list[*num_vars] = (char *)estrdup(value);
                    106:        len_list[*num_vars] = strlen(value);
                    107:        (*num_vars)++;
                    108: }
                    109: /* }}} */
                    110: 
                    111: #else
                    112: 
                    113: #define SAFE_RETURN { \
                    114:        if (lbuf) efree(lbuf); \
                    115:        if (abuf) efree(abuf); \
                    116:        if (array_index) efree(array_index); \
                    117:        zend_hash_destroy(&PG(rfc1867_protected_variables)); \
                    118:        zend_llist_destroy(&header); \
                    119:        if (mbuff->boundary_next) efree(mbuff->boundary_next); \
                    120:        if (mbuff->boundary) efree(mbuff->boundary); \
                    121:        if (mbuff->buffer) efree(mbuff->buffer); \
                    122:        if (mbuff) efree(mbuff); \
                    123:        return; }
                    124: #endif
                    125: 
                    126: /* The longest property name we use in an uploaded file array */
                    127: #define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
                    128: 
                    129: /* The longest anonymous name */
                    130: #define MAX_SIZE_ANONNAME 33
                    131: 
                    132: /* Errors */
                    133: #define UPLOAD_ERROR_OK   0  /* File upload succesful */
                    134: #define UPLOAD_ERROR_A    1  /* Uploaded file exceeded upload_max_filesize */
                    135: #define UPLOAD_ERROR_B    2  /* Uploaded file exceeded MAX_FILE_SIZE */
                    136: #define UPLOAD_ERROR_C    3  /* Partially uploaded */
                    137: #define UPLOAD_ERROR_D    4  /* No file uploaded */
                    138: #define UPLOAD_ERROR_E    6  /* Missing /tmp or similar directory */
                    139: #define UPLOAD_ERROR_F    7  /* Failed to write file to disk */
                    140: #define UPLOAD_ERROR_X    8  /* File upload stopped by extension */
                    141: 
                    142: void php_rfc1867_register_constants(TSRMLS_D) /* {{{ */
                    143: {
                    144:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK",         UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
                    145:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE",   UPLOAD_ERROR_A,  CONST_CS | CONST_PERSISTENT);
                    146:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE",  UPLOAD_ERROR_B,  CONST_CS | CONST_PERSISTENT);
                    147:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL",    UPLOAD_ERROR_C,  CONST_CS | CONST_PERSISTENT);
                    148:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE",    UPLOAD_ERROR_D,  CONST_CS | CONST_PERSISTENT);
                    149:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E,  CONST_CS | CONST_PERSISTENT);
                    150:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F,  CONST_CS | CONST_PERSISTENT);
                    151:        REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION",  UPLOAD_ERROR_X,  CONST_CS | CONST_PERSISTENT);
                    152: }
                    153: /* }}} */
                    154: 
                    155: static void normalize_protected_variable(char *varname TSRMLS_DC) /* {{{ */
                    156: {
                    157:        char *s = varname, *index = NULL, *indexend = NULL, *p;
                    158: 
                    159:        /* overjump leading space */
                    160:        while (*s == ' ') {
                    161:                s++;
                    162:        }
                    163: 
                    164:        /* and remove it */
                    165:        if (s != varname) {
                    166:                memmove(varname, s, strlen(s)+1);
                    167:        }
                    168: 
                    169:        for (p = varname; *p && *p != '['; p++) {
                    170:                switch(*p) {
                    171:                        case ' ':
                    172:                        case '.':
                    173:                                *p = '_';
                    174:                                break;
                    175:                }
                    176:        }
                    177: 
                    178:        /* find index */
                    179:        index = strchr(varname, '[');
                    180:        if (index) {
                    181:                index++;
                    182:                s = index;
                    183:        } else {
                    184:                return;
                    185:        }
                    186: 
                    187:        /* done? */
                    188:        while (index) {
                    189:                while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
                    190:                        index++;
                    191:                }
                    192:                indexend = strchr(index, ']');
                    193:                indexend = indexend ? indexend + 1 : index + strlen(index);
                    194: 
                    195:                if (s != index) {
                    196:                        memmove(s, index, strlen(index)+1);
                    197:                        s += indexend-index;
                    198:                } else {
                    199:                        s = indexend;
                    200:                }
                    201: 
                    202:                if (*s == '[') {
                    203:                        s++;
                    204:                        index = s;
                    205:                } else {
                    206:                        index = NULL;
                    207:                }
                    208:        }
                    209:        *s = '\0';
                    210: }
                    211: /* }}} */
                    212: 
                    213: static void add_protected_variable(char *varname TSRMLS_DC) /* {{{ */
                    214: {
                    215:        int dummy = 1;
                    216: 
                    217:        normalize_protected_variable(varname TSRMLS_CC);
                    218:        zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
                    219: }
                    220: /* }}} */
                    221: 
                    222: static zend_bool is_protected_variable(char *varname TSRMLS_DC) /* {{{ */
                    223: {
                    224:        normalize_protected_variable(varname TSRMLS_CC);
                    225:        return zend_hash_exists(&PG(rfc1867_protected_variables), varname, strlen(varname)+1);
                    226: }
                    227: /* }}} */
                    228: 
                    229: static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
                    230: {
                    231:        if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
                    232:                php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC);
                    233:        }
                    234: }
                    235: /* }}} */
                    236: 
                    237: static void safe_php_register_variable_ex(char *var, zval *val, zval *track_vars_array, zend_bool override_protection TSRMLS_DC) /* {{{ */
                    238: {
                    239:        if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
                    240:                php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
                    241:        }
                    242: }
                    243: /* }}} */
                    244: 
                    245: static void register_http_post_files_variable(char *strvar, char *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
                    246: {
                    247:        int register_globals = PG(register_globals);
                    248: 
                    249:        PG(register_globals) = 0;
                    250:        safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC);
                    251:        PG(register_globals) = register_globals;
                    252: }
                    253: /* }}} */
                    254: 
                    255: static void register_http_post_files_variable_ex(char *var, zval *val, zval *http_post_files, zend_bool override_protection TSRMLS_DC) /* {{{ */
                    256: {
                    257:        int register_globals = PG(register_globals);
                    258: 
                    259:        PG(register_globals) = 0;
                    260:        safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
                    261:        PG(register_globals) = register_globals;
                    262: }
                    263: /* }}} */
                    264: 
                    265: static int unlink_filename(char **filename TSRMLS_DC) /* {{{ */
                    266: {
                    267:        VCWD_UNLINK(*filename);
                    268:        return 0;
                    269: }
                    270: /* }}} */
                    271: 
                    272: void destroy_uploaded_files_hash(TSRMLS_D) /* {{{ */
                    273: {
                    274:        zend_hash_apply(SG(rfc1867_uploaded_files), (apply_func_t) unlink_filename TSRMLS_CC);
                    275:        zend_hash_destroy(SG(rfc1867_uploaded_files));
                    276:        FREE_HASHTABLE(SG(rfc1867_uploaded_files));
                    277: }
                    278: /* }}} */
                    279: 
                    280: /* {{{ Following code is based on apache_multipart_buffer.c from libapreq-0.33 package. */
                    281: 
                    282: #define FILLUNIT (1024 * 5)
                    283: 
                    284: typedef struct {
                    285: 
                    286:        /* read buffer */
                    287:        char *buffer;
                    288:        char *buf_begin;
                    289:        int  bufsize;
                    290:        int  bytes_in_buffer;
                    291: 
                    292:        /* boundary info */
                    293:        char *boundary;
                    294:        char *boundary_next;
                    295:        int  boundary_next_len;
                    296: 
                    297: } multipart_buffer;
                    298: 
                    299: typedef struct {
                    300:        char *key;
                    301:        char *value;
                    302: } mime_header_entry;
                    303: 
                    304: /*
                    305:  * Fill up the buffer with client data.
                    306:  * Returns number of bytes added to buffer.
                    307:  */
                    308: static int fill_buffer(multipart_buffer *self TSRMLS_DC)
                    309: {
                    310:        int bytes_to_read, total_read = 0, actual_read = 0;
                    311: 
                    312:        /* shift the existing data if necessary */
                    313:        if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
                    314:                memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
                    315:        }
                    316: 
                    317:        self->buf_begin = self->buffer;
                    318: 
                    319:        /* calculate the free space in the buffer */
                    320:        bytes_to_read = self->bufsize - self->bytes_in_buffer;
                    321: 
                    322:        /* read the required number of bytes */
                    323:        while (bytes_to_read > 0) {
                    324: 
                    325:                char *buf = self->buffer + self->bytes_in_buffer;
                    326: 
                    327:                actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC);
                    328: 
                    329:                /* update the buffer length */
                    330:                if (actual_read > 0) {
                    331:                        self->bytes_in_buffer += actual_read;
                    332:                        SG(read_post_bytes) += actual_read;
                    333:                        total_read += actual_read;
                    334:                        bytes_to_read -= actual_read;
                    335:                } else {
                    336:                        break;
                    337:                }
                    338:        }
                    339: 
                    340:        return total_read;
                    341: }
                    342: 
                    343: /* eof if we are out of bytes, or if we hit the final boundary */
                    344: static int multipart_buffer_eof(multipart_buffer *self TSRMLS_DC)
                    345: {
                    346:        if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) {
                    347:                return 1;
                    348:        } else {
                    349:                return 0;
                    350:        }
                    351: }
                    352: 
                    353: /* create new multipart_buffer structure */
                    354: static multipart_buffer *multipart_buffer_new(char *boundary, int boundary_len)
                    355: {
                    356:        multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
                    357: 
                    358:        int minsize = boundary_len + 6;
                    359:        if (minsize < FILLUNIT) minsize = FILLUNIT;
                    360: 
                    361:        self->buffer = (char *) ecalloc(1, minsize + 1);
                    362:        self->bufsize = minsize;
                    363: 
                    364:        spprintf(&self->boundary, 0, "--%s", boundary);
                    365: 
                    366:        self->boundary_next_len = spprintf(&self->boundary_next, 0, "\n--%s", boundary);
                    367: 
                    368:        self->buf_begin = self->buffer;
                    369:        self->bytes_in_buffer = 0;
                    370: 
                    371:        return self;
                    372: }
                    373: 
                    374: /*
                    375:  * Gets the next CRLF terminated line from the input buffer.
                    376:  * If it doesn't find a CRLF, and the buffer isn't completely full, returns
                    377:  * NULL; otherwise, returns the beginning of the null-terminated line,
                    378:  * minus the CRLF.
                    379:  *
                    380:  * Note that we really just look for LF terminated lines. This works
                    381:  * around a bug in internet explorer for the macintosh which sends mime
                    382:  * boundaries that are only LF terminated when you use an image submit
                    383:  * button in a multipart/form-data form.
                    384:  */
                    385: static char *next_line(multipart_buffer *self)
                    386: {
                    387:        /* look for LF in the data */
                    388:        char* line = self->buf_begin;
                    389:        char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
                    390: 
                    391:        if (ptr) {      /* LF found */
                    392: 
                    393:                /* terminate the string, remove CRLF */
                    394:                if ((ptr - line) > 0 && *(ptr-1) == '\r') {
                    395:                        *(ptr-1) = 0;
                    396:                } else {
                    397:                        *ptr = 0;
                    398:                }
                    399: 
                    400:                /* bump the pointer */
                    401:                self->buf_begin = ptr + 1;
                    402:                self->bytes_in_buffer -= (self->buf_begin - line);
                    403: 
                    404:        } else {        /* no LF found */
                    405: 
                    406:                /* buffer isn't completely full, fail */
                    407:                if (self->bytes_in_buffer < self->bufsize) {
                    408:                        return NULL;
                    409:                }
                    410:                /* return entire buffer as a partial line */
                    411:                line[self->bufsize] = 0;
                    412:                self->buf_begin = ptr;
                    413:                self->bytes_in_buffer = 0;
                    414:        }
                    415: 
                    416:        return line;
                    417: }
                    418: 
                    419: /* Returns the next CRLF terminated line from the client */
                    420: static char *get_line(multipart_buffer *self TSRMLS_DC)
                    421: {
                    422:        char* ptr = next_line(self);
                    423: 
                    424:        if (!ptr) {
                    425:                fill_buffer(self TSRMLS_CC);
                    426:                ptr = next_line(self);
                    427:        }
                    428: 
                    429:        return ptr;
                    430: }
                    431: 
                    432: /* Free header entry */
                    433: static void php_free_hdr_entry(mime_header_entry *h)
                    434: {
                    435:        if (h->key) {
                    436:                efree(h->key);
                    437:        }
                    438:        if (h->value) {
                    439:                efree(h->value);
                    440:        }
                    441: }
                    442: 
                    443: /* finds a boundary */
                    444: static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC)
                    445: {
                    446:        char *line;
                    447: 
                    448:        /* loop thru lines */
                    449:        while( (line = get_line(self TSRMLS_CC)) )
                    450:        {
                    451:                /* finished if we found the boundary */
                    452:                if (!strcmp(line, boundary)) {
                    453:                        return 1;
                    454:                }
                    455:        }
                    456: 
                    457:        /* didn't find the boundary */
                    458:        return 0;
                    459: }
                    460: 
                    461: /* parse headers */
                    462: static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
                    463: {
                    464:        char *line;
                    465:        mime_header_entry prev_entry, entry;
                    466:        int prev_len, cur_len;
                    467: 
                    468:        /* didn't find boundary, abort */
                    469:        if (!find_boundary(self, self->boundary TSRMLS_CC)) {
                    470:                return 0;
                    471:        }
                    472: 
                    473:        /* get lines of text, or CRLF_CRLF */
                    474: 
                    475:        while( (line = get_line(self TSRMLS_CC)) && strlen(line) > 0 )
                    476:        {
                    477:                /* add header to table */
                    478:                char *key = line;
                    479:                char *value = NULL;
                    480: 
                    481:                /* space in the beginning means same header */
                    482:                if (!isspace(line[0])) {
                    483:                        value = strchr(line, ':');
                    484:                }
                    485: 
                    486:                if (value) {
                    487:                        *value = 0;
                    488:                        do { value++; } while(isspace(*value));
                    489: 
                    490:                        entry.value = estrdup(value);
                    491:                        entry.key = estrdup(key);
                    492: 
                    493:                } else if (zend_llist_count(header)) { /* If no ':' on the line, add to previous line */
                    494: 
                    495:                        prev_len = strlen(prev_entry.value);
                    496:                        cur_len = strlen(line);
                    497: 
                    498:                        entry.value = emalloc(prev_len + cur_len + 1);
                    499:                        memcpy(entry.value, prev_entry.value, prev_len);
                    500:                        memcpy(entry.value + prev_len, line, cur_len);
                    501:                        entry.value[cur_len + prev_len] = '\0';
                    502: 
                    503:                        entry.key = estrdup(prev_entry.key);
                    504: 
                    505:                        zend_llist_remove_tail(header);
                    506:                } else {
                    507:                        continue;
                    508:                }
                    509: 
                    510:                zend_llist_add_element(header, &entry);
                    511:                prev_entry = entry;
                    512:        }
                    513: 
                    514:        return 1;
                    515: }
                    516: 
                    517: static char *php_mime_get_hdr_value(zend_llist header, char *key)
                    518: {
                    519:        mime_header_entry *entry;
                    520: 
                    521:        if (key == NULL) {
                    522:                return NULL;
                    523:        }
                    524: 
                    525:        entry = zend_llist_get_first(&header);
                    526:        while (entry) {
                    527:                if (!strcasecmp(entry->key, key)) {
                    528:                        return entry->value;
                    529:                }
                    530:                entry = zend_llist_get_next(&header);
                    531:        }
                    532: 
                    533:        return NULL;
                    534: }
                    535: 
                    536: static char *php_ap_getword(char **line, char stop)
                    537: {
                    538:        char *pos = *line, quote;
                    539:        char *res;
                    540: 
                    541:        while (*pos && *pos != stop) {
                    542:                if ((quote = *pos) == '"' || quote == '\'') {
                    543:                        ++pos;
                    544:                        while (*pos && *pos != quote) {
                    545:                                if (*pos == '\\' && pos[1] && pos[1] == quote) {
                    546:                                        pos += 2;
                    547:                                } else {
                    548:                                        ++pos;
                    549:                                }
                    550:                        }
                    551:                        if (*pos) {
                    552:                                ++pos;
                    553:                        }
                    554:                } else ++pos;
                    555:        }
                    556:        if (*pos == '\0') {
                    557:                res = estrdup(*line);
                    558:                *line += strlen(*line);
                    559:                return res;
                    560:        }
                    561: 
                    562:        res = estrndup(*line, pos - *line);
                    563: 
                    564:        while (*pos == stop) {
                    565:                ++pos;
                    566:        }
                    567: 
                    568:        *line = pos;
                    569:        return res;
                    570: }
                    571: 
                    572: static char *substring_conf(char *start, int len, char quote TSRMLS_DC)
                    573: {
                    574:        char *result = emalloc(len + 2);
                    575:        char *resp = result;
                    576:        int i;
                    577: 
                    578:        for (i = 0; i < len; ++i) {
                    579:                if (start[i] == '\\' && (start[i + 1] == '\\' || (quote && start[i + 1] == quote))) {
                    580:                        *resp++ = start[++i];
                    581:                } else {
                    582: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                    583:                        if (php_mb_encoding_translation(TSRMLS_C)) {
                    584:                                size_t j = php_mb_gpc_mbchar_bytes(start+i TSRMLS_CC);
                    585:                                while (j-- > 0 && i < len) {
                    586:                                        *resp++ = start[i++];
                    587:                                }
                    588:                                --i;
                    589:                        } else {
                    590:                                *resp++ = start[i];
                    591:                        }
                    592: #else
                    593:                        *resp++ = start[i];
                    594: #endif
                    595:                }
                    596:        }
                    597: 
                    598:        *resp = '\0';
                    599:        return result;
                    600: }
                    601: 
                    602: static char *php_ap_getword_conf(char **line TSRMLS_DC)
                    603: {
                    604:        char *str = *line, *strend, *res, quote;
                    605: 
                    606: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                    607:        if (php_mb_encoding_translation(TSRMLS_C)) {
                    608:                int len=strlen(str);
                    609:                php_mb_gpc_encoding_detector(&str, &len, 1, NULL TSRMLS_CC);
                    610:        }
                    611: #endif
                    612: 
                    613:        while (*str && isspace(*str)) {
                    614:                ++str;
                    615:        }
                    616: 
                    617:        if (!*str) {
                    618:                *line = str;
                    619:                return estrdup("");
                    620:        }
                    621: 
                    622:        if ((quote = *str) == '"' || quote == '\'') {
                    623:                strend = str + 1;
                    624: look_for_quote:
                    625:                while (*strend && *strend != quote) {
                    626:                        if (*strend == '\\' && strend[1] && strend[1] == quote) {
                    627:                                strend += 2;
                    628:                        } else {
                    629:                                ++strend;
                    630:                        }
                    631:                }
                    632:                if (*strend && *strend == quote) {
                    633:                        char p = *(strend + 1);
                    634:                        if (p != '\r' && p != '\n' && p != '\0') {
                    635:                                strend++;
                    636:                                goto look_for_quote;
                    637:                        }
                    638:                }
                    639: 
                    640:                res = substring_conf(str + 1, strend - str - 1, quote TSRMLS_CC);
                    641: 
                    642:                if (*strend == quote) {
                    643:                        ++strend;
                    644:                }
                    645: 
                    646:        } else {
                    647: 
                    648:                strend = str;
                    649:                while (*strend && !isspace(*strend)) {
                    650:                        ++strend;
                    651:                }
                    652:                res = substring_conf(str, strend - str, 0 TSRMLS_CC);
                    653:        }
                    654: 
                    655:        while (*strend && isspace(*strend)) {
                    656:                ++strend;
                    657:        }
                    658: 
                    659:        *line = strend;
                    660:        return res;
                    661: }
                    662: 
                    663: /*
                    664:  * Search for a string in a fixed-length byte string.
                    665:  * If partial is true, partial matches are allowed at the end of the buffer.
                    666:  * Returns NULL if not found, or a pointer to the start of the first match.
                    667:  */
                    668: static void *php_ap_memstr(char *haystack, int haystacklen, char *needle, int needlen, int partial)
                    669: {
                    670:        int len = haystacklen;
                    671:        char *ptr = haystack;
                    672: 
                    673:        /* iterate through first character matches */
                    674:        while( (ptr = memchr(ptr, needle[0], len)) ) {
                    675: 
                    676:                /* calculate length after match */
                    677:                len = haystacklen - (ptr - (char *)haystack);
                    678: 
                    679:                /* done if matches up to capacity of buffer */
                    680:                if (memcmp(needle, ptr, needlen < len ? needlen : len) == 0 && (partial || len >= needlen)) {
                    681:                        break;
                    682:                }
                    683: 
                    684:                /* next character */
                    685:                ptr++; len--;
                    686:        }
                    687: 
                    688:        return ptr;
                    689: }
                    690: 
                    691: /* read until a boundary condition */
                    692: static int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes, int *end TSRMLS_DC)
                    693: {
                    694:        int len, max;
                    695:        char *bound;
                    696: 
                    697:        /* fill buffer if needed */
                    698:        if (bytes > self->bytes_in_buffer) {
                    699:                fill_buffer(self TSRMLS_CC);
                    700:        }
                    701: 
                    702:        /* look for a potential boundary match, only read data up to that point */
                    703:        if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
                    704:                max = bound - self->buf_begin;
                    705:                if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
                    706:                        *end = 1;
                    707:                }
                    708:        } else {
                    709:                max = self->bytes_in_buffer;
                    710:        }
                    711: 
                    712:        /* maximum number of bytes we are reading */
                    713:        len = max < bytes-1 ? max : bytes-1;
                    714: 
                    715:        /* if we read any data... */
                    716:        if (len > 0) {
                    717: 
                    718:                /* copy the data */
                    719:                memcpy(buf, self->buf_begin, len);
                    720:                buf[len] = 0;
                    721: 
                    722:                if (bound && len > 0 && buf[len-1] == '\r') {
                    723:                        buf[--len] = 0;
                    724:                }
                    725: 
                    726:                /* update the buffer */
                    727:                self->bytes_in_buffer -= len;
                    728:                self->buf_begin += len;
                    729:        }
                    730: 
                    731:        return len;
                    732: }
                    733: 
                    734: /*
                    735:   XXX: this is horrible memory-usage-wise, but we only expect
                    736:   to do this on small pieces of form data.
                    737: */
                    738: static char *multipart_buffer_read_body(multipart_buffer *self, unsigned int *len TSRMLS_DC)
                    739: {
                    740:        char buf[FILLUNIT], *out=NULL;
                    741:        int total_bytes=0, read_bytes=0;
                    742: 
                    743:        while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
                    744:                out = erealloc(out, total_bytes + read_bytes + 1);
                    745:                memcpy(out + total_bytes, buf, read_bytes);
                    746:                total_bytes += read_bytes;
                    747:        }
                    748: 
                    749:        if (out) {
                    750:                out[total_bytes] = '\0';
                    751:        }
                    752:        *len = total_bytes;
                    753: 
                    754:        return out;
                    755: }
                    756: /* }}} */
                    757: 
                    758: /*
                    759:  * The combined READER/HANDLER
                    760:  *
                    761:  */
                    762: 
                    763: SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler) /* {{{ */
                    764: {
                    765:        char *boundary, *s = NULL, *boundary_end = NULL, *start_arr = NULL, *array_index = NULL;
                    766:        char *temp_filename = NULL, *lbuf = NULL, *abuf = NULL;
                    767:        int boundary_len = 0, total_bytes = 0, cancel_upload = 0, is_arr_upload = 0, array_len = 0;
                    768:        int max_file_size = 0, skip_upload = 0, anonindex = 0, is_anonymous;
                    769:        zval *http_post_files = NULL;
                    770:        HashTable *uploaded_files = NULL;
                    771: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                    772:        int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
                    773:        char **val_list = NULL;
                    774: #endif
                    775:        multipart_buffer *mbuff;
                    776:        zval *array_ptr = (zval *) arg;
                    777:        int fd = -1;
                    778:        zend_llist header;
                    779:        void *event_extra_data = NULL;
                    780:        int llen = 0;
                    781:        int upload_cnt = INI_INT("max_file_uploads");
                    782: 
                    783:        if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
                    784:                sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size));
                    785:                return;
                    786:        }
                    787: 
                    788:        /* Get the boundary */
                    789:        boundary = strstr(content_type_dup, "boundary");
                    790:        if (!boundary) {
                    791:                int content_type_len = strlen(content_type_dup);
                    792:                char *content_type_lcase = estrndup(content_type_dup, content_type_len);
                    793: 
                    794:                php_strtolower(content_type_lcase, content_type_len);
                    795:                boundary = strstr(content_type_lcase, "boundary");
                    796:                if (boundary) {
                    797:                        boundary = content_type_dup + (boundary - content_type_lcase);
                    798:                }
                    799:                efree(content_type_lcase);
                    800:        }
                    801: 
                    802:        if (!boundary || !(boundary = strchr(boundary, '='))) {
                    803:                sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
                    804:                return;
                    805:        }
                    806: 
                    807:        boundary++;
                    808:        boundary_len = strlen(boundary);
                    809: 
                    810:        if (boundary[0] == '"') {
                    811:                boundary++;
                    812:                boundary_end = strchr(boundary, '"');
                    813:                if (!boundary_end) {
                    814:                        sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
                    815:                        return;
                    816:                }
                    817:        } else {
                    818:                /* search for the end of the boundary */
                    819:                boundary_end = strpbrk(boundary, ",;");
                    820:        }
                    821:        if (boundary_end) {
                    822:                boundary_end[0] = '\0';
                    823:                boundary_len = boundary_end-boundary;
                    824:        }
                    825: 
                    826:        /* Initialize the buffer */
                    827:        if (!(mbuff = multipart_buffer_new(boundary, boundary_len))) {
                    828:                sapi_module.sapi_error(E_WARNING, "Unable to initialize the input buffer");
                    829:                return;
                    830:        }
                    831: 
                    832:        /* Initialize $_FILES[] */
                    833:        zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
                    834: 
                    835:        ALLOC_HASHTABLE(uploaded_files);
                    836:        zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
                    837:        SG(rfc1867_uploaded_files) = uploaded_files;
                    838: 
                    839:        ALLOC_ZVAL(http_post_files);
                    840:        array_init(http_post_files);
                    841:        INIT_PZVAL(http_post_files);
                    842:        PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
                    843: 
                    844: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                    845:        if (php_mb_encoding_translation(TSRMLS_C)) {
                    846:                val_list = (char **)ecalloc(num_vars_max+2, sizeof(char *));
                    847:                len_list = (int *)ecalloc(num_vars_max+2, sizeof(int));
                    848:        }
                    849: #endif
                    850:        zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
                    851: 
                    852:        if (php_rfc1867_callback != NULL) {
                    853:                multipart_event_start event_start;
                    854: 
                    855:                event_start.content_length = SG(request_info).content_length;
                    856:                if (php_rfc1867_callback(MULTIPART_EVENT_START, &event_start, &event_extra_data TSRMLS_CC) == FAILURE) {
                    857:                        goto fileupload_done;
                    858:                }
                    859:        }
                    860: 
                    861:        while (!multipart_buffer_eof(mbuff TSRMLS_CC))
                    862:        {
                    863:                char buff[FILLUNIT];
                    864:                char *cd = NULL, *param = NULL, *filename = NULL, *tmp = NULL;
                    865:                size_t blen = 0, wlen = 0;
                    866:                off_t offset;
                    867: 
                    868:                zend_llist_clean(&header);
                    869: 
                    870:                if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
                    871:                        goto fileupload_done;
                    872:                }
                    873: 
                    874:                if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
                    875:                        char *pair = NULL;
                    876:                        int end = 0;
                    877: 
                    878:                        while (isspace(*cd)) {
                    879:                                ++cd;
                    880:                        }
                    881: 
                    882:                        while (*cd && (pair = php_ap_getword(&cd, ';')))
                    883:                        {
                    884:                                char *key = NULL, *word = pair;
                    885: 
                    886:                                while (isspace(*cd)) {
                    887:                                        ++cd;
                    888:                                }
                    889: 
                    890:                                if (strchr(pair, '=')) {
                    891:                                        key = php_ap_getword(&pair, '=');
                    892: 
                    893:                                        if (!strcasecmp(key, "name")) {
                    894:                                                if (param) {
                    895:                                                        efree(param);
                    896:                                                }
                    897:                                                param = php_ap_getword_conf(&pair TSRMLS_CC);
                    898:                                        } else if (!strcasecmp(key, "filename")) {
                    899:                                                if (filename) {
                    900:                                                        efree(filename);
                    901:                                                }
                    902:                                                filename = php_ap_getword_conf(&pair TSRMLS_CC);
                    903:                                        }
                    904:                                }
                    905:                                if (key) {
                    906:                                        efree(key);
                    907:                                }
                    908:                                efree(word);
                    909:                        }
                    910: 
                    911:                        /* Normal form variable, safe to read all data into memory */
                    912:                        if (!filename && param) {
                    913:                                unsigned int value_len;
                    914:                                char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
                    915:                                unsigned int new_val_len; /* Dummy variable */
                    916: 
                    917:                                if (!value) {
                    918:                                        value = estrdup("");
                    919:                                }
                    920: 
                    921:                                if (sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
                    922:                                        if (php_rfc1867_callback != NULL) {
                    923:                                                multipart_event_formdata event_formdata;
                    924:                                                size_t newlength = new_val_len;
                    925: 
                    926:                                                event_formdata.post_bytes_processed = SG(read_post_bytes);
                    927:                                                event_formdata.name = param;
                    928:                                                event_formdata.value = &value;
                    929:                                                event_formdata.length = new_val_len;
                    930:                                                event_formdata.newlength = &newlength;
                    931:                                                if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
                    932:                                                        efree(param);
                    933:                                                        efree(value);
                    934:                                                        continue;
                    935:                                                }
                    936:                                                new_val_len = newlength;
                    937:                                        }
                    938: 
                    939: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                    940:                                        if (php_mb_encoding_translation(TSRMLS_C)) {
                    941:                                                php_mb_gpc_stack_variable(param, value, &val_list, &len_list, &num_vars, &num_vars_max TSRMLS_CC);
                    942:                                        } else {
                    943:                                                safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
                    944:                                        }
                    945: #else
                    946:                                        safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
                    947: #endif
                    948:                                } else if (php_rfc1867_callback != NULL) {
                    949:                                        multipart_event_formdata event_formdata;
                    950: 
                    951:                                        event_formdata.post_bytes_processed = SG(read_post_bytes);
                    952:                                        event_formdata.name = param;
                    953:                                        event_formdata.value = &value;
                    954:                                        event_formdata.length = value_len;
                    955:                                        event_formdata.newlength = NULL;
                    956:                                        php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
                    957:                                }
                    958: 
                    959:                                if (!strcasecmp(param, "MAX_FILE_SIZE")) {
                    960:                                        max_file_size = atol(value);
                    961:                                }
                    962: 
                    963:                                efree(param);
                    964:                                efree(value);
                    965:                                continue;
                    966:                        }
                    967: 
                    968:                        /* If file_uploads=off, skip the file part */
                    969:                        if (!PG(file_uploads)) {
                    970:                                skip_upload = 1;
                    971:                        } else if (upload_cnt <= 0) {
                    972:                                skip_upload = 1;
                    973:                                sapi_module.sapi_error(E_WARNING, "Maximum number of allowable file uploads has been exceeded");
                    974:                        }
                    975: 
                    976:                        /* Return with an error if the posted data is garbled */
                    977:                        if (!param && !filename) {
                    978:                                sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
                    979:                                goto fileupload_done;
                    980:                        }
                    981: 
                    982:                        if (!param) {
                    983:                                is_anonymous = 1;
                    984:                                param = emalloc(MAX_SIZE_ANONNAME);
                    985:                                snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
                    986:                        } else {
                    987:                                is_anonymous = 0;
                    988:                        }
                    989: 
                    990:                        /* New Rule: never repair potential malicious user input */
                    991:                        if (!skip_upload) {
                    992:                                long c = 0;
                    993:                                tmp = param;
                    994: 
                    995:                                while (*tmp) {
                    996:                                        if (*tmp == '[') {
                    997:                                                c++;
                    998:                                        } else if (*tmp == ']') {
                    999:                                                c--;
                   1000:                                                if (tmp[1] && tmp[1] != '[') {
                   1001:                                                        skip_upload = 1;
                   1002:                                                        break;
                   1003:                                                }
                   1004:                                        }
                   1005:                                        if (c < 0) {
                   1006:                                                skip_upload = 1;
                   1007:                                                break;
                   1008:                                        }
                   1009:                                        tmp++;
                   1010:                                }
                   1011:                        }
                   1012: 
                   1013:                        total_bytes = cancel_upload = 0;
                   1014:                        temp_filename = NULL;
                   1015:                        fd = -1;
                   1016: 
                   1017:                        if (!skip_upload && php_rfc1867_callback != NULL) {
                   1018:                                multipart_event_file_start event_file_start;
                   1019: 
                   1020:                                event_file_start.post_bytes_processed = SG(read_post_bytes);
                   1021:                                event_file_start.name = param;
                   1022:                                event_file_start.filename = &filename;
                   1023:                                if (php_rfc1867_callback(MULTIPART_EVENT_FILE_START, &event_file_start, &event_extra_data TSRMLS_CC) == FAILURE) {
                   1024:                                        temp_filename = "";
                   1025:                                        efree(param);
                   1026:                                        efree(filename);
                   1027:                                        continue;
                   1028:                                }
                   1029:                        }
                   1030: 
                   1031:                        if (skip_upload) {
                   1032:                                efree(param);
                   1033:                                efree(filename);
                   1034:                                continue;
                   1035:                        }
                   1036: 
                   1037:                        if (strlen(filename) == 0) {
                   1038: #if DEBUG_FILE_UPLOAD
                   1039:                                sapi_module.sapi_error(E_NOTICE, "No file uploaded");
                   1040: #endif
                   1041:                                cancel_upload = UPLOAD_ERROR_D;
                   1042:                        }
                   1043: 
                   1044:                        offset = 0;
                   1045:                        end = 0;
                   1046:                        
                   1047:                        if (!cancel_upload) {
                   1048:                                /* only bother to open temp file if we have data */
                   1049:                                blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
                   1050: #if DEBUG_FILE_UPLOAD
                   1051:                                if (blen > 0) {
                   1052: #else
                   1053:                                /* in non-debug mode we have no problem with 0-length files */
                   1054:                                {
                   1055: #endif
                   1056:                                        fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC);
                   1057:                                        upload_cnt--;
                   1058:                                        if (fd == -1) {
                   1059:                                                sapi_module.sapi_error(E_WARNING, "File upload error - unable to create a temporary file");
                   1060:                                                cancel_upload = UPLOAD_ERROR_E;
                   1061:                                        }
                   1062:                                }
                   1063:                        }
                   1064: 
                   1065:                        while (!cancel_upload && (blen > 0))
                   1066:                        {
                   1067:                                if (php_rfc1867_callback != NULL) {
                   1068:                                        multipart_event_file_data event_file_data;
                   1069: 
                   1070:                                        event_file_data.post_bytes_processed = SG(read_post_bytes);
                   1071:                                        event_file_data.offset = offset;
                   1072:                                        event_file_data.data = buff;
                   1073:                                        event_file_data.length = blen;
                   1074:                                        event_file_data.newlength = &blen;
                   1075:                                        if (php_rfc1867_callback(MULTIPART_EVENT_FILE_DATA, &event_file_data, &event_extra_data TSRMLS_CC) == FAILURE) {
                   1076:                                                cancel_upload = UPLOAD_ERROR_X;
                   1077:                                                continue;
                   1078:                                        }
                   1079:                                }
                   1080: 
                   1081:                                if (PG(upload_max_filesize) > 0 && (total_bytes+blen) > PG(upload_max_filesize)) {
                   1082: #if DEBUG_FILE_UPLOAD
                   1083:                                        sapi_module.sapi_error(E_NOTICE, "upload_max_filesize of %ld bytes exceeded - file [%s=%s] not saved", PG(upload_max_filesize), param, filename);
                   1084: #endif
                   1085:                                        cancel_upload = UPLOAD_ERROR_A;
                   1086:                                } else if (max_file_size && ((total_bytes+blen) > max_file_size)) {
                   1087: #if DEBUG_FILE_UPLOAD
                   1088:                                        sapi_module.sapi_error(E_NOTICE, "MAX_FILE_SIZE of %ld bytes exceeded - file [%s=%s] not saved", max_file_size, param, filename);
                   1089: #endif
                   1090:                                        cancel_upload = UPLOAD_ERROR_B;
                   1091:                                } else if (blen > 0) {
                   1092:                                        wlen = write(fd, buff, blen);
                   1093: 
                   1094:                                        if (wlen == -1) {
                   1095:                                                /* write failed */
                   1096: #if DEBUG_FILE_UPLOAD
                   1097:                                                sapi_module.sapi_error(E_NOTICE, "write() failed - %s", strerror(errno));
                   1098: #endif
                   1099:                                                cancel_upload = UPLOAD_ERROR_F;
                   1100:                                        } else if (wlen < blen) {
                   1101: #if DEBUG_FILE_UPLOAD
                   1102:                                                sapi_module.sapi_error(E_NOTICE, "Only %d bytes were written, expected to write %d", wlen, blen);
                   1103: #endif
                   1104:                                                cancel_upload = UPLOAD_ERROR_F;
                   1105:                                        } else {
                   1106:                                                total_bytes += wlen;
                   1107:                                        }
                   1108:                                        offset += wlen;
                   1109:                                }
                   1110: 
                   1111:                                /* read data for next iteration */
                   1112:                                blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC);
                   1113:                        }
                   1114: 
                   1115:                        if (fd != -1) { /* may not be initialized if file could not be created */
                   1116:                                close(fd);
                   1117:                        }
                   1118: 
                   1119:                        if (!cancel_upload && !end) {
                   1120: #if DEBUG_FILE_UPLOAD
                   1121:                                sapi_module.sapi_error(E_NOTICE, "Missing mime boundary at the end of the data for file %s", strlen(filename) > 0 ? filename : "");
                   1122: #endif
                   1123:                                cancel_upload = UPLOAD_ERROR_C;
                   1124:                        }
                   1125: #if DEBUG_FILE_UPLOAD
                   1126:                        if (strlen(filename) > 0 && total_bytes == 0 && !cancel_upload) {
                   1127:                                sapi_module.sapi_error(E_WARNING, "Uploaded file size 0 - file [%s=%s] not saved", param, filename);
                   1128:                                cancel_upload = 5;
                   1129:                        }
                   1130: #endif
                   1131:                        if (php_rfc1867_callback != NULL) {
                   1132:                                multipart_event_file_end event_file_end;
                   1133: 
                   1134:                                event_file_end.post_bytes_processed = SG(read_post_bytes);
                   1135:                                event_file_end.temp_filename = temp_filename;
                   1136:                                event_file_end.cancel_upload = cancel_upload;
                   1137:                                if (php_rfc1867_callback(MULTIPART_EVENT_FILE_END, &event_file_end, &event_extra_data TSRMLS_CC) == FAILURE) {
                   1138:                                        cancel_upload = UPLOAD_ERROR_X;
                   1139:                                }
                   1140:                        }
                   1141: 
                   1142:                        if (cancel_upload) {
                   1143:                                if (temp_filename) {
                   1144:                                        if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
                   1145:                                                unlink(temp_filename);
                   1146:                                        }
                   1147:                                        efree(temp_filename);
                   1148:                                }
                   1149:                                temp_filename = "";
                   1150:                        } else {
                   1151:                                zend_hash_add(SG(rfc1867_uploaded_files), temp_filename, strlen(temp_filename) + 1, &temp_filename, sizeof(char *), NULL);
                   1152:                        }
                   1153: 
                   1154:                        /* is_arr_upload is true when name of file upload field
                   1155:                         * ends in [.*]
                   1156:                         * start_arr is set to point to 1st [ */
                   1157:                        is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
                   1158: 
                   1159:                        if (is_arr_upload) {
                   1160:                                array_len = strlen(start_arr);
                   1161:                                if (array_index) {
                   1162:                                        efree(array_index);
                   1163:                                }
                   1164:                                array_index = estrndup(start_arr + 1, array_len - 2);
                   1165:                        }
                   1166: 
                   1167:                        /* Add $foo_name */
                   1168:                        if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
                   1169:                                llen = strlen(param);
                   1170:                                lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
                   1171:                                llen += MAX_SIZE_OF_INDEX + 1;
                   1172:                        }
                   1173: 
                   1174:                        if (is_arr_upload) {
                   1175:                                if (abuf) efree(abuf);
                   1176:                                abuf = estrndup(param, strlen(param)-array_len);
                   1177:                                snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
                   1178:                        } else {
                   1179:                                snprintf(lbuf, llen, "%s_name", param);
                   1180:                        }
                   1181: 
                   1182: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                   1183:                        if (php_mb_encoding_translation(TSRMLS_C)) {
                   1184:                                if (num_vars >= num_vars_max) {
                   1185:                                        php_mb_gpc_realloc_buffer(&val_list, &len_list, &num_vars_max, 1 TSRMLS_CC);
                   1186:                                }
                   1187:                                val_list[num_vars] = filename;
                   1188:                                len_list[num_vars] = strlen(filename);
                   1189:                                num_vars++;
                   1190:                                if (php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
                   1191:                                        str_len = strlen(filename);
                   1192:                                        php_mb_gpc_encoding_converter(&filename, &str_len, 1, NULL, NULL TSRMLS_CC);
                   1193:                                }
                   1194:                                s = php_mb_strrchr(filename, '\\' TSRMLS_CC);
                   1195:                                if ((tmp = php_mb_strrchr(filename, '/' TSRMLS_CC)) > s) {
                   1196:                                        s = tmp;
                   1197:                                }
                   1198:                                num_vars--;
                   1199:                                goto filedone;
                   1200:                        }
                   1201: #endif
                   1202:                        /* The \ check should technically be needed for win32 systems only where
                   1203:                         * it is a valid path separator. However, IE in all it's wisdom always sends
                   1204:                         * the full path of the file on the user's filesystem, which means that unless
                   1205:                         * the user does basename() they get a bogus file name. Until IE's user base drops
                   1206:                         * to nill or problem is fixed this code must remain enabled for all systems. */
                   1207:                        s = strrchr(filename, '\\');
                   1208:                        if ((tmp = strrchr(filename, '/')) > s) {
                   1209:                                s = tmp;
                   1210:                        }
                   1211: #ifdef PHP_WIN32
                   1212:                        if (PG(magic_quotes_gpc)) {
                   1213:                                if ((tmp = strrchr(s ? s : filename, '\'')) > s) {
                   1214:                                        s = tmp;
                   1215:                                }
                   1216:                                if ((tmp = strrchr(s ? s : filename, '"')) > s) {
                   1217:                                        s = tmp;
                   1218:                                }
                   1219:                        }
                   1220: #endif
                   1221: 
                   1222: #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
                   1223: filedone:
                   1224: #endif
                   1225: 
                   1226:                        if (!is_anonymous) {
                   1227:                                if (s && s >= filename) {
                   1228:                                        safe_php_register_variable(lbuf, s+1, strlen(s+1), NULL, 0 TSRMLS_CC);
                   1229:                                } else {
                   1230:                                        safe_php_register_variable(lbuf, filename, strlen(filename), NULL, 0 TSRMLS_CC);
                   1231:                                }
                   1232:                        }
                   1233: 
                   1234:                        /* Add $foo[name] */
                   1235:                        if (is_arr_upload) {
                   1236:                                snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
                   1237:                        } else {
                   1238:                                snprintf(lbuf, llen, "%s[name]", param);
                   1239:                        }
                   1240:                        if (s && s >= filename) {
                   1241:                                register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC);
                   1242:                        } else {
                   1243:                                register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC);
                   1244:                        }
                   1245:                        efree(filename);
                   1246:                        s = NULL;
                   1247: 
                   1248:                        /* Possible Content-Type: */
                   1249:                        if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
                   1250:                                cd = "";
                   1251:                        } else {
                   1252:                                /* fix for Opera 6.01 */
                   1253:                                s = strchr(cd, ';');
                   1254:                                if (s != NULL) {
                   1255:                                        *s = '\0';
                   1256:                                }
                   1257:                        }
                   1258: 
                   1259:                        /* Add $foo_type */
                   1260:                        if (is_arr_upload) {
                   1261:                                snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
                   1262:                        } else {
                   1263:                                snprintf(lbuf, llen, "%s_type", param);
                   1264:                        }
                   1265:                        if (!is_anonymous) {
                   1266:                                safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC);
                   1267:                        }
                   1268: 
                   1269:                        /* Add $foo[type] */
                   1270:                        if (is_arr_upload) {
                   1271:                                snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
                   1272:                        } else {
                   1273:                                snprintf(lbuf, llen, "%s[type]", param);
                   1274:                        }
                   1275:                        register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
                   1276: 
                   1277:                        /* Restore Content-Type Header */
                   1278:                        if (s != NULL) {
                   1279:                                *s = ';';
                   1280:                        }
                   1281:                        s = "";
                   1282: 
                   1283:                        {
                   1284:                                /* store temp_filename as-is (without magic_quotes_gpc-ing it, in case upload_tmp_dir
                   1285:                                 * contains escapeable characters. escape only the variable name.) */
                   1286:                                zval zfilename;
                   1287: 
                   1288:                                /* Initialize variables */
                   1289:                                add_protected_variable(param TSRMLS_CC);
                   1290: 
                   1291:                                /* if param is of form xxx[.*] this will cut it to xxx */
                   1292:                                if (!is_anonymous) {
                   1293:                                        ZVAL_STRING(&zfilename, temp_filename, 1);
                   1294:                                        safe_php_register_variable_ex(param, &zfilename, NULL, 1 TSRMLS_CC);
                   1295:                                }
                   1296: 
                   1297:                                /* Add $foo[tmp_name] */
                   1298:                                if (is_arr_upload) {
                   1299:                                        snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
                   1300:                                } else {
                   1301:                                        snprintf(lbuf, llen, "%s[tmp_name]", param);
                   1302:                                }
                   1303:                                add_protected_variable(lbuf TSRMLS_CC);
                   1304:                                ZVAL_STRING(&zfilename, temp_filename, 1);
                   1305:                                register_http_post_files_variable_ex(lbuf, &zfilename, http_post_files, 1 TSRMLS_CC);
                   1306:                        }
                   1307: 
                   1308:                        {
                   1309:                                zval file_size, error_type;
                   1310: 
                   1311:                                error_type.value.lval = cancel_upload;
                   1312:                                error_type.type = IS_LONG;
                   1313: 
                   1314:                                /* Add $foo[error] */
                   1315:                                if (cancel_upload) {
                   1316:                                        file_size.value.lval = 0;
                   1317:                                        file_size.type = IS_LONG;
                   1318:                                } else {
                   1319:                                        file_size.value.lval = total_bytes;
                   1320:                                        file_size.type = IS_LONG;
                   1321:                                }
                   1322: 
                   1323:                                if (is_arr_upload) {
                   1324:                                        snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
                   1325:                                } else {
                   1326:                                        snprintf(lbuf, llen, "%s[error]", param);
                   1327:                                }
                   1328:                                register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
                   1329: 
                   1330:                                /* Add $foo_size */
                   1331:                                if (is_arr_upload) {
                   1332:                                        snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
                   1333:                                } else {
                   1334:                                        snprintf(lbuf, llen, "%s_size", param);
                   1335:                                }
                   1336:                                if (!is_anonymous) {
                   1337:                                        safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
                   1338:                                }
                   1339: 
                   1340:                                /* Add $foo[size] */
                   1341:                                if (is_arr_upload) {
                   1342:                                        snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
                   1343:                                } else {
                   1344:                                        snprintf(lbuf, llen, "%s[size]", param);
                   1345:                                }
                   1346:                                register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
                   1347:                        }
                   1348:                        efree(param);
                   1349:                }
                   1350:        }
                   1351: 
                   1352: fileupload_done:
                   1353:        if (php_rfc1867_callback != NULL) {
                   1354:                multipart_event_end event_end;
                   1355: 
                   1356:                event_end.post_bytes_processed = SG(read_post_bytes);
                   1357:                php_rfc1867_callback(MULTIPART_EVENT_END, &event_end, &event_extra_data TSRMLS_CC);
                   1358:        }
                   1359: 
                   1360:        SAFE_RETURN;
                   1361: }
                   1362: /* }}} */
                   1363: 
                   1364: /*
                   1365:  * Local variables:
                   1366:  * tab-width: 4
                   1367:  * c-basic-offset: 4
                   1368:  * End:
                   1369:  * vim600: sw=4 ts=4 fdm=marker
                   1370:  * vim<600: sw=4 ts=4
                   1371:  */

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