MW211 EXIT

devlog
PHP/ZipArchive
2013年09月24日
PHP標準でZIP圧縮ができるようになった(って結構前から?)。
ZipArchiveクラスである。
include不要、即使える。

こんな感じ。
┌──────────────────────────────────────┐
│$newZipArchive = new ZipArchive();                                          │
│$result = $newZipArchive->open('test.zip',                                  │
│                               ZIPARCHIVE::CREATE);                         │
│if ($result !== TRUE) {                                                     │
│    exit('エラー');                                                         │
│}                                                                           │
│$newZipArchive->addFromString('test.txt',                                   │
│                              'てすと');                                    │
│$newZipArchive->close();                                                    │
└──────────────────────────────────────┘
即席でテキストファイルを作り、圧縮している例だ。

「addFromString()」メソッドの部分を、「addFile()」メソッドにすれば
既存ファイルを参照して、圧縮することができる。
┌──────────────────────────────────────┐
│$newZipArchive->addFile('C:\input.txt',                                     │
│                        'test.txt');                                        │
└──────────────────────────────────────┘
分類:PHP
PECL/PECLバッチのシンタックスエラー
2013年09月23日
「pecl.bat」を実行した場合に発生する以下のエラー。
  ┌────────────────────────────────────┐
  │syntax error,unexpected '(' in Unknown on line 9                        │
  └────────────────────────────────────┘
PEARの場合と同件で、パスに「Program Files (x86)」のように括弧が混じっていると、
発生するもの。
解消策としては以下の通り(PEARの場合と同じ)。
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  このエラーの解消策としては、例えば「pecl.bat」の中身を以下のように変更する
  ┌────────────────────────────────────┐
  │include_path="%PHP_PEAR_INSTALL_DIR%"                                   │
  └────────────────────────────────────┘
    ↓
  ┌────────────────────────────────────┐
  │"include_path='%PHP_PEAR_INSTALL_DIR%'"                                 │
  └────────────────────────────────────┘
  全体を「"」で囲ってやるのだ(右辺だけではなく全体という点に注意)
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
なお、シンタックスエラーの行番号は直す場所の行番号と全く関係ないから注意。
分類:PECL
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、【未解決】
設計/チャンクサイズ
2013年09月19日
「チャンクサイズ(Chunk_Size)」。
「Chunk」は「塊」の意。よって、データを区切る大きさのことを言う。
RAIDアレイ管理の場合は「ストライプサイズ」とも。
これらの総称として「ブロックサイズ」がある。
分類:設計
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
前へ 1 … 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 … 156 次へ