質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Informix

Informixは、IBM社の関係データベース管理システム。かつては国内シェアをトップのRDBMSでした。高可用性、インスタンスレベルの指定時刻までのリストアなどの特徴を持ちます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

2回答

5186閲覧

PHPからInformixにODBC接続で、表示結果が途中で文字化けする

M-Kajiwara

総合スコア24

Informix

Informixは、IBM社の関係データベース管理システム。かつては国内シェアをトップのRDBMSでした。高可用性、インスタンスレベルの指定時刻までのリストアなどの特徴を持ちます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2017/04/27 11:49

編集2017/06/07 03:23

###質問内容
PHPからODBCでInformixに接続してデータを取得しようとしています。
PHPからSQLを実行し結果が取得できたのですが、
結果の途中から文字化けを起こしています。

実行結果から、途中から文字化けしていることや、登録されていないデータが含まれていることから、
終端文字のような特殊な文字が原因で文字化けが発生していると考え調査しています。

正しく結果を表示するための方法や解決の糸口など、教えていただけないでしょうか。

###環境
Webサーバ

  • CentOS 7 (UTF-8)
  • PHP 7.0.18 (UTF-8)
  • Apache 2.4.6 (UTF-8)
  • InformixのODBCドライバ 4.10 ? 1.3.3 ?

DBサーバ

  • Unix
  • Informix 7.32fc2 (Shift-JIS)

クライアント

  • IE 11 (エンコード:UTF-8)

###作業内容
実行PHP

php

1public function sample(){ 2 try { 3 $db = new PDO("informix:host=192.168.1.10; service=1526; database=sampledb; server=sampleserver; protocol=onsoctcp;CLIENT_LOCALE=ja_JP.utf8;DB_LOCALE=ja_jp.sjis-s;EnableScrollableCursors=1", "user", "password"); 4 $sql = "SELECT 商品名 AS A FROM 商品M"; 5 $stmt = $db->prepare($sql); 6 $stmt->execute(); 7 8 foreach ($stmt as $row) { 9 echo $row['A']; 10 echo '<br>'; 11 } 12 } catch (PDOException $e) { 13 14 } 15}

「商品M」テーブル
|番号|商品名|
|:--|:--:|--:|
|1|ノートパソコン用キーボード|
|2|iPad Air|
|3|デスクトップPC|

実行結果(ブラウザから確認)

ノートパソコン用キ01������2013-07-16 10:02:23���Ռ�:�� iPad Air デスクトッ01������2013-07-16 10:02:23���Ռ�:��

###解決方法
2017/06/07 12:20 追記
最終的な対応方法を共有します。

  • Informixドライバを利用し接続しました。
  • 接続文字列の「CLIENT_LOCALE」と「DB_LOCALE」の文字コードを統一し、

Informixから取得した結果を、PHP側で対象の文字コードに変換し利用しました。

php

1// 表示用 2public function view(){ 3 $item_list = $this->sample(); 4 foreach ($item_list as $row) { 5 echo $row['A']; 6 echo '<br>'; 7 } 8} 9 10// Informixのデータ取得 11public function sample(){ 12 try { 13 $db = new PDO("informix:host=192.168.1.10; service=1526; database=sampledb; server=sampleserver; protocol=onsoctcp;CLIENT_LOCALE=ja_jp.sjis-s;DB_LOCALE=ja_jp.sjis-s;EnableScrollableCursors=1", "user", "password"); 14 $sql = "SELECT 商品名 AS A FROM 商品M"; 15 $sql_sjis = mb_convert_encoding($sql, "SJIS-win", "UTF-8"); 16 $stmt = $db->prepare($sql_sjis); 17 $stmt->execute(); 18 19 $item_list = $stmt->fetchAll(); 20 mb_convert_variables("UTF-8", "SJIS-win", $item_list); 21 22 } catch (PDOException $e) {} 23 24 return $item_list; 25}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

恐らく、 PDO の Informix ドライバのバグではないでしょうか。以下のチケットにて、 「文字コードの変換を伴う場合、結果セットとして壊れた文字列が返される」 というバグが報告されておりますが、未だ修正が完了しておりません。こちらに引っかかってしまっているものと思われます。

