QA@IT

Linux+PHPからSQLServerへのodbc接続できない。

14075 PV

■環境
 ・OS:Linux 2.6.32-358.14.1.el6.x86_64
 ・PHP:5.3.3

の環境からSQLSererへ接続するためunixodbcを導入しました。

Freetds、odbcの設定は完了し、「isql -v mssql_production ユーザ名 パスワード」での接続確認まで出来ています。

mssql_productionはodbc.iniで設定したDSNです。

PHPで以下のプログラムを実行したのですが、
Failed: SQLSTATE[IM002] SQLDriverConnect: 0 [unixODBC][Driver Manager]Data source name not found, and no default driver specifiedのエラーが返ってきてしまいます。

$server = "サーバ名";
$database = "DB名";
$user = "ユーザ名";
$password = "パスワード";
$driver ="mssql_production";

$con = odbc_connect("Driver=$driver;Server=$server;Database=$database;", $user, $password);

原因が分からないためご教示よろしくお願いします。

回答

ちょっとインストールしていて気になったんですが、
unixODBCとFreeTDSはどのようにインストールしましたか?

OSが .el6.x86_64 とのことだったので
CentOS 6の x64で試していますが、
最初 yumからunixODBC (devではない方)入れて、freetdsはソースからコンパイルしたんですけど、そうするとlibodbc.soが生成されませんでした。

(unixODBC-devel入れてもいけたかもしれませんが)unixODBCもソースからビルドしてfreetdsの./configureでunixODBCの場所指定してコンパイルしたらlibodbc.soも出来上がりました。

それとisqlは確認されたとのことですが、tsqlでも接続はできていますか?


インストールし終わって isql、tsqlで接続できるがphpのインタラクティブコンソールから接続できないという、同じような状態になりましたので、
何かわかったらまた回答に追加しますね。


エラーはでなくなりました。

DBへの読み書きは行っていませんが(確認予定もありません)、とりあえずodbc_connectで落ちなくなったので報告します。

isqlやtsql接続のために設定していたファイルをホームディレクトリにドットファイルとしてコピーしてください。

具体的には私の環境では

# cp /etc/odbc.ini ~/.odbc.ini
# cp /usr/local/bin/freetds-0.91/etc/freetds.conf ~/.freetds.conf

としてます(freetds.conf は私が上記の場所にビルドしたのでこの位置ですが多分違う場所にあると思います)
コピー先には先頭に ドットがついていることに注意してください。

これで以下の様にエラーが出ていたのが

# php -a
Interactive shell

php > $conn = odbc_connect("SqlServer", "user", "pass");
PHP Warning:  odbc_connect(): SQL error: [unixODBC][Driver Manager]Data source name not found, and no default driver specified, SQL state IM002 in SQLConnect in php shell code on line 1
php > $conn = odbc_connect("QAITSQLSVR", "user", "pass");
PHP Warning:  odbc_connect(): SQL error: [unixODBC][FreeTDS][SQL Server]Unable to connect to data source, SQL state S1000 in SQLConnect in php shell code on line 1

以下の様にエラーがでなくなりました。

# php -a
Interactive shell

php > $conn = odbc_connect("QAITSQLSVR", "user", "pass");
php >

なお、上記のSqlServer(エラーの方にあるやつ) は freetds.confのセクション名、QAITSQLSVRはodbc.iniのセクション名になっているものです。
user,passはもちろんご自分の環境のものを入れてください。

確認で入れてたpyodbcもエラー出てたのがエラーが出なくなったのでうちの環境ではこれが原因だったようです。
お試しください。

ただ、これだとWindowsで言うところのユーザーDSNなんですよね。
システムDSNの位置はexportしてたつもりなんですがなんだか見てくれないようで。そちらを使わせる方法は不明です。

あと、エラー2つ載せてますが、実は違うエラーです。DSNにあたる文字列を指定している場合はIM002ではなく、S1000エラーです。現在出ているエラーがIM~の方であれば指定している文字がDSNじゃないかもしれませんのでご注意ください。

編集 履歴 (4)
  • 結果的にはphpを再インストールしたところ、接続できるようになりました。
    phpinfoで確認したところ、「environment」の項目に以下の二つが追加されていました。(再インストール前後の違いはおそらくここだけ)なので環境変数の問題?かと思っています。
    ODBCSYSINI /usr/local/etc
    ODBCINI /usr/local/etc/odbc.ini
    -
  • うちの環境ではそれに加えて FREETDSCONF もexportしてましたが動作はしなかったですね(.bashrcでも×)。 入れなおしたタイミングで/etc/php.d/ などの内容が更新されたのかもしれません。いずれにせよ、odbcのiniファイルを見つけられるようにする必要があるという事ですね。 -

