EmojiHelper - キャリアを意識せずに絵文字を出力できるCakePHPのHelperクラス

アシアル亀本さんが公開している携帯絵文字JSONデータを使って、キャリアを意識せずに同じような絵文字を表示します。

たとえば、下記のようなViewをDoCoMoの携帯から見ると、number*1が100のDoCoMoの絵文字(猫)を出力します。

<?php echo $emoji->d(101); ?>

同様に、SoftBankの携帯から見るとnumberが79の絵文字(猫)が、auの携帯から見るとnumberが251の絵文字(猫)が表示されます。

DoCoMoなら指定した番号そのままの絵文字が、他キャリアではdocomo_convert.jsonを使って似たような絵文字に変換しているわけです。

ちなみにSoftBankをベースとしたいなら

<?php echo $emoji->s(number); ?>

auをベースとしたいなら

<?php echo $emoji->a(number); ?>

とかするとよいです。ただ、聞くところによると*23キャリアの中でDoCoMoがいちばん絵文字数が少ないらしいので、3キャリアで表示をだいたい同じ風にしたいのならばとりあえず$emoji->d(number)としておくべきかもしれません。

何らかの理由で自動変換させたくない場合は、Viewの先頭で

<?php $emoji->auto_convert = false; ?>

とするか、出力時に

<?php $emoji->d(number, true); ?>

としてください。

指定したnumberの絵文字が存在しない場合や、変換先キャリアに対応する絵文字が無い場合は$emoji->unknown_charを代わりに出力します。デフォルトは下駄(〓)です。

ちなみに判別しているのはキャリアだけで、携帯電話の世代は全く見ていません。ので、自動変換先の絵文字が本当にその携帯電話で表示できるかどうかは知りません。必要なら適当に書き足してください。

全くの無保証ですが、どうぞご自由にお使いください。

インストール

  1. 下記コードをemoji.phpなどの名前で保存し、CakePHPのapp/views/helpersディレクトリあたりに配置する
  2. アシアル亀本さんが公開している携帯絵文字JSONデータをダウンロードし、適当な場所(app/webroot/filesとか)に配置する
  3. emoji.phpのEMOJI_JSON_DIR定数の値に、先ほど絵文字JSONデータを配置したディレクトリのパスを定義する。このとき、値の末尾はパス区切り文字で終わるようにする。

以下ソース。

ソースコード

<?php
//
// 携帯電話向け絵文字出力ヘルパー(for DoCoMo/Softbank/au) v1.0.0
//

// History
// [2008/01/31][1.0.0]公開

// TODO
// ・同キャリアでの世代間絵文字変換チェック


// 絵文字JSONデータ(http://blog.asial.co.jp/330)が配置されているパス
// 末尾にパス区切り文字を含む形で定義
define('EMOJI_JSON_DIR', 'path/to/json/');

// キャリアを示す定数
define('EMOJI_CARRIER_DOCOMO', 0);   // DoCoMo
define('EMOJI_CARRIER_SOFTBANK', 1); // SoftBank
define('EMOJI_CARRIER_AU', 2);       // au
define('EMOJI_CARRIER_MAX', 3);      // 最大数
define('EMOJI_CARRIER_UNKNOWN', 9);  // 不明(PCなど)


class EmojiHelper extends Helper {
    // 現在のキャリア
    var $current_carrier = EMOJI_CARRIER_UNKNOWN;
    
    // 現在のキャリアに応じて絵文字を変換するか否か
    var $auto_convert = true;
    
    // 現在のキャリアが不明な場合や、キャリア間変換が不能な場合に返す文字
    var $unknown_char = '';
    
    // 絵文字テーブル
    var $emoji = array();
    
    // 変換テーブル
    var $convert = array();
    
    // キャリア定数と名前との関連づけ
    var $convert_str = array(
        EMOJI_CARRIER_DOCOMO => 'docomo',
        EMOJI_CARRIER_SOFTBANK => 'softbank',
        EMOJI_CARRIER_AU => 'ezweb',
    );
    
    /*
     * PHP4用コンストラクタ
     */
    function EmojiHelper() {
        $this->__construct();
    }
    
    /*
     * PHP5用コンストラクタ
     */
    function __construct() {
        // キャリア判別
        $agent = $_SERVER['HTTP_USER_AGENT']; 
        if (ereg("^DoCoMo", $agent)) {
            // DoCoMo
            $this->current_carrier = EMOJI_CARRIER_DOCOMO;
        } elseif (ereg("^J-PHONE|^Vodafone|^SoftBank|^Vemulator|^Semulator", $agent)) {
            // SoftBank
            $this->current_carrier = EMOJI_CARRIER_SOFTBANK;
        } elseif (ereg("^UP.Browser|^KDDI", $agent)) {
            // au
            $this->current_carrier = EMOJI_CARRIER_AU;
        } else {
            // その他(PC等)
            $this->current_carrier = EMOJI_CARRIER_UNKNOWN;
        }
        
        // 絵文字テーブル・変換テーブルの読み込み
        for ($i = EMOJI_CARRIER_DOCOMO; $i < EMOJI_CARRIER_MAX; $i++) {
            $json = file_get_contents(EMOJI_JSON_DIR . $this->convert_str[$i] . '_convert.json');
            $this->convert[$i] = json_decode($json, true);
            $json = file_get_contents(EMOJI_JSON_DIR . $this->convert_str[$i] . '_emoji.json');
            $this->emoji[$i] = json_decode($json, true);
        }
    }
    
