PHP Note
category: 携帯端末 積極的なスパム投稿対策 Parse error ゼロで始まるPHP

携帯端末

created: 2003-09-14 | modified: 2003-11-02

携帯端末の移り変わりは早くこのコンテンツははっきり言って古いです。ブラウザの判別や文字コードの処理の参考資料程度になるかと思いますので残しています。

わりと新しい情報としては↓この掲示板のやりとりや、このページ最下部の「携帯端末コンテンツ作成で役立つサイト」のリンク先が参考になります。


端末判別

携帯端末を判別するには PCでブラウザを判別する時と同じように、$_SERVER['HTTP_USER_AGENT'] の値を調べます。この書式は 4.1.0 以降のバージョンで利用可能です。それ以前のバージョンでは、$HTTP_USER_AGENT を使用します。

$_SERVER['HTTP_USER_AGENT'] の値には、i-mode端末は "DoCoMo"、j-sky端末は、"J-PHONE"、Ezweb端末は、"UP.Browser" という文字列が含まれています。正規表現関数を使ってこれらの文字の有無を確かめれば機種を判別できます。

例えば、機種を判別して各端末用のページに振り分ける

<?php
if (preg_match('/DoCoMo/', $_SERVER['HTTP_USER_AGENT'])) {
    // i-mode用のページにジャンプ
    header('Location: index_imode.html');
    exit();
} elseif (preg_match("/J-PHONE/", $_SERVER['HTTP_USER_AGENT'])) {
    // j-sky用のページにジャンプ
    header('Location: index_jsky.html');
    exit();
} elseif(preg_match("/UP\.Browser/", $_SERVER['HTTP_USER_AGENT'])) {
    // Ezweb用のページにジャンプ
    header('Location: index_ezweb.html');
    exit();
} else {
    // その他端末用のページにジャンプ
    header('Location: index_others.html');
    exit();
}
?>

例えば、携帯端末を判別する関数

<?php
/**
 * function get_mobile_agent ()
 *
 * 機  能:接続中の携帯端末を示す番号を返す
 * 引  数:なし
 * 戻り値:0 = 以下に該当しない未定義の端末
 *         1 = i-mode
 *         2 = j-sky
 *         3 = Ezweb
 */

function get_mobile_agent()
{
    if (preg_match('/DoCoMo/', $_SERVER['HTTP_USER_AGENT'])) {
        return 1;
    } elseif (preg_match('/J-PHONE/', $_SERVER['HTTP_USER_AGENT'])) {
        return 2;
    } elseif (preg_match('/UP\.Browser/', $_SERVER['HTTP_USER_AGENT'])) {
        return 3;
    } else {
        return 0;
    }
}
?>


i-mode の絵文字

i-mode 絵文字の構造

i-mode端末の絵文字は Shift-JIS の外字にあたる2バイトコードを使って表現されてます。外字ですので正確には『 Shift-JIS 』ではありません。よって PHP搭載のマルチバイトモジュール(mbsting)で他の文字コードに変換した場合、絵文字の文字コードは失われますので注意が必要です。

i-mode の絵文字は、1バイト目が "0xF8" 又は "0xF9"、2バイト目が "0x40" から "0xFC"の間に点在していますので、文字列中の絵文字を判別するには 1バイトずつ文字コードを確認する必要があります。


i-mode 絵文字の表示

i-mode端末に絵文字を表示させるには 絵文字コードをそのまま出力するだけです。しかしスクリプト中で Shift-JIS 以外にエンコード変換されるようなことがあると、それ以降絵文字とは違う文字コードとして判別されてしまいます。

このような場合、文字コードをアスキー文字だけで表記するHTMLの書式を使って文字コードを保持します。書式は、"&#[文字コードの10進数表記];" となります。まず "&#"、つづいて絵文字コードを10進数表記に直したもの、最後に ";" という書式となります。 ちなみに「晴れマーク("F89F")」の場合は、"&#63647;" となります。これならばアスキー文字ばかりなのでエンコード変換されたとしても絵文字コードは保持されます。

