[PHP][opensource]中国身份证号码识别类

idcard类源代码:

  1. <?php
  2.  
  3. /**
  4. * file name: $RCSfile: class.idcard.inc.php,v $
  5. * file source: $Source: http://www.liqintao.net/blog,v $
  6. * description: 中国身份证号码识别类
  7. * create time: 2006-3-6 15:54:03
  8. * @version $Id: class.idcard.inc.php,v 1.2 2006/03/19 15:06:06 Sandy Lee Exp $
  9. * @copyright Copyright (c) 2005-2006, Sandy Lee(Leeqintao@gmail.com)
  10. * @author Sandy Lee
  11. */
  12.  
  13. define('IDC_INDEX_CAT', 0);            // 号码类别索引名称
  14. define('IDC_INDEX_NUM_ORIGIN', 1);    // 号码原始数据索引名称
  15. define('IDC_INDEX_NUM_18', 2);        // 号码对应18位编号索引名称
  16. define('IDC_INDEX_ADDR', 3);        // 号码对应地址信息索引名称
  17. define('IDC_INDEX_BIRTH', 4);        // 号码对应生日信息索引名称
  18. define('IDC_INDEX_SEX', 5);            // 号码对应性别信息索引名称
  19.  
  20. define('IDC_FLAG_INVALID', 0);        // 无效号码
  21. define('IDC_FLAG_OLD', 1);            // 15位旧号码
  22. define('IDC_FLAG_NEW', 2);            // 18位新号码
  23.  
  24. define('IDC_SEX_UNKNOWN', 0);        // 性别未知
  25. define('IDC_SEX_MALE', 1);            // 男性
  26. define('IDC_SEX_FEMALE', 2);        // 女性
  27.  
  28. class idcard{
  29. /**
  30. * @var array 经过解析的信息数组:
  31. */
  32. var $arr_info;
  33.  
  34. /**
  35. * 构造函数
  36. */
  37. function idcard()
  38. {
  39. $this->flag_cat = 0;
  40. $this->arr_info = array (
  41. IDC_INDEX_CAT => IDC_FLAG_INVALID,
  42. IDC_INDEX_NUM_ORIGIN => '',
  43. IDC_INDEX_NUM_18 => '',
  44. IDC_INDEX_ADDR => array(0 => '', 1 => '', 2 => ''),    // 省/市/区县
  45. IDC_INDEX_BIRTH => array(0 => '', 1 => '', 2 => ''),// 年/月/日
  46. IDC_INDEX_SEX => IDC_SEX_UNKNOWN,
  47. );
  48. }
  49.  
  50. /**
  51. * 解析身份证号码
  52. *
  53. * @param string $num 传入15位或18位身份证的编码
  54. */
  55. function parse_idc($num)
  56. {
  57. if (preg_match("/^/d{15}$|^/d{18}$|^/d{17}x$/", $num) == 0)
  58. {
  59. $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID;    // 设置无效号码标志
  60. return $this->arr_info;
  61. }
  62.  
  63. $this->arr_info[IDC_INDEX_NUM_ORIGIN] = $num;    //
  64.  
  65. if (strlen($num) == 15)    // 旧15位编码
  66. {
  67. $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_OLD;    //
  68. $this->arr_info[IDC_INDEX_NUM_18] = $this->update15($num);
  69. }
  70.  
  71. if (strlen($num) == 18) // 新18位编码
  72. {
  73. $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_NEW;    //
  74. $this->arr_info[IDC_INDEX_NUM_18] = $num;
  75. }
  76.  
  77. if (!$this->verify_num($this->arr_info[IDC_INDEX_NUM_18]))    // 判断编码是否有效
  78. {
  79. $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID;    // 设置无效号码标志
  80. return $this->arr_info;
  81. }
  82.  
  83. $this->arr_info[IDC_INDEX_ADDR] = $this->parse_addr($this->arr_info[IDC_INDEX_NUM_18]);
  84. $this->arr_info[IDC_INDEX_BIRTH] = $this->parse_birth($this->arr_info[IDC_INDEX_NUM_18]);
  85. $this->arr_info[IDC_INDEX_SEX] = $this->parse_sex($this->arr_info[IDC_INDEX_NUM_18]);
  86.  
  87. // 判断生日是否合理,是否大于当前时间
  88. if (checkdate($this->arr_info[IDC_INDEX_BIRTH][1], $this->arr_info[IDC_INDEX_BIRTH][2], $this->arr_info[IDC_INDEX_BIRTH][0]) == false)
  89. {
  90. $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID;    // 设置无效号码标志
  91. }
  92. elseif( strtotime($this->arr_info[IDC_INDEX_BIRTH][0]."/".$this->arr_info[IDC_INDEX_BIRTH][1]."/".$this->arr_info[IDC_INDEX_BIRTH][2]) > time())
  93. {
  94. $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID;    // 设置无效号码标志
  95. }
  96. return $this->arr_info;
  97. }
  98.  
  99. /**
  100. * 15位升级到18位
  101. *
  102. * @param string $num 传入15位旧身份证的编码
  103. * @return string 返回对应的18位新身份证编码
  104. */
  105. function update15($num)
  106. {
  107. if (strlen($num) != 15)
  108. {
  109. return '';
  110. }
  111.  
  112. // 如果身份证顺序码是996 997 998 999,这些是为百岁以上老人的特殊编码
  113. if (array_search(substr($num, 12, 3), array( 996 , 997 , 998 , 999 )) !== false)
  114. {
  115. $num = substr($num, 0, 6) . 18 . substr($num, 6, 9);
  116. }
  117. else
  118. {
  119. $num = substr($num, 0, 6) . 19 . substr($num, 6, 9);
  120. }
  121.  
  122. return $num.$this->cal_verify($num);
  123. }
  124.  
  125. /**
  126. * 识别地址码
  127. *
  128. * @param string $num 传入18位身份证的编码
  129. * @return array 地址信息,array(0 => '省', 1 => '市', 2 => '区(县)')
  130. */
  131. function parse_addr($num)
  132. {
  133. $arr_rtn = array(0 => '', 1 => '', 2 => '');    // 省/市/区县
  134.  
  135. if (strlen($num) != 18)
  136. {
  137. return $arr_rtn;
  138. }
  139. $file_data = dirname(__FILE__)."/area_code.dat";
  140. if (!file_exists($file_data))
  141. {
  142. return $arr_rtn;
  143. }
  144.  
  145. $h = fopen($file_data, "r");
  146.  
  147. $s1 = str_pad(substr($num, 0, 2), 6, "0", STR_PAD_RIGHT);
  148. $s2 = str_pad(substr($num, 0, 4), 6, "0", STR_PAD_RIGHT);
  149. $s3 = str_pad(substr($num, 0, 6), 6, "0", STR_PAD_RIGHT);
  150.  
  151. while (!feof ($h))
  152. {
  153. $buffer = fgets($h, 4096);
  154. $arr = explode(",", $buffer);
  155.  
  156. // 前两位
  157. if (strcmp($arr[0], $s1) == 0)
  158. {
  159. $arr_rtn[0] = $arr[1];
  160. }
  161. // 中间两位
  162. if (strcmp($arr[0], $s2) == 0)
  163. {
  164. $arr_rtn[1] = $arr[1];
  165. }
  166. // 末两位
  167. if (strcmp($arr[0], $s3) == 0)
  168. {
  169. $arr_rtn[2] = $arr[1];
  170. break;
  171. }
  172. }
  173.  
  174. fclose($h);
  175. return $arr_rtn;
  176. }
  177.  
  178. /**
  179. * 识别出生年月日
  180. *
  181. * @param string $num 传入18位身份证的编码
  182. * @return array 生日信息,array(0 => '年', 1 => '月', 2 => '日')
  183. */
  184. function parse_birth($num)
  185. {
  186. $arr_rtn = array(0 => '', 1 => '', 2 => '');    // 年/月/日
  187.  
  188. if (strlen($num) != 18)
  189. {
  190. return $arr_rtn;
  191. }
  192.  
  193. $arr_rtn[0] = substr($num, 6, 4);    // 年
  194. $arr_rtn[1] = substr($num, 10, 2);    // 月
  195. $arr_rtn[2] = substr($num, 12, 2);    // 日
  196.  
  197. return $arr_rtn;
  198. }
  199.  
  200. /**
  201. * 识别性别
  202. *
  203. * @param string $num 传入18位身份证的编码
  204. * @return int 返回男女标志
  205. */
  206. function parse_sex($num)
  207. {
  208. $rtn_sex = IDC_SEX_UNKNOWN;
  209. if (strlen($num) != 18)
  210. {
  211. return $rtn_sex;
  212. }
  213.  
  214. if (is_int(substr($num, 16, 1)/2))
  215. {
  216. $rtn_sex = IDC_SEX_FEMALE;    // 女
  217. }
  218. else
  219. {
  220. $rtn_sex = IDC_SEX_MALE;    // 男
  221. }
  222. return     $rtn_sex;
  223. }
  224.  
  225. /**
  226. * 生成校验码
  227. *
  228. * @param string $num 传入18位或者前17位身份证的编码
  229. * @return string 返回校验码
  230. */
  231. function cal_verify($num)
  232. {
  233. if (strlen($num) != 17)
  234. {
  235. if (strlen($num) == 18)
  236. {
  237. $num = substr($num, 0, 17);
  238. }
  239. else
  240. {
  241. return false;
  242. }
  243. }
  244.  
  245. // 加权因子
  246. $factor = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
  247.  
  248. // 校验码对应值
  249. $verify_number_list = array( 1 , 0 , X , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 );
  250. $checksum = 0;
  251. for ($i = 0; $i < strlen($num); $i++)
  252. {
  253. $checksum += substr($num, $i, 1) * $factor[$i];
  254. }
  255.  
  256. $mod = $checksum % 11;
  257. return $verify_number_list[$mod];
  258. }
  259.  
  260. /**
  261. * 验证18位新号码的有效性
  262. *
  263. * @param string $num 传入18位身份证号码
  264. * @return bool 验证成功:true|验证失败:false
  265. */
  266. function verify_num($num)
  267. {
  268. if (strlen($num) != 18)
  269. {
  270. return false;
  271. }
  272.  
  273. if (strcasecmp(substr($num, 17, 1), $this->cal_verify($num)) == 0)
  274. {
  275. return true;
  276. }
  277. else
  278. {
  279. return false;
  280. }
  281. }
  282. }
  283. ?>

