PDO
              PDO(プリペアドステートメント)を使用してデータベースにアクセスするのは、結構安全らしい。
              
…ということで、まとめてみる。
              
※PCでの閲覧推奨。スマホは変なとこで改行するから間違えちゃうかも。
              
覚えないで、利用方法だけ知っておく。
            
- 1: PDOで接続(connect)
- 2: PDOで作成(create)
- 3: PDOで挿入(insert)
- 4: PDOで変更(update)
- 5: PDOで参照(select)
- 6: PDOで削除(delete)
- 7: PDOで抹消(drop)
- 8: 総括
- 1: PDOで接続する(DSN)
- PDOでMySQLに接続。
                
 Data Source Name(データソースネーム)
- // PDO接続の基本
                
 try {
 $pdo = new PDO(
 'mysql:host=ホスト名;dbname=DB名;
 charset=utf8', 'ユーザー名', 'パスワード',
 array( PDO::ATTR_EMULATE_PREPARES=> false));
 } catch (PDOException $e) {
 exit('データベース接続失敗。'.$e->getMessage());
 }
- 
                  赤文字だけ要変更。
                  
 $pdoは、以降で使用する。
 catch で接続できなかった時は、エラーメッセージを表示
 コレが基本みたいだけど、覚えるなら次のを。
 覚えませんけどね。
- PDO::ATTR_EMULATE_PREPARES
                  
 PHP5.2以降はデフォ。設定不要。
 プリペアドステートメントは2回アクセスするため、要設定!
 include_once("URI"); で設定を入れておけば、とても幸せ。
 define は、要変更!
 (私はこれを雛形にします:コピペ用)
- 
                [データベースが無い時]
                
 define('DB_HOST', 'localhost');
 define('DB_USER', 'root');
 define('DB_PASS', '1234');
 $option = array(
 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
 // デフォルトのエラー発生時の処理方法を指定
 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
 // SELECT 等でデータを取得する際の型を指定
 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
 // SELECT した行数を取得する関数 rowCount() が使える
 PDO::ATTR_EMULATE_PREPARES => false,
 // MySQLネイティブのプリペアドステートメント機能の代わりにエミュしたものを使う設定
 PDO::ATTR_STRINGIFY_FETCHES => false
 // 取得時した内容を文字列型に変換するかのオプション,int型も文字列扱い
 );
 $dsn = 'mysql: host=' . DB_HOST . ';charset=utf8';
 
 try {
 $pdo = new PDO($dsn, DB_USER, DB_PASS, $option);
 } catch (PDOException $e){
 echo $e->getMessage();
 }
- 
                [データベースが有る時]
                
 define('DB_HOST', 'localhost');
 define('DB_USER', 'root');
 define('DB_PASS', '1234');
 define("DB_NAME","database");
 $option = array(
 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
 // デフォルトのエラー発生時の処理方法を指定
 PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
 // SELECT 等でデータを取得する際の型を指定
 PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
 // SELECT した行数を取得する関数 rowCount() が使える
 PDO::ATTR_EMULATE_PREPARES => false,
 // MySQLネイティブのプリペアドステートメント機能の代わりにエミュしたものを使う設定
 PDO::ATTR_STRINGIFY_FETCHES => false
 // 取得時した内容を文字列型に変換するかのオプション,int型も文字列扱い
 );
 
 $dsn = 'mysql:dbname='.DB_NAME.';host=' . DB_HOST . ';charset=utf8';
 try {
 $pdo = new PDO($dsn, DB_USER, DB_PASS, $option);
 } catch (PDOException $e){
 echo $e->getMessage();
 }
- 2: create文
- データベースやテーブルを作成
- こちらも雛形っぽくしているけど、型を決めないといけないので要アレンジ
- 
                // Database作成
                
 // データベース名:bbs を追加
 define("DB_NAME","bbs");
 $sql= sprintf('create database if not exists %s default character set utf8;',DB_NAME);
 $res= $pdo -> prepare($sql);
 $res -> execute();
- 
                $sql でsql文を作成。
                
 実行だけすれば良いが、自分の中で手法を統一させるために、あえて$resを使用。
 sql文を prepareに入れて、接続していた$pdoでアクセス。
 この際にシングルアローを使用する。
 sql文の実行は、 execute()を使用する。
 if not existsは、同じデータベース名がなければ作成という制御。
 default character set utf8;で文字コードを指定。
- データベースを作成したら、要再接続!
                
 その際には下記を付与。
- 
                // Database作成時の再接続
                
 // nullで接続を切断
 $pdo = null;
 $dsn = 'mysql:dbname='.DB_NAME.';host=' . DB_HOST . ';charset=utf8';
 try {
 $pdo = new PDO($dsn, DB_USER, DB_PASS, $option);
 } catch (PDOException $e){
 echo $e->getMessage();
 }
- 
                $pdo を nullにすることで接続を終了。
                
 DB_NAMEは既に定数化しているので、そのまま使用。
- 
                // Table作成
                
 $sql1= 'create table if not exists users(
 user_id int not null auto_increment,
 user_name varchar(255) not null,
 password char(32) not null,
 primary key(user_id),
 unique(user_name)
 )character set utf8;';
 $res1= $pdo -> prepare($sql1);
 $res1 -> execute();
 
