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

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

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

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

Q&A

解決済

1回答

2969閲覧

PHP5.5の「大文字小文字を区別しない比較がロケールに依存しなくなる」について

mkt-0818

総合スコア8

PHP

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

2グッド

0クリップ

投稿2016/05/13 14:33

PHP5.5の「下位互換性のない変更点」(下記ページ)

http://php.net/manual/ja/migration55.incompatible.php

に記載されている「大文字小文字を区別しない比較がロケールに依存しなくなる」の内容について具体的にどのロケール及びコードで過去バージョンと差異が発生するのか、ご教示頂けないでしょうか。

認識しているロケールごとにmb_internal_encodingも変更して確認してみましたが、全てPHP5.5とPHP5.4で同じ結果が返ってきます。
(ロケールによって結果は異なりますが・・・)

PHP5.4と5.5で結果が異なる具体的なコードをご教示頂けると有難いです。

###確認したソースコードの一部(環境:CentOS6.4-ファイルの文字コードはUTF8)

<?php error_reporting(E_ALL); function sl($locale, $str) { $arEncode = array('', 'UCS-4','UCS-4BE','UCS-4LE','UCS-2','UCS-2BE','UCS-2LE','UTF-32','UTF-32BE','UTF-32LE','UTF-16','UTF-16BE','UTF-16LE','UTF-7','UTF7-IMAP','UTF-8','ASCII','EUC-JP','SJIS','eucJP-win','SJIS-win','ISO-2022-JP','ISO-2022-JP-MS','CP932','CP51932','SJIS-mac','JIS','JIS-ms','CP50220','CP50220raw','CP50221','CP50222','ISO-8859-1','ISO-8859-2','ISO-8859-3','ISO-8859-4','ISO-8859-5','ISO-8859-6','ISO-8859-7','ISO-8859-8','ISO-8859-9','ISO-8859-10','ISO-8859-13','ISO-8859-14','ISO-8859-15','byte2be','byte2le','byte4be','byte4le','BASE64','HTML-ENTITIES','7bit','8bit','EUC-CN','CP936','GB18030','HZ','EUC-TW','CP950','BIG-5','EUC-KR','UHC','ISO-2022-KR','Windows-1251','Windows-1252','CP866','KOI8-R','ArmSCII-8'); foreach ($arEncode as $encode) { mb_internal_encoding($encode); ex($locale, $str); } } function ex($locale, $str) { if (setlocale(LC_ALL, $locale) === false) { error_log('Locale not found: ' . $locale) . PHP_EOL; return; } echo STRTOUPPER($str) . PHP_EOL; echo MB_STRTOUPPER($str) . PHP_EOL; echo STRCASECMP($str, STRTOUPPER($str)) . PHP_EOL; echo STRLEN($str) . PHP_EOL; echo MB_STRLEN($str) . PHP_EOL; echo SUBSTR($str, 10, 10) . PHP_EOL; echo STRIPOS($str, chr(0xE6)) . PHP_EOL; echo STRPOS($str, chr(0xE6)) . PHP_EOL; echo STR_REPLACE(chr(0xE6), '日本語', $str) . PHP_EOL; echo STR_IREPLACE(chr(0xE6), '日本語', $str) . PHP_EOL; echo UCFIRST($str) . PHP_EOL; } $str = null; for($i=0xC0; $i<=0xFF; $i++){ $str .= chr($i); if ($i == 0xDF) $str .= 'abc日本語'; } sl('C',$str); sl('POSIX',$str); sl('aa_DJ',$str); sl('aa_DJ.iso88591',$str); sl('aa_DJ.utf8',$str); sl('aa_ER',$str); sl('aa_ER.utf8',$str); /*文字数制限により省略(「locale -a」の結果全て)*/ sl('zh_TW.utf8',$str); sl('zu_ZA',$str); sl('zu_ZA.iso88591',$str); sl('zu_ZA.utf8',$str);
yodel, saitomarch👍を押しています

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

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

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

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

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

guest

回答1

0

ベストアンサー

PHP5.5より前の環境が無いため検証はあまりできていませんが、そもそもそこで述べていることに誤解があるようです。

そのページで述べている大文字小文字無視のマッチングは、関数名やクラス名や定数名についての話であり、strcasecmp等の関数での処理での話ではありません。たとえば、hoiという関数があった場合、HOIでも呼び出せるというところの大文字小文字の無視です。5.4以前ではトルコ語の環境にするとHOİ(** İ **はIの上または右上方に・がありますが、環境によっては正しく表示されません)でも呼び出せたようですが、5.5以降は言語環境に関係なくASCIIでのルールにのみ従うようになったため、呼び出せなくなったと言うことです。

