百度卡证文字识别

公司有个业务需求,是调用百度的卡证文字识别api,然后自动填入对应字段

看完文档封装了一个服务类,希望对大家有帮助

图片支持base64和url的形式,原本打算直接用url的形式,但是我测试之后发现有个问题,百度那边对于url,会时不时出现下载超时或者下载失败的情况

就想了个方案,先把图片url转base64,再用base64的方式去调用接口

 

1.下面是示例代码,首先是对应得方法

    /**
     * 卡证文字识别
     *
     * @author panzhide
     * @time 2025-02-26 14:21:41
     * @return void
     */
    public function certificate_image_identify()
    {
        $url = I('url', '');
        $type = I('type', ''); // 图片类型:1=身份证,2=银行卡,3=营业执照
        if (!$url) {
            $this->errmsg('参数有误');
        }
        if (!$type) {
            $this->errmsg('图片类型参数有误');
        }

        // 图片装base64编码,避免图片url失效
        $baseimg = url2base64($url);
        $image = preg_replace('/^data:image\/[^;]+;base64,/', '', $baseimg);

        import('Org.BaiduOcrClient', COMMON_PATH);
        $BaiduOcrClient = new \BaiduOcrClient();
        try {
            // 图片类型:1=身份证,2=银行卡,3=营业执照
            switch ($type) {
                case 1:
                    $return_data = $BaiduOcrClient->identifyIdCard($url, $image);
                    break;
                case 2:
                    $return_data = $BaiduOcrClient->recognizeBankCard($url, $image);
                    break;
                case 3:
                    $return_data = $BaiduOcrClient->recognizeBusinessLicense($url, $image);
                    break;
                
                default:
                    $return_data = $BaiduOcrClient->recognizeBusinessLicense($url, $image);
                    break;
            }
            $data['data'] = $return_data;

            $this->out($data);
        } catch (\Exception $e) {
            $this->errmsg($e->getMessage());
        }
    }

2.图片url转base64的方法

    /**
     * 图片url转base64
     */
    if(! function_exists('url2base64')) {
        function url2base64($url)
        {
            $img_type = pathinfo($url)['extension'];

            if(empty($img_type)){
                return '';
            }

            $file_content = (base64_encode(file_get_contents($url)));

            if(empty($file_content)){
                return '';
            }
            return   'data:image/' . $img_type . ';base64,' . $file_content;//合成图片的base64编码
        }
    }

  

3.百度对应的服务类

<?php
class BaiduOcrClient
{
    const ACCESS_TOKEN_CACHE_KEY = 'baidu_ocr_access_token';
    const ACCESS_TOKEN_EXPIRY = 3600; // 1小时有效期

    private $apiKey;
    private $secretKey;

    public function __construct() // 去掉类型提示
    {
        $cfg = load_site_config();
        $this->apiKey = $cfg['baidu_api']["client_id"];
        $this->secretKey = $cfg['baidu_api']["client_secret"];
    }

    /**
     * 身份证识别
     *
     * @param string $imageContent 图片二进制内容或URL
     * @param array $options 可选参数
     * @return array
     */
    public function identifyIdCard($url, $image, $options = []) // 去掉类型提示
    {
        $baseParams = [
            'id_card_side' => 'front',
            'detect_ps' => 'false',
            'detect_risk' => 'false',
            'detect_quality' => 'false',
            'detect_photo' => 'false',
            'detect_card' => 'false',
            'detect_direction' => 'false',
            'url' => $url,
            'image' => $image
        ];

        return $this->request(
            'https://aip.baidubce.com/rest/2.0/ocr/v1/idcard',
            array_merge($baseParams, $options, ['url' => $url, 'image' => $image,])
        );
    }

    /**
     * 银行卡识别
     *
     * @param string $imageContent 图片二进制内容或URL
     * @param array $options 可选参数
     * @return array
     */
    public function recognizeBankCard($url, $image, $options = []) // 去掉类型提示
    {
        $baseParams = [
            'url' => $url,
            'image' => $image,
            'detect_quality' => 'false'
        ];

        return $this->request(
            'https://aip.baidubce.com/rest/2.0/ocr/v1/bankcard',
            array_merge($baseParams, $options)
        );
    }

    /**
     * 营业执照识别
     *
     * @param string $imageContent 图片二进制内容或URL
     * @param array $options 可选参数
     * @return array
     */
    public function recognizeBusinessLicense($url, $image, $options = []) // 去掉类型提示
    {
        $baseParams = [
            'url' => $url,
            'image' => $image,
            'detect_quality' => 'false'
        ];

        return $this->request(
            'https://aip.baidubce.com/rest/2.0/ocr/v1/business_license',
            array_merge($baseParams, $options)
        );
    }