- 
                後で主キー追加設定 -> create table users(primary kye(user_id));
                
 空白ダメ -> not null
 主キー -> primary key(カラム名);
 ユニーク -> unique(カラム名);
 auto_increment はカラムに1つだけ。
 ここでも文字コードを指定しておく。
- 
                $sql2= 'create table if not exists texts(
                
 id int not null auto_increment,
 name varchar(255) not null,
 text varchar(500),
 primary key(id)
 )character set utf8;';
 $res2 = $pdo -> prepare($sql2);
 $res2 -> execute();
- 3: insert文
- PDOでデータをINSERTする
                
 プリペアドステートメントで挿入
 "test1"を"users"に追加する
- 
                // tableにinsertする 
                
 $sql = $pdo -> prepare("INSERT INTO users (user_name, password) VALUES (:name, :pass)");
 $sql-> bindParam(':name', $name, PDO::PARAM_STR);
 $sql->bindParam(':pass', $pass, PDO::PARAM_STR);
 
 //$sql->bindValue(':value', $value, PDO::PARAM_INT);
 
 $name = 'test1';
 $pass = md5('1234');
 $sql->execute();
- $sql->bindParam('ここにbindする変数', 変数, PDO::PARAM_STR);
- sprintfでの%sや%dの代わりにbindを使用する。
                
 ● bindParamは PDO::PARAM_INT を指定しても 文字列として扱われる
 ● bindValue は値の指定を変数でも行えるし、数値を指定する事も可能
 この場合は PDO::PARAM_INT などの型指定が必要。
- 4: update文
- 
                
 PDOでデータをINSERTする
 プリペアドステートメントで挿入
- 
                // insertした"test1"を"test2"に変更 
                
 $sql = $pdo -> prepare(
 "UPDATE users SET user_name= :name , password= :pass where user_name='test1';"
 );
 $sql->bindParam(':name', $name, PDO::PARAM_STR);
 $sql->bindParam(':pass', $pass, PDO::PARAM_STR);
 
 $name = 'test2';
 $pass = md5('1111');
 $sql->execute();
- 
                ● insertとほぼ一緒。
                
 結局は覚えることって少ないのかも…
 と、ここで気付き始めました。
 そして気合を入れてPHP_Manualを見てみたら…
 メチャ多くて、再度覚えることを諦めました(苦笑)
 先生じゃないんだから、使えたらいいんだよ。うん。
- 5: select文
- 
                これはちょっと違うので注意。
                
 でも、一番使うと思うので覚えますね。きっと。
- 
                // PDOでデータをselectする
                
 // $pdo->query("SELECT * FROM テーブル名 WHERE 条件文 ORDER BY 条件");
 
 $sql = $pdo -> query("SELECT * FROM users;");
 
 while($row = $sql -> fetch(PDO::FETCH_ASSOC)) {
 $id = $row["user_id"];
 $user = $row["user_name"];
 $pass = $row["password"];
 
 // ヒアドキュメントで表示
 // <<< EOS から EOS までをhtml形式で表示
 // 中で 変数も展開される
 
 echo <<<EOS
 <dl>
 <dd>$id</dd>
 <dd>$user</dd>
 <dd>$pass</dd>
 </dl>
 EOS;
 }
- 
                fetch(PDO::FETCH_ASSOC)
                
 ↑ mysql_fetch_assoc と同義
 EOSは勝手に付けています。なんでも良いので。
- メジャーなのはEOF…
                
 End Of File
 ファイルは違和感全開なので、
 End Of Strings
 文字列ってことにしてみました。
- EOS;の前にはスペースやタグは入れないこと!
- 6: delete文
- データ削除は簡単。
- 
                // "test2"のデータを削除
                
 $sql = $pdo -> query("DELETE FROM users WHERE user_name='test2';");
 $sql->execute();
- $sqlでsql文を作成して、execute();で実行するだけ。
- 7: drop文
- データではなく、入れ物自体の削除。
                
 これも簡単。
- 
                 // tableの削除
                
 $sql = $pdo -> query("DROP TABLE IF EXISTS users,texts;");
 $sql->execute();
- 
                // databaseの削除
                
 $sql = $pdo -> query("DROP DATABASE IF EXISTS bbs;");
 $sql->execute();
- 8: 総括
- 
                [宣言]
                
 これから作成するものに関しては、すべてPDOを使用します。
 
 理由は3点。
 1: 非推奨となっている。
 2: MySQL以外の他データベースでも使用可。
 3: ヒアドキュメントが便利
 逆にPDOを使わないと、これからはダメなのでしょう。
 ヒアドキュメントはsprintfよりも視認性が高いので利用していこうと思う。
 私の好きなコードを揃えるのも簡単。
 (PHP_EOLを使用しなくても改行される。)
 
 データベースは、やることが決まっていて基本はCRUDだけ。
 難しいのは…
 必要なカラムや他とbindしたりの初期設定や明確な構造をいかに作成するか。
 今後の課題でもありますね。
 
 でも基本はsql文というのも分かったし、
 一度使えるようになったら、違うデータベースでもPDOでアクセス出来るからマスターしたいな。。。
 
 本気でやり出したら、面白いかも。