忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2017/11/24 09:04 |
PHP1-42:PHPでPDO

XAMPPはMySQLですが、他に有名なフリーのDBとしてPostgreSQLが存在します。
商用としては高性能なOracleが、Windows用にはMSSQL等があります。
PHPはデフォルトで、それぞれのDBMSに対して専用の接続関数を用意しています。
MySQLならmysql_connect()、PostgreSQLならpg_connect()、Oracleならoci_connect()といったかんじです。
しかしこれではDBが変更になった際など、全てのプログラムからDB関係の関数を全て探し出して変更しなければなりません。
そんなことをすると恐ろしい手間がかかるので、それを避けるためにDataAccessObjectが編み出されました。

まあ簡単に言うとDBにアクセスするクラスを作成し、コンストラクタに'mysql'なり'postgres'なりの文字を与えれば、あとの接続やSQLの実行といった部分は全部クラス内でやってくれますよということです。
これによって、例えばDBが変更になった場合でも、最初の引数だけ変更すればOKとなるわけです。
更にDBのインスタンス化を行う部分を一つのファイルに纏めてしまえば、DBが変更になっても変更箇所はたった一箇所で済むようになります。
まあ実際はそううまくいくわけもなく、ベンダ固有のSQL実装など修正部分が出てくるのは避けられませんが、それでも素のDB接続関数を用いるよりは遙かに簡単になります。

PHPでDataAccessObjectパターンを行う手段は幾つか存在します。
有名どころではPear::MDB2やPear::DB_DataObjectがありますが、PHP5でようやくモジュールとしてPDOが登場しました。
http://jp.php.net/manual/ja/book.pdo.php
Pearと違ってCで書かれているので高速性が期待できます。

早速使ってみましょう。
Linuxではインストールが必要ですが、Windowsではphp.iniのコメントを外すだけです。
http://jp.php.net/manual/ja/pdo.installation.php

まずはDBの準備です。
phpMyAdminから編集するなりSQLを打つなりでテスト用DBとテーブル、ユーザを作成します。
 

