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 290820 2009-11-16 13:34:57Z iliaa $ */
21 :
22 : /*
23 : * This product includes software developed by the Apache Group
24 : * for use in the Apache HTTP server project (http://www.apache.org/).
25 : *
26 : */
27 :
28 : #include <stdio.h>
29 : #include "php.h"
30 : #include "php_open_temporary_file.h"
31 : #include "zend_globals.h"
32 : #include "php_globals.h"
33 : #include "php_variables.h"
34 : #include "rfc1867.h"
35 : #include "php_ini.h"
36 :
37 : #define DEBUG_FILE_UPLOAD ZEND_DEBUG
38 :
39 : PHPAPI int (*php_rfc1867_callback)(unsigned int event, void *event_data, void **extra TSRMLS_DC) = NULL;
40 :
41 : #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
42 : #include "ext/mbstring/mbstring.h"
43 :
44 : static void safe_php_register_variable(char *var, char *strval, int val_len, zval *track_vars_array, zend_bool override_protection TSRMLS_DC);
45 :
46 : #define SAFE_RETURN { \
47 : php_mb_flush_gpc_variables(num_vars, val_list, len_list, array_ptr TSRMLS_CC); \
48 : if (lbuf) efree(lbuf); \
49 : if (abuf) efree(abuf); \
50 : if (array_index) efree(array_index); \
51 : zend_hash_destroy(&PG(rfc1867_protected_variables)); \
52 : zend_llist_destroy(&header); \
53 : if (mbuff->boundary_next) efree(mbuff->boundary_next); \
54 : if (mbuff->boundary) efree(mbuff->boundary); \
55 : if (mbuff->buffer) efree(mbuff->buffer); \
56 : if (mbuff) efree(mbuff); \
57 : return; }
58 :
59 : void php_mb_flush_gpc_variables(int num_vars, char **val_list, int *len_list, zval *array_ptr TSRMLS_DC)
60 4 : {
61 : int i;
62 4 : if (php_mb_encoding_translation(TSRMLS_C)) {
63 0 : if (num_vars > 0 &&
64 : php_mb_gpc_encoding_detector(val_list, len_list, num_vars, NULL TSRMLS_CC) == SUCCESS) {
65 0 : php_mb_gpc_encoding_converter(val_list, len_list, num_vars, NULL, NULL TSRMLS_CC);
66 : }
67 0 : for (i=0; i<num_vars; i+=2){
68 0 : safe_php_register_variable(val_list[i], val_list[i+1], len_list[i+1], array_ptr, 0 TSRMLS_CC);
69 0 : efree(val_list[i]);
70 0 : efree(val_list[i+1]);
71 : }
72 0 : efree(val_list);
73 0 : efree(len_list);
74 : }
75 4 : }
76 :
77 : void php_mb_gpc_realloc_buffer(char ***pval_list, int **plen_list, int *num_vars_max, int inc TSRMLS_DC)
78 0 : {
79 : /* allow only even increments */
80 0 : if (inc & 1) {
81 0 : inc++;
82 : }
83 0 : (*num_vars_max) += inc;
84 0 : *pval_list = (char **)erealloc(*pval_list, (*num_vars_max+2)*sizeof(char *));
85 0 : *plen_list = (int *)erealloc(*plen_list, (*num_vars_max+2)*sizeof(int));
86 0 : }
87 :
88 : 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)
89 0 : {
90 0 : char **val_list=*pval_list;
91 0 : int *len_list=*plen_list;
92 :
93 0 : if (*num_vars>=*num_vars_max){
94 0 : php_mb_gpc_realloc_buffer(pval_list, plen_list, num_vars_max,
95 : 16 TSRMLS_CC);
96 : /* in case realloc relocated the buffer */
97 0 : val_list = *pval_list;
98 0 : len_list = *plen_list;
99 : }
100 :
101 0 : val_list[*num_vars] = (char *)estrdup(param);
102 0 : len_list[*num_vars] = strlen(param);
103 0 : (*num_vars)++;
104 0 : val_list[*num_vars] = (char *)estrdup(value);
105 0 : len_list[*num_vars] = strlen(value);
106 0 : (*num_vars)++;
107 0 : }
108 :
109 : #else
110 :
111 : #define SAFE_RETURN { \
112 : if (lbuf) efree(lbuf); \
113 : if (abuf) efree(abuf); \
114 : if (array_index) efree(array_index); \
115 : zend_hash_destroy(&PG(rfc1867_protected_variables)); \
116 : zend_llist_destroy(&header); \
117 : if (mbuff->boundary_next) efree(mbuff->boundary_next); \
118 : if (mbuff->boundary) efree(mbuff->boundary); \
119 : if (mbuff->buffer) efree(mbuff->buffer); \
120 : if (mbuff) efree(mbuff); \
121 : return; }
122 : #endif
123 :
124 : /* The longest property name we use in an uploaded file array */
125 : #define MAX_SIZE_OF_INDEX sizeof("[tmp_name]")
126 :
127 : /* The longest anonymous name */
128 : #define MAX_SIZE_ANONNAME 33
129 :
130 : /* Errors */
131 : #define UPLOAD_ERROR_OK 0 /* File upload succesful */
132 : #define UPLOAD_ERROR_A 1 /* Uploaded file exceeded upload_max_filesize */
133 : #define UPLOAD_ERROR_B 2 /* Uploaded file exceeded MAX_FILE_SIZE */
134 : #define UPLOAD_ERROR_C 3 /* Partially uploaded */
135 : #define UPLOAD_ERROR_D 4 /* No file uploaded */
136 : #define UPLOAD_ERROR_E 6 /* Missing /tmp or similar directory */
137 : #define UPLOAD_ERROR_F 7 /* Failed to write file to disk */
138 : #define UPLOAD_ERROR_X 8 /* File upload stopped by extension */
139 :
140 : void php_rfc1867_register_constants(TSRMLS_D)
141 13565 : {
142 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_OK", UPLOAD_ERROR_OK, CONST_CS | CONST_PERSISTENT);
143 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_INI_SIZE", UPLOAD_ERROR_A, CONST_CS | CONST_PERSISTENT);
144 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_FORM_SIZE", UPLOAD_ERROR_B, CONST_CS | CONST_PERSISTENT);
145 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_PARTIAL", UPLOAD_ERROR_C, CONST_CS | CONST_PERSISTENT);
146 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_FILE", UPLOAD_ERROR_D, CONST_CS | CONST_PERSISTENT);
147 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_NO_TMP_DIR", UPLOAD_ERROR_E, CONST_CS | CONST_PERSISTENT);
148 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_CANT_WRITE", UPLOAD_ERROR_F, CONST_CS | CONST_PERSISTENT);
149 13565 : REGISTER_MAIN_LONG_CONSTANT("UPLOAD_ERR_EXTENSION", UPLOAD_ERROR_X, CONST_CS | CONST_PERSISTENT);
150 13565 : }
151 :
152 : static void normalize_protected_variable(char *varname TSRMLS_DC)
153 54 : {
154 54 : char *s=varname, *index=NULL, *indexend=NULL, *p;
155 :
156 : /* overjump leading space */
157 108 : while (*s == ' ') {
158 0 : s++;
159 : }
160 :
161 : /* and remove it */
162 54 : if (s != varname) {
163 0 : memmove(varname, s, strlen(s)+1);
164 : }
165 :
166 432 : for (p=varname; *p && *p != '['; p++) {
167 378 : switch(*p) {
168 : case ' ':
169 : case '.':
170 0 : *p='_';
171 : break;
172 : }
173 : }
174 :
175 : /* find index */
176 54 : index = strchr(varname, '[');
177 54 : if (index) {
178 30 : index++;
179 30 : s=index;
180 : } else {
181 24 : return;
182 : }
183 :
184 : /* done? */
185 90 : while (index) {
186 :
187 60 : while (*index == ' ' || *index == '\r' || *index == '\n' || *index=='\t') {
188 0 : index++;
189 : }
190 30 : indexend = strchr(index, ']');
191 30 : indexend = indexend ? indexend + 1 : index + strlen(index);
192 :
193 30 : if (s != index) {
194 0 : memmove(s, index, strlen(index)+1);
195 0 : s += indexend-index;
196 : } else {
197 30 : s = indexend;
198 : }
199 :
200 30 : if (*s == '[') {
201 0 : s++;
202 0 : index = s;
203 : } else {
204 30 : index = NULL;
205 : }
206 : }
207 30 : *s++='\0';
208 : }
209 :
210 :
211 : static void add_protected_variable(char *varname TSRMLS_DC)
212 12 : {
213 12 : int dummy=1;
214 :
215 12 : normalize_protected_variable(varname TSRMLS_CC);
216 12 : zend_hash_add(&PG(rfc1867_protected_variables), varname, strlen(varname)+1, &dummy, sizeof(int), NULL);
217 12 : }
218 :
219 :
220 : static zend_bool is_protected_variable(char *varname TSRMLS_DC)
221 42 : {
222 42 : normalize_protected_variable(varname TSRMLS_CC);
223 42 : 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 24 : {
229 24 : if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
230 24 : php_register_variable_safe(var, strval, val_len, track_vars_array TSRMLS_CC);
231 : }
232 24 : }
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 30 : {
237 30 : if (override_protection || !is_protected_variable(var TSRMLS_CC)) {
238 30 : php_register_variable_ex(var, val, track_vars_array TSRMLS_CC);
239 : }
240 30 : }
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 12 : {
245 12 : int register_globals = PG(register_globals);
246 :
247 12 : PG(register_globals) = 0;
248 12 : safe_php_register_variable(strvar, val, strlen(val), http_post_files, override_protection TSRMLS_CC);
249 12 : PG(register_globals) = register_globals;
250 12 : }
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 18 : {
255 18 : int register_globals = PG(register_globals);
256 :
257 18 : PG(register_globals) = 0;
258 18 : safe_php_register_variable_ex(var, val, http_post_files, override_protection TSRMLS_CC);
259 18 : PG(register_globals) = register_globals;
260 18 : }
261 :
262 :
263 : static int unlink_filename(char **filename TSRMLS_DC)
264 4 : {
265 4 : VCWD_UNLINK(*filename);
266 4 : return 0;
267 : }
268 :
269 :
270 : void destroy_uploaded_files_hash(TSRMLS_D)
271 4 : {
272 4 : zend_hash_apply(SG(rfc1867_uploaded_files), (apply_func_t) unlink_filename TSRMLS_CC);
273 4 : zend_hash_destroy(SG(rfc1867_uploaded_files));
274 4 : FREE_HASHTABLE(SG(rfc1867_uploaded_files));
275 4 : }
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 26 : {
313 26 : int bytes_to_read, total_read = 0, actual_read = 0;
314 :
315 : /* shift the existing data if necessary */
316 26 : if (self->bytes_in_buffer > 0 && self->buf_begin != self->buffer) {
317 22 : memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
318 : }
319 :
320 26 : self->buf_begin = self->buffer;
321 :
322 : /* calculate the free space in the buffer */
323 26 : bytes_to_read = self->bufsize - self->bytes_in_buffer;
324 :
325 : /* read the required number of bytes */
326 56 : while (bytes_to_read > 0) {
327 :
328 30 : char *buf = self->buffer + self->bytes_in_buffer;
329 :
330 30 : actual_read = sapi_module.read_post(buf, bytes_to_read TSRMLS_CC);
331 :
332 : /* update the buffer length */
333 30 : if (actual_read > 0) {
334 4 : self->bytes_in_buffer += actual_read;
335 4 : SG(read_post_bytes) += actual_read;
336 4 : total_read += actual_read;
337 4 : bytes_to_read -= actual_read;
338 : } else {
339 26 : break;
340 : }
341 : }
342 :
343 26 : 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 13 : {
350 13 : if ( (self->bytes_in_buffer == 0 && fill_buffer(self TSRMLS_CC) < 1) ) {
351 0 : return 1;
352 : } else {
353 13 : 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 4 : {
361 4 : multipart_buffer *self = (multipart_buffer *) ecalloc(1, sizeof(multipart_buffer));
362 :
363 4 : int minsize = boundary_len + 6;
364 4 : if (minsize < FILLUNIT) minsize = FILLUNIT;
365 :
366 4 : self->buffer = (char *) ecalloc(1, minsize + 1);
367 4 : self->bufsize = minsize;
368 :
369 4 : spprintf(&self->boundary, 0, "--%s", boundary);
370 :
371 4 : self->boundary_next_len = spprintf(&self->boundary_next, 0, "\n--%s", boundary);
372 :
373 4 : self->buf_begin = self->buffer;
374 4 : self->bytes_in_buffer = 0;
375 :
376 4 : 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 52 : {
393 : /* look for LF in the data */
394 52 : char* line = self->buf_begin;
395 52 : char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
396 :
397 52 : if (ptr) { /* LF found */
398 :
399 : /* terminate the string, remove CRLF */
400 44 : if ((ptr - line) > 0 && *(ptr-1) == '\r') {
401 0 : *(ptr-1) = 0;
402 : } else {
403 44 : *ptr = 0;
404 : }
405 :
406 : /* bump the pointer */
407 44 : self->buf_begin = ptr + 1;
408 44 : self->bytes_in_buffer -= (self->buf_begin - line);
409 :
410 : } else { /* no LF found */
411 :
412 : /* buffer isn't completely full, fail */
413 8 : if (self->bytes_in_buffer < self->bufsize) {
414 8 : 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 44 : 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 48 : {
429 48 : char* ptr = next_line(self);
430 :
431 48 : if (!ptr) {
432 4 : fill_buffer(self TSRMLS_CC);
433 4 : ptr = next_line(self);
434 : }
435 :
436 48 : return ptr;
437 : }
438 :
439 :
440 : /* Free header entry */
441 : static void php_free_hdr_entry(mime_header_entry *h)
442 15 : {
443 15 : if (h->key) {
444 15 : efree(h->key);
445 : }
446 15 : if (h->value) {
447 15 : efree(h->value);
448 : }
449 15 : }
450 :
451 :
452 : /* finds a boundary */
453 : static int find_boundary(multipart_buffer *self, char *boundary TSRMLS_DC)
454 13 : {
455 : char *line;
456 :
457 : /* loop thru lines */
458 37 : while( (line = get_line(self TSRMLS_CC)) )
459 : {
460 : /* finished if we found the boundary */
461 20 : if (!strcmp(line, boundary)) {
462 9 : return 1;
463 : }
464 : }
465 :
466 : /* didn't find the boundary */
467 4 : return 0;
468 : }
469 :
470 :
471 : /* parse headers */
472 : static int multipart_buffer_headers(multipart_buffer *self, zend_llist *header TSRMLS_DC)
473 13 : {
474 : char *line;
475 : mime_header_entry prev_entry, entry;
476 : int prev_len, cur_len;
477 :
478 : /* didn't find boundary, abort */
479 13 : if (!find_boundary(self, self->boundary TSRMLS_CC)) {
480 4 : return 0;
481 : }
482 :
483 : /* get lines of text, or CRLF_CRLF */
484 :
485 33 : while( (line = get_line(self TSRMLS_CC)) && strlen(line) > 0 )
486 : {
487 : /* add header to table */
488 :
489 15 : char *key = line;
490 15 : char *value = NULL;
491 :
492 : /* space in the beginning means same header */
493 15 : if (!isspace(line[0])) {
494 15 : value = strchr(line, ':');
495 : }
496 :
497 15 : if (value) {
498 15 : *value = 0;
499 30 : do { value++; } while(isspace(*value));
500 :
501 15 : entry.value = estrdup(value);
502 15 : 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 15 : zend_llist_add_element(header, &entry);
522 15 : prev_entry = entry;
523 : }
524 :
525 9 : return 1;
526 : }
527 :
528 :
529 : static char *php_mime_get_hdr_value(zend_llist header, char *key)
530 15 : {
531 : mime_header_entry *entry;
532 :
533 15 : if (key == NULL) {
534 0 : return NULL;
535 : }
536 :
537 15 : entry = zend_llist_get_first(&header);
538 36 : while (entry) {
539 21 : if (!strcasecmp(entry->key, key)) {
540 15 : return entry->value;
541 : }
542 6 : 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 39 : {
551 39 : char *pos = *line, quote;
552 : char *res;
553 :
554 357 : while (*pos && *pos != stop) {
555 :
556 294 : if ((quote = *pos) == '"' || quote == '\'') {
557 15 : ++pos;
558 145 : while (*pos && *pos != quote) {
559 115 : if (*pos == '\\' && pos[1] && pos[1] == quote) {
560 0 : pos += 2;
561 : } else {
562 115 : ++pos;
563 : }
564 : }
565 15 : if (*pos) {
566 15 : ++pos;
567 : }
568 264 : } else ++pos;
569 :
570 : }
571 39 : if (*pos == '\0') {
572 9 : res = estrdup(*line);
573 9 : *line += strlen(*line);
574 9 : return res;
575 : }
576 :
577 30 : res = estrndup(*line, pos - *line);
578 :
579 90 : while (*pos == stop) {
580 30 : ++pos;
581 : }
582 :
583 30 : *line = pos;
584 30 : return res;
585 : }
586 :
587 :
588 : static char *substring_conf(char *start, int len, char quote TSRMLS_DC)
589 15 : {
590 15 : char *result = emalloc(len + 2);
591 15 : char *resp = result;
592 : int i;
593 :
594 130 : for (i = 0; i < len; ++i) {
595 115 : 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 115 : 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 115 : *resp++ = start[i];
607 : }
608 : #else
609 : *resp++ = start[i];
610 : #endif
611 : }
612 : }
613 :
614 15 : *resp++ = '\0';
615 15 : return result;
616 : }
617 :
618 :
619 : static char *php_ap_getword_conf(char **line TSRMLS_DC)
620 15 : {
621 15 : char *str = *line, *strend, *res, quote;
622 :
623 : #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
624 15 : 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 30 : while (*str && isspace(*str)) {
631 0 : ++str;
632 : }
633 :
634 15 : if (!*str) {
635 0 : *line = str;
636 0 : return estrdup("");
637 : }
638 :
639 30 : if ((quote = *str) == '"' || quote == '\'') {
640 15 : strend = str + 1;
641 15 : look_for_quote:
642 145 : while (*strend && *strend != quote) {
643 115 : if (*strend == '\\' && strend[1] && strend[1] == quote) {
644 0 : strend += 2;
645 : } else {
646 115 : ++strend;
647 : }
648 : }
649 15 : if (*strend && *strend == quote) {
650 15 : char p = *(strend + 1);
651 15 : if (p != '\r' && p != '\n' && p != '\0') {
652 0 : strend++;
653 0 : goto look_for_quote;
654 : }
655 : }
656 :
657 15 : res = substring_conf(str + 1, strend - str - 1, quote TSRMLS_CC);
658 :
659 15 : if (*strend == quote) {
660 15 : ++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 30 : while (*strend && isspace(*strend)) {
673 0 : ++strend;
674 : }
675 :
676 15 : *line = strend;
677 15 : 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 30 : {
688 30 : int len = haystacklen;
689 30 : char *ptr = haystack;
690 :
691 : /* iterate through first character matches */
692 62 : while( (ptr = memchr(ptr, needle[0], len)) ) {
693 :
694 : /* calculate length after match */
695 32 : len = haystacklen - (ptr - (char *)haystack);
696 :
697 : /* done if matches up to capacity of buffer */
698 32 : 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 30 : 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 18 : {
713 : int len, max;
714 : char *bound;
715 :
716 : /* fill buffer if needed */
717 18 : if (bytes > self->bytes_in_buffer) {
718 18 : fill_buffer(self TSRMLS_CC);
719 : }
720 :
721 : /* look for a potential boundary match, only read data up to that point */
722 18 : if ((bound = php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 1))) {
723 18 : max = bound - self->buf_begin;
724 18 : if (end && php_ap_memstr(self->buf_begin, self->bytes_in_buffer, self->boundary_next, self->boundary_next_len, 0)) {
725 12 : *end = 1;
726 : }
727 : } else {
728 0 : max = self->bytes_in_buffer;
729 : }
730 :
731 : /* maximum number of bytes we are reading */
732 18 : len = max < bytes-1 ? max : bytes-1;
733 :
734 : /* if we read any data... */
735 18 : if (len > 0) {
736 :
737 : /* copy the data */
738 9 : memcpy(buf, self->buf_begin, len);
739 9 : buf[len] = 0;
740 :
741 9 : if (bound && len > 0 && buf[len-1] == '\r') {
742 0 : buf[--len] = 0;
743 : }
744 :
745 : /* update the buffer */
746 9 : self->bytes_in_buffer -= len;
747 9 : self->buf_begin += len;
748 : }
749 :
750 18 : 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 3 : {
760 3 : char buf[FILLUNIT], *out=NULL;
761 3 : int total_bytes=0, read_bytes=0;
762 :
763 9 : while((read_bytes = multipart_buffer_read(self, buf, sizeof(buf), NULL TSRMLS_CC))) {
764 3 : out = erealloc(out, total_bytes + read_bytes + 1);
765 3 : memcpy(out + total_bytes, buf, read_bytes);
766 3 : total_bytes += read_bytes;
767 : }
768 :
769 3 : if (out) out[total_bytes] = '\0';
770 3 : *len = total_bytes;
771 :
772 3 : 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 4 : {
783 4 : char *boundary, *s=NULL, *boundary_end = NULL, *start_arr=NULL, *array_index=NULL;
784 4 : char *temp_filename=NULL, *lbuf=NULL, *abuf=NULL;
785 4 : int boundary_len=0, total_bytes=0, cancel_upload=0, is_arr_upload=0, array_len=0;
786 4 : int max_file_size=0, skip_upload=0, anonindex=0, is_anonymous;
787 4 : zval *http_post_files=NULL; HashTable *uploaded_files=NULL;
788 : #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
789 4 : int str_len = 0, num_vars = 0, num_vars_max = 2*10, *len_list = NULL;
790 4 : char **val_list = NULL;
791 : #endif
792 : multipart_buffer *mbuff;
793 4 : zval *array_ptr = (zval *) arg;
794 4 : int fd=-1;
795 : zend_llist header;
796 4 : void *event_extra_data = NULL;
797 4 : int llen = 0;
798 4 : int upload_cnt = INI_INT("max_file_uploads");
799 :
800 4 : if (SG(request_info).content_length > SG(post_max_size)) {
801 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));
802 0 : return;
803 : }
804 :
805 : /* Get the boundary */
806 4 : boundary = strstr(content_type_dup, "boundary");
807 4 : if (!boundary || !(boundary=strchr(boundary, '='))) {
808 0 : sapi_module.sapi_error(E_WARNING, "Missing boundary in multipart/form-data POST data");
809 0 : return;
810 : }
811 :
812 4 : boundary++;
813 4 : boundary_len = strlen(boundary);
814 :
815 4 : if (boundary[0] == '"') {
816 0 : boundary++;
817 0 : boundary_end = strchr(boundary, '"');
818 0 : if (!boundary_end) {
819 0 : sapi_module.sapi_error(E_WARNING, "Invalid boundary in multipart/form-data POST data");
820 0 : return;
821 : }
822 : } else {
823 : /* search for the end of the boundary */
824 4 : boundary_end = strchr(boundary, ',');
825 : }
826 4 : if (boundary_end) {
827 0 : boundary_end[0] = '\0';
828 0 : boundary_len = boundary_end-boundary;
829 : }
830 :
831 : /* Initialize the buffer */
832 4 : 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 4 : zend_hash_init(&PG(rfc1867_protected_variables), 5, NULL, NULL, 0);
839 :
840 4 : ALLOC_HASHTABLE(uploaded_files);
841 4 : zend_hash_init(uploaded_files, 5, NULL, (dtor_func_t) free_estring, 0);
842 4 : SG(rfc1867_uploaded_files) = uploaded_files;
843 :
844 4 : ALLOC_ZVAL(http_post_files);
845 4 : array_init(http_post_files);
846 4 : INIT_PZVAL(http_post_files);
847 4 : PG(http_globals)[TRACK_VARS_FILES] = http_post_files;
848 :
849 : #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
850 4 : 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 4 : zend_llist_init(&header, sizeof(mime_header_entry), (llist_dtor_func_t) php_free_hdr_entry, 0);
856 :
857 4 : 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 17 : while (!multipart_buffer_eof(mbuff TSRMLS_CC))
867 : {
868 : char buff[FILLUNIT];
869 13 : char *cd=NULL,*param=NULL,*filename=NULL, *tmp=NULL;
870 13 : size_t blen=0, wlen=0;
871 : off_t offset;
872 :
873 13 : zend_llist_clean(&header);
874 :
875 13 : if (!multipart_buffer_headers(mbuff, &header TSRMLS_CC)) {
876 4 : goto fileupload_done;
877 : }
878 :
879 9 : if ((cd = php_mime_get_hdr_value(header, "Content-Disposition"))) {
880 9 : char *pair=NULL;
881 9 : int end=0;
882 :
883 18 : while (isspace(*cd)) {
884 0 : ++cd;
885 : }
886 :
887 42 : while (*cd && (pair = php_ap_getword(&cd, ';')))
888 : {
889 24 : char *key=NULL, *word = pair;
890 :
891 63 : while (isspace(*cd)) {
892 15 : ++cd;
893 : }
894 :
895 24 : if (strchr(pair, '=')) {
896 15 : key = php_ap_getword(&pair, '=');
897 :
898 15 : if (!strcasecmp(key, "name")) {
899 9 : if (param) {
900 0 : efree(param);
901 : }
902 9 : param = php_ap_getword_conf(&pair TSRMLS_CC);
903 6 : } else if (!strcasecmp(key, "filename")) {
904 6 : if (filename) {
905 0 : efree(filename);
906 : }
907 6 : filename = php_ap_getword_conf(&pair TSRMLS_CC);
908 : }
909 : }
910 24 : if (key) {
911 15 : efree(key);
912 : }
913 24 : efree(word);
914 : }
915 :
916 : /* Normal form variable, safe to read all data into memory */
917 9 : if (!filename && param) {
918 : unsigned int value_len;
919 3 : char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
920 : unsigned int new_val_len; /* Dummy variable */
921 :
922 3 : if (!value) {
923 0 : value = estrdup("");
924 : }
925 :
926 3 : 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 3 : } 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 3 : if (!strcasecmp(param, "MAX_FILE_SIZE")) {
966 0 : max_file_size = atol(value);
967 : }
968 :
969 3 : efree(param);
970 3 : efree(value);
971 3 : continue;
972 : }
973 :
974 : /* If file_uploads=off, skip the file part */
975 6 : if (!PG(file_uploads)) {
976 0 : skip_upload = 1;
977 6 : } 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 6 : if (!param && !filename) {
984 0 : sapi_module.sapi_error(E_WARNING, "File Upload Mime headers garbled");
985 0 : goto fileupload_done;
986 : }
987 :
988 6 : if (!param) {
989 0 : is_anonymous = 1;
990 0 : param = emalloc(MAX_SIZE_ANONNAME);
991 0 : snprintf(param, MAX_SIZE_ANONNAME, "%u", anonindex++);
992 : } else {
993 6 : is_anonymous = 0;
994 : }
995 :
996 : /* New Rule: never repair potential malicious user input */
997 6 : if (!skip_upload) {
998 6 : char *tmp = param;
999 6 : long c = 0;
1000 :
1001 44 : while (*tmp) {
1002 32 : if (*tmp == '[') {
1003 0 : c++;
1004 32 : } else if (*tmp == ']') {
1005 0 : c--;
1006 0 : if (tmp[1] && tmp[1] != '[') {
1007 0 : skip_upload = 1;
1008 0 : break;
1009 : }
1010 : }
1011 32 : if (c < 0) {
1012 0 : skip_upload = 1;
1013 0 : break;
1014 : }
1015 32 : tmp++;
1016 : }
1017 : }
1018 :
1019 6 : total_bytes = cancel_upload = 0;
1020 :
1021 6 : if (!skip_upload) {
1022 : /* Handle file */
1023 6 : fd = php_open_temporary_fd_ex(PG(upload_tmp_dir), "php", &temp_filename, 1 TSRMLS_CC);
1024 6 : upload_cnt--;
1025 6 : 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 6 : 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 6 : if (skip_upload) {
1054 0 : efree(param);
1055 0 : efree(filename);
1056 0 : continue;
1057 : }
1058 :
1059 6 : if(strlen(filename) == 0) {
1060 : #if DEBUG_FILE_UPLOAD
1061 : sapi_module.sapi_error(E_NOTICE, "No file uploaded");
1062 : #endif
1063 0 : cancel_upload = UPLOAD_ERROR_D;
1064 : }
1065 :
1066 6 : offset = 0;
1067 6 : end = 0;
1068 18 : while (!cancel_upload && (blen = multipart_buffer_read(mbuff, buff, sizeof(buff), &end TSRMLS_CC)))
1069 : {
1070 6 : 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 6 : 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 0 : cancel_upload = UPLOAD_ERROR_A;
1090 6 : } 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 0 : cancel_upload = UPLOAD_ERROR_B;
1095 6 : } else if (blen > 0) {
1096 :
1097 6 : wlen = write(fd, buff, blen);
1098 :
1099 6 : 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 6 : } 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 6 : total_bytes += wlen;
1112 : }
1113 :
1114 6 : offset += wlen;
1115 : }
1116 : }
1117 6 : if (fd!=-1) { /* may not be initialized if file could not be created */
1118 6 : close(fd);
1119 : }
1120 6 : 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 0 : 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 6 : 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 6 : if (cancel_upload) {
1145 0 : if (temp_filename) {
1146 0 : if (cancel_upload != UPLOAD_ERROR_E) { /* file creation failed */
1147 0 : unlink(temp_filename);
1148 : }
1149 0 : efree(temp_filename);
1150 : }
1151 0 : temp_filename="";
1152 : } else {
1153 6 : 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 6 : is_arr_upload = (start_arr = strchr(param,'[')) && (param[strlen(param)-1] == ']');
1161 :
1162 6 : if (is_arr_upload) {
1163 0 : array_len = strlen(start_arr);
1164 0 : if (array_index) {
1165 0 : efree(array_index);
1166 : }
1167 0 : array_index = estrndup(start_arr+1, array_len-2);
1168 : }
1169 :
1170 : /* Add $foo_name */
1171 6 : if (llen < strlen(param) + MAX_SIZE_OF_INDEX + 1) {
1172 4 : llen = strlen(param);
1173 4 : lbuf = (char *) safe_erealloc(lbuf, llen, 1, MAX_SIZE_OF_INDEX + 1);
1174 4 : llen += MAX_SIZE_OF_INDEX + 1;
1175 : }
1176 :
1177 6 : if (is_arr_upload) {
1178 0 : if (abuf) efree(abuf);
1179 0 : abuf = estrndup(param, strlen(param)-array_len);
1180 0 : snprintf(lbuf, llen, "%s_name[%s]", abuf, array_index);
1181 : } else {
1182 6 : snprintf(lbuf, llen, "%s_name", param);
1183 : }
1184 :
1185 : #if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
1186 6 : 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 6 : s = strrchr(filename, '\\');
1213 6 : if ((tmp = strrchr(filename, '/')) > s) {
1214 0 : 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 6 : filedone:
1228 : #endif
1229 :
1230 6 : if (!is_anonymous) {
1231 6 : if (s && s > filename) {
1232 0 : safe_php_register_variable(lbuf, s+1, strlen(s+1), NULL, 0 TSRMLS_CC);
1233 : } else {
1234 6 : safe_php_register_variable(lbuf, filename, strlen(filename), NULL, 0 TSRMLS_CC);
1235 : }
1236 : }
1237 :
1238 : /* Add $foo[name] */
1239 6 : if (is_arr_upload) {
1240 0 : snprintf(lbuf, llen, "%s[name][%s]", abuf, array_index);
1241 : } else {
1242 6 : snprintf(lbuf, llen, "%s[name]", param);
1243 : }
1244 6 : if (s && s > filename) {
1245 0 : register_http_post_files_variable(lbuf, s+1, http_post_files, 0 TSRMLS_CC);
1246 : } else {
1247 6 : register_http_post_files_variable(lbuf, filename, http_post_files, 0 TSRMLS_CC);
1248 : }
1249 6 : efree(filename);
1250 6 : s = NULL;
1251 :
1252 : /* Possible Content-Type: */
1253 6 : if (cancel_upload || !(cd = php_mime_get_hdr_value(header, "Content-Type"))) {
1254 0 : cd = "";
1255 : } else {
1256 : /* fix for Opera 6.01 */
1257 6 : s = strchr(cd, ';');
1258 6 : if (s != NULL) {
1259 0 : *s = '\0';
1260 : }
1261 : }
1262 :
1263 : /* Add $foo_type */
1264 6 : if (is_arr_upload) {
1265 0 : snprintf(lbuf, llen, "%s_type[%s]", abuf, array_index);
1266 : } else {
1267 6 : snprintf(lbuf, llen, "%s_type", param);
1268 : }
1269 6 : if (!is_anonymous) {
1270 6 : safe_php_register_variable(lbuf, cd, strlen(cd), NULL, 0 TSRMLS_CC);
1271 : }
1272 :
1273 : /* Add $foo[type] */
1274 6 : if (is_arr_upload) {
1275 0 : snprintf(lbuf, llen, "%s[type][%s]", abuf, array_index);
1276 : } else {
1277 6 : snprintf(lbuf, llen, "%s[type]", param);
1278 : }
1279 6 : register_http_post_files_variable(lbuf, cd, http_post_files, 0 TSRMLS_CC);
1280 :
1281 : /* Restore Content-Type Header */
1282 6 : if (s != NULL) {
1283 0 : *s = ';';
1284 : }
1285 6 : 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 6 : add_protected_variable(param TSRMLS_CC);
1294 :
1295 : /* if param is of form xxx[.*] this will cut it to xxx */
1296 6 : if (!is_anonymous) {
1297 6 : ZVAL_STRING(&zfilename, temp_filename, 1);
1298 6 : safe_php_register_variable_ex(param, &zfilename, NULL, 1 TSRMLS_CC);
1299 : }
1300 :
1301 : /* Add $foo[tmp_name] */
1302 6 : if (is_arr_upload) {
1303 0 : snprintf(lbuf, llen, "%s[tmp_name][%s]", abuf, array_index);
1304 : } else {
1305 6 : snprintf(lbuf, llen, "%s[tmp_name]", param);
1306 : }
1307 6 : add_protected_variable(lbuf TSRMLS_CC);
1308 6 : ZVAL_STRING(&zfilename, temp_filename, 1);
1309 6 : 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 6 : error_type.value.lval = cancel_upload;
1316 6 : error_type.type = IS_LONG;
1317 :
1318 : /* Add $foo[error] */
1319 6 : if (cancel_upload) {
1320 0 : file_size.value.lval = 0;
1321 0 : file_size.type = IS_LONG;
1322 : } else {
1323 6 : file_size.value.lval = total_bytes;
1324 6 : file_size.type = IS_LONG;
1325 : }
1326 :
1327 6 : if (is_arr_upload) {
1328 0 : snprintf(lbuf, llen, "%s[error][%s]", abuf, array_index);
1329 : } else {
1330 6 : snprintf(lbuf, llen, "%s[error]", param);
1331 : }
1332 6 : register_http_post_files_variable_ex(lbuf, &error_type, http_post_files, 0 TSRMLS_CC);
1333 :
1334 : /* Add $foo_size */
1335 6 : if (is_arr_upload) {
1336 0 : snprintf(lbuf, llen, "%s_size[%s]", abuf, array_index);
1337 : } else {
1338 6 : snprintf(lbuf, llen, "%s_size", param);
1339 : }
1340 6 : if (!is_anonymous) {
1341 6 : safe_php_register_variable_ex(lbuf, &file_size, NULL, 0 TSRMLS_CC);
1342 : }
1343 :
1344 : /* Add $foo[size] */
1345 6 : if (is_arr_upload) {
1346 0 : snprintf(lbuf, llen, "%s[size][%s]", abuf, array_index);
1347 : } else {
1348 6 : snprintf(lbuf, llen, "%s[size]", param);
1349 : }
1350 6 : register_http_post_files_variable_ex(lbuf, &file_size, http_post_files, 0 TSRMLS_CC);
1351 : }
1352 6 : efree(param);
1353 : }
1354 : }
1355 4 : fileupload_done:
1356 4 : 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 4 : 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 : */
|