リクエスト情報:クライアントからサーバに送信される情報
サーバとクライアントがお互いに通信する際に利用するプロトコルのこと
HTTP通信の構成
分類 | 項目 | 概要 |
HTTPリクエスト | HTTPメッソド | サーバに対する直接の要求と取得するパス |
リクエストヘッダ | リクエストの構成情報、クライアント情報etc | |
リクエスト本体 | フォームから送信されたデータ | |
レスポンス | HTTPステータス | サーバーでの処理結果を表すメッセージ |
レスポンスヘッダ | コンテンツの構成情報、サーバー情報etc | |
レスポンス本体 | コンテンツ本体 |
HTTPステータス
分類 | HTTPステータス | 意味 |
100(情報) | 100(Continue) | 継続可能 |
200(成功) | 200(OK) | 成功 |
201(Created) | 成功(サーバー側に新しいリソースを生成) | |
202(Accepted) | 受付完了(未処理) | |
300(リダイレクト) | 301(Moved Permanently) | リソースが恒久的に移動した |
302(Moved Temporarily) | リソースが一時的に移動した | |
303(See Other) | リソースが別の場所に存在する | |
304(Not Modified) | リソースが変更されてない | |
400(クライアントエラー) | 400(Bad Request) | 不正なリクエスト |
401(Unauthorized) | HTTP認証要求 | |
403(Forbidden) | アクセスを拒否 | |
404(Not Found) | リソースが見つからない | |
405(Method Not Allowed) | HTTPメソッドが不許可 | |
407(Proxy Authentication Required) | プロキシで認証の必要がある | |
408(Request Time-out) | リクエストタイムアウト | |
500(サーバーエラー) | 500(Internal Server Error) | サーバエラー |
501(Not Implemented) | 応答に必要な機能が未実装 | |
503(Service Unavailable) | HTTPサーバが利用不可 |
リクエスト情報を取得/操作するための変数
必要なリクエスト情報はPHP側で自動的に解析し、用意するので、
スクリプト側ではこれを参照するだけでよい。
ポストデータとは、
「method="POST"」で定義されたHTMLフォームから送信されるデータのこと。
クライアントから送信されたポストデータを取得するのが、$_POSTの役割。
これは連想配列で、各要素にアクセスするには$_POST['要素名']というように記述する
ユーザーから入力された値やDB/外部サービスなどから取得した値を表示する場合には、
HTMLエスケープを行う必要がある。
文字列に含まれる「<」「>」「&」「"」などの文字列を、
「<」「>」「&」「"」の文字に置き換える処理のことを言う。
これを行うことによって、たとえば「<」はタグの始まりを意味するのではなく、
本来の「<」という記号として認識するため、サイトクロススクリプティング(XXS)対策になる。
エスケープを行うには以下の関数を使う
string htmlspecialchars(string $str [, int $style = ENT_COMPAT [, string $char]]) $strをエスケープする。 原則として、$style = ENT_QUOTES と指定するのが一般的。 なお関数名が長く、利用頻度も高いので、ユーザー定義関数として、 短い名前に直しておく方がよい
クエリ情報とは、
URLの末尾「?」以降に「キー名=値」のセットで付加される簡単な情報。
URLのパス本体とクエリ情報は「?」で区切られ、複数のキーがある場合は「&」で連結される。
URLに直接指定するほか、フォームタグにGETオプションを指定する方法がある。
※ただし、パス本体とクエリ情報の区切り文字である「?」や「&」、「%」、
空白文字やマルチバイト文字をクエリ文字に含める場合は予めURLエンコードをしておく必要がある。
string urlencode (string $str) 文字列を URL エンコードする
クエリ情報はデータをURLに載せて送信しているのに対し、
ポストデータはリクエストボディと呼ばれるブロックに格納してデータのやり取りを行う。
ポストデータはサイズが事実上無制限であるのに対して、 クエリ情報はURLにデータを載せているため、ブラウザやサーバ環境の制限を受ける
セキュリティ上よくない。
ただし、だからといって「データを保護すること」が目的でポストデータを使うのは誤り。
データを保護するならば「SSL(Secure Socket Layer)」のような暗号化通信をする必要がある。
普段我々が目にしない不可視な情報
(例えば、ブラウザの種類や対応する言語、リンク元のページ etc)などの様々な情報が
内部的に生成されてサーバーに送信されている。
こういった情報のことをヘッダ情報という。
種類 | ヘッダ名 | 概要 |
一般ヘッダ | Cache-Control | キャッシュルールを規定する |
Connection | プロキシサーバで削除すべきHTTPヘッダを指定 | |
Date | コンテンツを生成した日時 | |
Progma | キャッシングを利用するか | |
Transfer-Encoding | コンテンツの転送エンコーディング方式 | |
リクエスト | Accept | クライアントがサポートしているコンテンツ |
Accept-Language | クライアントが対応している言語 | |
Authorization | 認証情報 | |
Cookie | クライアントに保存されたクッキ− | |
Host | 要求先のホスト名 | |
Proxy-Authorization | プロキシサーバ用認証情報 | |
Range | 要求するリソース | |
Referer | リンク元のURL | |
User-Agent | クライアントの種類 | |
レスポンス | ETag | リソースを一意に特定するためのキー |
Location | クライアントに新しいURIに移動するように促す | |
Server | クライアントにクッキーを送信 | |
エンティティ | Content-Encoding | コンテンツエンコーディング |
Content-Length | コンテンツのサイズ | |
Content-Type | コンテンツの種類 | |
Expires | コンテンツの有効期限 | |
Last-Modified | コンテンツの最終更新年月 |
上記のヘッダ情報を扱うには、
以下の$_SERVER経由でアクセスできるサーバ変数を使う
ヘッダ情報は
「クライアントからサーバに送られるリクエストヘッダ」
「サーバからクライアントに送られるレスポンスヘッダ」に大別できる。
PHPスクリプトからレスポンスヘッダを操作することも可能
リダイレクトを行うには、以下の関数を使う
void header(string $head [, bool $rep = TRUE [, int $code]]) 生の HTTP ヘッダを送信する header()関数は、 通常のHTMLタグまたはPHPからの出力にかかわらず、すべての実際の出力の前にコールする必要がある
上記の関数の「$head」部分にURLを書く
※実際に裏で行われていること
1. header関数が書かれたページが、サーバに要求される
↓
2. サーバがページを処理して、Locationヘッダを発行し、クライアントに情報を返す
↓
3. クライアントからLocationヘッダに書かれたURLにアクセスしようとして、再びサーバに自動要求
↓
4. 結果ページへアクセス
リダイレクトは一つのリクエスト処理に見えるが、
HTTPの観点では「2回リクエスト」が自動で行われている
header関数の「$head」部分に「ページの有効期限」をかく(Expires〜)
header関数の「$head」部分でContent-typeを指定する
サーバ側で設定されている環境変数を取得するためのスーパーグローバル変数
環境変数とは、コンピュータ上に予め定義されたパラメータのことで、
プログラムを実行する際に参照するパスやオプション値などを設定する
Cookieとは、クライアント側に保存可能な小さなテキストのこと。
HTTPはクライアントからの要求に対してサーバがレスポンスを返して終わりだった。
これをHTTPは「ステートレス(状態を保存できない)」なプロトコル。
しかし、Cookieを利用することで「クライアント単位で維持したい情報」の管理が容易になる。
Cookieに値を保存するには以下の関数を使う
bool setcookie(string $name [, string $valu [, int $expire = 0 [, string $path [, string $domain [, bool $secure = FALSE [, bool $httponly = FALSE]]]]]]) $nameにはCookieの名前、$valueにはCookieにセットする値 他にも有効なドメインやパス、SSLの通信要求などがある
第7引数に関してをTRUEにすることによって、HTTPCookeiが有効になり、
HTTP経由でのみアクセス可能となる。
JavaScript?経由ではアクセスできない。
先のCookeiには以下のような問題点がある
上記の理由から、セッションというCookieよりもよりセキュアな手段を利用する。
セッションを利用するには、下記の関数を最初に呼び出す必要がある
bool session_start()
セッションはCookeiでセッションIDを管理して、そのセッションIDをクラインとに発行する。
そのためサーバ側でデータが保存されるので、ネットワーク上に実データが流れないため
Cookeiを単体で使うよりも安全である。
セッションはCookeiよりも安全にデータを保存できるが、
その反面サーバに負担をかけやすいという問題もある。
そのため不要になったセッションは迅速に、確実に破棄する必要がある。
これはサーバへ負担の面だけではなく、セキュリティの関係からも重要。
以下、セッションの破棄の方法
// セッション変数を全て解除する $_SESSION = array(); // セッションを切断するにはセッションクッキーも削除する。 // Note: セッション情報だけでなくセッションを破壊する。 if (isset($_COOKIE[session_name()])) { setcookie(session_name(), '', time()-42000, '/'); } // 最終的に、セッションを破壊する session_destroy();
また、必ずしも上の動作を実行できるとは限らない。
例. エンドユーザーが勝手にブラウザを閉じてアプリケーションを終了
この場合は、サーバ側にセッション情報が残ったままだが、
これは永久に残るわけではなく、セッションの有効期限が過ぎれば自然と消滅する。
なお、セッションの有効期限はphp.iniで設定可能。
$_FILESはアップロードしたファイルに関する情報を取得するためのスーパーグローバル変数。
formタグにenctyoe="multipart/form-data"を指定してファイルのアップ用formを作成。
いろいろごにょごにょした後に、
move_uploaded_fileでアップロード中の一時フォルダから、
本来の保存先にファイルを移動すればok!
1つの情報を1枚のカードとして扱う
関連するデータ同士が網状に繋がっている
よく使われている、皆さんが想像しやすいもの。 表みたいな感じのDB
オブジェクトの形式で表現されるデータを格納するデータベース
キー/値のセットでデータを管理 複雑な検索は不向きだが、スケーラビリティに優れ、クラウド環境で使用されることが多い 有名どころでは「Tokyo Tyrant」とか
※大まかなDB関係、SQL関係は今回カット
以下、PHPとの連携について
さまざまな種類のDBごとの違いを吸収して、アプリケーションがDBにアクセスする際の
手段を共通化するもの
代表的なDB抽象レイヤ
PEAR::DB、PEAR::MDB/MDB2、PEAR::DB_Objects、PDO、Zend_Db、dbx
以下、シンプルな構文仕様で処理速度の速い、PDO(PHP Data Objects)を使用する。
なお、PDOはコアモジュールとドライバに分けられ、
そのドライバを変えることでいろいろなDBにアクセス可能になる
PDOの場合、DBとの接続を管理するのはPDOクラスの役割。
まずはPDOクラスをインスタンス化させる
new PDO(string $dns [, string $user [, string $password [, array $option]]]) $dsn:データベース接続文字列 $user:接続ユーザ名 $password:接続時のパスワード $option:接続オプション(オプション名=>設定値)
例. サンプル2
また、DB接続時の挙動を決めるパラメータのことを接続オプションと言い、
PDOクラスをインスタンス化する場合に連想配列「オプション名=>設定値」の形で指定するか、
以下のsetAttributeメソッドを使って個別に設定する
bool PDO::setAttribute(int $attr, mixed $value) $attr:オプション名 $value:設定値
※ドライバ固有のオプションもあるので、あまり積極的な使用は進められない
PDOクラスは何かしらの理由で接続できなかった場合、PDOクラスはPDOException例外を投げる。
このような例外が発生したときに行う処理を例外処理といい、
例外処理を行う場合にはtry〜catch命令を使う
try { // 例外が発生するコード } catch(発生するかもしれない例外の種類 例外を受け取る変数名) { // 例外発生処理 }
例外が発生すると、エラーなどが起こってスクリプトが終了してしまうことがあるが、
この命令を使えば、catchブロックに引き継がれるので処理を継続できる
なお、例外はクラスの一種で、
catchブロックに渡された変数を介して例外に関するさまざまな情報にアクセスできる。
以下、利用可能なメッソド
メソッド | 概要 |
getMessage() | 例外メッセージ |
getCode() | 例外コード |
getFile() | 例外が発生したファイル名 |
getLine() | 例外が発生した行数 |
getTrace() | バックトレース(配列) |
getTraceAsString?() | バックとレース(文字列) |
なお、例外クラスについては、次週もう一度やる
例.
$db = new PDO(〜); //DBと接続確立 $stt = $db->prepare('INSERT INTO book (title, author) VALUES (:title, :author)'); $stt->bindValue(:title, $title); $stt->bindValue(:author, $author); $stt->execute();
PDOを使ってSQLを発行する時は、PDOStatementオブジェクトを使う
PDOStatementオブジェクトは、PDOオブジェクト$dbからprepareメソッドを呼び出すことで取得できる
prepaerメッソド PDO::prepare(string $statement [, array $options]) $statement:発行するSQL $options:接続オプション
また、SQLに動的にパラメータを入れる場合には、
SQLにプレイスホルダと呼ばれるパラメータを置く場所をつくり、
以下のbindValueメッソドでプレイスホルダに具体的な値をセットしていく
bindValueメソッド bool PDO::bindValue(mixed $param, mixed $value [, int $type = PDO::PARAM_STR]) $param:パラメータ名 $value:パラメータ値 $type:データ型
なお、このプレイスホルダはSQL中ですべて?にしてもよく、
bindValueメッソドパラメータ名には、SQLで現れた順番の数字を入れていく
これを名前なしパラメータという
しかし、この方法はシンプルに記述できるものの、パラメータと値の関係わかりにくいため、
多用すべきではない
このあと、executeメッソドによって、DBに命令が送信される
上記のようなパラメータが必要でないSQL(固定的なSQL)の場合には queryメソッドを使用することができる。
queryメソッドの引数の中にSQLを書けばよい
例. サンプル3
lastInsertIdメッソド string PDO::lastInsertId([string $name]) $name:シーケンス名
シーケンス名:DBで一意な数値キーを生成するために利用しする
PostgreSQLやOracleのようなDBで利用する
結果セット:SQLのSELECTによりテーブルから取り出された、
レコードを保持するためにメモリ上に用意された仮想テーブルのこと
この結果セットを取得するのが、prepare/executeメソッドの役割
executeメソッドは、取得した結果セットを自分自身にセットする。
この結果セットを読み込んでいく場合には、レコードごとに読み込んでいく必要があり、
現在読み込み可能なレコードを表す内部的な目印のことをレコードポインタといい、
レコードポインタが表す現在のレコードのことをカレントレコードという
executeメソッドによって結果セットが生成されたタイミングではレコードポインタは「先頭の行の直前」をさしている
PDOStatementのfetchメソッドはレコードポインタを次のポインタに移動しながら、~カレントレコードに含まれるフィードを読み込むメソッドで、
次のレコードに移動できない場合(次のレコードがない場合)、featchメソッドはFALSEを返す。
その性質を利用して、featchメソッドがFALSEを返すまでwhileループを繰り返すことで、
結果セット内の全てのレコードを取得する。
fetchメソッド mixed PDO::fetch([int $style = PDO**FETCH_BOTH]) $style:フェッチモード
定数 | 取得形式 | 取得値 |
PDO::FETCH_ASSOC | 連想配列 | $row['name'] |
PDO::FETCH_NUM | 一般配列 | $row[0] |
PDO::FETCH_BOTH | 一般配列/連想配列 | row['name'] |
PDO::FETCH_NAMED | 連想配列 | $row['name'] |
PDO::FETCH_OBJ | オブジェクト | $row->name |
PDO::FETCH_COLUMN | スカラー値 | $row |
PDO::FETCH_BOUND | bindColumnメソッドでバインドされたPHP変数 | $name |
PDO::FETCH_CLASS | 指定されたクラスにフェッチ | $row->name |
また、フェッチメソッドにはいろいろ種類があるので、それらを使い分ける
fetchAllメソッド mixed PDO::fetchAll([int $style = PDO::FETCH_BOTH]) $style:フェッチモード 結果セットの内容をまとめて配列に変換できる
fetchColumnメソッド mixed PDO::fetchColumn([int $column = 0]) $column:取得するインデックス番号 結果セットの指定の列のみ取得する
fetchObjectメソッド mixed PDO::fetchObject([string $class [, array $args]]) $class:フェッチ先となるクラス名 $args:クラスをインスタンス化する際に引き渡すパラメータ
PDOにはパラメータをバインドするメソッドには以下の2種類があり、
それぞれ以下のように使い分ける。
bindParamメソッド bool PDO::bindParam(mixed $param, mixed &$value [, int $type [, int $len]]) $param:パラメータ名 $value:パラメータ値 $type:データ型 $len:データ長
関連する複数の処理をグループ化したもの。
グループ化した処理に関しては、
このグループ化した複数の処理を実行することを「トランザクション処理」といい、
トランザクション処理を確定することを「コミット」という。
また、トランザクション処理は「すべて成功」か「すべて失敗」かであることを保証するたまの処理であり、
トランザクション処理中のどこかで失敗が起きると、全ての処理を元に戻す。
これを「ロールバック」という。
PDOにおいてトランザクション処理を行うには、
beginTransactionメソッドとcommitメソッドとの間にトランザクション処理を入れる。
また、ロールバックを行うにはrollBackメソッドを使う
beginTransactionメソッド bool PDO::beginTransaction(void) オートコミットモードをオフにする。 オートコミットモードがオフの間、PDOオブジェクトを通じてデータベースに加えた変更は、PDO::commit()をコールするまでコミットされない。 PDO::rollback()をコールすると、データベースへの全ての変更をロールバックし、 オートコミットモードに設定された接続を返す。 MySQLを含むいくつかのDBでは、「DROP TABLE」や「CREATE TABLE」のようなDB定義言語 (DDL)ステートメントがトランザクション中に発行される場合、 暗黙的なコミットが自動的に発行される。 この暗黙的なコミットにより、そのトランザクション境界で他のあらゆる変更をロールバックすることができなくなる。
参考資料