絵文字の削除

あるサイトのPCサイトとスマホサイト作ってて、スマホで入力された絵文字を削除するという必要に迫られたのでメモ。理想は、

<input type="password">

の時みたいに、絵文字のキーボードを利用不可にして、絵文字を入力できないようにすることだけど。できないっぽい?
ガラケーで使われてる絵文字と、スマホで使われてる絵文字は仕組みが違うのかな?その辺のことはよく分かってないけど、とりあえずiOS6Androidに関していうと、「http://www.unicode.org/~scherer/emoji4unicode/snapshot/full.html」の

が使われてるそうだ。「携帯絵文字変換ライブラリ HTML_Emoji - libemoji.com」というライブラリを

<?php
  // 数値文字参照の絵文字を UTF-8 の絵文字に変換
  $text = $emoji->filter($text, array('DecToUtf8', 'HexToUtf8'));
  // $text に含まれている、3キャリアの UTF-8 の絵文字を削除
  $text = $emoji->removeEmoji($text);
?>

って使うと、iOSの絵文字は消えてくれた。これはガラケーの絵文字を削除するためのものなのかな?よくわからん。消えてくれたからいいや。
一方、Androidで使われているのはGoogle定義の絵文字だからか(?)消えてくれなかった。ってことでCakePHP(1.2.8)のcomponent書いた。

<?php
class DelemojiComponent extends Object
{
  // 1桁の16進数を、4桁の2進数へ変換する
  function toStrBin($strHex) {
    $int = intval($strHex, 16);
    $result = sprintf('%04b', $int);
    return $result;
  }

  // 4桁の2進数を1桁の16進数へ変換する
  function toStrHex($strBin) {
    $int = intval($strBin, 2);
    $result = sprintf('%1X', $int);
    return $result;
  }

  // utf8をunicodeへ変換する
  function toStrUnicode($strUtf8) {
    $len = mb_strlen($strUtf8);
    $b = '';
    // 16進数1文字を2進数4bitへ変換
    for ($i = 0; $i < $len; $i++) {
      $b .= $this->toStrBin($strUtf8[$i]);
    }

    $strUnicodeBin = '';
    $byte = $len / 2;
    $unicodeByte;
    if ($byte == 1) {
      // 1バイト文字
      // unicodeのコードポイントは2バイト: 00000000, 0xxxxxxx
      $unicodeByte = 2;
      $strUnicodeBin = '00000000' . $b;
    } else if ($byte == 2) {
      // 2バイト文字
      // unicodeのコードポイントは2バイト: 00000xxx, xxyyyyyy
      $unicodeByte = 2;
      $strUnicodeBin = '00000' . mb_substr($b, 3, 5) . mb_substr($b, 10, 6);
    } else if ($byte == 3) {
      // 3バイト文字
      // unicodeのコードポイントは2バイト: xxxxyyyy, yyzzzzzz
      $unicodeByte = 2;
      $strUnicodeBin = mb_substr($b, 4, 4) . mb_substr($b, 10, 6) . mb_substr($b, 18, 6);
    } else {
      // 4バイト文字
      // unicodeのコードポイントは3バイト: 000wwwxx, xxxxyyyy, yyzzzzzzz
      $unicodeByte = 3;
      $strUnicodeBin = '000' . mb_substr($b, 5, 3) . mb_substr($b, 10, 6) . mb_substr($b, 18, 6) . mb_substr($b, 26, 6);
    }

    // 16進表現に直す
    $strUnicodeHex = '';
    for ($i = 0; $i < $unicodeByte * 2; $i++) {
      $s = mb_substr($strUnicodeBin, $i * 4, 4);
      $strUnicodeHex .= $this->toStrHex($s);
    }
    return $strUnicodeHex;
  }

  // google定義の絵文字を削除する
  function removeGoogleCharCode($str) {

    // まず、数値文字参照形式のgoogle独自のコードを削除しておく。
    // 正規表現で表わすと &#xFE[0-9a-fA-F]{3}; となる。
    $removedCharRef = mb_ereg_replace('&#xFE[0-9a-fA-F]{3};', '', $str);

    // 以降では、数値文字参照ではなく、UTF-8のバイト列として表わされた絵文字を削除する。
    $hex = bin2hex($removedCharRef);
    $length = mb_strlen($hex);
    $maxByte = 4;  // 最大4バイト
    $offset = 0;
    $result = '';

    while ($offset < $length) {

      $head = $hex[$offset] . $hex[$offset + 1];
      $dec = base_convert($head , 16, 10);
      $byte = 0;
      $skip = false;
      if (240 <= $dec) {
        // 4バイト文字: 1バイト目が1111 0xxx
        $byte = 4;
      } else if (224 <= $dec) {
        // 3バイト文字: 1バイト目が1110 xxxx
        $byte = 3;
      } else if (192 <= $dec) {
        // 2バイト文字: 1バイト目が110x xxxx
        $byte = 2;
      } else {
        // 1バイト文字: 1バイト目が0xxx xxxx
        $byte = 1;
      }

      $b = '';
      for ($i = 0; $i < $byte; $i++) {
        $b .= ($hex[$offset + (2 * $i)] . $hex[$offset + (2 * $i + 1)]);
      }

      // 削除対象かどうか調べる
      if ($byte == 4) {
        $unicode = $this->toStrUnicode($b);
        // UTF-8が4バイトだと、unicodeは3バイトなので6文字
        if ($unicode[0] === '0' &&
          $unicode[1] === 'F' &&
          $unicode[2] === 'E') {
          // コードポイントが 0FE000 以降は、googleの絵文字コードなので削除
          $skip = true;  
        }
      }

      if (!$skip) {
        // この文字は必要なので追加
        $result .= $b;
      }
      $offset += ($byte * 2);
    }

    $result = pack('H*', $result);
    return $result;
  }
} 
?>

これを、

<?php
class HogeController extends AppController {
  var $components = array('Delemoji');

  // ... 中略 ...

  function doSomething () {
    // ... 略 ...
    $text = $this->Delemoji->removeGoogleCharCode($text);
    // ... 略 ...
  }

?>

みたいに使うと、消えるんじゃないかなー。クソ効率悪いからあんまり長い文字列食わせると時間かかるかも。