PHPで高速に携帯ゲートウェイのIPから携帯キャリアを判別する

[追記]id:hetimaに指摘された、32bitアーキテクチャでの問題を修正。大感謝。

携帯電話からのWebアクセスゲートウェイIPアドレスから、
携帯キャリアを判別したい場合がある。


通常は、id:tokuhiromによる
Net::CIDR::MobileJP(WWW::MobileCarrierJP)を使うといいと思う。

YAMLが出力されるので、さまざまな環境で利用ができるよ!


今回、PHPで携帯キャリアを判別したいと思ったんだけど、
PHPYAMLを読んでその中身をすべて検査するなんてやだいやだい!
と沸き立つような強い衝動が。


というわけで、cidr-mobilejpというPythonスクリプトを書いた。

各携帯キャリアのページからCIDR情報をスクレイピングして、
その情報を元に携帯キャリアを(たぶん高速に)判別するPHPスクリプトを出力します。


DoCoMoについてはメールゲートウェイなどの余計なIPアドレスが入っちゃってますが、
実害ないでしょう。


id:tomisimaが書いていたスクリプトを基に、
AirHPhone対応を施したりいろんな改造をしました。

パフォーマンスは計って遅かったら泣くから計らない。
ip2longが遅い可能性が大いにあるんだよなー…

特徴1: CIDRでは別箇表示されるが、隣接したIPアドレス領域の扱い

CIDRではサブネットマスクでの範囲指定しかできないため、
ip2longやinet_atonが返す数値が隣接していても
ばらばらに記載しなければいけない場合があります。


cidr-mobilejpでは隣接したIPアドレス領域をまとめることによって
判別処理の高速化を図っています。

特徴2: 二分探索

PHPのip2long()を用いてIPアドレス文字列を数値化し、
二分探索で携帯キャリアを判別するようにしています。

出力されたスクリプト

こんなスクリプトが出力されます。
以下のURLに出力されたスクリプトを置いておきます。