PHP :: Bug #64008 :: PDO Informix returns corrupted strings when character conversion is active

バグの原因は単純なもので、問題はドライバが「文字コード変換後のデータサイズをきちんと予測せず、変換前と同じサイズのバッファを用意している」ことにあります。結果、変換後に元よりもサイズが大きくなる場合、途中まで変換した段階でバッファがあふれて処理が中断してしまう上、末尾の Null 文字も格納できずにゴミがくっついてしまう…という状況に陥ります。
今回の場合、日本語が Shift_JIS では概ね 2 bytes ですが UTF-8 では概ね 3 bytes なので、文字列の 2/3 程度だけ変換したところでバッファが足りなくなる計算になりますから、ご質問に記載なさっている実行結果にも一致しているように思います。

さて、対策としては、一つは上記のバグチケットでも言及されている通り、 informix_statement.c の該当部分で確保するバッファサイズを適当に数倍にするパッチを当ててからドライバをコンパイルするという方法があります。この場合、 C 言語の知識も必要になりますし、「結局、確保したバッファサイズを超えた時のエラー処理がちゃんとしていないままだから、場合によって問題は再現し得るのでは?」という課題は残りますが、ある程度デプロイ環境が操作できて、かつ他のサービスと共用していない状況なら、対策としてナシでは無いと思います。将来、ドライバ側がきちんと修正される可能性もありますしね。

もう一つは、当該のバグを抑々回避するため、文字コードの変換を PDO より先でやらせない、という方法になるでしょうね。つまり、 CLIENT_LOCALE で UTF-8 を指定せず、データベース側と揃えて Shift_JIS にしてしまい、投げるクエリも結果セットもPHP 側で変換してやるということです。
この場合、全て PHP 側で完結させることができるので、ある意味「安全」な方法かもしれませんが、勿論いちいち PHP の各所で文字コード変換をやらないといけなくなりますから、 (良くて PDO を wrap するクラスを書いて自動で変換させることはできそう、とはいえ) やっぱり難点は残ります。それぞれのメリット・デメリットを考慮の上で判断頂ければと思います。

投稿2017/05/06 19:35

argparse

総合スコア1017

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

M-Kajiwara

2017/05/08 06:38

回答いただきありがとうございます。 まさかドライバのバグとは思いもよりませんでした・・・ まだまだ調査不足ですね。。。 回答でおっしゃられている通り課題や、 環境の変更ができないということもあり、 PHP側での対応になりますが、データ量も多く処理速度の面でやや不安です。 現在代替手段を検証中でそれでも解決できない場合、 PHPでの対応を試みます。 バグについて、分かりやすく解説して頂きとても助かりました。 ありがとうございます。 参考までに検証中の代替手段について、 SQLServerのリンクサーバーという機能を利用し、Informixと同期 PHPからSQLServerにODBC接続するという方法を行っています。
guest

0

すべての文字化けは、文字コードが異なることで発生するとお考えください。

Informix 7.32fc2 (Shift-JIS)

ここをutf8に変更するか

変換コストがかかるのでやめたほうがいいのですが・・・、
mb_convert_encoding
を用いて
sqlを utf8 -> Shift-JIS に必ず変換して実行
受け取った結果を Shift-JIS -> utf8 に変換して出力
という方法が考えられます。

文字コードの統一が難しい場合は、文字化けのリスクを受け続ける事を念頭においてください。

投稿2017/04/28 01:22

raichi

総合スコア278

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

M-Kajiwara

2017/04/28 01:47

ご回答ありがとうございます。 今回は文字コードを統一することは難しい為、 mb_convert_encodingを試してみようと思います。 変換コストがかかるようなので、代替手段についても考えていきます。 >すべての文字化けは、文字コードが異なることで発生するとお考えください。 ありがとうございます。このことを念頭において考えるようにします。 今までで文字化けというと、 対象のデータ全てが文字化けするイメージで捉えていました。 途中から文字化けしていた為、特殊文字が化けているのだと思い込んでいました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問