php 身份证相关处理方法
/** * 截取身份证年、月、日,通过与当前时间戳的比较计算年龄 * @param string $idcard 身份证 * @return int */ function getAgeByID($idcard) { // 过了这年的生日才算多了一周岁 if(empty($idcard)) return 0; // 获得出生年月日的时间戳 $date = strtotime(substr($idcard, 6, 8)); // 获得今日的时间戳 $today = strtotime('today'); // 得到两个日期相差的大体年数 $diff = floor(($today-$date)/ 86400/ 365); // strtotime 加上这个年数后得到那日的时间戳后与今日的时间戳相比 $age = strtotime(substr($idcard, 6, 8).' +'.$diff.'years') > $today? ($diff+1): $diff; return $age; } /** * 通过截取身份证年、月、日来进行比较计算年龄 * @param string $idcard 身份证 * @return int */ function getAgeByIdcard($idcard) { if(!$idcard) return 0; $year = substr($idcard, 6, 4); $monthDay = substr($idcard, 10, 4); $age = date('Y') - $year; if($monthDay > date('md')) { $age--; } return $age; } /** * 根据身份证计算年月龄 * @param string $idcard * @param string $date * @return string */ function getAgeYMDByIdcard($idcard, $date='') { if(!$idcard) return 0; $year = substr($idcard, 6, 4); $month = substr($idcard, 10, 2); $day = substr($idcard, 12, 2); $date = $date ?: date('Y-m-d'); $diffDate = diffDate($year.'-'.$month.'-'.$day, $date); return $diffDate['year'].'周岁'.$diffDate['month'].'月龄'.$diffDate['day'].'天'; } /** * 通过身份证获取出生年月日 * @param string $idcard * @return string */ function getBirthdayByIdcard($idcard) { if(!$idcard) return ''; $year = substr($idcard, 6, 4); $month = substr($idcard, 10, 2); $day = substr($idcard, 12, 2); return $year.'-'.$month.'-'.$day; } /** * 功能:把15位身份证转换成18位 * * @param string $idCard * @return newid or id */ function getIDCard($idCard) { // 若是15位,则转换成18位;否则直接返回ID if (15 == strlen($idCard)) { $W = array(7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2,1 ); $A = array("1","0","X","9","8","7","6","5","4","3","2" ); $s = 0; $idCard18 = substr($idCard, 0, 6)."19".substr($idCard, 6); $idCard18_len = strlen($idCard18); for($i = 0; $i < $idCard18_len; $i++) { $s = $s + substr($idCard18, $i, 1) * $W[$i]; } $idCard18 .= $A[$s % 11]; return $idCard18; } else { return $idCard; } } /** * 已测试,百度很多写法不行的 * 1就是男性 2就是女性 * 通过身份证获取性别类型 * @param type $card * @return int */ function getCardSex($idcard) { if(empty($idcard)) return null; $sexint = (int)substr($idcard, 16, 1); return $sexint % 2 === 0 ? '2' : '1'; }
/** *function:计算两个日期相隔多少年,多少月,多少天 *param string $date1[格式如:2011-11-5] *param string $date2[格式如:2012-12-01] *return array array('年','月','日'); *@author Donlyn *<li>created at 2018-03-05</li> */ function diffDate($date1, $date2) { if (strtotime($date1) > strtotime($date2)) { $tmp = $date2; $date2 = $date1; $date1 = $tmp; } list ($Y1, $m1, $d1) = explode('-', $date1); list ($Y2, $m2, $d2) = explode('-', $date2); $Y = $Y2 - $Y1; $m = $m2 - $m1; $d = $d2 - $d1; if ($d < 0) { $d += (int)date('t', strtotime("-1 month $date2")); $m--; } if ($m < 0) { $m += 12; $Y--; } return array( 'year' => $Y, 'month' => $m, 'day' => $d ); }
class IdentityCard { /** * 校验身份证号是否合法 * @param string $num 待校验的身份证号 * @return bool */ public static function isValid($num) { //老身份证长度15位,新身份证长度18位 $length = strlen($num); if ($length == 15) { //如果是15位身份证 //15位身份证没有字母 if (!is_numeric($num)) { return false; } // 省市县(6位) $areaNum = substr($num, 0, 6); // 出生年月(6位) $dateNum = substr($num, 6, 6); } else if ($length == 18) { //如果是18位身份证 //基本格式校验 if (!preg_match('/^\d{17}[0-9xX]$/', $num)) { return false; } // 省市县(6位) $areaNum = substr($num, 0, 6); // 出生年月日(8位) $dateNum = substr($num, 6, 8); } else { //假身份证 return false; } //验证地区 if (!self::isAreaCodeValid($areaNum)) { return false; } //验证日期 if (!self::isDateValid($dateNum)) { return false; } //验证最后一位 if (!self::isVerifyCodeValid($num)) { return false; } return true; } /** * 获取身份证上的出生年月日 * @author donlyn * @date 211029 */ public static function getBirthDay($idcard) { if(self::isValid($idcard)) { $birth_day = strlen($idcard)==15 ? ('19' . substr($idcard, 6, 6)) : substr($idcard, 6, 8); return substr($birth_day,0,4).'-'.substr($birth_day,4,2).'-'.substr($birth_day,6,2); } return ''; } /** * 省市自治区校验 * @param string $area 省、直辖市代码 * @return bool */ private static function isAreaCodeValid($area) { $provinceCode = substr($area, 0, 2); // 根据GB/T2260—999,省市代码11到65 if (11 <= $provinceCode && $provinceCode <= 65) { return true; } else { return false; } } /** * 验证出生日期合法性 * @param string $date 日期 * @return bool */ private static function isDateValid($date) { if (strlen($date) == 6) { //15位身份证号没有年份,这里拼上年份 $date = '19'.$date; } $year = intval(substr($date, 0, 4)); $month = intval(substr($date, 4, 2)); $day = intval(substr($date, 6, 2)); //日期基本格式校验 if (!checkdate($month, $day, $year)) { return false; } //日期格式正确,但是逻辑存在问题(如:年份大于当前年) $currYear = date('Y'); if ($year > $currYear) { return false; } return true; } /** * 根据身份证号码计算年龄 */ public static function getAgeByID($id){ //过了这年的生日才算多了1周岁 if(empty($id)) return ''; $date=strtotime(substr($id,6,8)); //获得出生年月日的时间戳 $today=strtotime('today'); //获得今日的时间戳 111cn.net $diff=floor(($today-$date)/86400/365); //得到两个日期相差的大体年数 //strtotime加上这个年数后得到那日的时间戳后与今日的时间戳相比 $age=strtotime(substr($id,6,8).' +'.$diff.'years')>$today?($diff+1):$diff; return $age; } /** * 验证18位身份证最后一位 * @param string $num 待校验的身份证号 * @return bool */ private static function isVerifyCodeValid($num) { if (strlen($num) == 18) { $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; $tokens = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; $checkSum = 0; for ($i = 0; $i < 17; $i++) { $checkSum += intval($num{$i}) * $factor[$i]; } $mod = $checkSum % 11; $token = $tokens[$mod]; $lastChar = strtoupper($num{17}); if ($lastChar != $token) { return false; } } return true; } }
/*
// 测试
$num = '33071919610920021X';
if (IdentityCard::isValid($num)) {
echo '身份证格式正确';
} else {
echo '身份证格式不正确';
}
*/
//=============新的18位身份证号码各位的含义:=======================
//1-2位省、自治区、直辖市代码;11-65
//3-4位地级市、盟、自治州代码;
//5-6位县、县级市、区代码;
//7-14位出生年月日,比如19670401代表1967年4月1日;
//15-17位为顺序号,其中17位男为单数,女为双数;
//18位为校验码,0-9和X,由公式随机产生。
//举例:
//130503 19670401 0012这个身份证号的含义: 13为河北,05为邢台,03为桥西区,出生日期为1967年4月1日,顺序号为001,2为验证码
//===========15位身份证号码各位的含义:=======================
//1-2位省、自治区、直辖市代码;
//3-4位地级市、盟、自治州代码;
//5-6位县、县级市、区代码;
//7-12位出生年月日,比如670401代表1967年4月1日,这是和18位号码的第一个区别;
//13-15位为顺序号,其中15位男为单数,女为双数;
//与18位身份证号的第二个区别:没有最后一位的验证码。
//举例:
//130503 670401 001的含义; 13为河北,05为邢台,03为桥西区,出生日期为1967年4月1日,顺序号为001。