Apache 2.2 s mod_deflate + PHP

Apache 2.2 s mod_deflate + PHP
« kdy: 09. 11. 2010, 18:50:04 »
Mám problém se zprovozněním modulu mod_deflate v Apache 2.2 s PHP.
Modul mám načtený a funguje, komprese podle odeslaných hlaviček probíhá. Problém nastane ve chvíli, kdy chci pomocí PHP generovat vlastní hlavičky a umožnit stažení souboru. Ukázkový kód:

Kód: [Vybrat]
<?php

// force download dialog
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");

header('Content-Disposition: attachment; filename="test.mp3"');
header('Content-Type: audio/mpeg');
header('Content-Length: ' filesize('/path/to/test.mp3'));
header('Content-Transfer-Encoding: binary');

readfile('/path/to/test.mp3');

?>

Skript volám přes běžný prohlížeč (Firefox) a odchytávám si hlavičky, abych poznal výsledek.

Konfigurace Apache je pomocí .htaccess upravena pro kompresi POUZE požadovaných typů souborů, které chci určit na základě mime type. V .htaccess mám:

Kód: [Vybrat]
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE application/x-javascript
</IfModule>
Výsledkem tohoto by měla být komprese pouze html, plain, xml, css a js souborů. V PHP si vygeneruji ke stažení mp3 soubor a odešlu správné hlavičky. Tento mp3 soubor NESMÍ být pro mé účely komprimován pomocí mod_deflate. Bohužel právě to se mi děje. Toto chování jsem odzkoušel na distribicích Red Hat, CentOS 5.5, ale i ve Windows (Xampp 1.7.3). Je zajímavé, že v Debianu i Arch Linuxu mi se stejným nastavením vše funguje požadovaným způsobem.

Problém bude určitě v konfiguraci Apache, v PHP problém nebude (php.ini je stejné). Změnit definici Apache přes přípony pomocí "AddOutputFilter" není pro mě řešením. Pokud odeberu řádek:

Kód: [Vybrat]
AddOutputFilterByType DEFLATE text/html
pak se mp3 nabídne ke stažení bez komprese, což je přesně co potřebuji.


Skoro to vypadá, že mime type výsledku volaného skriptu je text/html, což mi přijde jako nesmysl, ale přesně tak se to chová. HTML soubory i PHP skripty samozřejmě komprimovat chci.

Co může v nastavení Apache toto způsobovat?


v1kt0r

Re: Apache 2.2 s mod_deflate + PHP
« Odpověď #1 kdy: 09. 11. 2010, 19:23:24 »
Nejsem PHPista, ale je mozne, ze tou silenou baterii "Content-Type" (podle ukazky kodu ho produkujes nekolikrat s ruznymi hodnotami - pravdepodobne se pak v hlavickach objevi postupne vsechny ty varianty) privedes Apache k nazoru, ze Content-Type je zmateny, tudiz jakoby nebyl zadan, tudiz se vezme standardni text/html a zbytek zpracovani jede podle nej?
Rozhodni se pro jeden content type ("octet stream" se jevi jako nejjistejsi volba) a posilej jen ten.

Mimochodem - proc ti vadi ten deflate na MPG obsah? Ano, nema velky smysl, ale pokud se nepletu, rozpakuje to prohlizec jeste predtim, nez ti stazeny soubor preda. Je to jen transportni kodovani. A kazda rozumna http knihovna by ho mela umet rozbalit. Pokud to pozdeji neplanujes stahovat prohlizecem, ale necim vlastnim, muzes hlavickou "Accept" serveru sdelit, ze si deflate/gzip neprejes.

Re: Apache 2.2 s mod_deflate + PHP
« Odpověď #2 kdy: 09. 11. 2010, 20:01:55 »
Díky za reakci. V použití více hlaviček typu Content-Type problém není, podle mě jsou všechny až na tu poslední zbytečné (během testů jsem je i zakomentoval) a použije se až ta poslední, což je pak vidět podle hlaviček. Ten skript jsem dostal v takového podobě od vývojářů. Jak jsem psal, v Debian a Arch Linux funguje stejný skript bez problému.

Tento skript je pouze simulace, důležité je vrácení (nabídnutí ke stažení) souboru včetně hlavičky s proměnnou Content-Lenght, což mi Apache při zapnuté kompresi z pochopitelných důvodu při požadavku nevrátí.

Za ideálních podmínek bude tento soubor předán Flash přehrávači, který je součástí komplexní aplikace a ta ho pak přehraje. Avšak bez proměnné Content-Lenght tento přehrávač nefunguje správně a přehrávat nezačne, proto celá ta patálie. Stažení souboru samozřejmě proběhne a mě osobně by to ke štěstí stačilo, ale bohužel někteří lidé jsou hold náročnější.

Zkoušel jsem i jako poslední možnost vynutit zakázání komprese pomocí hlavičky, ale nepodařilo se. Ten problém je určitě v konfiguraci Apache.

Re: Apache 2.2 s mod_deflate + PHP
« Odpověď #3 kdy: 10. 11. 2010, 08:55:57 »
Po lehkém nakopnutí správným směrem od kolegy jsem problém vyřešil následujícím způsobem:

Konstrukci s použítím AddOutputFilterByType jsem nahradil řešením přes mod_filter (ten je třeba v Red Hat explicitně povolit), v dokumentaci je k parametru AddOutputFilterByType moc vtipná poznámka: Available in Apache 2.0.33 and later; deprecated in Apache 2.1 and later

Výsledný kód pro .htaccess:
Kód: [Vybrat]
<IfModule mod_filter.c>
<IfModule mod_deflate.c>
  FilterDeclare COMPRESS
  FilterProvider COMPRESS DEFLATE Content-Type text/html
  FilterProvider COMPRESS DEFLATE Content-Type text/plain
  FilterProvider COMPRESS DEFLATE Content-Type text/xml
  FilterProvider COMPRESS DEFLATE Content-Type text/css
  FilterProvider COMPRESS DEFLATE Content-Type application/x-javascript
  FilterChain COMPRESS
</IfModule>
</IfModule>

http://httpd.apache.org/docs/current/mod/mod_filter.html
Podle dokumentace jde o vhodnější cestu, i když možná méně přehlednout. Důležité je, že takto to funguje!