PHP

1<?php 2function hoi() 3{ 4 echo "hoi"; 5} 6HOİ(); // Iではなくİ。5.4以前でトルコ語なら呼び出せる。

なお、ここでのロケールはシステムのロケールだと思われます。マルチバイト文字の扱い方の変更に過ぎないmb_internal_encodingでは設定できず、PHPを呼び出す前にシステム(OS)のロケールを変更しないと確認できないかも知れません。

投稿2016/05/13 22:35

raccy

総合スコア21735

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

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

mkt-0818

2016/05/14 14:08

raccyさん ご回答有難うございます。 http://b60.uchb.net/linux/2014/09/articles4php55.html を拝見して、そうゆう事象が発生するなのか?と勘違いしておりましたが、 こちらの内容って、この問題とは別の問題っぽいですね。 クラス名、関数名、定数名ってASCIIコードでのみ定義できるものと思っておりましたが、違うんですね。 >これは、マルチバイト文字セット (UTF-8 も含む) で非 ASCII 文字に対して大文字小文字を区別しないマッチングをしているコードで問題になるかもしれません。 >ヨーロッパ諸国語のアクセント記号などがこれにあてはまります。 上記の記載内容からヨーロッパ諸国で通常使用される「ISO-8859-1」での「アクセント記号(0xC0~0xFF)」は マルチバイトじゃないような。(マルチバイトを扱える文字コードでアクセント記号を使用した場合って意味???) eripongさん ご回答有難うございます。 ご指摘頂いたバグについて、バグ投稿された際に記載されているスクリプトは、 私の環境ではVer.5.4と5.5でも正常に実行されてましたが、 「raccyさん」の回答頂いた内容からも、こちらが怪しいですね。 raccyさん、eripongさん ご回答頂いた内容を踏まえて、再度、事象の再現確認をしたいと思います。 (再現できるかはわかりませんが。) ですので、解決済み及びベストアンサーのマークは2、3日お待ち頂けますでしょうか。
mkt-0818

2016/05/16 14:37 編集

