readfileでファイルをダウンロードさせる際のメモ

4日間位PHPでアップローダを書いていて、公開しながらデバックしていたんですが、一番収穫が多かったと思われるreadfileについての書き方をメモしておこうと。

[tmkm-amazon]4839933146[/tmkm-amazon]

今回はMySQLにアップロード日時や削除期限、ダウンロード回数等を保存させるようにするためにPHPのreadfileをつかってみたんですが、実際に複数のアクセスがあると

メモリ及びスワップの使用率が半端なくなる。

ちなみにこの月曜日に公開した時点でのコードは

// DL用出力
 $newcount = $printstring["dlcount"]+1;
 $fileext = $printstring["ext"];
 header('Content-Disposition: attachment; filename="'.$printstring["name"].'"');
 header('Content-Type: '.$type[$fileext]);
 header('Content-Length: '.filesize($dir["upfile"]."/".$printstring["filename"])."'");
 readfile($printsring["download"]);
 $dbstring["sql"] = "UPDATE ".$mydb["uptable"]." SET dlcount='".$newcount."' WHERE upload_no='".$dbstring["dlno"]."'";
 $dbstring["update"] = mysql_query($dbstring["sql"]);

こんな感じ。

データベースから引っ張ってきた「今までのダウンロード回数」・「ファイル拡張子」・「ファイル名」から、configファイル内にある変数を引っ張ってきたあとに、headerに書きだしてダウンロードさせる形式をとっています。

ただしこのままのコードではメモリやスワップがすごいことになってSSHでのアクセスすらままらなかったので、調べてみた結果、

  1. データベースにアクセスしたあとにLocationヘッダーでファイルの場所に飛ばす
  2. 出力バッファを切る

といった解決方法が見つかったんですが、1個目のLocationヘッダーで飛ばすのは、ファイルの直アドレスが分かってしまうためにダウンロードカウントでの制御が無意味になる可能性があったため、

2個目の出力バッファを切るを試してみました。

// DL用出力
 $newcount = $printstring["dlcount"]+1;
 $fileext = $printstring["ext"];
 header('Content-Disposition: attachment; filename="'.$printstring["name"].'"');
 header('Content-Type: '.$type[$fileext]);
 header('Content-Length: '.filesize($dir["upfile"]."/".$printstring["filename"])."'");
 ob_end_flush();
 readfile($printsring["download"]);
 $dbstring["sql"] = "UPDATE ".$mydb["uptable"]." SET dlcount='".$newcount."' WHERE upload_no='".$dbstring["dlno"]."'";
 $dbstring["update"] = mysql_query($dbstring["sql"]);

追加したのはreadfileの前にob_end_flush();を挟んだだけ。

その結果、

メモリ・スワップ使用率も安定できました。

普段全く使うことがない関数なので、こういうことがないと存在すら知らなかったんじゃないかなぁと言う事で。

[tmkm-amazon]4798119865[/tmkm-amazon]