備忘録(PHP)の最近のブログ記事

PHPなどで、処理を実行するときに長時間の処理となってしまう場合、ブラウザ側でタイムアウトとなってしまい継続処理がうまく実行できない場合があります。

定期的にパケットを送信してタイムアウトにならないように対策をしますが、それでも対応できない場合にブラウザのタイムアウトの設定を調整します。定期的にパケットを送信してタイムアウトにならないように対策をしますが、それでも対応できない場合にブラウザのタイムアウトの設定を調整します。

Firefoxについては、アドレスバーにabout:configと入力することで設定画面を開くことが出来ます。

表示された項目のnetwork.http.keep-alive.timeoutという項目がタイムアウト時間にあたります(秒数指定)。

PHPで、四則演算をすることって多々あると思います。

その中で、小数点を含む計算をしたときに、コンピュータは賢いようで賢くないので、誤計算をしてしまいます。

例えば、
(0.1 + 0.7) * 10
答は、8なのですが、
コンピュータが出した答は7

おいおい、ってなるんですよね。

PHPだと、bcadd()関数を使って計算しないとダメなのです。
乗算の場合は、bcmul()関数。


ところが、いろいろとやっているうちに、同じ計算をしているのに現象が起きるページと起きないページがあるんです。

なぜか?

違いを見比べて見たところ、
現象が起きているページ→計算結果を直接出力している。
現象が起きていないページ→計算結果を変数に格納してから、出力している。
PHPのバージョンかもしれませんが、私の環境下ではこのような結果になりました。

結論:
計算結果は、一度変数に格納してから、出力するといい。

もしかすると、特定の環境下という条件かもしれません。

詳しい情報お持ちの方は、ご教授下さい。

PHPでファイルの内容を読み取りデータベースにインポートするプログラムを構築していたのですが、ファイルのエンコードが不明だったので、mb_detect_encodingを使ってエンコードを調べてから、処理をすることにしていました。

しかし、mb_detect_encodingの返り値がFALSEしか返ってこない。
なぜ??

調べてみると、
mb_detect_order('auto');
print_r(mb_detect_order());
を実行。

すると、結果は
. Array ( [0] => ASCII [1] => UTF-8 ) bool(false)
ん?

ASCIIとUTF-8しかない。

テストで取り込んでいたテキストは、EUCとSJIS。

納得。

PHP6の正式版のリリースが待たれていますが、現在多くのプログラムはバージョン4、5で稼動しています。
一部のサーバではPHP4からPHP5への移行を行っていますが、いまだにPHP4,5は現役と言えるでしょう。
しかし、PHP6のリリースでPHP4,5,6と環境が3つになると管理が面倒になります。
少なくとも、私は未だPHP6というものをよく知りません。
そこで、今回はPHP6について新機能を備忘録として記載しておくことにしました。

以前、PHP マルチスレッド処理(並行処理)を実行する方法という記事を書きましたが、別ウィンドウを開いてマルチプロセスを実現する方法が分かりました。

それは、ほんと単純なことでした。

セッションを使わない、開始しないだけでした。

セッションを開始すると、セッション情報が保持されるため別ウィンドウを開いたとしても、同じセッションIDを利用する。(たぶん)
その同じセッションIDというのが曲者で、同じセッションIDだと別ウィンドウを開いても同一プロセスとして扱われてしまい、片方のプロセスが終わらないともう一方のプロセスが開始されない。

気づいたときには、「なんだ、そんなことか」と思いました。

PHPのmail関数を使って、日本語(マルチバイト)のファイル名を添付するしてメールを送信する方法を紹介します。

方法はいたって簡単でした。

普通に日本語ファイル名をそのまま記述すると、拡張子が外れた状態で受信してしまいます。

そこで、一つおまじないをかけます。

日本語ファイル名に対して、mb_encode_mimeheader()関数を使ってエンコードするだけです。

例:$mail_body .= "Content-Disposition: attachment; filename=\"".mb_encode_mimeheader("ファイル名").".【拡張子】\";\n";

もしかしたら、間違っているかもしれませんが、私の環境下では正常に送信・受信できました。

PHPのmail関数を使って、複数のファイルを添付してメールを送信する方法を紹介します。

// メールヘッダ部
$header="From:".【メール送信元】."\n".
       "MIME-Version: 1.0\n".
       "Content-Type: multipart/mixed;".
       " boundary=\"__BOUNDARY__\"\n\n".
       "Mime-Version: 1.0\n".
       "Content-Type: text/plain; charset=ISO-2022-JP\n".
       "Content-Transfer-Encoding: 7bit";

// メール本文部
$mail_body="メール本文\n".
"--__BOUNDARY__\n";

// 添付ファイル部
$temp_file_body ="";

// 添付ファイル1
$file1_name="【添付ファイルパス】";
$file = fopen($file1_name,"r");
$file1_contents=file_get_contents($file1_name);
fclose($file);
// 添付ファイル2
$file2_name="【添付ファイルパス】";
$file = fopen($file2_name,"r");
$file2_contents=file_get_contents($file2_name);
fclose($file);
// 添付ファイル3
$file3_name="【添付ファイルパス】";
$file = fopen($file3_name,"r");
$file3_contents=file_get_contents($file3_name);
fclose($file);

