LoginSignup
10
11

More than 5 years have passed since last update.

PHPのお勉強5

Posted at

概念・言語仕様・補完的な実装(の続き)

参考:

PHP: 言語リファレンス - Manual
http://goo.gl/TFWYSf
メニューバーが見やすいリファレンスがあったのでメモ(5.4までと古いけど)
http://i.cmaas.net/php/

バイナリ

PHPはデフォルトでバイナリをテキストとして読み込むのか。
マルチバイト文字も内部ではバイト列なわけだしバイナリみたいものか。

PHPでは今のところテキストとバイナリを区別するものは何もありません。というのもPHPの文字列は単なるバイト列であるからです。マニュアルにも以下のように記述されています。
そこでバイナリをPHPで扱い易いように変換してくれるのがunpack関数です。この関数はバイト列で表現された値を、PHPで簡単に扱える型にまとめて変換してくれる関数です。
このget_png_size関数でやっていることを簡単に説明すると、PNG画像のIHDRチャンクから画像の大きさを表現しているバイト列を取ってきてunpackでその幅と高さをPHPの整数に変換しています。
PNGフォーマットやIHDRチャンクの詳細などについてはPNGフォーマットの仕様書を見ましょう。

じゃあ、バイナリセーフってなに?

$_POST['login_id']にヌルバイト文字(\0)を入れられると、このフィルタリン グは意味を持たなくなります。ためしに

test.php
$_POST['login_id'] = "abc\0 -** 1 **-";

としてみて下さい。ereg関数はtrueを返し、if内部のスクリプトが実行されたと思います。この原因はereg関数がヌルバイト文字の直前までしかマッチングを行わないことにあります。
...
他のバイナリセーフではない関数の一部
ereg_replace(), eregi(), eregi_replace(),
split(), spliti(),
include(), include_once(), require(), require_once()
fopen(), file_get_contents(), readfile(), basename()

バイナリセーフ出ない関数でパスワードを除く手法(PHP 5.3.4前の脆弱性)。
なるほど危ない。

http://example.com/get_image.php?..%2F..%2F..%2Fetc%2Fpasswd%00.png
のようにアクセスすると,/etc/passwdファイルを読み取ることができました。
...
注意
PHPのファイル関数からアクセスできなくするだけで,データベースなどからシステム上のファイルにアクセスすることは可能です。open_basedirもsafe_modeと同様,問題が発生した場合の影響範囲を制限するフェイルセーフ対策です。

各言語の文字列

なるほど、コード中の文字列はバイト列ではなくリテラル(コンピュータプログラムのソースコードなどで、特定のデータ型による値を直接表記する際の書式。また、そのような書式に従って記載された値。)。

PHPでは文字列は長さの情報と単なるバイト配列であり、可変である。
長さの情報を持っているため、本来は終端文字を考えなくてよく、文字列の途中に \x00 を含めることもできる。ただし、文字列の途中に \x00 を含めた文字列は、バイナリセーフでない関数に渡すとおかしなことになるかもしれないので、やめたほうがよい。

・pack,unpackの使い方。やはりマニュアルの情報では不十分らしい。
・分かってきたらバイナリエディタとかよりスクリプトの方が楽になったりするかな。
・配列のキーは0ではなく1からみたいなので注意。

しかし、マニュアルにはあまり詳しい使い方が書かれていないので、unpack関数、特に書式コードをどう使えばいいか解りにくいのが難点です。ネットで検索してもあまり纏まった記事も見つかりませんでした。
そこで、PHPのunpack関数を利用してバイナリファイルを読み込む際に調べた事をまとめてみました。