CREATE DATABASE `testdb` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE TABLE `books` (
 `id` int(11) NOT NULL auto_increment,
 `name` varchar(128) NOT NULL,
 `author` varchar(128) NOT NULL,
 `publisher` varchar(128) default NULL,
 `price` int(10) default '0',
 `isbn` varchar(16) default NULL,
 `date` date default NULL,
 `comment` text,
 `created_at` timestamp NOT NULL default CURRENT_TIMESTAMP,
 `updated_at` datetime default NULL,
 `deleted_at` datetime default NULL,
 PRIMARY KEY  (`id`),
 KEY `index_name` (`name`),
 KEY `index_author` (`author`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'testpass';
GRANT USAGE ON * . * TO 'testuser'@'localhost' IDENTIFIED BY 'testpass' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0 ;
GRANT ALL PRIVILEGES ON `testdb` . * TO 'testuser'@'localhost' WITH GRANT OPTION ;


できました。
booksテーブルは別にこんなに立派である必要はありませんが、昔作ったのを流用しました。
とりあえず適当に一件登録しておいてください。

次はPHPの用意です。

pdo.php 

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
    
    //PDO
    define('DB_DSN','mysql:host=localhost;dbname=testdb');
    define('DB_USERNAME','testuser');
    define('DB_PASSWORD','testpass');
    
    $db = new PDO(DB_DSN,DB_USERNAME,DB_PASSWORD);
    
    $select=$db->query('SELECT * FROM books');
    while($loop=$select->fetch(PDO::FETCH_ASSOC)){
        $ret[]=$loop;
    }

簡単に$dbにPDOオブジェクトが作成されました。
後はこれに対しSQLを書いていくだけですが、PDOを経由しているので実行する時にDBの種類を考える必要がありません。

 

もしDBが変更になった場合、最初のDB_DSNを、
define('DB_DSN','pgsql:host=localhost port=8888 dbname=testdb');
等と変更するだけです。
移植性、独立性の高いコードを書くことが出来ました。

さっそく実行。
 

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  array(11) {
    ["id"]=>
    string(1) "1"
    ["name"]=>
    string(5) "?????"
    ["author"]=>
    string(2) "??"
    ["publisher"]=>
    string(6) "??????"
    ["price"]=>
    string(4) "1050"
    ["isbn"]=>
    string(14) "978-4883810451"
    ["date"]=>
    string(10) "2006-10-01"
    ["comment"]=>
    string(7) "????(?)"
    ["created_at"]=>
    string(19) "2008-08-15 11:45:49"
    ["updated_at"]=>
    NULL
    ["deleted_at"]=>
    NULL

お?
見事に文字化けしています。
PHPもUTF8、MySQLもUTF8、ブラウザもUTF8なのに何故?

実はこれMySQLからPHPへの出力時に変な文字コードで出力しているのが原因です。
MySQLからの出力は、テーブルの文字コードそのままではなく、設定ファイルに従って変換された上で出力されます。
このデフォルト値がlatin1なる日本語の使えないコードであるため、日本語が全て文字化けしてしまうのです。

というわけで
$db->query('SET NAMES utf8');
の一文を入れるだけで直るのですが、セキュリティ上の理由から勧められていません。
http://nonn-et-twk.net/twk/why-set-names-in-php-is-bad
かわりにmysql_set_charset()を使えと書いてありますが、PDOでどうしろと。

MySQL側で動作を修正した場合、MySQL全体に影響が及ぶので、他のシステムが存在した場合そちらが動作不具合を起こす可能性もあります。
http://dev.mysql.com/doc/refman/4.1/ja/charset-connection.html

まあ今回はローカルで特に問題ないのでmy.cnfを修正しました。
マニュアルには
default-character-set-name=character_set_name
とか書いてありますが、正しくは
default-character-set = utf8
です。

修正方法は、my.cnf(Windows上では短縮ダイアルに見える)の適当なところに、
  [mysqld]
  default-character-set = utf8
  skip-character-set-client-handshake

という文字を突っ込むだけです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
array(11) {
    ["id"]=>
    string(1) "1"
    ["name"]=>
    string(16) "恋空〈上〉"
    ["author"]=>
    string(7) "美嘉"
    ["publisher"]=>
    string(19) "スターツ出版"
    ["price"]=>
    string(1) "0"
    ["isbn"]=>
    string(15) "978-4883810451"
    ["date"]=>
    string(10) "2006-10-01"
    ["comment"]=>
    string(18) "スイーツ(笑)"
    ["created_at"]=>
    string(19) "2008-01-01 01:01:01"
    ["updated_at"]=>
    NULL
    ["deleted_at"]=>
    NULL

めでたし。
PR


2009/01/07 10:43 | Comments(4) | TrackBack(1) | PHP

トラックバック

トラックバックURL:
Zend_DbはMySQLやOracleといったDB間の差異を吸収してくれるデータベースアダプタです。 といっても内部的にPDOを使用しているのでPDOが使えるのならわざわざZend_Dbを使用する意味はほとんどないんですが。 zend_db.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...
弱小PHPerの憂鬱 | 2009/09/07 17:11

コメント

おーい元気にしてるんか?
俺は前の会社をやめて転職して中部に引越したよ。

たまには連絡くれ。
では。
posted by saygo at 2009/01/08 01:10 [ コメントを修正する ]
おひさしゅう。

ネットは死ぬわ電話は死ぬわ俺は死ぬわでもう駄目です。
NEの筈だったのに何故か今はWeb開発に居るし。
posted by 名無しさん必死だな at 2009/01/10 00:14 [ コメントを修正する ]
XAMPP 1.7.0で
複数列が返るselect文をPDO::queryすると落ちる

select id from~はOK
一列しかないテーブルにselect * もOK

select id,nameとかすると死
posted by 名無しさん必死だな at 2009/03/13 16:25 [ コメントを修正する ]
脆弱性があるようなクズコード書いてんじゃねえよこのハゲ!(意訳)
というようなことを言われました。
http://www.tokumaru.org/d/20100701.html

PDOはデフォルトではプレースホルダを使わず勝手にエミュレーションしてしまうらしいので、コンストラクタに引数を渡してやらないといけないようです。
http://d.hatena.ne.jp/do_aki/20100221/1266746673
posted by NurseAngel at 2010/07/01 23:13 [ コメントを修正する ]

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<PHP1-43:PHPでPDOつづき | HOME | JavaScript2-9:JavaScriptで犯罪者作成装置>>
忍者ブログ[PR]