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