オリジナルのプラグインを zip で配ろうとしたら、JSON のファイルは取れるのに、zip だけダウンロードが途中で止まりました。
原因:HTML を整える処理が zip にもかかっていた
このブログのテーマには、ページを出す前に HTML のコメントやタブ、続く空行を消して、少し軽くする処理が入っています。ob_start で出力をまとめて受け取り、最後に置き換えてから出す作りです。
zip を readfile で送ると、その内容もこのバッファを通ります。zip の中にたまたまタブや改行の並びがあると、それが消されてしまい、ファイルが壊れます。さらに、先に送った Content-Length(ファイルの大きさ)と実際に届く大きさが合わなくなるので、ブラウザは残りを待ち続け、ダウンロードが止まったように見えていました。
直し方:送る前に、出力のバッファを全部外す
// 出力をまとめて置き換える仕組みを外す(外さないと zip の中身が書き換わる)
while ( ob_get_level() > 0 ) {
ob_end_clean();
}
status_header( 200 );
nocache_headers();
header( 'Content-Type: application/zip' );
header( 'Content-Length: ' . filesize( $file ) );
header( 'Content-Disposition: attachment; filename="' . basename( $file ) . '"' );
readfile( $file );
exit;
直したあと、取ってきた zip と元の zip を比べて、1 バイトも違わないことを確認しました。
気をつけること
WordPress からファイルを送るとき
- テーマやプラグインが ob_start を使っていないかを、先に確認する
- 送る前にバッファを外し、送ったら exit で止める
- ページのキャッシュのプラグインがあるときは、DONOTCACHEPAGE でキャッシュに入れない
- 確認は、元のファイルと取ってきたファイルを比べる(大きさだけでなく内容も)
