[Utility.php] 携帯電話を判別する。IPアドレスから。【確定版】
篠原 隆司
アフィリエイト広告を利用しています
このページの内容が役に立ったら X (旧twitter) でフォローして頂けると励みになります
挨拶や報告は無しで大丈夫です
昨日、[Utility.php] 携帯電話を判別する。IPアドレスから。 で、コードを掲載したのだけど、やっぱり気に入らない箇所があるので、書き直した。
昨日の記事と重複する内容は省略するので、昨日の記事と合わせてお読み下さい。
変更した箇所
- IPアドレス帯域を手動更新してたのを、各webサイトから自動取得するようにした
- 生成するPHPコードをスリム化した。(263行→188行に)
- テストコードを追加した。
- PHPコードを生成するコードをclass化した。(※)
(※) システムに組み込んで本格的に使う箇所じゃないので、わざわざclassにする必要もないと思う。ブログに掲載するために、public と private の関係(functionのスコープ)なんかを明示したかっただけなので。
下記のコードを実行するとこのように出力されます。
生成された【 isMobile 】関数を、お使いのシステムにコピーして使用します。
$this->carriers = array( array( "carrier" => self::cc_return_value_docomo , "uri" => "http://www.nttdocomo.co.jp/service/imode/make/content/ip/" , "pattern" => "/<li>([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2})</li>/" ) , array( "carrier" => self::cc_return_value_au , "uri" => "http://www.au.kddi.com/ezfactory/tec/spec/ezsava_ip.html" , "pattern" => "/<td><div class="TableText">([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3})</div></td>s+<td><div class="TableText">(/[0-9]{1,2})</div></td>/" ) , array( "carrier" => self::cc_return_value_yahoo , "uri" => "http://creation.mb.softbank.jp/web/web_ip.html" , "pattern" => "/<td bgcolor="#eeeeee"> ([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}/[0-9]{1,2})</td>/" ) ); } /* * デスクトラクタ */ public function __destruct(){} /* * PHPコードを取得する */ public function getPhpCode() { // IPアドレス帯域の配列 $arrCidr = array(); foreach ($this->carriers as $ca){ if (($arr = $this->getIpRangeFromUri($ca["carrier"], $ca["uri"], $ca["pattern"])) === false){ return 'load error : ' . $ca["carrier"] . ' site' . C_LF; } foreach ($arr as $ar){ array_push($arrCidr, $ar); } } // IPアドレスの最小値で昇順にソート $func = create_function('$va, $vb' , ' $a = $va[0]; $b = $vb[0]; if ($a == $b) return 0; return ($a < $b) ? -1 : 1;'); usort($arrCidr, $func); // IPアドレス範囲が連続する箇所を連結して配列を作り直す $list = array(); $cnt = count($arrCidr); $prev = array(0, 0, 'none', '0.0.0.0/32'); $j = 0; for ($i = 0; $i getCode($list, $harf, 0, $upper, 0); } /* * 携帯電話会社がIPアドレス帯を公開しているURIからリストを取得 */ private function getIpRangeFromUri($carrier, $uri, $pattern){ $retArr = array(); $html = file_get_contents($uri); $html = mb_convert_encoding($html, "utf-8", "utf-8,sjis,euc"); if (preg_match_all($pattern, $html, $regs)){ $cnt = count($regs[1]); for ($i = 0; $i getRangeAndValue($cidr, $carrier); array_push($retArr, $arr); } return $retArr; } return false; } /* * CIDRから、IPアドレスの上限・下限とその他を配列で返す */ private function getRangeAndValue($cidr, $carrier){ $buf = explode('/', $cidr); $start = sprintf('%u', ip2long($buf[0])); $end = $start; if (isset($buf[1])){ $end += $this->ipRange($buf[1]) - 1; } return array( (float)$start , (float)$end , $carrier , $cidr ); } /* * IPアドレスの範囲の個数を返す */ private function ipRange($range){ if ($range > 32){ return 0; } else if ($range < 0){ return 0; } else { return pow(2, (32 - $range)); } } /* * IPアドレスを二分探索する条件式を作る */ private function getCode(&$list, $harf, $lower, $upper, $kaisou, $elseif = false){ $ret = ''; // 階層に合わせて、行の先頭にタブ文字を挿入 $tab = C_TAB2; for ($i = 0; $i = ' . $list[$harf][0] . '){' . ' // $list[' . $harf . ' to ' . $upper . ']' . C_LF; $ret .= $tab . C_TAB1 . 'if ($ip 0){ $n = ($n + ($n % 2)) / 2 + $harf2; $ret .= $tab . C_TAB1 . '} else '; $ret .= $this->getCode($list, $n, $harf2, $upper, $kaisou, true); } else if ($n == 0){ $ret .= $tab . C_TAB1 . '} else if ($ip >= ' . $list[$harf2][0] . '){' . C_LF; $ret .= $tab . C_TAB2 . 'if ($ip 0){ $n = ($n - ($n % 2)) / 2 + $lower; $ret .= $tab . '} else '; $ret .= $this->getCode($list, $n, $lower, $harf2, $kaisou-1, true); } if ( ! $elseif) $ret .= $tab . '}' . C_LF; return $ret; } } // 実行 $mobileIpRange = new mobileIpRange(); ?> <title>携帯電話のIPアドレス判別</title> <!-- body, textarea{ font-size : 12px; line-height:135%; font-family:"MS Pゴシック", sans-serif; } textarea{ width:600px; height:500px; } --> <h1>携帯電話のIPアドレス判別</h1> <form> <h2>テストコード</h2> <textarea><?php // array('期待する値', 'IPアドレス') $arrTest = array( array('other', '192.168.0.1') , array('docomo', '210.153.84.50') , array('au', '121.111.231.1') , array('au', '121.111.231.10') , array('au', '121.111.231.161') , array('au', '121.111.231.168') , array('yahoo', '123.108.237.243') , array('yahoo', '123.108.236.115') , array('yahoo', '123.108.237.31') , array('docomo', '124.146.174.10') , array('docomo', '124.146.174.123') , array('docomo', '124.146.175.52') , array('docomo', '124.146.175.48') ); echo '期待する値と戻り値が異なれば赤色で表示'; echo '<ul>'; foreach ($arrTest as $arr){ $ret = isMobile($arr[1]); echo '<li>' . $arr[0] . ' : ' . $arr[1] . ' : ' . $ret . '</li>'; } echo '</ul>'; ?></textarea> <h2>判別関数</h2> <textarea> /* * IPアドレスから、携帯キャリアを判別する * IPアドレス帯域は追加・削除されることがあります。 * 携帯電話各社の発表事項に注意してください。 * 生成日時 : */ function isMobile($ipAddress){ $ip = sprintf('%u', ip2long($ipAddress)); getPhpCode();?> return ''; } </textarea> </form>
php