idcard类源代码:
- <?php
- /**
- * file name: $RCSfile: class.idcard.inc.php,v $
- * file source: $Source: http://www.liqintao.net/blog,v $
- * description: 中国身份证号码识别类
- * create time: 2006-3-6 15:54:03
- * @version $Id: class.idcard.inc.php,v 1.2 2006/03/19 15:06:06 Sandy Lee Exp $
- * @copyright Copyright (c) 2005-2006, Sandy Lee(Leeqintao@gmail.com)
- * @author Sandy Lee
- */
- define('IDC_INDEX_CAT', 0); // 号码类别索引名称
- define('IDC_INDEX_NUM_ORIGIN', 1); // 号码原始数据索引名称
- define('IDC_INDEX_NUM_18', 2); // 号码对应18位编号索引名称
- define('IDC_INDEX_ADDR', 3); // 号码对应地址信息索引名称
- define('IDC_INDEX_BIRTH', 4); // 号码对应生日信息索引名称
- define('IDC_INDEX_SEX', 5); // 号码对应性别信息索引名称
- define('IDC_FLAG_INVALID', 0); // 无效号码
- define('IDC_FLAG_OLD', 1); // 15位旧号码
- define('IDC_FLAG_NEW', 2); // 18位新号码
- define('IDC_SEX_UNKNOWN', 0); // 性别未知
- define('IDC_SEX_MALE', 1); // 男性
- define('IDC_SEX_FEMALE', 2); // 女性
- class idcard{
- /**
- * @var array 经过解析的信息数组:
- */
- var $arr_info;
- /**
- * 构造函数
- */
- function idcard()
- {
- $this->flag_cat = 0;
- $this->arr_info = array (
- IDC_INDEX_CAT => IDC_FLAG_INVALID,
- IDC_INDEX_NUM_ORIGIN => '',
- IDC_INDEX_NUM_18 => '',
- IDC_INDEX_ADDR => array(0 => '', 1 => '', 2 => ''), // 省/市/区县
- IDC_INDEX_BIRTH => array(0 => '', 1 => '', 2 => ''),// 年/月/日
- IDC_INDEX_SEX => IDC_SEX_UNKNOWN,
- );
- }
- /**
- * 解析身份证号码
- *
- * @param string $num 传入15位或18位身份证的编码
- */
- function parse_idc($num)
- {
- if (preg_match("/^/d{15}$|^/d{18}$|^/d{17}x$/", $num) == 0)
- {
- $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID; // 设置无效号码标志
- return $this->arr_info;
- }
- $this->arr_info[IDC_INDEX_NUM_ORIGIN] = $num; //
- if (strlen($num) == 15) // 旧15位编码
- {
- $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_OLD; //
- $this->arr_info[IDC_INDEX_NUM_18] = $this->update15($num);
- }
- if (strlen($num) == 18) // 新18位编码
- {
- $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_NEW; //
- $this->arr_info[IDC_INDEX_NUM_18] = $num;
- }
- if (!$this->verify_num($this->arr_info[IDC_INDEX_NUM_18])) // 判断编码是否有效
- {
- $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID; // 设置无效号码标志
- return $this->arr_info;
- }
- $this->arr_info[IDC_INDEX_ADDR] = $this->parse_addr($this->arr_info[IDC_INDEX_NUM_18]);
- $this->arr_info[IDC_INDEX_BIRTH] = $this->parse_birth($this->arr_info[IDC_INDEX_NUM_18]);
- $this->arr_info[IDC_INDEX_SEX] = $this->parse_sex($this->arr_info[IDC_INDEX_NUM_18]);
- // 判断生日是否合理,是否大于当前时间
- if (checkdate($this->arr_info[IDC_INDEX_BIRTH][1], $this->arr_info[IDC_INDEX_BIRTH][2], $this->arr_info[IDC_INDEX_BIRTH][0]) == false)
- {
- $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID; // 设置无效号码标志
- }
- elseif( strtotime($this->arr_info[IDC_INDEX_BIRTH][0]."/".$this->arr_info[IDC_INDEX_BIRTH][1]."/".$this->arr_info[IDC_INDEX_BIRTH][2]) > time())
- {
- $this->arr_info[IDC_INDEX_CAT] = IDC_FLAG_INVALID; // 设置无效号码标志
- }
- return $this->arr_info;
- }
- /**
- * 15位升级到18位
- *
- * @param string $num 传入15位旧身份证的编码
- * @return string 返回对应的18位新身份证编码
- */
- function update15($num)
- {
- if (strlen($num) != 15)
- {
- return '';
- }
- // 如果身份证顺序码是996 997 998 999,这些是为百岁以上老人的特殊编码
- if (array_search(substr($num, 12, 3), array( 996 , 997 , 998 , 999 )) !== false)
- {
- $num = substr($num, 0, 6) . 18 . substr($num, 6, 9);
- }
- else
- {
- $num = substr($num, 0, 6) . 19 . substr($num, 6, 9);
- }
- return $num.$this->cal_verify($num);
- }
- /**
- * 识别地址码
- *
- * @param string $num 传入18位身份证的编码
- * @return array 地址信息,array(0 => '省', 1 => '市', 2 => '区(县)')
- */
- function parse_addr($num)
- {
- $arr_rtn = array(0 => '', 1 => '', 2 => ''); // 省/市/区县
- if (strlen($num) != 18)
- {
- return $arr_rtn;
- }
- $file_data = dirname(__FILE__)."/area_code.dat";
- if (!file_exists($file_data))
- {
- return $arr_rtn;
- }
- $h = fopen($file_data, "r");
- $s1 = str_pad(substr($num, 0, 2), 6, "0", STR_PAD_RIGHT);
- $s2 = str_pad(substr($num, 0, 4), 6, "0", STR_PAD_RIGHT);
- $s3 = str_pad(substr($num, 0, 6), 6, "0", STR_PAD_RIGHT);
- while (!feof ($h))
- {
- $buffer = fgets($h, 4096);
- $arr = explode(",", $buffer);
- // 前两位
- if (strcmp($arr[0], $s1) == 0)
- {
- $arr_rtn[0] = $arr[1];
- }
- // 中间两位
- if (strcmp($arr[0], $s2) == 0)
- {
- $arr_rtn[1] = $arr[1];
- }
- // 末两位
- if (strcmp($arr[0], $s3) == 0)
- {
- $arr_rtn[2] = $arr[1];
- break;
- }
- }
- fclose($h);
- return $arr_rtn;
- }
- /**
- * 识别出生年月日
- *
- * @param string $num 传入18位身份证的编码
- * @return array 生日信息,array(0 => '年', 1 => '月', 2 => '日')
- */
- function parse_birth($num)
- {
- $arr_rtn = array(0 => '', 1 => '', 2 => ''); // 年/月/日
- if (strlen($num) != 18)
- {
- return $arr_rtn;
- }
- $arr_rtn[0] = substr($num, 6, 4); // 年
- $arr_rtn[1] = substr($num, 10, 2); // 月
- $arr_rtn[2] = substr($num, 12, 2); // 日
- return $arr_rtn;
- }
- /**
- * 识别性别
- *
- * @param string $num 传入18位身份证的编码
- * @return int 返回男女标志
- */
- function parse_sex($num)
- {
- $rtn_sex = IDC_SEX_UNKNOWN;
- if (strlen($num) != 18)
- {
- return $rtn_sex;
- }
- if (is_int(substr($num, 16, 1)/2))
- {
- $rtn_sex = IDC_SEX_FEMALE; // 女
- }
- else
- {
- $rtn_sex = IDC_SEX_MALE; // 男
- }
- return $rtn_sex;
- }
- /**
- * 生成校验码
- *
- * @param string $num 传入18位或者前17位身份证的编码
- * @return string 返回校验码
- */
- function cal_verify($num)
- {
- if (strlen($num) != 17)
- {
- if (strlen($num) == 18)
- {
- $num = substr($num, 0, 17);
- }
- else
- {
- return false;
- }
- }
- // 加权因子
- $factor = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
- // 校验码对应值
- $verify_number_list = array( 1 , 0 , X , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 );
- $checksum = 0;
- for ($i = 0; $i < strlen($num); $i++)
- {
- $checksum += substr($num, $i, 1) * $factor[$i];
- }
- $mod = $checksum % 11;
- return $verify_number_list[$mod];
- }
- /**
- * 验证18位新号码的有效性
- *
- * @param string $num 传入18位身份证号码
- * @return bool 验证成功:true|验证失败:false
- */
- function verify_num($num)
- {
- if (strlen($num) != 18)
- {
- return false;
- }
- if (strcasecmp(substr($num, 17, 1), $this->cal_verify($num)) == 0)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- ?>
调用方法示例:
- <?php
- require_once "class.idcard.inc.php";
- $code = "xxxxxxxxxx"; // 身份证号码
- $card = new idcard();
- $info = $card->parse_idc($code);
- $out = array();
- $out[IDC_INDEX_NUM_ORIGIN] = $info[IDC_INDEX_NUM_ORIGIN];
- $out[IDC_INDEX_NUM_18] = $info[IDC_INDEX_NUM_18];
- switch ($info[IDC_INDEX_CAT])
- {
- case IDC_FLAG_INVALID:
- $out[IDC_INDEX_CAT] = "无效身份证号码";
- break;
- case IDC_FLAG_OLD:
- $out[IDC_INDEX_CAT] = "15位旧身份证号码";
- break;
- case IDC_FLAG_NEW:
- $out[IDC_INDEX_CAT] = "18位新身份证号码";
- break;
- default:
- $out[IDC_INDEX_CAT] = "无效身份证号码";
- }
- $out[IDC_INDEX_ADDR] = $info[IDC_INDEX_ADDR][0].'.'.$info[IDC_INDEX_ADDR][1].'.'.$info[IDC_INDEX_ADDR][2];
- $out[IDC_INDEX_BIRTH] = $info[IDC_INDEX_BIRTH][0].'年'.$info[IDC_INDEX_BIRTH][1].'月'.$info[IDC_INDEX_BIRTH][2].'日';
- switch($info[IDC_INDEX_SEX])
- {
- case IDC_SEX_UNKNOWN:
- $out[IDC_INDEX_SEX] = "未知";
- break;
- case IDC_SEX_MALE:
- $out[IDC_INDEX_SEX] = "男";
- break;
- case IDC_SEX_FEMALE:
- $out[IDC_INDEX_SEX] = "女";
- break;
- default:
- $out[IDC_INDEX_SEX] = "未知";
- }
- print_r($out);
- ?>
------------------------------------------------------------------------------------------------------------------
未做过测试.....................................