ファイルのダウンロードが途中で止まる・zip が壊れる:テーマの出力の整形(ob_start)を外してから送る

広告WordPress・PHP を学べる本

Amazonのアソシエイトとして、WordPress functions.phpは適格販売により収入を得ています。

オリジナルのプラグインを 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 でキャッシュに入れない
  • 確認は、元のファイルと取ってきたファイルを比べる(大きさだけでなく内容も)

SiteBeacon(サイトビーコン)

サイトが止まったら、すぐに気づける。

ホームページを 5 分ごとにチェックして、止まったとき・エラーが出たとき・SSL やドメインの期限が近いときに、メールでお知らせします。2 サイトまでは、ずっと無料で使えます。

SiteBeacon を見る サイトを直す相談をする

監視で気づいたあとの直す作業も、同じ担当がお受けします。