Files
tougao/application/common/LatexContent.php
2025-12-22 10:08:24 +08:00

618 lines
28 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 app\common\LatexTable;
/**
* LaTeX内容生成类
*/
class LatexContent{
//期刊相关的信息
private $iYear = 2025;//年
private $iPeriod = 1;//期
private $sAbbr = 'tmr';//期刊缩写
private $sWebsite = 'https://www.tmrjournals.com/tmr';//期刊官网
//模版地址
private $sLatexUrl = '/public/latex/';
//期刊官网接口地址
private $sJournalUrl = 'http://zmzm.journal.dev.com/';//'http://journalapi.tmrjournals.com/public/index.php/';//
//文章图片
private $sArticleIcon = '/public/articleicon/';
//文章图片
private $sArticleMainImage = '/public/articleImage/';
//编辑系统URL
private $sSubmissionUrl = 'https://submission.tmrjournals.com/';
//图片模版
private $sImageTempalte = '\begin{figure}[hbt!]
\centering
\includegraphics[width=0.75\linewidth]{{{img_url}}}
\caption{{{img_title}}}
\label{{{img_fig_sim}}}
\end{figure}' ;
//首页内容
private $sFirst = '\documentclass[
journal={{journal_abbr}},
journalname={{{{journal_title}}}},
layout=largetwo,
year={{stage_year}},%年
volume={{stage_vol}},%卷
no={{stage_no}},%期
page={{stage_page}},%号
]{tmr-tex}
\doi{{{doi}}}
\journalweb{{{website}}}
% \def\ORCIdICONNAME{{{CLSFILEURL}}/orcid_icon.png} %定义ORCID图片
% \def\TMRLOGONAME{{{CLSFILEURL}}/tmr-logo.pdf} % 定义期刊LOGO图片
\usepackage{amsmath}
\usepackage[nopatch]{microtype}
\usepackage{booktabs}
\usepackage[backend=biber]{biblatex}
\usepackage{xcolor} % 蓝色字体(参考文献)
\usepackage{multirow} % 单元格合并(必选)
\usepackage{array} % 列格式居中(必选)
\usepackage{geometry} % 页面适配,避免内容溢出
\addbibresource{example.bib}
\title{{{article_title}}}
{{author_info}}
\addbibresource{example.bib}
{{correspondence_info}}
\keywords{keyword entry 1, keyword entry 2, keyword entry 3} %% First letter not capped
{{author_contribution}}
\competinginterests{The authors declare no conflicts of interest.}
{{article_acknowledgment}}
\Peerreviewinformation{{{journal_title}} thanks all anonymous reviewers for their contribution to the peer review of this paper}
{{article_abbreviation}}
{{article_cite}}
\received{{{received_date}}}
\revised{{{revision_date}}}
\accepted{{{accepted_date}}}
\Availableonline{{{pub_date}}}
{{executive_editor}}
{{abstract}}
{{keywords}}
{{article_icon}}';
//正文内容
private $sMain = '\begin{document}
\twocolumn
{{tmr_highlight}}
{{article_main}}
\end{document}';
/**
* 生成初稿-基本内容
* @param article_id 文章ID
*/
public function buildFirst($aProductionArticle = []){
//获取模版
$sTemplateInfo = $this->sFirst;
//查询期刊信息
$iJournalId = empty($aProductionArticle['journal_id']) ? 0 : $aProductionArticle['journal_id'];
if(!empty($iJournalId)){
$aWhere = ['journal_id' => $iJournalId,'state' => 0];
$aJournal = Db::name('journal')->where($aWhere)->find();
if(!empty($aJournal)){
//获取编辑信息
$aWhere = ['user_id' => $aJournal['editor_id'],'state' => 0];
$aUser = Db::name('user')->field('realname')->where($aWhere)->find();
}
}
//子刊信息
$iJournalStageId = empty($aProductionArticle['journal_stage_id']) ? 0 : $aProductionArticle['journal_stage_id'];
if(!empty($iJournalStageId)){
$aJournalStage = $this->getJournalStage(['journal_stage_id' => $iJournalStageId]);
$aJournalStage = empty($aJournalStage['data']) ? [] : $aJournalStage['data'];
}
//期刊简写
$sAbbr = empty($aJournal['abbr']) ? $this->sAbbr : $aJournal['abbr'];
$sAbbr = strtolower($sAbbr);
$sJournalTitle = empty($aJournal['title']) ? '' : $aJournal['title'];
//年
$iYear = empty($aJournalStage['stage_year']) ? date('Y') : $aJournalStage['stage_year'];
//卷
$iVolume = empty($aJournalStage['stage_vol']) ? 0 : $aJournalStage['stage_vol'];
//期
$iPeriod = empty($aJournalStage['stage_no']) ? 0 : $aJournalStage['stage_no'];
//页
$sPage = empty($aJournalStage['stage_page']) ? '' : $aJournalStage['stage_page'];
//期刊web
$sWebsite = empty($aJournal['website']) ? $this->sWebsite : $aJournal['website'];
$aSearch = ['{{journal_abbr}}' => $sAbbr,'{{stage_year}}' => $iYear,'{{stage_vol}}' => $iVolume,'{{stage_no}}' => $iPeriod,'{{stage_page}}' => $sPage,'{{website}}' => $sWebsite,'{{journal_title}}' => $sJournalTitle];
//获取DOI
$aSearch['{{doi}}'] = empty($aProductionArticle['doi']) ? '' : $aProductionArticle['doi'];
//获取作者信息
$aAuthoInfo = $this->dealAuthor(['p_article_id' => $aProductionArticle['p_article_id']]);
$aSearch['{{author_info}}'] = empty($aAuthoInfo['author']) ? '' : $aAuthoInfo['author'];
//通讯作者信息
$aSearch['{{correspondence_info}}'] = empty($aAuthoInfo['correspondence']) ? '' : '\Correspondence{'.$aAuthoInfo['correspondence'].'}';
//文章基本信息处理
//标题
$sTitle = empty($aProductionArticle['title']) ? '' : $this->dealContent($aProductionArticle['title']);
if(!empty($sTitle)){
if(!empty($aProductionArticle['ltai'])){
$aLtai = explode(',', $aProductionArticle['ltai']);
foreach ($aLtai as $key => $value) {
if(empty($value)){
continue;
}
$sTitle = str_replace($value, '\textit{'.$value.'}', $sTitle);
}
}
}
$aSearch['{{article_title}}'] = $sTitle;
//author_contribution
$aSearch['{{author_contribution}}'] = empty($aProductionArticle['author_contribution']) ? '' : '\authorcontributions{'.$this->dealContent($aProductionArticle['author_contribution']).'}';
//acknowledgment
$aSearch['{{article_acknowledgment}}'] = empty($aProductionArticle['acknowledgment']) ? '' : '\Acknowledgments{'.$this->dealContent($aProductionArticle['acknowledgment']).'}';
//abbreviation
$aSearch['{{article_abbreviation}}'] = empty($aProductionArticle['abbreviation']) ? '' : '\Abbreviations{'.$this->dealContent($aProductionArticle['abbreviation']).'}';
//文章引用信息
$sCite = $this->getArticleCite($aProductionArticle,$aJournal,$aJournalStage);
$aSearch['{{article_cite}}'] = empty($sCite) ? '' : '\Citation{'.$sCite.'}';
//获取文章时间
$aTime = $this->getArticleTime(['article_id' => $aProductionArticle['article_id']]);
$aTime = empty($aTime['data']) ? [] : $aTime['data'];
$aSearch['{{received_date}}'] = empty($aTime['received_date']) ? '' : $aTime['received_date'];
$aSearch['{{revision_date}}'] = empty($aTime['revision_date']) ? '' : $aTime['revision_date'];
$aSearch['{{accepted_date}}'] = empty($aTime['accepted_date']) ? '' : $aTime['accepted_date'];
$aSearch['{{pub_date}}'] = empty($aProductionArticle['pub_date']) ? '' : $aProductionArticle['pub_date'];
//获取编辑信息
$aSearch['{{executive_editor}}'] = empty($aUser['realname']) ? '' : '\Executiveeditor{'.$this->dealContent($aUser['realname']).'}';
//摘要替换
$sAbstract = empty($aProductionArticle['abstract']) ? '' : $this->dealContent($aProductionArticle['abstract']);
if(!empty($sAbstract)){
$aRelace = ['Background:' => '\textcolor[HTML]{0070C0}{\textbf{Background:}}','Methods:' => '\textcolor[HTML]{0070C0}{\textbf{Methods:}}','Results:' => '\textcolor[HTML]{0070C0}{\textbf{Results:}}','Conclusion:' => '\textcolor[HTML]{0070C0}{\textbf{Conclusion:}}'];
$sAbstract = str_replace(array_keys($aRelace), array_values($aRelace), $sAbstract);
$sAbstract = '\tmrabstract{'.$sAbstract.'}';
}
$aSearch['{{abstract}}'] = $sAbstract;
//关键词
$sKeywords = empty($aProductionArticle['keywords']) ? '' : '\keywords{'.$this->dealContent($aProductionArticle['keywords']).'}';
$aSearch['{{keywords}}'] = $sKeywords;
//文章图片地址
$sIcon = empty($aProductionArticle['icon']) ? '' : $aProductionArticle['icon'];
if(!empty($sIcon)){
// $sIconUrl = rtrim(ROOT_PATH).$this->sArticleIcon.'/'.$sIcon;
// if(file_exists($sIconUrl)){
// $sIcon = '\KeywordImage{'.$sIconUrl.'}';
// }else{
// $sIcon = '';
// }
//下载图片
$sImagePath = trim($this->sSubmissionUrl,'/').$this->sArticleIcon.'/'.$sIcon;
$aImageInfo = $this->getImage($sImagePath,$aProductionArticle['p_article_id']);
if(!empty($aImageInfo['data'])){
$sIcon = '\KeywordImage{'.$aImageInfo['data'].'}';
}else{
$sIcon = '';
}
}
$aSearch['{{article_icon}}'] = $sIcon;
$aSearch['{{keywords}}'] = $sKeywords;
$aSearch['{{CLSFILEURL}}'] = ROOT_PATH.'public/latex/cls';
//模版内容替换
$sTemplateInfo = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplateInfo);
//返回内容
return ['status' => 1,'msg' => 'success','data' => $sTemplateInfo];
}
/**
* 生成初稿-主内容
* @param article_id 文章ID
*/
public function buildMain($aProductionArticle = []){
//获取模版
$sTemplateInfo = $this->sMain;
//数据替换
$aSearch = ['{{tmr_highlight}}' => '','{{article_main}}' => ''];
$sHighlight = '';
if($aProductionArticle['journal_id'] == 1){//tmr独有
$tradition_tag = empty($aProductionArticle['tradition_tag']) ? '' : strtolower( $aProductionArticle['tradition_tag']);
$tradition = empty($aProductionArticle['tradition']) ? '' : $this->dealContent($aProductionArticle['tradition']);
$pattern = '/<em[^>]*>(.*?)<\/em>/is';
$replacement = '\\emph{$1}';
// $tradition = preg_replace($pattern, $replacement, $tradition);
if(in_array($tradition_tag, ['highlight','highlights']) && !empty($tradition)){
$sHighlight .= '\highlightitem{Highlights}{'.$tradition.'}'."\n";
}
$mhoo = empty($aProductionArticle['mhoo']) ? '' : $this->dealContent( $aProductionArticle['mhoo']);
$mhoo = preg_replace($pattern, $replacement, $mhoo);
if(!empty($mhoo)){
$sHighlight .= '\highlightitem{Medical history of objective}{'.$mhoo.'}'."\n";
}
}
$aSearch['{{tmr_highlight}}'] = empty($sHighlight) ? '' : '\begin{highlight}'."\n".$sHighlight."\n".'\end{highlight}'."\n";
//查询正文信息
// $aProductionArticle['article_id'] = 4477;
$aWhere = ['article_id' => $aProductionArticle['article_id'],'state' => 0];
$aArticleMain = Db::name('article_main')->field('am_id,article_id,type,content,ami_id,amt_id,is_h1,is_h2,is_h3,sort')->where($aWhere)->order('sort')->select();
if(!empty($aArticleMain)){
//查询图片
$aAmiId = array_unique(array_column($aArticleMain, 'ami_id'));
$aWhere = ['ami_id' => ['in',$aAmiId],'state' => 0];
$aArticleMainImage = Db::name('article_main_image')->field('ami_id,url,note')->where($aWhere)->select();
$aArticleMainImage = empty($aArticleMainImage) ? [] : array_column($aArticleMainImage, null,'ami_id');
//查询表格
$aAmtId = array_unique(array_column($aArticleMain, 'amt_id'));
$aWhere = ['amt_id' => ['in',$aAmtId],'state' => 0];
$aArticleMainTable = Db::name('article_main_table')->field('amt_id,type,table_data,url,title,note')->where($aWhere)->select();
$aArticleMainTable = empty($aArticleMainTable) ? [] : array_column($aArticleMainTable, null,'amt_id');
//获取图片模版
$sImageTempalte = $this->sImageTempalte;
//数据处理
$iStart = 0;
$sMain = '';
$oLatexTable = new LaTeXTable;
foreach ($aArticleMain as $key => $value) {
if(empty($iStart)){
if($value['is_h1'] == 0){
continue;
}else{
$iStart = $value['am_id'];
}
}
if($value['am_id'] >= $iStart){
if($value['is_h1'] == 1){
if(empty($value['content'])){
continue;
}
$sMain .= '\section{'.$this->dealContent($value['content']).'}'."\n";
}
if($value['is_h2'] == 1){
if(empty($value['content'])){
continue;
}
$sMain .= '\subsection{'.$this->dealContent($value['content']).'}'."\n";
}
if($value['is_h3'] == 1){
if(empty($value['content'])){
continue;
}
$sMain .= '\subsubsection{'.$this->dealContent($value['content']).'}'."\n";
}
if($value['is_h1'] == 0 && $value['is_h2'] == 0 && $value['is_h3'] == 0){
if($value['type'] == 0 ){
$sMain .= $this->dealContent($value['content'])."\\par\n";
}
if($value['type'] == 1 ){//图片
$aImageInfo = empty($aArticleMainImage[$value['ami_id']]) ? [] : $aArticleMainImage[$value['ami_id']];
if(empty($aImageInfo['url'])){
continue;
}
// $sIconUrl = rtrim(ROOT_PATH).$this->sArticleIcon.'/'.$sIcon;
// if(file_exists($sIconUrl)){
// $sIcon = '\KeywordImage{'.$sIconUrl.'}';
// }else{
// $sIcon = '';
// }
//下载图片
$sImagePath = trim($this->sSubmissionUrl,'/').$this->sArticleMainImage.'/'.$aImageInfo['url'];
$aResult = $this->getImage($sImagePath,$aProductionArticle['p_article_id']);
if(empty($aResult['data'])){
continue;
}
$aImageSearch = ['{{img_url}}' => $aResult['data'],'{{img_title}}' => $aImageInfo['note'],'{{img_fig_sim}}' => 'img_fig_sim_'.$value['ami_id']];
$sImageTempalteInfo = str_replace(array_keys($aImageSearch), array_values($aImageSearch), $sImageTempalte);
$sMain .= $sImageTempalteInfo."\\par\n";
}
if($value['type'] == 2 ){//表格
continue;
}
}
}
}
}
$aSearch['{{article_main}}'] = empty($sMain) ? '' : $sMain."\n";
//模版内容替换
$sTemplateInfo = str_replace(array_keys($aSearch), array_values($aSearch), $sTemplateInfo);
//返回内容
return ['status' => 1,'msg' => 'success','data' => $sTemplateInfo];
}
/**
* 生成初稿-作者信息
*/
private function dealAuthor($aParam = []){
// 获取作者信息
$aParam = empty($aParam) ? $this->request->post() : $aParam;
//必填值验证
$iPArticleId = empty($aParam['p_article_id']) ? '' : $aParam['p_article_id'];
if(empty($iPArticleId)){
return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
}
//
//查询作者信息
$aWhere = ['p_article_id' => $iPArticleId,'state' => 0];
$aAuthor = Db::name('production_article_author')->where($aWhere)->select();
if(empty($aAuthor)){
return ['status' => 3,'msg' => 'Author information is empty'];
}
//查询作者机构
$aWhere['p_article_author_id'] = ['in',array_column($aAuthor, 'p_article_author_id')];
$aAuthorOrgan = Db::name('production_article_author_to_organ')->field('p_article_author_id,p_article_organ_id')->where($aWhere)->select();
//查询机构信息
$aAuthorOrganList = [];
if(!empty($aAuthorOrgan)){
unset($aWhere['p_article_author_id']);
$aOrganId = array_unique(array_column($aAuthorOrgan, 'p_article_organ_id'));
$aWhere['p_article_organ_id'] = ['in',$aOrganId];
$aOrgan = Db::name('production_article_organ')->where($aWhere)->column('p_article_organ_id,organ_name');
if(!empty($aOrgan)) {
foreach ($aAuthorOrgan as $key => $value) {
if(empty($aOrgan[$value['p_article_organ_id']])){
continue;
}
$aAuthorOrganList[$value['p_article_author_id']][] = $aOrgan[$value['p_article_organ_id']];
}
}
}
//处理作者
$sAuthor = $sCorrespondence = '';
foreach ($aAuthor as $key => $value) {
//作者姓名
$sName = empty($value['fifirst_name']) ? '' : $value['fifirst_name'];
$sName = empty($sName) ? '' : $sName . ' ' .$value['last_name'];
if(empty($sName)){
$sName = empty($value['author_name']) ? '' : $value['author_name'];
}
if(empty($sName)){
continue;
}
$sAuthor .= '\author{'.$this->dealContent($sName).'}'."\n";
if(!empty($value['email']) && $value['is_report'] == 1){
$sAuthor .= '\email{'.$this->dealContent($value['email']).'}'."\n";
}
//作者机构
$aOrganList = empty($aAuthorOrganList[$value['p_article_author_id']]) ? [] : $aAuthorOrganList[$value['p_article_author_id']];
if(!empty($aOrganList)){
$i = 0;
foreach($aOrganList as $organ){
if(empty($organ)){
continue;
}
if($i == 0){
$sAuthor .= '\affiliation{'.$this->dealContent($organ).'}'."\n";
}else{
$sAuthor .= '\alsoaffiliation{'.$this->dealContent($organ).'}'."\n";
}
$i++;
}
}
if($value['is_first'] == 1){
$sAuthor .= '\firstauthor'."\n";
}
if(!empty($value['orcid'])){
$sAuthor .= '\orcid{'.$this->dealContent($value['orcid']).'}'."\n";
}
if($value['is_report'] == 1){
$sCorrespondence .= $sName;
if(!empty($aOrganList[0])){
$sCorrespondence .= ','.trim($this->dealContent($aOrganList[0]),'.');
}
if(!empty($value['email'])){
$sCorrespondence .= '.E-mail: '.trim($this->dealContent($value['email']),'.').'.';
}
}
}
return ['author' => $sAuthor,'correspondence' => $sCorrespondence];
}
/**
* 生成初稿-获取期刊分期信息
*/
private function getJournalStage($aParam = []){
// 获取分期ID
$aParam = empty($aParam) ? $this->request->post() : $aParam;
//必填值验证
$iJournalStageId = empty($aParam['journal_stage_id']) ? '' : $aParam['journal_stage_id'];
if(empty($iJournalStageId)){
return json_encode(array('status' => 2,'msg' => 'Please choose journal installment' ));
}
$sUrl = $this->sJournalUrl."api/Supplementary/getJournalStage";
$aResult = object_to_array(json_decode(myPost1($sUrl,$aParam)));
return $aResult;
}
/**
* 处理文章引用
* @param string $html
* @return string
*/
private function getArticleCite($aArticle = [],$aJournal = [],$aJournalStage = []){
$no = empty($aJournalStage['stage_no']) ? ':' : '(' . $aJournalStage['stage_no'] . '):';
$jabbr = empty($aJournal['jabbr']) ? '' : $aJournal['jabbr'];
$stage_year = empty($aJournalStage['stage_year']) ? '' : $aJournalStage['stage_year'];
$stage_vol = empty($aJournalStage['stage_vol']) ? '' : $aJournalStage['stage_vol'];
$aAbbr = empty($aArticle['abbr']) ? '' : explode(',', trim($aArticle['abbr']));
if(!empty($aAbbr)){
$sEnd = end($aAbbr);
if($sEnd != 'et al'){
$aArticle['abbr'] = implode(',', array_slice($aAbbr, 0,3));
if(!empty($aArticle['abbr'])){
$aArticle['abbr'] .= ', et al';
}
}
}
$sCite = '';
if ($aArticle['journal_id'] == 22) {
$sCite = $aArticle['abbr'] . '. ' . $aArticle['title'] . '[J]. ' . choiseJabbr($aArticle['article_id'],$jabbr) . ',' . $stage_year . ',' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi'];
$sCite = $this->dealContent($sCite);
} else {
$sCite = $this->dealContent($aArticle['abbr']) . '. ' . $this->dealContent($aArticle['title']) . '. \textit{' . $this->dealContent(choiseJabbr($aArticle['article_id'], $jabbr)) . '}. ' . $stage_year . ';' . $stage_vol . $no . $aArticle['npp'] . '. doi:' . $aArticle['doi'];
}
return $sCite;
}
private function getArticleTime($aParam = []){
//必填值验证
$iArticleId = empty($aParam['article_id']) ? '' : $aParam['article_id'];
if(empty($iArticleId)){
return array('status' => 2,'msg' => 'Please select an article' );
}
//查询文章
$aWhere = ['article_id' => $iArticleId];
$aArticle= Db::name('article')->field('ctime,received_time')->where($aWhere)->find();
if(empty($aArticle)){
return array('status' => 2,'msg' => 'The article does not exist' );
}
//获取文章记录
$aWhere = ['article_id' => $iArticleId,'state' => 0,'state_to' => ['in',[0,1,5]]];
$aArticleMsg = Db::name('article_msg')->field('state_from,state_to,ctime')->where($aWhere)->order('ctime deac')->select();
$iReceivedTime = $iRevisionTime = $iAcceptedTime = 0;
if(!empty($aArticleMsg)){
foreach ($aArticleMsg as $key => $value) {
if(empty($iReceivedTime) && $value['state_to'] == 0){
$iReceivedTime = $value['ctime'];
}
if(empty($iRevisionTime) && $value['state_to'] == 1){
$iRevisionTime = $value['ctime'];
}
if(empty($iAcceptedTime) && $value['state_to'] == 5){
$iAcceptedTime = $value['ctime'];
}
}
}
$iReceivedTime = empty($iReceivedTime) ? $aArticle['received_time'] : $iReceivedTime;
$iReceivedTime = empty($iReceivedTime) ? $aArticle['ctime'] : $iReceivedTime;
$aTime = [];
$aTime['received_date'] = empty($iReceivedTime) ? '' : $this->timestampToEnglishDate($iReceivedTime);
$aTime['revision_date'] = empty($iRevisionTime) ? '' : $this->timestampToEnglishDate($iRevisionTime);
$aTime['accepted_date'] = empty($iAcceptedTime) ? '' : $this->timestampToEnglishDate($iAcceptedTime);
return ['status' => 1,'msg' => 'success','data' => $aTime];
}
/**
* 时间戳转换为「d F Y」格式如 12 June 2025
* @param int $timestamp 时间戳如1749600000
* @return string 格式化后的英文日期
*/
private function timestampToEnglishDate($timestamp) {
//验证时间戳有效性
if (!is_numeric($timestamp) || $timestamp < 0) {
return '';
}
//设置本地化确保月份为英文全称兼容Linux/Windows
$locale = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'
? 'English_United States.1252'
: 'en_US.UTF-8';
setlocale(LC_TIME, $locale);
//格式化d=日无前导零、F=英文月份全称、Y=四位年 strftime的%e在Linux下是无前导零的日Windows用%#d
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
$dateStr = strftime('%#d %B %Y', $timestamp); // Windows
} else {
$dateStr = strftime('%e %B %Y', $timestamp); // Linux/Mac
}
return trim($dateStr);
}
/**
* 内容处理
*/
private function dealContent($content = '', $target = 'latex',$iIsDeal = 1) {
// 空值直接返回
if (empty($content)) {
return '';
}
//统一编码为UTF-8
$content = mb_convert_encoding($content, 'UTF-8', mb_detect_encoding($content));
//过滤不可见/非法字符
$content = preg_replace('/[\x00-\x1F\x7F]/u', '', $content);
//整合所有替换规则按优先级排序先处理HTML实体再处理LaTeX特殊字符
$replaceRules = [
// ========== HTML实体替换 ==========
'&nbsp;' => '~', // HTML非断行空格 → LaTeX非断行空格
'&nbsp' => '~', // 兼容无分号的&nbsp
'&amp;' => '\&', // HTML& → LaTeX转义&
'&lt;' => '<', // HTML< → 直接保留
'&gt;' => '>', // HTML> → 直接保留
// ========== LaTeX特殊字符转义 ==========
'{' => '\{', // 左花括号转义
'}' => '\}', // 右花括号转义
'&' => '\&', // 原生&转义(需在&amp;之后,避免覆盖)
'%' => '\%', // 百分号转义LaTeX注释符
'_' => '\_', // 下划线转义LaTeX下标符
'κ' => '$\kappa$', // 希腊字母κ → LaTeX数学环境避免乱码
'-' => '\text{-}', // 短横线强制保留形态
':' => ':', // 冒号无需转义(占位,便于统一维护)
];
//执行批量替换
$content = strtr($content, $replaceRules);
//清理多余空格/换行
$content = preg_replace('/\s+/u', ' ', trim($content));
return $content;
}
/**
* @title curl 请求获取图片保存到本地
* @param sPath 图片链接地址
*/
private function getImage($sPath = '',$iId = 0){
//判断参数
if(empty($sPath) || empty($iId)){
return ['status' => 2,'msg' => 'url is empty','data' => ''];
}
//获取图片名称
$aImageInfo = pathinfo($sPath);
//图片后缀名
$sExtension = empty($aImageInfo['extension']) ? 'jpg' : $aImageInfo['extension'];
//图片地址
$sDir = ROOT_PATH.trim($this->sLatexUrl,'/').'/article_pdf/'.$iId.'/';
$sImagePath = $sDir.basename($sPath);
if (file_exists($sImagePath)) {
return ['status' => 1,'msg' => 'success','data' => $sImagePath];
}
//下载图片
if (!is_dir($sDir)) {
mkdir($sDir, 0755, true);
}
//curl 请求
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$sPath); // 设置请求URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 设置返回数据而不是直接输出
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 禁用SSL验证
$response = curl_exec($ch);
if (curl_errno($ch)) {
return ['status' => 3,'msg' => 'Error:' . curl_error($ch),'data' => $sImagePath];
}
//保存图片
file_put_contents($sImagePath, $response);
curl_close($ch);
return ['status' => 1,'msg' => 'success','data' => $sImagePath];
}
}
?>