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

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

ただいまの
回答率

90.48%

  • PHP

    20814questions

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

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

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 767

mkt-0818

score 1

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);
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

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

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

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/05/14 07:55

    こちらも検証してませんが、おそらくこのBugなので、setlocaleすれば発生の確認はできそうです。

    https://bugs.php.net/bug.php?id=18556

    キャンセル

  • 2016/05/14 23: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日お待ち頂けますでしょうか。

    キャンセル

  • 2016/05/16 23:25 編集

    コメントでは、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)は大文字小文字の関係にない?


    長文で分かりにくい内容となり恐縮ですが、考察と疑問について、ご指摘頂ける方がございましたら、宜しくお願いします。

    キャンセル

  • 2016/05/17 21:29

    うーん、私もそれほど詳しいわけではありませんが、修正された理由はロケールによって動きが異なるのはよろしくないって所だと思います。

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

    キャンセル

  • 2016/05/22 22:39

    何だかすっきりはしませんが、とりあえず日本語のロケールを使用している限りは、バージョンアップしてもこの問題は発生しないと思いますので、クローズします。

    raccyさん、eripongさん

    貴重なアドバイスを頂き、有難うございました。
    これからも活用させて頂きたいと思いますので、目に留まった際には、
    宜しくお願い致します。

    キャンセル

関連した質問

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

  • PHP

    20814questions

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