If you have zlib.output_compression set to on when your script starts (in php.ini or via apache directive), then you disable it at runtime using ini_set() before producing output, your output will still be buffered! Even if you call ob_implicit_flush().
If you want unbuffered output, you must disable zlib.output_compression before your script starts (as well as mod_gzip of course, if you have both installed).
This behaviour experienced on Server: Apache/1.3.33 (Debian GNU/Linux) mod_gzip/1.3.26.1a PHP/4.3.10-18
CLXXXVIII. zlib 圧縮関数
導入
このモジュールにより gzip (.gz) で圧縮されたファイルを読み書きすることが可能となります。 この際、ファイルシステム 関数の gzip 圧縮対応版 (非圧縮ファイルも扱えますが、 ソケットは扱えません)を使用します。
注意: バージョン 4.0.4 で .gz ファイルに対応した fopen のラッパー を導入しました。 fopen() に渡すファイル名または パス名に zlib: をつけると、通常の f*() ファイルアクセス関数を使用して圧縮ファイルに透過的にアクセスすることが できます。
PHP 4.3.0 において、';' を含むファイル名との曖昧さを避けるため zlib: は compress.zlib:// に変更されました。fopencookie() 関数は もはや必要ありません。詳細な情報は、 圧縮ストリーム項 にあります。
要件
このモジュールは、Jean-loup Gailly および Mark Adler による » zlib の関数を使用します。 このモジュールを使用するには、zlib バージョン >= 1.0.9 を使用する必要があります。
インストール手順
PHPにおけるZlibサポートは、デフォルトでは利用できません。 Zlibサポートを有効にするには、PHPのコンパイル時にconfigureの オプションに--with-zlib[=DIR]を 指定してコンパイルする必要があります。
Windows 版の PHP には この拡張モジュールのサポートが組み込まれています。これらの関数を使用 するために拡張モジュールを追加でロードする必要はありません。
注意: PHP 4.3.0 以降、zlib モジュールは Windows 用 php バイナリにビルトインされています。
実行時設定
php.ini の設定により動作が変化します。
zlib 拡張モジュールは、 ブラウザがサポートする場合にページを透過的に圧縮するオプションを提供します。 ここで、 設定ファイル php.ini のオプションには、以下の 3 種類があります。
表 344. Zlib設定オプション
| 名前 | デフォルト | 変更の可否 | 変更履歴 |
|---|---|---|---|
| zlib.output_compression | "0" | PHP_INI_ALL | PHP 4.0.5 から利用可能 |
| zlib.output_compression_level | "-1" | PHP_INI_ALL | PHP 4.3.0 から利用可能 |
| zlib.output_handler | "" | PHP_INI_ALL | PHP 4.3.0 から利用可能 |
PHP_INI_* 定数の詳細および定義については 付録 I. php.ini ディレクティブ を参照してください。
以下に設定ディレクティブに関する 簡単な説明を示します。
- zlib.output_compression boolean/integer
透過的なページ圧縮を行うかどうか。php.ini または Apache の設定でこのオプションが、"On" に設定された場合、 ブラウザが "Accept-Encoding: gzip" または "deflate" ヘッダを送信する場合に、ページは圧縮されます。 "Content-Encoding: gzip" (および "deflate") と "Vary: Accept-Encoding" ヘッダが出力に追加されます。 実行時、何らかのデータを送出する前にのみ設定することが可能です。
このオプションも論理値 "On"/"Off" のかわりに整数値をとることができ、 これを用いて出力のバッファサイズ (デフォルトは 4KB) を設定することができます。
注意: このオプションに 'On' を設定した場合、 output_handler を空にする必要があります! かわりに zlib.output_handler を使用する必要があります。
- zlib.output_compression_level integer
透過的出力圧縮で使用される圧縮レベル。
- zlib.output_handler string
zlib.output_compression が有効な場合、 他の出力ハンドラを指定することはできません。 この設定は、output_handler と同じですが、順番が異なります。
リソース型
この拡張モジュールでは、ファイルポインタリソースを定義しています。これは gzopen() が返すものです。
定義済み定数
以下の定数が定義されています。 この関数の拡張モジュールが PHP 組み込みでコンパイルされているか、 実行時に動的にロードされている場合のみ使用可能です。
例
テンポラリファイルをオープンし、テスト用文字列を書きこみ、 続いて、このファイルの内容を 2 回出力します。
例 2642. 簡単な Zlib の例
<?php
$filename = tempnam('/tmp', 'zlibtest') . '.gz';
echo "<html>\n<head></head>\n<body>\n<pre>\n";
$s = "Only a test, test, test, test, test, test, test, test!\n";
// 最大限の圧縮を指定して書きこみ用にファイルをオープン
$zp = gzopen($filename, "w9");
// 文字列をファイルに書きこむ
gzwrite($zp, $s);
// ファイルを閉じる
gzclose($zp);
// 読みこみ用にファイルをオープン
$zp = gzopen($filename, "r");
// 3 文字読みこむ
echo gzread($zp, 3);
// ファイルの終端まで出力して閉じる
gzpassthru($zp);
gzclose($zp);
echo "\n";
// ファイルをオープンし、内容を出力する (2回目)
if (readgzfile($filename) != strlen($s)) {
echo "Error with zlib functions!";
}
unlink($filename);
echo "</pre>\n</body>\n</html>\n";
?>
目次
- gzclose — 開かれたgzファイルへのポインタを閉じる
- gzcompress — 文字列を圧縮する
- gzdecode — gzip 圧縮された文字列をデコードする
- gzdeflate — 文字列を deflate 圧縮する
- gzencode — gzip 圧縮された文字列を作成する
- gzeof — gz ファイルポインタがファイル終端かどうか調べる
- gzfile — gzファイル全体を配列に読み込む
- gzgetc — gz ファイルへのポインタから文字を得る
- gzgets — ファイルポインタから 1 行を得る
- gzgetss — gzファイルへのポインタから1行を得て、HTMLタグを取り除く
- gzinflate — deflate圧縮された文字列を解凍する
- gzopen — gz ファイルを開く
- gzpassthru — gzファイルへのポインタから残りのデータ全部を出力する
- gzputs — のエイリアス gzwrite()
- gzread — バイナリ対応のgzファイル読み込み
- gzrewind — gz ファイルポインタの示す位置を元に戻す
- gzseek — gz ファイルポインタの位置を移動する
- gztell — gzファイルポインタの読み込み/書き込み位置を返します
- gzuncompress — 圧縮された文字列を解凍する
- gzwrite — バイナリセーフな gz ファイル書き込み
- readgzfile — gz ファイルを出力する
- zlib_get_coding_type — 出力圧縮に使用されたコーディングの種類を返す
zlib 圧縮関数
26-Jun-2007 03:58
27-Jul-2006 10:59
php at seven dot net dot nz:
Have you been using register_shutdown_function() that outputs something? If yes, some of the output was not encoded and IE6 is less than forgiving about that. In my case it was reloading the page and sometimes showing a blank page. So IE6 does get invalid stream, bug is not bogus, only description is not good enough.
jpleveille at webgraphe dot com:
In PHP 4.4.2 register_shutdown_function() DOES output whatever you wish, but it is not encoded with the rest of the document. Which is even worse as you get a bug that is difficult / impossible to track down.
07-Jul-2006 05:49
zlib.output_compression has caused problems for me in IE 6, when pages are sometimes not displayed. This could be difficult to track down and PHP have no intention of fixing it, so hopefully you find this note in a search if it happens to you.
http://bugs.php.net/bug.php?id=38026
24-May-2006 02:34
PHP Version 5.1.4 here. What Bob said is correct even in this version (newest at the time of writing). You can't enable zlib.output_compression via ini_set(). You have to use php.ini.
19-Sep-2005 10:45
Contrary to what the documentation says, I've been unable to get zlib.output_compression to work via ini_set() (Even though I put it at the very beginning of the file before any output was sent) as of php 4.3.11. While it does get set to true, it will not actually do anything. Which means if you don't set this via php.ini or Apache configuration it's a no-go. I have to use ob_start("ob_gzhandler"); instead.
28-Aug-2005 12:27
If you need to compress data and send it as "Content-disposition: attachment" and on-the-fly to the client due to the size for example (40Mb) here's a dirty trick using ob_gzhandler()
Keep in mind that $str is the content to output.
When you start the output call
<?php
echo ob_gzhandler($str, PHP_OUTPUT_HANDLER_START);
?>
Then to output any further content
<?php
echo ob_gzhandler($str, PHP_OUTPUT_HANDLER_CONT);
?>
And to close the output
<?php
echo ob_gzhandler('', PHP_OUTPUT_HANDLER_END);
exit;
?>
Only tested on Apache 1.3.33 with PHP 5.0.4
04-Jul-2005 01:45
I tested all the compression levels against a 22k page and here are the results I got (in bytes):
off = 22549
1 = 4297
2 = 4279
3 = 4264
4 = 4117
5 = 4097
6 = 4063
7 = 4011
8 = 3998
9 = 3996
Looks like the best bets for zlib.output_compression_level is 1 or 5. The default of 6 is probably OK too. Don't know what the CPU usage difference is between them all though.
10-Jun-2005 10:08
register_shutdown_function() (http://www.php.net/register_shutdown_function) won't output anything if you use zlib.output_compression.
Shutdown function is called after closing all opened output buffers thus, for example, its output will not be compressed if zlib.output_compression is enabled.
08-Oct-2004 09:32
My gzip function.
This function read, compress and writhe only small chunks at one time, this way you can compress big files without memory problems...
<?php
function gzip($src, $level = 5, $dst = false){
if($dst == false){
$dst = $src.".gz";
}
if(file_exists($src)){
$filesize = filesize($src);
$src_handle = fopen($src, "r");
if(!file_exists($dst)){
$dst_handle = gzopen($dst, "w$level");
while(!feof($src_handle)){
$chunk = fread($src_handle, 2048);
gzwrite($dst_handle, $chunk);
}
fclose($src_handle);
gzclose($dst_handle);
return true;
} else {
error_log("$dst already exists");
}
} else {
error_log("$src doesn't exist");
}
return false;
}
?>
14-Jul-2004 12:03
Run, do not walk, run, to add this to your Apache config file:
php_flag zlib.output_compression On
php_value zlib.output_compression_level 5
I just tried this and achieved 10x and 15x speed inprovement on
some mature php pages. Pages I have been seating over to make 5% gains on. I use microtime() on critical pages to help me track page speed and that confirms the speed improvement. The php page takes a timestamp at the beginning and end, then logs the page duration. So any IP transmission effects are not included. There is
a clear subjective difference to the user.
The test system was PHP 4.3.6, Apache 2.0.49 over Linux 2.4.
As always YMMV.
12-Jun-2004 07:44
If you use "zlib.output_compression = On" in your php.ini file, and activates output buffering (ob_start), don't output this header :
header('Content-Length: '.ob_get_length());
This is because ob_get_length() will return the uncompressed size while zlib will compress the output. Thus your browser will get confused waiting for extra data that will never come.
04-Jun-2004 11:52
Have a look to this extended version :)
<?php
function compress( $srcFileName, $dstFileName )
{
// getting file content
$fp = fopen( $srcFileName, "r" );
$data = fread ( $fp, filesize( $srcFileName ) );
fclose( $fp );
// writing compressed file
$zp = gzopen( $dstFileName, "w9" );
gzwrite( $zp, $data );
gzclose( $zp );
}
function uncompress( $srcFileName, $dstFileName, $fileSize )
{
// getting content of the compressed file
$zp = gzopen( $srcFileName, "r" );
$data = fread ( $zp, $fileSize );
gzclose( $zp );
// writing uncompressed file
$fp = fopen( $dstFileName, "w" );
fwrite( $fp, $data );
fclose( $fp );
}
compress( "tmp/supportkonzept.rtf", "tmp/_supportkonzept.rtf.gz" );
uncompress( "tmp/_supportkonzept.rtf.gz", "tmp/_supportkonzept.rtf", filesize( "tmp/supportkonzept.rtf" ) );
?>
21-May-2004 03:38
/**
* @return bool
* @param string $in
* @param string $out
* @param string $param = "1"
* @desc compressing the file with the zlib-extension
*/
function gzip ($in, $out, $param="1")
{
if (!file_exists ($in) || !is_readable ($in))
return false;
if ((!file_exists ($out) && !is_writable (dirname ($out)) || (file_exists($out) && !is_writable($out)) ))
return false;
$in_file = fopen ($in, "rb");
if (!$out_file = gzopen ($out, "wb".$param)) {
return false;
}
while (!feof ($in_file)) {
$buffer = fgets ($in_file, 4096);
gzwrite ($out_file, $buffer, 4096);
}
fclose ($in_file);
gzclose ($out_file);
return true;
}
/**
* @return bool
* @param string $in
* @param string $out
* @desc uncompressing the file with the zlib-extension
*/
function gunzip ($in, $out)
{
if (!file_exists ($in) || !is_readable ($in))
return false;
if ((!file_exists ($out) && !is_writable (dirname ($out)) || (file_exists($out) && !is_writable($out)) ))
return false;
$in_file = gzopen ($in, "rb");
$out_file = fopen ($out, "wb");
while (!gzeof ($in_file)) {
$buffer = gzread ($in_file, 4096);
fwrite ($out_file, $buffer, 4096);
}
gzclose ($in_file);
fclose ($out_file);
return true;
}
14-May-2004 11:04
For decompressing, i modified a function posted earlier (that way $string doesn't have a big size that may be beyond the memory limit if the gzipped file is big) :
function file_ungzip($fromFile, $toFile) {
$zp = @gzopen($fromFile, "r");
$fp = @fopen($toFile, "w");
while(!@gzeof($zp)) {$string = @gzread($zp, 4096); @fwrite($fp, $string, strlen($string));}
@gzclose($zp);
@fclose($fp);
}
17-Nov-2003 09:02
I found the absolute easiest way to read a gzip file is as follows:
echo file_get_contents("compress.zlib:///myphp/test.txt.gz");
To create a gzip file:
file_put_contents("compress.zlib:///myphp/test.txt.gz","Put this in the file\r\n");
Things to note about this:
-The best prefix to use is "compress.zlib", not "zlib"
-If you wish to specify a path starting in the root path, you actually end up with three slashes. The above path corresponds to "/myphp/test.txt" on unix, and "c:\myphp\test.txt" on Windows (if C: is the current drive). I tested it just on Windows.
-Compression and decompression both use the same prefix of "compress.zlib://" (plus one more slash to get a root dir).
-I'm using 5.0, so I'm not 100% sure which behaviour started in which version.
28-May-2003 09:10
Nice function. I did it the other way round:
function uncompress($srcName, $dstName) {
$zp = gzopen($srcName, "r");
while(!gzeof($zp))
$string .= gzread($zp, 4096);
gzclose($zp);
$fp = fopen($dstName, "w");
fwrite($fp, $string, strlen($string));
fclose($fp);
}
uncompress("./myfile.txt.gz", "./myfile.txt");
A shorter approach would be:
function uncompress($srcName, $dstName) {
$string = implode("", gzfile($srcName));
$fp = fopen($dstName, "w");
fwrite($fp, $string, strlen($string));
fclose($fp);
}
25-Mar-2003 12:47
The method of first reading the source file and then passing its content to the gzip function instead of simply the source and destination filename was a bit confusing for me.
So I have written a simple funtion you can use to compress files in the gzip format (gzip is readable by winzip like .zip files)
function compress($srcName, $dstName)
{
$fp = fopen($srcName, "r");
$data = fread ($fp, filesize($srcName));
fclose($fp);
$zp = gzopen($dstName, "w9");
gzwrite($zp, $data);
gzclose($zp);
}
// Compress a file
compress("/web/myfile.dat", "/web/myfile.gz");
13-Feb-2003 07:06
If you turn zlib.output_compression_level on, be advised that you shouldn't try to flush() the output in your scripts. PHP will add the gzip header but send the output uncompressed, which plays havoc with Mozilla. IE seems to handle it, though.
19-Apr-2001 10:02
An alternate way to handle gzip compression is to let the mod_gzip module of apache handle it. This seems to contradict the tutorial on phpbuilder.com saying that it won't compress php (or any dynamic) output, but mod_gzip as of version 1.3.17.1a works well for me.
Here is an example of an httpd.conf setup:
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_minimum_file_size 300
mod_gzip_maximum_file_size 0
mod_gzip_maximum_inmem_size 100000
mod_gzip_keep_workfiles No
mod_gzip_temp_dir /tmp
mod_gzip_item_include file \.html$
mod_gzip_item_include file \.jsp$
mod_gzip_item_include file \.php$
mod_gzip_item_include file \.pl$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-httpd-php
mod_gzip_item_include mime ^httpd/unix-directory$
mod_gzip_item_include handler ^perl-script$
mod_gzip_item_include handler ^server-status$
mod_gzip_item_include handler ^server-info$
mod_gzip_item_exclude mime ^image/.*
</IfModule>
This will automatically compress all output of your files with the .php extention or the x-httpd-php mime type. Be sure to have dechunk set to Yes.