ただし、拡張絵文字の場合この方法はつかえません。拡張絵文字の場合は、"&#x[Unicodeに変換した文字コードの16進数表記];" という書式を使用します。「iアプリマーク("F9B1")」の場合、"&#xE70C;" となります。


i-mode絵文字の存在を確認する関数 (2004/12/09改)

<?php
/**
 * function iemoji_in ( $str )
 *
 * 機  能:文字列に i-mode絵文字が含まれているか確認する
 * 引  数:$str = 文字列
 * 戻り値:true = 絵文字あり
 *         false = 絵文字なし
 */

function iemoji_in ( $str )
{
    $str = unpack("C*", $str);
    $len = count($str);
    $n = 1;
    while ($n <= $len) {
        $ch1 = $str[$n];
        $ch2 = $str[$n+1];
        if (($ch1 == 0xF8) && (0x9F <= $ch2) && ($ch2 <= 0xFC)) {
            return true;
        } elseif (($ch1 == 0xF9) &&
            ((0x40 <= $ch2) && ($ch2 <= 0x49) ||
             (0x50 <= $ch2) && ($ch2 <= 0x52) ||
             (0x55 <= $ch2) && ($ch2 <= 0x57) ||
             (0x5B <= $ch2) && ($ch2 <= 0x5E) ||
             (0x72 <= $ch2) && ($ch2 <= 0x7E) ||
             (0x80 <= $ch2) && ($ch2 <= 0xFC))) {
            return true;
        // 2バイト文字の処理
        } elseif (((0x81 <= $ch1) && ($ch1 <= 0x9F))
             || ((0xE0 <= $ch1) && ($ch1 <= 0xFC))) {
            $n++;
        }
        $n++;
    }
    return false;
}
?>

i-mode端末の絵文字をHTMLエンティティに変換する

<?php
/**
 * function iemoji_encode ( $str, $opt = true )
 *
 * 機  能:i-mode基本絵文字を10進数SJIS表記に、
 *         拡張絵文字を16進数Unicode表記に変換する。
 * 引  数:$str = 文字列
 *         $opt = falseを指定すると絵文字を削除する。
 * 戻り値:変換(又は削除)後の文字列
 */

function iemoji_encode ( $str, $opt = true )
{
    $str = unpack("C*", $str);
    $len = count($str);
    $buff = "";
    $n = 1;

    while ($n <= $len) {
        $ch1 = $str[$n];
        $ch2 = $str[$n+1];
        if ((($ch1 == 0xF8) && (0x9F <= $ch2) && ($ch2 <= 0xFC)) ||
            (($ch1 == 0xF9) &&
             ((0x40 <= $ch2) && ($ch2 <= 0x49) ||
              (0x50 <= $ch2) && ($ch2 <= 0x52) ||
              (0x55 <= $ch2) && ($ch2 <= 0x57) ||
              (0x5B <= $ch2) && ($ch2 <= 0x5E) ||
              (0x72 <= $ch2) && ($ch2 <= 0x7E) ||
              (0x80 <= $ch2) && ($ch2 <= 0xB0)))) {
            if ($opt) {
                $buff .= '&#'.strval(($ch1 << 8) + $ch2).';';
            }
            $n++;
        } elseif (($ch1 == 0xF9) && (0xB1 <= $ch2) && ($ch2 <= 0xFC)) {
            if($opt) {
                $buff .= '&#x'.strtoupper(dechex(0xE700 + $ch2 - 165)).';';
            }
            $n++;
        } elseif (((0x81 <= $ch1) && ($ch1 <= 0x9F) ) || ((0xE0 <= $ch1) && ($ch1 <= 0xFC))) {
            // 2バイト文字の処理
            $buff .= pack("C", $ch1) . pack("C", $ch2);
            $n++;
        } else {
            $buff .= pack("C", $ch1);
        }
        $n++;
    }
    return $buff;
}
?>

HTMLエンティティ化されたi-mode絵文字を 2バイトコードに変換する