<?php
/*
This script is generated by scrape.py at 2010-07-27 17:53:08.
http://svn.coderepos.org/share/lang/python/cidr-mobilejp/trunk/scrape.py
*/
function ip2mobile($ip) {
  $n = sprintf('%u', ip2long($ip));

  if ($n < 1914044160) {
    if ($n < 1868151808) {
      if ($n < 1036427264) {
        if ($n < 1036419072) {
          if ($n < 1031078144) {
            if ($n >= 998712960 && $n <= 998713087) {
              return 'ezweb';
            }
          } else if ($n <= 1031078159) {
            return 'ezweb';
          } else {
            if ($n >= 1031078432 && $n <= 1031078447) {
              return 'ezweb';
            }
          }
        } else if ($n <= 1036421631) {
          return 'airhphone';
        } else {
          if ($n < 1036421888) {
            if ($n >= 1036421732 && $n <= 1036421735) {
              return 'airhphone';
            }
          } else if ($n <= 1036421895) {
            return 'airhphone';
          } else {
            if ($n < 1036422016) {
            } else if ($n <= 1036422063) {
              return 'airhphone';
            } else {
              if ($n >= 1036422144 && $n <= 1036423167) {
                return 'airhphone';
              }
            }
          }
        }
      } else if ($n <= 1036429055) {
        return 'airhphone';
      } else {
        if ($n < 1036803072) {
          if ($n < 1036449792) {
            if ($n >= 1036429312 && $n <= 1036431359) {
              return 'airhphone';
            }
          } else if ($n <= 1036451839) {
            return 'airhphone';
          } else {
            if ($n < 1036779520) {
            } else if ($n <= 1036779775) {
              return 'airhphone';
            } else {
              if ($n >= 1036780032 && $n <= 1036781439) {
                return 'airhphone';
              }
            }
          }
        } else if ($n <= 1036804095) {
          return 'airhphone';
        } else {
          if ($n < 1867943552) {
            if ($n >= 1867943232 && $n <= 1867943487) {
              return 'ezweb';
            }
          } else if ($n <= 1867943743) {
            return 'ezweb';
          } else {
            if ($n < 1867943872) {
            } else if ($n <= 1867943935) {
              return 'ezweb';
            } else {
              if ($n >= 1867944704 && $n <= 1867944735) {
                return 'ezweb';
              }
            }
          }
        }
      }
    } else if ($n <= 1868152831) {
      return 'docomo';
    } else {
      if ($n < 1913928192) {
        if ($n < 1913926656) {
          if ($n < 1913925888) {
            if ($n >= 1913925888 && $n <= 1913926143) {
              return 'airhphone';
            }
          } else if ($n <= 1913926399) {
            return 'airhphone';
          } else {
            if ($n < 1913926144) {
            } else if ($n <= 1913926655) {
              return 'airhphone';
            } else {
              if ($n >= 1913926400 && $n <= 1913926911) {
                return 'airhphone';
              }
            }
          }
        } else if ($n <= 1913927423) {
          return 'airhphone';
        } else {
          if ($n < 1913927424) {
            if ($n >= 1913927168 && $n <= 1913927679) {
              return 'airhphone';
            }
          } else if ($n <= 1913927935) {
            return 'airhphone';
          } else {
            if ($n < 1913927680) {
            } else if ($n <= 1913928191) {
              return 'airhphone';
            } else {
              if ($n >= 1913927936 && $n <= 1913928447) {
                return 'airhphone';
              }
            }
          }
        }
      } else if ($n <= 1913928703) {
        return 'airhphone';
      } else {
        if ($n < 1913929472) {
          if ($n < 1913928704) {
            if ($n >= 1913928448 && $n <= 1913928959) {
              return 'airhphone';
            }
          } else if ($n <= 1913929215) {
            return 'airhphone';
          } else {
            if ($n < 1913928960) {
            } else if ($n <= 1913929471) {
              return 'airhphone';
            } else {
              if ($n >= 1913929216 && $n <= 1913929727) {
                return 'airhphone';
              }
            }
          }
        } else if ($n <= 1913929983) {
          return 'airhphone';
        } else {
          if ($n < 1913929984) {
            if ($n >= 1913929728 && $n <= 1913930239) {
              return 'airhphone';
            }
          } else if ($n <= 1913930495) {
            return 'airhphone';
          } else {
            if ($n < 1913930240) {
            } else if ($n <= 1913930751) {
              return 'airhphone';
            } else {
              if ($n >= 1913930496 && $n <= 1913930751) {
                return 'airhphone';
              }
            }
          }
        }
      }
    }
  } else if ($n <= 1914044191) {
    return 'airhphone';
  } else {
    if ($n < 3414870784) {
      if ($n < 2037376768) {
        if ($n < 1990165664) {
          if ($n < 1989727936) {
            if ($n >= 1914044160 && $n <= 1914044191) {
              return 'airhphone';
            }
          } else if ($n <= 1989727999) {
            return 'ezweb';
          } else {
            if ($n >= 1990165248 && $n <= 1990165375) {
              return 'ezweb';
            }
          }
        } else if ($n <= 1990165695) {
          return 'ezweb';
        } else {
          if ($n < 1990165952) {
            if ($n >= 1990165760 && $n <= 1990165887) {
              return 'ezweb';
            }
          } else if ($n <= 1990166015) {
            return 'ezweb';
          } else {
            if ($n < 2037375744) {
            } else if ($n <= 2037375871) {
              return 'ezweb';
            } else {
              if ($n >= 2037375904 && $n <= 2037375935) {
                return 'ezweb';
              }
            }
          }
        }
      } else if ($n <= 2037376895) {
        return 'ezweb';
      } else {
        if ($n < 2098989824) {
          if ($n < 2070736352) {
            if ($n >= 2070736128 && $n <= 2070736159) {
              return 'softbank';
            }
          } else if ($n <= 2070736383) {
            return 'softbank';
          } else {
            if ($n < 2089987584) {
            } else if ($n <= 2089988095) {
              return 'docomo';
            } else {
              if ($n >= 2098987008 && $n <= 2098989311) {
                return 'airhphone';
              }
            }
          }
        } else if ($n <= 2098991615) {
          return 'airhphone';
        } else {
          if ($n < 3405602816) {
            if ($n >= 3404050432 && $n <= 3404051455) {
              return 'docomo';
            }
          } else if ($n <= 3405602847) {
            return 'softbank';
          } else {
            if ($n < 3405603040) {
            } else if ($n <= 3405603071) {
              return 'softbank';
            } else {
              if ($n >= 3414864896 && $n <= 3414865407) {
                return 'docomo';
              }
            }
          }
        }
      }
    } else if ($n <= 3414871039) {
      return 'docomo';
    } else {
      if ($n < 3548299392) {
        if ($n < 3534288384) {
          if ($n < 3532785600) {
            if ($n >= 3532169472 && $n <= 3532169727) {
              return 'docomo';
            }
          } else if ($n <= 3532785663) {
            return 'softbank';
          } else {
            if ($n < 3533263872) {
            } else if ($n <= 3533264127) {
              return 'docomo';
            } else {
              if ($n >= 3533264384 && $n <= 3533264895) {
                return 'docomo';
              }
            }
          }
        } else if ($n <= 3534288895) {
          return 'airhphone';
        } else {
          if ($n < 3534684544) {
            if ($n >= 3534314496 && $n <= 3534316543) {
              return 'airhphone';
            }
          } else if ($n <= 3534684671) {
            return 'softbank';
          } else {
            if ($n < 3538321632) {
            } else if ($n <= 3538321647) {
              return 'ezweb';
            } else {
              if ($n >= 3541231616 && $n <= 3541233663) {
                return 'airhphone';
              }
            }
          }
        }
      } else if ($n <= 3548299519) {
        return 'airhphone';
      } else {
        if ($n < 3682439424) {
          if ($n < 3681328384) {
            if ($n >= 3681288704 && $n <= 3681292287) {
              return 'airhphone';
            }
          } else if ($n <= 3681328511) {
            return 'ezweb';
          } else {
            if ($n < 3681328640) {
            } else if ($n <= 3681328671) {
              return 'ezweb';
            } else {
              if ($n >= 3681328680 && $n <= 3681328687) {
                return 'ezweb';
              }
            }
          }
        } else if ($n <= 3682439551) {
          return 'ezweb';
        } else {
          if ($n < 3682440192) {
            if ($n >= 3682439680 && $n <= 3682439695) {
              return 'ezweb';
            }
          } else if ($n <= 3682440319) {
            return 'ezweb';
          } else {
            if ($n < 3715563520) {
            } else if ($n <= 3715566079) {
              return 'airhphone';
            } else {
              if ($n >= 3724885632 && $n <= 3724886015) {
                return 'ezweb';
              }
            }
          }
        }
      }
    }
  }
  return 'pc';
}
?>

まとめ

PerlとかPythonとかPHPが入り混じってよくわかんね(笑)と思われると予想しますが、
出力されたPHPのソースはコピペで使えます。
是非ご利用くださーい。