クレジットカード番号から発行者検索機能実装
クレジットカード番号について
http://melfina.org/wiki/?%A5%AF%A5%EC%A5%B8%A5%C3%A5%C8%A5%AB%A1%BC%A5%C9%C8%D6%B9%E6
クレジットカード番号には法則があり、先頭6桁でカードの種類を識別、分類することができる。
先頭の6桁を銀行識別番号(Bank Identification Number、略称:BIN)ないしは発行者識別番号(Issuer Identification Number、略称:IIN)と呼び、この先頭6桁でカード発行会社(イシュア、issuer)が判るようになっている。
…らしい。
無料でクレジット番号から発行者を識別できる情報を提供してるサイト
Free BIN/IIN Lookup Web Service - binlist.net
下記のページから「archived/iin-user-contributions.csv」ファイルをダウンロードする。 github.com
DB構築
CREATE TABLE `mt_credit_card_iin`( `id` int(11) NOT NULL AUTO_INCREMENT, `iin` CHAR(6) NOT NULL, `card_brand` VARCHAR(64) NOT NULL, `card_sub_brand` VARCHAR(64), `card_type` VARCHAR(64) NOT NULL, `card_category` VARCHAR(64), `country_code` VARCHAR(128) NOT NULL, `bank_name` VARCHAR(128), `bank_url` VARCHAR(200), `bank_phone` VARCHAR(128), `bank_city` VARCHAR(64), PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
エンコードなどが原因で、MySQL上のINFILEコマンド実行時に最初の1行しか読み込めない場合、一度ファイルをエクセルで開いてからCSV形式で「名前を付けて保存」をすると直る。
mysql> LOAD DATA LOCAL INFILE 'C:\\util\\binlist-data-master\\binlist-data-master\\credit_card_iin.csv' -> INTO TABLE mt_credit_card_iin -> FIELDS TERMINATED BY ',' -> LINES TERMINATED BY '\r\n' -> (iin,card_brand,card_sub_brand,card_type,card_category,country_code,bank_name,bank_url,bank_phone,bank_city);
django rest frameworkでの実装例
クレジットカードの先頭の6桁の番号から発行者の情報を返す
Python
class CreditCardIinViewSet(viewsets.ViewSet): queryset = mt_credit_card_iin.objects.all() def list(self, request): iin_val = request.query_params.get('iin') if iin_val is not None and iin_val.isdigit() is True and 6 == len(iin_val) : if 0 is not mt_credit_card_iin.objects.filter(iin=iin_val).count(): iin_infos = mt_credit_card_iin.objects.filter(iin=iin_val)[:1] elif 0 is not mt_credit_card_iin.objects.filter(iin__startswith=iin_val[:4]).count(): iin_infos = mt_credit_card_iin.objects.filter(iin__startswith=iin_val[:4])[:1] else: return Response({'message': 'No results for {0}. Make sure you enter a valid BIN/IIN number.'.format(iin_val)}, status=status.HTTP_400_BAD_REQUEST) else: return Response({'message': 'No results for {0}. Make sure you enter a valid BIN/IIN number.'.format(iin_val)}, status=status.HTTP_400_BAD_REQUEST) serializer = CreditCardIinSerializer(iin_infos, many=True) serializer.data[0]['iin'] = iin_val return Response(serializer.data)
IPアドレス所在地検索機能の実装
一番最初にIPに紐付く地域情報DBを調べる
「ip address location database」でググるといくつかのサイトが確認できる。
調べた結果
調べてみると、IPから国~市情報までは無料提供もあるけど、細かい情報は大体有料な場合が多い。でも、機能の実装ならIP2Locationで提供しているLITE11で十分なのでこれをダウンロードしてみる。
IP2LocationはダウンロードページからDB構築手順も案内していて、色んな開発ケースに対してチュートリアルも提供しているので便利。
IP2LocationでIPアドレス検索用DB構築
IPv4
CREATE TABLE `mt_ip2location_db11`( `id` int(11) NOT NULL AUTO_INCREMENT, `ip_from` INT(10) UNSIGNED, `ip_to` INT(10) UNSIGNED, `country_code` CHAR(2), `country_name` VARCHAR(64), `region_name` VARCHAR(128), `city_name` VARCHAR(128), `latitude` DOUBLE, `longitude` DOUBLE, `zip_code` VARCHAR(30), `time_zone` VARCHAR(8), PRIMARY KEY (`id`), INDEX `idx_ip_from` (`ip_from`), INDEX `idx_ip_to` (`ip_to`), INDEX `idx_ip_from_to` (`ip_from`, `ip_to`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
IPv6
CREATE TABLE `mt_ip2location_db11_ipv6`( `id` int(11) NOT NULL AUTO_INCREMENT, `ip_from` DECIMAL(39,0) UNSIGNED NULL DEFAULT NULL, `ip_to` DECIMAL(39,0) UNSIGNED NOT NULL, `country_code` CHAR(2), `country_name` VARCHAR(64), `region_name` VARCHAR(128), `city_name` VARCHAR(128), `latitude` DOUBLE, `longitude` DOUBLE, `zip_code` VARCHAR(30), `time_zone` VARCHAR(8), PRIMARY KEY (`id`), INDEX `idx_ip_from` (`ip_from`), INDEX `idx_ip_to` (`ip_to`), INDEX `idx_ip_from_to` (`ip_from`, `ip_to`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
IPv4
mysql> LOAD DATA LOCAL INFILE 'C:\\util\\ip-address\\IP2LOCATION-LITE-DB11.CSV\\IP2LOCATION-LITE-DB11.CSV' -> INTO TABLE mt_ip2location_db11 -> FIELDS TERMINATED BY ',' -> ENCLOSED BY '"' -> LINES TERMINATED BY '\r\n' -> (ip_from,ip_to,country_code,country_name,region_name,city_name,latitude,longitude,zip_code,time_zone); Query OK, 4044940 rows affected (56.48 sec) Records: 4044940 Deleted: 0 Skipped: 0 Warnings: 0
IPv6
mysql> LOAD DATA LOCAL INFILE 'C:\\util\\ip-address\\IP2LOCATION-LITE-DB11.IPV6.CSV\\IP2LOCATION-LITE-DB11.IPV6.CSV' -> INTO TABLE mt_ip2location_db11_ipv6 -> FIELDS TERMINATED BY ',' -> ENCLOSED BY '"' -> LINES TERMINATED BY '\r\n' -> (ip_from,ip_to,country_code,country_name,region_name,city_name,latitude,longitude,zip_code,time_zone); Query OK, 4366556 rows affected, 3 warnings (1 min 9.98 sec) Records: 4366556 Deleted: 0 Skipped: 0 Warnings: 3
DBが準備できれば後はSELECTするだけなのでここまで。
※DBからIPv6の値を元に検索する方法が現在チュートリアルには存在してない、且つPythonのライブラリが存在するため、Pythonで開発する場合はライブラリを利用して実装することをお勧めする。
django rest frameworkでの実装例
IP情報からIPv4かIPv6か判別し、地域情報を返す
(IPv6はDB格納、IPv6はライブラリ(BIN)をプロジェクト内に格納)
Python
class Ip2locationViewSet(viewsets.ViewSet): queryset = mt_ip2location_db11.objects.all() def list(self, request): ip_val = request.query_params.get('ip') if ip_val is not None: try: ipnet = ipaddress.ip_network(ip_val) if ipnet.version == 4: ipv4_val = int(ipaddress.IPv4Address(ip_val)) ip_infos = mt_ip2location_db11.objects.filter(ip_to__gte=ipv4_val).order_by('ip_to')[:1] elif ipnet.version == 6: IP2LocObj = IP2Location.IP2Location(); IP2LocObj.open(os.path.join("data","IP2LOCATION-LITE-DB11.IPV6.BIN")); ip_infos = IP2LocObj.get_all(ip_val); ipv6_result = OrderedDict() ipv6_result['country_code'] = ip_infos.country_short ipv6_result['country_long'] = ip_infos.country_long ipv6_result['region_name'] = ip_infos.region ipv6_result['city_name'] = ip_infos.city ipv6_result['latitude'] = str(ip_infos.latitude) ipv6_result['longitude'] = str(ip_infos.longitude) ipv6_result['zip_code'] = ip_infos.zipcode ipv6_result['time_zone'] = ip_infos.timezone ipv6_result['ip'] = ip_val return Response([ipv6_result]) else: ip_infos = mt_ip2location_db11.objects.all()[:1] return Response(ip_infos, status=status.HTTP_404_NOT_FOUND) except ValueError: return Response({'message': 'IP形式が正しくありません。', 'ip': ip_val}, status=status.HTTP_400_BAD_REQUEST) else: return Response({'message': 'IPアドレスの情報がありません。', 'ip': ip_val}, status=status.HTTP_400_BAD_REQUEST) serializer = Ip2locationSerializer(ip_infos, many=True) serializer.data[0]['ip'] = ip_val return Response(serializer.data)