1999-06-13 01:50:39 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
1999-07-16 21:13:16 +08:00
| PHP version 4.0 |
1999-06-13 01:50:39 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2000-01-01 09:32:05 +08:00
| Copyright ( c ) 1997 , 1998 , 1999 , 2000 The PHP Group |
1999-06-13 01:50:39 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2000-05-18 23:34:45 +08:00
| This source file is subject to version 2.02 of the PHP license , |
1999-07-16 21:13:16 +08:00
| that is bundled with this package in the file LICENSE , and is |
| available at through the world - wide - web at |
2000-05-18 23:34:45 +08:00
| http : //www.php.net/license/2_02.txt. |
1999-07-16 21:13:16 +08:00
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
1999-06-13 01:50:39 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2000-06-04 13:46:28 +08:00
| Authors : Rasmus Lerdorf < rasmus @ php . net > |
1999-06-13 01:50:39 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
/* $Id$ */
# include <stdio.h>
# include "php.h"
1999-12-05 03:19:57 +08:00
# include "ext/standard/php_standard.h"
1999-10-15 23:22:25 +08:00
# include "ext/standard/file.h" /* for php_file_le_uploads() */
1999-06-13 01:50:39 +08:00
# include "zend_globals.h"
# include "php_globals.h"
2000-01-29 01:24:53 +08:00
# include "php_variables.h"
1999-05-26 06:28:24 +08:00
# include "rfc1867.h"
1999-06-13 01:50:39 +08:00
# define NEW_BOUNDARY_CHECK 1
2000-06-04 13:46:28 +08:00
# define SAFE_RETURN { if (namebuf) efree(namebuf); if (filenamebuf) efree(filenamebuf); if (lbuf) efree(lbuf); if (abuf) efree(abuf); if(arr_index) efree(arr_index); return; }
1999-06-13 01:50:39 +08:00
2000-04-03 05:27:32 +08:00
/* The longest property name we use in an uploaded file array */
2000-04-03 06:15:14 +08:00
# define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
2000-04-03 05:27:32 +08:00
2000-02-20 04:12:26 +08:00
static void register_http_post_files_variable ( char * strvar , char * val , zval * http_post_files ELS_DC PLS_DC )
{
int register_globals = PG ( register_globals ) ;
PG ( register_globals ) = 0 ;
php_register_variable ( strvar , val , http_post_files ELS_CC PLS_CC ) ;
PG ( register_globals ) = register_globals ;
}
static void register_http_post_files_variable_ex ( char * var , zval * val , zval * http_post_files ELS_DC PLS_DC )
{
int register_globals = PG ( register_globals ) ;
PG ( register_globals ) = 0 ;
php_register_variable_ex ( var , val , http_post_files ELS_CC PLS_CC ) ;
PG ( register_globals ) = register_globals ;
}
1999-06-13 01:50:39 +08:00
/*
* Split raw mime stream up into appropriate components
*/
2000-02-18 04:23:59 +08:00
static void php_mime_split ( char * buf , int cnt , char * boundary , zval * array_ptr )
1999-06-13 01:50:39 +08:00
{
char * ptr , * loc , * loc2 , * s , * name , * filename , * u , * fn ;
int len , state = 0 , Done = 0 , rem , urem ;
2000-02-13 01:37:11 +08:00
int eolsize ;
1999-06-13 01:50:39 +08:00
long bytes , max_file_size = 0 ;
2000-06-04 13:46:28 +08:00
char * namebuf = NULL , * filenamebuf = NULL , * lbuf = NULL ,
* abuf = NULL , * start_arr = NULL , * end_arr = NULL , * arr_index = NULL ;
1999-06-13 01:50:39 +08:00
FILE * fp ;
2000-06-04 13:46:28 +08:00
int itype , is_arr_upload = 0 , arr_len = 0 ;
2000-02-20 04:12:26 +08:00
zval * http_post_files = NULL ;
1999-06-13 01:50:39 +08:00
ELS_FETCH ( ) ;
PLS_FETCH ( ) ;
2000-02-20 04:12:26 +08:00
if ( PG ( track_vars ) ) {
ALLOC_ZVAL ( http_post_files ) ;
array_init ( http_post_files ) ;
INIT_PZVAL ( http_post_files ) ;
2000-02-27 02:59:29 +08:00
PG ( http_globals ) . post_files = http_post_files ;
2000-02-20 04:12:26 +08:00
}
1999-06-13 01:50:39 +08:00
ptr = buf ;
rem = cnt ;
len = strlen ( boundary ) ;
while ( ( ptr - buf < cnt ) & & ! Done ) {
switch ( state ) {
case 0 : /* Looking for mime boundary */
loc = memchr ( ptr , * boundary , cnt ) ;
if ( loc ) {
if ( ! strncmp ( loc , boundary , len ) ) {
state = 1 ;
2000-02-13 01:37:11 +08:00
eolsize = 2 ;
2000-02-16 06:51:18 +08:00
if ( * ( loc + len ) = = 0x0a ) {
2000-02-13 01:37:11 +08:00
eolsize = 1 ;
2000-02-16 06:51:18 +08:00
}
2000-02-13 01:37:11 +08:00
rem - = ( loc - ptr ) + len + eolsize ;
ptr = loc + len + eolsize ;
1999-06-13 01:50:39 +08:00
} else {
rem - = ( loc - ptr ) + 1 ;
ptr = loc + 1 ;
}
} else {
Done = 1 ;
}
break ;
case 1 : /* Check content-disposition */
if ( strncasecmp ( ptr , " Content-Disposition: form-data; " , 31 ) ) {
if ( rem < 31 ) {
SAFE_RETURN ;
}
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File Upload Mime headers garbled [%c%c%c%c%c] " , * ptr , * ( ptr + 1 ) , * ( ptr + 2 ) , * ( ptr + 3 ) , * ( ptr + 4 ) ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
loc = memchr ( ptr , ' \n ' , rem ) ;
name = strstr ( ptr , " name= \" " ) ;
if ( name & & name < loc ) {
name + = 7 ;
s = memchr ( name , ' \" ' , loc - name ) ;
if ( ! s ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File Upload Mime headers garbled [%c%c%c%c%c] " , * name , * ( name + 1 ) , * ( name + 2 ) , * ( name + 3 ) , * ( name + 4 ) ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
if ( namebuf ) {
efree ( namebuf ) ;
}
namebuf = estrndup ( name , s - name ) ;
if ( lbuf ) {
efree ( lbuf ) ;
}
2000-04-03 05:27:32 +08:00
lbuf = emalloc ( s - name + MAX_SIZE_OF_INDEX ) ;
1999-06-13 01:50:39 +08:00
state = 2 ;
loc2 = memchr ( loc + 1 , ' \n ' , rem ) ;
rem - = ( loc2 - ptr ) + 1 ;
ptr = loc2 + 1 ;
2000-06-04 13:46:28 +08:00
/* is_arr_upload is true when name of file upload field
* ends in [ . * ]
* start_arr is set to point to 1 st [
* end_arr points to last ]
*/
is_arr_upload = ( start_arr = strrchr ( namebuf , ' [ ' ) ) & &
( end_arr = strrchr ( namebuf , ' ] ' ) ) & &
( end_arr = namebuf + strlen ( namebuf ) - 1 ) ;
if ( is_arr_upload ) {
arr_len = strlen ( start_arr ) ;
if ( arr_index ) efree ( arr_index ) ;
arr_index = estrndup ( start_arr + 1 , arr_len - 1 ) ;
}
1999-06-13 01:50:39 +08:00
} else {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File upload error - no name component in content disposition " ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
filename = strstr ( s , " filename= \" " ) ;
if ( filename & & filename < loc ) {
filename + = 11 ;
s = memchr ( filename , ' \" ' , loc - filename ) ;
if ( ! s ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File Upload Mime headers garbled [%c%c%c%c%c] " , * filename , * ( filename + 1 ) , * ( filename + 2 ) , * ( filename + 3 ) , * ( filename + 4 ) ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
if ( filenamebuf ) {
efree ( filenamebuf ) ;
}
filenamebuf = estrndup ( filename , s - filename ) ;
2000-02-20 04:12:26 +08:00
/* Add $foo_name */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
if ( abuf ) {
efree ( abuf ) ;
}
abuf = estrndup ( namebuf , strlen ( namebuf ) - arr_len ) ;
sprintf ( lbuf , " %s_name[%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s_name " , namebuf ) ;
}
1999-06-13 01:50:39 +08:00
s = strrchr ( filenamebuf , ' \\ ' ) ;
if ( s & & s > filenamebuf ) {
2000-02-20 04:12:26 +08:00
php_register_variable ( lbuf , s + 1 , NULL ELS_CC PLS_CC ) ;
1999-06-13 01:50:39 +08:00
} else {
2000-02-20 04:12:26 +08:00
php_register_variable ( lbuf , filenamebuf , NULL ELS_CC PLS_CC ) ;
1999-06-13 01:50:39 +08:00
}
2000-02-20 04:12:26 +08:00
/* Add $foo[name] */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
sprintf ( lbuf , " %s[name][%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s[name] " , namebuf ) ;
}
2000-02-20 04:12:26 +08:00
if ( s & & s > filenamebuf ) {
register_http_post_files_variable ( lbuf , s + 1 , http_post_files ELS_CC PLS_CC ) ;
} else {
register_http_post_files_variable ( lbuf , filenamebuf , http_post_files ELS_CC PLS_CC ) ;
}
1999-06-13 01:50:39 +08:00
state = 3 ;
if ( ( loc2 - loc ) > 2 ) {
if ( ! strncasecmp ( loc + 1 , " Content-Type: " , 13 ) ) {
* ( loc2 - 1 ) = ' \0 ' ;
2000-02-20 04:12:26 +08:00
/* Add $foo_type */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
sprintf ( lbuf , " %s_type[%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s_type " , namebuf ) ;
}
2000-02-20 04:12:26 +08:00
php_register_variable ( lbuf , loc + 15 , NULL ELS_CC PLS_CC ) ;
/* Add $foo[type] */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
sprintf ( lbuf , " %s[type][%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s[type] " , namebuf ) ;
}
2000-02-20 04:12:26 +08:00
register_http_post_files_variable ( lbuf , loc + 15 , http_post_files ELS_CC PLS_CC ) ;
1999-06-13 01:50:39 +08:00
* ( loc2 - 1 ) = ' \n ' ;
}
rem - = 2 ;
ptr + = 2 ;
}
}
break ;
case 2 : /* handle form-data fields */
loc = memchr ( ptr , * boundary , rem ) ;
u = ptr ;
while ( loc ) {
if ( ! strncmp ( loc , boundary , len ) )
break ;
u = loc + 1 ;
urem = rem - ( loc - ptr ) - 1 ;
loc = memchr ( u , * boundary , urem ) ;
}
if ( ! loc ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File Upload Field Data garbled " ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
* ( loc - 4 ) = ' \0 ' ;
2000-02-18 04:23:59 +08:00
php_register_variable ( namebuf , ptr , array_ptr ELS_CC PLS_CC ) ;
1999-06-13 01:50:39 +08:00
/* And a little kludge to pick out special MAX_FILE_SIZE */
1999-12-18 03:51:39 +08:00
itype = php_check_ident_type ( namebuf ) ;
1999-06-13 01:50:39 +08:00
if ( itype ) {
u = strchr ( namebuf , ' [ ' ) ;
if ( u )
* u = ' \0 ' ;
}
if ( ! strcmp ( namebuf , " MAX_FILE_SIZE " ) ) {
max_file_size = atol ( ptr ) ;
}
if ( itype ) {
if ( u )
* u = ' [ ' ;
}
rem - = ( loc - ptr ) ;
ptr = loc ;
state = 0 ;
break ;
case 3 : /* Handle file */
loc = memchr ( ptr , * boundary , rem ) ;
u = ptr ;
while ( loc ) {
if ( ! strncmp ( loc , boundary , len )
# if NEW_BOUNDARY_CHECK
& & ( loc - 2 > buf & & * ( loc - 2 ) = = ' - ' & & * ( loc - 1 ) = = ' - ' ) /* ensure boundary is prefixed with -- */
& & ( loc - 2 = = buf | | * ( loc - 3 ) = = ' \n ' ) /* ensure beginning of line */
# endif
) {
break ;
}
u = loc + 1 ;
urem = rem - ( loc - ptr ) - 1 ;
loc = memchr ( u , * boundary , urem ) ;
}
if ( ! loc ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File Upload Error - No Mime boundary found after start of file header " ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
2000-02-20 04:12:26 +08:00
bytes = 0 ;
fn = tempnam ( PG ( upload_tmp_dir ) , " php " ) ;
1999-06-13 01:50:39 +08:00
if ( ( loc - ptr - 4 ) > PG ( upload_max_filesize ) ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " Max file size of %ld bytes exceeded - file [%s] not saved " , PG ( upload_max_filesize ) , namebuf ) ;
2000-02-20 04:12:26 +08:00
fn = " none " ;
1999-06-13 01:50:39 +08:00
} else if ( max_file_size & & ( ( loc - ptr - 4 ) > max_file_size ) ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " Max file size exceeded - file [%s] not saved " , namebuf ) ;
2000-02-20 04:12:26 +08:00
fn = " none " ;
1999-06-13 01:50:39 +08:00
} else if ( ( loc - ptr - 4 ) < = 0 ) {
2000-02-20 04:12:26 +08:00
fn = " none " ;
1999-06-13 01:50:39 +08:00
} else {
2000-04-15 22:20:01 +08:00
fp = V_FOPEN ( fn , " wb " ) ;
1999-06-13 01:50:39 +08:00
if ( ! fp ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " File Upload Error - Unable to open temporary file [%s] " , fn ) ;
1999-06-13 01:50:39 +08:00
SAFE_RETURN ;
}
bytes = fwrite ( ptr , 1 , loc - ptr - 4 , fp ) ;
fclose ( fp ) ;
1999-12-18 03:51:39 +08:00
zend_list_insert ( fn , php_file_le_uploads ( ) ) ; /* Tell PHP about the file so the destructor can unlink it later */
1999-06-13 01:50:39 +08:00
if ( bytes < ( loc - ptr - 4 ) ) {
1999-08-03 03:17:14 +08:00
php_error ( E_WARNING , " Only %d bytes were written, expected to write %ld " , bytes , loc - ptr - 4 ) ;
1999-06-13 01:50:39 +08:00
}
}
2000-02-20 04:12:26 +08:00
php_register_variable ( namebuf , fn , NULL ELS_CC PLS_CC ) ;
2000-04-03 05:27:32 +08:00
/* Add $foo[tmp_name] */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
sprintf ( lbuf , " %s[tmp_name][%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s[tmp_name] " , namebuf ) ;
}
2000-04-03 05:27:32 +08:00
register_http_post_files_variable ( lbuf , fn , http_post_files ELS_CC PLS_CC ) ;
2000-02-20 04:12:26 +08:00
{
zval file_size ;
file_size . value . lval = bytes ;
file_size . type = IS_LONG ;
/* Add $foo_size */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
sprintf ( lbuf , " %s_size[%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s_size " , namebuf ) ;
}
2000-02-20 04:12:26 +08:00
php_register_variable_ex ( lbuf , & file_size , NULL ELS_CC PLS_CC ) ;
/* Add $foo[size] */
2000-06-04 13:46:28 +08:00
if ( is_arr_upload ) {
sprintf ( lbuf , " %s[size][%s] " , abuf , arr_index ) ;
} else {
sprintf ( lbuf , " %s[size] " , namebuf ) ;
}
2000-02-20 04:12:26 +08:00
register_http_post_files_variable_ex ( lbuf , & file_size , http_post_files ELS_CC PLS_CC ) ;
}
1999-06-13 01:50:39 +08:00
state = 0 ;
rem - = ( loc - ptr ) ;
ptr = loc ;
break ;
}
}
SAFE_RETURN ;
}
2000-02-18 04:23:59 +08:00
SAPI_POST_HANDLER_FUNC ( rfc1867_post_handler )
1999-05-26 06:28:24 +08:00
{
char * boundary ;
uint boundary_len ;
2000-02-18 04:23:59 +08:00
zval * array_ptr = ( zval * ) arg ;
1999-05-29 06:41:48 +08:00
1999-05-26 06:28:24 +08:00
boundary = strstr ( content_type_dup , " boundary " ) ;
if ( ! boundary | | ! ( boundary = strchr ( boundary , ' = ' ) ) ) {
sapi_module . sapi_error ( E_COMPILE_ERROR , " Missing boundary in multipart/form-data POST data " ) ;
return ;
}
boundary + + ;
boundary_len = strlen ( boundary ) ;
1999-06-13 01:50:39 +08:00
if ( SG ( request_info ) . post_data ) {
2000-02-18 04:23:59 +08:00
php_mime_split ( SG ( request_info ) . post_data , SG ( request_info ) . post_data_length , boundary , array_ptr ) ;
1999-05-26 06:28:24 +08:00
}
}
1999-06-13 01:50:39 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
*/