    /**
     * 执行API请求
     */
    private function request($url, $params) // 去掉类型提示
    {
        $ch = curl_init();
        try {
            $query = http_build_query(['access_token' => $this->getAccessToken()]);
            curl_setopt_array($ch, [
                CURLOPT_URL => "{$url}?{$query}",
                CURLOPT_POST => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_SSL_VERIFYPEER => true,
                CURLOPT_SSL_VERIFYHOST => 2,
                CURLOPT_POSTFIELDS => $this->buildPostData($params),
                CURLOPT_HTTPHEADER => [
                    'Content-Type: application/x-www-form-urlencoded',
                    'Accept: application/json'
                ],
                CURLOPT_TIMEOUT => 30,
            ]);

            $response = curl_exec($ch);
            if ($error = curl_error($ch)) {
                throw new RuntimeException("CURL Error: {$error}");
            }

            return $this->parseResponse($response);
        } finally {
            curl_close($ch);
        }
    }

    /**
     * 处理API响应
     */
    private function parseResponse($response) // 去掉类型提示
    {
        $data = json_decode($response, true);
        if (JSON_ERROR_NONE !== json_last_error()) {
            throw new RuntimeException('JSON Parse Error: ' . json_last_error_msg());
        }
        if (!empty($data['error_code'])) {
            throw new RuntimeException("API Error [{$data['error_code']}]: {$data['error_msg']}");
        }
        return $data;
    }

    /**
     * 构建POST数据(支持文件内容)
     */
    private function buildPostData($params) // 去掉类型提示
    {
        // image和url同时存在,则保留url
        if (empty($params['image'])) {
            unset($params['image']);
        }
        if (empty($params['url'])) {
            unset($params['url']);
        }
        if ($params['image'] && $params['url']) {
            unset($params['url']);
        }
        return http_build_query($params);
    }

    private function getAccessToken()
    {
        // 从缓存获取Access Token
        $cached = SS(self::ACCESS_TOKEN_CACHE_KEY);
        if ($cached && $this->isTokenValid($cached)) {
            return $cached['token'];
        }

        // 请求新的Access Token
        $ch = curl_init();
        try {
            curl_setopt_array($ch, [
                CURLOPT_URL => 'https://aip.baidubce.com/oauth/2.0/token',
                CURLOPT_POST => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_SSL_VERIFYPEER => true,
                CURLOPT_POSTFIELDS => http_build_query([
                    'grant_type' => 'client_credentials',
                    'client_id' => $this->apiKey,
                    'client_secret' => $this->secretKey,
                ]),
            ]);

            $response = curl_exec($ch);
            if ($error = curl_error($ch)) {
                throw new RuntimeException("Token Request Failed: {$error}");
            }

            $data = json_decode($response, true);
            if (!isset($data['access_token'])) {
                throw new RuntimeException('Failed to get access token');
            }

            // 使用SS()缓存带有效期信息
            $cacheData = [
                'token' => $data['access_token'],
                'expiry' => time() + (int)($data['expires_in'] ?: self::ACCESS_TOKEN_EXPIRY)
            ];
            SS(self::ACCESS_TOKEN_CACHE_KEY, $cacheData, $cacheData['expiry'] - time());

            return $cacheData['token'];
        } finally {
            curl_close($ch);
        }
    }

    private function isTokenValid($cached) // 去掉类型提示
    {
        return isset($cached['expiry']) && $cached['expiry'] > time();
    }

    private function isUrl($str) // 去掉类型提示
    {
        return filter_var($str, FILTER_VALIDATE_URL) !== false;
    }
}

4.服务类中有用的缓存,建议替换成redis,我这边是系统太老没得办法

/**
 * 缓存管理
 * @param mixed $name 缓存名称,如果为数组表示进行缓存设置
 * @param mixed $value 缓存值
 * @param mixed $options 缓存参数
 * @return mixed
 */
function SS($name, $value = '', $options = null)
{
    static $cache = '';
    if (is_array($options) && empty($cache)) {
        // 缓存操作的同时初始化
        $type = isset($options['type']) ? $options['type'] : '';
        $cache = Think\Cache::getInstance($type, $options);
    } elseif (is_array($name)) { // 缓存初始化
        $type = isset($name['type']) ? $name['type'] : '';
        $cache = Think\Cache::getInstance($type, $name);
        return $cache;
    } elseif (empty($cache)) { // 自动初始化
        $type = C('DATA_CACHE_TYPE');
        $options = C('DATA_CACHE_OPTIONS');
        $cache = Think\Cache::getInstance($type, $options);
    }
    if ('' === $value) { // 获取缓存
        return $cache->get($name);
    } elseif (is_null($value)) { // 删除缓存
        return $cache->rm($name);
    } else { // 缓存数据
        if (is_array($options)) {
            $expire = isset($options['expire']) ? $options['expire'] : NULL;
        } else {
            $expire = is_numeric($options) ? $options : NULL;
        }
        return $cache->set($name, $value, $expire);
    }
}

  

posted @ 2025-02-26 17:39  潘潘潘的博客  阅读(15)  评论(0)    收藏  举报