Files
tougao/application/common/ProductionArticleRefer.php
wangjinlei ae221e6be6 1
2026-04-16 13:30:31 +08:00

303 lines
14 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
namespace app\common;
use think\Db;
use think\Env;
class ProductionArticleRefer
{
// DOI匹配核心正则生产级优化支持%字符、限制长度、单词边界断言)
// private const DOI_PATTERN = '/(?:doi[:\s]?|DOI[:\s]?)?\b10\.\d+(?:\.\d+)*\/[a-zA-Z0-9._\-!()%\/:;@$&+=?#[\]<>~`|^]+/i';
// 错误码与错误信息映射(标准化错误处理)
private const ERROR_CODES = [
'EMPTY_STRING' => 'Input string is empty (preprocessed)',
'NO_MATCH' => 'No valid DOI detected',
'INVALID_AFTER_CLEAN' => 'No effective DOI after cleaning',
'FORCE_EXTRACT_FAILED' => 'Forced extraction still has no valid DOI',
'EXTRACTION_EXCEPTION' => 'Exception occurred during DOI extraction process',
];
/**
* 获取未处理的参考文献
*
* @return void
*/
public function top($aParam = []) {
//文章ID
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
if(empty($iArticleId)){
return json_encode(array('status' => 2,'msg' => 'Please select an article'.json_encode($aParam) ));
}
// 获取生产文章ID
$iPArticleId = empty($aParam['p_article_id']) ? 0 : $aParam['p_article_id'];
if(empty($iPArticleId)) {
return json_encode(array('status' => 2,'msg' => 'Please select an production article'.json_encode($aParam) ));
}
//查询未处理过的数据
$aWhere = ['p_article_id' => $iPArticleId,'article_id' => $iArticleId,'state' => 0,'refer_doi' => ['<>',''],'is_deal' => 2];
$aResult = Db::name('production_article_refer')->field('article_id,p_article_id,p_refer_id,refer_doi')->where($aWhere)->select();
if(empty($aResult)){
return json_encode(array('status' => 2,'msg' => 'The reference data to be processed is empty'.json_encode($aParam)));
}
//数据处理
foreach ($aResult as $key => $value) {
if(empty($value['refer_doi'])){
continue;
}
//调用获取参考文献详情队列
\think\Queue::push('app\api\job\ArticleReferDetailQueue@fire', $value, 'ArticleReferDetailQueue');
}
return json_encode(['status' => 1,'msg' => 'Add to reference processing queue']);
}
/**
* 处理参考文献
*
* @return void
*/
public function get($aParam = []) {
// 获取生产文章ID
$iPReferId = empty($aParam['p_refer_id']) ? 0 : $aParam['p_refer_id'];
if(empty($iPReferId)) {
return json_encode(array('status' => 2,'msg' => 'Please select a reference'.json_encode($aParam) ));
}
// 获取生产文章ID
$iPArticleId = empty($aParam['p_article_id']) ? 0 : $aParam['p_article_id'];
if(empty($iPArticleId)) {
return json_encode(array('status' => 2,'msg' => 'Please select an production article'.json_encode($aParam) ));
}
//查询未处理过的数据
$aWhere = ['p_refer_id' => $iPReferId,'p_article_id' => $iPArticleId,'state' => 0];
$aRefer = Db::name('production_article_refer')->field('refer_doi,refer_content')->where($aWhere)->find();
if(empty($aRefer)){
return json_encode(array('status' => 2,'msg' => 'No reference records found'.json_encode($aParam)));
}
if(empty($aRefer['refer_doi'])){
return json_encode(['status' => 4,'msg' => 'Reference DOI is empty'.json_encode($aParam)]);
}
//数据处理
$doi = str_replace('/', '%2F', $aRefer['refer_doi']);
$url = "https://citation.doi.org/format?doi=$doi&style=cancer-translational-medicine&lang=en-US";
$res = myGet($url);
$frag = trim(substr($res, strpos($res, '.') + 1));
if(empty($frag)){
$aUpdate = ['refer_frag' => $aRefer['refer_content'],'refer_type' => 'other','is_deal' => 1,'update_time' => time()];
$aWhere = ['p_refer_id' => $iPReferId];
$result = Db::name('production_article_refer')->where($aWhere)->limit(1)->update($aUpdate);
//写入通过AI获取参考文献详情队列
// \think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$aParam,'AiCheckReferByDoi');
return json_encode(array('status' => 2,'msg' => 'The data obtained from the interface is empty'.$url));
}
//整理数据入库
$update = [];
if (mb_substr_count($frag, '.') != 3){
$f = $frag . " Available at: " . PHP_EOL . "https://doi.org/" . $aRefer['refer_doi'];
$update['refer_type'] = "other";
$update['refer_frag'] = $f;
$update['cs'] = 1;
//写入通过AI获取参考文献详情队列
// \think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$aParam,'AiCheckReferByDoi');
}
if (mb_substr_count($frag, '.') == 3){
$res = explode('.', $frag);
$update['author'] = prgeAuthor($res[0]);
$update['title'] = trim($res[1]);
$bj = bekjournal($res[2]);
$joura = formateJournal(trim($bj[0]));
$update['joura'] = $joura;
$is_js = 0;
if ($joura == trim($bj[0])) {
}
$update['refer_type'] = "journal";
$update['is_ja'] = $joura == trim($bj[0]) ? 0 : 1;
$update['dateno'] = str_replace(' ', '', str_replace('-', '', trim($bj[1])));
//新增处理 期卷页码 20251127 start
if(!empty($update['dateno'])){
$sStr = $update['dateno'];
$aStr = explode(':', $sStr);
if(!empty($aStr[1])){
$parts = explode('', $aStr[1]);
if(count($parts) == 2){
$prefix = empty($parts[0]) ? 0 : intval($parts[0]);
$suffix = empty($parts[1]) ? 0 : intval($parts[1]);
if($prefix > $suffix){
$prefixLen = strlen($prefix);
$suffixLen = strlen($suffix);
$missingLen = $prefixLen - $suffixLen;
if ($missingLen > 0) {
$fillPart = substr($prefix, 0, $missingLen);
$newSuffix = $fillPart . $suffix;
$update['dateno'] = $aStr[0].':'.$prefix.''.$newSuffix;
}
}
}
}
// if(empty($aStr[1])){
// //写入通过AI获取参考文献详情队列
// \think\Queue::push('app\api\job\AiCheckReferByDoi@fire',$aParam,'AiCheckReferByDoi');
// }
}
//新增处理 期卷页码 20251127 end
$update['doilink'] = strpos($aRefer['refer_doi'],"http")===false?"https://doi.org/" . $aRefer['refer_doi']:$aRefer['refer_doi'];
$update['cs'] = 1;
}
//数据库更新
if(empty($update)){
return json_encode(array('status' => 3,'msg' => 'Update data to empty'.$url.'====='.$frag));
}
$aWhere = ['p_refer_id' => $iPReferId];
$update += ['is_deal' => 1,'update_time' => time()];
$result = Db::name('production_article_refer')->where($aWhere)->limit(1)->update($update);
if($result === false){
return json_encode(array('status' => 3,'msg' => 'Update failed'.json_encode($update)));
}
return json_encode(['status' => 1,'msg' => 'Update successful']);
}
// /**
// * 实例方法提取单个DOI核心逻辑生产级优化
// * @param string $str 待检测字符串
// * @param bool $standardize 是否标准化DOI转小写
// * @param bool $forceExtract 是否强制提取(忽略微小格式瑕疵)
// * @return array 提取结果含错误码、错误信息、DOI
// */
// // public function extractDoiFromString(string $str, bool $standardize = true, bool $forceExtract = false): array
// // {
// // // 初始化标准化结果
// // $result = [
// // 'has_doi' => false,
// // 'doi' => null,
// // 'error_code' => null,
// // 'error_msg' => null,
// // ];
// // try {
// // // 严格类型校验(防止非字符串参数传入)
// // if (!is_string($str)) {
// // throw new InvalidArgumentException('输入参数必须为字符串类型', 1001);
// // }
// // // 字符串预处理生产级全角转半角、URL解码、HTML标签移除等
// // $processedStr = $this->preprocessString($str);
// // if (trim($processedStr) === '') {
// // $result['error_code'] = 'EMPTY_STRING';
// // $result['error_msg'] = self::ERROR_CODES['EMPTY_STRING'];
// // return $result;
// // }
// // // 性能优化用preg_match仅匹配首个DOI替代preg_match_all
// // // 优化后的带前缀版正则
// // $pattern = '/(?:doi[:\s]*|DOI[:\s]*)?\b10\.\d+(?:\.\d+)*\/[a-zA-Z0-9._\-!()%\/:;@$&+=?#[\]<>~`|^'"{},\\\\]+(?![\w?#])/i";
// // if (!preg_match($pattern, $processedStr, $match)) {
// // $result['error_code'] = 'NO_MATCH';
// // $result['error_msg'] = self::ERROR_CODES['NO_MATCH'];
// // return $result;
// // }
// // // 清洗并验证首个DOI
// // $cleanDoi = $this->cleanAndValidateDoi($match[0], $standardize, $forceExtract);
// // if ($cleanDoi !== null) {
// // $result['has_doi'] = true;
// // $result['doi'] = $cleanDoi;
// // } else {
// // // 根据是否强制提取设置错误信息
// // $errorKey = $forceExtract ? 'FORCE_EXTRACT_FAILED' : 'INVALID_AFTER_CLEAN';
// // $result['error_code'] = $errorKey;
// // $result['error_msg'] = self::ERROR_CODES[$errorKey];
// // }
// // } catch (InvalidArgumentException $e) {
// // // 业务异常:标准化错误码和信息
// // $result['error_code'] = 'INVALID_PARAM';
// // $result['error_msg'] = '参数错误:' . $e->getMessage();
// // } catch (Exception $e) {
// // // 系统异常:隐藏敏感信息,记录通用错误
// // $result['error_code'] = 'EXTRACTION_EXCEPTION';
// // $result['error_msg'] = self::ERROR_CODES['EXTRACTION_EXCEPTION'] . '' . $e->getMessage();
// // }
// // return $result;
// // }
// // /**
// // * 字符串预处理(生产级:覆盖所有编码/格式干扰场景)
// // * @param string $str 原始字符串
// // * @return string 预处理后的纯净字符串
// // */
// // private function preprocessString(string $str): string
// // {
// // // 1. 全角转半角(解决中文全角字符干扰,如10.1007/s11042-020-10103-4)
// // $str = $this->fullWidthToHalfWidth($str);
// // // 2. 移除所有HTML标签解决网页文本中DOI被<p>/<a>/<b>等标签包裹的问题)
// // $str = strip_tags($str);
// // // 3. URL解码处理%2F等URL编码的特殊字符如10.1007%2Fs11042-020-10103-4
// // $str = urldecode($str);
// // // 4. 解码HTML实体处理&amp;、&#47;等HTML实体编码
// // $str = html_entity_decode($str, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// // // 5. 移除不可见字符(换行、制表符、零宽空格、控制字符等)
// // $str = preg_replace('/[\x00-\x1F\x7F\x{200B}-\x{200F}]/u', ' ', $str);
// // // 6. 合并多个空格为单个(避免连续空格干扰正则匹配)
// // $str = preg_replace('/\s+/', ' ', $str);
// // return $str;
// // }
// // /**
// // * 清洗并验证DOI生产级优化正则规则严格长度校验
// // * @param string $match 原始正则匹配结果
// // * @param bool $standardize 是否标准化DOI转小写
// // * @param bool $forceExtract 是否强制提取
// // * @return string|null 有效DOI或null
// // */
// // private function cleanAndValidateDoi(string $match, bool $standardize, bool $forceExtract): ?string
// // {
// // // 1. 移除DOI前缀doi:/DOI:)和首尾空白字符
// // $cleanDoi = preg_replace('/^doi[:\s]?|^DOI[:\s]?/i', '', trim($match));
// // // 2. 移除尾部常见标点避免DOI被标点包裹如10.1007/s11042-020-10103-4.
// // $cleanDoi = rtrim($cleanDoi, '.,;(){}[]!?"\'');
// // // 3. 严格的长度校验DOI官方规范6-200字符
// // $doiLength = strlen($cleanDoi);
// // if ($doiLength < 6 || $doiLength > 200) {
// // return null;
// // }
// // // 4. 验证规则生产级优化添加单词边界避免匹配不完整DOI
// // // 基础规则严格遵循官方规范10.开头+包含/+/后有内容
// // $basicRule = '/^10\.\d+\/.+$/D';
// // // 宽松规则强制提取时使用添加单词边界避免匹配被字符包裹的DOI
// // $looseRule = '/\b10\.\d+\/[^\s%]{1,190}\b/';
// // $validateRule = $forceExtract ? $looseRule : $basicRule;
// // $isValid = preg_match($validateRule, $cleanDoi) === 1;
// // // 5. 验证通过则标准化转小写否则返回null
// // if ($isValid) {
// // return $standardize ? strtolower($cleanDoi) : $cleanDoi;
// // }
// // return null;
// // }
// // /**
// // * 辅助方法:全角转半角
// // * @param string $str 包含全角字符的字符串
// // * @return string 半角字符串
// // */
// // private function fullWidthToHalfWidth(string $str): string
// // {
// // $fullWidthChars = [
// // '' => '0', '' => '1', '' => '2', '' => '3', '' => '4',
// // '' => '5', '' => '6', '' => '7', '' => '8', '' => '9',
// // '' => '.', '' => '/', '' => '-', '' => '%', '' => '!',
// // '' => '(', '' => ')', '' => ':', '' => ';', '' => ',',
// // '' => '"', '' => '\''
// // ];
// // return strtr($str, $fullWidthChars);
// // }
}
?>