MW211 EXIT

devlog
PHP/出力制御関数の例
2013年09月22日
まず、標準出力の例。
┌──┬───────────────────────────────────┐
│記述│echo '出力';                                                          │
├──┼───────────────────────────────────┤
│結果│出力                                                                  │
└──┴───────────────────────────────────┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
続いて、出力制御(ob)を経由した場合の例。
┌──┬───────────────────────────────────┐
│記述│ob_start();                                                           │
│    │echo '出力';                                                          │
│    │ob_end_flush();                                                       │
├──┼───────────────────────────────────┤
│結果│出力                                                                  │
└──┴───────────────────────────────────┘
ちなみに、途中で投げたしても(最後の処理を書き忘れても)補足されるようだ。
でも、これはやめた方がいいだろう。
┌──┬───────────────────────────────────┐
│記述│ob_start();                                                           │
│    │echo '出力';                                                          │
├──┼───────────────────────────────────┤
│結果│出力                                                                  │
└──┴───────────────────────────────────┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
次に、出力しないで破棄する場合の例。当然ながら何も出力されない。
┌──┬───────────────────────────────────┐
│記述│ob_start();                                                           │
│    │echo '出力';                                                          │
│    │ob_end_clean();                                                       │
├──┼───────────────────────────────────┤
│結果│(出力なし)                                                            │
└──┴───────────────────────────────────┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
直前に文字列に退避しておいた場合の例。本体がなくなっても退避されている。
┌──┬───────────────────────────────────┐
│記述│ob_start();                                                           │
│    │echo '出力';                                                          │
│    │$ob = '[' . ob_get_contents() . ']';                                  │
│    │ob_end_clean();                                                       │
│    │echo $ob;                                                             │
├──┼───────────────────────────────────┤
│結果│[出力]                                                                │
└──┴───────────────────────────────────┘
本体も出力すれば、二重に出力される。(本体はなくなっていない)。
┌──┬───────────────────────────────────┐
│記述│ob_start();                                                           │
│    │echo '出力';                                                          │
│    │$ob = '[' . ob_get_contents() . ']';                                  │
│    │ob_end_flush();                                                       │
│    │echo $ob;                                                             │
├──┼───────────────────────────────────┤
│結果│出力[出力]                                                            │
└──┴───────────────────────────────────┘
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ちなみにクリアして退避にすれば、本体はなくなっているので、重複しない。
┌──┬───────────────────────────────────┐
│記述│ob_start();                                                           │
│    │echo '出力';                                                          │
│    │$ob = '[' . ob_get_clean() . ']';                                     │
│    │ob_end_flush();                                                       │
│    │echo $ob;                                                             │
├──┼───────────────────────────────────┤
│結果│[出力]                                                                │
└──┴───────────────────────────────────┘
分類:PHP
PHP/出力制御関数
2013年09月21日
そのまま標準出力するのではなく、一旦出力バッファに溜め込んでから出力する。
出力バッファ内で一括置換的なことができるので便利であるらしい。

【基本】
┌──────────────┬───────────────────────┐
│ob_start()                  │開始                                          │
├──────────────┼───────────────────────┤
│ob_get_contents()           │取得                                          │
│ob_flush()                  │出力                                          │
│ob_clean                    │消去                                          │
├──────────────┼───────────────────────┤
│ob_end_flush()              │終了(出力)                                    │
│ob_get_flush()              │=ob_get_contents()+ob_end_flush()           │
│ob_end_clean()              │終了(破棄)                                    │
│ob_get_clean()              │=ob_get_contents()+ob_end_clean()           │
└──────────────┴───────────────────────┘
【確認】
┌──────────────┬───────────────────────┐
│ob_get_status()             │各種情報確認                                  │
│ob_get_level()              │階層確認                                      │
├──────────────┼───────────────────────┤
│ob_get_length()             │サイズ確認                                    │
├──────────────┼───────────────────────┤
│ob_list_handlers()          │使用中ハンドラ確認                            │
└──────────────┴───────────────────────┘
【特殊】
┌──────────────┬───────────────────────┐
│ob_gzhandler()              │gzip圧縮設定(「ob_start('ob_gzhandler');」)   │
├──────────────┼───────────────────────┤
│output_add_rewrite_var()    │URLにGETパラメータを付加                      │
│output_reset_rewrite_vars() │output_add_rewrite_var()を終了                │
└──────────────┴───────────────────────┘
【フラッシュ】
┌──────────────┬───────────────────────┐
│flush()                     │フラッシュ                                    │
├──────────────┼───────────────────────┤
│ob_implicit_flush(TRUE)     │自動フラッシュ設定(flush()不要)               │
└──────────────┴───────────────────────┘
  実際に出力するためには「ob_flush()」系の直後に「flush()」も必要。
  以下のような関係となる。
  ┌──────────────────┐
  │                        │(echo)    │
  │┌─────┌─────↓─┐      │
  ││PHP       │ 出力バッファ │      │
  │└─────└─────┬─┘      │
  │                        │ob_flush()│
  │┌─────┌─────↓─┐      │
  ││Webサーバ │ 出力バッファ │      │
  │└─────└─────┬─┘      │
  │                        │flush()   │
  │┌───────────↓┐        │
  ││ブラウザ                │        │
  │└────────────┘        │
  └──────────────────┘