コメントでは、MarkDown機能が使用できなく、質問者がコードをさらに記載したい場合は、みなさんどうされているのでしょうか? 醜い投稿となり申し訳ございません。 ```PHP <?php class aÀ{} //「À」(0xC0) class InfoBlob{} //「I」(0x49) class i{} //「i」(0x69) class g{} //「g」(0x67) class E{} //「E」(0x45) function sl($locale) { if (setlocale(LC_ALL, $locale) === false) { error_log('Locale not found: ' . $locale) . PHP_EOL; return; } if(!class_exists('aÀ')) echo 'aÀ:'. $locale . PHP_EOL; //①「À」(0xC0) if(!class_exists('aà')) echo 'aà:'. $locale . PHP_EOL; //②「à」(0xE0) if(!class_exists('InfoBlob')) echo 'InfoBlob:'. $locale . PHP_EOL; //③「I」(0x49) if(!class_exists('infoBlob')) echo 'infoBlob:'. $locale . PHP_EOL; //④「i」(0x69) echo strtolower('INFOBLOB') . PHP_EOL; //⑤小文字変換 if(!class_exists('İ')) echo 'I:'. $locale . PHP_EOL; //⑥「İ」(0x0130) if(!class_exists('Ġ')) echo 'G:'. $locale . PHP_EOL; //⑦「Ġ」(0x0117) if(!class_exists('ė')) echo 'e:'. $locale . PHP_EOL; //⑧「ė」(0x0120) } sl('C'); sl('POSIX'); sl('aa_DJ'); //・・・(省略) sl('ja_JP'); sl('ja_JP.eucjp'); sl('ja_JP.ujis'); sl('ja_JP.utf8'); sl('japanese'); sl('japanese.euc'); //・・・(省略) sl('zu_ZA'); sl('zu_ZA.iso88591'); sl('zu_ZA.utf8'); ``` **【出力結果】** ※以下の日本語ロケールは以下を指します。 ja_JP ja_JP.eucjp ja_JP.ujis ja_JP.utf8 japanese japanese.euc - ①if(!class_exists('aÀ')) echo 'aÀ:'. $locale . PHP_EOL; //①「À」(0xC0) →5.4でのみ309個(全733個中)出力 ※日本語ロケールの出力なし (詳細は省略) →5.5では出力なし - ②if(!class_exists('aà')) echo 'aà:'. $locale . PHP_EOL; //②「à」(0xE0) →5.4, 5.5とも全ロケールで出力される - ③if(!class_exists('InfoBlob')) echo 'InfoBlob:'. $locale . PHP_EOL; //③「I」(0x49) →5.4でのみ16個出力 ※日本語ロケールの出力なし InfoBlob:az_AZ InfoBlob:az_AZ.utf8 InfoBlob:crh_UA InfoBlob:crh_UA.utf8 InfoBlob:ku_TR InfoBlob:ku_TR.iso88599 InfoBlob:ku_TR.utf8 InfoBlob:tr_CY InfoBlob:tr_CY.iso88599 InfoBlob:tr_CY.utf8 InfoBlob:tr_TR InfoBlob:tr_TR.iso88599 InfoBlob:tr_TR.utf8 InfoBlob:tt_RU.utf8@iqtelif InfoBlob:tt_RU@iqtelif InfoBlob:turkish →5.5では出力なし - ④if(!class_exists('infoBlob')) echo 'infoBlob:'. $locale . PHP_EOL; //④「i」(0x69) →5.4, 5.5とも出力なし - ⑤echo strtolower('INFOBLOB') . PHP_EOL; //⑤小文字変換 →5.4でのみ③で出力されるロケールについては「InfoBlob」。それ以外は「infoBlob」。 - ⑥if(!class_exists('İ')) echo 'I:'. $locale . PHP_EOL; //⑥「İ」(0x0130) →5.4でのみ③の出力と同一のロケールを出力。 →5.5では出力なし - ⑦if(!class_exists('Ġ')) echo 'G:'. $locale . PHP_EOL; //⑦「Ġ」(0x0117) →5.4, 5.5とも出力なし - ⑧if(!class_exists('ė')) echo 'e:'. $locale . PHP_EOL; //⑧「ė」(0x0120) →5.4, 5.5とも出力なし **【考察】** - 考察① ①②の結果、Ver5.4ではアクセント記号を使用したクラス名はロケールによっては使用できない。 (アクセント記号のクラス名は大文字、小文字は全てのロケールで異なると判定される。) - 考察② ③④⑤⑥⑦⑧の結果、Ver5.4ではトルコ語及びトルコ語の規則を使用するアゼルバイジャン(az)、クルド(ku)等のロケールでの大文字「I」が正しく扱えなかった為、クラス名、関数名の大文字、小文字と大文字、小文字の相違を伴う関数の結果が正しく返されなかった。 https://bugs.php.net/bug.php?id=18556 →考察②での特定のロケールで大文字「I」に問題があった為、ロケールに依存しないよう修正された。 結果、考察①のようにアクセント記号にて定義されたものが、ロケールによって認識しないものが、認識されるようになった? **【疑問】** - 疑問① http://php.net/manual/ja/language.oop5.basic.php のクラス名に以下の文字を使用できるとあるが、 __^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$__ ⑥⑦⑧で使用した文字コード「İ」「Ġ」「ė」は 範囲外であるが、正しく認識している? - 疑問② 「À」(0xC0) と「à」(0xE0)は大文字小文字の関係にない? 長文で分かりにくい内容となり恐縮ですが、考察と疑問について、ご指摘頂ける方がございましたら、宜しくお願いします。
raccy

2016/05/17 12:29

うーん、私もそれほど詳しいわけではありませんが、修正された理由はロケールによって動きが異なるのはよろしくないって所だと思います。 PHPはそもそもASCII以外の文字を考慮していません。文字列はただの8bitのcharの羅列でしか見ていません。PHPにはソースコード自体の文字コードを指定する方法はありませんし、mbstringはそれを特定のエンコードと見なして処理しているだけに過ぎません。Shift_JISで"表"を"表\"とする必要があるのも8bitのcharの羅列でしか見ていないからです。ですので、Unicodeで見ても意味がありません。もしUTF-8でエンコードしている場合はU+80以上の文字は全て\x80-\xffの範囲に入ります。注意すべき所はここら辺かなと思います。
mkt-0818

2016/05/22 13:39

何だかすっきりはしませんが、とりあえず日本語のロケールを使用している限りは、バージョンアップしてもこの問題は発生しないと思いますので、クローズします。 raccyさん、eripongさん 貴重なアドバイスを頂き、有難うございました。 これからも活用させて頂きたいと思いますので、目に留まった際には、 宜しくお願い致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問