PDO

PDO(プリペアドステートメント)を使用してデータベースにアクセスするのは、結構安全らしい。
…ということで、まとめてみる。
※PCでの閲覧推奨。スマホは変なとこで改行するから間違えちゃうかも。
覚えないで、利用方法だけ知っておく。

戻る



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();
}

Topへ


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();

Topへ


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 などの型指定が必要。

Topへ


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を見てみたら…
メチャ多くて、再度覚えることを諦めました(苦笑)
先生じゃないんだから、使えたらいいんだよ。うん。

Topへ


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;の前にはスペースやタグは入れないこと!

Topへ


6: delete文
データ削除は簡単。
// "test2"のデータを削除
$sql = $pdo -> query("DELETE FROM users WHERE user_name='test2';");
$sql->execute();
$sqlでsql文を作成して、execute();で実行するだけ。

Topへ


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();

Topへ


8: 総括
[宣言]
これから作成するものに関しては、すべてPDOを使用します。

理由は3点。
 1: 非推奨となっている。
 2: MySQL以外の他データベースでも使用可。
 3: ヒアドキュメントが便利
逆にPDOを使わないと、これからはダメなのでしょう。
ヒアドキュメントはsprintfよりも視認性が高いので利用していこうと思う。
私の好きなコードを揃えるのも簡単。
(PHP_EOLを使用しなくても改行される。)

データベースは、やることが決まっていて基本はCRUDだけ。
難しいのは…
必要なカラムや他とbindしたりの初期設定や明確な構造をいかに作成するか。
今後の課題でもありますね。

でも基本はsql文というのも分かったし、
一度使えるようになったら、違うデータベースでもPDOでアクセス出来るからマスターしたいな。。。

本気でやり出したら、面白いかも。

Topへ


[Education]
ProgramDeveloped.

[MHW]
MONSTER HUNTER: WORLD

[Links]
My Links.

[GoogleSearch]

[Special Thanks]
ちょびネット