コメントとか行間がわかりやすい。
携帯端末用再配布禁止命令についても知らなかった。興味深い。(http://www.plusmb.jp/2008/10/17/784.html)

PHPで、GIFファイルのコメントデータを削除する
三大画像形式のコメントデータ削除に成功したから・・・
次は、私個人の当初の目的だったコメントデータへの携帯端末用再配布禁止命令copy="NO"、kddi_copyright=onの書き込み処理を書きます。

バイナリオプションをつけてfreadからバイナリを取得することもある。

test.php
<?php
function send_file($name) {
  ob_end_clean();
  $path = "protected/".$name;
  if (!is_file($path) or connection_status()!=0) return(FALSE);
  header("Cache-Control: no-store, no-cache, must-revalidate");
  header("Cache-Control: post-check=0, pre-check=0", false);
  header("Pragma: no-cache");
  header("Expires: ".gmdate("D, d M Y H:i:s", mktime(date("H")+2, date("i"), date("s"), date("m"), date("d"), date("Y")))." GMT");
  header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
  header("Content-Type: application/octet-stream");
  header("Content-Length: ".(string)(filesize($path)));
  header("Content-Disposition: inline; filename=$name");
  header("Content-Transfer-Encoding: binary\n");
  if ($file = fopen($path, 'rb')) {
    while(!feof($file) and (connection_status()==0)) {
      print(fread($file, 1024*8));
      flush();
    }
    fclose($file);
  }
  return((connection_status()==0) and !connection_aborted());
}
?>
<?php 
function downloadMP3 ($fileDir, $fileName) { 
   $completeFilePath=$fileDir.'/'.$fileName; 
   header('Pragma: no-cache'); 
   header("Content-type: audio/mpeg\nContent-Disposition: attachment; filename=\"" . $fileName . "\"\nContent-length: ".(string)(filesize($completeFilePath))); 
   $fd=fopen($completeFilePath,'rb'); 
      while(!feof($fd)) { 
         print(fread($fd, 4096)); 
         flush(); 
      } 
} 
?>

ちょっとずれるけどストリーミングについて。

従来のダウンロード再生
ストリーミング
プログレッシブダウンロード再生〔擬似ストリーミング再生〕
リアルストリーミング再生

デコレーター

・再帰的なインスタンス化の構造が特徴。
・やり過ぎずに上手に使えば便利らしい。
・委譲による継承がより本質的な概念っぽい。
・トレイトじゃだめかな。代替策として置き換えできないかな?

Decorator パターンの方針は、既存のオブジェクトを新しい Decorator オブジェクトでラップすることである。 その方法として、Decorator のコンストラクタの引数でラップ対象の Component オブジェクトを読み込み、コンストラクタの内部でそのオブジェクトをメンバに設定することが一般的である。
Decorator パターンは、既存のクラスを拡張する際にクラスの継承の代替手段として用いられる。継承がコンパイル時に機能を拡張するのに対し、Decorator パターンはプログラムの実行時に機能追加をする点が異なる。

集約と汎化の良いところどりで、実に柔軟にメソッドを拡張できるパターンですが、
やり過ぎると実にカオスになって手に負えなくなる諸刃の剣なパターンでもあります。

これは単純に「委譲による継承」パターンとすべきだろう。

MVC

モデル・ビュー・コントローラーの構成のアーキテクチャ(デザインパターンの組み合わせによってなる)のことだったり、そのフレームワーク(MVCフレームワーク)を指すっぽい。

PHPのプログラミング手法としてMVCと呼ばれるものがあります。
MVCとはModel・View・Controllerの略で、処理を3つの役割に分割して実装する手法です。

そういうこともあって、MVCの概念にとらわれ過ぎず、ここの趣旨のように、必要に応じて新しい概念を付け足すなんてのもありじゃないかと思います。

いろいろあると、、イベント駆動のアーキテクチャーの場合のMVVMなど。

もう一つ最初に伝えておくべきことは 完璧な UI アーキテクチャーはない ということです。
銀の弾丸などない という格言があります。
ソフトウェア開発では、魔法のように問題を解決するような技術は存在しないことを示唆する言葉です。 これは UI アーキテクチャーでも同様です。
そのため、最後に出てきた UI アーキテクチャーでも決定版とはなりません。
問題がでてきて、新しいものが生まれるという繰り返しが今後も続いていくでしょう。 - See more at: http://yohshiy.blog.fc2.com/blog-entry-215.html#sthash.bVYTmi36.dpuf
...
誤解されたり、改良されたりで、 MVC は人によって解釈が様々になってしまっているのが現状です。
MVC が何を指しているのか、はっきり言って正解はわかりません。 - See more at: http://yohshiy.blog.fc2.com/blog-entry-215.html#sthash.bVYTmi36.dpuf

HMVC

最近つかっているfuelPHPはHMVC。

HMVC リクエストは、複数の場所で、ロジックの分離とコントローラロジックを再利用するための優れた方法です。 1つのよくある使用法は、テーマやテンプレートエンジンを使用してページを生成するときに、 各ページはセクションに分かれていて、セクションはウィジェットによって表示されます。 モジュールを使用してウィジェットの出力を生成する、高度にモジュール化され簡単にコンポーネントを再利用できるアプリケーションを作成できます。

日本語超俺訳で言うと「機能毎にMVC構造をモジュール分割(フォルダ分け)して階層化してしまえ+モジュールの中から別のモジュールを呼べるようにしてしまえ。」って事です。
ソースのモジュール化を推し進めることでHMVC…"Hierarchical Model View Controller"をガシガシ使えまっせ。

MV*

クライアント側フレームワークはMVC、MVVM、MVWなど複数の考え方が存在しているため、それらをまとめて「MV*」と表現

「MVC」と「MVC2」の違い

「MVC2」での「モデル」「ビュー」「コントローラ」の位置づけは「Smalltalk MVC」と
同等ですが、「MVC2」では「ビュー」と「モデル」がObserverパターンの関係ではありません。
そもそもWebアプリケーションなので、毎回HTTPリクエストを経由する必要があり、
Observerパターンなんて使えるわけがありません。
(Ajax使って似たような考え方を適用することはできるかもしれませんが)
「MVC2」はWebアプリケーションのサーバサイド処理をするうえで、「データ」と「UI」を分離する考え方。
ただそれだけなのです。
...
広義の「MVC」という言葉は、このシンプルな流れに当てはめてみると、
 ・「コントローラ」は「入力」を受け付け
 ・「モデル」はデータの「処理」を行い
 ・「ビュー」が見た目を整形して「出力」する
ということになりそうです。

MVCとデザインパターン

MVCは、デザインパターンの1種と扱われる場合もあるが(MVCパターンと呼称される)、MVC自体が他の小さなデザインパターン(Observer パターン・Command パターン・Factory Method パターン・Facade パターンなど)を利用して実装されることが多いところからすると、デザインパターンというより、さらに粒度の大きい1種のソフトウェアアーキテクチャという方が適当であろう[7][10]。

MVCアーキテクチャ以外にも選択肢はある

利用したいアーキテクチャは、私たちの目的に合致していれば多少の間に合わせでもよく、MVCは手始めにはとても優れたものだった。
...
Event-Drivenアーキテクチャ
Naked Objectsパターン
Pipelinesパターン
...
MVCやほかのパターンと一緒に、アプリケーションを密結合にしたいのか疎結合にしたいのか、そしてアプリケーションの中心で状態を持ちたいのか、関連コンポーネントの中にもったほうがいいかということと共に 検討されるべきだ

ディスパッチャ

URLディスパッチャとかプロセスディスパッチャというような種類がある。

ディスパッチャとは,実行可能状態にあるプロセス(タスク)の中から,次に実行するべきプロセスを選び,CPUを効率良く利用するためのプログラムを言います。

できればDispatcher自体は汎用的なクラスにしたいので、
Dispatcherは抽象クラス(抽象クラスの詳細はこちら)などにして、
振分けを行うswitchの部分だけ別メソッドとして抽象メソッド化し、
各システムではDispatcherを継承して振分けメソッドだけを実装するような形にすれば、汎用的といえます。

関数型

プログラミングパラダイムのあたりは深そうなのでひとまず保留。
でもPHPでもっと関数型プログラミングがしやすくなれば便利なのか。
そういうものでもないのかね。
オブジェクト指向プログラミングは現実の物質世界にイメージが似通っていて、
便利な面もあるけど限界があるよってことなのかどうなのか。

ここでの「関数」とは、数学でいう「関数」であり、手続き型プログラミングなどにおける「関数」ではないことをまず注意する。
典型的には原則としては副作用がないものであることが挙げられる。

読んでたら時間がいつのまにか過ぎていた。難しい。
たぶん理解についてはずっと保留かな。
関数型プログラミングについてはいつか考えたい。
ある程度学習して、js実装時に意識してみればいいかな。

構造体 + 関数型パラダイム = オブジェクト指向

おそらく定義はずれてるのかな。
なので、オブジェクト指向とそうでは無い関数型プログラミングとの比較ということだろうか。

ふたつのアプローチの比較
オブジェクト指向的アプローチは、名前をつけてプログラムを整理する。
関数型プログラミング的アプローチは、汎用部品でなんとかする。

保留メモ:純粋関数型言語、第一級関数(高階関数が扱える)、カリー化(部分適用)、型推論、参照透過、部分適用、遅延評価

特徴としては
変数は再代入禁止である
関数は参照透過性が保たれている(副作用がない)

ちまたには、関数型プログラミングの利点は変数が無いことだ、とか、より安全だから、とか、より速いから、などという妄言が満ち溢れています。
オブジェクト指向と関数型プログラミングは、水と油ではありません。プログラマは自分のプログラムに最適なアプローチを選ぶことができます。

PHP は、ファーストクラスの関数をサポートしている。 つまり、関数を変数に代入できるってことだ。 自分で定義した関数だろうがもともと組み込まれている関数だろうが、 変数で参照したり動的に実行したりできる。 何かの関数を別の関数の引数として渡すこともできるし、関数の返り値を別の関数にすることもできる(高階関数っていう機能)。
再帰 (ある関数の中から自分自身を呼ぶこと) も PHP の機能としてサポートしている。 しかし、たいていの PHP コードはそれよりも逐次処理を重視している。
新型の無名関数 (クロージャにも対応したもの) が使えるようになったのは、PHP 5.3 (2009 年) 以降だ。

「関数を追うのが大変」「慣れるまで分かりにくい」欠点はありますが、
「変数の値が変わらない」ことは、読みやすさ、書きやすさ、わかりやすさの全てに大きく関わる利点です。
PHPに限らず、他の言語でも意識してコーディングするとハッピーになれますよ!^^

インタープリンタ

一般的に使われるPHPの処理系はこのバイトコードインタプリタというもので、
一旦ソースコードを一通りパースしてシンタックスエラーの有無や関数定義などを確認してから
バイトコードを生成し、それをPHPの仮想マシンが逐次実行していくという形になっています。
PHPに限らずPythonやRuby1.9以降などこういう「中間コード生成 -> 仮想マシンで実行」という形式を取る処理系は割と多いです。

文法

なるほど、、どうもわたしはPHP5.3くらいで頭が止まっているらしい。便利になってるのね。
0bではじまるバイナリ数値は2進数なのね。

"array" 関数の代わりに角括弧で配列を宣言できるようになった。多少簡潔になったが,それだけのものだ。
配列の間接参照を関数の戻り値として使用できるようになった。これまでは最初にテンポラリ変数に設定する必要があった: $FirstName = GetNames()[0]
PHP 5.4 のクロージャでは,従来は許されていなかった "$this" ポインタが使用できるようになった。
インスタンス生成からのクラスメンバへのアクセスが可能になった:(new CustomerService)->Delete(customerId)
"0b" プレフィックスを使用するバイナリ数値。

リフレクション

・ReflectionClassはクラスについての情報を報告する役割を持っています。
・インスタンスも作れる。

ここまでの所感

順不同で適当に調べていったのですこしわかりにくいけど覚書としては機能するか。。
まだ全然深掘りするべき所はあるので気が向いたら見直そう。

10
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
11