<?php
/**
 * function iemoji_decode ( $str )
 *
 * 機  能:i-mode基本絵文字10進数SJIS表記と、拡張絵文字
 *         16進数Unicode表記を 元の2バイトコードに変換する。
 * 引  数:$str = 文字列
 * 戻り値:変換後の文字列
 */

function iemoji_decode ( $str )
{
    $str = preg_split('/&#([x0-9A-F]{5});/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
    $line = count($str);
    $buff = "";
    $n = 0;

    while ($n < $line) {
        if ($n % 2) {
            if (preg_match("/^[0-9]{5}$/", $str[$n])) {
                $temp = intval($str[$n]);
                if ((0xF89F <= $temp) && ($temp <= 0xF8FC) ||
                    (0xF940 <= $temp) && ($temp <= 0xF949) ||
                    (0xF950 <= $temp) && ($temp <= 0xF952) ||
                    (0xF955 <= $temp) && ($temp <= 0xF957) ||
                    (0xF95B <= $temp) && ($temp <= 0xF95E) ||
                    (0xF972 <= $temp) && ($temp <= 0xF97E) ||
                    (0xF980 <= $temp) && ($temp <= 0xF9B0))
                    $buff .= pack("C*", $temp >> 8, $temp % 256);
                else
                    $buff .= $str[$n];
            } elseif (preg_match("/^xE7(0[\x43-\x46]|[1-4][0-9A-F]|5[0-7])$/", $str[$n], $temp)) {
                $buff .= pack("C*", 0xF9, hexdec($temp[1]) + 165);
            } else {
                $buff .= $str[$n];
            }
        } else {
            $buff .= $str[$n];
        }
        $n++;
    }
    return $buff;
}
?>


J-PHONE の絵文字

J-PHONE の絵文字の構造

J-PHONEの絵文字は、エスケープシーケンス(制御コード)ではさまれた5バイトのコードにより、端末内臓の画像を呼び出し絵文字として表示させています。1バイト目が"0x1B"、2バイト目が、"$"、3・4バイト目が"0x21"から"0x7A"までのアスキー文字、5バイト目が"0x0F"となっています。 同じグループ(3バイト目が同じ文字)の絵文字が連続する場合、各絵文字の4バイト目だけが連続するという圧縮されるケースがあります。(複雑です)


J-PHONE の絵文字の表示

J-PHONE端末に絵文字を表示させる場合も絵文字コードをそのまま出力するだけです。「晴れマーク」の場合、"0x1B","$","Gj","0x0F" を連続して出力すれば良い訳です。

ただ、PHPでエスケープシーケンスを文字として扱う場合、"0x1B" は "\x1B" 、"0x0F" は "\x0F" と表記します。また PHPで "$" は変数を示す記号なので "$" を文字として扱う場合は "\$" と表記します。これを踏まえ「晴れマーク」をPHPの文字列として表記すると "\x1B\$Gj\x0F" となります。


j-sky絵文字の存在を確認する関数

<?php
/**
 * function jemoji_in ( $str )
 *
 * 機  能:文字列に j-sky端末の絵文字が含まれているか確認する
 * 引  数:$str  = 文字列
 * 戻り値:true  = 絵文字あり
 *         false = 絵文字なし
 */

function jemoji_in ( $str )
{
    if (preg_match("/\x1B[\x24][\x21-\x7A]{2,}\x0F/", $str)) {
        return true;
    } else {
        return false;
    }
}
?>

j-sky絵文字をHTMLエンティティに変換する関数

<?php
/**
 * function jemoji_encode ( $str, $opt = true )
 *
 * 機  能:文字列に含まれるj-sky絵文字をHTMLエンティティに変換する
 * 引  数:$str  = 文字列
 *         $opt  = falseを指定すると絵文字を削除する
 * 戻り値:変換後の文字列
 */

function jemoji_encode ( $str, $opt = true )
{
    $str = preg_split("/\x1B[\x24]([\x21-\x7A]{2,})\x0F/", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
    $line = count($str);
    $buff = "";
    $n = 0;

    while ($n < $line) {
        if($n % 2) {
            if ($opt) {
                $buff .= '&#27;$'.$str[$n].'&#15;';
            }
        } else {
            $buff .= $str[$n];
        }
        $n++;
    }
    return $buff;
}
?>

HTMLエンティティ化された j-sky絵文字を元の絵文字コードに変換する関数

<?php
/**
 * function jemoji_decode ( $str )
 *
 * 機  能:文字列に含まれるj-sky絵文字をHTMLエンティティに変換する
 * 引  数:$str = 文字列
 * 戻り値:変換後の文字列
 */

function jemoji_decode ( $str )
{
    $str = preg_split("/&#27;[\x24]([\x21-\x7A]{2,}?)&#15;/", $str, -1, PREG_SPLIT_DELIM_CAPTURE);
    $line = count($str);
    $buff = "";
    $n = 0;

    while ($n < $line) {
        if ($n % 2) {
            $buff .= "\x1B$".$str[$n]."\x0F";
        } else {
            $buff .= $str[$n];
        }
        $n++;
    }
    return $buff;
}
?>


Ezweb の絵文字

Ezweb の絵文字の構造

Ezweb端末では、専用のタグによって端末内臓の画像を呼び出し絵文字として表示させています。 絵文字の書式は、HDML の場合、<img icon="絵文字番号"> 、XHTML の場合は、<img localsrc="絵文字番号" /> となります。


Ezweb の絵文字の表示

表示する場合は素直にタグを出力するだけです。「晴れマーク」の場合、<img icon="44"> または、<img localsrc="44" /> となります。

ただし、Ezweb端末で絵文字を入力できるのはメールだけのようです。Ezweb端末送られてきたメールをスクリプトで処理することもあるかと思います。やはり絵文字の判定は必要だと考えます。マルチバイトや制御コードを判別する必要はないので正規表現で判別できます。


Ezweb端末の絵文字が存在するか確認する関数

<?php
/**
 * function eemoji_in ( $str )
 *
 * 機  能:文字列に Ezweb端末の絵文字が含まれているか確認する
 * 引  数:$str  = 文字列
 * 戻り値:true  = 絵文字あり
 *         false = 絵文字なし
 */

function eemoji_in ( $str )
{
    if (preg_match("/<img\s+(icon|localsrc)\s*=\s*\"?[0-9]+\"?\s*\/*>/i", $str)) {
        return true;
    } else {
        return false;
    }
}
?>

EZweb端末の絵文字を削除する

<?php
/**
 * function eemoji_delet ( $str )
 *
 * 機  能:EZweb端末の絵文字を削除する
 * 引  数:$str  = 文字列
 * 戻り値:削除後の文字列
 */

function eemoji_delet ( $str )
{
    $str = preg_split("/<img\s+(icon|localsrc)\s*=\s*\"?[0-9]+\"?\s*\/*>/i", $str);
    return inplode('', $str);
}
?>


絵文字の相互変換

各端末によって絵文字を実現する手法が異なりますので、関数を使って「一発変換!」とはいかないようです。そこで各端末ごとに1対1で対応する絵文字テーブルを作って、絵文字を置き換える処理を実現してみようと思います。

[2003-11-02] 絵文字テーブルも含め仕様の見直しを行ってきましたが、端末の進化にスキルが追いつきませんでした。これまでココに置いていた「絵文字の相互変換」は動作不安定であったため封印いたしました。
また絵文字の相互変換は PHPで対処が必要な場面も少なくなりましたので、携帯端末はこれにて終了「未完」のままといたします。




category: 携帯端末 積極的なスパム投稿対策 Parse error ゼロで始まるPHP
PHP Note
ページの一番上へ
twitterでつぶやく Googleグックマークに登録 Yahooグックマークに登録 livedoorクリップに登録 @niftyクリップに登録 はてなブックマークに登録 deliciousに登録 Buzzurlに登録 FC2ブックマークに登録
最近更新したNote
よく読まれている記事
Yahoo Search

最近更新された掲示板トピックス
PHPマニュアル
今日のブックマーク
PHPマニュアル関数検索
関数名を入力し検索ボタンをクリック↑