jxlwqq/id-validator

View on GitHub
src/Helper.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php

namespace Jxlwqq\IdValidator;

/**
 * Trait Helper.
 */
trait Helper
{
    /**
     * 获取地址码信息.
     *
     * @param string $addressCode  地址码
     * @param string $birthdayCode 出生日期码
     * @param bool   $strictMode   是否启动严格模式检查
     *
     * @return bool|mixed|string
     */
    private function _getAddressInfo($addressCode, $birthdayCode, $strictMode = false)
    {
        $addressInfo = [
            'province' => '',
            'city'     => '',
            'district' => '',
        ];

        // 省级信息
        $provinceAddressCode = substr($addressCode, 0, 2).'0000';
        $addressInfo['province'] = $this->_getAddress($provinceAddressCode, $birthdayCode, $strictMode);

        $firstCharacter = $addressCode[0]; // 用于判断是否是港澳台居民居住证(8字开头)

        // 港澳台居民居住证无市级、县级信息
        if ($firstCharacter == '8') {
            return $addressInfo;
        }

        // 市级信息
        $cityAddressCode = substr($addressCode, 0, 4).'00';
        $addressInfo['city'] = $this->_getAddress($cityAddressCode, $birthdayCode, $strictMode);

        // 县级信息
        $addressInfo['district'] = $this->_getAddress($addressCode, $birthdayCode, $strictMode);

        // 这里不判断市级信息的原因:
        // 1)直辖市,无市级信息
        // 2)省直辖县或县级市,无市级信息
        return (empty($addressInfo['district']) or empty($addressInfo['province'])) ? false : $addressInfo;
    }

    /**
     * 获取省市区地址码.
     *
     * @param string $addressCode  地址码
     * @param string $birthdayCode 出生日期码
     * @param bool   $strictMode   是否启动严格模式检查
     *
     * @return string
     */
    private function _getAddress($addressCode, $birthdayCode, $strictMode = false)
    {
        $address = '';
        if (isset($this->_addressCodeTimeline[$addressCode])) {
            $timeline = $this->_addressCodeTimeline[$addressCode];
            $year = substr($birthdayCode, 0, 4);
            // 严格模式下,会检查【地址码正式启用的年份】与【身份证上的出生年份】
            foreach ($timeline as $val) {
                $start_year = $val['start_year'] != '' ? $val['start_year'] : '0001';
                $end_year = $val['end_year'] != '' ? $val['end_year'] : '9999';
                if ($year >= $start_year and $year <= $end_year) {
                    $address = $val['address'];
                }
            }

            // 非严格模式下,则不会检查【地址码正式启用的年份】与【身份证上的出生年份】的关系
            if (empty($address) and !$strictMode) {
                // 由于较晚申请户口或身份证等原因,导致会出现地址码正式启用于2000年,但实际1999年出生的新生儿,由于晚了一年报户口,导致身份证上的出生年份早于地址码正式启用的年份
                // 由于某些地区的地址码已经废弃,但是实际上在之后的几年依然在使用
                // 这里就不做时间判断了
                return array_pop($timeline)['address'];
            }

            return $address;
        }

        // 修复 \d\d\d\d01、\d\d\d\d02、\d\d\d\d11 和 \d\d\d\d20 的历史遗留问题
        // 以上四种地址码,现实身份证真实存在,但民政部历年公布的官方地址码中可能没有查询到
        // 如:440401 450111 等
        // 所以这里需要特殊处理
        // 1980年、1982年版本中,未有制定省辖市市辖区的代码,所有带县的省辖市给予“××××20”的“市区”代码。
        // 1984年版本开始对地级市(前称省辖市)市辖区制定代码,其中“××××01”表示市辖区的汇总码,同时撤销“××××20”的“市区”代码(追溯至1983年)。
        // 1984年版本的市辖区代码分为城区和郊区两类,城区由“××××02”开始排起,郊区由“××××11”开始排起,后来版本已不再采用此方式,已制定的代码继续沿用。
        $suffixes = substr($addressCode, 4, 2);
        switch ($suffixes) {
            case '20':
                $address = '市区';
                break;
            case '01':
                $address = '市辖区';
                break;
            case '02':
                $address = '城区';
                break;
            case '11':
                $address = '郊区';
                break;
        }

        return $address;
    }

    /**
     * 获取星座信息.
     *
     * @param string $birthdayCode 出生日期码
     *
     * @return string
     */
    private function _getConstellation($birthdayCode)
    {
        $constellationList = include __DIR__.'/../data/constellation.php';
        $month = (int) substr($birthdayCode, 4, 2);
        $day = (int) substr($birthdayCode, 6, 2);

        $start_date = $constellationList[$month]['start_date'];
        $start_day = (int) explode('-', $start_date)[1];

        if ($day < $start_day) {
            $tmp_month = $month == 1 ? 12 : $month - 1;

            return $constellationList[$tmp_month]['name'];
        }

        return $constellationList[$month]['name'];
    }

    /**
     * 获取生肖信息.
     *
     * @param string $birthdayCode 出生日期码
     *
     * @return mixed
     */
    private function _getChineseZodiac($birthdayCode)
    {
        $chineseZodiacList = include __DIR__.'/../data/chineseZodiac.php';
        $start = 1900; // 子鼠
        $end = substr($birthdayCode, 0, 4);
        $key = ($end - $start) % 12;

        return $chineseZodiacList[$key];
    }
}