PHP5上級試験/準上級試験の上級合格に挑戦(16) プログラミングPHP第3版 7章〜8章

# 7章　Webに関するテクニック

## 7.1 HTTPの基本（リクエスト・レスポンス）
下記はHTTPのリクエスト・レスポンスのまとめをしている

### HTTPリクエスト
Webページをリクエストする際にブラウザからWebサーバーに送られる 
ヘッダは絶対あるが、通常は本文も含まれる
オプションのヘッダ情報が含まれる場合がある

```index.php
GET /index.html HTTP/1.1  //　必須。　HTTPコマンドのメソッド、使うページ、HTTPプロトコルのバージョン
User-Agent: Mozilla/5.0 (Windows 2000; U)Opera 6.0 [en] //ウェブブラウザ情報
Accept: image/gif, image/jpeg,text/*, */*　//MIME（ファイルのタイプ）の種類を指定
　//何も含まれない空行がある。これが終了の証
```

### HTTPレスポンス
リクエストに対するWebサーバーからブラウザに返されるレスポンス

```index.php
HTTP/1.1 200 OK //プロトコルバージョン・ステータスコード　２００はOK
Date: Thu, 31 May 2012 14:07:50 GMT //日付
Server: Apache/2.2.14 (Ubuntu) //Webサーバのソフトウェアの情報
Content-Type: text/html　//レスポンスに含まれるデータのMIMEタイプ
Content-Length: 1845　// 渡されるデータの大きさ
```
# 8章　データベース

