From ae5033ccd70bca89c2268075f8eb3602c3f1e23d Mon Sep 17 00:00:00 2001 From: chengxl Date: Mon, 22 Dec 2025 10:08:24 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=9F=E6=88=90=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/api/controller/Production.php | 56 ++ application/common/LatexContent.php | 618 ++++++++++++++++++++++ 2 files changed, 674 insertions(+) create mode 100644 application/common/LatexContent.php diff --git a/application/api/controller/Production.php b/application/api/controller/Production.php index dd8490c..c26b1db 100644 --- a/application/api/controller/Production.php +++ b/application/api/controller/Production.php @@ -3227,4 +3227,60 @@ class Production extends Base } } } + + /** + * 生成初稿 + * @param article_id 文章ID + */ + public function createArticlePdf($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]; + $aProductionArticle = Db::name('production_article')->where($aWhere)->find(); + if(empty($aProductionArticle)){ + return json_encode(array('status' => 3,'msg' => 'No articles found' )); + } + + //内容 + $oLatexContent = new \app\common\LatexContent; + + //内容生成 + //获取第一页内容 + $aResult = $oLatexContent->buildFirst($aProductionArticle); + $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; + $sMsg = empty($aResult['msg']) ? 'Content generation failed-First' : $aResult['msg']; + $sFirstTemplateInfo = empty($aResult['data']) ? '' : $aResult['data']; + + if($iStatus != 1){ + return json_encode(array('status' => 4,'msg' => $sMsg)); + } + if(empty($sFirstTemplateInfo)){ + return json_encode(array('status' => 5,'msg' => 'Article content retrieval failed')); + } + + //生成主内容 + $aResult = $oLatexContent->buildMain($aProductionArticle); + $iStatus = empty($aResult['status']) ? 0 : $aResult['status']; + $sMsg = empty($aResult['msg']) ? 'Content generation failed-Main' : $aResult['msg']; + $sMainTemplateInfo = empty($aResult['data']) ? '' : $aResult['data']; + if($iStatus != 1){ + return json_encode(array('status' => 4,'msg' => $sMsg)); + } + if(empty($sMainTemplateInfo)){ + return json_encode(array('status' => 5,'msg' => 'Article content retrieval failed')); + } + + //生成文件 + $sTemplateInfo = $sFirstTemplateInfo."\n".$sMainTemplateInfo; + return json_encode(array('status' => 1,'msg' => 'PDF generated successfully')); + } } diff --git a/application/common/LatexContent.php b/application/common/LatexContent.php new file mode 100644 index 0000000..3df09b1 --- /dev/null +++ b/application/common/LatexContent.php @@ -0,0 +1,618 @@ +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>/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实体替换 ========== + ' ' => '~', // HTML非断行空格 → LaTeX非断行空格 + ' ' => '~', // 兼容无分号的  + '&' => '\&', // HTML& → LaTeX转义& + '<' => '<', // HTML< → 直接保留 + '>' => '>', // HTML> → 直接保留 + // ========== LaTeX特殊字符转义 ========== + '{' => '\{', // 左花括号转义 + '}' => '\}', // 右花括号转义 + '&' => '\&', // 原生&转义(需在&之后,避免覆盖) + '%' => '\%', // 百分号转义(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]; + + } + +} +?> \ No newline at end of file