1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
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@lerdorf.on.ca> |
16 : | Stefan Röhrich <sr@linux.de> |
17 : | Zeev Suraski <zeev@zend.com> |
18 : | Jade Nicoletti <nicoletti@nns.ch> |
19 : | Michael Wallner <mike@php.net> |
20 : +----------------------------------------------------------------------+
21 : */
22 :
23 : /* $Id: zlib.c 286750 2009-08-03 18:09:19Z jani $ */
24 :
25 : #ifdef HAVE_CONFIG_H
26 : # include "config.h"
27 : #endif
28 :
29 : #include "php.h"
30 : #include "SAPI.h"
31 : #include "php_ini.h"
32 : #include "ext/standard/info.h"
33 : #include "ext/standard/file.h"
34 :
35 : #include "php_zlib.h"
36 :
37 : ZEND_DECLARE_MODULE_GLOBALS(zlib);
38 :
39 : /* {{{ Memory management wrappers */
40 :
41 : static voidpf php_zlib_alloc(voidpf opaque, uInt items, uInt size)
42 728 : {
43 728 : return (voidpf)safe_emalloc(items, size, 0);
44 : }
45 :
46 : static void php_zlib_free(voidpf opaque, voidpf address)
47 728 : {
48 728 : efree((void*)address);
49 728 : }
50 : /* }}} */
51 :
52 : /* {{{ php_zlib_output_conflict_check() */
53 : static int php_zlib_output_conflict_check(zval *handler_name TSRMLS_DC)
54 5 : {
55 5 : if (php_output_get_level(TSRMLS_C) > 0) {
56 0 : PHP_OUTPUT_CONFLICT(PHP_ZLIB_OUTPUT_HANDLER_NAME, return FAILURE);
57 0 : PHP_OUTPUT_CONFLICT("ob_gzhandler", return FAILURE);
58 0 : PHP_OUTPUT_CONFLICT("mb_output_handler", return FAILURE);
59 0 : PHP_OUTPUT_CONFLICT("URL-Rewriter", return FAILURE);
60 : }
61 5 : return SUCCESS;
62 : }
63 : /* }}} */
64 :
65 : /* {{{ php_zlib_output_encoding() */
66 : static int php_zlib_output_encoding(TSRMLS_D)
67 5 : {
68 : zval **enc;
69 :
70 5 : if (!ZLIBG(compression_coding)) {
71 5 : zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC);
72 :
73 5 : if (PG(http_globals)[TRACK_VARS_SERVER] && SUCCESS == zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_ACCEPT_ENCODING", sizeof("HTTP_ACCEPT_ENCODING"), (void *) &enc)) {
74 3 : convert_to_string(*enc);
75 3 : if (strstr(Z_STRVAL_PP(enc), "gzip")) {
76 3 : ZLIBG(compression_coding) = PHP_ZLIB_ENCODING_GZIP;
77 0 : } else if (strstr(Z_STRVAL_PP(enc), "deflate")) {
78 0 : ZLIBG(compression_coding) = PHP_ZLIB_ENCODING_DEFLATE;
79 : }
80 : }
81 : }
82 :
83 5 : return ZLIBG(compression_coding);
84 : }
85 : /* }}} */
86 :
87 : /* {{{ php_zlib_output_handler() */
88 : static int php_zlib_output_handler(void **handler_context, php_output_context *output_context)
89 5 : {
90 5 : php_zlib_context *ctx = *(php_zlib_context **) handler_context;
91 5 : int flags = Z_SYNC_FLUSH;
92 : PHP_OUTPUT_TSRMLS(output_context);
93 :
94 5 : if (!php_zlib_output_encoding(TSRMLS_C)) {
95 : /* "Vary: Accept-Encoding" header sent along uncompressed content breaks caching in MSIE,
96 : so let's just send it with successfully compressed content or unless the complete
97 : buffer gets discarded, see http://bugs.php.net/40325;
98 :
99 : Test as follows:
100 : +Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
101 : +Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n";'
102 : -Vary: $ HTTP_ACCEPT_ENCODING=gzip ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
103 : -Vary: $ HTTP_ACCEPT_ENCODING= ./sapi/cgi/php <<<'<?php ob_start("ob_gzhandler"); echo "foo\n"; ob_end_clean();'
104 : */
105 2 : if (output_context->op != (PHP_OUTPUT_HANDLER_START|PHP_OUTPUT_HANDLER_CLEAN|PHP_OUTPUT_HANDLER_FINAL)) {
106 2 : sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
107 : }
108 2 : return FAILURE;
109 : }
110 :
111 3 : if (output_context->op & PHP_OUTPUT_HANDLER_START) {
112 : /* start up */
113 3 : if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
114 0 : return FAILURE;
115 : }
116 : }
117 :
118 3 : if (output_context->op & PHP_OUTPUT_HANDLER_CLEAN) {
119 : /* free buffers */
120 0 : deflateEnd(&ctx->Z);
121 :
122 0 : if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
123 : /* discard */
124 0 : return SUCCESS;
125 : } else {
126 : /* restart */
127 0 : if (Z_OK != deflateInit2(&ctx->Z, ZLIBG(output_compression_level), Z_DEFLATED, ZLIBG(compression_coding), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY)) {
128 0 : return FAILURE;
129 : }
130 0 : ctx->buffer.used = 0;
131 : }
132 : } else {
133 :
134 3 : if (output_context->in.used) {
135 : /* append input */
136 2 : if (ctx->buffer.free < output_context->in.used) {
137 2 : if (!(ctx->buffer.aptr = erealloc_recoverable(ctx->buffer.data, ctx->buffer.used + ctx->buffer.free + output_context->in.used))) {
138 0 : deflateEnd(&ctx->Z);
139 0 : return FAILURE;
140 : }
141 2 : ctx->buffer.data = ctx->buffer.aptr;
142 2 : ctx->buffer.free += output_context->in.used;
143 : }
144 2 : memcpy(ctx->buffer.data + ctx->buffer.used, output_context->in.data, output_context->in.used);
145 2 : ctx->buffer.free -= output_context->in.used;
146 2 : ctx->buffer.used += output_context->in.used;
147 : }
148 :
149 3 : output_context->out.size = PHP_ZLIB_BUFFER_SIZE_GUESS(output_context->in.used);
150 3 : output_context->out.data = emalloc(output_context->out.size);
151 3 : output_context->out.free = 1;
152 3 : output_context->out.used = 0;
153 :
154 3 : ctx->Z.avail_in = ctx->buffer.used;
155 3 : ctx->Z.next_in = (Bytef *) ctx->buffer.data;
156 3 : ctx->Z.avail_out = output_context->out.size;
157 3 : ctx->Z.next_out = (Bytef *) output_context->out.data;
158 :
159 3 : if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
160 3 : flags = Z_FINISH;
161 0 : } else if (output_context->op & PHP_OUTPUT_HANDLER_FLUSH) {
162 0 : flags = Z_FULL_FLUSH;
163 : }
164 :
165 3 : switch (deflate(&ctx->Z, flags)) {
166 : case Z_OK:
167 0 : if (flags == Z_FINISH) {
168 0 : deflateEnd(&ctx->Z);
169 0 : return FAILURE;
170 : }
171 : case Z_STREAM_END:
172 3 : if (ctx->Z.avail_in) {
173 0 : memmove(ctx->buffer.data, ctx->buffer.data + ctx->buffer.used - ctx->Z.avail_in, ctx->Z.avail_in);
174 : }
175 3 : ctx->buffer.free += ctx->buffer.used - ctx->Z.avail_in;
176 3 : ctx->buffer.used = ctx->Z.avail_in;
177 3 : output_context->out.used = output_context->out.size - ctx->Z.avail_out;
178 : break;
179 : default:
180 0 : deflateEnd(&ctx->Z);
181 0 : return FAILURE;
182 : }
183 :
184 3 : php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_GET_FLAGS, &flags TSRMLS_CC);
185 :
186 3 : if (!(flags & PHP_OUTPUT_HANDLER_STARTED)) {
187 3 : if (SG(headers_sent) || !ZLIBG(output_compression)) {
188 2 : deflateEnd(&ctx->Z);
189 2 : return FAILURE;
190 : }
191 1 : switch (ZLIBG(compression_coding)) {
192 : case PHP_ZLIB_ENCODING_GZIP:
193 1 : sapi_add_header_ex(ZEND_STRL("Content-Encoding: gzip"), 1, 1 TSRMLS_CC);
194 1 : break;
195 : case PHP_ZLIB_ENCODING_DEFLATE:
196 0 : sapi_add_header_ex(ZEND_STRL("Content-Encoding: deflate"), 1, 1 TSRMLS_CC);
197 0 : break;
198 : default:
199 0 : deflateEnd(&ctx->Z);
200 0 : return FAILURE;
201 : }
202 1 : sapi_add_header_ex(ZEND_STRL("Vary: Accept-Encoding"), 1, 1 TSRMLS_CC);
203 1 : php_output_handler_hook(PHP_OUTPUT_HANDLER_HOOK_IMMUTABLE, NULL TSRMLS_CC);
204 : }
205 :
206 1 : if (output_context->op & PHP_OUTPUT_HANDLER_FINAL) {
207 1 : deflateEnd(&ctx->Z);
208 : }
209 : }
210 1 : return SUCCESS;
211 : }
212 : /* }}} */
213 :
214 : /* {{{ php_zlib_output_handler_dtor() */
215 : static void php_zlib_output_handler_dtor(void *opaq TSRMLS_DC)
216 5 : {
217 5 : php_zlib_context *ctx = (php_zlib_context *) opaq;
218 :
219 5 : if (ctx) {
220 5 : if (ctx->buffer.data) {
221 2 : efree(ctx->buffer.data);
222 : }
223 5 : efree(ctx);
224 : }
225 5 : }
226 : /* }}} */
227 :
228 : /* {{{ php_zlib_output_handler_init() */
229 : static php_output_handler *php_zlib_output_handler_init(zval *handler_name, size_t chunk_size, int flags TSRMLS_DC)
230 5 : {
231 5 : php_output_handler *h = NULL;
232 : php_zlib_context *ctx;
233 :
234 5 : if (!ZLIBG(output_compression)) {
235 1 : ZLIBG(output_compression) = chunk_size ? chunk_size : PHP_OUTPUT_HANDLER_DEFAULT_SIZE;
236 : }
237 5 : if ((h = php_output_handler_create_internal(handler_name, php_zlib_output_handler, chunk_size, flags TSRMLS_CC))) {
238 5 : ctx = (php_zlib_context *) ecalloc(1, sizeof(php_zlib_context));
239 5 : ctx->Z.zalloc = php_zlib_alloc;
240 5 : ctx->Z.zfree = php_zlib_free;
241 5 : php_output_handler_set_context(h, ctx, php_zlib_output_handler_dtor TSRMLS_CC);
242 : }
243 :
244 5 : return h;
245 : }
246 : /* }}} */
247 :
248 : /* {{{ php_zlib_output_compression_start() */
249 : static void php_zlib_output_compression_start(TSRMLS_D)
250 16993 : {
251 : zval *zoh, *tmp;
252 : php_output_handler *h;
253 :
254 16993 : switch (ZLIBG(output_compression)) {
255 : case 0:
256 16989 : break;
257 : case 1:
258 4 : ZLIBG(output_compression) = PHP_OUTPUT_HANDLER_DEFAULT_SIZE;
259 : /* break omitted intentionally */
260 : default:
261 4 : MAKE_STD_ZVAL(tmp);
262 4 : ZVAL_ASCII_STRING(tmp, PHP_ZLIB_OUTPUT_HANDLER_NAME, ZSTR_DUPLICATE);
263 4 : if ( (h = php_zlib_output_handler_init(tmp, ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC)) &&
264 : (SUCCESS == php_output_handler_start(h TSRMLS_CC))) {
265 4 : if (ZLIBG(output_handler) && *ZLIBG(output_handler)) {
266 0 : MAKE_STD_ZVAL(zoh);
267 0 : ZVAL_ASCII_STRING(zoh, ZLIBG(output_handler), ZSTR_DUPLICATE);
268 0 : php_output_start_user(zoh, ZLIBG(output_compression), PHP_OUTPUT_HANDLER_STDFLAGS TSRMLS_CC);
269 0 : zval_ptr_dtor(&zoh);
270 : }
271 : }
272 4 : zval_ptr_dtor(&tmp);
273 : break;
274 : }
275 16993 : }
276 : /* }}} */
277 :
278 : /* {{{ php_zlib_encode() */
279 : static int php_zlib_encode(const char *in_buf, size_t in_len, char **out_buf, size_t *out_len, int encoding, int level TSRMLS_DC)
280 119 : {
281 : int status;
282 : z_stream Z;
283 :
284 119 : memset(&Z, 0, sizeof(z_stream));
285 119 : Z.zalloc = php_zlib_alloc;
286 119 : Z.zfree = php_zlib_free;
287 :
288 119 : if (Z_OK == (status = deflateInit2(&Z, level, Z_DEFLATED, encoding, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY))) {
289 119 : *out_len = PHP_ZLIB_BUFFER_SIZE_GUESS(in_len);
290 119 : *out_buf = emalloc(*out_len);
291 :
292 119 : Z.next_in = (Bytef *) in_buf;
293 119 : Z.next_out = (Bytef *) *out_buf;
294 119 : Z.avail_in = in_len;
295 119 : Z.avail_out = *out_len;
296 :
297 119 : status = deflate(&Z, Z_FINISH);
298 119 : deflateEnd(&Z);
299 :
300 119 : if (Z_STREAM_END == status) {
301 : /* size buffer down to actual length */
302 119 : *out_buf = erealloc(*out_buf, Z.total_out + 1);
303 119 : (*out_buf)[*out_len = Z.total_out] = '\0';
304 119 : return SUCCESS;
305 : } else {
306 0 : efree(*out_buf);
307 : }
308 : }
309 :
310 0 : *out_buf = NULL;
311 0 : *out_len = 0;
312 :
313 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
314 0 : return FAILURE;
315 : }
316 : /* }}} */
317 :
318 : /* {{{ inflate_rounds() */
319 : static inline int inflate_rounds(z_stream *Z, size_t max, char **buf, size_t *len)
320 81 : {
321 81 : int status, round = 0;
322 81 : php_zlib_buffer buffer = {NULL, NULL, 0, 0, 0};
323 :
324 81 : *buf = NULL;
325 81 : *len = 0;
326 :
327 81 : buffer.size = Z->avail_in;
328 :
329 : do {
330 462 : if ((max && (max < buffer.used)) || !(buffer.aptr = erealloc_recoverable(buffer.data, buffer.size))) {
331 1 : status = Z_MEM_ERROR;
332 : } else {
333 460 : buffer.data = buffer.aptr;
334 460 : Z->avail_out = buffer.free = buffer.size - buffer.used;
335 460 : Z->next_out = (Bytef *) buffer.data + buffer.used;
336 : #if 0
337 : fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
338 : #endif
339 460 : status = inflate(Z, Z_NO_FLUSH);
340 :
341 460 : buffer.used += buffer.free - Z->avail_out;
342 460 : buffer.free = Z->avail_out;
343 : #if 0
344 : fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
345 : #endif
346 460 : buffer.size += (buffer.size >> 3) + 1;
347 : }
348 461 : } while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < 100);
349 :
350 156 : if (status == Z_OK || status == Z_STREAM_END) {
351 75 : buffer.data = erealloc(buffer.data, buffer.used + 1);
352 75 : buffer.data[buffer.used] = '\0';
353 75 : *buf = buffer.data;
354 75 : *len = buffer.used;
355 6 : } else if (buffer.data) {
356 6 : efree(buffer.data);
357 : }
358 :
359 81 : return status;
360 : }
361 : /* }}} */
362 :
363 : /* {{{ php_zlib_decode() */
364 : static int php_zlib_decode(const char *in_buf, size_t in_len, char **out_buf, size_t *out_len, int encoding, size_t max_len TSRMLS_DC)
365 85 : {
366 85 : int status = Z_DATA_ERROR;
367 : z_stream Z;
368 :
369 85 : memset(&Z, 0, sizeof(z_stream));
370 85 : Z.zalloc = php_zlib_alloc;
371 85 : Z.zfree = php_zlib_free;
372 :
373 85 : if (in_len) {
374 81 : retry_raw_inflate:
375 81 : status = inflateInit2(&Z, encoding);
376 81 : if (Z_OK == status) {
377 81 : Z.next_in = (Bytef *) in_buf;
378 81 : Z.avail_in = in_len;
379 :
380 81 : switch (status = inflate_rounds(&Z, max_len, out_buf, out_len)) {
381 : case Z_OK:
382 : case Z_STREAM_END:
383 75 : inflateEnd(&Z);
384 75 : return SUCCESS;
385 :
386 : case Z_DATA_ERROR:
387 : /* raw deflated data? */
388 5 : if (PHP_ZLIB_ENCODING_ANY == encoding) {
389 0 : inflateEnd(&Z);
390 0 : encoding = PHP_ZLIB_ENCODING_RAW;
391 0 : goto retry_raw_inflate;
392 : }
393 : }
394 6 : inflateEnd(&Z);
395 : }
396 : }
397 :
398 10 : *out_buf = NULL;
399 10 : *out_len = 0;
400 :
401 10 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", zError(status));
402 10 : return FAILURE;
403 : }
404 : /* }}} */
405 :
406 : /* {{{ proto string zlib_get_coding_type(void) U
407 : Returns the coding type used for output compression */
408 : static PHP_FUNCTION(zlib_get_coding_type)
409 0 : {
410 0 : if (zend_parse_parameters_none() == FAILURE) {
411 0 : return;
412 : }
413 0 : switch (ZLIBG(compression_coding)) {
414 : case PHP_ZLIB_ENCODING_GZIP:
415 0 : RETURN_ASCII_STRINGL("gzip", sizeof("gzip") - 1, 1);
416 : case PHP_ZLIB_ENCODING_DEFLATE:
417 0 : RETURN_ASCII_STRINGL("deflate", sizeof("deflate") - 1, 1);
418 : default:
419 0 : RETURN_FALSE;
420 : }
421 : }
422 : /* }}} */
423 :
424 : /* {{{ proto array gzfile(string filename [, int use_include_path]) U
425 : Read and uncompress entire .gz-file into an array */
426 : static PHP_FUNCTION(gzfile)
427 74 : {
428 : zstr filename;
429 : int filename_len;
430 : zend_uchar filename_type;
431 74 : int flags = REPORT_ERRORS;
432 74 : char buf[8192] = {0};
433 74 : long use_include_path = 0;
434 : php_stream *stream;
435 :
436 74 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|l", &filename, &filename_len, &filename_type, &use_include_path)) {
437 25 : return;
438 : }
439 :
440 49 : if (filename_type == IS_UNICODE && SUCCESS != php_stream_path_encode(NULL, &filename.s, &filename_len, filename.u, filename_len, REPORT_ERRORS, NULL)) {
441 0 : RETURN_FALSE;
442 : }
443 :
444 49 : if (use_include_path) {
445 17 : flags |= USE_PATH;
446 : }
447 : /* using a stream here is a bit more efficient (resource wise) than php_gzopen_wrapper */
448 49 : stream = php_stream_gzopen(NULL, filename.s, "rb", flags, NULL, NULL STREAMS_CC TSRMLS_CC);
449 49 : if (filename_type == IS_UNICODE) {
450 49 : efree(filename.s);
451 : }
452 49 : if (!stream) {
453 : /* Error reporting is already done by stream code */
454 21 : RETURN_FALSE;
455 : }
456 :
457 28 : array_init(return_value);
458 203 : while (php_stream_gets(stream, ZSTR(buf), sizeof(buf) - 1)) {
459 147 : add_next_index_string(return_value, buf, 1);
460 : }
461 28 : php_stream_close(stream);
462 : }
463 : /* }}} */
464 :
465 : /* {{{ proto resource gzopen(string filename, string mode [, int use_include_path]) U
466 : Open a .gz-file and return a .gz-file pointer */
467 : static PHP_FUNCTION(gzopen)
468 207 : {
469 : zstr filename;
470 : char *mode;
471 : int filename_len, mode_len;
472 : zend_uchar filename_type;
473 207 : int flags = REPORT_ERRORS;
474 : php_stream *stream;
475 207 : long use_include_path = 0;
476 :
477 207 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ts|l", &filename, &filename_len, &filename_type, &mode, &mode_len, &use_include_path) == FAILURE) {
478 27 : return;
479 : }
480 :
481 180 : if (filename_type == IS_UNICODE && SUCCESS != php_stream_path_encode(NULL, &filename.s, &filename_len, filename.u, filename_len, REPORT_ERRORS, NULL)) {
482 0 : RETURN_FALSE;
483 : }
484 :
485 180 : if (use_include_path) {
486 23 : flags |= USE_PATH;
487 : }
488 180 : stream = php_stream_gzopen(NULL, filename.s, mode, flags, NULL, NULL STREAMS_CC TSRMLS_CC);
489 :
490 180 : if (filename_type == IS_UNICODE) {
491 180 : efree(filename.s);
492 : }
493 180 : if (!stream) {
494 56 : RETURN_FALSE;
495 : }
496 124 : php_stream_to_zval(stream, return_value);
497 : }
498 : /* }}} */
499 :
500 : /* {{{ proto int readgzfile(string filename [, int use_include_path]) U
501 : Output a .gz-file */
502 : static PHP_FUNCTION(readgzfile)
503 68 : {
504 : zstr filename;
505 : int filename_len;
506 : zend_uchar filename_type;
507 68 : int flags = REPORT_ERRORS;
508 : php_stream *stream;
509 : int size;
510 68 : long use_include_path = 0;
511 :
512 68 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|l", &filename, &filename_len, &filename_type, &use_include_path) == FAILURE) {
513 23 : return;
514 : }
515 :
516 45 : if (filename_type == IS_UNICODE && SUCCESS != php_stream_path_encode(NULL, &filename.s, &filename_len, filename.u, filename_len, REPORT_ERRORS, NULL)) {
517 0 : RETURN_FALSE;
518 : }
519 :
520 45 : if (use_include_path) {
521 14 : flags |= USE_PATH;
522 : }
523 45 : stream = php_stream_gzopen(NULL, filename.s, "rb", flags, NULL, NULL STREAMS_CC TSRMLS_CC);
524 45 : if (filename_type == IS_UNICODE) {
525 45 : efree(filename.s);
526 : }
527 45 : if (!stream) {
528 20 : RETURN_FALSE;
529 : }
530 25 : size = php_stream_passthru(stream);
531 25 : php_stream_close(stream);
532 25 : RETURN_LONG(size);
533 : }
534 : /* }}} */
535 :
536 : #define PHP_ZLIB_ENCODE_FUNC(name, default_encoding) \
537 : static PHP_FUNCTION(name) \
538 : { \
539 : char *in_buf, *out_buf; \
540 : int in_len; \
541 : size_t out_len; \
542 : long level = -1; \
543 : long encoding = default_encoding; \
544 : if (default_encoding) { \
545 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|ll", &in_buf, &in_len, &level, &encoding)) { \
546 : return; \
547 : } \
548 : } else { \
549 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Sl|l", &in_buf, &in_len, &encoding, &level)) { \
550 : return; \
551 : } \
552 : } \
553 : if (level < -1 || level > 9) { \
554 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "compression level (%ld) must be within -1..9", level); \
555 : RETURN_FALSE; \
556 : } \
557 : switch (encoding) { \
558 : case PHP_ZLIB_ENCODING_RAW: \
559 : case PHP_ZLIB_ENCODING_GZIP: \
560 : case PHP_ZLIB_ENCODING_DEFLATE: \
561 : break; \
562 : default: \
563 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "encoding mode must be either ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE"); \
564 : RETURN_FALSE; \
565 : } \
566 : if (SUCCESS != php_zlib_encode(in_buf, in_len, &out_buf, &out_len, encoding, level TSRMLS_CC)) { \
567 : RETURN_FALSE; \
568 : } \
569 : RETURN_STRINGL(out_buf, out_len, 0); \
570 : }
571 :
572 : #define PHP_ZLIB_DECODE_FUNC(name, encoding) \
573 : static PHP_FUNCTION(name) \
574 : { \
575 : char *in_buf, *out_buf; \
576 : int in_len; \
577 : size_t out_len; \
578 : long max_len = 0; \
579 : if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S|l", &in_buf, &in_len, &max_len)) { \
580 : return; \
581 : } \
582 : if (max_len < 0) { \
583 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "length (%ld) must be greater or equal zero", max_len); \
584 : RETURN_FALSE; \
585 : } \
586 : if (SUCCESS != php_zlib_decode(in_buf, in_len, &out_buf, &out_len, encoding, max_len TSRMLS_CC)) { \
587 : RETURN_FALSE; \
588 : } \
589 : RETURN_STRINGL(out_buf, out_len, 0); \
590 : }
591 :
592 : /* {{{ proto binary zlib_encode(binary data, int encoding[, int level = -1]) U
593 : Compress data with the specified encoding */
594 0 : PHP_ZLIB_ENCODE_FUNC(zlib_encode, 0);
595 : /* }}} */
596 :
597 : /* {{{ proto binary zlib_decode(binary data[, int max_decoded_len]) U
598 : Uncompress any raw/gzip/zlib encoded data */
599 0 : PHP_ZLIB_DECODE_FUNC(zlib_decode, PHP_ZLIB_ENCODING_ANY);
600 : /* }}} */
601 :
602 : /* NOTE: The naming of these userland functions was quite unlucky */
603 :
604 : /* {{{ proto binary gzdeflate(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_RAW]) U
605 : Encode data with the raw deflate encoding */
606 48 : PHP_ZLIB_ENCODE_FUNC(gzdeflate, PHP_ZLIB_ENCODING_RAW);
607 : /* }}} */
608 : /* {{{ proto binary gzencode(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_GZIP]) U
609 : Encode data with the gzip encoding */
610 56 : PHP_ZLIB_ENCODE_FUNC(gzencode, PHP_ZLIB_ENCODING_GZIP);
611 : /* }}} */
612 : /* {{{ proto binary gzcompress(binary data[, int level = -1[, int encoding = ZLIB_ENCODING_DEFLATE]) U
613 : Encode data with the zlib encoding */
614 48 : PHP_ZLIB_ENCODE_FUNC(gzcompress, PHP_ZLIB_ENCODING_DEFLATE);
615 : /* }}} */
616 : /* {{{ proto binary gzinflate(binary data[, int max_decoded_len]) U
617 : Decode raw deflate encoded data */
618 53 : PHP_ZLIB_DECODE_FUNC(gzinflate, PHP_ZLIB_ENCODING_RAW);
619 : /* }}} */
620 : /* {{{ proto binary gzdecode(binary data[, int max_decoded_len]) U
621 : Decode gzip encoded data */
622 0 : PHP_ZLIB_DECODE_FUNC(gzdecode, PHP_ZLIB_ENCODING_GZIP);
623 : /* }}} */
624 : /* {{{ proto binary gzuncompress(binary data[, int max_decoded_len]) U
625 : Decode zlib encoded data */
626 46 : PHP_ZLIB_DECODE_FUNC(gzuncompress, PHP_ZLIB_ENCODING_DEFLATE);
627 : /* }}} */
628 :
629 : #ifdef COMPILE_DL_ZLIB
630 : ZEND_GET_MODULE(php_zlib)
631 : #endif
632 :
633 : /* {{{ arginfo */
634 : ZEND_BEGIN_ARG_INFO(arginfo_zlib_get_coding_type, 0)
635 : ZEND_END_ARG_INFO()
636 :
637 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzfile, 0, 0, 1)
638 : ZEND_ARG_INFO(0, filename)
639 : ZEND_ARG_INFO(0, use_include_path)
640 : ZEND_END_ARG_INFO()
641 :
642 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzopen, 0, 0, 2)
643 : ZEND_ARG_INFO(0, filename)
644 : ZEND_ARG_INFO(0, mode)
645 : ZEND_ARG_INFO(0, use_include_path)
646 : ZEND_END_ARG_INFO()
647 :
648 : ZEND_BEGIN_ARG_INFO_EX(arginfo_readgzfile, 0, 0, 1)
649 : ZEND_ARG_INFO(0, filename)
650 : ZEND_ARG_INFO(0, use_include_path)
651 : ZEND_END_ARG_INFO()
652 :
653 : ZEND_BEGIN_ARG_INFO_EX(arginfo_zlib_encode, 0, 0, 2)
654 : ZEND_ARG_INFO(0, data)
655 : ZEND_ARG_INFO(0, encoding)
656 : ZEND_ARG_INFO(0, level)
657 : ZEND_END_ARG_INFO()
658 :
659 : ZEND_BEGIN_ARG_INFO_EX(arginfo_zlib_decode, 0, 0, 1)
660 : ZEND_ARG_INFO(0, data)
661 : ZEND_ARG_INFO(0, max_decoded_len)
662 : ZEND_END_ARG_INFO()
663 :
664 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzdeflate, 0, 0, 1)
665 : ZEND_ARG_INFO(0, data)
666 : ZEND_ARG_INFO(0, level)
667 : ZEND_ARG_INFO(0, encoding)
668 : ZEND_END_ARG_INFO()
669 :
670 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzencode, 0, 0, 1)
671 : ZEND_ARG_INFO(0, data)
672 : ZEND_ARG_INFO(0, level)
673 : ZEND_ARG_INFO(0, encoding)
674 : ZEND_END_ARG_INFO()
675 :
676 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzcompress, 0, 0, 1)
677 : ZEND_ARG_INFO(0, data)
678 : ZEND_ARG_INFO(0, level)
679 : ZEND_ARG_INFO(0, encoding)
680 : ZEND_END_ARG_INFO()
681 :
682 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzinflate, 0, 0, 1)
683 : ZEND_ARG_INFO(0, data)
684 : ZEND_ARG_INFO(0, max_decoded_len)
685 : ZEND_END_ARG_INFO()
686 :
687 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzdecode, 0, 0, 1)
688 : ZEND_ARG_INFO(0, data)
689 : ZEND_ARG_INFO(0, max_decoded_len)
690 : ZEND_END_ARG_INFO()
691 :
692 : ZEND_BEGIN_ARG_INFO_EX(arginfo_gzuncompress, 0, 0, 1)
693 : ZEND_ARG_INFO(0, data)
694 : ZEND_ARG_INFO(0, max_decoded_len)
695 : ZEND_END_ARG_INFO()
696 : /* }}} */
697 :
698 : /* {{{ php_zlib_functions[] */
699 : static const zend_function_entry php_zlib_functions[] = {
700 : PHP_FE(readgzfile, arginfo_readgzfile)
701 : PHP_FALIAS(gzrewind, rewind, NULL)
702 : PHP_FALIAS(gzclose, fclose, NULL)
703 : PHP_FALIAS(gzeof, feof, NULL)
704 : PHP_FALIAS(gzgetc, fgetc, NULL)
705 : PHP_FALIAS(gzgets, fgets, NULL)
706 : PHP_FALIAS(gzgetss, fgetss, NULL)
707 : PHP_FALIAS(gzread, fread, NULL)
708 : PHP_FE(gzopen, arginfo_gzopen)
709 : PHP_FALIAS(gzpassthru, fpassthru, NULL)
710 : PHP_FALIAS(gzseek, fseek, NULL)
711 : PHP_FALIAS(gztell, ftell, NULL)
712 : PHP_FALIAS(gzwrite, fwrite, NULL)
713 : PHP_FALIAS(gzputs, fwrite, NULL)
714 : PHP_FE(gzfile, NULL)
715 : PHP_FE(gzcompress, arginfo_gzcompress)
716 : PHP_FE(gzuncompress, arginfo_gzuncompress)
717 : PHP_FE(gzdeflate, arginfo_gzdeflate)
718 : PHP_FE(gzinflate, arginfo_gzinflate)
719 : PHP_FE(gzencode, arginfo_gzencode)
720 : PHP_FE(gzdecode, arginfo_gzdecode)
721 : PHP_FE(zlib_encode, arginfo_zlib_encode)
722 : PHP_FE(zlib_decode, arginfo_zlib_decode)
723 : PHP_FE(zlib_get_coding_type, arginfo_zlib_get_coding_type)
724 : {NULL, NULL, NULL}
725 : };
726 : /* }}} */
727 :
728 : /* {{{ OnUpdate_zlib_output_compression */
729 : static PHP_INI_MH(OnUpdate_zlib_output_compression)
730 17019 : {
731 : int status, int_value;
732 : char *ini_value;
733 :
734 17019 : if (new_value == NULL) {
735 0 : return FAILURE;
736 : }
737 :
738 17019 : if (!strncasecmp(new_value, "off", sizeof("off"))) {
739 0 : new_value = "0";
740 0 : new_value_length = sizeof("0");
741 17019 : } else if (!strncasecmp(new_value, "on", sizeof("on"))) {
742 0 : new_value = "1";
743 0 : new_value_length = sizeof("1");
744 : }
745 :
746 17019 : int_value = zend_atoi(new_value, new_value_length);
747 17019 : ini_value = zend_ini_string("output_handler", sizeof("output_handler"), 0);
748 :
749 17019 : if (ini_value && *ini_value && int_value) {
750 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_CORE_ERROR, "Cannot use both zlib.output_compression and output_handler together!!");
751 0 : return FAILURE;
752 : }
753 :
754 17019 : if (stage == PHP_INI_STAGE_RUNTIME) {
755 6 : status = php_output_get_status(TSRMLS_C);
756 6 : if (status & PHP_OUTPUT_SENT) {
757 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot change zlib.output_compression - headers already sent");
758 0 : return FAILURE;
759 6 : } else if ((status & PHP_OUTPUT_WRITTEN) && int_value) {
760 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot enable zlib.output_compression - there has already been output");
761 0 : return FAILURE;
762 : }
763 : }
764 :
765 17019 : status = OnUpdateLong(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
766 :
767 17019 : if (stage == PHP_INI_STAGE_RUNTIME && int_value) {
768 : zval tmp;
769 :
770 0 : INIT_PZVAL(&tmp);
771 0 : ZVAL_ASCII_STRING(&tmp, PHP_ZLIB_OUTPUT_HANDLER_NAME, ZSTR_DUPLICATE);
772 0 : if (!php_output_handler_started(&tmp TSRMLS_CC)) {
773 0 : php_zlib_output_compression_start(TSRMLS_C);
774 : }
775 0 : zval_dtor(&tmp);
776 : }
777 :
778 17019 : return status;
779 : }
780 : /* }}} */
781 :
782 : /* {{{ OnUpdate_zlib_output_handler */
783 : static PHP_INI_MH(OnUpdate_zlib_output_handler)
784 17007 : {
785 17007 : if (stage == PHP_INI_STAGE_RUNTIME && (php_output_get_status(TSRMLS_C) & PHP_OUTPUT_SENT)) {
786 0 : php_error_docref("ref.outcontrol" TSRMLS_CC, E_WARNING, "Cannot change zlib.output_handler - headers already sent");
787 0 : return FAILURE;
788 : }
789 :
790 17007 : return OnUpdateString(entry, new_value, new_value_length, mh_arg1, mh_arg2, mh_arg3, stage TSRMLS_CC);
791 : }
792 : /* }}} */
793 :
794 : /* {{{ INI */
795 : PHP_INI_BEGIN()
796 : STD_PHP_INI_BOOLEAN("zlib.output_compression", "0", PHP_INI_ALL, OnUpdate_zlib_output_compression, output_compression, zend_zlib_globals, zlib_globals)
797 : STD_PHP_INI_ENTRY("zlib.output_compression_level", "-1", PHP_INI_ALL, OnUpdateLong, output_compression_level, zend_zlib_globals, zlib_globals)
798 : STD_PHP_INI_ENTRY("zlib.output_handler", "", PHP_INI_ALL, OnUpdate_zlib_output_handler, output_handler, zend_zlib_globals, zlib_globals)
799 : PHP_INI_END()
800 : /* }}} */
801 :
802 : /* {{{ PHP_MINIT_FUNCTION */
803 : static PHP_MINIT_FUNCTION(zlib)
804 17007 : {
805 17007 : php_register_url_stream_wrapper("compress.zlib", &php_stream_gzip_wrapper TSRMLS_CC);
806 17007 : php_stream_filter_register_factory("zlib.*", &php_zlib_filter_factory TSRMLS_CC);
807 :
808 17007 : PHP_OUTPUT_ALIAS_REGISTER("ob_gzhandler", php_zlib_output_handler_init);
809 17007 : PHP_OUTPUT_CONFLICT_REGISTER("ob_gzhandler", php_zlib_output_conflict_check);
810 17007 : PHP_OUTPUT_CONFLICT_REGISTER(PHP_ZLIB_OUTPUT_HANDLER_NAME, php_zlib_output_conflict_check);
811 :
812 17007 : REGISTER_LONG_CONSTANT("FORCE_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT);
813 17007 : REGISTER_LONG_CONSTANT("FORCE_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT);
814 :
815 17007 : REGISTER_LONG_CONSTANT("ZLIB_ENCODING_RAW", PHP_ZLIB_ENCODING_RAW, CONST_CS|CONST_PERSISTENT);
816 17007 : REGISTER_LONG_CONSTANT("ZLIB_ENCODING_GZIP", PHP_ZLIB_ENCODING_GZIP, CONST_CS|CONST_PERSISTENT);
817 17007 : REGISTER_LONG_CONSTANT("ZLIB_ENCODING_DEFLATE", PHP_ZLIB_ENCODING_DEFLATE, CONST_CS|CONST_PERSISTENT);
818 17007 : REGISTER_INI_ENTRIES();
819 17007 : return SUCCESS;
820 : }
821 : /* }}} */
822 :
823 : /* {{{ PHP_MSHUTDOWN_FUNCTION */
824 : static PHP_MSHUTDOWN_FUNCTION(zlib)
825 17039 : {
826 17039 : php_unregister_url_stream_wrapper("zlib" TSRMLS_CC);
827 17039 : php_stream_filter_unregister_factory("zlib.*" TSRMLS_CC);
828 :
829 17039 : UNREGISTER_INI_ENTRIES();
830 17039 : return SUCCESS;
831 : }
832 : /* }}} */
833 :
834 : /* {{{ PHP_RINIT_FUNCTION */
835 : static PHP_RINIT_FUNCTION(zlib)
836 16993 : {
837 16993 : ZLIBG(compression_coding) = 0;
838 :
839 16993 : php_zlib_output_compression_start(TSRMLS_C);
840 :
841 16993 : return SUCCESS;
842 : }
843 : /* }}} */
844 :
845 : /* {{{ PHP_MINFO_FUNCTION */
846 : static PHP_MINFO_FUNCTION(zlib)
847 43 : {
848 43 : php_info_print_table_start();
849 43 : php_info_print_table_header(2, "ZLib Support", "enabled");
850 43 : php_info_print_table_row(2, "Stream Wrapper", "compress.zlib://");
851 43 : php_info_print_table_row(2, "Stream Filter", "zlib.inflate, zlib.deflate");
852 43 : php_info_print_table_row(2, "Compiled Version", ZLIB_VERSION);
853 43 : php_info_print_table_row(2, "Linked Version", (char *) zlibVersion());
854 43 : php_info_print_table_end();
855 :
856 43 : DISPLAY_INI_ENTRIES();
857 43 : }
858 : /* }}} */
859 :
860 : /* {{{ php_zlib_module_entry */
861 : zend_module_entry php_zlib_module_entry = {
862 : STANDARD_MODULE_HEADER,
863 : "zlib",
864 : php_zlib_functions,
865 : PHP_MINIT(zlib),
866 : PHP_MSHUTDOWN(zlib),
867 : PHP_RINIT(zlib),
868 : NULL,
869 : PHP_MINFO(zlib),
870 : "2.0",
871 : PHP_MODULE_GLOBALS(zlib),
872 : NULL,
873 : NULL,
874 : NULL,
875 : STANDARD_MODULE_PROPERTIES_EX
876 : };
877 : /* }}} */
878 :
879 : /*
880 : * Local variables:
881 : * tab-width: 4
882 : * c-basic-offset: 4
883 : * End:
884 : * vim600: sw=4 ts=4 fdm=marker
885 : * vim<600: sw=4 ts=4
886 : */
|