PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - main - rfc1867.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 544 601 90.5 %
Date: 2015-08-02 Functions: 28 29 96.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 02 Aug 2015 07:47:06 +0000 (10 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.