SQLは大きく分けてDMLとDDLがある
DML...Data Manipulation Language（＝データ操作言語）で、SELECT,INSERT,UPDATE,DELETEの４つ
DDL...Data Definition Language(=データ定義言語）。DML以外がこちらになる

## MySQLiオブジェクトインターフェース

MySQLのバージョンはいくつかあり、自由配布できる「Community server」（DBの一種）もその一つ
PHPからこのDBを利用するインターフェースはいくつかあり、
オブジェクト指向のインターフェースとしては「MySQLi(MySQL Improved)」拡張モジュールがある
これはPHPの標準インストールに含まれている

これは書籍データを登録した例

```index.php
$db = new mysqli(host,user,password,databaseName);

//例）petermacというユーザーとパスワードが1q2w3e9i8u7yのlibraryというテーブルにログイン
$db = new mysqli(localhost,petermac,1q2w3e9i8u7y,"library");
//新しい書籍データを挿入
$sql = "INSERT INTO books (authorid, title, ISBN, pub_year, available) 
   VALUES (4, 'I, Robot', '0-553-29438-5', 1950, 1)";
if ($db->query($sql) {
    echo "書籍データを保存しました";
} else {
    echo "追加に失敗しました。もう一度やり直すがか、サポートに問い合わせてください";
}
db->close;
```

これは検索されたタイトルに基づいてデータ検索した例

```index.php
$db = new mysqli(host,user,password,databaseName);

//例）petermacというユーザーとパスワードが1q2w3e9i8u7yのlibraryというテーブルにログイン
$db = new mysqli(localhost,petermac,1q2w3e9i8u7y,"library");
//データ検索
$sql = "SELECT a.name, b.title FROM books b, authors a WHERE a.authorid=b.authorid";
$result = $db->query($sql);
while ($row = $result->fetch_assoc() {
  echo "{$row['title']}の著者は{$row['name']}です<br />";
}
$result->close();
db->close;
```
MySQLiで最も便利なメソッドはmulti_queryで、複数のSQLコマンドを１つの文で実行できる
たとえば新しいデータをINSERTし、それを使ったUPDATE文を実行するなどができる

参考：http://www.php.net/mysqli

他のを調べたければ上記を。

## SQLite

軽量なDBでMySQLiと同じくデフォルトで使用可能。
データをファイルベースで格納するのが特徴
→DBのサイズを抑えたい時や、PHP以外の製品に依存したくない時などに重宝

※PHP５．３の時点ではextension=php_sqlite3.dllに対応するファイルが含まれていないため
 extension=php_sqlite.dllという記述が必要


```index.php
//インスタンス作成。その場所にファイルがなくても新規作成してくれる
$db = new SQLiteDatabase("c:/copy/library.sqlite);

//authorsテーブル作成
$sql = "CREATE TABLE 'authors' ('autohorid' INTEGER PRIMARY KEY, 'name' TEXT)";

if (!$database->queryExec($sql,$error)){
  echo "作成に失敗 - {$error}<br />";
} else {
  echo "Authorsテーブルを作成しました<br /> ";
}
//データ追加
$sql = <<<SQL
INSERT INTO 'authors' ('name') VALUES ('J.R.R. トールキン');
INSERT INTO 'authors' ('name') VALUES ('アレックス・ヘイリー');
INSERT INTO 'authors' ('name') VALUES ('トム・クランシー');
INSERT INTO 'authors' ('name') VALUES ('アイザック・アシモフ');
SQL;

if (!$database->queryExec($sql, $error)){
  echo "追加に失敗 - {$error}<br />";
} else {
  echo "AuthorsへのINSERT - OK<br />";
}

```
データ型もMySQLとは違う
Text（テキスト型）/Numeric(整数または実数)/Integer（整数値のみ）/Real（浮動小数点のみ）/None（なんでも）

※TextはNULLなど。数値を渡すとテキスト変換してから格納
※Numericは文字列を渡すと数値に変換しようとする
※IntegerやRealは実際の形式と違う数値をもらってもすべて整数値や浮動小数点に変換する。
※Noneはデータをそのまま格納する（何もしないということ）

下はbooksテーブルを作りデータを作成する例

```index.php
//インスタンス作成。その場所にファイルがなくても新規作成してくれる
$db = new SQLiteDatabase("c:/copy/library.sqlite);
$sql = "CREATE TABLE 'books' ('bookid' INTEGER PRIMARY KEY,
   'authorid' INTEGER,
   'title' TEXT,
   'ISBN'  TEXT,
   'pub_year' INTEGER,
   'available' INTEGER)";


if (!$database->queryExec($sql,$error)){
  echo "作成に失敗 - {$error}<br />";
} else {
  echo "Booksテーブルを作成しました<br /> ";
}
//データ追加
$sql = <<<SQL
INSERT INTO 'books' ('authorid', 'title', 'ISBN', 'pub_year', 'available') 
VALUES (1,'二つの塔', '0-261-10236-2, 1954, 1);

INSERT INTO 'books' ('authorid', 'title', 'ISBN', 'pub_year', 'available') 
VALUES (1,'王の帰還', '0-261-10237-0, 1955, 1);

INSERT INTO 'books' ('authorid', 'title', 'ISBN', 'pub_year', 'available') 
VALUES (1,'ルーツ', '0-440 17464-3, 1974, 1);
SQL;

if (!$database->queryExec($sql, $error)){
  echo "追加に失敗 - {$error}<br />";
} else {
  echo "BooksへのINSERT - OK<br />";
}
```
上記は前のところと後ろのところでSQLを書いて、複数のSQLコマンドを同時に実行している
MySQLiではmulti_queryメソッドを使う必要があったが、
この場合だと、query_execだけでできる。

リソースの消費が少なければいったんSQLiteを使用したいところ。
なお、DBが変わる可能性がある場合はPDOを使用しておくと、SQLiteからMySQLに変えるなども可能。

```index.php
//インスタンス作成。その場所にファイルがなくても新規作成してくれる
$db = new SQLiteDatabase("c:/copy/library.sqlite);
$sql = "SELECT a.name, b.title FROM books b, authors a WHERE a.authorid=b, authorid";
$result = $db->query($sql);
while ($row = $result->fetch(){
  echo "{$row['b.title']}の著者は{$row['a.name']}です<br />";
}

```

# 8.5 ファイルレベルの直接操作

PHP+MySQLをしたくないときはテキストファイルでデータを管理するという手がある

以下の処理を行うファイル操作関数名を答えよ。

(1)　サーバー上にディレクトリを作る
(2)　指定したファイル・ディレクトリがあるかどうか調べる
(3)  既存のファイルを読み込み用または書き込み用で開く
(4) ファイルの内容を変数に読み込み、PHPから使えるようにする
(5) ファイルへの書き込み用に排他ロックを確保する
(6) 変数の内容をファイルに書き出す
(7) ファイルの読み込みの時、一度に読み込むバイト数を指定
(8) 使い終えたファイルを閉じる

　
　
　
　
　
　

解答
(1)　mkdir()
(2)　file_exists()
(3)  fopen()
(4)  fread()
(5)  flock()
(6)  fwrite()
(7)  filesize()
(8)  fclose()

要するにこれらの関数を知っていれば、ファイルを開き、そこにデータを入れて、保存するということを繰り返せるということ。アンケートも次のページに行くにはリダイレクトで対応すればOK

# 8.6 MongoDB
NoSQL（つまり非リレーション）型のデータベース
MongoDBではテーブルはコレクションといい、
行はドキュメントになる。でも配列といったほうが適切

まずは何よりも実践

テーブルにデータを４行分入力する場面

```index.php
$mongo = new Mongo(); //接続
$db = $mongo->library; //コレクション（つまりテーブル）。ない時は自動で作成される
$authors = $db->authors; //インターフェース作成

//これらの１行目は行（ドキュメント）の作成、2つめはlibraryへのデータ追加
$author = array('authorid' => 1, 'name' => "J.R.R.Tolkien");
$authors->insert($author);
//これらの１行目は行（ドキュメント）の作成、2つめはlibraryへのデータ追加
$author = array('authorid' => 2, 'name' => "Alex Haley");
$authors->insert($author);

//これらの１行目は行（ドキュメント）の作成、2つめはlibraryへのデータ追加。すでに値があった場合はそれを更新する。また既存idも更新。
$author = array('authorid' => 3, 'name' => "Tom Clancy");
$authors->save($author);

$author = array('authorid' => 4, 'name' => "Isaac Asimov");
$authors->save($author);
```

次にテーブルからデータを取得する場面

```index.php
$mongo = new Mongo(); //接続
$db = $mongo->library; //コレクション（つまりテーブル）。ない時は自動で作成される
$authors = $db->authors; //インターフェース作成

//authoridが４の名前を出力
$data = $authors->findone(array('authorid' => 4));

echo "Generated Primary Key: {$data['_id']}<br/>";
echo "Author name: {$data['name']}";
```
出力
Isaac Asimov


何冊かの本をドキュメントに追加し、それを特定の著者と関連付ける。
この場合、DB内に複数のテーブルがあるという例えは難しくなる。

下のupdate()関数は最初の引数は検索用の一意な識別子、つまり'name'...のところ
次の引数は定義済の演算子＄setを使い、最初の引数、つまりnameで指定した著者に書籍のデータを
セットする。つまり下の４冊の本は全部Issac Asimovが書いたというふうに関連付ける。

```index.php
$mongo = new Mongo(); //接続
$db = $mongo->library; //コレクション（つまりテーブル）。ない時は自動で作成される
$authors = $db->authors; //インターフェース作成

$authors->update(
  array('name' => "Isaac Asimov"),
  array('$set' =>
    array('books' =>
      array(
        "0-425-17034-9" => "Foundation",
        "0-261-10236-2" => "I, Robot",
        "0-440-17464-3" => "Second Foundation",
        "0-425-13354-0" => "Pebble In The Sky"
       )
    )
  )
);

```

次は、Issac Asimovを検索し、その結果を関連付けに使う方法。
ちなみに結果は上記と同じになる。

```index.php
$mongo = new Mongo(); //接続
$db = $mongo->library; //コレクション（つまりテーブル）。ない時は自動で作成される
$authors = $db->authors; //インターフェース作成

//authoridが４の名前を出力
$data = $authors->findone(array('name' => "Issac Asimov"));

$bookData = array(
    array(
        'ISBN' => "0-553-29337-0",
        'title' => "Foundation",
        'pub_year' => 1951,
        'available' => 1),
    array(
        'ISBN' => "0-553-29338-5",
        'title' => "I, Robot",
        'pub_year' => 1950,
        'available' => 1),
    array(
        'ISBN' => "0-517-546671",
        'title' => "Exploring the Earth and The Cosmos",
        'pub_year' => 1982,
        'available' => 1),
    array(
        'ISBN' => "0-553-29336-1",
        'title' => "Second Foundation",
        'pub_year' => 1953,
        'available' => 1)
   );


$authors->update(
  array('_id=> $data['_id']),
    array('$set' => array('books' => $bookData)
  )
);

```

さて、上記の例で、例の著者の本の検索をする。

```index.php
$mongo = new Mongo(); //接続
$db = $mongo->library; //コレクション（つまりテーブル）。ない時は自動で作成される
$authors = $db->authors; //インターフェース作成

//authoridが４の名前を出力
$data = $authors->findone(array('authorid' => 4));

echo "Generated Primary Key: {$data['_id']}<br/>";
echo "Author name: {$data['name']}<br>";
echo "2nd Book Info -ISBN: {$data['books'][1]['ISBN']}<br>";
echo "2nd Book Info -Title: {$data['books'][1]['title']}<br>";

```
出力
Generated Primary Key: 4ff43ef45b9e7d300c0000007
Author name: Issac Asimov
2nd Book Info -ISBN: 0-553-29338-5
2nd Book Info -Title: I, Robot

となる。

MongoDBの使い方
http://php.net/manual/ja/book.mongo.php