调用方法示例:

  1. <?php
  2. require_once "class.idcard.inc.php";
  3. $code = "xxxxxxxxxx"; // 身份证号码
  4. $card = new idcard();
  5. $info = $card->parse_idc($code);
  6. $out = array();
  7.  
  8. $out[IDC_INDEX_NUM_ORIGIN] = $info[IDC_INDEX_NUM_ORIGIN];
  9. $out[IDC_INDEX_NUM_18] = $info[IDC_INDEX_NUM_18];
  10. switch ($info[IDC_INDEX_CAT])
  11. {
  12. case IDC_FLAG_INVALID:
  13. $out[IDC_INDEX_CAT] = "无效身份证号码";
  14. break;
  15. case IDC_FLAG_OLD:
  16. $out[IDC_INDEX_CAT] = "15位旧身份证号码";
  17. break;
  18. case IDC_FLAG_NEW:
  19. $out[IDC_INDEX_CAT] = "18位新身份证号码";
  20. break;
  21. default:
  22. $out[IDC_INDEX_CAT] = "无效身份证号码";
  23. }
  24.  
  25. $out[IDC_INDEX_ADDR] = $info[IDC_INDEX_ADDR][0].'.'.$info[IDC_INDEX_ADDR][1].'.'.$info[IDC_INDEX_ADDR][2];
  26. $out[IDC_INDEX_BIRTH] = $info[IDC_INDEX_BIRTH][0].''.$info[IDC_INDEX_BIRTH][1].''.$info[IDC_INDEX_BIRTH][2].'';
  27. switch($info[IDC_INDEX_SEX])
  28. {
  29. case IDC_SEX_UNKNOWN:
  30. $out[IDC_INDEX_SEX] = "未知";
  31. break;
  32. case IDC_SEX_MALE:
  33. $out[IDC_INDEX_SEX] = "";
  34. break;
  35. case IDC_SEX_FEMALE:
  36. $out[IDC_INDEX_SEX] = "";
  37. break;
  38. default:
  39. $out[IDC_INDEX_SEX] = "未知";
  40. }
  41. print_r($out);
  42.  
  43. ?>

------------------------------------------------------------------------------------------------------------------

未做过测试.....................................

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值