This source file includes following definitions.
- php_stream_memory_write
- php_stream_memory_read
- php_stream_memory_close
- php_stream_memory_flush
- php_stream_memory_seek
- php_stream_memory_cast
- php_stream_memory_stat
- php_stream_memory_set_option
- _php_stream_memory_create
- _php_stream_memory_open
- _php_stream_memory_get_buffer
- php_stream_temp_write
- php_stream_temp_read
- php_stream_temp_close
- php_stream_temp_flush
- php_stream_temp_seek
- php_stream_temp_cast
- php_stream_temp_stat
- php_stream_temp_set_option
- _php_stream_temp_create_ex
- _php_stream_temp_create
- _php_stream_temp_open
- php_stream_url_wrap_rfc2397
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 #define _GNU_SOURCE
22 #include "php.h"
23 #include "ext/standard/base64.h"
24
25 PHPAPI size_t php_url_decode(char *str, size_t len);
26
27
28
29
30
31
32
33
34
35
36
37
38
39 typedef struct {
40 char *data;
41 size_t fpos;
42 size_t fsize;
43 size_t smax;
44 int mode;
45 } php_stream_memory_data;
46
47
48
49 static size_t php_stream_memory_write(php_stream *stream, const char *buf, size_t count)
50 {
51 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
52 assert(ms != NULL);
53
54 if (ms->mode & TEMP_STREAM_READONLY) {
55 return 0;
56 }
57 if (ms->fpos + count > ms->fsize) {
58 char *tmp;
59
60 if (!ms->data) {
61 tmp = emalloc(ms->fpos + count);
62 } else {
63 tmp = erealloc(ms->data, ms->fpos + count);
64 }
65 if (!tmp) {
66 count = ms->fsize - ms->fpos + 1;
67 } else {
68 ms->data = tmp;
69 ms->fsize = ms->fpos + count;
70 }
71 }
72 if (!ms->data)
73 count = 0;
74 if (count) {
75 assert(buf!= NULL);
76 memcpy(ms->data+ms->fpos, (char*)buf, count);
77 ms->fpos += count;
78 }
79 return count;
80 }
81
82
83
84
85 static size_t php_stream_memory_read(php_stream *stream, char *buf, size_t count)
86 {
87 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
88 assert(ms != NULL);
89
90 if (ms->fpos == ms->fsize) {
91 stream->eof = 1;
92 count = 0;
93 } else {
94 if (ms->fpos + count >= ms->fsize) {
95 count = ms->fsize - ms->fpos;
96 }
97 if (count) {
98 assert(ms->data!= NULL);
99 assert(buf!= NULL);
100 memcpy(buf, ms->data+ms->fpos, count);
101 ms->fpos += count;
102 }
103 }
104 return count;
105 }
106
107
108
109
110 static int php_stream_memory_close(php_stream *stream, int close_handle)
111 {
112 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
113 assert(ms != NULL);
114
115 if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) {
116 efree(ms->data);
117 }
118 efree(ms);
119 return 0;
120 }
121
122
123
124
125 static int php_stream_memory_flush(php_stream *stream)
126 {
127
128 return 0;
129 }
130
131
132
133
134 static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
135 {
136 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
137 assert(ms != NULL);
138
139 switch(whence) {
140 case SEEK_CUR:
141 if (offset < 0) {
142 if (ms->fpos < (size_t)(-offset)) {
143 ms->fpos = 0;
144 *newoffs = -1;
145 return -1;
146 } else {
147 ms->fpos = ms->fpos + offset;
148 *newoffs = ms->fpos;
149 stream->eof = 0;
150 return 0;
151 }
152 } else {
153 if (ms->fpos + (size_t)(offset) > ms->fsize) {
154 ms->fpos = ms->fsize;
155 *newoffs = -1;
156 return -1;
157 } else {
158 ms->fpos = ms->fpos + offset;
159 *newoffs = ms->fpos;
160 stream->eof = 0;
161 return 0;
162 }
163 }
164 case SEEK_SET:
165 if (ms->fsize < (size_t)(offset)) {
166 ms->fpos = ms->fsize;
167 *newoffs = -1;
168 return -1;
169 } else {
170 ms->fpos = offset;
171 *newoffs = ms->fpos;
172 stream->eof = 0;
173 return 0;
174 }
175 case SEEK_END:
176 if (offset > 0) {
177 ms->fpos = ms->fsize;
178 *newoffs = -1;
179 return -1;
180 } else if (ms->fsize < (size_t)(-offset)) {
181 ms->fpos = 0;
182 *newoffs = -1;
183 return -1;
184 } else {
185 ms->fpos = ms->fsize + offset;
186 *newoffs = ms->fpos;
187 stream->eof = 0;
188 return 0;
189 }
190 default:
191 *newoffs = ms->fpos;
192 return -1;
193 }
194 }
195
196
197
198 static int php_stream_memory_cast(php_stream *stream, int castas, void **ret)
199 {
200 return FAILURE;
201 }
202
203
204 static int php_stream_memory_stat(php_stream *stream, php_stream_statbuf *ssb)
205 {
206 time_t timestamp = 0;
207 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
208 assert(ms != NULL);
209
210 memset(ssb, 0, sizeof(php_stream_statbuf));
211
212
213 ssb->sb.st_mode = ms->mode & TEMP_STREAM_READONLY ? 0444 : 0666;
214
215 ssb->sb.st_size = ms->fsize;
216 ssb->sb.st_mode |= S_IFREG;
217
218 #ifdef NETWARE
219 ssb->sb.st_mtime.tv_sec = timestamp;
220 ssb->sb.st_atime.tv_sec = timestamp;
221 ssb->sb.st_ctime.tv_sec = timestamp;
222 #else
223 ssb->sb.st_mtime = timestamp;
224 ssb->sb.st_atime = timestamp;
225 ssb->sb.st_ctime = timestamp;
226 #endif
227
228 ssb->sb.st_nlink = 1;
229 ssb->sb.st_rdev = -1;
230
231 ssb->sb.st_dev = 0xC;
232
233 ssb->sb.st_ino = 0;
234
235 #ifndef PHP_WIN32
236 ssb->sb.st_blksize = -1;
237 #endif
238
239 #if !defined(PHP_WIN32) && !defined(__BEOS__)
240 ssb->sb.st_blocks = -1;
241 #endif
242
243 return 0;
244 }
245
246
247 static int php_stream_memory_set_option(php_stream *stream, int option, int value, void *ptrparam)
248 {
249 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
250 size_t newsize;
251
252 switch(option) {
253 case PHP_STREAM_OPTION_TRUNCATE_API:
254 switch (value) {
255 case PHP_STREAM_TRUNCATE_SUPPORTED:
256 return PHP_STREAM_OPTION_RETURN_OK;
257
258 case PHP_STREAM_TRUNCATE_SET_SIZE:
259 if (ms->mode & TEMP_STREAM_READONLY) {
260 return PHP_STREAM_OPTION_RETURN_ERR;
261 }
262 newsize = *(size_t*)ptrparam;
263 if (newsize <= ms->fsize) {
264 if (newsize < ms->fpos) {
265 ms->fpos = newsize;
266 }
267 } else {
268 ms->data = erealloc(ms->data, newsize);
269 memset(ms->data+ms->fsize, 0, newsize - ms->fsize);
270 ms->fsize = newsize;
271 }
272 ms->fsize = newsize;
273 return PHP_STREAM_OPTION_RETURN_OK;
274 }
275 default:
276 return PHP_STREAM_OPTION_RETURN_NOTIMPL;
277 }
278 }
279
280
281 PHPAPI php_stream_ops php_stream_memory_ops = {
282 php_stream_memory_write, php_stream_memory_read,
283 php_stream_memory_close, php_stream_memory_flush,
284 "MEMORY",
285 php_stream_memory_seek,
286 php_stream_memory_cast,
287 php_stream_memory_stat,
288 php_stream_memory_set_option
289 };
290
291
292
293 PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC)
294 {
295 php_stream_memory_data *self;
296 php_stream *stream;
297
298 self = emalloc(sizeof(*self));
299 self->data = NULL;
300 self->fpos = 0;
301 self->fsize = 0;
302 self->smax = ~0u;
303 self->mode = mode;
304
305 stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
306 stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
307 return stream;
308 }
309
310
311
312
313 PHPAPI php_stream *_php_stream_memory_open(int mode, char *buf, size_t length STREAMS_DC)
314 {
315 php_stream *stream;
316 php_stream_memory_data *ms;
317
318 if ((stream = php_stream_memory_create_rel(mode)) != NULL) {
319 ms = (php_stream_memory_data*)stream->abstract;
320
321 if (mode == TEMP_STREAM_READONLY || mode == TEMP_STREAM_TAKE_BUFFER) {
322
323 ms->data = buf;
324 ms->fsize = length;
325 } else {
326 if (length) {
327 assert(buf != NULL);
328 php_stream_write(stream, buf, length);
329 }
330 }
331 }
332 return stream;
333 }
334
335
336
337
338 PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC)
339 {
340 php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
341
342 assert(ms != NULL);
343 assert(length != 0);
344
345 *length = ms->fsize;
346 return ms->data;
347 }
348
349
350
351
352
353
354 typedef struct {
355 php_stream *innerstream;
356 size_t smax;
357 int mode;
358 zval meta;
359 char* tmpdir;
360 } php_stream_temp_data;
361
362
363
364 static size_t php_stream_temp_write(php_stream *stream, const char *buf, size_t count)
365 {
366 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
367 assert(ts != NULL);
368
369 if (!ts->innerstream) {
370 return -1;
371 }
372 if (php_stream_is(ts->innerstream, PHP_STREAM_IS_MEMORY)) {
373 size_t memsize;
374 char *membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
375
376 if (memsize + count >= ts->smax) {
377 php_stream *file = php_stream_fopen_temporary_file(ts->tmpdir, "php", NULL);
378 if (file == NULL) {
379 php_error_docref(NULL, E_WARNING, "Unable to create temporary file, Check permissions in temporary files directory.");
380 return 0;
381 }
382 php_stream_write(file, membuf, memsize);
383 php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
384 ts->innerstream = file;
385 php_stream_encloses(stream, ts->innerstream);
386 }
387 }
388 return php_stream_write(ts->innerstream, buf, count);
389 }
390
391
392
393
394 static size_t php_stream_temp_read(php_stream *stream, char *buf, size_t count)
395 {
396 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
397 size_t got;
398
399 assert(ts != NULL);
400
401 if (!ts->innerstream) {
402 return -1;
403 }
404
405 got = php_stream_read(ts->innerstream, buf, count);
406
407 stream->eof = ts->innerstream->eof;
408
409 return got;
410 }
411
412
413
414
415 static int php_stream_temp_close(php_stream *stream, int close_handle)
416 {
417 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
418 int ret;
419
420 assert(ts != NULL);
421
422 if (ts->innerstream) {
423 ret = php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE));
424 } else {
425 ret = 0;
426 }
427
428 zval_ptr_dtor(&ts->meta);
429
430 if (ts->tmpdir) {
431 efree(ts->tmpdir);
432 }
433
434 efree(ts);
435
436 return ret;
437 }
438
439
440
441
442 static int php_stream_temp_flush(php_stream *stream)
443 {
444 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
445 assert(ts != NULL);
446
447 return ts->innerstream ? php_stream_flush(ts->innerstream) : -1;
448 }
449
450
451
452
453 static int php_stream_temp_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
454 {
455 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
456 int ret;
457
458 assert(ts != NULL);
459
460 if (!ts->innerstream) {
461 *newoffs = -1;
462 return -1;
463 }
464 ret = php_stream_seek(ts->innerstream, offset, whence);
465 *newoffs = php_stream_tell(ts->innerstream);
466 stream->eof = ts->innerstream->eof;
467
468 return ret;
469 }
470
471
472
473 static int php_stream_temp_cast(php_stream *stream, int castas, void **ret)
474 {
475 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
476 php_stream *file;
477 size_t memsize;
478 char *membuf;
479 zend_off_t pos;
480
481 assert(ts != NULL);
482
483 if (!ts->innerstream) {
484 return FAILURE;
485 }
486 if (php_stream_is(ts->innerstream, PHP_STREAM_IS_STDIO)) {
487 return php_stream_cast(ts->innerstream, castas, ret, 0);
488 }
489
490
491
492
493
494
495 if (ret == NULL && castas == PHP_STREAM_AS_STDIO) {
496 return SUCCESS;
497 }
498
499
500 if (ret == NULL) {
501 return FAILURE;
502 }
503
504
505 membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
506 file = php_stream_fopen_tmpfile();
507 php_stream_write(file, membuf, memsize);
508 pos = php_stream_tell(ts->innerstream);
509
510 php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
511 ts->innerstream = file;
512 php_stream_encloses(stream, ts->innerstream);
513 php_stream_seek(ts->innerstream, pos, SEEK_SET);
514
515 return php_stream_cast(ts->innerstream, castas, ret, 1);
516 }
517
518
519 static int php_stream_temp_stat(php_stream *stream, php_stream_statbuf *ssb)
520 {
521 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
522
523 if (!ts || !ts->innerstream) {
524 return -1;
525 }
526 return php_stream_stat(ts->innerstream, ssb);
527 }
528
529
530 static int php_stream_temp_set_option(php_stream *stream, int option, int value, void *ptrparam)
531 {
532 php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
533
534 switch(option) {
535 case PHP_STREAM_OPTION_META_DATA_API:
536 if (Z_TYPE(ts->meta) != IS_UNDEF) {
537 zend_hash_copy(Z_ARRVAL_P((zval*)ptrparam), Z_ARRVAL(ts->meta), zval_add_ref);
538 }
539 return PHP_STREAM_OPTION_RETURN_OK;
540 default:
541 if (ts->innerstream) {
542 return php_stream_set_option(ts->innerstream, option, value, ptrparam);
543 }
544 return PHP_STREAM_OPTION_RETURN_NOTIMPL;
545 }
546 }
547
548
549 PHPAPI php_stream_ops php_stream_temp_ops = {
550 php_stream_temp_write, php_stream_temp_read,
551 php_stream_temp_close, php_stream_temp_flush,
552 "TEMP",
553 php_stream_temp_seek,
554 php_stream_temp_cast,
555 php_stream_temp_stat,
556 php_stream_temp_set_option
557 };
558
559
560
561
562 PHPAPI php_stream *_php_stream_temp_create_ex(int mode, size_t max_memory_usage, const char *tmpdir STREAMS_DC)
563 {
564 php_stream_temp_data *self;
565 php_stream *stream;
566
567 self = ecalloc(1, sizeof(*self));
568 self->smax = max_memory_usage;
569 self->mode = mode;
570 ZVAL_UNDEF(&self->meta);
571 if (tmpdir) {
572 self->tmpdir = estrdup(tmpdir);
573 }
574 stream = php_stream_alloc_rel(&php_stream_temp_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b");
575 stream->flags |= PHP_STREAM_FLAG_NO_BUFFER;
576 self->innerstream = php_stream_memory_create_rel(mode);
577 php_stream_encloses(stream, self->innerstream);
578
579 return stream;
580 }
581
582
583
584 PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC)
585 {
586 return php_stream_temp_create_ex(mode, max_memory_usage, NULL);
587 }
588
589
590
591 PHPAPI php_stream *_php_stream_temp_open(int mode, size_t max_memory_usage, char *buf, size_t length STREAMS_DC)
592 {
593 php_stream *stream;
594 php_stream_temp_data *ts;
595 zend_off_t newoffs;
596
597 if ((stream = php_stream_temp_create_rel(mode, max_memory_usage)) != NULL) {
598 if (length) {
599 assert(buf != NULL);
600 php_stream_temp_write(stream, buf, length);
601 php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs);
602 }
603 ts = (php_stream_temp_data*)stream->abstract;
604 assert(ts != NULL);
605 ts->mode = mode;
606 }
607 return stream;
608 }
609
610
611 PHPAPI php_stream_ops php_stream_rfc2397_ops = {
612 php_stream_temp_write, php_stream_temp_read,
613 php_stream_temp_close, php_stream_temp_flush,
614 "RFC2397",
615 php_stream_temp_seek,
616 php_stream_temp_cast,
617 php_stream_temp_stat,
618 php_stream_temp_set_option
619 };
620
621 static php_stream * php_stream_url_wrap_rfc2397(php_stream_wrapper *wrapper, const char *path,
622 const char *mode, int options, zend_string **opened_path,
623 php_stream_context *context STREAMS_DC)
624 {
625 php_stream *stream;
626 php_stream_temp_data *ts;
627 char *comma, *semi, *sep, *key;
628 size_t mlen, dlen, plen, vlen;
629 zend_off_t newoffs;
630 zval meta;
631 int base64 = 0, ilen;
632 zend_string *base64_comma = NULL;
633
634 ZVAL_NULL(&meta);
635 if (memcmp(path, "data:", 5)) {
636 return NULL;
637 }
638
639 path += 5;
640 dlen = strlen(path);
641
642 if (dlen >= 2 && path[0] == '/' && path[1] == '/') {
643 dlen -= 2;
644 path += 2;
645 }
646
647 if ((comma = memchr(path, ',', dlen)) == NULL) {
648 php_stream_wrapper_log_error(wrapper, options, "rfc2397: no comma in URL");
649 return NULL;
650 }
651
652 if (comma != path) {
653
654 mlen = comma - path;
655 dlen -= mlen;
656 semi = memchr(path, ';', mlen);
657 sep = memchr(path, '/', mlen);
658
659 if (!semi && !sep) {
660 php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal media type");
661 return NULL;
662 }
663
664 array_init(&meta);
665 if (!semi) {
666 add_assoc_stringl(&meta, "mediatype", (char *) path, mlen);
667 mlen = 0;
668 } else if (sep && sep < semi) {
669 plen = semi - path;
670 add_assoc_stringl(&meta, "mediatype", (char *) path, plen);
671 mlen -= plen;
672 path += plen;
673 } else if (semi != path || mlen != sizeof(";base64")-1 || memcmp(path, ";base64", sizeof(";base64")-1)) {
674 zval_ptr_dtor(&meta);
675 php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal media type");
676 return NULL;
677 }
678
679 while(semi && (semi == path)) {
680 path++;
681 mlen--;
682 sep = memchr(path, '=', mlen);
683 semi = memchr(path, ';', mlen);
684 if (!sep || (semi && semi < sep)) {
685 if (mlen != sizeof("base64")-1 || memcmp(path, "base64", sizeof("base64")-1)) {
686
687 zval_ptr_dtor(&meta);
688 php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal parameter");
689 return NULL;
690 }
691 base64 = 1;
692 mlen -= sizeof("base64") - 1;
693 path += sizeof("base64") - 1;
694 break;
695 }
696
697 plen = sep - path;
698 vlen = (semi ? semi - sep : mlen - plen) - 1 ;
699 key = estrndup(path, plen);
700 if (plen != sizeof("mediatype")-1 || memcmp(key, "mediatype", sizeof("mediatype")-1)) {
701 add_assoc_stringl_ex(&meta, key, plen, sep + 1, vlen);
702 }
703 efree(key);
704 plen += vlen + 1;
705 mlen -= plen;
706 path += plen;
707 }
708 if (mlen) {
709 zval_ptr_dtor(&meta);
710 php_stream_wrapper_log_error(wrapper, options, "rfc2397: illegal URL");
711 return NULL;
712 }
713 } else {
714 array_init(&meta);
715 }
716 add_assoc_bool(&meta, "base64", base64);
717
718
719 comma++;
720 dlen--;
721
722 if (base64) {
723 base64_comma = php_base64_decode((const unsigned char *)comma, dlen);
724 if (!base64_comma) {
725 zval_ptr_dtor(&meta);
726 php_stream_wrapper_log_error(wrapper, options, "rfc2397: unable to decode");
727 return NULL;
728 }
729 comma = ZSTR_VAL(base64_comma);
730 ilen = (int)ZSTR_LEN(base64_comma);
731 } else {
732 comma = estrndup(comma, dlen);
733 dlen = php_url_decode(comma, dlen);
734 ilen = (int)dlen;
735 }
736
737 if ((stream = php_stream_temp_create_rel(0, ~0u)) != NULL) {
738
739 php_stream_temp_write(stream, comma, ilen);
740 php_stream_temp_seek(stream, 0, SEEK_SET, &newoffs);
741
742 vlen = strlen(mode);
743 if (vlen >= sizeof(stream->mode)) {
744 vlen = sizeof(stream->mode) - 1;
745 }
746 memcpy(stream->mode, mode, vlen);
747 stream->mode[vlen] = '\0';
748 stream->ops = &php_stream_rfc2397_ops;
749 ts = (php_stream_temp_data*)stream->abstract;
750 assert(ts != NULL);
751 ts->mode = mode && mode[0] == 'r' && mode[1] != '+' ? TEMP_STREAM_READONLY : 0;
752 ZVAL_COPY_VALUE(&ts->meta, &meta);
753 }
754 if (base64_comma) {
755 zend_string_free(base64_comma);
756 } else {
757 efree(comma);
758 }
759
760 return stream;
761 }
762
763 PHPAPI php_stream_wrapper_ops php_stream_rfc2397_wops = {
764 php_stream_url_wrap_rfc2397,
765 NULL,
766 NULL,
767 NULL,
768 NULL,
769 "RFC2397",
770 NULL,
771 NULL,
772 NULL,
773 NULL
774 };
775
776 PHPAPI php_stream_wrapper php_stream_rfc2397_wrapper = {
777 &php_stream_rfc2397_wops,
778 NULL,
779 1,
780 };
781
782
783
784
785
786
787
788
789