意外と困っている人が多そうだったので、まとめておく。
結論から言うと、デフォルトの状態ではLinuxからCakePHP2でSQLServerには繋がらないです。
DataSourceの接続部分のソースを少し書き換える必要があります。 下記が手順です。
1. 下準備をする。
下記がインストールされていることをチェック!
(1) php > 5.4
1 2 3 4
| $ php -v PHP 5.4.27 (cli) (built: Apr 23 2014 01:18:28) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies
|
(2) freetds
1 2
| $ which tsql /usr/local/bin/tsql
|
うまい確認方法が見当たらなかったのですが、freetds
がインストールされていればtsqlも一緒にインストールされているはずなので tsqlチェックで多分大丈夫。
(3) pdo_dblib
1 2
| $ php -m | grep pdo pdo_dblib
|
peclでインストール出来るよ。
(4) cakephp
cakephpのバージョンは2.4.7を用意しました。
※2系なら多分大体一緒。
2. cakephpの基本設定
通常通りにcakeのブランクアプリを作成して、ブラウザでアクセスします。
Warningが出ていますね。
1 2 3
| CakePHP is NOT able to connect to the database.
Database connection "Sqlserver" is missing, or could not be created.
|
つまり、databaseの設定はあるけど、databaseには接続出来ていません。
この段階でdatabase.phpの設定内容下記の通りです。
1 2 3 4 5 6 7 8
| 'Database/Sqlserver', 'persistent' => false, 'host' => 'localhost', 'login' => 'hoge', 'password' => 'hoge', 'database' => 'test', ); }
|
何故繋がらないのか?
それは、cakephp2のDatabase/Sqlserverというdatasourceがpdo_sqlsrvというPDOモジュールを想定して作られているからです。
pdo_sqlsrvはMicrosoftがwindows用に用意しているモジュールで、Linux用はありません。
実際のソースコード内では、利用可能なPDOモジュールを確認してsqlsrvが無いからNGってことでエラーになっています。
つまり、通常状態のcakephpではSQLServerには接続出来ないのです。
3. cakephpの改造
改造と言っても、coreのファイルに手を入れる必要はありません。 自分のアプリケーションの同名PATHにSqlserver.phpとDboSource.phpをコピーして、少し手直しして上げるだけです。
ディレクトリ構成は下記の通り。Model配下のDatasourceディレクトリにコピーしたファイルを置きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| app── Config ├── Console ├── Controller │ └── Component ├── Lib ├── Model │ ├── Behavior │ └── Datasource │ ├── DboSource.php │ └── Database │ └── Sqlserver.php ├── Plugin ├── Vendor ├── View ├── tmp └── webroot
|
下は修正内容のdiffです。ひとまず、動かすことを目的にしてますので、修正方法は荒いです。 DboSource.php
1 2 3 4 5 6 7 8 9
| @@ -304,7 +304,7 @@ class DboSource extends DataSource { * @return string The database version */ public function getVersion() { - return $this->_connection->getAttribute(PDO::ATTR_SERVER_VERSION); + return false; } /**
|
Sqlserver.php ※PHP5.3の方はページ下部の追記分も修正を行う必要あり。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @@ -123,16 +123,13 @@ class Sqlserver extends DboSource { PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ); - if (!empty($config['encoding'])) { - $flags[PDO::SQLSRV_ATTR_ENCODING] = $config['encoding']; - } + $enc = !empty($config['encoding']) ? $config['encoding'] : 'UTF-8'; try { $this->_connection = new PDO( - "sqlsrv:server={$config['host']};Database={$config['database']}", + "dblib:host={$config['host']};dbname={$config['database']};charset={$enc}", $config['login'], - $config['password'], - $flags + $config['password'] ); $this->connected = true; if (!empty($config['settings'])) { @@ -156,7 +153,7 @@ class Sqlserver extends DboSource { * @return boolean */ public function enabled() { - return in_array('sqlsrv', PDO::getAvailableDrivers()); + return in_array('dblib', PDO::getAvailableDrivers()); } /** @@ -494,7 +491,7 @@ class Sqlserver extends DboSource { } else { $map = array(0, $name); } - $map[] = ($column['sqlsrv:decl_type'] === 'bit') ? 'boolean' : $column['native_type']; + $map[] = ($column['native_type'] === 'bit') ? 'boolean' : $column['native_type']; $this->map[$index++] = $map; } }
|
この状態で、再度ブラウザでアクセスしてみると・・・
見事につながりました。
pdo_sqlsrvとpdo_dblibの仕様の違いがあるので完璧とまでは行かないのですが、ひとまず一通りのCRUDは出来ます。
もし、SQLServerにLinux環境下のCakephp2から接続出来ないのであれば、上記をお試し下さい。
※2014/5/12追記
PHP5.3の場合、pdo_dblibがgetColumnMetaという関数をサポートしていないため、更に下記の修正を行ってください。
Sqlserver.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| --- a/app/Model/Datasource/Database/Sqlserver.php +++ b/app/Model/Datasource/Database/Sqlserver.php @@ -475,24 +475,39 @@ class Sqlserver extends DboSource { $this->map = array(); $numFields = $results->columnCount(); $index = 0; + $j = 0; + $querystring = $results->queryString; + if (stripos($querystring, 'SELECT') === 0) { + $last = strripos($querystring, 'FROM'); + if ($last !== false) { + $selectpart = substr($querystring, 7, $last - 8); + $selects = String::tokenize($selectpart, ',', '(', ')'); + } + } + while ($j < $numFields) { + if (!isset($selects[$j])) { + $j++; + continue; + } + if (preg_match('/\bAS\s+\[(.*)\]/i', $selects[$j], $matches)) { + $columnName = trim($matches[1], '"'); + } else { + $columnName = trim(str_replace('"', '', $selects[$j])); + }
|