    /*
     * 指定したキャリアの絵文字を出力します
     * $carrier : キャリア定数(EMOJI_CARRIER_*)
     * $number : 指定キャリアの絵文字番号
     * $force : 真の時、現在のキャリアにかかわらず強制的に指定キャリアの絵文字を出力する
     */
    function out($carrier, $number, $force = false) {
        $ret = '';
        
        // 自動変換フラグが有効であるとき現在のキャリア用に絵文字番号を変換
        // (ただし、現在のキャリアが不明な場合と$force == trueの場合を除く)
        if (!$force && $this->auto_convert && $this->current_carrier != $carrier && $this->current_carrier != EMOJI_CARRIER_UNKNOWN) {
            if (array_key_exists($number, $this->convert[$carrier][$this->convert_str[$carrier]])) {
                $number = $this->convert[$carrier][$this->convert_str[$carrier]][$number][$this->convert_str[$this->current_carrier]];
                $carrier = $this->current_carrier;
            } else {
                // 変換先絵文字が見つからないので
                // 不明キャリア扱いとする
                $carrier = EMOJI_CARRIER_UNKNOWN;
            }
        } else {
            // 表示しようとしている絵文字の存在チェック
            if (!array_key_exists($number, $this->emoji[$carrier][$this->convert_str[$carrier]])) {
                // 無いため不明キャリア扱いとする
                $carrier = EMOJI_CARRIER_UNKNOWN;
            }
        }
        
        switch ($carrier) {
            case EMOJI_CARRIER_DOCOMO:
                $code = $this->emoji[EMOJI_CARRIER_DOCOMO][$this->convert_str[EMOJI_CARRIER_DOCOMO]][$number]['sjis'];
                $code1 = substr($code, 0, 2);
                $code2 = substr($code, 2, 2);
                $ret = pack('C*', hexdec($code1), hexdec($code2));
                break;
            case EMOJI_CARRIER_SOFTBANK:
                $code = $this->emoji[EMOJI_CARRIER_SOFTBANK][$this->convert_str[EMOJI_CARRIER_SOFTBANK]][$number]['webcode'];
                $code1 = substr($code, 0, 2);
                $code2 = substr($code, 2, 2);
                $ret = pack('C*', hexdec('1b'), ord('$'), hexdec($code1), hexdec($code2), hexdec('0f'));
                break;
            case EMOJI_CARRIER_AU:
                $ret = '<img localsrc="' . $number . '" />';
                break;
            case EMOJI_CARRIER_UNKNOWN:
            default:
                $ret = $this->unknown_char;
        }
        
        return $ret;
    }
    
    /*
     * DoCoMoの絵文字を出力します
     * $number : DoCoMoの絵文字番号
     * $force : 真の時、現在のキャリアにかかわらず強制的にDoCoMoの絵文字を出力する
     */
    function docomo($number, $force = false) {
        return $this->output($this->out(EMOJI_CARRIER_DOCOMO, $number, $force));
    }
    function d($number, $force = false) {
        return $this->output($this->out(EMOJI_CARRIER_DOCOMO, $number, $force));
    }
    
    /*
     * SoftBankの絵文字を出力します
     * $number : SoftBankの絵文字番号
     * $force : 真の時、現在のキャリアにかかわらず強制的にSoftBankの絵文字を出力する
     */
    function softbank($number, $force = false) {
        return $this->output($this->out(EMOJI_CARRIER_SOFTBANK, $number, $force));
    }
    function s($number, $force = false) {
        return $this->output($this->out(EMOJI_CARRIER_SOFTBANK, $number, $force));
    }
    
    /*
     * auの絵文字を出力します
     * $number : auの絵文字番号
     * $force : 真の時、現在のキャリアにかかわらず強制的にauの絵文字を出力する
     */
    function au($number, $force = false) {
        return $this->output($this->out(EMOJI_CARRIER_AU, $number, $force));
    }
    function a($number, $force = false) {
        return $this->output($this->out(EMOJI_CARRIER_AU, $number, $force));
    }
}
?>

本当はちゃんとテストして機能もブラッシュアップしてから公開しようと思っていたのですが、今日ブクマでこういうものを見かけてしまい、分かっていたけどあえて見ないようにしていた車輪の再発明(しかも劣化している)感が閉じたまぶたを突き破らんばかりの勢いで噴出してきたため、あきらめ半分投げやり半分で公開することにしました。テキトーな動作確認はしているので多分動くでしょう。バグなどあったら教えてくれると赤面しながら直します。

まぁ、アレですよね。自分が欲しいと思ったコードは大抵すでに誰かが書いてますよね。素晴らしい世界。みんな創造性あふれすぎ。マジリスペクト。

*1:JSONデータのnumber

*2:携帯向けのページは作ったこと無いのです。これからチャレンジしてみようと奮闘中