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

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_3/main - rfc1867.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 612
Code covered: 75.3 % Executed lines: 461
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:15 +0000 (3 days ago)

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