PHPやApacheはrootが持っている odbc.iniやfreetds.confを見に行きます。
そこに設定されてない場合は繋がらないです。

odbc.iniを編集するのであれば、
odbcinstを使って編集することをお勧めします。
下記のようにdsnのテンプレートを作って

$ vi dsn.template
    [mssql_production]
    #ドライバーの説明
    Description = SQL Server2008R2
    #ドライバーの場所 
    #  ドライバーのフルパスか
    #  ドライバー名(ここではFreeTDS)を記述する
    Driver = /usr/lib/i386-linux-gnu/odbc/libtdsodbc.so
    #トレースするかの有無
    Trace = No
    #データベースのIPアドレス
    Server = IPアドレス
    #データベース名
    Database = データベース
    #ポート番号 SQL Serverは通常 1433
    Port = 1433
    #TDS_Version SQLServer2000は7.1 SQLServer2005以降は7.2
    TDS_Version = 7.2
    #クライアント(Linux側)の文字コードセット
    ClientCharset = UTF-8

上記のテンプレートをodbcinstに読み込ませる。

$ sudo odbcinst -i -s -l -f dsn.template

又は

 # odbcinst -i -s -l -f dsn.template

後はphpinfoでFreeTDSとunixODBCが入ってるか確かめた方がいいです。
下記は私の phpinfo(); の情報

mssql
MSSQL Support   enabled
Active Persistent Links 0
Active Links    0
Library version FreeTDS

odbc
ODBC Support    enabled
Active Persistent Links 0
Active Links    0
ODBC library    unixODBC
ODBC_INCLUDE    -I/usr/include
ODBC_LFLAGS -L/usr/lib
ODBC_LIBS   -lodbc

日本語のBlogではFreeTDSをビルドコンパイルする人が多いですが、
yumやapt-getでもすんなり入りますよ。

編集 履歴 (0)

** 9/9 19:40 追記しました。 **

$server = "サーバ名";
$database = "DB名";
$user = "ユーザ名";
$password = "パスワード";

// Microsoft SQL Server using the SQL Native Client 10.0 ODBC Driver - allows connection to SQL 7, 2000, 2005 and 2008
$connection = odbc_connect("Driver={SQL Server Native Client 10.0};Server=$server;Database=$database;", $user, $password);

この形式で接続しても状態は変わりませんか?


http://php.net/manual/ja/function.odbc-connect.php

odbc_connectのマニュアルに、第1引数はdsnか、dsnではない場合は直接接続文字列も設定できるとあります。

今回であればdsnがあるので

$con = odbc_connect($driver, $user, $password);

になるのではないでしょうか。
接続ドライバとDSNは別のものです。

エラーについては、
"Driver=$driver;Server=$server;Database=$database;"
(正確には展開した文字列である Driver=mssql_production;Server=サーバ名;Database=DB名; )
というdsnは存在せず、

かといって接続文字列と解釈してみても "Driver=mssql_production;" で指定される mssql_production というドライバも見つからない。

というエラーだと思います。

編集 履歴 (2)

アドバイスありがとうございます。

$server = "サーバ名";
$database = "DB名";
$user = "ユーザ名";
$password = "パスワード";
$driver ="mssql_production";

$con = odbc_connect($driver, $user, $password);
   if (!$con) {
       exit('データベースに接続できませんでした。');
   }

としてみたのですが、やはり$conがnullとなってしまっているようです。

編集 履歴 (0)
  • そのphpコードはコマンドラインから実行してますか?webサーバーなどで実行していますか? -
  • 繋がらない事に変わりは無いがIM002のエラーは出なくなったということでしょうか? -
  • コマンドライン、Webサーバどちらでも同じ結果になり、エラーも出ています。Webから実行した場合はApacheのエラーログに出力されています。 -
  • odbc.iniのdriverの設定、/etc/odbcinst.iniの対応するドライバの設定も済んでいるんですよね?(isqlでつながっているので大丈夫だとは思いますが)。DSNではなく http://phpspot.net/php/man/php/function.odbc-connect.html の最後にあるように接続文字列で接続してみてもかわりませんか? -
  • DSNではない接続コードを回答に追記しました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。