分類:PHP
PHP/fread()とチャンクサイズの関係
2013年09月20日
fread()の読込終了条件の一つとして、以下がある。
「バッファつきで読み込まれた、プレーンなファイルでないストリームの場合に、
  一回の読み込みバイト数がチャンクサイズ(通常は 8192)に達した。
  それまでにバッファされていたデータの内容によって、
  返されるデータのサイズはチャンクサイズより大きくなることがあります。」
読みようによっては「fread($fp, 8192);」までしか
第二引数が指定できないように見える。
だけど、実際は結構無制限(PHPのメモリサイズとの相談となる)。
  ・テキストファイル読込時は無制限でOK
  ・URLを指定してHTML読込時も無制限でOK

つまり「バッファつき…ストリームの場合」ってのは結構イレギュラーなケースっぽい。
で、どんなケースなのかというと、「ユーザ定義のストリーム」ってやつを
読み込む時が対象みたい。

「ストリーム」機能って、シーケンシャルに読み込めるものなら
なんでも対象となる便利なPHPの機能っぽいが、今一よくわからない。

引き続き調査。
分類:PHP、【未解決】
PHPダウンロード/readfile()の代案のおまけ
2013年09月18日
「readfile()」で大容量ファイルを扱うと以下のエラーがでるといった。
┌──────────────────────────────────────┐
│Fatal error:  Allowed memory size of xxxxxxxxx bytes exhausted              │
│                                   (tried to allocate xxxxxxxxx bytes) in …│
└──────────────────────────────────────┘

これと同じで「fread()」の第二引数で、一回の読み込みサイズを
物凄く大きく指定した場合(ループせずに一回で済まそうとした場合)も、
これと同じエラーとなる。
┌──────────────────────────────────────┐
│@readfile($参照ファイル);                                                   │
├──────────────────────────────────────┤
│$fp = fopen($参照ファイル, 'rb');                                           │
│fread($fp, 大きなサイズ);                                                   │
│fclose($fp);                                                                │
└──────────────────────────────────────┘

つまりまとめて(メモリに)読み込んで一気に提供(標準出力)すると
中間バッファに限界があるが、ループして小出しに提供すれば
中間バッファが小さくても足りるということだ。

【追記】出力バッファリングをオフにすれば「readfile()」が使えると判明
分類:PHP
PHPダウンロード/readfile()の代案
2013年09月17日
「readfile()」は「fread()」(のループ)で代替することができる。

以下のような感じとなる。
┌──────────────────────────────────────┐
│@readfile($参照ファイル);                                                   │
├──────────────────────────────────────┤
│set_time_limit(0);                                                          │
│$fp = fopen($参照ファイル, 'rb');                                           │
│while (!feof($fp)) {                                                        │
│    echo fread($fp, 8192);                                                  │
│}                                                                           │
│fclose($fp);                                                                │
└──────────────────────────────────────┘
「readfile()」はあまり気にすることない、PHP処理時間上限ってのに注意。

つまり、PHP処理時間上限ってのを
「php.ini」の「max_execution_time」(既定値30秒)で定義しているわけだが、
この処理時間がこれを超えると強制的に打ち切られてしまう。

大容量のダウンロードを行った場合、時間がかかると
強制的に打ち切られて、中途半端なダウンロードファイルが提供されてしまうのだ。

ということで、その設定を変えるか、その代案として
先頭で「set_time_limit(0)」実行し、一時的にこれを無制限にするかする必要がある。

ま、そもそもはそんな長時間かけてダウンロードするような設計は避けた方がよい
ということなのだろうけど、必要に直面した場合には
(「fread()」による代案も含め)このような回避方法があるということだ。


【追記】出力バッファリングをオフにすれば「readfile()」が使えると判明
分類:PHP
PHPダウンロード/readfile()は大きなファイルには使えない
2013年09月16日
便利な「readfile()」だが、大容量のファイルをダウンロードする場合に、
使えないという弱点がある。。
もし、これを行った場合、以下のようなエラーがダウンロードされる。
┌──────────────────────────────────────┐
│Fatal error:  Allowed memory size of xxxxxxxxx bytes exhausted              │
│                                   (tried to allocate xxxxxxxxx bytes) in …│
└──────────────────────────────────────┘
但し、一般的には「@readfile()」のように「@」を付けて
エラーメッセージを抑止しているので空のファイルがダウンロードされるだろう。
この場合は「@」を外してもう一度実行してみるとよい。

