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

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

ただいまの
回答率

88.77%

json_decode()で配列に変換するとユニコード文字が文字化けする

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 4,564

ishidou

score 7

 前提・実現したいこと

APIから取得したJSONをPHPにてMYSQLのデータベースに登録したい。
JSONテキストをjson_decode()で配列に変換すると、
読めないユニコード文字が文字列として取り扱えない。

なお、受信しているJSONはLINEからのJSONであり
LINE独自の絵文字が返信されてきています。
「\uDBC0\uDC8D」
このため通常のブラウザでは表示できず􀂍となっています。
この文字列を「\uDBC0\uDC8D」のままでMySQLに登録したい。

json_decodeを使うと文字化けするため、
使用せずに該当文字列だけ取り出して変数に
そのまま入れることはできないでしょうか。

 発生している問題・エラーメッセージ

デコード前
string(xx) "{"Message":"\uDBC0\uDC8D"}" 

デコード後
array(1) { ["Message"]=> string(4) "􀂍" } 

サーバー環境 
PHP7.2.1  mysql5.2

 該当のソースコード

$json = json_decode($json,true); 
$Message = $json["Message"];
var_dump($Message);

<質問への返答及び追記>
(1)「普通の日本語など、他のマルチバイト文字列はどうしたいですか?」
LINE絵文字 と 日本語文字列 が一緒に送信されてくるため、
他のマルチバイト文字列は日本語のテキストとして、mysqlに登録したいです。
例えば、「\uDBC0\uDC8Dこんにちは」というように登録したいです。

(2)「取り扱えない」の意味について
json_decodeした後に、\uDBC0\uDC8Dという英数字のままでmysqlに登録したいのですが
外字のため変換されてしまい英数字のままにできないという意味です。

⇒追記
\uDBC0\uDC8Dの文字がブラウザで表示されずに「􀂍」になっているだけのようすです。
mysqlもブラウザからphpmyadminで中を見ているので「􀂍」が登録されています。
この「􀂍」をLINEに送信すると元の絵文字が表示されました。
単にブラウザで表示できていないだけのようです。

(3)外字に対するグリフが見つからないだけでは?
すみません、その通りです。
初心者なので外字が見つからないために表示されないので、どのように対処すべきかわからない状況です。

(4)バイナリデータとしてデータベースに登録すれば?
バイナリデータとして登録したことがないので調べながら試してみます。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2018/04/07 17:02

    では、問題解決ってこと?

    キャンセル

  • defghi1977

    2018/04/07 17:03

    問題がなかったことが問題だったということで

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2018/04/07 17:41 編集

    あとはもう、defghi1977さんの言うようにフォント対応ですね。

    キャンセル

回答 5

checkベストアンサー

+3

問題は二つだと思っています。

  • MySQLへの登録時にエラーになる、または、無視や途切れが発生する。
  • ブラウザ上で文字化け(Tofu)が発生する。

それぞれ分けて考えます。なお、PHPのコードは全てUTF-8で処理していることが前提です。

まず、"\uDBC0\uDC8D"が何かというとこれはサロゲートペアというもので、この二つセットで一つの文字を表しています。JavaScriptでは内部の文字列がUTF-16になっているため、U+10000以上のユニコード文字は必ずサロゲートペアになります。正しく処理されればU+10008Dという一つの文字になります。ただし、この文字はSupplemental Private Use Area-B(私的領域の一つ)というブロックに属しており、アプリケーションやフォントによって好きな文字を割り当てても良いのですが、互換性のない他のアプリケーションやフォントではその文字は用意されない(または、別の何かになる)ため、文字化けが発生します。ここまではいいでしょうか?

最初にMySQLへの登録についてです。通常、MySQLでユニコード文字列を扱う場合、文字コードとしてutf8またはutf8mb4を使っていることがほとんどだと思います。そして、デフォルトのまま設定している場合や内容が古いサイトや本等を参考にした場合はutf8になっていることがほとんどでしょう。しかし、ここにutf8の罠があります。utf8はU+FFFFまでのユニコード文字にしか対応しておらず、U+10000以上の文字は扱えません。絵文字(🐱など)や一部の異字(𠮷など)が対応していないと言っている場合、MySQLがutf8だったためというのがあります。これを解消するには文字コードをutf8mb4に変更するしかありません。一応、途中で変える手順もあるようですが、私は失敗したことがあるので、最悪DB全てを作り直すことも視野に入れてください。ということで、まずはMySQLの文字コードがutf8mb4になっているかを確認してください。utf8の場合はU+10008Dを含め絵文字等も登録できません。utf8mb4に変更してください。

次にブラウザ側の文字化けです。MySQLへの登録されうまくいけば、ブラウザまではU+10008Dを渡すことができます。しかし、この文字は私的領域であるため、ブラウザにこの文字を表示するためのグリフ(図形)を持つフォントはありません。方法は二つです。

  1. その文字のグリフを持つフォントをWebフォントとして提供する。
  2. 別の文字などに置き換える。

WebフォントはLINE社が自由に使って良いものを用意していなければ、難しいでしょう。フォントが無ければ置き換えです。置き換えはPHP側で行います。正規表現などを使って私的領域※の文字を別の何かに置き換えます。ただし、preg系(PCRE)をu付きで使うか、mb_ereg系(Oniguruma)を使う必要がありますので、ご注意ください。

※ 私的領域の文字の範囲(LINEが全て使用するわけではありません)
U+E000 から U+F8FF
U+F0000 から U+FFFFD
U+100000 から U+10FFFFD
PHPにはユニコード文字リテラルがないようですので、正規表現を書くには一工夫必要です。とりあえず、サンプルを書きましたので、参考にしてください。

