Files
evus.acvisa.com/app/home/common.php

576 lines
18 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
const GET_WEB_CONFIG_URL = 'https://uniuser.jzvisa.com/home/Company/index/model/evus';
const CREATE_EVUS_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/applyevus';
const UPDATE_EVUS_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/updateevus';
const CREATE_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/do_apply';
const NEWS_LIST = 'https://uniuser.jzvisa.com/home/news/lists';
const NEWS_DETAIL = 'https://uniuser.jzvisa.com/home/news/detail';
const YZM_URL = 'https://uniuser.jzvisa.com/home/sms/sendCode';
const GET_ORDER_URL = 'https://uniuser.jzvisa.com/home/order/orderList';
const INCOICETYPE = '1';
const MODEL = 'msg';
const BUCKET = 'gzevus';
const COUNTRY = 'EVUS登记';
const SOURCE = 'evus.acvisa.cn';
const PAY_MARK = 'evuscn';
const OSS_URL = 'https://files.jzvisa.com/' . BUCKET . '/';
/*esta 配置*/
const ESTA_COUNTRY = 'ESTA登记';
const PAY_ESTA_MARK = 'estacn';
const ESTA_MODEL = 'esta';
const ESTA_INCOICETYPE = '6';
const BASE_PATH = '/evus'; // 可后端模板注入
// 公共函数
function formDataToJson($fields, $postData, $kew_key, $checkField)
{
if (!isset($postData[$checkField]) || $postData[$checkField] != 1) {
foreach ($fields as $field) {
unset($postData[$field]);
}
return $postData;
}
$data = [];
foreach ($postData[$fields[0]] as $index => $value) {
$entry = [];
foreach ($fields as $field) {
$entry[$field] = isset($postData[$field][$index]) ? $postData[$field][$index] : null;
}
$data[] = $entry;
}
$postData[$kew_key] = json_encode($data, JSON_UNESCAPED_UNICODE);
foreach ($fields as $field) {
unset($postData[$field]);
}
return $postData;
}
function find_json($json_name, $field, $field_value)
{
$data = file_get_contents($json_name);
$data_arr = json_decode($data, true);
$found = array_filter($data_arr, function ($item) use ($field, $field_value) {
return $item[$field] === $field_value;
});
// 输出结果
if ($found) {
$found = array_values($found); // 获取过滤后的第一个元素
return $found;
} else {
return false;
}
}
function getNameById($json_name, $id)
{
$data = file_get_contents('./json/' . $json_name . '.json');
$data_arr = json_decode($data, true);
foreach ($data_arr as $item) {
if (array_key_exists('data', $item['data'])) {
foreach ($item['data']['data'] as $dataItem) {
if ($dataItem['id'] === $id) {
return $dataItem['name'];
}
}
}
}
return null;
}
function getIdByName($json_name, $id)
{
$data = file_get_contents('./json/' . $json_name . '.json');
$data_arr = json_decode($data, true);
foreach ($data_arr as $item) {
if (array_key_exists('data', $item['data'])) {
foreach ($item['data']['data'] as $dataItem) {
if ($dataItem['name'] === $id) {
return $dataItem['id'];
}
}
}
}
return null;
}
function isMobile()
{
$_SERVER['ALL_HTTP'] = isset($_SERVER['ALL_HTTP']) ? $_SERVER['ALL_HTTP'] : '';
if (preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone|iphone|ipad|ipod|android|xoom)/i',
strtolower($_SERVER['HTTP_USER_AGENT']))) {
return true;
}
if ((isset($_SERVER['HTTP_ACCEPT'])) and (strpos(strtolower($_SERVER['HTTP_ACCEPT']),
'application/vnd.wap.xhtml+xml') !== false)) {
return true;
}
if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
return true;
}
if (isset($_SERVER['HTTP_PROFILE'])) {
return true;
}
$mobile_ua = strtolower(substr($_SERVER['HTTP_USER_AGENT'], 0, 4));
$mobile_agents = array(
'w3c ',
'acs-',
'alav',
'alca',
'amoi',
'audi',
'avan',
'benq',
'bird',
'blac',
'blaz',
'brew',
'cell',
'cldc',
'cmd-',
'dang',
'doco',
'eric',
'hipt',
'inno',
'ipaq',
'java',
'jigs',
'kddi',
'keji',
'leno',
'lg-c',
'lg-d',
'lg-g',
'lge-',
'maui',
'maxo',
'midp',
'mits',
'mmef',
'mobi',
'mot-',
'moto',
'mwbp',
'nec-',
'newt',
'noki',
'oper',
'palm',
'pana',
'pant',
'phil',
'play',
'port',
'prox',
'qwap',
'sage',
'sams',
'sany',
'sch-',
'sec-',
'send',
'seri',
'sgh-',
'shar',
'sie-',
'siem',
'smal',
'smar',
'sony',
'sph-',
'symb',
't-mo',
'teli',
'tim-',
'tosh',
'tsm-',
'upg1',
'upsi',
'vk-v',
'voda',
'wap-',
'wapa',
'wapi',
'wapp',
'wapr',
'webc',
'winw',
'winw',
'xda',
'xda-'
);
if (in_array($mobile_ua, $mobile_agents)) {
return true;
}
if (strpos(strtolower($_SERVER['ALL_HTTP']), 'operamini') !== false) {
return true;
}
// Pre-final check to reset everything if the user is on Windows
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows') !== false) {
return false;
}
// But WP7 is also Windows, with a slightly different characteristic
if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows phone') !== false) {
return true;
}
return false;
}
function getOrderNumber()
{
return date('YmdHis') . mt_rand(10, 99);
}
function cmf_get_current_user_id()
{
$sessionUserId = session('user.id');
if (empty($sessionUserId)) {
return 0;
}
return $sessionUserId;
}
function getIP()
{
$realip = '';
$unknown = 'unknown';
if (isset($_SERVER)){
if(isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], $unknown)){
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach($arr as $ip){
$ip = trim($ip);
if ($ip != 'unknown'){
$realip = $ip;
break;
}
}
}else if(isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']) && strcasecmp($_SERVER['HTTP_CLIENT_IP'], $unknown)){
$realip = $_SERVER['HTTP_CLIENT_IP'];
}else if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR']) && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)){
$realip = $_SERVER['REMOTE_ADDR'];
}else{
$realip = $unknown;
}
}else{
if(getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), $unknown)){
$realip = getenv("HTTP_X_FORWARDED_FOR");
}else if(getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), $unknown)){
$realip = getenv("HTTP_CLIENT_IP");
}else if(getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), $unknown)){
$realip = getenv("REMOTE_ADDR");
}else{
$realip = $unknown;
}
}
$realip = preg_match("/[\d\.]{7,15}/", $realip, $matches) ? $matches[0] : $unknown;
return $realip;
}
function build_ocr_signature(string $appId, string $secret, ?int $timestamp = null): array
{
$timestamp = $timestamp ?? time();
$signString = $appId . "\n" . (string)$timestamp;
$signature = hash_hmac('sha256', $signString, $secret);
return [
'app_id' => $appId,
'timestamp' => (string)$timestamp,
'signature' => $signature,
'base_url' => config('app.OCR_BASE_URL'),
];
}
// 这是系统自动生成的公共文件
function arrayToJson($params, $values)
{
$datas = [];
$count = count($values[0]);
$valcount = count($params);
for ($i = 0; $i < $count; $i++) {
for ($j = 0; $j < $valcount; $j++) {
$data[$params[$j]] = $values[$j][$i];
}
$datas[] = $data;
}
if (empty($datas)) {
return '';
}
return json_encode($datas);
}
function getCate($val)
{
$cates = explode('-', $val);
if (count($cates) == 1) {
if ($val == 'CNMI') {
return 'CW/E2C';
}
} else {
preg_match_all('/[A-Z]+/', $val, $matches);
return $matches[0][0];
}
}
//非常给力的authcode加密函数,Discuz!经典代码(带详解)
function authcode($string, $operation = 'DECODE', $key = '20241021', $expiry = 0)
{
// 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙
$ckey_length = 4;
// 密匙
$key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
// 密匙a会参与加解密
$keya = md5(substr($key, 0, 16));
// 密匙b会用来做数据完整性验证
$keyb = md5(substr($key, 16, 16));
// 密匙c用于变化生成的密文
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
// 参与运算的密匙
$cryptkey = $keya . md5($keya . $keyc);
$key_length = strlen($cryptkey);
// 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),
//解密时会通过这个密匙验证数据完整性
// 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
// 产生密匙簿
for ($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
// 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度
for ($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 核心加解密部分
for ($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
// 从密匙簿得出密匙进行异或,再转成字符
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
if ($operation == 'DECODE') {
// 验证数据有效性,请看未加密明文的格式
if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
} else {
// 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因
// 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码
return $keyc . str_replace('=', '', base64_encode($result));
}
}
function getChineseCode($code)
{
$url = "http://code.mcdvisa.com/save.php?action=getcode&i=0&w={$code}";
$data = file_get_contents($url);
if (empty($data)){
return [
'code'=>0,
'data'=>[]
];
}
// 创建 DOMDocument 对象并加载 HTML
$dom = new DOMDocument();
libxml_use_internal_errors(true); // 抑制 HTML 解析错误
$dom->loadHTML($data);
libxml_clear_errors();
// 获取所有的 <li> 元素
$lis = $dom->getElementsByTagName('li');
$pattern = '/-?\d+(?:\.\d+)?/';
$datas=[];
foreach ($lis as $li) {
$text = $li->textContent;
preg_match_all($pattern, $text, $matches);
$datas[] = $matches[0][0];
}
return [
'code'=>200,
'data'=>$datas
];
}
/**
* 查询姓名电码。
* @param string $fullName 中文全名
* @param int $surnameLength 姓氏字数:单姓 1,复姓 2
* 依赖第三方网页结构;失败时抛出异常,由调用方转换为用户提示。
*/
function queryNameTelecode(string $fullName, int $surnameLength = 1): array
{
$fullName = trim($fullName);
$length = mb_strlen($fullName, 'UTF-8');
if (!preg_match('/^\p{Han}+$/u', $fullName) || $length > 8) {
throw new InvalidArgumentException('请输入不超过 8 个汉字的姓名');
}
if ($surnameLength < 1 || $surnameLength >= $length) {
throw new InvalidArgumentException('姓氏字数必须小于姓名总字数');
}
if (!extension_loaded('curl') || !extension_loaded('dom')) {
throw new RuntimeException('电码查询服务未就绪,请手动填写或联系管理员');
}
$url = 'https://apps.chasedream.com/chinese-commercial-code/';
// 两次请求共用一个时间预算,避免每次都等待完整超时时间。
$deadline = hrtime(true) + 15 * 1000000000;
$curl = curl_init($url);
if ($curl === false) {
throw new RuntimeException('无法初始化 cURL');
}
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 15,
CURLOPT_COOKIEFILE => '', // 内存 Cookie,会话内复用
CURLOPT_USERAGENT => 'NameTelecodeLookup/1.0',
// 协商压缩响应并自动解压,减少两次查询的网络传输量。
CURLOPT_ENCODING => '',
]);
$request = static function () use ($curl, $deadline): string {
$remainingMs = (int) floor(($deadline - hrtime(true)) / 1000000);
if ($remainingMs <= 0) {
throw new RuntimeException('电码查询超时,请稍后重试或手动填写');
}
curl_setopt($curl, CURLOPT_TIMEOUT_MS, $remainingMs);
$html = curl_exec($curl);
if ($html === false) {
throw new RuntimeException('电码查询连接失败或超时,请稍后重试或手动填写');
}
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status !== 200) {
throw new RuntimeException('电码查询服务暂时不可用,请稍后重试或手动填写');
}
if (trim($html) === '') {
throw new RuntimeException('电码查询返回空内容,请稍后重试或手动填写');
}
return $html;
};
$parse = static function (string $html): DOMXPath {
$previous = libxml_use_internal_errors(true);
try {
$dom = new DOMDocument();
if (!$dom->loadHTML('<?xml encoding="UTF-8">' . $html)) {
throw new RuntimeException('无法解析网页');
}
return new DOMXPath($dom);
} finally {
libxml_clear_errors();
libxml_use_internal_errors($previous);
}
};
try {
// 获取本次页面的动态隐藏字段。
$xpath = $parse($request());
$payload = [];
foreach ($xpath->query(
'//form[@id="form1"]//input[@type="hidden"][@name]'
) as $input) {
$payload[$input->getAttribute('name')] =
$input->getAttribute('value');
}
if (!isset($payload['__VIEWSTATE'])) {
throw new RuntimeException('查询页面结构发生变化');
}
$payload['txtInput'] = $fullName;
$payload['btnSearch'] = '查询';
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($payload),
CURLOPT_REFERER => $url,
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
],
]);
$xpath = $parse($request());
$mapping = [];
// 只接受“一个汉字 + 一个四位电码”的结果行。
foreach ($xpath->query('//table[@id="grvDict"]//tr') as $row) {
$characters = [];
$codes = [];
foreach ($xpath->query('./td', $row) as $cell) {
$text = trim($cell->textContent);
if (preg_match('/^\p{Han}$/u', $text)) {
$characters[] = $text;
} elseif (preg_match('/^[0-9]{4}$/', $text)) {
$codes[] = $text;
}
}
if (count($characters) === 1 && count($codes) === 1) {
$character = $characters[0];
$code = $codes[0];
if (isset($mapping[$character])
&& $mapping[$character] !== $code) {
throw new RuntimeException("“{$character}”返回多个电码");
}
$mapping[$character] = $code;
}
}
$characters = preg_split('//u', $fullName, -1, PREG_SPLIT_NO_EMPTY);
$codes = [];
foreach ($characters as $character) {
if (!isset($mapping[$character])) {
throw new RuntimeException(
"未取得“{$character}”的电码,请人工核实或检查网页结构"
);
}
$codes[] = $mapping[$character];
}
return [
'full_name' => $fullName,
'surname' => mb_substr($fullName, 0, $surnameLength, 'UTF-8'),
'given_name' => mb_substr($fullName, $surnameLength, null, 'UTF-8'),
'surname_code' => implode('', array_slice($codes, 0, $surnameLength)),
'given_name_code' => implode('', array_slice($codes, $surnameLength)),
'full_code' => implode('', $codes),
'characters' => $mapping,
];
} finally {
curl_close($curl);
}
}