Coverage Report

Created: 2022-10-06 21:30

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