<?php
$json = '{"Message":"これは\uDBC0\uDC8Dです。"}';
$json = json_decode($json,true); 
$Message = $json["Message"];
var_dump($Message);
$Message = preg_replace("/[\xEE\x80\x80-\xEF\xA3\xBF\xF3\xB0\x80\x80-\xF3\xBF\xBF\xBD\xF4\x80\x80\x80-\xF4\x8F\xBF\xBD]/u", "【表示不可】",$Message);
var_dump($Message);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/07 17:19

    回答を書いている途中に進んだ内容は読めてなかったです。再読込すると、投稿内容が消えることがあるので。で、一体どこで、utf8mb4になっている話が出ていたのですか?私が確認をミスっていたのでしょうか?

    キャンセル

  • 2018/04/07 17:25

    raccy様、lucker様有難うございます。
    途中でコメントしていましたので、混乱させてしまいましたね。
    どこで問題が起こっているのかが、わらからないのが一番の問題でした。

    状況を切り分けていただきながら進めて頂いていましたので、なんとか理解できました。

    当面はサンプルコードを利用して表示できないことを画面に表示させたいと思います。

    キャンセル

  • 2018/04/09 20:05

    PHP7からUnicodeコードポイント表記入りました

    PHP7調査(6)文字列中にコードポイントでUTF-8の1文字を書けるようになった - Qiita https://qiita.com/hnw/items/513dfc411ae22d0cdaa6

    キャンセル

+1

(2)「取り扱えない」の意味について
json_decodeした後に、\uDBC0\uDC8Dという英数字のままでmysqlに登録したいのですが
外字のため変換されてしまい英数字のままにできないという意味です。

これ、どういう状態ですか?

何をもって、「外字のため変換されてしまい」と判断し、実際にどうなっているんですか?
どうやってそれを確認したんですか?

提示されたソースコードって

$json = json_decode($json,true); 
$Message = $json["Message"];
var_dump($Message);

これですけど、ここで絵文字が表示されないから問題だと思っているのか
mysqlに登録したら変換されてしまって元の文字が維持できていないから問題だと思っているのか
よーわからんのですよ。

デコード前
string(xx) "{"Message":"\uDBC0\uDC8D"}" 

デコード後
array(1) { ["Message"]=> string(4) "􀂍" } 

string(4)ってことは恐らく普通にjson_decode()出来ていると思うんだけど…。

とにかく、何をもって上手くいかないと判断しているのかが分からないので回答すべきかどうか悩むっす。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/07 17:04

    混乱させてしまってすみません。 \uDBC0\uDC8Dの文字がブラウザで表示されずに「􀂍」になっているだけのようすです。mysqlもブラウザからphpmyadminで中を見ているので「􀂍」が登録されています。この「􀂍」をLINEに送信すると元の絵文字が表示されたので単にブラウザで表示できていないだけのようです。

    ブラウザで表示されない = json_decodeができていない と判断していました。

    しかし、LINEのAPIを使って送受信した内容をPCのブラウザから見れるようにしたいので
    見れないという問題は残ったままです。

    キャンセル

  • 2018/04/07 17:07

    > しかし、LINEのAPIを使って送受信した内容をPCのブラウザから見れるようにしたいので
    だら, LINEが使っている文字コードに対応するWEBフォントを作って配信すれば済むことでは?

    キャンセル

+1

NOTE:
MySQLにおけるユニコード文字列の取扱いについてはraccyさんの回答をご覧ください.


MySQL側の文字コードがutf-8ならべつにIN-OUTで文字コードが変化しているわけじゃないので、そのままで良いと思いますが?

􀂍と表示されるのが気持ち悪いのは判りますが, これは文字化けというより"豆腐"です.

WEBブラウザにおける"豆腐"を解決するのであれば"豆腐"化しているグリフを含むWEBフォント(woff形式など)を配布すればよいでしょう. CSSには@font-face規則を用いてHTTP経由でWEBフォントを読み込む仕組みがあります.

https://developer.mozilla.org/ja/docs/Web/CSS/@font-face

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/07 17:06

    回答有難うございます。
    豆腐が気持ち悪いのですが、なんとかブラウザでも表示されるようにはできないものでしょうか。

    キャンセル

  • 2018/04/07 17:08

    できるよ. WEBフォントをこさえて, WEBブラウザに配信すれば良いのですよ.
    https://developer.mozilla.org/ja/docs/Web/CSS/@font-face
    CSSに専用の@font-face規則ってのがありましてですね, これを使えば良いのです.

    キャンセル

  • 2018/04/07 17:18

    なるほどWEBフォントをこさえないといけないのですね。
    LINEから配布されるとよいのですが。

    キャンセル

  • 2018/04/07 17:20

    なんかユースケース的に「よくありそう」なので, 色々と調べてみればいいと思います. (もしなければ、自分で作って自慢するのも良いでしょう)

    キャンセル

0

まあ LINE 絵文字ってことで

https://github.com/Miserlou/Emo

というのがあるっぽい(使い方はしらんが説明文を見ると LINE絵文字を表示するためのものっぽい)

パイソンか

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-2

文字列ではなく、バイナリデータとしてデータベースに登録すればいいんじゃないでしょうか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/07 14:23

    データストレージとして使う分には十分ですが、インデックスとか張って検索したいときにはつらそう…?

    キャンセル

  • 2018/04/07 15:55

    回答ありがとうございます。
    バイナリデータとして登録したことがないのですが、調べながらやってみます。
    今のところ検索することは予定していません。

    キャンセル

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

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る