// 添付ファイル1の記述
$temp_file_body .="Content-Type: application/octet-stream;name=\"【添付ファイル1名】\";\n";
$temp_file_body .= "Content-Disposition: attachment; filename=\"【添付ファイル1名】\";\n";
$temp_file_body .= "Content-Transfer-Encoding: base64\n\n";
$temp_file_body .= chunk_split(base64_encode($file1_contents)) . "\n";

// 区切り
$temp_file_body .= "--__BOUNDARY__\n";

// 添付ファイル2の記述
$temp_file_body .="Content-Type: application/octet-stream;name=\"【添付ファイル1名】\";\n";
$temp_file_body .= "Content-Disposition: attachment; filename=\"【添付ファイル1名】\";\n";
$temp_file_body .= "Content-Transfer-Encoding: base64\n\n";
$temp_file_body .= chunk_split(base64_encode($file2_contents)) . "\n";

// 区切り
$temp_file_body .= "--__BOUNDARY__\n";

// 添付ファイル3の記述
$temp_file_body .="Content-Type: application/octet-stream;name=\"【添付ファイル1名】\";\n";
$temp_file_body .= "Content-Disposition: attachment; filename=\"【添付ファイル1名】\";\n";
$temp_file_body .= "Content-Transfer-Encoding: base64\n\n";
$temp_file_body .= chunk_split(base64_encode($file3_contents)) . "\n";

// 結合
$send_mail_body=$header.$mail_body.$temp_file_body;

// 文字エンコードをJISに変換
$send_mail_body=mb_convert_encoding($send_mail_body,'JIS');

// 文字エンコードをJISに変換
$subject=mb_convert_encoding("メール件名",'JIS');

// メール送信
mail(【メール宛先】,$subject,$send_mail_body,$header);

PHPで複数の処理を実行したい場合、どうしても逐次処理となってしまいます。
例えば、5秒かかる処理が10個あった場合、5×10=50秒必要です。
それを、マルチスレッド(並列処理)で行えば5秒ですみます。
その方法を紹介します。情報元はこちらです。

PHPでマルチスレッド(バックグラウンド処理)を実現する方法 - EC studio 技術ブログ

とあるシステムである特定の処理が遅いと指摘をうけていました。
ある条件になると、処理時間が超過してしまいブラウザタイムアウトとなってしまい、処理が終了しないという状況になります。


さて、原因についてですが、まず条件というのが、処理件数が多くなってしまうということなのですが、処理件数が多いと処理に時間がかかるのはしょうがない。


処理の概要ですが、データベースから条件を指定して抽出を行い、その抽出したデータにさらにPHP側で処理を行うというものです。


ここで時間がかかっていたのは、データベース側ではなくPHP側です。
当初、データベース側で複雑な条件を指定すると時間がかかるため、PHP側の処理に変更したのですがどうもPHP側にすると遅いという状況でした。
この遅くなるという部分の処理ですが、チェック用の配列Arrayの中にデータベースから取り出した値が存在するかチェックを行ってTRUEならば、チェック用の配列に値を格納。これを繰り返すという内容なのですが、このチェック用の配列が1000件近くになると極端に遅くなるんです。


では、どうすればいいか。
方法としては、二つあります。

  • 1つは、この配列がある程度、例えば100件程度になれば別の配列に格納する。ただ、この方法だと配列の全件チェックはできないのでNG.
  • 2つ目は、配列ではなくデータベースに格納する。
    この方法だと、処理件数が少ないと遅くなるのですが、処理件数が多くなると全件チェックはSELECT文一つで完結するので、早くなる。
    データベースはMySQLなので、ストレージエンジンはHEAPを選択しようと思ったのですが、HEAPはメモリ上にデータを格納する性質上、MySQL終了時にクリアされる。
    しかし、クリアされるのはレコードのみで、テーブルは残ってしまう。
    将来的に、件数が肥大してメモリ圧迫も困るので結局MyISAMを選択しました。

さてさて、結果はまず150秒ほどかかっていた処理が30秒ほどになりました。
そして、タイムアウトになっていた処理も200秒程度で処理が完了します。


今回のことで、データが多く大きくなると格納する変数、配列も考慮しておかないといけないのだなと実感しました。
たぶん、Cを経験されている方はメモリの管理も含めて開発しているのでしょうから、今回のようなトラブルは開発時点で分かっていることなんでしょう。
まだまだ、未熟だと実感しましたOTL


PHPを使ってユーザにファイルをダウンロードしてもらいたい場合は、header関数を使ってContent-Disposition:ヘッダを送信すれば簡単に構築できます。
今回はその方法を簡単に紹介しましょう。

まずは基本的なContent-Disposition構文は次のとおりです。
Content-Disposition: attachment; filename="<ファイル名>"
Content-Type:<ファイル形式>

Content-Disipositionフィールドを「attachment」とすることで、ユーザに表示するか保存するかを選択させることができます。よくある開くか保存するかのダイアログボックスが表示されます。

Content-typeを設定すればファイル形式を指定できます。

ファイル形式 対応するContent-Type
HTML text/html
テキスト text/plan
CSS text/css
JPEG画像 image/jpeg
GIF画像 image/gif
PNG画像 image/x-png
PDF application/pdf
tar形式圧縮ファイル application/x-tar
zip形式圧縮ファイル application/zip
CSVファイル application/x-csv
Excelファイル application/vnd.ms-excel
その他のファイル application/octet-stream

次は、簡単なプログラムを書いてみます。

カスタム検索

ファーストサーバー



問い合わせ

メールフォーム