CentOS7 + PHP 7.1 から Microsoft SQLServer への二つの道のり

2020年10月13日 リンク切れ更新。内容修正


(1) yum で php-sybase パッケージをインストール
FreeTDS使用 PDOで使う場合、プリフィックスに dblib: を使用する方法

(2) yum で php-sqlsrv パッケージをインストール
MicrosoftのODBC Driver for SQLServer を使用し、PDOで使う場合、プリフィックスに sqlsrv: を使用する方法

(1)は、PHP5系で長らく使われてきた方法です。yumでphp-sybaseをインストールすれば他に何も要りません。リポジトリによっては php-mssql かも。
FreeTDS/php-sybase を使用する時に注意しないといけないのは、主に /etc/freetds.conf で指定する TDSプロトコルのバージョンです。検索したら たまに 8.0にしている記事がありますが、8.0は後方互換性のために定義されていて、実際には 7.1 へのエイリアスとなってます。ドキュメントが更新されたらしく8.0は互換性で残しているが今後削除されるかもしれない、だって。(Choosing a TDS protocol version)
また、SELECTとかで日付・時間の値を取得したとき、返される値がシステムのロケールに依存している場合があります。この場合、/etc/locales.conf を(なければ作成して) ロケール毎に指定するか、php.ini の mssql.datetimeconvert の値をいじる必要があります。

また、プリペアードステートメントを使ったクエリだと、文字列リテラルのとき、自動的にNプレフィックスをつけてくれません。ですので、PDO::prepareで 「N?」という風に付けないといけません。「?」だけでもエラーにはなりませんが、絵文字とか化けます。

(2)は、基本的にPHP 7系以降の方法です。長らく Microsoftは SQLServerのPHPドライバは Windows向けPHPのみサポートしてきましたが、おそらく SQLServer on Linux のリリースに合わせ Linux/MacOS用のPHPドライバ/ODBCドライバもサポートするようになったんじゃないかな?
Windows用PHPと同じように、Linuxの各ディストリビューションのPHPでもフツーに SQLServerへ CRUDできるようになりました。

このページは (2)の方法の備忘録です。

素のCentOS7で、sudo yum install php すると、PHP5.4 がインストールされます(@_@) 5系はもう deprecated ですので、REMIレポジトリを追加し、PHP7をインストールします。。。

※ 2021/06/30 追記
CentOS 8もしくは CentOS Stream の場合、標準で PHP7.2がインストールされるのでREMIリポジトリは不要です。7.4とかに上げたい場合は、DNFコマンドで、 dnf module list php とすれば 利用可能な バージョンの一覧がでます。詳しくは DNFコマンドを調べてみてください。

1. Add REMI repository

$ sudo yum install epel-release
$ sudo rpm -Uvh http://rpms.remirepo.net/enterprise/remi-release-7.rpm

リポジトリ確認
$ yum repolist

2. Install Mircrosoft ODBC Driver for SQLServer

$ sudo su
# curl https://packages.microsoft.com/config/rhel/7/prod.repo > /etc/yum.repos.d/mssql-release.repo
# exit
$ sudo yum remove unixODBC-utf16 unixODBC-utf16-devel
$ sudo ACCEPT_EULA=Y yum install msodbcsql17
$ sudo ACCEPT_EULA=Y yum install mssql-tools
$ echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
$ echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc
$ source ~/.bashrc

3. Install php and others… by remi repository
もしBaseリポジトリからインストールされたPHPがある場合は、まずそれを削除。

$ sudo yum remove php-*
$ sudo yum --enablerepo=remi,remi-php71 install php php-devel php-pdo php-sqlsrv

他のphpモジュールも必要であればインストール。
$ sudo yum --enablerepo=remi,remi-php71 install unixODBC-devel php-mbstring php-gd php-cli
※追記:CentOS8がリリースされてます。
CentOS8では標準でPHP7.2がインストールされますので、REMIリポジトリは必要ありません。
ただし、DNF(YUM)ではphp-sqlsrvをインストールできないので、pecl を利用しないといけません。
詳しくはマイクロソフトのサイトを参照した方がよろしいかと。
https://www.microsoft.com/en-us/sql-server/developer-get-started/php/rhel/step/2.html

接続するときの注意事項。

  • 接続文字列でSQLServerのサーバー名を指定する時、SQLServerインスタンスの着信ポートが1433以外の場合は、コロン(:)じゃなくて、カンマで区切って指定。これハマった💦
  • SQLServer 接続マネージャ で TCPを有効にする。私がSQLServerをインストールした時、デフォルトでは無効になってました。
  • OS(普通はWindows Server)のファイヤーウォールで着信ポートを許可する事。

あとは普通に接続。テーブル作成はWindowsでSQLServer Management Studio(SSMS)を使うとラクですので、適当にテーブルを作成し、そのテーブルに対して「テーブルをスクリプト化 ⇒ 新規作成 ⇒ ファイル」でSQLファイルとして保存しておく。保存したらそのテーブルは一旦削除(別にしなくてもいいけど)。

<?php
//SQL Serverの着信ポートを SQLServer構成マネージャで確認しておく。1433以外の場合はカンマで区切って指定
$pdo = new PDO('sqlsrv:Server=localhost,49494;Database=Sample','sa','xxxxxx');

//(必要なら)テーブル作成
$sql = file_get_contents(<上で作ったSQLファイルのパス>);
$res = $pdo->exec($sql);
var_dump($res);

//UTF-8なCSVファイルをDBに登録するための用意
// ここでは1行に3つのセル(id,name,desc 等)があるCSVを仮定してます。
// 改行を含むセルがあるCSVファイルの場合、SplFileObject 以外は使わない方が良いと思う。
$csv = new SplFileObject(<csv file path>,'r');
$csv->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY);

//Create
$sth = $pdo->prepare('INSERT INTO tbl_sample VALUES(?,?,?)');
$sth->bindParam(1,$param1,PDO::PARAM_STR);
$sth->bindParam(2,$param2,PDO::PARAM_INT);
$sth->bindParam(3,$param3,PDO::PARAM_STR);
foreach($csv as $row)
{
  list($param1,$param2,$param3) = $row;
  $sth->execute();
}

//Read
$sth = $pdo->query('SELECT * FROM INFORMATION_SCHEMA.TABLES');
$rows = $sth->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);

//Update
$sth = $pdo->prepare('UPDATE tbl_sample SET column2=?,column3=? WHERE column1 = ?');
$sth->bindValue(1,2,PDO::PARAM_INT);
$sth->bindValue(2,'column value3',PDO::PARAM_STR);
$sth->bindValue(3,'column value 1',PDO::PARAM_STR);
$res = $sth->execute();
var_dump($res);

//Delete
$res = $pdo->exec("DELETE FROM tbl_sample WHERE column1 = N'column1 value'");
var_dump($res);

【タイプミス修正】2020年3月18日