PHP5上級試験/準上級試験の上級合格に挑戦(19) プログラミングPHP第3版 12章~13章

# １２章　セキュリティ

## 12.2.1 SQLインジェクション
SQLインジェクションはバインド変数を使うことで防げる
バインド変数に格納されたものは確実にデータとして扱われるためエスケープが不要になる

```index.php
$sql = $db->prepare("SELECT count(*) FROM users
  WHERE username = :username AND password = :hash");
$sql->bindParam(":username", $clean['username'], PDO::PARAM_STRING, 32);
$sql->bindParam(":hash", hash($_POST['password']), PDO::PARAM_STRING, 32);

```

# 12.3 出力のエスケープ

PHPアプリケーションからのデータ送信先でよく使われるのは

+ HTTPクライアント（Webブラウザ）　→エスケープ関数はhtmlentities()
+ DB →DBの専用エスケープ関数がある

Ex) 
 MySQL → mysql_real_escape_string()
 MySQLi → mysqli_real_escape_string()
 PostgreSQL →　pg_escape_string()
 PDO →　PDO::quote()

```index.php
<a href="http://host/script.php?var={$value}">ここをクリック</a>
```

DBの場合他にもDB抽象化ライブラリでエスケープする方法もある

# 12.3.1 ファイル名

フォームのフィールドでユーザ名を記入させると考える時、
これがパスだった場合思わぬスクリプトを実行させてしまう。

また、PHPはデフォルトでリモートのファイルをオープンできる
→パラメータでファイル名を指定させてはいけない

または

+ リモートファイルへのアクセス禁止
+ realpath()とbasename()でファイル名をチェック
+ open_basedirオプションでドキュメントルート以外からのファイルシステムへのアクセス制限

# 12.3.1.1 相対パスのチェック

+ `realpath()` ->.や..などの特殊文字を展開する、つまりフルパスが得られる
+ `basename()` ->パスからファイル名を返す

basename(realpath($filename))として、入力されたユーザ名（ファイル名）と一致するか確かめる、という方法が取れる。

# 12.6.5 PHPライブラリを隠す

ドキュメントルートにおく必要がある場合は、 ウェブサーバーの設定でアクセス制限

```index.php
<Files ~ "\.inc$">
  Order allo,deny
  Deny from all
</Files>
```
ページを作成するPHPスクリプトとは別の場所にコードライブラリを置く場合、ライブラリの場所をPHPに教えないといけない。
include()やrequire()でパスまで含めて指定したり、
php.iniのinclude_pathを以下のように変更

```php.ini

include_path = ".:/usr/local/php:/usr/local/lib/myapp";

```

# 12.10 まとめ

+ 入力のフィルタリングはできるだけ厳しく
+ 出力時は背景に応じたエスケープを行い、出力先がデータを誤解しないようにする
+ 変数は常に初期化
+ `register_globals`,`magic_quotes_gpc`,`allow_url_fopen`は全て無効に
+ ファイル名を作成したら`basename()`と`realpath()`で確認。（ユーザ入力をもとにするものも含む）
+ ライブラリファイルはドキュメントルート以外のところへ。.incというファイル名も避け、.phpかまたは別の分かりづらい拡張子にする
+ ユーザ権限が変わった`session_regenerate_id（）`をコール
+ ファイル作成してからパーミッション変更ではなく、`umask()`を設定、指定したパーミッションでファイル作成
+ ユーザからの入力は`eval()`や`preg_replace`(\eオプションを使う場合）、システムコマンド、バックティック演算子（``）では使わない

※システムコマンド・・・`system()`、`exec()`、`passthru()`、`popen()`、`shell_exec()`、`proc_open()`など

# １３章　アプリケーションに関するテクニック

## 13.2 テンプレートシステム

たとえば、「user.template」という名前でHTML文書を作成
→｛NAME}などで、PHPスクリプトからの結果を埋め込むことができる
phpスクリプトから、そのマーカーを置き換えるなどしてHTML文書を完成させる
という方法が取れる

## 13.5.1 ベンチマーク

ベンチマークユーティリティabをつかって高度なパフォーマンステストが可能

```index.php
$ /usr/local/apache/bin/ab -c 10 -n 1000 http://localhost/info.php
```

## 13.5.2 プロファイリング

コードの処理速度なら、`microtime()` を使う、マクロでいうTimer()の差を調べるのと同じ方法で可能

他にもPEAR::Benchmarkクラスを使ってもコードの一部を繰り返し実行して所要時間を計測するということもできる

## 13.5.5.1 リバースプロキシキャッシュ

特定のサーバへの接続を必ず経由させるもので、ブラウザとサーバの間に設置する。
通常のプロキシは内部ネットワークから外部インターネットへのアクセスの間に置くのに対して、
外部インターネットから内部ネットワークへのアクセスの間に置くためリバースプロキシと呼ばれている

プロキシのキャッシュは、ブラウザの種類や言語設定などに合わせて個別にもたせることも可能
→Varyヘッダをつかうことで、どのリクエストパラメータがキャッシュに影響を与えるのかを指摘できる

このプロキシキャッシュはハードウェアで実現できるものもあるが、ソフトウェアだと、オープンソースのSquidが有名。

## 13.5.5.2 ロードバランシングとリダイレクト

処理分散システム＝ロードバランシングシステムという
すべてのマシンに均等に処理を分けるシステムもあれば、負荷の少ないマシンに振り分けるシステムもあり、それはリダイレクタでURLを書き換えることで、綿密な処理の振り分けが可能になる
これらはソフトウェアでも、SquidにSquidGuardなどを使ってリダイレクト機能を追加すれば可能

## 13.5.5.4 全部まとめて使う

これらの考えとレプリケーションの考えを全部まとめると、
ソフトウェアであるSquidキャッシュリダイレクタに、MySqlスレーブ３台、それらにつながっているマスタMySQLサーバーというのが考えられる。
この方法が考えられるうえで一番最適。

ちなみに３台のMySQLサーバーは、全部読み込み専用で、ローカルのUnixドメインソケットを使ってそこにアクセスする。
書き込みは、TCPソケットで、マスタサーバーに対して行う。