で、この原因なのだが、「readfile()」はダウンロードファイルを
一旦すべてメモリ上に展開してしまうため、
大容量ファイルだとメモリが足りなくなってしまうのだ。

使えるメモリは「php.ini」の「memory_limit」で定義しているので
この値を大きくすれば対応できる場合もあるが、物理的にメモリが限られているので、
この範囲内でしか調整ができない。
#もちろんPHP内の他でもメモリは消費されるので、ダウンロードファイルの
  サイズぎりぎりってわけにはいかない(大きめにとらなければならない)

ということで、代案が必要だが、次回。

【追記】出力バッファリングをオフにすれば「readfile()」が使えると判明
分類:PHP
PHPダウンロード/readfile()
2013年09月15日
簡単にいえば「readfile()」は、指定された(内部)ファイルを
そのままダウンロードファイルとして提供してくれる便利な関数だ。
┌──────────────────────────────────────┐
│header('Content-Disposition: attachment; filename="ダウンロード先名"');     │
│header('Content-Type: application/octet-stream');                           │
│@readfile($ダウンロード元ファイルパス);                                     │
└──────────────────────────────────────┘
こんな感じで使う。ファイルパス($ダウンロード元ファイルパス)と
公開されるファイル名(ダウンロード先名)を指定するだけで
後は煩雑な処理をまとめてやってくれる。

なお、「readfile()」の前に「@」を付けてエラーメッセージを抑止しているのは
もしエラーが発生した場合、その内容がダウンロードファイルとして
公開されてしまうので、それを防ぐためだ。
分類:PHP
PHP/isset()を複数判定する場合
2013年09月08日
┌──────────────────────────────────────┐
│if ((isset($_POST['a'])) && (isset($_POST['b']))) {                         │
└──────────────────────────────────────┘

「isset()」を複数判定する場合は、「&&」で繋げるのではなく、
第二引数以降に追加していこう。
┌──────────────────────────────────────┐
│if (isset($_POST['a'], $_POST['b'])) {                                      │
└──────────────────────────────────────┘

ま、好き好きですが。
分類:PHP
PHP/BOMコードとPHPソース
2013年08月11日
PHPソースファイルをうっかりメモ帳で開いて保存してしまうと大変なことが起きる。
#UTF-8で作成している場合の話ね

メモ帳はBOM付きで保存してしまうのだ。

では、BOM付きPHPソースファイルの影響はというと…。

┌──────────────────────────────────────┐
│あ<?php                                                                     │
└──────────────────────────────────────┘
単純な話、上記のようにうっかりPHPソースの外に
変な文字を混入させてしまった場合と同じだと考えていい。
┌──────────────────────────────────────┐
│(BOM)<?php                                                                  │
└──────────────────────────────────────┘

【画面表示の場合】
作成されるHTMLソースの先頭にBOMコードが付加されるので、
UTF-8(BOM無し)ソースではなく、UTF-8(BOM付き)ソースとなる。
但し、これは何の問題もない。
しかしながら、インクルードするファイルが二つ以上BOMに侵されていると
BOMが二重に付加された方にになり、二つ目のBOMが半角スペースのようになり
悪さをしてしまう。

【ダウンロード機能の場合】
画面表示ではなくダウンロードに使う場合、出力されるデータの先頭に
BOMが付加されてしまう。
UTF-8のデータとしてダウンロードするなら影響はないが、
シフトJISのCSVファイルとかに変換してダウンロードする場合は、
シフトJISの中(正確には先頭)にBOMが混在するので文字化けを誘発する。
もちろん、UTF-8のデータだとしても、前述のように二重にBOMがあれば
二つ目が悪さをしてしまう。
分類:PHP
PHP/文字コード変換とBOMコード
2013年08月06日
「mb_convert_encoding()」で文字コード変換を行い、
「UTF-8→シフトJIS」変換をする場合、以下のような感じとなる。
┌──────────────────────────────────────┐
│$変換後SJIS = mb_convert_encoding($変換前UTF-8, 'SJIS-win', 'UTF-8');       │
└──────────────────────────────────────┘

だが、ここで「BOM付きUTF-8」だった場合には、「BOM」が除去されないので
「BOM付きシフトJIS」(?)になる。

当然ながら、そんなものはないので文字化けとなる。
ファイルの先頭が「EFBBBF」だとそのケースだ。

で、「BOM付きUTF-8」を「mb_convert_encoding()」で変換する機能………が、
あったら便利なのだが、見当たらない。

そこで手作業。
┌──────────────────────────────────────┐
│if (($変換前[0] == chr(0xEF))                                               │
│ && ($変換前[1] == chr(0xBB))                                               │
│ && ($変換前[2] == chr(0xBF)))                                              │
│{                                                                           │
│    $変換前 = substr($変換前, 3);                                           │
│}                                                                           │
└──────────────────────────────────────┘
まあ、こんな感じだわね。

なんかもっとすっきりする解決方法はないものか。
分類:PHP
前へ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 … 18 次へ