Compare commits
8 Commits
6b9d119b27
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e370fe390 | ||
|
|
63416a4567 | ||
| da71dfc04e | |||
| 9c8f7cc3b6 | |||
| 5860f78f6d | |||
| 6fdc4efb6f | |||
| edb3c1b27b | |||
|
|
978c81ea10 |
@@ -1178,6 +1178,107 @@ class Base extends Controller
|
|||||||
return $ids;
|
return $ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析方括号引用内层(如 1,2 / 3-5),展开为文献序号列表。
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
protected function expandCitationBracketNumbers(string $referencePart): array
|
||||||
|
{
|
||||||
|
$referencePart = trim($referencePart);
|
||||||
|
if ($referencePart === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$referencePart = str_replace(
|
||||||
|
[',', '–', '—', '−', '‐', '‑'],
|
||||||
|
[',', '-', '-', '-', '-', '-'],
|
||||||
|
$referencePart
|
||||||
|
);
|
||||||
|
$out = [];
|
||||||
|
$segments = preg_split('/\s*,\s*/', $referencePart);
|
||||||
|
foreach ($segments as $seg) {
|
||||||
|
$seg = trim((string)$seg);
|
||||||
|
if ($seg === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$seg = str_replace(['–', '—', '−', '‐', '‑'], '-', $seg);
|
||||||
|
if (preg_match('/^(\d+)\s*-\s*(\d+)$/', $seg, $m)) {
|
||||||
|
$a = intval($m[1]);
|
||||||
|
$b = intval($m[2]);
|
||||||
|
if ($a > $b) {
|
||||||
|
$t = $a;
|
||||||
|
$a = $b;
|
||||||
|
$b = $t;
|
||||||
|
}
|
||||||
|
for ($i = $a; $i <= $b; $i++) {
|
||||||
|
$out[] = $i;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$n = intval($seg);
|
||||||
|
if ($n > 0) {
|
||||||
|
$out[] = $n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从正文片段提取被引用的文献序号(reference_no = index+1)。
|
||||||
|
* 兼容 <mycite data-id="p_refer_id"> 与 <blue>[n]</blue> / [n] 两种形态。
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
protected function extractCitationRefNosFromMainContent(string $text, int $pArticleId = 0): array
|
||||||
|
{
|
||||||
|
if ($text === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$nos = [];
|
||||||
|
|
||||||
|
$pReferIds = $this->extractMyciteIds($text);
|
||||||
|
if (!empty($pReferIds) && $pArticleId > 0) {
|
||||||
|
$refers = Db::name('production_article_refer')
|
||||||
|
->where('p_article_id', $pArticleId)
|
||||||
|
->whereIn('p_refer_id', $pReferIds)
|
||||||
|
->where('state', 0)
|
||||||
|
->field('p_refer_id,index')
|
||||||
|
->select();
|
||||||
|
$idToNo = [];
|
||||||
|
foreach ($refers as $row) {
|
||||||
|
$idToNo[intval($row['p_refer_id'])] = intval($row['index']) + 1;
|
||||||
|
}
|
||||||
|
foreach ($pReferIds as $pid) {
|
||||||
|
if (isset($idToNo[$pid])) {
|
||||||
|
$nos[] = $idToNo[$pid];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match_all('/(?:<\s*blue[^>]*>)?\[([^\]]+)\](?:<\/\s*blue\s*>)?/iu', $text, $m)) {
|
||||||
|
foreach ($m[1] as $inner) {
|
||||||
|
$innerNorm = str_replace(
|
||||||
|
[',', '–', '—', '−', '‐', '‑'],
|
||||||
|
[',', '-', '-', '-', '-', '-'],
|
||||||
|
trim((string)$inner)
|
||||||
|
);
|
||||||
|
if (!preg_match('/^[\d\s,\-]+$/u', $innerNorm)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($this->expandCitationBracketNumbers($innerNorm) as $n) {
|
||||||
|
if ($n > 0) {
|
||||||
|
$nos[] = $n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$nos = array_values(array_unique($nos));
|
||||||
|
sort($nos, SORT_NUMERIC);
|
||||||
|
return $nos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* table_data:二维数组 JSON [[{text,colspan,rowspan},...],...];支持双重 JSON 字符串编码。
|
* table_data:二维数组 JSON [[{text,colspan,rowspan},...],...];支持双重 JSON 字符串编码。
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1385,7 +1385,7 @@ class EmailClient extends Base
|
|||||||
$factoryId = intval($this->request->param('promotion_factory_id', 0));
|
$factoryId = intval($this->request->param('promotion_factory_id', 0));
|
||||||
$sendDate = trim($this->request->param('send_date', date('Y-m-d', strtotime('+1 day'))));
|
$sendDate = trim($this->request->param('send_date', date('Y-m-d', strtotime('+1 day'))));
|
||||||
$taskName = trim($this->request->param('task_name', ''));
|
$taskName = trim($this->request->param('task_name', ''));
|
||||||
$noRepeatDays = intval($this->request->param('no_repeat_days', 30));
|
$noRepeatDays = intval($this->request->param('no_repeat_days', 15));
|
||||||
$minInterval = intval($this->request->param('min_interval', 30));
|
$minInterval = intval($this->request->param('min_interval', 30));
|
||||||
$maxInterval = intval($this->request->param('max_interval', 60));
|
$maxInterval = intval($this->request->param('max_interval', 60));
|
||||||
$maxBounceRate = intval($this->request->param('max_bounce_rate', 5));
|
$maxBounceRate = intval($this->request->param('max_bounce_rate', 5));
|
||||||
@@ -2624,8 +2624,8 @@ class EmailClient extends Base
|
|||||||
$expertType = intval($factory['expert_type']);
|
$expertType = intval($factory['expert_type']);
|
||||||
$dailyLimit = max(1, intval($factory['send_count']));
|
$dailyLimit = max(1, intval($factory['send_count']));
|
||||||
|
|
||||||
// 默认频次:expert=30天,内部=60天
|
// 默认频次:expert=15天,内部=20天
|
||||||
$noRepeatDaysDefault = $expertType === 5 ? 30 : 60;
|
$noRepeatDaysDefault = $expertType === 5 ? 15 : 20;
|
||||||
$noRepeatDays = intval($this->request->param('no_repeat_days', $noRepeatDaysDefault));
|
$noRepeatDays = intval($this->request->param('no_repeat_days', $noRepeatDaysDefault));
|
||||||
|
|
||||||
if ($expertType === 5) {
|
if ($expertType === 5) {
|
||||||
@@ -2734,7 +2734,7 @@ class EmailClient extends Base
|
|||||||
|
|
||||||
$query = Db::name('expert')->alias('e')
|
$query = Db::name('expert')->alias('e')
|
||||||
->join('t_expert_field ef', 'e.expert_id = ef.expert_id', 'inner')
|
->join('t_expert_field ef', 'e.expert_id = ef.expert_id', 'inner')
|
||||||
->where('e.state', 0)
|
// ->where('e.state', 0)
|
||||||
->where('e.unsubscribed', 0)
|
->where('e.unsubscribed', 0)
|
||||||
->where('ef.state', 0);
|
->where('ef.state', 0);
|
||||||
|
|
||||||
@@ -2776,11 +2776,16 @@ class EmailClient extends Base
|
|||||||
$query->where('e.country_id', 'in', $countryIds);
|
$query->where('e.country_id', 'in', $countryIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query
|
$res1 = $query
|
||||||
->field('e.*')
|
->field('e.*')
|
||||||
->group('e.expert_id')
|
->group('e.expert_id')
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->select();
|
->select();
|
||||||
|
|
||||||
|
|
||||||
|
// echo $query->getLastSql();
|
||||||
|
|
||||||
|
return $res1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -217,6 +217,24 @@ class Finalreview extends Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($aLists as $key => $value) {
|
||||||
|
$rr = Db::name("article_reviewer_final")->where("reviewer_id",$value['user_id'])->order("id desc")->limit(1)->select();
|
||||||
|
if(isset($rr[0])){
|
||||||
|
$aLists[$key]['last_time'] = $rr[0]['invited_time'];
|
||||||
|
}else{
|
||||||
|
$aLists[$key]['last_time'] = 0;
|
||||||
|
}
|
||||||
|
$info = Db::name("user_reviewer_info")->field("field,field_ai")->where("reviewer_id",$value['user_id'])->find();
|
||||||
|
if($info){
|
||||||
|
$aLists[$key]['field'] = $info['field'];
|
||||||
|
$aLists[$key]['field_ai'] = $info['field_ai'];
|
||||||
|
}else{
|
||||||
|
$aLists[$key]['field'] = '';
|
||||||
|
$aLists[$key]['field_ai'] = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
return json_encode(['status' => 1,'msg' => 'success','data' => ['total' => $iCount,'lists' => $aLists]]);
|
return json_encode(['status' => 1,'msg' => 'success','data' => ['total' => $iCount,'lists' => $aLists]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,24 @@ class Journal extends Base {
|
|||||||
return jsonSuccess($program);
|
return jsonSuccess($program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function citeMate(){
|
||||||
|
$data = $this->request->post();
|
||||||
|
$rule = new Validate([
|
||||||
|
"journal_id"=>"require",
|
||||||
|
"year"=>"require"
|
||||||
|
]);
|
||||||
|
if(!$rule->check($data)){
|
||||||
|
return jsonError($rule->getError());
|
||||||
|
}
|
||||||
|
$journal_info = $this->journal_obj->where("journal_id",$data['journal_id'])->find();
|
||||||
|
$url = "http://journalapi.tmrjournals.com/public/index.php/api/Main/citeMate";
|
||||||
|
$program['journal_issn'] = $journal_info['issn'];
|
||||||
|
$program['year'] = $data['year'];
|
||||||
|
$res = object_to_array(json_decode(myPost($url,$program)));
|
||||||
|
|
||||||
|
return json($res);
|
||||||
|
}
|
||||||
|
|
||||||
public function delJournalStage(){
|
public function delJournalStage(){
|
||||||
$data = $this->request->post();
|
$data = $this->request->post();
|
||||||
$rule = new Validate([
|
$rule = new Validate([
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use think\Env;
|
|||||||
use think\Queue;
|
use think\Queue;
|
||||||
use think\Validate;
|
use think\Validate;
|
||||||
use app\common\CrossrefService;
|
use app\common\CrossrefService;
|
||||||
use app\common\ReferenceCheckService;
|
use app\common\ReferenceRelevanceCheckService;
|
||||||
|
|
||||||
class Preaccept extends Base
|
class Preaccept extends Base
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ class Preaccept extends Base
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
(new ReferenceCheckService())->clearArticleChecksByPArticleId($pArticleId);
|
(new ReferenceRelevanceCheckService())->clearArticleChecksByPArticleId($pArticleId);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\think\Log::error(
|
\think\Log::error(
|
||||||
'resetArticleChecksOnReferChange[' . $sourceTag . '] p_article_id='
|
'resetArticleChecksOnReferChange[' . $sourceTag . '] p_article_id='
|
||||||
@@ -1221,6 +1221,14 @@ class Preaccept extends Base
|
|||||||
$insert['ctime'] = time();
|
$insert['ctime'] = time();
|
||||||
$this->article_main_log_obj->insert($insert);
|
$this->article_main_log_obj->insert($insert);
|
||||||
|
|
||||||
|
// $articleId = intval($am_info['article_id']);
|
||||||
|
// $amId = intval($data['am_id']);
|
||||||
|
//
|
||||||
|
// // 本段引用集合变化(如 10,11 → 11,12)时仅清空该 am_id 下的校对明细
|
||||||
|
// if ($this->hasMainCitationChange($old_content, $new_raw_content, $articleId)) {
|
||||||
|
// $this->clearMainChecksOnCitationChange($articleId, $amId);
|
||||||
|
// }
|
||||||
|
|
||||||
// 判断是否存在“引用删除”(新 content 相对旧 content 缺少 <mycite>)
|
// 判断是否存在“引用删除”(新 content 相对旧 content 缺少 <mycite>)
|
||||||
$hasCitationDeletion = $this->hasMyciteDeletion($old_content, $new_raw_content);
|
$hasCitationDeletion = $this->hasMyciteDeletion($old_content, $new_raw_content);
|
||||||
|
|
||||||
@@ -1246,6 +1254,39 @@ class Preaccept extends Base
|
|||||||
//返回更新数据 20260119 end
|
//返回更新数据 20260119 end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正文单节保存后,仅清空该 am_id 下已有的引用校对明细(按 article_id 定位)。
|
||||||
|
*/
|
||||||
|
private function clearMainChecksOnCitationChange(int $articleId, int $amId)
|
||||||
|
{
|
||||||
|
if ($articleId <= 0 || $amId <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
(new ReferenceCheckService())->clearChecksByAmId($articleId, $amId);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\think\Log::error(
|
||||||
|
'clearMainChecksOnCitationChange article_id=' . $articleId
|
||||||
|
. ' am_id=' . $amId . ' ' . $e->getMessage()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本段正文引用集合是否变化(增删改任一即 true)。
|
||||||
|
* old 多为库内 <blue>[n]</blue>,new 多为编辑器提交的 <mycite data-id="p_refer_id">。
|
||||||
|
*/
|
||||||
|
private function hasMainCitationChange(string $oldContent, string $newContent, int $articleId): bool
|
||||||
|
{
|
||||||
|
$pArticleId = intval(Db::name('production_article')
|
||||||
|
->where('article_id', $articleId)
|
||||||
|
->whereIn('state', [0, 2])
|
||||||
|
->value('p_article_id'));
|
||||||
|
$oldNos = $this->extractCitationRefNosFromMainContent($oldContent, $pArticleId);
|
||||||
|
$newNos = $this->extractCitationRefNosFromMainContent($newContent, $pArticleId);
|
||||||
|
return $oldNos !== $newNos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否发生 <mycite> 删除(new 相对 old 少了任意引用 id)
|
* 是否发生 <mycite> 删除(new 相对 old 少了任意引用 id)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ use think\Db;
|
|||||||
use think\Env;
|
use think\Env;
|
||||||
use think\Queue;
|
use think\Queue;
|
||||||
use app\common\ReferenceCheckService;
|
use app\common\ReferenceCheckService;
|
||||||
|
use app\common\ReferenceRelevanceCheckService;
|
||||||
|
use app\common\DbReconnectHelper;
|
||||||
/**
|
/**
|
||||||
* @title 参考文献
|
* @title 参考文献
|
||||||
* @description 相关方法汇总
|
* @description 相关方法汇总
|
||||||
@@ -1309,38 +1311,48 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
return json_encode(['status' => 8,'msg' => 'fail']);
|
return json_encode(['status' => 8,'msg' => 'fail']);
|
||||||
}
|
}
|
||||||
/**
|
// ============================================================
|
||||||
* 参考文献第一次校对
|
// 参考文献「主题相关性」校对(RabbitMQ 链式消费,复用 reference_check 队列)
|
||||||
* @return \think\response\Json
|
// 表:t_article_reference_relevance_check_result / t_article_reference_relevance_check_batch
|
||||||
*/
|
// 消费:php think reference_check:mq-consume
|
||||||
public function allReferenceCheckAI(){
|
// ============================================================
|
||||||
//获取参数
|
|
||||||
$aParam = empty($aParam) ? $this->request->post() : $aParam;
|
|
||||||
|
|
||||||
//必填值验证
|
/**
|
||||||
$iPArticleId = empty($aParam['p_article_id']) ? '' : $aParam['p_article_id'];
|
* 启动整篇参考文献相关性校对
|
||||||
if(empty($iPArticleId)){
|
* POST: p_article_id(必填)
|
||||||
return json_encode(array('status' => 2,'msg' => 'Please select an article' ));
|
*
|
||||||
|
* 文献摘要/内容优先读 t_production_article_refer.abstract_text、refer_content_cleaned;
|
||||||
|
* 二者都为空时在校对执行阶段抓取并回写 refer 表,校对时始终从 refer 表读取。
|
||||||
|
*/
|
||||||
|
public function allReferenceCheckAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
if ($iPArticleId <= 0) {
|
||||||
|
return jsonError('Please select an article');
|
||||||
}
|
}
|
||||||
//查询文章(p_article_id 与 article_id 都要带,下游服务方法两者都用)
|
|
||||||
$aWhere = ['p_article_id' => $iPArticleId,'state' => ['in',[0,2]]];
|
$aProductionArticle = Db::name('production_article')
|
||||||
$aProductionArticle = Db::name('production_article')->field('p_article_id,article_id')->where($aWhere)->find();
|
->field('p_article_id,article_id')
|
||||||
if(empty($aProductionArticle)){
|
->where(['p_article_id' => $iPArticleId, 'state' => ['in', [0, 2]]])
|
||||||
return json_encode(array('status' => 3,'msg' => 'No articles found' ));
|
->find();
|
||||||
|
if (empty($aProductionArticle)) {
|
||||||
|
return jsonError('No articles found');
|
||||||
}
|
}
|
||||||
if($this->checkReferStatus($iPArticleId)==0){
|
if ($this->checkReferStatus($iPArticleId) == 0) {
|
||||||
return jsonError('Please correct the reference content before running the check.');
|
return jsonError('Please correct the reference content before running the check.');
|
||||||
}
|
}
|
||||||
//已存在校对记录则禁止重复执行第一次校对,提示走重置接口
|
|
||||||
$iExisting = Db::name('article_reference_check_result')
|
$existing = Db::name('article_reference_relevance_check_result')
|
||||||
->where('p_article_id', $iPArticleId)
|
->where('p_article_id', $iPArticleId)
|
||||||
->count();
|
->count();
|
||||||
if(intval($iExisting) > 0){
|
if (intval($existing) > 0) {
|
||||||
return jsonError('This article already has a reference check record. Please use the "Reset Check" endpoint to run the check again.');
|
return jsonError('This article already has relevance check records.');
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$svc = new ReferenceCheckService();
|
DbReconnectHelper::ensure();
|
||||||
$result = $svc->enqueueByPArticle($aProductionArticle);
|
$result = (new ReferenceRelevanceCheckService())->enqueueByPArticle($aProductionArticle);
|
||||||
if (empty($result['check_ids'])) {
|
if (empty($result['check_ids'])) {
|
||||||
return jsonError('No reference citations were found in the article.');
|
return jsonError('No reference citations were found in the article.');
|
||||||
}
|
}
|
||||||
@@ -1349,8 +1361,156 @@ class References extends Base
|
|||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文献校对重置:删除该文章已有的全部校对明细,并重新入队整篇校对
|
* 相关性校对进度(同 referenceCheckProgressAI)
|
||||||
|
* POST/GET: p_article_id(必填)
|
||||||
|
*/
|
||||||
|
public function referenceRelevanceCheckProgressAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
if (empty($aParam)) {
|
||||||
|
$aParam = $this->request->param();
|
||||||
|
}
|
||||||
|
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
if ($iPArticleId <= 0) {
|
||||||
|
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = (new ReferenceRelevanceCheckService())->getProgressByPArticleId($iPArticleId);
|
||||||
|
return jsonSuccess($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 p_article_id 查整篇文章相关性校对总状态(同 referenceCheckArticleStatusAI)
|
||||||
|
* POST/GET: p_article_id(必填)
|
||||||
|
*/
|
||||||
|
public function referenceRelevanceCheckArticleStatusAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
if (empty($aParam)) {
|
||||||
|
$aParam = $this->request->param();
|
||||||
|
}
|
||||||
|
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
if ($iPArticleId <= 0) {
|
||||||
|
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = (new ReferenceRelevanceCheckService())->getArticleProgressStatusByPArticleId($iPArticleId);
|
||||||
|
return jsonSuccess($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 p_refer_id 查单条参考文献的相关性校对明细与进度(同 referenceCheckDetailsAI)
|
||||||
|
* POST/GET: p_refer_id(必填)
|
||||||
|
*/
|
||||||
|
public function referenceRelevanceCheckDetailsAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
if (empty($aParam)) {
|
||||||
|
$aParam = $this->request->param();
|
||||||
|
}
|
||||||
|
|
||||||
|
$iPReferId = empty($aParam['p_refer_id']) ? 0 : intval($aParam['p_refer_id']);
|
||||||
|
if ($iPReferId <= 0) {
|
||||||
|
return json_encode(array('status' => 2, 'msg' => 'Please select a reference'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = (new ReferenceRelevanceCheckService())->getDetailsByPReferId($iPReferId);
|
||||||
|
return jsonSuccess($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空并重新执行相关性校对
|
||||||
|
* POST: p_article_id
|
||||||
|
*/
|
||||||
|
public function referenceRelevanceCheckResetAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
if ($iPArticleId <= 0) {
|
||||||
|
return jsonError('Please select an article');
|
||||||
|
}
|
||||||
|
$aProductionArticle = Db::name('production_article')
|
||||||
|
->field('p_article_id,article_id')
|
||||||
|
->where(['p_article_id' => $iPArticleId, 'state' => ['in', [0, 2]]])
|
||||||
|
->find();
|
||||||
|
if (empty($aProductionArticle)) {
|
||||||
|
return jsonError('No articles found');
|
||||||
|
}
|
||||||
|
if ($this->checkReferStatus($iPArticleId) == 0) {
|
||||||
|
return jsonError('Please correct the reference content before running the check.');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$result = (new ReferenceRelevanceCheckService())->resetAndRecheckByArticle($aProductionArticle);
|
||||||
|
return jsonSuccess($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅清空相关性校对记录(不重跑)
|
||||||
|
* POST: p_article_id
|
||||||
|
*/
|
||||||
|
public function referenceRelevanceCheckClearAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
if ($iPArticleId <= 0) {
|
||||||
|
return jsonError('p_article_id is required');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$deleted = (new ReferenceRelevanceCheckService())->clearByPArticleId($iPArticleId);
|
||||||
|
return jsonSuccess(['p_article_id' => $iPArticleId, 'deleted' => intval($deleted)]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅重跑相关性 status=0 的记录(不清空,不抓摘要,不清洗文献内容)
|
||||||
|
* POST: p_article_id
|
||||||
|
*/
|
||||||
|
public function referenceRelevanceCheckRecheckPendingAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
if ($iPArticleId <= 0) {
|
||||||
|
return jsonError('p_article_id is required');
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$result = (new ReferenceRelevanceCheckService())->recheckPendingOnlyByArticle($iPArticleId);
|
||||||
|
return jsonSuccess($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 支撑力度校对已下线,请使用 allReferenceCheckAI(主题相关性校对)
|
||||||
|
*/
|
||||||
|
public function allReferenceCheckAI2()
|
||||||
|
{
|
||||||
|
return jsonError('Support strength check is deprecated. Please use allReferenceCheckAI.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文献校对重置:删除该文章已有的全部相关性校对明细,并重新入队整篇校对
|
||||||
* POST/GET: article_id(必填)
|
* POST/GET: article_id(必填)
|
||||||
* @url /api/Article/referenceCheckReset
|
* @url /api/Article/referenceCheckReset
|
||||||
*/
|
*/
|
||||||
@@ -1378,7 +1538,7 @@ class References extends Base
|
|||||||
return json_encode(array('status' => 4,'msg' => 'Unbound article' ));
|
return json_encode(array('status' => 4,'msg' => 'Unbound article' ));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$result = (new ReferenceCheckService())->resetAndRecheckByArticle($aProductionArticle);
|
$result = (new ReferenceRelevanceCheckService())->resetAndRecheckByArticle($aProductionArticle);
|
||||||
return jsonSuccess($result);
|
return jsonSuccess($result);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
@@ -1415,7 +1575,7 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$deleted = (new ReferenceCheckService())->clearArticleChecksByPArticleId($iPArticleId);
|
$deleted = (new ReferenceRelevanceCheckService())->clearByPArticleId($iPArticleId);
|
||||||
return jsonSuccess([
|
return jsonSuccess([
|
||||||
'p_article_id' => $iPArticleId,
|
'p_article_id' => $iPArticleId,
|
||||||
'deleted' => intval($deleted),
|
'deleted' => intval($deleted),
|
||||||
@@ -1426,7 +1586,7 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按 p_article_id 查整篇引用校对进度(按 reference_no 分组聚合)
|
* 按 p_article_id 查整篇相关性校对进度(按 reference_no 分组聚合)
|
||||||
*
|
*
|
||||||
* POST/GET: p_article_id(必填)
|
* POST/GET: p_article_id(必填)
|
||||||
*
|
*
|
||||||
@@ -1439,6 +1599,8 @@ class References extends Base
|
|||||||
* records[i].status 与分组同一套数值含义(但 record 不会出现 1=校对中):
|
* records[i].status 与分组同一套数值含义(但 record 不会出现 1=校对中):
|
||||||
* 0 = 待校验 2 = 校对完成 3 = 校对失败
|
* 0 = 待校验 2 = 校对完成 3 = 校对失败
|
||||||
*
|
*
|
||||||
|
* records[i] 含 reason(中英双语)、reason_en、combined_reason(中英双语)、combined_reason_en
|
||||||
|
*
|
||||||
* summary 用字符串键:pending / checking / completed / failed
|
* summary 用字符串键:pending / checking / completed / failed
|
||||||
*/
|
*/
|
||||||
public function referenceCheckProgressAI()
|
public function referenceCheckProgressAI()
|
||||||
@@ -1453,7 +1615,7 @@ class References extends Base
|
|||||||
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
return json_encode(array('status' => 2, 'msg' => 'Please select an article'));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$result = (new ReferenceCheckService())->getProgressByPArticleId($iPArticleId);
|
$result = (new ReferenceRelevanceCheckService())->getProgressByPArticleId($iPArticleId);
|
||||||
return jsonSuccess($result);
|
return jsonSuccess($result);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
@@ -1461,7 +1623,7 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按 p_article_id 查整篇文章引用校对总状态(用于前端按钮分流)
|
* 按 p_article_id 查整篇文章相关性校对总状态(用于前端按钮分流)
|
||||||
*
|
*
|
||||||
* POST/GET: p_article_id(必填)
|
* POST/GET: p_article_id(必填)
|
||||||
*
|
*
|
||||||
@@ -1495,7 +1657,7 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = (new ReferenceCheckService())->getArticleProgressStatusByPArticleId($iPArticleId);
|
$result = (new ReferenceRelevanceCheckService())->getArticleProgressStatusByPArticleId($iPArticleId);
|
||||||
return jsonSuccess($result);
|
return jsonSuccess($result);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
@@ -1523,7 +1685,7 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = (new ReferenceCheckService())->getArticleCheckQueuePositionByPArticleId($iPArticleId);
|
$result = (new ReferenceRelevanceCheckService())->getArticleCheckQueuePositionByPArticleId($iPArticleId);
|
||||||
return jsonSuccess($result);
|
return jsonSuccess($result);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
@@ -1531,13 +1693,12 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 某条参考文献下「校对失败」的明细重新校对(异步)
|
* 某条参考文献下「相关性校对失败」的明细重新校对(异步)
|
||||||
*
|
*
|
||||||
* POST/GET: p_refer_id(必填)
|
* POST/GET: p_refer_id(必填)
|
||||||
* p_article_id(可选)
|
* p_article_id(可选)
|
||||||
*
|
*
|
||||||
* 仅重跑 status=3(校对失败)的记录;不改动 refer_text,只重置结果字段后入 RabbitMQ 批次队列。
|
* 仅重跑 status=3(校对失败)的记录;不改动 refer_text,只重置结果字段后入 RabbitMQ 批次队列。
|
||||||
* 返回:p_refer_id、p_article_id、reset、queued、check_ids、queue
|
|
||||||
*/
|
*/
|
||||||
public function referenceCheckRecheckFailedAI()
|
public function referenceCheckRecheckFailedAI()
|
||||||
{
|
{
|
||||||
@@ -1554,21 +1715,53 @@ class References extends Base
|
|||||||
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = (new ReferenceCheckService())->enqueueRecheckFailedByPReferId($iPReferId, $iPArticleId);
|
$result = (new ReferenceRelevanceCheckService())->enqueueRecheckFailedByPReferId($iPReferId, $iPArticleId);
|
||||||
return jsonSuccess([]);
|
return jsonSuccess($result);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按 p_refer_id 查单条参考文献的校对明细与进度
|
* 某条参考文献下「校对失败」重跑,并联动同一引用标签分组(如 [1,2])全部重跑(异步)
|
||||||
|
*
|
||||||
|
* POST/GET: p_refer_id(必填)
|
||||||
|
* p_article_id(可选)
|
||||||
|
*
|
||||||
|
* 返回:p_refer_id、p_article_id、reset、queued、check_ids、queue
|
||||||
|
*/
|
||||||
|
public function referenceCheckRecheckFailedWithGroupAI()
|
||||||
|
{
|
||||||
|
$aParam = $this->request->post();
|
||||||
|
if (empty($aParam)) {
|
||||||
|
$aParam = $this->request->param();
|
||||||
|
}
|
||||||
|
|
||||||
|
$iPReferId = empty($aParam['p_refer_id']) ? 0 : intval($aParam['p_refer_id']);
|
||||||
|
if ($iPReferId <= 0) {
|
||||||
|
return json_encode(array('status' => 2, 'msg' => 'Please select a reference'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$iPArticleId = empty($aParam['p_article_id']) ? 0 : intval($aParam['p_article_id']);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = (new ReferenceRelevanceCheckService())->enqueueRecheckFailedByPReferIdWithGroup($iPReferId, $iPArticleId);
|
||||||
|
return jsonSuccess($result);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return jsonError($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按 p_refer_id 查单条参考文献的相关性校对明细与进度
|
||||||
*
|
*
|
||||||
* POST/GET: p_refer_id(必填)
|
* POST/GET: p_refer_id(必填)
|
||||||
*
|
*
|
||||||
* 分组进度:progress_status(0待/1中/2完成/3失败)、pending、done、failed、pass、
|
* 分组进度:progress_status(0待/1中/2完成/3失败)、pending、done、failed、pass、
|
||||||
* is_pass、progress_percent、last_updated_at
|
* is_pass、progress_percent、last_updated_at
|
||||||
* list 每项:check_id、am_id、status、confidence、reason、is_match、is_pass
|
* list 每项:check_id、am_id、status、is_relevant、relevance_level、relevance_role、
|
||||||
|
* relevance_score、reason(中英双语【中文】/【English】)、reason_en、
|
||||||
|
* combined_*、combined_reason_en、cite_group_refs、cite_check_mode、is_pass
|
||||||
*/
|
*/
|
||||||
public function referenceCheckDetailsAI()
|
public function referenceCheckDetailsAI()
|
||||||
{
|
{
|
||||||
@@ -1583,13 +1776,33 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$result = (new ReferenceCheckService())->getCheckDetailsByPReferId($iPReferId);
|
$result = (new ReferenceRelevanceCheckService())->getDetailsByPReferId($iPReferId);
|
||||||
return jsonSuccess($result);
|
return jsonSuccess($result);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
return jsonError($e->getMessage());
|
return jsonError($e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对校对明细中从未出现过的参考文献(p_refer_id 差集)重新扫描全文并入队校对
|
||||||
|
*
|
||||||
|
* POST/GET: p_article_id(必填)
|
||||||
|
*
|
||||||
|
* 差集:production_article_refer(state=0) 减去 article_reference_check_result 已出现的 p_refer_id。
|
||||||
|
* 适用:首次校对漏匹配、表格后上传、正文补标等场景。不重置已有明细。
|
||||||
|
* 前置:须已执行过第一次校对(库中已有校对记录)。
|
||||||
|
*
|
||||||
|
* 返回:missing_p_refer_ids、matched_p_refer_ids、still_unmatched_p_refer_ids、
|
||||||
|
* queued、new_reference_nos、check_ids、queue
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @deprecated 支撑力度漏匹配补扫已下线,请清空后使用 allReferenceCheckAI 重新校对
|
||||||
|
*/
|
||||||
|
public function referenceCheckRematchNewAI()
|
||||||
|
{
|
||||||
|
return jsonError('Support strength rematch is deprecated. Please use referenceCheckResetAI or allReferenceCheckAI.');
|
||||||
|
}
|
||||||
|
|
||||||
public function checkReferStatus($p_article_id){
|
public function checkReferStatus($p_article_id){
|
||||||
$list = $this->production_article_refer_obj->where('p_article_id', $p_article_id)->where('state', 0)->select();
|
$list = $this->production_article_refer_obj->where('p_article_id', $p_article_id)->where('state', 0)->select();
|
||||||
if (!$list) {
|
if (!$list) {
|
||||||
@@ -1604,4 +1817,6 @@ class References extends Base
|
|||||||
}
|
}
|
||||||
return $frag;
|
return $frag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class ReferenceCheckMqConsume extends Command
|
|||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this->setName('reference_check:mq-consume')
|
$this->setName('reference_check:mq-consume')
|
||||||
->setDescription('Consume RabbitMQ reference check article queue');
|
->setDescription('Consume RabbitMQ reference relevance check article queue (ref_check.article)');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function execute(Input $input, Output $output)
|
protected function execute(Input $input, Output $output)
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ class CrossrefService
|
|||||||
private $timeout = 15; // 请求超时(秒)
|
private $timeout = 15; // 请求超时(秒)
|
||||||
private $maxRetry = 2; // 单个DOI最大重试次数
|
private $maxRetry = 2; // 单个DOI最大重试次数
|
||||||
private $crossrefUrl = "https://api.crossref.org/works/"; // 接口地址
|
private $crossrefUrl = "https://api.crossref.org/works/"; // 接口地址
|
||||||
|
private $pubmedAbbr = true; // CrossRef 无期刊缩写时,是否回退到 PubMed/NLM 规范缩写
|
||||||
|
|
||||||
|
/** @var PubmedService|null 懒加载 */
|
||||||
|
private $pubmedService = null;
|
||||||
|
|
||||||
public function __construct($config = [])
|
public function __construct($config = [])
|
||||||
{
|
{
|
||||||
@@ -24,6 +28,7 @@ class CrossrefService
|
|||||||
if (isset($config['timeout'])) $this->timeout = intval($config['timeout']);
|
if (isset($config['timeout'])) $this->timeout = intval($config['timeout']);
|
||||||
if (isset($config['maxRetry'])) $this->maxRetry = intval($config['maxRetry']);
|
if (isset($config['maxRetry'])) $this->maxRetry = intval($config['maxRetry']);
|
||||||
if (isset($config['crossrefUrl'])) $this->crossrefUrl = (string)$config['crossrefUrl'];
|
if (isset($config['crossrefUrl'])) $this->crossrefUrl = (string)$config['crossrefUrl'];
|
||||||
|
if (isset($config['pubmed_abbr'])) $this->pubmedAbbr = (bool)$config['pubmed_abbr'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +196,15 @@ class CrossrefService
|
|||||||
|
|
||||||
$title = $this->getTitle($msg);
|
$title = $this->getTitle($msg);
|
||||||
$publisher = $this->getPublisher($msg);
|
$publisher = $this->getPublisher($msg);
|
||||||
$joura = !empty($publisher['title']) ? $publisher['title'] : ($publisher['short_title'] ?? '');
|
$validDoi = $this->filterValidDoi($doi);
|
||||||
|
// 期刊缩写优先级:CrossRef short-container-title → PubMed/NLM 规范缩写 → CrossRef 全称
|
||||||
|
$shortTitle = trim((string)($publisher['short_title'] ?? ''));
|
||||||
|
$fullTitle = trim((string)($publisher['title'] ?? ''));
|
||||||
|
$joura = $shortTitle;
|
||||||
|
if ($joura === '') {
|
||||||
|
$pubmedAbbr = $this->lookupPubmedJournalAbbr($validDoi);
|
||||||
|
$joura = $pubmedAbbr !== '' ? $pubmedAbbr : $fullTitle;
|
||||||
|
}
|
||||||
$authors = $this->getAuthors($msg);
|
$authors = $this->getAuthors($msg);
|
||||||
$dateno = $this->getVolumeIssuePages($msg);
|
$dateno = $this->getVolumeIssuePages($msg);
|
||||||
$retractInfo = $this->checkRetracted($msg);
|
$retractInfo = $this->checkRetracted($msg);
|
||||||
@@ -260,26 +273,111 @@ class CrossrefService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取标题
|
* 提取标题(英文优先)
|
||||||
|
*
|
||||||
|
* CrossRef 的 title / original-title 可能包含多个语言版本(中文期刊/双语文章常见)。
|
||||||
|
* 这里优先返回不含中日韩字符的版本,全部为中文时才退回第一个。
|
||||||
*/
|
*/
|
||||||
public function getTitle($aDoiInfo = [])
|
public function getTitle($aDoiInfo = [])
|
||||||
{
|
{
|
||||||
return $aDoiInfo['title'][0] ?? '';
|
$candidates = [];
|
||||||
|
if (!empty($aDoiInfo['title']) && is_array($aDoiInfo['title'])) {
|
||||||
|
$candidates = array_merge($candidates, $aDoiInfo['title']);
|
||||||
|
}
|
||||||
|
if (!empty($aDoiInfo['original-title']) && is_array($aDoiInfo['original-title'])) {
|
||||||
|
$candidates = array_merge($candidates, $aDoiInfo['original-title']);
|
||||||
|
}
|
||||||
|
return $this->pickPreferredLatin($candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取期刊/出版社相关信息
|
* 提取期刊/出版社相关信息(期刊名英文优先)
|
||||||
*/
|
*/
|
||||||
public function getPublisher($aDoiInfo = [])
|
public function getPublisher($aDoiInfo = [])
|
||||||
{
|
{
|
||||||
|
$containerTitles = (!empty($aDoiInfo['container-title']) && is_array($aDoiInfo['container-title']))
|
||||||
|
? $aDoiInfo['container-title'] : [];
|
||||||
|
$shortTitles = (!empty($aDoiInfo['short-container-title']) && is_array($aDoiInfo['short-container-title']))
|
||||||
|
? $aDoiInfo['short-container-title'] : [];
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'title' => isset($aDoiInfo['container-title'][0]) ? $aDoiInfo['container-title'][0] : '',
|
'title' => $this->pickPreferredLatin($containerTitles),
|
||||||
'short_title' => isset($aDoiInfo['short-container-title'][0]) ? $aDoiInfo['short-container-title'][0] : '',
|
'short_title' => $this->pickPreferredLatin($shortTitles),
|
||||||
'ISSN' => $aDoiInfo['ISSN'] ?? [],
|
'ISSN' => $aDoiInfo['ISSN'] ?? [],
|
||||||
'publisher' => $aDoiInfo['publisher'] ?? '',
|
'publisher' => $aDoiInfo['publisher'] ?? '',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否包含中日韩(CJK)字符
|
||||||
|
*/
|
||||||
|
public function hasCjk($str)
|
||||||
|
{
|
||||||
|
$str = (string)$str;
|
||||||
|
if ($str === '') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return preg_match('/[\x{4e00}-\x{9fff}\x{3040}-\x{30ff}\x{ac00}-\x{d7af}\x{3400}-\x{4dbf}]/u', $str) === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从多个候选字符串中优先挑选「不含 CJK 字符」的一个;
|
||||||
|
* 全部为空则返回空串,全部含 CJK 则返回第一个非空值。
|
||||||
|
*
|
||||||
|
* @param array $candidates
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function pickPreferredLatin($candidates)
|
||||||
|
{
|
||||||
|
if (!is_array($candidates) || empty($candidates)) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$firstNonEmpty = '';
|
||||||
|
foreach ($candidates as $item) {
|
||||||
|
$s = trim((string)$item);
|
||||||
|
if ($s === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($firstNonEmpty === '') {
|
||||||
|
$firstNonEmpty = $s;
|
||||||
|
}
|
||||||
|
if (!$this->hasCjk($s)) {
|
||||||
|
return $s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $firstNonEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用 PubMed/NLM 反查期刊规范缩写(CrossRef 无缩写时的兜底)。
|
||||||
|
* 任何异常都吞掉并返回空串,保证不影响主流程。
|
||||||
|
*
|
||||||
|
* @param string $doi 已规整的裸 DOI
|
||||||
|
* @return string 缩写或空串
|
||||||
|
*/
|
||||||
|
private function lookupPubmedJournalAbbr($doi)
|
||||||
|
{
|
||||||
|
$doi = trim((string)$doi);
|
||||||
|
if (!$this->pubmedAbbr || $doi === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($this->pubmedService === null) {
|
||||||
|
$this->pubmedService = new PubmedService([
|
||||||
|
'email' => $this->mailto,
|
||||||
|
'timeout' => $this->timeout,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$abbr = $this->pubmedService->journalAbbrByDoi($doi);
|
||||||
|
return is_string($abbr) ? trim($abbr) : '';
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提取作者列表
|
* 提取作者列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -89,25 +89,31 @@ class ProductionArticleRefer
|
|||||||
]);
|
]);
|
||||||
$summary = $svc->fetchWorkSummary($doiNorm);
|
$summary = $svc->fetchWorkSummary($doiNorm);
|
||||||
if ($summary !== null && !empty($summary['doi'])) {
|
if ($summary !== null && !empty($summary['doi'])) {
|
||||||
$update_a = [];
|
|
||||||
$title = trim((string)($summary['title'] ?? ''));
|
$title = trim((string)($summary['title'] ?? ''));
|
||||||
$jouraRaw = trim((string)($summary['joura'] ?? ''));
|
$jouraRaw = trim((string)($summary['joura'] ?? ''));
|
||||||
// 姓全写 + 名首字母,超过 3 个作者取前 3 个 + et al
|
// 姓全写 + 名首字母,超过 3 个作者取前 3 个 + et al
|
||||||
$authorCitation = $svc->getAuthorsCitation($summary['raw'] ?? [], 3);
|
$authorCitation = $svc->getAuthorsCitation($summary['raw'] ?? [], 3);
|
||||||
$dateno = trim((string)($summary['dateno'] ?? ''));
|
|
||||||
$doilink = trim((string)($summary['doilink'] ?? ''));
|
// 英文优先兜底:若 CrossRef 结果的标题/期刊/作者仍含中日韩字符,
|
||||||
$update_a['title'] = $title;
|
// 说明该 DOI 元数据是中文,放弃 CrossRef 路径,改走下方 citation.doi.org(lang=en-US)
|
||||||
$update_a['author'] = $authorCitation !== '' ? $authorCitation . '.' : '';
|
$hasCjk = $svc->hasCjk($title) || $svc->hasCjk($jouraRaw) || $svc->hasCjk($authorCitation);
|
||||||
$update_a['joura'] = $jouraRaw;
|
if (!$hasCjk) {
|
||||||
$update_a['dateno'] = $dateno;
|
$update_a = [];
|
||||||
$update_a['refer_type'] = "journal";
|
$dateno = trim((string)($summary['dateno'] ?? ''));
|
||||||
$update_a['is_ja'] = 1;
|
$doilink = trim((string)($summary['doilink'] ?? ''));
|
||||||
$update_a['doilink'] = $doilink;
|
$update_a['title'] = $title;
|
||||||
$update_a['cs'] = 1;
|
$update_a['author'] = $authorCitation !== '' ? $authorCitation . '.' : '';
|
||||||
$update_a['update_time'] = time();
|
$update_a['joura'] = $jouraRaw;
|
||||||
$update_a['is_deal'] = 1;
|
$update_a['dateno'] = $dateno;
|
||||||
Db::name('production_article_refer')->where(['p_refer_id' => $iPReferId])->limit(1)->update($update_a);
|
$update_a['refer_type'] = "journal";
|
||||||
return json_encode(['status' => 1,'msg' => 'Update successful']);
|
$update_a['is_ja'] = 1;
|
||||||
|
$update_a['doilink'] = $doilink;
|
||||||
|
$update_a['cs'] = 1;
|
||||||
|
$update_a['update_time'] = time();
|
||||||
|
$update_a['is_deal'] = 1;
|
||||||
|
Db::name('production_article_refer')->where(['p_refer_id' => $iPReferId])->limit(1)->update($update_a);
|
||||||
|
return json_encode(['status' => 1,'msg' => 'Update successful']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//结束---用crossref接口的方式处理数据
|
//结束---用crossref接口的方式处理数据
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ class PubmedService
|
|||||||
$pmid = trim($pmid);
|
$pmid = trim($pmid);
|
||||||
if ($pmid === '') return null;
|
if ($pmid === '') return null;
|
||||||
|
|
||||||
$cacheKey = 'pmid_' . $pmid;
|
// v2:解析结果新增 journal_iso_abbr / journal_medline_ta,换 key 避免命中旧缓存
|
||||||
|
$cacheKey = 'pmid_v2_' . $pmid;
|
||||||
$cached = $this->cacheGet($cacheKey, 30 * 86400);
|
$cached = $this->cacheGet($cacheKey, 30 * 86400);
|
||||||
if (is_array($cached)) return $cached;
|
if (is_array($cached)) return $cached;
|
||||||
|
|
||||||
@@ -96,6 +97,84 @@ class PubmedService
|
|||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOI -> 期刊规范缩写(NLM/ISO 形式,如 "J Clin Oncol")
|
||||||
|
* 优先 ISOAbbreviation,回退 MedlineTA;查不到返回 null。
|
||||||
|
*/
|
||||||
|
public function journalAbbrByDoi(string $doi): ?string
|
||||||
|
{
|
||||||
|
$info = $this->fetchByDoi($doi);
|
||||||
|
if (!is_array($info)) return null;
|
||||||
|
|
||||||
|
$abbr = trim((string)($info['journal_iso_abbr'] ?? ''));
|
||||||
|
if ($abbr === '') {
|
||||||
|
$abbr = trim((string)($info['journal_medline_ta'] ?? ''));
|
||||||
|
}
|
||||||
|
return $abbr !== '' ? $abbr : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按书目信息检索 PubMed(标题 + 第一作者 + 年份)
|
||||||
|
*/
|
||||||
|
public function searchByBibliographic($title, $author = '', $year = ''): ?array
|
||||||
|
{
|
||||||
|
$title = trim((string)$title);
|
||||||
|
if ($title === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$terms = ['(' . $this->quoteTerm($title) . '[Title])'];
|
||||||
|
$author = trim((string)$author);
|
||||||
|
if ($author !== '') {
|
||||||
|
$parts = preg_split('/[,;]/', $author);
|
||||||
|
$first = trim((string)($parts[0] ?? ''));
|
||||||
|
if ($first !== '') {
|
||||||
|
$terms[] = '(' . $this->quoteTerm($first) . '[Author])';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$year = trim((string)$year);
|
||||||
|
if ($year !== '' && preg_match('/^(19|20)\d{2}$/', $year)) {
|
||||||
|
$terms[] = '(' . $year . '[pdat])';
|
||||||
|
}
|
||||||
|
|
||||||
|
$pmid = $this->esearch(implode(' AND ', $terms));
|
||||||
|
if (!$pmid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$info = $this->fetchByPmid($pmid);
|
||||||
|
if (!$info) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$info['pmid'] = $pmid;
|
||||||
|
$info['doi'] = $this->extractDoiFromPmidRecord($pmid);
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function quoteTerm($text)
|
||||||
|
{
|
||||||
|
return str_replace('"', '', trim((string)$text));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractDoiFromPmidRecord($pmid)
|
||||||
|
{
|
||||||
|
$url = $this->base . 'efetch.fcgi?' . http_build_query([
|
||||||
|
'db' => 'pubmed',
|
||||||
|
'id' => $pmid,
|
||||||
|
'retmode' => 'xml',
|
||||||
|
'tool' => $this->tool,
|
||||||
|
'email' => $this->email,
|
||||||
|
]);
|
||||||
|
$xml = $this->httpGet($url);
|
||||||
|
if ($xml === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (preg_match('/<ArticleId IdType="doi">([^<]+)<\/ArticleId>/i', $xml, $m)) {
|
||||||
|
return trim($m[1]);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------- Internals -----------------
|
// ----------------- Internals -----------------
|
||||||
|
|
||||||
private function esearch(string $term): ?string
|
private function esearch(string $term): ?string
|
||||||
@@ -162,6 +241,9 @@ class PubmedService
|
|||||||
$pubTypes = array_values(array_unique($pubTypes));
|
$pubTypes = array_values(array_unique($pubTypes));
|
||||||
|
|
||||||
$journal = $this->xpText($xp, '//PubmedArticle//Journal//Title');
|
$journal = $this->xpText($xp, '//PubmedArticle//Journal//Title');
|
||||||
|
// 期刊规范缩写:ISOAbbreviation(Journal 下)与 MedlineTA(MedlineJournalInfo 下)
|
||||||
|
$journalIsoAbbr = $this->xpText($xp, '//PubmedArticle//Journal//ISOAbbreviation');
|
||||||
|
$journalMedlineTa = $this->xpText($xp, '//PubmedArticle//MedlineJournalInfo//MedlineTA');
|
||||||
|
|
||||||
$year = '';
|
$year = '';
|
||||||
$year = $this->xpText($xp, '//PubmedArticle//JournalIssue//PubDate//Year');
|
$year = $this->xpText($xp, '//PubmedArticle//JournalIssue//PubDate//Year');
|
||||||
@@ -182,6 +264,8 @@ class PubmedService
|
|||||||
'mesh_terms' => $mesh,
|
'mesh_terms' => $mesh,
|
||||||
'publication_types' => $pubTypes,
|
'publication_types' => $pubTypes,
|
||||||
'journal' => $journal,
|
'journal' => $journal,
|
||||||
|
'journal_iso_abbr' => $journalIsoAbbr,
|
||||||
|
'journal_medline_ta' => $journalMedlineTa,
|
||||||
'year' => $year,
|
'year' => $year,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,12 @@
|
|||||||
namespace app\common\mq;
|
namespace app\common\mq;
|
||||||
|
|
||||||
use think\Db;
|
use think\Db;
|
||||||
use app\common\ReferenceCheckService;
|
use app\common\DbReconnectHelper;
|
||||||
|
use app\common\ReferenceRelevanceCheckService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RabbitMQ 消费:按文章串行,文章内 reference_no 升序逐条校对(含低分同步二轮)
|
* RabbitMQ 消费(队列 reference_check / ref_check.article):
|
||||||
|
* 全局文章串行,文章内 reference_no 升序链式逐条「主题相关性」校对。
|
||||||
*/
|
*/
|
||||||
class ReferenceCheckArticleWorker
|
class ReferenceCheckArticleWorker
|
||||||
{
|
{
|
||||||
@@ -15,18 +17,20 @@ class ReferenceCheckArticleWorker
|
|||||||
const BATCH_DONE = 2;
|
const BATCH_DONE = 2;
|
||||||
const BATCH_PARTIAL_FAILED = 3;
|
const BATCH_PARTIAL_FAILED = 3;
|
||||||
|
|
||||||
/** @var ReferenceCheckService */
|
/** @var ReferenceRelevanceCheckService */
|
||||||
private $svc;
|
private $svc;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->svc = new ReferenceCheckService();
|
$this->svc = new ReferenceRelevanceCheckService();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleMessage(array $payload)
|
public function handleMessage(array $payload)
|
||||||
{
|
{
|
||||||
|
DbReconnectHelper::ensure();
|
||||||
$pArticleId = intval(isset($payload['p_article_id']) ? $payload['p_article_id'] : 0);
|
$pArticleId = intval(isset($payload['p_article_id']) ? $payload['p_article_id'] : 0);
|
||||||
$batchId = intval(isset($payload['batch_id']) ? $payload['batch_id'] : 0);
|
$batchId = intval(isset($payload['batch_id']) ? $payload['batch_id'] : 0);
|
||||||
|
$trigger = isset($payload['trigger']) ? (string)$payload['trigger'] : 'enqueue';
|
||||||
if ($pArticleId <= 0 || $batchId <= 0) {
|
if ($pArticleId <= 0 || $batchId <= 0) {
|
||||||
$this->svc->log('ReferenceCheckArticleWorker invalid payload');
|
$this->svc->log('ReferenceCheckArticleWorker invalid payload');
|
||||||
return;
|
return;
|
||||||
@@ -34,7 +38,11 @@ class ReferenceCheckArticleWorker
|
|||||||
|
|
||||||
if (!$this->canStartArticleWork($batchId)) {
|
if (!$this->canStartArticleWork($batchId)) {
|
||||||
$this->svc->log('ReferenceCheckArticleWorker defer batch_id=' . $batchId . ' other article running');
|
$this->svc->log('ReferenceCheckArticleWorker defer batch_id=' . $batchId . ' other article running');
|
||||||
(new ReferenceCheckMqPublisher())->publishArticleStart($pArticleId, $batchId, isset($payload['trigger']) ? $payload['trigger'] : 'enqueue');
|
(new ReferenceCheckMqPublisher())->publishArticleStart(
|
||||||
|
$pArticleId,
|
||||||
|
$batchId,
|
||||||
|
isset($payload['trigger']) ? $payload['trigger'] : 'enqueue'
|
||||||
|
);
|
||||||
sleep(3);
|
sleep(3);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -46,6 +54,11 @@ class ReferenceCheckArticleWorker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->svc->recoverQueueRowsForArticle($pArticleId);
|
||||||
|
if ($trigger !== 'recheck_pending_only'
|
||||||
|
&& ReferenceRelevanceCheckService::PREPARE_LITERATURE_BEFORE_CHECK) {
|
||||||
|
$this->svc->prepareLiteratureContentByArticle($pArticleId);
|
||||||
|
}
|
||||||
$this->svc->log('ReferenceCheckArticleWorker start p_article_id=' . $pArticleId . ' batch_id=' . $batchId);
|
$this->svc->log('ReferenceCheckArticleWorker start p_article_id=' . $pArticleId . ' batch_id=' . $batchId);
|
||||||
|
|
||||||
$done = 0;
|
$done = 0;
|
||||||
@@ -59,7 +72,7 @@ class ReferenceCheckArticleWorker
|
|||||||
if ($checkId <= 0) {
|
if ($checkId <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$result = $this->processOneRow($checkId, $row);
|
$result = $this->processOneRow($checkId, $row, $trigger === 'recheck_pending_only');
|
||||||
if ($result === 'ok') {
|
if ($result === 'ok') {
|
||||||
$done++;
|
$done++;
|
||||||
} elseif ($result === 'failed') {
|
} elseif ($result === 'failed') {
|
||||||
@@ -75,7 +88,7 @@ class ReferenceCheckArticleWorker
|
|||||||
|
|
||||||
private function canStartArticleWork($batchId)
|
private function canStartArticleWork($batchId)
|
||||||
{
|
{
|
||||||
$running = Db::name('article_reference_check_batch')
|
$running = Db::name('article_reference_relevance_check_batch')
|
||||||
->where('batch_status', self::BATCH_RUNNING)
|
->where('batch_status', self::BATCH_RUNNING)
|
||||||
->where('id', '<>', intval($batchId))
|
->where('id', '<>', intval($batchId))
|
||||||
->count();
|
->count();
|
||||||
@@ -85,7 +98,7 @@ class ReferenceCheckArticleWorker
|
|||||||
private function claimBatch($batchId)
|
private function claimBatch($batchId)
|
||||||
{
|
{
|
||||||
$now = date('Y-m-d H:i:s');
|
$now = date('Y-m-d H:i:s');
|
||||||
$affected = Db::name('article_reference_check_batch')
|
$affected = Db::name('article_reference_relevance_check_batch')
|
||||||
->where('id', intval($batchId))
|
->where('id', intval($batchId))
|
||||||
->whereIn('batch_status', [self::BATCH_WAITING, self::BATCH_RUNNING])
|
->whereIn('batch_status', [self::BATCH_WAITING, self::BATCH_RUNNING])
|
||||||
->update([
|
->update([
|
||||||
@@ -97,15 +110,15 @@ class ReferenceCheckArticleWorker
|
|||||||
|
|
||||||
private function getBatch($batchId)
|
private function getBatch($batchId)
|
||||||
{
|
{
|
||||||
return Db::name('article_reference_check_batch')->where('id', intval($batchId))->find();
|
return Db::name('article_reference_relevance_check_batch')->where('id', intval($batchId))->find();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function fetchNextPendingRow($pArticleId)
|
private function fetchNextPendingRow($pArticleId)
|
||||||
{
|
{
|
||||||
return Db::name('article_reference_check_result')
|
return Db::name('article_reference_relevance_check_result')
|
||||||
->where('p_article_id', intval($pArticleId))
|
->where('p_article_id', intval($pArticleId))
|
||||||
->where('queue_status', ReferenceCheckService::QUEUE_PENDING)
|
->where('queue_status', ReferenceRelevanceCheckService::QUEUE_PENDING)
|
||||||
->where('status', ReferenceCheckService::RECORD_PENDING)
|
->where('status', ReferenceRelevanceCheckService::RECORD_PENDING)
|
||||||
->order('reference_no asc,am_id asc,text_start asc,id asc')
|
->order('reference_no asc,am_id asc,text_start asc,id asc')
|
||||||
->find();
|
->find();
|
||||||
}
|
}
|
||||||
@@ -113,44 +126,44 @@ class ReferenceCheckArticleWorker
|
|||||||
/**
|
/**
|
||||||
* @return string ok|failed|skip
|
* @return string ok|failed|skip
|
||||||
*/
|
*/
|
||||||
private function processOneRow($checkId, array $row)
|
private function processOneRow($checkId, array $row, $skipLiteratureFetch = false)
|
||||||
{
|
{
|
||||||
$claimed = Db::name('article_reference_check_result')
|
DbReconnectHelper::ensure();
|
||||||
|
$claimed = Db::name('article_reference_relevance_check_result')
|
||||||
->where('id', intval($checkId))
|
->where('id', intval($checkId))
|
||||||
->where('queue_status', ReferenceCheckService::QUEUE_PENDING)
|
->where('queue_status', ReferenceRelevanceCheckService::QUEUE_PENDING)
|
||||||
->update(['queue_status' => ReferenceCheckService::QUEUE_RUNNING]);
|
->update(['queue_status' => ReferenceRelevanceCheckService::QUEUE_RUNNING]);
|
||||||
if (intval($claimed) <= 0) {
|
if (intval($claimed) <= 0) {
|
||||||
return 'skip';
|
return 'skip';
|
||||||
}
|
}
|
||||||
|
|
||||||
$retryCount = intval(isset($row['retry_count']) ? $row['retry_count'] : 0);
|
$retryCount = intval(isset($row['retry_count']) ? $row['retry_count'] : 0);
|
||||||
try {
|
try {
|
||||||
$this->svc->runReferenceCheckOnce($checkId);
|
$this->svc->runCheckOnce($checkId, $skipLiteratureFetch);
|
||||||
$amId = intval(isset($row['am_id']) ? $row['am_id'] : 0);
|
$this->svc->markQueueRuntime($checkId, ReferenceRelevanceCheckService::QUEUE_COMPLETED, $retryCount);
|
||||||
if ($amId > 0) {
|
|
||||||
$this->svc->syncAmRefCheckStatus($amId);
|
|
||||||
}
|
|
||||||
$this->svc->markQueueRuntime($checkId, ReferenceCheckService::QUEUE_COMPLETED, $retryCount);
|
|
||||||
return 'ok';
|
return 'ok';
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->svc->log('ReferenceCheckArticleWorker check_id=' . $checkId . ' err=' . $e->getMessage());
|
$this->svc->log('ReferenceCheckArticleWorker check_id=' . $checkId . ' err=' . $e->getMessage());
|
||||||
if ($retryCount < ReferenceCheckService::QUEUE_MAX_RETRY) {
|
DbReconnectHelper::ensure();
|
||||||
$this->svc->markQueueRuntime($checkId, ReferenceCheckService::QUEUE_PENDING, $retryCount + 1);
|
if ($retryCount < ReferenceRelevanceCheckService::QUEUE_MAX_RETRY) {
|
||||||
return $this->processOneRow($checkId, array_merge($row, ['retry_count' => $retryCount + 1]));
|
$this->svc->markQueueRuntime($checkId, ReferenceRelevanceCheckService::QUEUE_PENDING, $retryCount + 1);
|
||||||
|
return $this->processOneRow($checkId, array_merge($row, ['retry_count' => $retryCount + 1]), $skipLiteratureFetch);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$this->svc->updateCheckResult($checkId, [
|
$fresh = Db::name('article_reference_relevance_check_result')->where('id', intval($checkId))->find();
|
||||||
'status' => ReferenceCheckService::RECORD_FAILED,
|
$groupRows = !empty($fresh) ? $this->svc->findCitationGroupRowsForWorker($fresh) : [];
|
||||||
'error_msg' => $e->getMessage(),
|
if (!empty($groupRows)) {
|
||||||
]);
|
$this->svc->failGroupWithQueue($groupRows, $e->getMessage(), $retryCount);
|
||||||
$this->svc->markQueueRuntime($checkId, ReferenceCheckService::QUEUE_FAILED, $retryCount);
|
} else {
|
||||||
|
$this->svc->updateCheckResult($checkId, [
|
||||||
|
'status' => ReferenceRelevanceCheckService::RECORD_FAILED,
|
||||||
|
'error_msg' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
$this->svc->markQueueRuntime($checkId, ReferenceRelevanceCheckService::QUEUE_FAILED, $retryCount);
|
||||||
|
}
|
||||||
} catch (\Exception $e2) {
|
} catch (\Exception $e2) {
|
||||||
\think\Log::error('ReferenceCheckArticleWorker markFailed: ' . $e2->getMessage());
|
\think\Log::error('ReferenceCheckArticleWorker markFailed: ' . $e2->getMessage());
|
||||||
}
|
}
|
||||||
$amId = intval(isset($row['am_id']) ? $row['am_id'] : 0);
|
|
||||||
if ($amId > 0) {
|
|
||||||
$this->svc->syncAmRefCheckStatus($amId);
|
|
||||||
}
|
|
||||||
return 'failed';
|
return 'failed';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,7 +179,7 @@ class ReferenceCheckArticleWorker
|
|||||||
if ($failed > 0) {
|
if ($failed > 0) {
|
||||||
$status = self::BATCH_PARTIAL_FAILED;
|
$status = self::BATCH_PARTIAL_FAILED;
|
||||||
}
|
}
|
||||||
Db::name('article_reference_check_batch')->where('id', intval($batchId))->update([
|
Db::name('article_reference_relevance_check_batch')->where('id', intval($batchId))->update([
|
||||||
'batch_status' => $status,
|
'batch_status' => $status,
|
||||||
'done_count' => intval($done),
|
'done_count' => intval($done),
|
||||||
'failed_count' => intval($failed),
|
'failed_count' => intval($failed),
|
||||||
@@ -179,7 +192,7 @@ class ReferenceCheckArticleWorker
|
|||||||
|
|
||||||
private function publishNextWaitingBatch()
|
private function publishNextWaitingBatch()
|
||||||
{
|
{
|
||||||
$next = Db::name('article_reference_check_batch')
|
$next = Db::name('article_reference_relevance_check_batch')
|
||||||
->where('batch_status', self::BATCH_WAITING)
|
->where('batch_status', self::BATCH_WAITING)
|
||||||
->order('id asc')
|
->order('id asc')
|
||||||
->find();
|
->find();
|
||||||
@@ -193,8 +206,8 @@ class ReferenceCheckArticleWorker
|
|||||||
isset($next['trigger']) ? $next['trigger'] : 'enqueue'
|
isset($next['trigger']) ? $next['trigger'] : 'enqueue'
|
||||||
);
|
);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$this->svc->log('publishNextWaitingBatch failed: ' . $e->getMessage());
|
$this->svc->log('ReferenceCheck publishNextWaitingBatch failed: ' . $e->getMessage());
|
||||||
\think\Log::error('publishNextWaitingBatch: ' . $e->getMessage());
|
\think\Log::error('ReferenceCheck publishNextWaitingBatch: ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,18 +28,17 @@ class LLMService
|
|||||||
* @param string $contextText 正文引用处句子
|
* @param string $contextText 正文引用处句子
|
||||||
* @param string $referText 参考文献条目(或 refer 格式化文本)
|
* @param string $referText 参考文献条目(或 refer 格式化文本)
|
||||||
* @param bool $isAgain 是否为 DOI 二次复核
|
* @param bool $isAgain 是否为 DOI 二次复核
|
||||||
* @param string|null $doiBlock 可选:系统抓取到的 DOI 真实文献内容(仅二次复核使用)
|
* @param string|null $doiBlock 可选:系统抓取到的 DOI 真实文献内容(仅二次复核使用)
|
||||||
|
* @param string $citeGroupRefs 引用文献组,如 1,2 或 4,5,6
|
||||||
|
* @param string $localContext 本引用位置附近上下文(可选)
|
||||||
|
* @return array{results:array,request_failed?:bool}
|
||||||
*/
|
*/
|
||||||
public function checkReference($contextText, $referText, $isAgain = false, $doiBlock = null)
|
public function checkReference($contextText, $referText, $isAgain = false, $doiBlock = null, $citeGroupRefs = '', $localContext = '')
|
||||||
{
|
{
|
||||||
// request_failed=true 表示"LLM 通讯/解析层面的失败"(可重试,区别于业务上的"未命中");
|
|
||||||
// 上游 runReferenceCheckOnce 会据此把 DB.status 置为 3(失败) 并抛异常触发 MQ worker 重试
|
|
||||||
$fallback = [
|
$fallback = [
|
||||||
'can_support' => false,
|
'results' => [],
|
||||||
'is_match' => false,
|
|
||||||
'confidence' => 0.0,
|
|
||||||
'reason' => 'LLM not configured or request failed',
|
|
||||||
'request_failed' => true,
|
'request_failed' => true,
|
||||||
|
'reason' => 'LLM not configured or request failed',
|
||||||
];
|
];
|
||||||
if ($this->url === '' || $this->model === '') {
|
if ($this->url === '' || $this->model === '') {
|
||||||
\think\Log::warning('ReferenceCheck LLM: url or model not configured');
|
\think\Log::warning('ReferenceCheck LLM: url or model not configured');
|
||||||
@@ -47,15 +46,16 @@ class LLMService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$contextText = trim($contextText);
|
$contextText = trim($contextText);
|
||||||
|
\think\Log::info('llm checkReference:' . $contextText);
|
||||||
$referText = trim($referText);
|
$referText = trim($referText);
|
||||||
|
\think\Log::info('llm referText:' . $referText);
|
||||||
$doiBlock = trim((string)$doiBlock);
|
$doiBlock = trim((string)$doiBlock);
|
||||||
|
$citeGroupRefs = trim((string)$citeGroupRefs);
|
||||||
|
$localContext = trim((string)$localContext);
|
||||||
if ($contextText === '' || $referText === '') {
|
if ($contextText === '' || $referText === '') {
|
||||||
// 空文本是入参问题,不是 LLM 故障,不需要重试
|
|
||||||
return [
|
return [
|
||||||
'can_support' => false,
|
'results' => [],
|
||||||
'is_match' => false,
|
'reason' => 'Empty citation context or reference text',
|
||||||
'confidence' => 0.0,
|
|
||||||
'reason' => 'Empty citation context or reference text',
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,27 +63,30 @@ class LLMService
|
|||||||
if (mb_strlen($contextText) > $maxContextLen) {
|
if (mb_strlen($contextText) > $maxContextLen) {
|
||||||
$contextText = mb_substr($contextText, 0, $maxContextLen);
|
$contextText = mb_substr($contextText, 0, $maxContextLen);
|
||||||
}
|
}
|
||||||
if (mb_strlen($referText) > 4000) {
|
if (mb_strlen($localContext) > 3000) {
|
||||||
$referText = mb_substr($referText, 0, 4000);
|
$localContext = mb_substr($localContext, 0, 3000);
|
||||||
}
|
}
|
||||||
if (mb_strlen($doiBlock) > 4000) {
|
if (mb_strlen($referText) > 6000) {
|
||||||
$doiBlock = mb_substr($doiBlock, 0, 4000);
|
$referText = mb_substr($referText, 0, 6000);
|
||||||
|
}
|
||||||
|
if (mb_strlen($doiBlock) > 8000) {
|
||||||
|
$doiBlock = mb_substr($doiBlock, 0, 8000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isAgain) {
|
if ($isAgain) {
|
||||||
$system = $this->buildReferenceCheckSecondPassPrompt();
|
$system = $this->buildReferenceCheckSecondPassPrompt();
|
||||||
$user = $this->buildReferenceCheckSecondPassUserPrompt($contextText, $referText, $doiBlock);
|
$user = $this->buildReferenceCheckSecondPassUserPrompt($contextText, $referText, $doiBlock, $citeGroupRefs, $localContext);
|
||||||
} else {
|
} else {
|
||||||
$system = $this->buildReferenceCheckFirstPassPrompt();
|
$system = $this->buildReferenceCheckFirstPassPrompt();
|
||||||
$user = $this->buildReferenceCheckFirstPassUserPrompt($contextText, $referText);
|
$user = $this->buildReferenceCheckFirstPassUserPrompt($contextText, $referText, $citeGroupRefs, $localContext, $doiBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
\think\Log::info('ReferenceCheck system head: ' . mb_substr($system, 0, 200));
|
// \think\Log::info('ReferenceCheck system head: ' . mb_substr($system, 0, 200));
|
||||||
\think\Log::info('ReferenceCheck user head: ' . mb_substr($user, 0, 600));
|
// \think\Log::info('ReferenceCheck user head: ' . mb_substr($user, 0, 600));
|
||||||
$payload = [
|
$payload = [
|
||||||
'model' => $this->model,
|
'model' => $this->model,
|
||||||
'temperature' => 0,
|
'temperature' => 0,
|
||||||
'messages' => [
|
'messages' => [
|
||||||
['role' => 'system', 'content' => $system],
|
['role' => 'system', 'content' => $system],
|
||||||
['role' => 'user', 'content' => $user],
|
['role' => 'user', 'content' => $user],
|
||||||
],
|
],
|
||||||
@@ -101,23 +104,14 @@ class LLMService
|
|||||||
return $fallback;
|
return $fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
$canSupport = $this->parseCanSupportFromParsed($parsed);
|
$results = $this->parseReferenceCheckResultsFromParsed($parsed, $citeGroupRefs, $localContext, $doiBlock);
|
||||||
$confidence = $this->snapReferenceCheckConfidence(
|
if (empty($results)) {
|
||||||
$this->normalizeConfidence(isset($parsed['confidence']) ? $parsed['confidence'] : 0),
|
\think\Log::warning('ReferenceCheck LLM: empty results array');
|
||||||
$canSupport
|
return $fallback;
|
||||||
);
|
}
|
||||||
$reason = $this->cleanReason((string)(isset($parsed['reason']) ? $parsed['reason'] : ''));
|
|
||||||
\think\Log::info(
|
\think\Log::info($results);
|
||||||
'ReferenceCheck result: can_support=' . ($canSupport ? '1' : '0')
|
return ['results' => $results];
|
||||||
. ', confidence=' . $confidence
|
|
||||||
. ', reason=' . $reason
|
|
||||||
);
|
|
||||||
return [
|
|
||||||
'can_support' => $canSupport,
|
|
||||||
'is_match' => $canSupport,
|
|
||||||
'confidence' => $confidence,
|
|
||||||
'reason' => $reason,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,83 +168,541 @@ class LLMService
|
|||||||
$s = strtolower(trim((string)$value));
|
$s = strtolower(trim((string)$value));
|
||||||
return in_array($s, ['1', 'true', 'yes', 'support', 'supported'], true);
|
return in_array($s, ['1', 'true', 'yes', 'support', 'supported'], true);
|
||||||
}
|
}
|
||||||
|
private function bulidReferenceCheckFirstPassPrompt(){
|
||||||
|
return <<<'PROMPT'
|
||||||
|
你是一名护理、医学与科研期刊的资深文献编辑,专门校对「正文引用句」与「对应参考文献条目」是否匹配。
|
||||||
|
|
||||||
/** 第一次校对:书目条目 vs 正文全文 */
|
你的目标是严格识别错引、张冠李戴、方法不符、对象不符、结论不成立的问题。
|
||||||
|
|
||||||
|
宁可少判 true,也不要漏掉错引。
|
||||||
|
|
||||||
|
你只能依据用户提供的内容判断:
|
||||||
|
1. 正文引用句
|
||||||
|
2. 当前对应参考文献条目
|
||||||
|
|
||||||
|
禁止假设已阅读全文。
|
||||||
|
禁止联网。
|
||||||
|
禁止脑补文献内容。
|
||||||
|
禁止根据学科常识推断研究结果。
|
||||||
|
|
||||||
|
====================
|
||||||
|
【核心任务】
|
||||||
|
|
||||||
|
判断:
|
||||||
|
|
||||||
|
正文在该引用位置表达的核心观点、结论、方法、数据、定义、模型、研究发现、指南依据等,
|
||||||
|
|
||||||
|
是否能够被该条参考文献合理支撑。
|
||||||
|
|
||||||
|
你判断的是:
|
||||||
|
|
||||||
|
“引用是否成立”
|
||||||
|
|
||||||
|
不是:
|
||||||
|
|
||||||
|
“正文是否正确”。
|
||||||
|
|
||||||
|
====================
|
||||||
|
【总原则(最高优先级)】
|
||||||
|
|
||||||
|
采用严格审稿标准:
|
||||||
|
|
||||||
|
边界不清时,一律判 false。
|
||||||
|
|
||||||
|
宁可误杀(人工复核),不要漏掉错引。
|
||||||
|
|
||||||
|
同领域 ≠ 匹配。
|
||||||
|
|
||||||
|
同关键词 ≠ 匹配。
|
||||||
|
|
||||||
|
相关 ≠ 能支撑。
|
||||||
|
|
||||||
|
====================
|
||||||
|
【强制规则】
|
||||||
|
|
||||||
|
1. 严禁关键词硬匹配
|
||||||
|
|
||||||
|
不能因为出现:
|
||||||
|
患者、护理、治疗、研究、模型、算法、深度学习、机器学习、焦虑、效果
|
||||||
|
|
||||||
|
等泛化词汇就判定匹配。
|
||||||
|
|
||||||
|
必须看:
|
||||||
|
|
||||||
|
- 核心对象
|
||||||
|
- 研究问题
|
||||||
|
- 方法
|
||||||
|
- 场景
|
||||||
|
- 结局指标
|
||||||
|
- 核心论点
|
||||||
|
|
||||||
|
是否一致。
|
||||||
|
|
||||||
|
====================
|
||||||
|
2. 方法学必须严格一致(极重要)
|
||||||
|
|
||||||
|
若正文明确提到:
|
||||||
|
|
||||||
|
- 算法
|
||||||
|
- 模型
|
||||||
|
- 聚类方法
|
||||||
|
- 深度学习架构
|
||||||
|
- 统计方法
|
||||||
|
- 数学模型
|
||||||
|
- 评价指标
|
||||||
|
|
||||||
|
必须要求文献与其存在明确关联。
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
不匹配:
|
||||||
|
- fuzzy clustering ≠ deep learning
|
||||||
|
- CNN ≠ LSTM
|
||||||
|
- random forest ≠ SVM
|
||||||
|
- 聚类 ≠ 分类
|
||||||
|
- 特征选择 ≠ 分类预测
|
||||||
|
- 风险因素分析 ≠ 干预研究
|
||||||
|
|
||||||
|
仅属于同一“大领域(AI/ML)”
|
||||||
|
不能判定匹配。
|
||||||
|
|
||||||
|
若方法体系不同:
|
||||||
|
|
||||||
|
优先判 false + 0.10。
|
||||||
|
|
||||||
|
====================
|
||||||
|
3. 医学护理引用严格一致
|
||||||
|
|
||||||
|
若正文涉及:
|
||||||
|
|
||||||
|
- 疾病
|
||||||
|
- 人群
|
||||||
|
- 护理场景
|
||||||
|
- 干预措施
|
||||||
|
- 结局指标
|
||||||
|
|
||||||
|
必须基本一致。
|
||||||
|
|
||||||
|
例如:
|
||||||
|
|
||||||
|
不匹配:
|
||||||
|
- ICU ≠ 普通病房
|
||||||
|
- 老年人 ≠ 儿童
|
||||||
|
- 糖尿病 ≠ 高血压
|
||||||
|
- 心理护理 ≠ 运动干预
|
||||||
|
- 焦虑改善 ≠ 生存率提高
|
||||||
|
|
||||||
|
====================
|
||||||
|
4. 强结论必须强证据
|
||||||
|
|
||||||
|
正文若出现:
|
||||||
|
|
||||||
|
- 显著改善
|
||||||
|
- 明显降低
|
||||||
|
- 证实
|
||||||
|
- 优于
|
||||||
|
- 有效预测
|
||||||
|
- 危险因素
|
||||||
|
- 因果关系
|
||||||
|
|
||||||
|
文献必须能合理支撑该强结论。
|
||||||
|
|
||||||
|
仅“应用研究”“相关研究”“观察研究”
|
||||||
|
不能自动支持强结论。
|
||||||
|
|
||||||
|
否则 false。
|
||||||
|
|
||||||
|
====================
|
||||||
|
5. 特定证据类型必须一致
|
||||||
|
|
||||||
|
正文若明确写:
|
||||||
|
|
||||||
|
- RCT/randomized trial
|
||||||
|
- Meta-analysis
|
||||||
|
- Guideline
|
||||||
|
- Systematic review
|
||||||
|
- Expert consensus
|
||||||
|
|
||||||
|
而参考文献类型明显不符:
|
||||||
|
|
||||||
|
直接 false。
|
||||||
|
|
||||||
|
====================
|
||||||
|
6. 信息不足从严
|
||||||
|
|
||||||
|
若参考文献只有:
|
||||||
|
|
||||||
|
作者 + 年份
|
||||||
|
|
||||||
|
或信息过少,
|
||||||
|
|
||||||
|
无法建立明确关联:
|
||||||
|
|
||||||
|
false + 0.30
|
||||||
|
|
||||||
|
====================
|
||||||
|
【判定逻辑】
|
||||||
|
|
||||||
|
只有同时满足以下条件,才能 true:
|
||||||
|
|
||||||
|
1. 主题一致
|
||||||
|
2. 核心对象一致
|
||||||
|
3. 核心论点一致
|
||||||
|
4. 方法/研究方向一致
|
||||||
|
5. 无明显错引风险
|
||||||
|
|
||||||
|
任意一点明显不符:
|
||||||
|
|
||||||
|
false。
|
||||||
|
|
||||||
|
====================
|
||||||
|
【评分(只能四选一)】
|
||||||
|
|
||||||
|
只能输出:
|
||||||
|
|
||||||
|
0.90
|
||||||
|
0.75
|
||||||
|
0.30
|
||||||
|
0.10
|
||||||
|
|
||||||
|
禁止任何其他分数。
|
||||||
|
|
||||||
|
评分规则:
|
||||||
|
|
||||||
|
0.90
|
||||||
|
明确匹配:
|
||||||
|
主题、对象、方法、核心论点均明显一致。
|
||||||
|
|
||||||
|
0.75
|
||||||
|
基本匹配:
|
||||||
|
整体支撑成立,但存在轻微概括或小范围表述差异。
|
||||||
|
|
||||||
|
0.30
|
||||||
|
存疑:
|
||||||
|
同领域但支撑不足;
|
||||||
|
信息不足;
|
||||||
|
需人工复核。
|
||||||
|
|
||||||
|
0.10
|
||||||
|
明确错引:
|
||||||
|
主题、对象、方法或核心论点明显不符。
|
||||||
|
|
||||||
|
硬规则:
|
||||||
|
|
||||||
|
is_match=true
|
||||||
|
只能:
|
||||||
|
0.75 或 0.90
|
||||||
|
|
||||||
|
is_match=false
|
||||||
|
只能:
|
||||||
|
0.10 或 0.30
|
||||||
|
|
||||||
|
====================
|
||||||
|
【reason 要求】
|
||||||
|
|
||||||
|
仅说明:
|
||||||
|
|
||||||
|
1. 是否主题一致;
|
||||||
|
2. 核心论点/方法是否能支撑。
|
||||||
|
|
||||||
|
禁止模糊措辞:
|
||||||
|
“可能”
|
||||||
|
“看起来”
|
||||||
|
“应该”
|
||||||
|
“疑似”
|
||||||
|
|
||||||
|
长度:
|
||||||
|
|
||||||
|
20~60字。
|
||||||
|
|
||||||
|
====================
|
||||||
|
【输出要求】
|
||||||
|
|
||||||
|
仅输出一行 minified JSON。
|
||||||
|
|
||||||
|
禁止 markdown。
|
||||||
|
禁止解释。
|
||||||
|
禁止换行。
|
||||||
|
禁止任何额外内容。
|
||||||
|
|
||||||
|
格式:
|
||||||
|
|
||||||
|
{"is_match":true|false,"confidence":0.10|0.30|0.75|0.90,"reason":"简体中文说明"}
|
||||||
|
PROMPT;
|
||||||
|
|
||||||
|
}
|
||||||
|
/** 第一次校对:参考文献真实性与支撑力度 */
|
||||||
private function buildReferenceCheckFirstPassPrompt()
|
private function buildReferenceCheckFirstPassPrompt()
|
||||||
{
|
{
|
||||||
return <<<'PROMPT'
|
return $this->buildReferenceCheckSupportSystemPrompt(false);
|
||||||
你是文献引用校对助手。判断【正文全文】与【参考文献书目】是否相关、能否用于支撑正文中的引用。
|
|
||||||
|
|
||||||
【核心原则:从宽判断,避免误杀】
|
|
||||||
默认倾向 can_support=true。只要文献与正文不是「风马牛不相及」,即判为相关、能支撑。
|
|
||||||
不要求变量一致、不要求结论逐条对应、不要求研究设计相同。
|
|
||||||
|
|
||||||
【仅当以下情况才判 can_support=false(与正文明显无关)】
|
|
||||||
- 学科/主题完全无关(如正文讲深度学习聚类,文献是糖尿病步态检测)。
|
|
||||||
- 明显张冠李戴(正文断言 A 疗法的效果,文献研究的是完全不同的 B 问题且无关联)。
|
|
||||||
- 文献条目与正文讨论的对象/场景毫无交集,且无法作背景或理论引用。
|
|
||||||
|
|
||||||
【以下情况均应 can_support=true】
|
|
||||||
- 同一大领域或相邻方向(如护理、心理、管理、医学、统计、AI 等相近子领域)。
|
|
||||||
- 可作背景文献、综述性引用、理论或方法的一般性依据。
|
|
||||||
- 表述略宽、略有概括、变量名不完全一致,但大方向说得通。
|
|
||||||
|
|
||||||
【confidence 固定档位(禁止其它小数)】
|
|
||||||
can_support=true:0.65(有关联但较泛)/ 0.78 / 0.85 / 0.92 / 0.98(非常确定相关)
|
|
||||||
can_support=false:0.15(明确风马牛不相及)/ 0.25 / 0.35 / 0.45(仅当实在无法建立任何合理关联)
|
|
||||||
|
|
||||||
【输出】仅一行 minified JSON,无 markdown:
|
|
||||||
{"can_support":true|false,"is_match":true|false,"confidence":0.15|0.25|0.35|0.45|0.65|0.78|0.85|0.92|0.98,"reason":"30-80字简体中文"}
|
|
||||||
is_match 必须与 can_support 相同。
|
|
||||||
PROMPT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildReferenceCheckFirstPassUserPrompt($contextText, $referText)
|
private function buildReferenceCheckSupportSystemPrompt($isSecondPass = false)
|
||||||
{
|
{
|
||||||
return "【正文全文 article_main.content】\n" . $contextText
|
$prompt = <<<'PROMPT'
|
||||||
. "\n\n【参考文献书目 refer_text】\n" . $referText
|
你是一名护理、医学、生物医学与科研期刊的资深学术编辑,正在执行“参考文献真实性与支撑力度校对”。
|
||||||
. "\n\n请从宽判断:文献与正文非风马牛不相即可判 can_support=true,只返回 JSON。";
|
|
||||||
|
你的任务不是判断“主题是否相关”,而是判断:
|
||||||
|
【稿件正文中某段被引用内容】是否真的能被【对应编号的参考文献】直接或充分支撑。
|
||||||
|
|
||||||
|
你必须严格基于用户提供的材料作出判断,不得凭常识、不得脑补、不得假设参考文献中“可能写过但未提供”的内容。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【一、任务目标】
|
||||||
|
你需要判断:
|
||||||
|
“正文引用位置的核心论点、结论、背景陈述、机制解释、疗效描述、数据表达或因果表述,
|
||||||
|
是否能被对应参考文献真实支持。”
|
||||||
|
|
||||||
|
这里的“支持”不是指“文献主题相关”或“研究领域接近”,而是指:
|
||||||
|
参考文献中确实包含足以支持正文该处表述的内容。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【二、输出原则:结果必须直接对应数据库行】
|
||||||
|
|
||||||
|
你输出的结果将直接写入数据库表 t_article_reference_check_result。
|
||||||
|
|
||||||
|
因此:
|
||||||
|
## 输出必须是 results 数组,数组中的每一个对象对应数据库中的一行,也就是“一个引用位置中的一条参考文献结果”。
|
||||||
|
|
||||||
|
换句话说:
|
||||||
|
- 如果某个引用位置是 [3],则输出 1 条 result(reference_no=3)
|
||||||
|
- 如果某个引用位置是 [1,2],则输出 2 条 result:
|
||||||
|
- 一条对应 reference_no=1
|
||||||
|
- 一条对应 reference_no=2
|
||||||
|
|
||||||
|
每条 result 都必须给出该参考文献“单独”对正文引用句的支撑判断。
|
||||||
|
如果该引用位置是联合引用(citation group 中有多篇文献),则除了单条判断外,还必须给出该引用组整体的联合判断(combined_* 字段)。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【三、最重要原则:只看“是否支撑正文核心断言”,不是看“主题是否沾边”】
|
||||||
|
|
||||||
|
以下情况不能判为强支撑:
|
||||||
|
1. 参考文献只和主题大致相关,但没有明确支持正文中的关键表述
|
||||||
|
2. 正文说的是“疗效提升/死亡率下降/全球高发/耐药/多通路机制”等明确论点,而文献只是在背景里泛泛提到疾病
|
||||||
|
3. 正文是多层复合句,文献只支撑其中一小部分
|
||||||
|
4. 正文有因果、比较、趋势、机制、疗效强度等强表述,而文献没有明确证据
|
||||||
|
5. 文献是基础机制研究,但正文引用它来支撑宏观流行病学、临床治疗现状或指南式结论
|
||||||
|
6. 文献可以“推测支持”但不是“直接/明确支持”
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【三b、多 claim 复合句 → 0.78 部分支撑(勿误降到 0.45)】
|
||||||
|
|
||||||
|
正文常为 2~4 个连续 claim 的复合句。须逐 claim 比对后综合给分:
|
||||||
|
|
||||||
|
- 若文献(含 DOI 摘要)能**明确支撑多数关键概念**(如遗传异质性/多基因改变、多 survival pathway 并存、耐药或治疗挑战),
|
||||||
|
但**未逐字写出**正文完整因果链(如「异质性→多通路→单靶点疗效下降」),
|
||||||
|
→ 应判 **partial_support**,confidence 通常 **0.78**(边界情况 0.65),**不得**仅因文献主标题聚焦某化合物/干预就降到 0.45。
|
||||||
|
|
||||||
|
- 0.45 仅用于:文献与 claim 方向明显不符、仅同病沾边、或几乎无可用证据。
|
||||||
|
|
||||||
|
**校准样例(单条 [4],须接近此逻辑):**
|
||||||
|
|
||||||
|
引用句:
|
||||||
|
Furthermore, the genomic heterogeneity of colorectal cancer (CRC) presents additional difficulties because tumors frequently make use of several survival pathways at once, which reduces the efficacy of single-target treatments [4].
|
||||||
|
|
||||||
|
文献4(Sheikhnia et al., thymoquinone CRC 机制综述):
|
||||||
|
- Claim1 遗传异质性/多基因改变:文献有 APC/KRAS/TP53、MSI/CIN 等 → 支撑较强
|
||||||
|
- Claim2 多 survival pathway:文献列举 PI3K/Akt、Wnt、STAT3、NF-κB 等多通路 → 支撑较强
|
||||||
|
- Claim3 单靶点疗效下降:文献有 drug resistance/治疗挑战,但未直述因果链 → 部分支撑
|
||||||
|
- **输出**:can_support=1, confidence=**0.78**, support_role=supplementary_support(**不是 0.45**)
|
||||||
|
|
||||||
|
用户消息中若提供【DOI 真实文献内容】,**必须结合摘要判断**,不得仅凭书目标题给分。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【四、评分规则】
|
||||||
|
|
||||||
|
你必须使用以下 8 个固定分值之一:
|
||||||
|
0.98 / 0.92 / 0.85 / 0.78 / 0.65 / 0.45 / 0.25 / 0.15
|
||||||
|
|
||||||
|
判定含义:
|
||||||
|
- 0.98 / 0.92 / 0.85 => 强支撑(strong_support)
|
||||||
|
- 0.78 / 0.65 => 部分支撑(partial_support)
|
||||||
|
- 0.45 / 0.25 => 支撑不足(insufficient_support)
|
||||||
|
- 0.15 => 不支撑(not_support)
|
||||||
|
|
||||||
|
can_support 取值规则:
|
||||||
|
- 若该文献/联合引文整体可判为 strong_support 或 partial_support,则 can_support = 1
|
||||||
|
- 若判为 insufficient_support 或 not_support,则 can_support = 0
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【五、单条文献结果如何判断】
|
||||||
|
|
||||||
|
对于每一条参考文献,你必须判断它“单独”能否支撑该引用位置的正文内容,并输出:
|
||||||
|
- can_support
|
||||||
|
- confidence
|
||||||
|
- reason
|
||||||
|
- support_role
|
||||||
|
|
||||||
|
其中:
|
||||||
|
### support_role 只能取以下值之一
|
||||||
|
- primary_support:该文献本身就是主要证据来源,能支撑引用句核心内容
|
||||||
|
- supplementary_support:能支撑部分重要内容,但不是主要来源
|
||||||
|
- minimal_support:只提供少量背景或边缘支撑
|
||||||
|
- no_meaningful_support:几乎不能支撑该引用句
|
||||||
|
|
||||||
|
### reason 的写法要求
|
||||||
|
必须使用中文,明确写出:
|
||||||
|
1. 这篇文献具体支撑正文的哪一部分
|
||||||
|
2. 哪些部分没有支撑到
|
||||||
|
3. 是否存在文献类型与引用用途不匹配的问题
|
||||||
|
4. 为什么给这个分值,而不是更高或更低
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【六、联合引用的判断规则】
|
||||||
|
|
||||||
|
当同一个引用位置包含多篇参考文献时(例如 [1,2] / [4,5,6]),除了逐条给单条结果外,还要额外判断:
|
||||||
|
“这些文献合起来,是否足以支撑该引用位置的正文内容?”
|
||||||
|
|
||||||
|
联合结论输出到:
|
||||||
|
- combined_can_support
|
||||||
|
- combined_confidence
|
||||||
|
- combined_reason
|
||||||
|
|
||||||
|
规则:
|
||||||
|
1. 联合评分不是单条评分平均值
|
||||||
|
2. 如果其中一篇文献已强支撑,其他文献只是补充,则联合评分可接近主支撑文献
|
||||||
|
3. 如果多篇文献分别覆盖不同部分,合起来能较完整支撑正文,则联合评分可以高于某些单条评分
|
||||||
|
4. 但如果最关键的核心断言没有被任何文献明确支撑,则联合评分不能虚高
|
||||||
|
5. 如果多篇文献都只是零散相关,需要大量推断才能拼出正文结论,则联合评分通常不应过高
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【七、单引文的 combined_* 字段处理规则】
|
||||||
|
|
||||||
|
即使某个引用位置只有 1 条参考文献,也仍然必须输出 combined_* 字段。
|
||||||
|
此时:
|
||||||
|
- combined_can_support = can_support
|
||||||
|
- combined_confidence = confidence
|
||||||
|
- combined_reason = “该引用位置仅包含单条文献,联合结论等同于该文献的单条结论。” 或等价表述
|
||||||
|
|
||||||
|
这样可以保证输出结构统一,便于数据库写入。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【八、输出 JSON 结构】
|
||||||
|
|
||||||
|
你必须输出合法 JSON,且只能输出以下结构:
|
||||||
|
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"reference_no": 1,
|
||||||
|
"cite_group_refs": "1,2",
|
||||||
|
"can_support": 0,
|
||||||
|
"confidence": 0.65,
|
||||||
|
"reason": "中文,单条文献结论",
|
||||||
|
"support_role": "supplementary_support",
|
||||||
|
"combined_can_support": 1,
|
||||||
|
"combined_confidence": 0.85,
|
||||||
|
"combined_reason": "中文,联合引用整体结论"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【九、字段约束】
|
||||||
|
|
||||||
|
### 1)results 中每个对象都必须包含以下字段:
|
||||||
|
- reference_no
|
||||||
|
- cite_group_refs
|
||||||
|
- can_support
|
||||||
|
- confidence
|
||||||
|
- reason
|
||||||
|
- support_role
|
||||||
|
- combined_can_support
|
||||||
|
- combined_confidence
|
||||||
|
- combined_reason
|
||||||
|
|
||||||
|
### 2)reference_no
|
||||||
|
必须对应当前引用位置中的某一条参考文献编号。
|
||||||
|
|
||||||
|
### 3)cite_group_refs
|
||||||
|
必须是该引用位置的完整引文组,格式如:
|
||||||
|
- "3"
|
||||||
|
- "1,2"
|
||||||
|
- "4,5,6"
|
||||||
|
|
||||||
|
### 4)同一引用位置若包含多条参考文献,则必须输出多条 result
|
||||||
|
例如 cite_group_refs = "1,2" 时,必须输出:
|
||||||
|
- 一条 reference_no=1
|
||||||
|
- 一条 reference_no=2
|
||||||
|
|
||||||
|
### 5)同一引用位置下的 combined_* 必须一致
|
||||||
|
例如同属 "1,2" 的两条 result,它们的:
|
||||||
|
- combined_can_support
|
||||||
|
- combined_confidence
|
||||||
|
- combined_reason
|
||||||
|
必须完全一致。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【十、禁止事项】
|
||||||
|
你绝对不能:
|
||||||
|
- 杜撰文献中不存在的结论
|
||||||
|
- 把“主题相关”当作“内容支撑”
|
||||||
|
- 因为是同一疾病就默认支持
|
||||||
|
- 输出 JSON 以外的任何内容
|
||||||
|
|
||||||
|
现在开始,读取用户提供的引用位置正文、参考文献信息和文献内容,输出结果。
|
||||||
|
PROMPT;
|
||||||
|
|
||||||
|
if ($isSecondPass) {
|
||||||
|
$prompt .= <<<'PROMPT'
|
||||||
|
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【二次校对补充(DOI 真实文献内容)】
|
||||||
|
用户消息中会提供【DOI 真实文献内容(PubMed/Crossref)】。
|
||||||
|
必须以 DOI 真实内容为准复核支撑力度;书目信息与 DOI 冲突时以 DOI 为准。
|
||||||
|
仍须输出完整 results 数组,逐条给出单文献判断与联合判断。
|
||||||
|
PROMPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $prompt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 第二次校对:Crossref 摘要(Refer_doi) */
|
private function buildReferenceCheckFirstPassUserPrompt($contextText, $referText, $citeGroupRefs = '', $localContext = '', $doiBlock = '')
|
||||||
|
{
|
||||||
|
return $this->buildReferenceCheckSupportUserPrompt($contextText, $referText, $citeGroupRefs, $localContext, $doiBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildReferenceCheckSupportUserPrompt($contextText, $referText, $citeGroupRefs, $localContext, $doiBlock)
|
||||||
|
{
|
||||||
|
$citeGroupRefs = trim((string)$citeGroupRefs);
|
||||||
|
$localContext = trim((string)$localContext);
|
||||||
|
$doiBlock = trim((string)$doiBlock);
|
||||||
|
|
||||||
|
$parts = [
|
||||||
|
"【正文节 t_article_main】\n" . $contextText,
|
||||||
|
];
|
||||||
|
if ($citeGroupRefs !== '') {
|
||||||
|
$mode = strpos($citeGroupRefs, ',') !== false ? '联合引用' : '单独引用';
|
||||||
|
$parts[] = "【引用文献组 cite_group_refs】{$citeGroupRefs}({$mode})";
|
||||||
|
}
|
||||||
|
if ($localContext !== '') {
|
||||||
|
$parts[] = "【本引用位置附近上下文】\n" . $localContext;
|
||||||
|
}
|
||||||
|
$parts[] = "【参考文献书目(按编号列出)】\n" . $referText;
|
||||||
|
if ($doiBlock !== '') {
|
||||||
|
$parts[] = "【DOI 真实文献内容(PubMed/Crossref,一轮校对已提供)】\n" . $doiBlock;
|
||||||
|
}
|
||||||
|
$parts[] = '请严格按 system 要求输出 results 数组 JSON,每条 result 对应一个 reference_no,并包含 combined_* 字段。';
|
||||||
|
|
||||||
|
return implode("\n\n", $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 第二次校对:DOI 真实文献内容复核 */
|
||||||
private function buildReferenceCheckSecondPassPrompt()
|
private function buildReferenceCheckSecondPassPrompt()
|
||||||
{
|
{
|
||||||
return <<<'PROMPT'
|
return $this->buildReferenceCheckSupportSystemPrompt(true);
|
||||||
你是文献引用二次校对助手。已根据 Refer_doi 从 Crossref(https://api.crossref.org/works/)获取摘要,请结合【正文全文】复核该文献是否相关。
|
|
||||||
|
|
||||||
【核心原则:与第一次相同,从宽判断】
|
|
||||||
默认倾向 can_support=true。只要 Crossref 摘要(或书目)与正文不是风马牛不相及,即判相关、能支撑。
|
|
||||||
以【Crossref 摘要】为准;摘要与书目冲突时以摘要为准。
|
|
||||||
|
|
||||||
【仅当以下情况才判 can_support=false】
|
|
||||||
- 摘要显示的研究主题/对象/方法与正文讨论内容完全风马牛不相及。
|
|
||||||
- 典型风马牛不相及、张冠李戴,且无法解释为背景或泛化引用。
|
|
||||||
|
|
||||||
【以下情况均应 can_support=true】
|
|
||||||
- 摘要与正文属同领域或相近方向,能作背景、理论或方向性支撑。
|
|
||||||
- 细节不完全一致,但不存在明显矛盾。
|
|
||||||
|
|
||||||
【无 Crossref 摘要时】
|
|
||||||
结合 refer_text 从宽判断;非明显无关仍可 can_support=true,confidence 建议 0.65。
|
|
||||||
|
|
||||||
【confidence 固定档位(禁止其它小数)】
|
|
||||||
can_support=true:0.65 / 0.78 / 0.85 / 0.92 / 0.98
|
|
||||||
can_support=false:0.15 / 0.25 / 0.35 / 0.45
|
|
||||||
|
|
||||||
【输出】仅一行 minified JSON:
|
|
||||||
{"can_support":true|false,"is_match":true|false,"confidence":0.15|0.25|0.35|0.45|0.65|0.78|0.85|0.92|0.98,"reason":"30-80字简体中文"}
|
|
||||||
is_match 必须与 can_support 相同。
|
|
||||||
PROMPT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildReferenceCheckSecondPassUserPrompt($contextText, $referText, $doiBlock)
|
private function buildReferenceCheckSecondPassUserPrompt($contextText, $referText, $doiBlock, $citeGroupRefs = '', $localContext = '')
|
||||||
{
|
{
|
||||||
$doiBlock = trim((string)$doiBlock);
|
return $this->buildReferenceCheckSupportUserPrompt(
|
||||||
return "【正文全文 article_main.content】\n" . $contextText
|
$contextText,
|
||||||
. "\n\n【参考文献书目 refer_text】\n" . $referText
|
$referText,
|
||||||
. "\n\n【Crossref 摘要】(Refer_doi → api.crossref.org/works/)\n"
|
$citeGroupRefs,
|
||||||
. ($doiBlock !== '' ? $doiBlock : '(未获取到摘要,请结合 refer_text 从宽判断)')
|
$localContext,
|
||||||
. "\n\n文献与正文非风马牛不相即可判 can_support=true,只返回 JSON。";
|
$doiBlock !== '' ? $doiBlock : '(未获取到 DOI 摘要或元数据,请结合书目条目从严判断)'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
private function buildReferenceCheckSystemPrompt3()
|
private function buildReferenceCheckSystemPrompt3()
|
||||||
{
|
{
|
||||||
@@ -1169,13 +1621,174 @@ PROMPT;
|
|||||||
|
|
||||||
private function buildReferenceCheckRecheckUserPrompt($contextText, $referText, $doiBlock)
|
private function buildReferenceCheckRecheckUserPrompt($contextText, $referText, $doiBlock)
|
||||||
{
|
{
|
||||||
return $this->buildReferenceCheckSecondPassUserPrompt($contextText, $referText, $doiBlock);
|
return $this->buildReferenceCheckSecondPassUserPrompt($contextText, $referText, $doiBlock, '', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 与 buildReferenceCheckSystemPrompt3 一致的 confidence 档位
|
* @return array<int, array>
|
||||||
*/
|
*/
|
||||||
private function getReferenceCheckConfidenceBands($isMatch)
|
private function parseReferenceCheckResultsFromParsed(array $parsed, $defaultCiteGroupRefs = '', $localContext = '', $doiBlock = '')
|
||||||
|
{
|
||||||
|
$rows = [];
|
||||||
|
if (isset($parsed['results']) && is_array($parsed['results'])) {
|
||||||
|
$rows = $parsed['results'];
|
||||||
|
} elseif (isset($parsed['reference_no']) || isset($parsed['confidence'])) {
|
||||||
|
$rows = [$parsed];
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized = [];
|
||||||
|
foreach ($rows as $item) {
|
||||||
|
if (!is_array($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$refNo = intval(isset($item['reference_no']) ? $item['reference_no'] : 0);
|
||||||
|
if ($refNo <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$confidence = $this->snapReferenceCheckConfidenceValue(
|
||||||
|
$this->normalizeConfidence(isset($item['confidence']) ? $item['confidence'] : 0)
|
||||||
|
);
|
||||||
|
$canSupport = $this->canSupportFromConfidence($confidence);
|
||||||
|
if (array_key_exists('can_support', $item)) {
|
||||||
|
$canSupport = $this->boolFromLlmValue($item['can_support']);
|
||||||
|
} elseif (array_key_exists('is_match', $item)) {
|
||||||
|
$canSupport = $this->boolFromLlmValue($item['is_match']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$reason = $this->cleanReason((string)(isset($item['reason']) ? $item['reason'] : ''));
|
||||||
|
$supportRole = $this->normalizeSupportRole(isset($item['support_role']) ? $item['support_role'] : '');
|
||||||
|
list($confidence, $canSupport, $supportRole) = $this->applyMultiClaimPartialSupportFloor(
|
||||||
|
$localContext,
|
||||||
|
$doiBlock,
|
||||||
|
$confidence,
|
||||||
|
$canSupport,
|
||||||
|
$supportRole,
|
||||||
|
$reason
|
||||||
|
);
|
||||||
|
|
||||||
|
$combinedConfidence = $this->snapReferenceCheckConfidenceValue(
|
||||||
|
$this->normalizeConfidence(isset($item['combined_confidence']) ? $item['combined_confidence'] : $confidence)
|
||||||
|
);
|
||||||
|
$combinedCanSupport = $this->canSupportFromConfidence($combinedConfidence);
|
||||||
|
if (array_key_exists('combined_can_support', $item)) {
|
||||||
|
$combinedCanSupport = $this->boolFromLlmValue($item['combined_can_support']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$citeGroupRefs = trim((string)(isset($item['cite_group_refs']) ? $item['cite_group_refs'] : $defaultCiteGroupRefs));
|
||||||
|
if ($citeGroupRefs === '' && $defaultCiteGroupRefs !== '') {
|
||||||
|
$citeGroupRefs = trim((string)$defaultCiteGroupRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
$normalized[] = [
|
||||||
|
'reference_no' => $refNo,
|
||||||
|
'cite_group_refs' => $citeGroupRefs,
|
||||||
|
'can_support' => $canSupport,
|
||||||
|
'is_match' => $canSupport,
|
||||||
|
'confidence' => $confidence,
|
||||||
|
'reason' => $reason,
|
||||||
|
'support_role' => $supportRole,
|
||||||
|
'combined_can_support' => $combinedCanSupport,
|
||||||
|
'combined_confidence' => $combinedConfidence,
|
||||||
|
'combined_reason' => $this->cleanReason((string)(isset($item['combined_reason']) ? $item['combined_reason'] : '')),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeSupportRole($role)
|
||||||
|
{
|
||||||
|
$role = strtolower(trim((string)$role));
|
||||||
|
$allowed = [
|
||||||
|
'primary_support',
|
||||||
|
'supplementary_support',
|
||||||
|
'minimal_support',
|
||||||
|
'no_meaningful_support',
|
||||||
|
];
|
||||||
|
return in_array($role, $allowed, true) ? $role : 'no_meaningful_support';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function canSupportFromConfidence($confidence)
|
||||||
|
{
|
||||||
|
return floatval($confidence) >= 0.65 - 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 多通路/异质性 claim + DOI 有多通路证据时,防止误打 0.45(应对齐 0.78 部分支撑)
|
||||||
|
*/
|
||||||
|
private function applyMultiClaimPartialSupportFloor($localContext, $doiBlock, $confidence, $canSupport, $supportRole, $reason)
|
||||||
|
{
|
||||||
|
$confidence = floatval($confidence);
|
||||||
|
if ($confidence > 0.45) {
|
||||||
|
return [$confidence, $canSupport, $supportRole];
|
||||||
|
}
|
||||||
|
|
||||||
|
$claimText = trim((string)$localContext);
|
||||||
|
if ($claimText === '') {
|
||||||
|
return [$confidence, $canSupport, $supportRole];
|
||||||
|
}
|
||||||
|
|
||||||
|
$claimIsMechanism = (bool)preg_match(
|
||||||
|
'/\b(genomic heterogeneity|heterogeneity|survival pathway|pathways at once|single-target|multi.?pathway|genetic alteration|drug resistance|异质性|生存通路|多.*通路|单靶点|耐药)\b/ui',
|
||||||
|
$claimText
|
||||||
|
);
|
||||||
|
if (!$claimIsMechanism) {
|
||||||
|
return [$confidence, $canSupport, $supportRole];
|
||||||
|
}
|
||||||
|
|
||||||
|
$corpus = trim((string)$doiBlock) . ' ' . trim((string)$reason);
|
||||||
|
if ($corpus === '') {
|
||||||
|
return [$confidence, $canSupport, $supportRole];
|
||||||
|
}
|
||||||
|
|
||||||
|
$refHasPathwayEvidence = (bool)preg_match(
|
||||||
|
'/\b(pathway|PI3K|Akt|mTOR|Wnt|STAT3|NF-κB|NF-kB|genetic alteration|MSI|CIN|drug resistance|signaling|multiple|APC|KRAS|TP53|通路|耐药|信号)\b/ui',
|
||||||
|
$corpus
|
||||||
|
);
|
||||||
|
if (!$refHasPathwayEvidence) {
|
||||||
|
return [$confidence, $canSupport, $supportRole];
|
||||||
|
}
|
||||||
|
|
||||||
|
$confidence = 0.78;
|
||||||
|
$canSupport = true;
|
||||||
|
if ($supportRole === 'no_meaningful_support' || $supportRole === 'minimal_support') {
|
||||||
|
$supportRole = 'supplementary_support';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$confidence, $canSupport, $supportRole];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getReferenceCheckConfidenceBands()
|
||||||
|
{
|
||||||
|
return [0.15, 0.25, 0.45, 0.65, 0.78, 0.85, 0.92, 0.98];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function snapReferenceCheckConfidenceValue($confidence)
|
||||||
|
{
|
||||||
|
$bands = $this->getReferenceCheckConfidenceBands();
|
||||||
|
foreach ($bands as $band) {
|
||||||
|
if (abs($confidence - $band) < 0.001) {
|
||||||
|
return $band;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$nearest = $bands[0];
|
||||||
|
$minDiff = abs($confidence - $nearest);
|
||||||
|
foreach ($bands as $band) {
|
||||||
|
$diff = abs($confidence - $band);
|
||||||
|
if ($diff < $minDiff) {
|
||||||
|
$minDiff = $diff;
|
||||||
|
$nearest = $band;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 兼容旧逻辑
|
||||||
|
*/
|
||||||
|
private function getReferenceCheckConfidenceBandsLegacy($isMatch)
|
||||||
{
|
{
|
||||||
return $isMatch
|
return $isMatch
|
||||||
? [0.65, 0.78, 0.85, 0.92, 0.98]
|
? [0.65, 0.78, 0.85, 0.92, 0.98]
|
||||||
@@ -1183,22 +1796,24 @@ PROMPT;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将模型输出的 confidence 吸附到合法档位(如 0.95 → 0.92,0.75 → 0.78)
|
* 将模型输出的 confidence 吸附到合法档位
|
||||||
*/
|
*/
|
||||||
private function snapReferenceCheckConfidence($confidence, $isMatch)
|
private function snapReferenceCheckConfidence($confidence, $isMatch)
|
||||||
{
|
{
|
||||||
$bands = $this->getReferenceCheckConfidenceBands($isMatch);
|
$snapped = $this->snapReferenceCheckConfidenceValue($confidence);
|
||||||
|
$bands = $this->getReferenceCheckConfidenceBandsLegacy($isMatch);
|
||||||
|
if (in_array($snapped, $bands, true)) {
|
||||||
|
return $snapped;
|
||||||
|
}
|
||||||
foreach ($bands as $band) {
|
foreach ($bands as $band) {
|
||||||
if (abs($confidence - $band) < 0.001) {
|
if (abs($snapped - $band) < 0.001) {
|
||||||
return $band;
|
return $band;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$nearest = $bands[0];
|
$nearest = $bands[0];
|
||||||
$minDiff = abs($confidence - $nearest);
|
$minDiff = abs($snapped - $nearest);
|
||||||
foreach ($bands as $band) {
|
foreach ($bands as $band) {
|
||||||
$diff = abs($confidence - $band);
|
$diff = abs($snapped - $band);
|
||||||
if ($diff < $minDiff) {
|
if ($diff < $minDiff) {
|
||||||
$minDiff = $diff;
|
$minDiff = $diff;
|
||||||
$nearest = $band;
|
$nearest = $band;
|
||||||
|
|||||||
670
application/common/service/ReferenceRelevanceLlmService.php
Normal file
670
application/common/service/ReferenceRelevanceLlmService.php
Normal file
@@ -0,0 +1,670 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\common\service;
|
||||||
|
|
||||||
|
use think\Env;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参考文献「主题相关性」LLM 校对(独立于支撑力度校对 LLMService)
|
||||||
|
*/
|
||||||
|
class ReferenceRelevanceLlmService
|
||||||
|
{
|
||||||
|
private $url;
|
||||||
|
private $model;
|
||||||
|
private $apiKey;
|
||||||
|
private $timeout;
|
||||||
|
private $lastPostError = '';
|
||||||
|
private $maxSectionChars;
|
||||||
|
private $maxLocalContextChars;
|
||||||
|
private $maxReferChars;
|
||||||
|
private $maxAbstractChars;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->url = trim((string)Env::get('promotion.promotion_llm_url', ''));
|
||||||
|
$this->model = trim((string)Env::get('promotion.promotion_llm_model', ''));
|
||||||
|
$this->apiKey = trim((string)Env::get('promotion.promotion_llm_api_key', ''));
|
||||||
|
$this->timeout = max(180, intval(Env::get('promotion.promotion_llm_timeout', 180)));
|
||||||
|
// 控制发送给 LLM 的上下文长度,降低单次推理耗时(可通过 env 覆盖)
|
||||||
|
$this->maxSectionChars = max(1500, intval(Env::get('promotion.relevance_llm_max_section_chars', 4500)));
|
||||||
|
$this->maxLocalContextChars = max(600, intval(Env::get('promotion.relevance_llm_max_local_context_chars', 1800)));
|
||||||
|
$this->maxReferChars = max(1500, intval(Env::get('promotion.relevance_llm_max_refer_chars', 3500)));
|
||||||
|
$this->maxAbstractChars = max(1500, intval(Env::get('promotion.relevance_llm_max_abstract_chars', 3500)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{results:array,request_failed?:bool,reason?:string}
|
||||||
|
*/
|
||||||
|
public function checkRelevance($sectionText, $localContext, $referText, $abstractText = '', $citeGroupRefs = '')
|
||||||
|
{
|
||||||
|
$fallback = [
|
||||||
|
'results' => [],
|
||||||
|
'request_failed' => true,
|
||||||
|
'reason' => 'LLM not configured or request failed',
|
||||||
|
];
|
||||||
|
if ($this->url === '' || $this->model === '') {
|
||||||
|
return $fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sectionText = trim((string)$sectionText);
|
||||||
|
$localContext = trim((string)$localContext);
|
||||||
|
$referText = trim((string)$referText);
|
||||||
|
$abstractText = trim((string)$abstractText);
|
||||||
|
if ($sectionText === '' || $referText === '') {
|
||||||
|
return ['results' => [], 'reason' => 'Empty section or reference text'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mb_strlen($sectionText) > $this->maxSectionChars) {
|
||||||
|
$sectionText = mb_substr($sectionText, 0, $this->maxSectionChars);
|
||||||
|
}
|
||||||
|
if (mb_strlen($localContext) > $this->maxLocalContextChars) {
|
||||||
|
$localContext = mb_substr($localContext, 0, $this->maxLocalContextChars);
|
||||||
|
}
|
||||||
|
if (mb_strlen($referText) > $this->maxReferChars) {
|
||||||
|
$referText = mb_substr($referText, 0, $this->maxReferChars);
|
||||||
|
}
|
||||||
|
if (mb_strlen($abstractText) > $this->maxAbstractChars) {
|
||||||
|
$abstractText = mb_substr($abstractText, 0, $this->maxAbstractChars);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
'model' => $this->model,
|
||||||
|
'temperature' => 0,
|
||||||
|
'messages' => [
|
||||||
|
['role' => 'system', 'content' => $this->buildSystemPrompt()],
|
||||||
|
['role' => 'user', 'content' => $this->buildUserPrompt($sectionText, $localContext, $referText, $abstractText, $citeGroupRefs)],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$content = $this->postChat($payload);
|
||||||
|
if ($content === null) {
|
||||||
|
$reason = $this->lastPostError !== '' ? $this->lastPostError : 'LLM request failed';
|
||||||
|
return array_merge($fallback, ['reason' => $reason]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsed = $this->parseJson($content);
|
||||||
|
if ($parsed === null) {
|
||||||
|
return array_merge($fallback, ['reason' => 'LLM response JSON parse failed']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = $this->normalizeResults($parsed, $citeGroupRefs, $localContext, $referText, $abstractText);
|
||||||
|
if (empty($results)) {
|
||||||
|
return array_merge($fallback, ['reason' => 'LLM returned empty or invalid results']);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ['results' => $results];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildSystemPrompt()
|
||||||
|
{
|
||||||
|
return <<<'PROMPT'
|
||||||
|
你是一名护理、医学、生物医学与科研期刊的资深学术编辑,正在执行「参考文献主题相关性校对」。
|
||||||
|
|
||||||
|
你的任务:判断【引用位置正文表述】与【对应编号参考文献】在主题、研究对象、疾病/场景/结局方向上是否相关,能否作为该处引用的合理来源。
|
||||||
|
|
||||||
|
注意:这是「相关性」校对,侧重引用处具体 claim 与文献内容是否匹配;**不是**判断「是否同一疾病/同一领域」。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【零、最硬规则(违反则输出无效)】
|
||||||
|
1. **单条 relevance_score 只评价该编号文献单独**与引用处的关系;不得因联合组整体合理而抬高弱相关文献的单条分。
|
||||||
|
2. **禁止「同病高分」**:正文与文献都涉及 CRC,不等于单条可给 0.85~0.92。
|
||||||
|
**但若引用处 claim 本身就是机制/通路/异质性/耐药/治疗挑战**,且**研究主语一致**(同一疾病/同一化合物/同一干预对象),文献(含摘要/清洗内容)讨论同病多通路、遗传改变、耐药等,应给 **0.65~0.78**,不得误降到 0.45。
|
||||||
|
**主语不一致时仍适用本条禁止高分**:引用处主语为化合物 X,文献却是其他植物/提取物/计算预测,即使提到 X 或相同通路名,也不得因此给 0.78+。
|
||||||
|
3. 引用处若为**流行病学/负担类 claim**(most common、incidence、mortality、burden、全球高发等):
|
||||||
|
- 机制研究、分子通路、细胞增殖/迁移、血管生成等**原始研究** → 单条通常 **0.45 或更低**,`is_relevant=0`,`minimal_relevance`
|
||||||
|
- 不得因摘要提到 colorectal cancer 就给 0.92
|
||||||
|
- 仅当文献为流行病学综述/公共卫生研究,或明确讨论发病率、死亡率、疾病负担时,单条才可 **0.85~0.92**
|
||||||
|
4. **联合分写在 combined_relevance_score**,与单条分必须可分离(例如 [1,2] 时文献1=0.45、文献2=0.92、联合=0.92)。
|
||||||
|
5. **「来源/化学分类」型句子**(naturally occurring、pentacyclic triterpenoid、found in fruits/vegetables/medicinal plants、并列举具体植物学名):
|
||||||
|
- 先判文献类型:来源综述 / 生物活性综述 最适合;**抗癌治疗综述**对「来源分布」claim 通常仅 **0.65**
|
||||||
|
- 单篇可差异化打分(如 0.92 / 0.92 / 0.65),**不得**因联合而三篇都给高分
|
||||||
|
- 若原句含**具体列举项**(如多个植物学名),而材料未逐一核实全部学名,联合分通常 **≤0.85**(不得给 0.98)
|
||||||
|
6. **多要素综括句**(一句同时塞入:药学/研究兴趣 + 大量前临床研究 + 多种活性[抗炎/抗氧化/抗癌等] + 多个癌种/对象列举):
|
||||||
|
- 单篇即使是综述,通常仅 partially_related ~ near-direct(**0.78~0.86**),**不轻易给 0.92**(单篇难逐项覆盖全部要素)
|
||||||
|
- **联合分是整句覆盖度评估,可低于最高单条分**:若整句要素需多篇拼合、且含作者整合概括,联合通常 **0.72~0.78(partially_related)**,不给 0.85+
|
||||||
|
7. **联合分不是「取最高单条分」**:当各单篇都只覆盖整句一部分、需互补拼合时,联合分应反映「整句作为一个整体被支撑的完整度」,**允许低于任何一篇单条分**。
|
||||||
|
8. **主语/研究对象层级必须对齐**:引用处主语为某化合物/分子(如「X has been demonstrated…」)时,文献核心对象须为 **X 本身**或以 X 为核心的实验/综述。
|
||||||
|
- **植物提取物/混合物**研究、**其他物种/其他植物**的计算预测、成分表中顺带出现 X → 通常 **0.45 或更低**
|
||||||
|
- **关键:提取物即使 X 含量很高(如 50%+)且显示了抗癌/凋亡活性,活性归因于提取物整体而非 X 单体单独验证 → 仍属 weakly_related(≤0.45)、`minimal_relevance`**,不得评为 supplementary_relevance/0.78
|
||||||
|
- 只有当文献**针对 X 单体单独做了验证**(X monomer 处理、X 单独剂量效应等)时,主语才算对齐,方可进入 0.65+
|
||||||
|
- **不得**因摘要/讨论出现与引用句相同的通路名、凋亡、抗癌等词就给 0.78+
|
||||||
|
9. **证据层级与 demonstrated / mechanistically**:
|
||||||
|
- 本文实验结果或针对 X 的系统综述 > 计算预测/混合成分推测
|
||||||
|
- **讨论(Discussion)转引他人关于 X 的机制总结 ≠ 该文自身证据**;据此最多 **0.45~0.65**,不得评为 highly_related
|
||||||
|
- in silico / computational prediction 不足以支撑「has been demonstrated to mechanistically…」式强语气 claim 的高分
|
||||||
|
10. **点名通路/功能结局须逐项核对**:原句逐条列举通路(如 PI3K/AKT、MAPK、NF-κB)或结局(增殖、凋亡、血管生成、炎症信号等)时,**每一项单独核对是否在本文证据中成立**(非仅背景提及)。
|
||||||
|
- 讨论转述既往文献 ≠ 本文证明该项
|
||||||
|
- 缺原句任一点名项(如 angiogenesis)→ 单条通常 **不得 0.78+**
|
||||||
|
- **「覆盖部分结局」不足以进入 0.78**:原句点名了多条通路 + 多个结局,文献仅命中其中 1~2 个结局(如仅凋亡/增殖),且**点名通路在本文结果中全部缺失(仅讨论转引)**或主语层级不对 → 单条 **限 0.45(weakly_related / minimal_relevance)**,不得给 0.65~0.78
|
||||||
|
- 仅同领域沾边 1–2 项、主语或机制层级不对 → **0.45**
|
||||||
|
- **进入 0.65~0.78 的前提**:主语对齐(X 单体)+ 本文自身结果命中原句点名通路/结局的多数项;几乎全部明确对应 → **0.85+**
|
||||||
|
11. **文献「主题粒度」必须匹配 claim「主题粒度」**:引用处为**疾病总论型 claim**(流行病学负担、标准/多模态治疗现状与局限、基因组异质性、单靶点治疗受限、亟需新策略等总体背景)时:
|
||||||
|
- 最适合的来源是**疾病总体综述 / 分子病理综述 / 精准肿瘤学 / 耐药综述**;此类文献正面、系统地为该总论 claim 提供依据 → 可 **0.85+**
|
||||||
|
- **单一药物 / 单一成分 / 单一通路的专题综述**(如「某化合物抗某癌:A review」),即使同病、同大方向,也只是专题视角、并非为该总论 claim 做系统总结 → 通常 **partially_related(0.72~0.78)**,**不得给 0.85+**
|
||||||
|
- **单基因 / 单通路的机制原始研究**对纯流行病学负担 claim → 仍按规则 3 给 **0.45**
|
||||||
|
- 判断要点:文献类型是否「为该总论 claim 本身做系统综述/总论」;仅同病同方向、或只支撑整段中某一两句(如「需要更安全的新策略」),不足以进入 highly_related
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【一、必须先拆解 claim】
|
||||||
|
从【本引用位置附近上下文】中提炼最小主张单元(Claim A, Claim B…),**不要**把整句笼统归为「大概讲抗癌」。例如:
|
||||||
|
- **主语/研究对象**(化合物单体 vs 植物提取物 vs 其他物种;是否「X has been demonstrated」)
|
||||||
|
- **证据语气与层级**(demonstrated / mechanistically vs predict / suggest;本文结果 vs 讨论转引)
|
||||||
|
- **claim 主题粒度**:是否为疾病总论型(流行病学负担 / 治疗现状与局限 / 基因组异质性 / 单靶点受限 / 亟需新策略);若是,要求「总体综述 / 分子病理 / 精准肿瘤学 / 耐药综述」类来源,单一药物专题综述只算 partially_related
|
||||||
|
- 疾病流行病学(高发、死亡率)
|
||||||
|
- **点名通路/分子机制**(PI3K/AKT、MAPK、NF-κB 等,须逐项)
|
||||||
|
- **点名功能结局**(抑制增殖、凋亡、血管生成、炎症信号等,须逐项)
|
||||||
|
- 治疗/干预现状
|
||||||
|
- **化合物化学类别**(如 pentacyclic triterpenoid)
|
||||||
|
- **天然来源分布**(fruits / vegetables / medicinal plants)
|
||||||
|
- **具体列举项**(植物学名、药名、基因名等,须逐项核对)
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【二、逐篇文献单独判断(每条 result 对应一个 reference_no)】
|
||||||
|
对 cite_group_refs 中的每一篇文献,单独输出:
|
||||||
|
- 该文献与引用处哪些 claim 主题相关、哪些不相关(含具体列举项是否覆盖)
|
||||||
|
- 文献类型是否匹配引用用途(来源综述 / 生物活性综述 / 机制研究 / 流行病学综述 / 抗癌治疗综述等)
|
||||||
|
- relevance_score:只能使用 0.98 / 0.92 / 0.85 / 0.78 / 0.65 / 0.45 / 0.25 / 0.15
|
||||||
|
- relevance_level:highly_related | partially_related | weakly_related | unrelated
|
||||||
|
- is_relevant:score>=0.65 为 1,否则 0
|
||||||
|
- relevance_role:
|
||||||
|
- primary_relevance:该文献是引用处主题的主要相关来源
|
||||||
|
- supplementary_relevance:部分相关、补充性
|
||||||
|
- minimal_relevance:仅边缘/背景沾边
|
||||||
|
- no_meaningful_relevance:与引用处核心表述基本无关
|
||||||
|
- reason:中英双语结论,格式固定为两行:
|
||||||
|
【中文】(中文结论,须写明:①文献类型与**核心研究对象** ②**本文自身证据**覆盖了哪些 claim / 哪些未覆盖 ③主语/claim 不匹配须明确写出 ④为何此分值)
|
||||||
|
【English】(与中文对应的英文结论,语义一致)
|
||||||
|
- reason_en:仅英文结论(与 reason 中【English】段相同,勿留空)
|
||||||
|
|
||||||
|
主语/层级不对 → 单条 **0.45**,不得因讨论提及相同通路给 0.78:
|
||||||
|
引用处 claim 为「化合物 X 经 PI3K/AKT 等机制 demonstrated…」,文献为其他植物提取物或计算预测、仅在讨论转引他人 X 机制 → 0.45,weakly_related,is_relevant=0。
|
||||||
|
|
||||||
|
机制文引用流行病学句 → 单条 **0.45**,不得 0.92:
|
||||||
|
文献为 CRC 机制研究,引用处 claim 为全球高发/死亡率,文献无流行病学数据 → 0.45,minimal_relevance,is_relevant=0。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【三、联合引用 combined_*(同一 cite_group_refs 内各行必须一致)】
|
||||||
|
当 cite_group_refs 为 "1,2" 等多篇时,除逐篇判断外,必须给出引用组整体结论:
|
||||||
|
- 这些文献合起来,是否足以支撑/匹配该引用位置的整体表述?
|
||||||
|
- combined_relevance_score:八档固定分值之一,**不是单条平均分**
|
||||||
|
- 若一篇已强相关、其余仅弱补充,联合分可接近主相关文献,但**不必等于最高单条分**
|
||||||
|
- 若原句含具体列举项(学名等)且材料未逐一核实,联合分通常 **0.85**,不给 0.98
|
||||||
|
- 若核心 claim 无任何文献明确覆盖,联合分不能虚高
|
||||||
|
- 多篇联合仍缺主语对齐、缺原句点名通路/结局、或主要靠讨论转引 → 联合分通常 **≤0.45~0.65**,不得因单篇讨论出现相同关键词给到 0.78+
|
||||||
|
- combined_is_relevant:combined_relevance_score>=0.65 为 1
|
||||||
|
- combined_relevance_level:与 combined 分数对应的等级
|
||||||
|
- combined_reason:中英双语综合结论,格式同 reason(【中文】/【English】),说明各文献分工及最终分值理由
|
||||||
|
- combined_reason_en:仅英文综合结论(与 combined_reason 中【English】段相同)
|
||||||
|
|
||||||
|
单条引用时:combined_* 与单条一致;combined_reason / combined_reason_en 可与 reason / reason_en 相同。
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【四、评分与等级对照】
|
||||||
|
0.98 / 0.92 / 0.85 = highly_related
|
||||||
|
文献直接支持整句主旨,大部分关键要素都在文中明确出现
|
||||||
|
0.78 / 0.65 = partially_related
|
||||||
|
文献只支撑其中一部分,或支撑方式偏间接
|
||||||
|
0.45 = weakly_related
|
||||||
|
只是同领域文献,但与句子事实对应很弱
|
||||||
|
0.25 / 0.15 = unrelated
|
||||||
|
基本不支撑该句
|
||||||
|
≤0.15 = not_support
|
||||||
|
不支撑
|
||||||
|
|
||||||
|
==================================================
|
||||||
|
【五、输出 JSON(仅 JSON,无 markdown)】
|
||||||
|
{
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"reference_no": 1,
|
||||||
|
"cite_group_refs": "1,2",
|
||||||
|
"is_relevant": 0,
|
||||||
|
"relevance_score": 0.45,
|
||||||
|
"relevance_level": "weakly_related",
|
||||||
|
"relevance_role": "minimal_relevance",
|
||||||
|
"reason": "【中文】中文单条结论\n【English】English single-reference conclusion",
|
||||||
|
"reason_en": "English single-reference conclusion",
|
||||||
|
"combined_is_relevant": 1,
|
||||||
|
"combined_relevance_score": 0.92,
|
||||||
|
"combined_relevance_level": "highly_related",
|
||||||
|
"combined_reason": "【中文】中文联合结论\n【English】English combined conclusion",
|
||||||
|
"combined_reason_en": "English combined conclusion"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"reference_no": 2,
|
||||||
|
"cite_group_refs": "1,2",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
PROMPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildUserPrompt($sectionText, $localContext, $referText, $abstractText, $citeGroupRefs)
|
||||||
|
{
|
||||||
|
$parts = ["【正文节 t_article_main】\n" . $sectionText];
|
||||||
|
if (trim((string)$citeGroupRefs) !== '') {
|
||||||
|
$mode = strpos($citeGroupRefs, ',') !== false ? '联合引用' : '单独引用';
|
||||||
|
$parts[] = "【引用文献组 cite_group_refs】{$citeGroupRefs}({$mode})";
|
||||||
|
}
|
||||||
|
if ($localContext !== '') {
|
||||||
|
$parts[] = "【本引用位置附近上下文(优先据此拆解 claim)】\n" . $localContext;
|
||||||
|
}
|
||||||
|
$parts[] = "【参考文献书目(按编号)】\n" . $referText;
|
||||||
|
if ($abstractText !== '') {
|
||||||
|
$parts[] = "【文献摘要/清洗后内容(Europe PMC·PubMed·Crossref·PDF)】\n" . $abstractText;
|
||||||
|
}
|
||||||
|
$parts[] = '请先拆解最小主张单元(主语层级、证据来源、点名通路/结局逐项核对),判断每篇文献类型与**本文自身证据**,再**逐篇独立**给出单条 relevance_score(讨论转引、提取物/计算预测不得抬高;弱相关文献不得因联合而高分),最后给出 combined_*。reason / combined_reason 必须中英双语(【中文】/【English】),并分别填写 reason_en / combined_reason_en。仅输出 results 数组 JSON。';
|
||||||
|
|
||||||
|
return implode("\n\n", $parts);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeResults(array $parsed, $defaultCiteGroupRefs, $localContext = '', $referText = '', $abstractText = '')
|
||||||
|
{
|
||||||
|
$rows = [];
|
||||||
|
if (isset($parsed['results']) && is_array($parsed['results'])) {
|
||||||
|
$rows = $parsed['results'];
|
||||||
|
} elseif (isset($parsed['reference_no']) || isset($parsed['relevance_score'])) {
|
||||||
|
$rows = [$parsed];
|
||||||
|
}
|
||||||
|
|
||||||
|
$bands = $this->getScoreBands();
|
||||||
|
$localContext = trim((string)$localContext);
|
||||||
|
$referText = trim((string)$referText);
|
||||||
|
$abstractText = trim((string)$abstractText);
|
||||||
|
|
||||||
|
$out = [];
|
||||||
|
foreach ($rows as $item) {
|
||||||
|
if (!is_array($item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$refNo = intval(isset($item['reference_no']) ? $item['reference_no'] : 0);
|
||||||
|
if ($refNo <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$score = $this->snapScore(floatval(isset($item['relevance_score']) ? $item['relevance_score'] : 0), $bands);
|
||||||
|
$isRelevant = $score >= 0.65 - 0.001;
|
||||||
|
if (array_key_exists('is_relevant', $item)) {
|
||||||
|
$isRelevant = $this->boolVal($item['is_relevant']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$level = $this->levelFromScore($score, isset($item['relevance_level']) ? $item['relevance_level'] : '');
|
||||||
|
$role = $this->normalizeRelevanceRole(isset($item['relevance_role']) ? $item['relevance_role'] : '');
|
||||||
|
list($reason, $reasonEn) = $this->normalizeBilingualReason(
|
||||||
|
isset($item['reason']) ? $item['reason'] : '',
|
||||||
|
isset($item['reason_en']) ? $item['reason_en'] : ''
|
||||||
|
);
|
||||||
|
|
||||||
|
list($score, $level, $isRelevant, $role) = $this->enforceSingleReferenceConsistency(
|
||||||
|
$score,
|
||||||
|
$level,
|
||||||
|
$isRelevant,
|
||||||
|
$role,
|
||||||
|
$bands
|
||||||
|
);
|
||||||
|
|
||||||
|
$combinedScore = $this->snapScore(
|
||||||
|
floatval(isset($item['combined_relevance_score']) ? $item['combined_relevance_score'] : $score),
|
||||||
|
$bands
|
||||||
|
);
|
||||||
|
$combinedRelevant = $combinedScore >= 0.65 - 0.001;
|
||||||
|
if (array_key_exists('combined_is_relevant', $item)) {
|
||||||
|
$combinedRelevant = $this->boolVal($item['combined_is_relevant']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$combinedLevel = $this->levelFromScore(
|
||||||
|
$combinedScore,
|
||||||
|
isset($item['combined_relevance_level']) ? $item['combined_relevance_level'] : ''
|
||||||
|
);
|
||||||
|
list($combinedScore, $combinedLevel, $combinedRelevant) = $this->enforceCombinedConsistency(
|
||||||
|
$combinedScore,
|
||||||
|
$combinedLevel,
|
||||||
|
$combinedRelevant,
|
||||||
|
$bands
|
||||||
|
);
|
||||||
|
|
||||||
|
$citeGroupRefs = trim((string)(isset($item['cite_group_refs']) ? $item['cite_group_refs'] : $defaultCiteGroupRefs));
|
||||||
|
if ($citeGroupRefs === '' && $defaultCiteGroupRefs !== '') {
|
||||||
|
$citeGroupRefs = trim((string)$defaultCiteGroupRefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
list($combinedReason, $combinedReasonEn) = $this->normalizeBilingualReason(
|
||||||
|
isset($item['combined_reason']) ? $item['combined_reason'] : '',
|
||||||
|
isset($item['combined_reason_en']) ? $item['combined_reason_en'] : ''
|
||||||
|
);
|
||||||
|
if ($combinedReason === '' && $combinedReasonEn === '') {
|
||||||
|
list($combinedReason, $combinedReasonEn) = [$reason, $reasonEn];
|
||||||
|
}
|
||||||
|
|
||||||
|
$out[] = [
|
||||||
|
'reference_no' => $refNo,
|
||||||
|
'cite_group_refs' => $citeGroupRefs,
|
||||||
|
'is_relevant' => $isRelevant ? 1 : 0,
|
||||||
|
'relevance_score' => $score,
|
||||||
|
'relevance_level' => $level,
|
||||||
|
'relevance_role' => $role,
|
||||||
|
'reason' => $reason,
|
||||||
|
'reason_en' => $reasonEn,
|
||||||
|
'combined_is_relevant' => $combinedRelevant ? 1 : 0,
|
||||||
|
'combined_relevance_score' => $combinedScore,
|
||||||
|
'combined_relevance_level' => $combinedLevel,
|
||||||
|
'combined_reason' => $combinedReason,
|
||||||
|
'combined_reason_en' => $combinedReasonEn,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$out = $this->syncCombinedFieldsAcrossGroup($out);
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function enforceSingleReferenceConsistency($score, $level, $isRelevant, $role, array $bands)
|
||||||
|
{
|
||||||
|
$score = floatval($score);
|
||||||
|
if ($role === 'no_meaningful_relevance') {
|
||||||
|
if ($score > 0.25) {
|
||||||
|
$score = 0.25;
|
||||||
|
}
|
||||||
|
$level = 'unrelated';
|
||||||
|
$isRelevant = false;
|
||||||
|
} elseif ($role === 'minimal_relevance') {
|
||||||
|
if ($score > 0.45) {
|
||||||
|
$score = 0.45;
|
||||||
|
}
|
||||||
|
$level = 'weakly_related';
|
||||||
|
$isRelevant = false;
|
||||||
|
} elseif ($role === 'supplementary_relevance') {
|
||||||
|
if ($score > 0.78) {
|
||||||
|
$score = 0.78;
|
||||||
|
}
|
||||||
|
$level = $this->levelFromScore($score, $level);
|
||||||
|
} elseif ($role === 'primary_relevance') {
|
||||||
|
if ($score < 0.85) {
|
||||||
|
$score = 0.85;
|
||||||
|
}
|
||||||
|
$isRelevant = true;
|
||||||
|
$level = $this->levelFromScore($score, $level);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($level === 'weakly_related' && $score > 0.45) {
|
||||||
|
$score = 0.45;
|
||||||
|
$isRelevant = false;
|
||||||
|
} elseif ($level === 'unrelated' && $score > 0.25) {
|
||||||
|
$score = 0.25;
|
||||||
|
$isRelevant = false;
|
||||||
|
} elseif ($level === 'highly_related' && $score < 0.85) {
|
||||||
|
$score = 0.85;
|
||||||
|
$isRelevant = true;
|
||||||
|
} elseif ($level === 'partially_related') {
|
||||||
|
if ($score > 0.78) {
|
||||||
|
$score = 0.78;
|
||||||
|
}
|
||||||
|
if ($score < 0.65) {
|
||||||
|
$score = 0.65;
|
||||||
|
}
|
||||||
|
$isRelevant = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$isRelevant && $score >= 0.65) {
|
||||||
|
$score = 0.45;
|
||||||
|
$level = 'weakly_related';
|
||||||
|
}
|
||||||
|
if ($isRelevant && $score < 0.65) {
|
||||||
|
$score = 0.65;
|
||||||
|
$level = 'partially_related';
|
||||||
|
}
|
||||||
|
|
||||||
|
$score = $this->snapScore($score, $bands);
|
||||||
|
$level = $this->levelFromScore($score, $level);
|
||||||
|
|
||||||
|
return [$score, $level, $isRelevant, $role];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function enforceCombinedConsistency($combinedScore, $combinedLevel, $combinedRelevant, array $bands)
|
||||||
|
{
|
||||||
|
$combinedScore = $this->snapScore(floatval($combinedScore), $bands);
|
||||||
|
$combinedLevel = $this->levelFromScore($combinedScore, $combinedLevel);
|
||||||
|
$combinedRelevant = $combinedScore >= 0.65 - 0.001;
|
||||||
|
|
||||||
|
return [$combinedScore, $combinedLevel, $combinedRelevant];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function syncCombinedFieldsAcrossGroup(array $out)
|
||||||
|
{
|
||||||
|
$groups = [];
|
||||||
|
foreach ($out as $idx => $row) {
|
||||||
|
$key = (string)$row['cite_group_refs'];
|
||||||
|
if ($key === '') {
|
||||||
|
$key = 'ref:' . $row['reference_no'];
|
||||||
|
}
|
||||||
|
$groups[$key][] = $idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($groups as $indices) {
|
||||||
|
if (count($indices) <= 1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$bestIdx = $indices[0];
|
||||||
|
$bestScore = floatval($out[$bestIdx]['combined_relevance_score']);
|
||||||
|
foreach ($indices as $idx) {
|
||||||
|
$s = floatval($out[$idx]['combined_relevance_score']);
|
||||||
|
if ($s >= $bestScore) {
|
||||||
|
$bestScore = $s;
|
||||||
|
$bestIdx = $idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$src = $out[$bestIdx];
|
||||||
|
foreach ($indices as $idx) {
|
||||||
|
$out[$idx]['combined_is_relevant'] = intval($src['combined_is_relevant']);
|
||||||
|
$out[$idx]['combined_relevance_score'] = floatval($src['combined_relevance_score']);
|
||||||
|
$out[$idx]['combined_relevance_level'] = (string)$src['combined_relevance_level'];
|
||||||
|
$out[$idx]['combined_reason'] = (string)$src['combined_reason'];
|
||||||
|
$out[$idx]['combined_reason_en'] = (string)$src['combined_reason_en'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getScoreBands()
|
||||||
|
{
|
||||||
|
return [0.15, 0.25, 0.45, 0.65, 0.78, 0.85, 0.92, 0.98];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function snapScore($score, array $bands)
|
||||||
|
{
|
||||||
|
foreach ($bands as $band) {
|
||||||
|
if (abs($score - $band) < 0.001) {
|
||||||
|
return $band;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$nearest = $bands[0];
|
||||||
|
$minDiff = abs($score - $nearest);
|
||||||
|
foreach ($bands as $band) {
|
||||||
|
$diff = abs($score - $band);
|
||||||
|
if ($diff < $minDiff) {
|
||||||
|
$minDiff = $diff;
|
||||||
|
$nearest = $band;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nearest;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function levelFromScore($score, $levelHint = '')
|
||||||
|
{
|
||||||
|
$levelHint = strtolower(trim((string)$levelHint));
|
||||||
|
$allowed = ['highly_related', 'partially_related', 'weakly_related', 'unrelated'];
|
||||||
|
if (in_array($levelHint, $allowed, true)) {
|
||||||
|
return $levelHint;
|
||||||
|
}
|
||||||
|
$aliases = [
|
||||||
|
'highly_related' => ['highly_related', 'high_related', 'strong_related', 'strong_relevance'],
|
||||||
|
'partially_related' => ['partially_related', 'partial_related', 'moderate_related'],
|
||||||
|
'weakly_related' => ['weakly_related', 'weak_related', 'low_related', 'insufficient'],
|
||||||
|
'unrelated' => ['unrelated', 'not_related', 'irrelevant', 'no_meaningful_relevance'],
|
||||||
|
];
|
||||||
|
foreach ($aliases as $canonical => $list) {
|
||||||
|
if (in_array($levelHint, $list, true)) {
|
||||||
|
return $canonical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$score = floatval($score);
|
||||||
|
if ($score >= 0.85) {
|
||||||
|
return 'highly_related';
|
||||||
|
}
|
||||||
|
if ($score >= 0.65) {
|
||||||
|
return 'partially_related';
|
||||||
|
}
|
||||||
|
if ($score >= 0.45) {
|
||||||
|
return 'weakly_related';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'unrelated';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeRelevanceRole($role)
|
||||||
|
{
|
||||||
|
$role = strtolower(trim((string)$role));
|
||||||
|
$map = [
|
||||||
|
'primary_relevance' => ['primary_relevance', 'primary_support', 'primary'],
|
||||||
|
'supplementary_relevance' => ['supplementary_relevance', 'supplementary_support', 'supplementary'],
|
||||||
|
'minimal_relevance' => ['minimal_relevance', 'minimal_support', 'minimal'],
|
||||||
|
'no_meaningful_relevance' => ['no_meaningful_relevance', 'no_meaningful_support', 'none'],
|
||||||
|
];
|
||||||
|
foreach ($map as $canonical => $aliases) {
|
||||||
|
if ($role === $canonical || in_array($role, $aliases, true)) {
|
||||||
|
return $canonical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'no_meaningful_relevance';
|
||||||
|
}
|
||||||
|
|
||||||
|
private function cleanReason($reason)
|
||||||
|
{
|
||||||
|
$reason = trim(preg_replace('/[ \t]+/u', ' ', (string)$reason));
|
||||||
|
$reason = trim(preg_replace("/\n{3,}/u", "\n\n", $reason));
|
||||||
|
return mb_substr($reason, 0, 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{0:string,1:string} [bilingual reason, english only]
|
||||||
|
*/
|
||||||
|
private function normalizeBilingualReason($reason, $reasonEn)
|
||||||
|
{
|
||||||
|
$reason = trim((string)$reason);
|
||||||
|
$reasonEn = $this->cleanReason($reasonEn);
|
||||||
|
|
||||||
|
if ($reasonEn === '' && preg_match('/【English】\s*(.+)$/us', $reason, $m)) {
|
||||||
|
$reasonEn = $this->cleanReason($m[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$zh = '';
|
||||||
|
if (preg_match('/【中文】\s*(.*?)(?:\n【English】|$)/us', $reason, $m)) {
|
||||||
|
$zh = trim($m[1]);
|
||||||
|
} elseif ($reason !== '' && strpos($reason, '【English】') === false) {
|
||||||
|
$zh = trim($reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($zh !== '' && $reasonEn !== '' && strpos($reason, '【English】') === false) {
|
||||||
|
$reason = "【中文】{$zh}\n【English】{$reasonEn}";
|
||||||
|
} elseif ($zh !== '' && $reasonEn !== '' && strpos($reason, '【中文】') === false) {
|
||||||
|
$reason = "【中文】{$zh}\n【English】{$reasonEn}";
|
||||||
|
} else {
|
||||||
|
$reason = $this->cleanReason($reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reasonEn === '' && $zh !== '') {
|
||||||
|
$reasonEn = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$reason, $reasonEn];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function boolVal($v)
|
||||||
|
{
|
||||||
|
if (is_bool($v)) {
|
||||||
|
return $v;
|
||||||
|
}
|
||||||
|
if (is_numeric($v)) {
|
||||||
|
return intval($v) !== 0;
|
||||||
|
}
|
||||||
|
$s = strtolower(trim((string)$v));
|
||||||
|
return in_array($s, ['1', 'true', 'yes', 'y'], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function postChat(array $payload)
|
||||||
|
{
|
||||||
|
$this->lastPostError = '';
|
||||||
|
try {
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $this->url);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload, JSON_UNESCAPED_UNICODE));
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, min(15, $this->timeout));
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
|
||||||
|
$headers = ['Content-Type: application/json'];
|
||||||
|
if ($this->apiKey !== '') {
|
||||||
|
$headers[] = 'Authorization: Bearer ' . $this->apiKey;
|
||||||
|
}
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
$raw = curl_exec($ch);
|
||||||
|
if ($raw === false) {
|
||||||
|
$this->lastPostError = 'LLM curl error: ' . curl_error($ch);
|
||||||
|
\think\Log::warning('ReferenceRelevanceLlm: ' . $this->lastPostError);
|
||||||
|
curl_close($ch);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$httpCode = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
|
||||||
|
curl_close($ch);
|
||||||
|
if ($httpCode < 200 || $httpCode >= 300) {
|
||||||
|
$snippet = mb_substr(trim((string)$raw), 0, 200);
|
||||||
|
$this->lastPostError = 'LLM HTTP ' . $httpCode . ($snippet !== '' ? ': ' . $snippet : '');
|
||||||
|
\think\Log::warning('ReferenceRelevanceLlm: ' . $this->lastPostError);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$data = json_decode($raw, true);
|
||||||
|
if (!is_array($data)) {
|
||||||
|
$this->lastPostError = 'LLM response is not valid JSON';
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (isset($data['choices'][0]['message']['content'])) {
|
||||||
|
return (string)$data['choices'][0]['message']['content'];
|
||||||
|
}
|
||||||
|
if (isset($data['content'])) {
|
||||||
|
return (string)$data['content'];
|
||||||
|
}
|
||||||
|
$this->lastPostError = 'LLM response missing content field';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->lastPostError = 'LLM exception: ' . $e->getMessage();
|
||||||
|
\think\Log::warning('ReferenceRelevanceLlm: ' . $this->lastPostError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseJson($raw)
|
||||||
|
{
|
||||||
|
$raw = trim((string)$raw);
|
||||||
|
if ($raw === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$raw = preg_replace('/^```[a-zA-Z]*\s*|```$/m', '', $raw);
|
||||||
|
$raw = trim($raw);
|
||||||
|
$decoded = json_decode($raw, true);
|
||||||
|
if (is_array($decoded)) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
if (preg_match('/\{[\s\S]*\}/', $raw, $m)) {
|
||||||
|
$decoded = json_decode($m[0], true);
|
||||||
|
if (is_array($decoded)) {
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,8 @@
|
|||||||
"paypal/paypal-server-sdk": "^0.6.1",
|
"paypal/paypal-server-sdk": "^0.6.1",
|
||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
"php-amqplib/php-amqplib": "^2.12",
|
"php-amqplib/php-amqplib": "^2.12",
|
||||||
"tectalic/openai": "^1.6"
|
"tectalic/openai": "^1.6",
|
||||||
|
"smalot/pdfparser": "^2.0"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
-- 为预览标记增加原文位置字段([70-73] 展开为 4 条时共用 cite_tag_* / text_*)
|
-- 为预览标记增加原文位置字段([70-73] 展开为 4 条时共用 cite_tag_* / text_*)
|
||||||
ALTER TABLE `t_reference_check_result`
|
-- 已合并到 article_reference_check_result_alter_columns.sql(表名 t_article_reference_check_result)
|
||||||
|
ALTER TABLE `t_article_reference_check_result`
|
||||||
ADD COLUMN `cite_tag_start` int(11) NOT NULL DEFAULT 0 COMMENT 'blue标签起始字节偏移' AFTER `reference_raw`,
|
ADD COLUMN `cite_tag_start` int(11) NOT NULL DEFAULT 0 COMMENT 'blue标签起始字节偏移' AFTER `reference_raw`,
|
||||||
ADD COLUMN `cite_tag_end` int(11) NOT NULL DEFAULT 0 COMMENT 'blue标签结束字节偏移' AFTER `cite_tag_start`,
|
ADD COLUMN `cite_tag_end` int(11) NOT NULL DEFAULT 0 COMMENT 'blue标签结束字节偏移' AFTER `cite_tag_start`,
|
||||||
ADD COLUMN `text_start` int(11) NOT NULL DEFAULT 0 COMMENT '引用句起始字节偏移' AFTER `cite_tag_end`,
|
ADD COLUMN `text_start` int(11) NOT NULL DEFAULT 0 COMMENT '引用句起始字节偏移' AFTER `cite_tag_end`,
|
||||||
|
|||||||
5
vendor/composer/autoload_classmap.php
vendored
5
vendor/composer/autoload_classmap.php
vendored
@@ -6,5 +6,10 @@ $vendorDir = dirname(__DIR__);
|
|||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
|
||||||
|
'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||||
|
'Stringable' => $vendorDir . '/myclabs/php-enum/stubs/Stringable.php',
|
||||||
|
'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||||
|
'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||||
);
|
);
|
||||||
|
|||||||
3
vendor/composer/autoload_files.php
vendored
3
vendor/composer/autoload_files.php
vendored
@@ -7,12 +7,13 @@ $baseDir = dirname($vendorDir);
|
|||||||
|
|
||||||
return array(
|
return array(
|
||||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
|
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
|
||||||
|
'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
'9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php',
|
'9c67151ae59aff4788964ce8eb2a0f43' => $vendorDir . '/clue/stream-filter/src/functions_include.php',
|
||||||
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
|
'7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||||
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
|
'2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
|
||||||
'8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php',
|
'8cff32064859f4559445b89279f3199c' => $vendorDir . '/php-http/message/src/filters.php',
|
||||||
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
|
'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
|
||||||
'6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php',
|
|
||||||
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
|
'9b552a3cc426e3287cc811caefa3cf53' => $vendorDir . '/topthink/think-helper/src/helper.php',
|
||||||
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
|
'37a3dc5111fe8f707ab4c132ef1dbc62' => $vendorDir . '/guzzlehttp/guzzle/src/functions_include.php',
|
||||||
'1cfd2761b63b0a29ed23657ea394cb2d' => $vendorDir . '/topthink/think-captcha/src/helper.php',
|
'1cfd2761b63b0a29ed23657ea394cb2d' => $vendorDir . '/topthink/think-captcha/src/helper.php',
|
||||||
|
|||||||
1
vendor/composer/autoload_namespaces.php
vendored
1
vendor/composer/autoload_namespaces.php
vendored
@@ -6,6 +6,7 @@ $vendorDir = dirname(__DIR__);
|
|||||||
$baseDir = dirname($vendorDir);
|
$baseDir = dirname($vendorDir);
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
|
'Smalot\\PdfParser\\' => array($vendorDir . '/smalot/pdfparser/src'),
|
||||||
'Rs\\Json' => array($vendorDir . '/php-jsonpointer/php-jsonpointer/src'),
|
'Rs\\Json' => array($vendorDir . '/php-jsonpointer/php-jsonpointer/src'),
|
||||||
'PHPExcel' => array($vendorDir . '/phpoffice/phpexcel/Classes'),
|
'PHPExcel' => array($vendorDir . '/phpoffice/phpexcel/Classes'),
|
||||||
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
|
'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
|
||||||
|
|||||||
5
vendor/composer/autoload_psr4.php
vendored
5
vendor/composer/autoload_psr4.php
vendored
@@ -15,11 +15,12 @@ return array(
|
|||||||
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
|
'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
|
||||||
'Unirest\\' => array($vendorDir . '/apimatic/unirest-php/src'),
|
'Unirest\\' => array($vendorDir . '/apimatic/unirest-php/src'),
|
||||||
'Tectalic\\OpenAi\\' => array($vendorDir . '/tectalic/openai/src'),
|
'Tectalic\\OpenAi\\' => array($vendorDir . '/tectalic/openai/src'),
|
||||||
|
'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'),
|
||||||
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
|
||||||
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
|
'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'),
|
||||||
'Spatie\\DataTransferObject\\' => array($vendorDir . '/spatie/data-transfer-object/src'),
|
'Spatie\\DataTransferObject\\' => array($vendorDir . '/spatie/data-transfer-object/src'),
|
||||||
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
|
'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
|
||||||
'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
|
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
|
||||||
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
|
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
|
||||||
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
|
'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
|
||||||
'PhpOffice\\PhpWord\\' => array($vendorDir . '/phpoffice/phpword/src/PhpWord'),
|
'PhpOffice\\PhpWord\\' => array($vendorDir . '/phpoffice/phpword/src/PhpWord'),
|
||||||
@@ -30,6 +31,7 @@ return array(
|
|||||||
'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
|
'ParagonIE\\ConstantTime\\' => array($vendorDir . '/paragonie/constant_time_encoding/src'),
|
||||||
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
|
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
|
||||||
'Nyholm\\Psr7\\' => array($vendorDir . '/nyholm/psr7/src'),
|
'Nyholm\\Psr7\\' => array($vendorDir . '/nyholm/psr7/src'),
|
||||||
|
'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
|
||||||
'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
|
'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
|
||||||
'Http\\Message\\MultipartStream\\' => array($vendorDir . '/php-http/multipart-stream-builder/src'),
|
'Http\\Message\\MultipartStream\\' => array($vendorDir . '/php-http/multipart-stream-builder/src'),
|
||||||
'Http\\Message\\' => array($vendorDir . '/php-http/message/src'),
|
'Http\\Message\\' => array($vendorDir . '/php-http/message/src'),
|
||||||
@@ -39,7 +41,6 @@ return array(
|
|||||||
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
|
'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'),
|
||||||
'Core\\' => array($vendorDir . '/apimatic/core/src'),
|
'Core\\' => array($vendorDir . '/apimatic/core/src'),
|
||||||
'CoreInterfaces\\' => array($vendorDir . '/apimatic/core-interfaces/src'),
|
'CoreInterfaces\\' => array($vendorDir . '/apimatic/core-interfaces/src'),
|
||||||
'Composer\\Pcre\\' => array($vendorDir . '/composer/pcre/src'),
|
|
||||||
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
|
'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
|
||||||
'Clue\\StreamFilter\\' => array($vendorDir . '/clue/stream-filter/src'),
|
'Clue\\StreamFilter\\' => array($vendorDir . '/clue/stream-filter/src'),
|
||||||
);
|
);
|
||||||
|
|||||||
2
vendor/composer/autoload_real.php
vendored
2
vendor/composer/autoload_real.php
vendored
@@ -22,6 +22,8 @@ class ComposerAutoloaderInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
return self::$loader;
|
return self::$loader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
require __DIR__ . '/platform_check.php';
|
||||||
|
|
||||||
spl_autoload_register(array('ComposerAutoloaderInit2bc4f313dba415539e266f7ac2c87dcd', 'loadClassLoader'), true, true);
|
spl_autoload_register(array('ComposerAutoloaderInit2bc4f313dba415539e266f7ac2c87dcd', 'loadClassLoader'), true, true);
|
||||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||||
spl_autoload_unregister(array('ComposerAutoloaderInit2bc4f313dba415539e266f7ac2c87dcd', 'loadClassLoader'));
|
spl_autoload_unregister(array('ComposerAutoloaderInit2bc4f313dba415539e266f7ac2c87dcd', 'loadClassLoader'));
|
||||||
|
|||||||
32
vendor/composer/autoload_static.php
vendored
32
vendor/composer/autoload_static.php
vendored
@@ -8,12 +8,13 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
{
|
{
|
||||||
public static $files = array (
|
public static $files = array (
|
||||||
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
'0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
|
||||||
|
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
|
||||||
|
'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php',
|
||||||
'9c67151ae59aff4788964ce8eb2a0f43' => __DIR__ . '/..' . '/clue/stream-filter/src/functions_include.php',
|
'9c67151ae59aff4788964ce8eb2a0f43' => __DIR__ . '/..' . '/clue/stream-filter/src/functions_include.php',
|
||||||
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
|
'7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php',
|
||||||
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
|
'2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
|
||||||
'8cff32064859f4559445b89279f3199c' => __DIR__ . '/..' . '/php-http/message/src/filters.php',
|
'8cff32064859f4559445b89279f3199c' => __DIR__ . '/..' . '/php-http/message/src/filters.php',
|
||||||
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
|
'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php',
|
||||||
'6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php',
|
|
||||||
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
|
'9b552a3cc426e3287cc811caefa3cf53' => __DIR__ . '/..' . '/topthink/think-helper/src/helper.php',
|
||||||
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
|
'37a3dc5111fe8f707ab4c132ef1dbc62' => __DIR__ . '/..' . '/guzzlehttp/guzzle/src/functions_include.php',
|
||||||
'1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php',
|
'1cfd2761b63b0a29ed23657ea394cb2d' => __DIR__ . '/..' . '/topthink/think-captcha/src/helper.php',
|
||||||
@@ -50,6 +51,7 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
),
|
),
|
||||||
'S' =>
|
'S' =>
|
||||||
array (
|
array (
|
||||||
|
'Symfony\\Polyfill\\Php80\\' => 23,
|
||||||
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
'Symfony\\Polyfill\\Mbstring\\' => 26,
|
||||||
'Symfony\\Component\\HttpFoundation\\' => 33,
|
'Symfony\\Component\\HttpFoundation\\' => 33,
|
||||||
'Spatie\\DataTransferObject\\' => 26,
|
'Spatie\\DataTransferObject\\' => 26,
|
||||||
@@ -74,6 +76,7 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
),
|
),
|
||||||
'M' =>
|
'M' =>
|
||||||
array (
|
array (
|
||||||
|
'MyCLabs\\Enum\\' => 13,
|
||||||
'Matrix\\' => 7,
|
'Matrix\\' => 7,
|
||||||
),
|
),
|
||||||
'H' =>
|
'H' =>
|
||||||
@@ -92,7 +95,6 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
array (
|
array (
|
||||||
'Core\\' => 5,
|
'Core\\' => 5,
|
||||||
'CoreInterfaces\\' => 15,
|
'CoreInterfaces\\' => 15,
|
||||||
'Composer\\Pcre\\' => 14,
|
|
||||||
'Complex\\' => 8,
|
'Complex\\' => 8,
|
||||||
'Clue\\StreamFilter\\' => 18,
|
'Clue\\StreamFilter\\' => 18,
|
||||||
),
|
),
|
||||||
@@ -138,6 +140,10 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/tectalic/openai/src',
|
0 => __DIR__ . '/..' . '/tectalic/openai/src',
|
||||||
),
|
),
|
||||||
|
'Symfony\\Polyfill\\Php80\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/symfony/polyfill-php80',
|
||||||
|
),
|
||||||
'Symfony\\Polyfill\\Mbstring\\' =>
|
'Symfony\\Polyfill\\Mbstring\\' =>
|
||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
|
||||||
@@ -156,7 +162,7 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
),
|
),
|
||||||
'Psr\\Log\\' =>
|
'Psr\\Log\\' =>
|
||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/psr/log/src',
|
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
|
||||||
),
|
),
|
||||||
'Psr\\Http\\Message\\' =>
|
'Psr\\Http\\Message\\' =>
|
||||||
array (
|
array (
|
||||||
@@ -199,6 +205,10 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/nyholm/psr7/src',
|
0 => __DIR__ . '/..' . '/nyholm/psr7/src',
|
||||||
),
|
),
|
||||||
|
'MyCLabs\\Enum\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
|
||||||
|
),
|
||||||
'Matrix\\' =>
|
'Matrix\\' =>
|
||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src',
|
0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src',
|
||||||
@@ -235,10 +245,6 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/apimatic/core-interfaces/src',
|
0 => __DIR__ . '/..' . '/apimatic/core-interfaces/src',
|
||||||
),
|
),
|
||||||
'Composer\\Pcre\\' =>
|
|
||||||
array (
|
|
||||||
0 => __DIR__ . '/..' . '/composer/pcre/src',
|
|
||||||
),
|
|
||||||
'Complex\\' =>
|
'Complex\\' =>
|
||||||
array (
|
array (
|
||||||
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
|
0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
|
||||||
@@ -250,6 +256,13 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
);
|
);
|
||||||
|
|
||||||
public static $prefixesPsr0 = array (
|
public static $prefixesPsr0 = array (
|
||||||
|
'S' =>
|
||||||
|
array (
|
||||||
|
'Smalot\\PdfParser\\' =>
|
||||||
|
array (
|
||||||
|
0 => __DIR__ . '/..' . '/smalot/pdfparser/src',
|
||||||
|
),
|
||||||
|
),
|
||||||
'R' =>
|
'R' =>
|
||||||
array (
|
array (
|
||||||
'Rs\\Json' =>
|
'Rs\\Json' =>
|
||||||
@@ -274,7 +287,12 @@ class ComposerStaticInit2bc4f313dba415539e266f7ac2c87dcd
|
|||||||
);
|
);
|
||||||
|
|
||||||
public static $classMap = array (
|
public static $classMap = array (
|
||||||
|
'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php',
|
||||||
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
|
||||||
|
'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php',
|
||||||
|
'Stringable' => __DIR__ . '/..' . '/myclabs/php-enum/stubs/Stringable.php',
|
||||||
|
'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php',
|
||||||
|
'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php',
|
||||||
);
|
);
|
||||||
|
|
||||||
public static function getInitializer(ClassLoader $loader)
|
public static function getInitializer(ClassLoader $loader)
|
||||||
|
|||||||
832
vendor/composer/installed.json
vendored
832
vendor/composer/installed.json
vendored
File diff suppressed because it is too large
Load Diff
154
vendor/composer/installed.php
vendored
154
vendor/composer/installed.php
vendored
@@ -3,7 +3,7 @@
|
|||||||
'name' => 'topthink/think',
|
'name' => 'topthink/think',
|
||||||
'pretty_version' => 'dev-master',
|
'pretty_version' => 'dev-master',
|
||||||
'version' => 'dev-master',
|
'version' => 'dev-master',
|
||||||
'reference' => 'bbd690ca0f68c671ece05e82edc88ee7a68b82ed',
|
'reference' => '1d54946fef97376f7c2789af83a1616dd6f7a380',
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -11,9 +11,9 @@
|
|||||||
),
|
),
|
||||||
'versions' => array(
|
'versions' => array(
|
||||||
'apimatic/core' => array(
|
'apimatic/core' => array(
|
||||||
'pretty_version' => '0.3.16',
|
'pretty_version' => '0.3.17',
|
||||||
'version' => '0.3.16.0',
|
'version' => '0.3.17.0',
|
||||||
'reference' => 'ae4ab4ca26a41be41718f33c703d67b7a767c07b',
|
'reference' => 'a48a583f686ee3786432b976c795a2817ec095b3',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../apimatic/core',
|
'install_path' => __DIR__ . '/../apimatic/core',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -55,15 +55,6 @@
|
|||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'composer/pcre' => array(
|
|
||||||
'pretty_version' => '3.3.2',
|
|
||||||
'version' => '3.3.2.0',
|
|
||||||
'reference' => 'b2bed4734f0cc156ee1fe9c0da2550420d99a21e',
|
|
||||||
'type' => 'library',
|
|
||||||
'install_path' => __DIR__ . '/./pcre',
|
|
||||||
'aliases' => array(),
|
|
||||||
'dev_requirement' => false,
|
|
||||||
),
|
|
||||||
'ezyang/htmlpurifier' => array(
|
'ezyang/htmlpurifier' => array(
|
||||||
'pretty_version' => 'v4.19.0',
|
'pretty_version' => 'v4.19.0',
|
||||||
'version' => '4.19.0.0',
|
'version' => '4.19.0.0',
|
||||||
@@ -92,18 +83,18 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'guzzlehttp/psr7' => array(
|
'guzzlehttp/psr7' => array(
|
||||||
'pretty_version' => '2.8.0',
|
'pretty_version' => '2.9.0',
|
||||||
'version' => '2.8.0.0',
|
'version' => '2.9.0.0',
|
||||||
'reference' => '21dc724a0583619cd1652f673303492272778051',
|
'reference' => '7d0ed42f28e42d61352a7a79de682e5e67fec884',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
|
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'maennchen/zipstream-php' => array(
|
'maennchen/zipstream-php' => array(
|
||||||
'pretty_version' => '3.1.2',
|
'pretty_version' => '2.1.0',
|
||||||
'version' => '3.1.2.0',
|
'version' => '2.1.0.0',
|
||||||
'reference' => 'aeadcf5c412332eb426c0f9b4485f6accba2a99f',
|
'reference' => 'c4c5803cc1f93df3d2448478ef79394a5981cc58',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../maennchen/zipstream-php',
|
'install_path' => __DIR__ . '/../maennchen/zipstream-php',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -127,6 +118,15 @@
|
|||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
|
'myclabs/php-enum' => array(
|
||||||
|
'pretty_version' => '1.8.5',
|
||||||
|
'version' => '1.8.5.0',
|
||||||
|
'reference' => 'e7be26966b7398204a234f8673fdad5ac6277802',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../myclabs/php-enum',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'nyholm/psr7' => array(
|
'nyholm/psr7' => array(
|
||||||
'pretty_version' => '1.8.2',
|
'pretty_version' => '1.8.2',
|
||||||
'version' => '1.8.2.0',
|
'version' => '1.8.2.0',
|
||||||
@@ -137,9 +137,9 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'paragonie/constant_time_encoding' => array(
|
'paragonie/constant_time_encoding' => array(
|
||||||
'pretty_version' => 'v3.1.3',
|
'pretty_version' => 'v2.8.2',
|
||||||
'version' => '3.1.3.0',
|
'version' => '2.8.2.0',
|
||||||
'reference' => 'd5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77',
|
'reference' => 'e30811f7bc69e4b5b6d5783e712c06c8eabf0226',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
|
'install_path' => __DIR__ . '/../paragonie/constant_time_encoding',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -194,9 +194,9 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'php-http/message' => array(
|
'php-http/message' => array(
|
||||||
'pretty_version' => '1.16.1',
|
'pretty_version' => '1.16.2',
|
||||||
'version' => '1.16.1.0',
|
'version' => '1.16.2.0',
|
||||||
'reference' => '5997f3289332c699fa2545c427826272498a2088',
|
'reference' => '06dd5e8562f84e641bf929bfe699ee0f5ce8080a',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../php-http/message',
|
'install_path' => __DIR__ . '/../php-http/message',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -209,9 +209,9 @@
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
'php-http/multipart-stream-builder' => array(
|
'php-http/multipart-stream-builder' => array(
|
||||||
'pretty_version' => '1.3.1',
|
'pretty_version' => '1.4.2',
|
||||||
'version' => '1.3.1.0',
|
'version' => '1.4.2.0',
|
||||||
'reference' => 'ed56da23b95949ae4747378bed8a5b61a2fdae24',
|
'reference' => '10086e6de6f53489cca5ecc45b6f468604d3460e',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../php-http/multipart-stream-builder',
|
'install_path' => __DIR__ . '/../php-http/multipart-stream-builder',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -227,18 +227,18 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'phpmailer/phpmailer' => array(
|
'phpmailer/phpmailer' => array(
|
||||||
'pretty_version' => 'v6.11.1',
|
'pretty_version' => 'v6.12.0',
|
||||||
'version' => '6.11.1.0',
|
'version' => '6.12.0.0',
|
||||||
'reference' => 'd9e3b36b47f04b497a0164c5a20f92acb4593284',
|
'reference' => 'd1ac35d784bf9f5e61b424901d5a014967f15b12',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
|
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'phpoffice/math' => array(
|
'phpoffice/math' => array(
|
||||||
'pretty_version' => '0.2.0',
|
'pretty_version' => '0.3.0',
|
||||||
'version' => '0.2.0.0',
|
'version' => '0.3.0.0',
|
||||||
'reference' => 'fc2eb6d1a61b058d5dac77197059db30ee3c8329',
|
'reference' => 'fc31c8f57a7a81f962cbf389fd89f4d9d06fc99a',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../phpoffice/math',
|
'install_path' => __DIR__ . '/../phpoffice/math',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -254,18 +254,18 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'phpoffice/phpspreadsheet' => array(
|
'phpoffice/phpspreadsheet' => array(
|
||||||
'pretty_version' => '1.30.1',
|
'pretty_version' => '1.25.2',
|
||||||
'version' => '1.30.1.0',
|
'version' => '1.25.2.0',
|
||||||
'reference' => 'fa8257a579ec623473eabfe49731de5967306c4c',
|
'reference' => 'a317a09e7def49852400a4b3eca4a4b0790ceeb5',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
|
'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'phpoffice/phpword' => array(
|
'phpoffice/phpword' => array(
|
||||||
'pretty_version' => '1.3.0',
|
'pretty_version' => '1.4.0',
|
||||||
'version' => '1.3.0.0',
|
'version' => '1.4.0.0',
|
||||||
'reference' => '8392134ce4b5dba65130ba956231a1602b848b7f',
|
'reference' => '6d75328229bc93790b37e93741adf70646cea958',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../phpoffice/phpword',
|
'install_path' => __DIR__ . '/../phpoffice/phpword',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -297,9 +297,9 @@
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
'psr/http-factory' => array(
|
'psr/http-factory' => array(
|
||||||
'pretty_version' => '1.0.2',
|
'pretty_version' => '1.1.0',
|
||||||
'version' => '1.0.2.0',
|
'version' => '1.1.0.0',
|
||||||
'reference' => 'e616d01114759c4c489f93b099585439f795fe35',
|
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/http-factory',
|
'install_path' => __DIR__ . '/../psr/http-factory',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -313,9 +313,9 @@
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
'psr/http-message' => array(
|
'psr/http-message' => array(
|
||||||
'pretty_version' => '2.0',
|
'pretty_version' => '1.1',
|
||||||
'version' => '2.0.0.0',
|
'version' => '1.1.0.0',
|
||||||
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
|
'reference' => 'cb6ce4845ce34a8ad9e68117c10ee90a29919eba',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/http-message',
|
'install_path' => __DIR__ . '/../psr/http-message',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -329,18 +329,18 @@
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
'psr/log' => array(
|
'psr/log' => array(
|
||||||
'pretty_version' => '3.0.1',
|
'pretty_version' => '1.1.4',
|
||||||
'version' => '3.0.1.0',
|
'version' => '1.1.4.0',
|
||||||
'reference' => '79dff0b268932c640297f5208d6298f71855c03e',
|
'reference' => 'd49695b909c3b7628b6289db5479a1c204601f11',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/log',
|
'install_path' => __DIR__ . '/../psr/log',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'psr/simple-cache' => array(
|
'psr/simple-cache' => array(
|
||||||
'pretty_version' => '3.0.0',
|
'pretty_version' => '1.0.1',
|
||||||
'version' => '3.0.0.0',
|
'version' => '1.0.1.0',
|
||||||
'reference' => '764e0b3939f5ca87cb904f570ef9be2d78a07865',
|
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../psr/simple-cache',
|
'install_path' => __DIR__ . '/../psr/simple-cache',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -355,6 +355,15 @@
|
|||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
|
'smalot/pdfparser' => array(
|
||||||
|
'pretty_version' => 'v2.9.0',
|
||||||
|
'version' => '2.9.0.0',
|
||||||
|
'reference' => '6b53144fcb24af77093d4150dd7d0dd571f25761',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../smalot/pdfparser',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'spatie/data-transfer-object' => array(
|
'spatie/data-transfer-object' => array(
|
||||||
'pretty_version' => '1.14.1',
|
'pretty_version' => '1.14.1',
|
||||||
'version' => '1.14.1.0',
|
'version' => '1.14.1.0',
|
||||||
@@ -365,32 +374,41 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/deprecation-contracts' => array(
|
'symfony/deprecation-contracts' => array(
|
||||||
'pretty_version' => 'v3.6.0',
|
'pretty_version' => 'v2.5.4',
|
||||||
'version' => '3.6.0.0',
|
'version' => '2.5.4.0',
|
||||||
'reference' => '63afe740e99a13ba87ec199bb07bbdee937a5b62',
|
'reference' => '605389f2a7e5625f273b53960dc46aeaf9c62918',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
|
'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/http-foundation' => array(
|
'symfony/http-foundation' => array(
|
||||||
'pretty_version' => 'v8.0.1',
|
'pretty_version' => 'v5.4.50',
|
||||||
'version' => '8.0.1.0',
|
'version' => '5.4.50.0',
|
||||||
'reference' => '3690740e2e8b19d877f20d4f10b7a489cddf0fe2',
|
'reference' => '1a0706e8b8041046052ea2695eb8aeee04f97609',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/http-foundation',
|
'install_path' => __DIR__ . '/../symfony/http-foundation',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'symfony/polyfill-mbstring' => array(
|
'symfony/polyfill-mbstring' => array(
|
||||||
'pretty_version' => 'v1.32.0',
|
'pretty_version' => 'v1.37.0',
|
||||||
'version' => '1.32.0.0',
|
'version' => '1.37.0.0',
|
||||||
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
|
'reference' => '6a21eb99c6973357967f6ce3708cd55a6bec6315',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
|
'symfony/polyfill-php80' => array(
|
||||||
|
'pretty_version' => 'v1.37.0',
|
||||||
|
'version' => '1.37.0.0',
|
||||||
|
'reference' => 'dfb55726c3a76ea3b6459fcfda1ec2d80a682411',
|
||||||
|
'type' => 'library',
|
||||||
|
'install_path' => __DIR__ . '/../symfony/polyfill-php80',
|
||||||
|
'aliases' => array(),
|
||||||
|
'dev_requirement' => false,
|
||||||
|
),
|
||||||
'tectalic/openai' => array(
|
'tectalic/openai' => array(
|
||||||
'pretty_version' => 'v1.6.0',
|
'pretty_version' => 'v1.6.0',
|
||||||
'version' => '1.6.0.0',
|
'version' => '1.6.0.0',
|
||||||
@@ -412,7 +430,7 @@
|
|||||||
'topthink/think' => array(
|
'topthink/think' => array(
|
||||||
'pretty_version' => 'dev-master',
|
'pretty_version' => 'dev-master',
|
||||||
'version' => 'dev-master',
|
'version' => 'dev-master',
|
||||||
'reference' => 'bbd690ca0f68c671ece05e82edc88ee7a68b82ed',
|
'reference' => '1d54946fef97376f7c2789af83a1616dd6f7a380',
|
||||||
'type' => 'project',
|
'type' => 'project',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
@@ -428,18 +446,18 @@
|
|||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'topthink/think-helper' => array(
|
'topthink/think-helper' => array(
|
||||||
'pretty_version' => 'v3.1.11',
|
'pretty_version' => 'v3.1.12',
|
||||||
'version' => '3.1.11.0',
|
'version' => '3.1.12.0',
|
||||||
'reference' => '1d6ada9b9f3130046bf6922fe1bd159c8d88a33c',
|
'reference' => 'fe277121112a8f1c872e169a733ca80bb11c4acb',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../topthink/think-helper',
|
'install_path' => __DIR__ . '/../topthink/think-helper',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'topthink/think-image' => array(
|
'topthink/think-image' => array(
|
||||||
'pretty_version' => 'v1.0.7',
|
'pretty_version' => 'v1.0.8',
|
||||||
'version' => '1.0.7.0',
|
'version' => '1.0.8.0',
|
||||||
'reference' => '8586cf47f117481c6d415b20f7dedf62e79d5512',
|
'reference' => 'd1d748cbb2fe2f29fca6138cf96cb8b5113892f1',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../topthink/think-image',
|
'install_path' => __DIR__ . '/../topthink/think-image',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
|
|||||||
2
vendor/phpmailer/phpmailer/README.md
vendored
2
vendor/phpmailer/phpmailer/README.md
vendored
@@ -48,7 +48,7 @@ This software is distributed under the [LGPL 2.1](https://www.gnu.org/licenses/o
|
|||||||
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
|
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"phpmailer/phpmailer": "^6.11.1"
|
"phpmailer/phpmailer": "^6.12.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
or run
|
or run
|
||||||
|
|||||||
2
vendor/phpmailer/phpmailer/VERSION
vendored
2
vendor/phpmailer/phpmailer/VERSION
vendored
@@ -1 +1 @@
|
|||||||
6.11.1
|
6.12.0
|
||||||
|
|||||||
6
vendor/phpmailer/phpmailer/composer.json
vendored
6
vendor/phpmailer/phpmailer/composer.json
vendored
@@ -49,15 +49,14 @@
|
|||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
|
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
|
||||||
"ext-imap": "Needed to support advanced email address parsing according to RFC822",
|
|
||||||
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
|
||||||
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
|
||||||
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
|
||||||
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
|
||||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
|
||||||
"psr/log": "For optional PSR-3 debug logging",
|
"psr/log": "For optional PSR-3 debug logging",
|
||||||
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
|
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication",
|
||||||
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
|
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
@@ -72,7 +71,6 @@
|
|||||||
"license": "LGPL-2.1-only",
|
"license": "LGPL-2.1-only",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"check": "./vendor/bin/phpcs",
|
"check": "./vendor/bin/phpcs",
|
||||||
"style": "./vendor/bin/phpcbf",
|
|
||||||
"test": "./vendor/bin/phpunit --no-coverage",
|
"test": "./vendor/bin/phpunit --no-coverage",
|
||||||
"coverage": "./vendor/bin/phpunit",
|
"coverage": "./vendor/bin/phpunit",
|
||||||
"lint": [
|
"lint": [
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
|
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
|
||||||
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP ha sido afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
|
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP está afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
|
||||||
$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.';
|
$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.';
|
||||||
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
|
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
|
||||||
$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.';
|
$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.';
|
||||||
@@ -18,7 +18,7 @@ $PHPMAILER_LANG['execute'] = 'Imposible ejecutar: ';
|
|||||||
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
|
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
|
||||||
$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: ';
|
$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: ';
|
||||||
$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: ';
|
$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: ';
|
||||||
$PHPMAILER_LANG['from_failed'] = 'La siguiente dirección de remitente falló: ';
|
$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: ';
|
||||||
$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.';
|
$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.';
|
||||||
$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: ';
|
$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: ';
|
||||||
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
|
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
|
||||||
@@ -34,5 +34,3 @@ $PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
|
|||||||
$PHPMAILER_LANG['smtp_detail'] = 'Detalle: ';
|
$PHPMAILER_LANG['smtp_detail'] = 'Detalle: ';
|
||||||
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
|
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
|
||||||
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
|
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
|
||||||
$PHPMAILER_LANG['imap_recommended'] = 'No se recomienda usar el analizador de direcciones simplificado. Instala la extensión IMAP de PHP para un análisis RFC822 más completo.';
|
|
||||||
$PHPMAILER_LANG['deprecated_argument'] = 'El argumento $useimap ha quedado obsoleto';
|
|
||||||
|
|||||||
374
vendor/phpmailer/phpmailer/src/PHPMailer.php
vendored
374
vendor/phpmailer/phpmailer/src/PHPMailer.php
vendored
@@ -561,9 +561,9 @@ class PHPMailer
|
|||||||
* string $body the email body
|
* string $body the email body
|
||||||
* string $from email address of sender
|
* string $from email address of sender
|
||||||
* string $extra extra information of possible use
|
* string $extra extra information of possible use
|
||||||
* 'smtp_transaction_id' => last smtp transaction id
|
* "smtp_transaction_id' => last smtp transaction id
|
||||||
*
|
*
|
||||||
* @var callable|callable-string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $action_function = '';
|
public $action_function = '';
|
||||||
|
|
||||||
@@ -711,7 +711,7 @@ class PHPMailer
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected static $language = [];
|
protected $language = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of errors encountered.
|
* The number of errors encountered.
|
||||||
@@ -768,7 +768,7 @@ class PHPMailer
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const VERSION = '6.11.1';
|
const VERSION = '6.12.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error severity: message only, continue processing.
|
* Error severity: message only, continue processing.
|
||||||
@@ -1102,7 +1102,7 @@ class PHPMailer
|
|||||||
//At-sign is missing.
|
//At-sign is missing.
|
||||||
$error_message = sprintf(
|
$error_message = sprintf(
|
||||||
'%s (%s): %s',
|
'%s (%s): %s',
|
||||||
self::lang('invalid_address'),
|
$this->lang('invalid_address'),
|
||||||
$kind,
|
$kind,
|
||||||
$address
|
$address
|
||||||
);
|
);
|
||||||
@@ -1187,7 +1187,7 @@ class PHPMailer
|
|||||||
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
|
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
|
||||||
$error_message = sprintf(
|
$error_message = sprintf(
|
||||||
'%s: %s',
|
'%s: %s',
|
||||||
self::lang('Invalid recipient kind'),
|
$this->lang('Invalid recipient kind'),
|
||||||
$kind
|
$kind
|
||||||
);
|
);
|
||||||
$this->setError($error_message);
|
$this->setError($error_message);
|
||||||
@@ -1201,7 +1201,7 @@ class PHPMailer
|
|||||||
if (!static::validateAddress($address)) {
|
if (!static::validateAddress($address)) {
|
||||||
$error_message = sprintf(
|
$error_message = sprintf(
|
||||||
'%s (%s): %s',
|
'%s (%s): %s',
|
||||||
self::lang('invalid_address'),
|
$this->lang('invalid_address'),
|
||||||
$kind,
|
$kind,
|
||||||
$address
|
$address
|
||||||
);
|
);
|
||||||
@@ -1220,16 +1220,12 @@ class PHPMailer
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} elseif (!array_key_exists(strtolower($address), $this->ReplyTo)) {
|
||||||
foreach ($this->ReplyTo as $replyTo) {
|
$this->ReplyTo[strtolower($address)] = [$address, $name];
|
||||||
if (0 === strcasecmp($replyTo[0], $address)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->ReplyTo[] = [$address, $name];
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1242,18 +1238,15 @@ class PHPMailer
|
|||||||
* @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
|
* @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
|
||||||
*
|
*
|
||||||
* @param string $addrstr The address list string
|
* @param string $addrstr The address list string
|
||||||
* @param null $useimap Deprecated argument since 6.11.0.
|
* @param bool $useimap Whether to use the IMAP extension to parse the list
|
||||||
* @param string $charset The charset to use when decoding the address list string.
|
* @param string $charset The charset to use when decoding the address list string.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function parseAddresses($addrstr, $useimap = null, $charset = self::CHARSET_ISO88591)
|
public static function parseAddresses($addrstr, $useimap = true, $charset = self::CHARSET_ISO88591)
|
||||||
{
|
{
|
||||||
if ($useimap !== null) {
|
|
||||||
trigger_error(self::lang('deprecated_argument'), E_USER_DEPRECATED);
|
|
||||||
}
|
|
||||||
$addresses = [];
|
$addresses = [];
|
||||||
if (function_exists('imap_rfc822_parse_adrlist')) {
|
if ($useimap && function_exists('imap_rfc822_parse_adrlist')) {
|
||||||
//Use this built-in parser if it's available
|
//Use this built-in parser if it's available
|
||||||
$list = imap_rfc822_parse_adrlist($addrstr, '');
|
$list = imap_rfc822_parse_adrlist($addrstr, '');
|
||||||
// Clear any potential IMAP errors to get rid of notices being thrown at end of script.
|
// Clear any potential IMAP errors to get rid of notices being thrown at end of script.
|
||||||
@@ -1263,13 +1256,20 @@ class PHPMailer
|
|||||||
'.SYNTAX-ERROR.' !== $address->host &&
|
'.SYNTAX-ERROR.' !== $address->host &&
|
||||||
static::validateAddress($address->mailbox . '@' . $address->host)
|
static::validateAddress($address->mailbox . '@' . $address->host)
|
||||||
) {
|
) {
|
||||||
//Decode the name part if it's present and maybe encoded
|
//Decode the name part if it's present and encoded
|
||||||
if (
|
if (
|
||||||
property_exists($address, 'personal')
|
property_exists($address, 'personal') &&
|
||||||
&& is_string($address->personal)
|
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
|
||||||
&& $address->personal !== ''
|
defined('MB_CASE_UPPER') &&
|
||||||
|
preg_match('/^=\?.*\?=$/s', $address->personal)
|
||||||
) {
|
) {
|
||||||
$address->personal = static::decodeHeader($address->personal, $charset);
|
$origCharset = mb_internal_encoding();
|
||||||
|
mb_internal_encoding($charset);
|
||||||
|
//Undo any RFC2047-encoded spaces-as-underscores
|
||||||
|
$address->personal = str_replace('_', '=20', $address->personal);
|
||||||
|
//Decode the name
|
||||||
|
$address->personal = mb_decode_mimeheader($address->personal);
|
||||||
|
mb_internal_encoding($origCharset);
|
||||||
}
|
}
|
||||||
|
|
||||||
$addresses[] = [
|
$addresses[] = [
|
||||||
@@ -1280,51 +1280,40 @@ class PHPMailer
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//Use this simpler parser
|
//Use this simpler parser
|
||||||
$addresses = static::parseSimplerAddresses($addrstr, $charset);
|
$list = explode(',', $addrstr);
|
||||||
}
|
foreach ($list as $address) {
|
||||||
|
$address = trim($address);
|
||||||
return $addresses;
|
//Is there a separate name part?
|
||||||
}
|
if (strpos($address, '<') === false) {
|
||||||
|
//No separate name, just use the whole thing
|
||||||
/**
|
if (static::validateAddress($address)) {
|
||||||
* Parse a string containing one or more RFC822-style comma-separated email addresses
|
$addresses[] = [
|
||||||
* with the form "display name <address>" into an array of name/address pairs.
|
'name' => '',
|
||||||
* Uses a simpler parser that does not require the IMAP extension but doesnt support
|
'address' => $address,
|
||||||
* the full RFC822 spec. For full RFC822 support, use the PHP IMAP extension.
|
];
|
||||||
*
|
}
|
||||||
* @param string $addrstr The address list string
|
} else {
|
||||||
* @param string $charset The charset to use when decoding the address list string.
|
list($name, $email) = explode('<', $address);
|
||||||
*
|
$email = trim(str_replace('>', '', $email));
|
||||||
* @return array
|
$name = trim($name);
|
||||||
*/
|
if (static::validateAddress($email)) {
|
||||||
protected static function parseSimplerAddresses($addrstr, $charset)
|
//Check for a Mbstring constant rather than using extension_loaded, which is sometimes disabled
|
||||||
{
|
//If this name is encoded, decode it
|
||||||
// Emit a runtime notice to recommend using the IMAP extension for full RFC822 parsing
|
if (defined('MB_CASE_UPPER') && preg_match('/^=\?.*\?=$/s', $name)) {
|
||||||
trigger_error(self::lang('imap_recommended'), E_USER_NOTICE);
|
$origCharset = mb_internal_encoding();
|
||||||
|
mb_internal_encoding($charset);
|
||||||
$addresses = [];
|
//Undo any RFC2047-encoded spaces-as-underscores
|
||||||
$list = explode(',', $addrstr);
|
$name = str_replace('_', '=20', $name);
|
||||||
foreach ($list as $address) {
|
//Decode the name
|
||||||
$address = trim($address);
|
$name = mb_decode_mimeheader($name);
|
||||||
//Is there a separate name part?
|
mb_internal_encoding($origCharset);
|
||||||
if (strpos($address, '<') === false) {
|
}
|
||||||
//No separate name, just use the whole thing
|
$addresses[] = [
|
||||||
if (static::validateAddress($address)) {
|
//Remove any surrounding quotes and spaces from the name
|
||||||
$addresses[] = [
|
'name' => trim($name, '\'" '),
|
||||||
'name' => '',
|
'address' => $email,
|
||||||
'address' => $address,
|
];
|
||||||
];
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$parsed = static::parseEmailString($address);
|
|
||||||
$email = $parsed['email'];
|
|
||||||
if (static::validateAddress($email)) {
|
|
||||||
$name = static::decodeHeader($parsed['name'], $charset);
|
|
||||||
$addresses[] = [
|
|
||||||
//Remove any surrounding quotes and spaces from the name
|
|
||||||
'name' => trim($name, '\'" '),
|
|
||||||
'address' => $email,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1332,42 +1321,6 @@ class PHPMailer
|
|||||||
return $addresses;
|
return $addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a string containing an email address with an optional name
|
|
||||||
* and divide it into a name and email address.
|
|
||||||
*
|
|
||||||
* @param string $input The email with name.
|
|
||||||
*
|
|
||||||
* @return array{name: string, email: string}
|
|
||||||
*/
|
|
||||||
private static function parseEmailString($input)
|
|
||||||
{
|
|
||||||
$input = trim((string)$input);
|
|
||||||
|
|
||||||
if ($input === '') {
|
|
||||||
return ['name' => '', 'email' => ''];
|
|
||||||
}
|
|
||||||
|
|
||||||
$pattern = '/^\s*(?:(?:"([^"]*)"|\'([^\']*)\'|([^<]*?))\s*)?<\s*([^>]+)\s*>\s*$/';
|
|
||||||
if (preg_match($pattern, $input, $matches)) {
|
|
||||||
$name = '';
|
|
||||||
// Double quotes including special scenarios.
|
|
||||||
if (isset($matches[1]) && $matches[1] !== '') {
|
|
||||||
$name = $matches[1];
|
|
||||||
// Single quotes including special scenarios.
|
|
||||||
} elseif (isset($matches[2]) && $matches[2] !== '') {
|
|
||||||
$name = $matches[2];
|
|
||||||
// Simplest scenario, name and email are in the format "Name <email>".
|
|
||||||
} elseif (isset($matches[3])) {
|
|
||||||
$name = trim($matches[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['name' => $name, 'email' => trim($matches[4])];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ['name' => '', 'email' => $input];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the From and FromName properties.
|
* Set the From and FromName properties.
|
||||||
*
|
*
|
||||||
@@ -1381,10 +1334,6 @@ class PHPMailer
|
|||||||
*/
|
*/
|
||||||
public function setFrom($address, $name = '', $auto = true)
|
public function setFrom($address, $name = '', $auto = true)
|
||||||
{
|
{
|
||||||
if (is_null($name)) {
|
|
||||||
//Helps avoid a deprecation warning in the preg_replace() below
|
|
||||||
$name = '';
|
|
||||||
}
|
|
||||||
$address = trim((string)$address);
|
$address = trim((string)$address);
|
||||||
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
|
$name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
|
||||||
//Don't validate now addresses with IDN. Will be done in send().
|
//Don't validate now addresses with IDN. Will be done in send().
|
||||||
@@ -1396,7 +1345,7 @@ class PHPMailer
|
|||||||
) {
|
) {
|
||||||
$error_message = sprintf(
|
$error_message = sprintf(
|
||||||
'%s (From): %s',
|
'%s (From): %s',
|
||||||
self::lang('invalid_address'),
|
$this->lang('invalid_address'),
|
||||||
$address
|
$address
|
||||||
);
|
);
|
||||||
$this->setError($error_message);
|
$this->setError($error_message);
|
||||||
@@ -1652,7 +1601,7 @@ class PHPMailer
|
|||||||
&& ini_get('mail.add_x_header') === '1'
|
&& ini_get('mail.add_x_header') === '1'
|
||||||
&& stripos(PHP_OS, 'WIN') === 0
|
&& stripos(PHP_OS, 'WIN') === 0
|
||||||
) {
|
) {
|
||||||
trigger_error(self::lang('buggy_php'), E_USER_WARNING);
|
trigger_error($this->lang('buggy_php'), E_USER_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1682,7 +1631,7 @@ class PHPMailer
|
|||||||
call_user_func_array([$this, 'addAnAddress'], $params);
|
call_user_func_array([$this, 'addAnAddress'], $params);
|
||||||
}
|
}
|
||||||
if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
|
if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
|
||||||
throw new Exception(self::lang('provide_address'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('provide_address'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Validate From, Sender, and ConfirmReadingTo addresses
|
//Validate From, Sender, and ConfirmReadingTo addresses
|
||||||
@@ -1699,7 +1648,7 @@ class PHPMailer
|
|||||||
if (!static::validateAddress($this->{$address_kind})) {
|
if (!static::validateAddress($this->{$address_kind})) {
|
||||||
$error_message = sprintf(
|
$error_message = sprintf(
|
||||||
'%s (%s): %s',
|
'%s (%s): %s',
|
||||||
self::lang('invalid_address'),
|
$this->lang('invalid_address'),
|
||||||
$address_kind,
|
$address_kind,
|
||||||
$this->{$address_kind}
|
$this->{$address_kind}
|
||||||
);
|
);
|
||||||
@@ -1721,7 +1670,7 @@ class PHPMailer
|
|||||||
$this->setMessageType();
|
$this->setMessageType();
|
||||||
//Refuse to send an empty message unless we are specifically allowing it
|
//Refuse to send an empty message unless we are specifically allowing it
|
||||||
if (!$this->AllowEmpty && empty($this->Body)) {
|
if (!$this->AllowEmpty && empty($this->Body)) {
|
||||||
throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Trim subject consistently
|
//Trim subject consistently
|
||||||
@@ -1860,10 +1809,8 @@ class PHPMailer
|
|||||||
} else {
|
} else {
|
||||||
$sendmailFmt = '%s -oi -f%s -t';
|
$sendmailFmt = '%s -oi -f%s -t';
|
||||||
}
|
}
|
||||||
} elseif ($this->Mailer === 'qmail') {
|
|
||||||
$sendmailFmt = '%s';
|
|
||||||
} else {
|
} else {
|
||||||
//Allow sendmail to choose a default envelope sender. It may
|
//allow sendmail to choose a default envelope sender. It may
|
||||||
//seem preferable to force it to use the From header as with
|
//seem preferable to force it to use the From header as with
|
||||||
//SMTP, but that introduces new problems (see
|
//SMTP, but that introduces new problems (see
|
||||||
//<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
|
//<https://github.com/PHPMailer/PHPMailer/issues/2298>), and
|
||||||
@@ -1881,35 +1828,33 @@ class PHPMailer
|
|||||||
foreach ($this->SingleToArray as $toAddr) {
|
foreach ($this->SingleToArray as $toAddr) {
|
||||||
$mail = @popen($sendmail, 'w');
|
$mail = @popen($sendmail, 'w');
|
||||||
if (!$mail) {
|
if (!$mail) {
|
||||||
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
$this->edebug("To: {$toAddr}");
|
$this->edebug("To: {$toAddr}");
|
||||||
fwrite($mail, 'To: ' . $toAddr . "\n");
|
fwrite($mail, 'To: ' . $toAddr . "\n");
|
||||||
fwrite($mail, $header);
|
fwrite($mail, $header);
|
||||||
fwrite($mail, $body);
|
fwrite($mail, $body);
|
||||||
$result = pclose($mail);
|
$result = pclose($mail);
|
||||||
$addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
|
$addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
|
||||||
foreach ($addrinfo as $addr) {
|
$this->doCallback(
|
||||||
$this->doCallback(
|
($result === 0),
|
||||||
($result === 0),
|
[[$addrinfo['address'], $addrinfo['name']]],
|
||||||
[[$addr['address'], $addr['name']]],
|
$this->cc,
|
||||||
$this->cc,
|
$this->bcc,
|
||||||
$this->bcc,
|
$this->Subject,
|
||||||
$this->Subject,
|
$body,
|
||||||
$body,
|
$this->From,
|
||||||
$this->From,
|
[]
|
||||||
[]
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
|
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
|
||||||
if (0 !== $result) {
|
if (0 !== $result) {
|
||||||
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$mail = @popen($sendmail, 'w');
|
$mail = @popen($sendmail, 'w');
|
||||||
if (!$mail) {
|
if (!$mail) {
|
||||||
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
fwrite($mail, $header);
|
fwrite($mail, $header);
|
||||||
fwrite($mail, $body);
|
fwrite($mail, $body);
|
||||||
@@ -1926,7 +1871,7 @@ class PHPMailer
|
|||||||
);
|
);
|
||||||
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
|
$this->edebug("Result: " . ($result === 0 ? 'true' : 'false'));
|
||||||
if (0 !== $result) {
|
if (0 !== $result) {
|
||||||
throw new Exception(self::lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
throw new Exception($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2065,19 +2010,17 @@ class PHPMailer
|
|||||||
if ($this->SingleTo && count($toArr) > 1) {
|
if ($this->SingleTo && count($toArr) > 1) {
|
||||||
foreach ($toArr as $toAddr) {
|
foreach ($toArr as $toAddr) {
|
||||||
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
|
$result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
|
||||||
$addrinfo = static::parseAddresses($toAddr, null, $this->CharSet);
|
$addrinfo = static::parseAddresses($toAddr, true, $this->CharSet);
|
||||||
foreach ($addrinfo as $addr) {
|
$this->doCallback(
|
||||||
$this->doCallback(
|
$result,
|
||||||
$result,
|
[[$addrinfo['address'], $addrinfo['name']]],
|
||||||
[[$addr['address'], $addr['name']]],
|
$this->cc,
|
||||||
$this->cc,
|
$this->bcc,
|
||||||
$this->bcc,
|
$this->Subject,
|
||||||
$this->Subject,
|
$body,
|
||||||
$body,
|
$this->From,
|
||||||
$this->From,
|
[]
|
||||||
[]
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
|
$result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
|
||||||
@@ -2087,7 +2030,7 @@ class PHPMailer
|
|||||||
ini_set('sendmail_from', $old_from);
|
ini_set('sendmail_from', $old_from);
|
||||||
}
|
}
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
throw new Exception(self::lang('instantiate'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('instantiate'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2173,12 +2116,12 @@ class PHPMailer
|
|||||||
$header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
|
$header = static::stripTrailingWSP($header) . static::$LE . static::$LE;
|
||||||
$bad_rcpt = [];
|
$bad_rcpt = [];
|
||||||
if (!$this->smtpConnect($this->SMTPOptions)) {
|
if (!$this->smtpConnect($this->SMTPOptions)) {
|
||||||
throw new Exception(self::lang('smtp_connect_failed'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
//If we have recipient addresses that need Unicode support,
|
//If we have recipient addresses that need Unicode support,
|
||||||
//but the server doesn't support it, stop here
|
//but the server doesn't support it, stop here
|
||||||
if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) {
|
if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) {
|
||||||
throw new Exception(self::lang('no_smtputf8'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
//Sender already validated in preSend()
|
//Sender already validated in preSend()
|
||||||
if ('' === $this->Sender) {
|
if ('' === $this->Sender) {
|
||||||
@@ -2190,7 +2133,7 @@ class PHPMailer
|
|||||||
$this->smtp->xclient($this->SMTPXClient);
|
$this->smtp->xclient($this->SMTPXClient);
|
||||||
}
|
}
|
||||||
if (!$this->smtp->mail($smtp_from)) {
|
if (!$this->smtp->mail($smtp_from)) {
|
||||||
$this->setError(self::lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
|
$this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
|
||||||
throw new Exception($this->ErrorInfo, self::STOP_CRITICAL);
|
throw new Exception($this->ErrorInfo, self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2212,7 +2155,7 @@ class PHPMailer
|
|||||||
|
|
||||||
//Only send the DATA command if we have viable recipients
|
//Only send the DATA command if we have viable recipients
|
||||||
if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
|
if ((count($this->all_recipients) > count($bad_rcpt)) && !$this->smtp->data($header . $body)) {
|
||||||
throw new Exception(self::lang('data_not_accepted'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('data_not_accepted'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$smtp_transaction_id = $this->smtp->getLastTransactionID();
|
$smtp_transaction_id = $this->smtp->getLastTransactionID();
|
||||||
@@ -2243,7 +2186,7 @@ class PHPMailer
|
|||||||
foreach ($bad_rcpt as $bad) {
|
foreach ($bad_rcpt as $bad) {
|
||||||
$errstr .= $bad['to'] . ': ' . $bad['error'];
|
$errstr .= $bad['to'] . ': ' . $bad['error'];
|
||||||
}
|
}
|
||||||
throw new Exception(self::lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
|
throw new Exception($this->lang('recipients_failed') . $errstr, self::STOP_CONTINUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2297,7 +2240,7 @@ class PHPMailer
|
|||||||
$hostinfo
|
$hostinfo
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
$this->edebug(self::lang('invalid_hostentry') . ' ' . trim($hostentry));
|
$this->edebug($this->lang('invalid_hostentry') . ' ' . trim($hostentry));
|
||||||
//Not a valid host entry
|
//Not a valid host entry
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2309,7 +2252,7 @@ class PHPMailer
|
|||||||
|
|
||||||
//Check the host name is a valid name or IP address before trying to use it
|
//Check the host name is a valid name or IP address before trying to use it
|
||||||
if (!static::isValidHost($hostinfo[2])) {
|
if (!static::isValidHost($hostinfo[2])) {
|
||||||
$this->edebug(self::lang('invalid_host') . ' ' . $hostinfo[2]);
|
$this->edebug($this->lang('invalid_host') . ' ' . $hostinfo[2]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$prefix = '';
|
$prefix = '';
|
||||||
@@ -2329,7 +2272,7 @@ class PHPMailer
|
|||||||
if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) {
|
if (static::ENCRYPTION_STARTTLS === $secure || static::ENCRYPTION_SMTPS === $secure) {
|
||||||
//Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
|
//Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
|
||||||
if (!$sslext) {
|
if (!$sslext) {
|
||||||
throw new Exception(self::lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
|
throw new Exception($this->lang('extension_missing') . 'openssl', self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$host = $hostinfo[2];
|
$host = $hostinfo[2];
|
||||||
@@ -2381,7 +2324,7 @@ class PHPMailer
|
|||||||
$this->oauth
|
$this->oauth
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
throw new Exception(self::lang('authenticate'));
|
throw new Exception($this->lang('authenticate'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -2431,7 +2374,7 @@ class PHPMailer
|
|||||||
*
|
*
|
||||||
* @return bool Returns true if the requested language was loaded, false otherwise.
|
* @return bool Returns true if the requested language was loaded, false otherwise.
|
||||||
*/
|
*/
|
||||||
public static function setLanguage($langcode = 'en', $lang_path = '')
|
public function setLanguage($langcode = 'en', $lang_path = '')
|
||||||
{
|
{
|
||||||
//Backwards compatibility for renamed language codes
|
//Backwards compatibility for renamed language codes
|
||||||
$renamed_langcodes = [
|
$renamed_langcodes = [
|
||||||
@@ -2480,9 +2423,6 @@ class PHPMailer
|
|||||||
'smtp_error' => 'SMTP server error: ',
|
'smtp_error' => 'SMTP server error: ',
|
||||||
'variable_set' => 'Cannot set or reset variable: ',
|
'variable_set' => 'Cannot set or reset variable: ',
|
||||||
'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
|
'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
|
||||||
'imap_recommended' => 'Using simplified address parser is not recommended. ' .
|
|
||||||
'Install the PHP IMAP extension for full RFC822 parsing.',
|
|
||||||
'deprecated_argument' => 'Argument $useimap is deprecated',
|
|
||||||
];
|
];
|
||||||
if (empty($lang_path)) {
|
if (empty($lang_path)) {
|
||||||
//Calculate an absolute path so it can work if CWD is not here
|
//Calculate an absolute path so it can work if CWD is not here
|
||||||
@@ -2549,7 +2489,7 @@ class PHPMailer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self::$language = $PHPMAILER_LANG;
|
$this->language = $PHPMAILER_LANG;
|
||||||
|
|
||||||
return $foundlang; //Returns false if language not found
|
return $foundlang; //Returns false if language not found
|
||||||
}
|
}
|
||||||
@@ -2561,11 +2501,11 @@ class PHPMailer
|
|||||||
*/
|
*/
|
||||||
public function getTranslations()
|
public function getTranslations()
|
||||||
{
|
{
|
||||||
if (empty(self::$language)) {
|
if (empty($this->language)) {
|
||||||
self::setLanguage(); // Set the default language.
|
$this->setLanguage(); // Set the default language.
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$language;
|
return $this->language;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2988,6 +2928,10 @@ class PHPMailer
|
|||||||
//Create unique IDs and preset boundaries
|
//Create unique IDs and preset boundaries
|
||||||
$this->setBoundaries();
|
$this->setBoundaries();
|
||||||
|
|
||||||
|
if ($this->sign_key_file) {
|
||||||
|
$body .= $this->getMailMIME() . static::$LE;
|
||||||
|
}
|
||||||
|
|
||||||
$this->setWordWrap();
|
$this->setWordWrap();
|
||||||
|
|
||||||
$bodyEncoding = $this->Encoding;
|
$bodyEncoding = $this->Encoding;
|
||||||
@@ -3019,12 +2963,6 @@ class PHPMailer
|
|||||||
if (static::ENCODING_BASE64 !== $altBodyEncoding && static::hasLineLongerThanMax($this->AltBody)) {
|
if (static::ENCODING_BASE64 !== $altBodyEncoding && static::hasLineLongerThanMax($this->AltBody)) {
|
||||||
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
|
$altBodyEncoding = static::ENCODING_QUOTED_PRINTABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->sign_key_file) {
|
|
||||||
$this->Encoding = $bodyEncoding;
|
|
||||||
$body .= $this->getMailMIME() . static::$LE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Use this as a preamble in all multipart message types
|
//Use this as a preamble in all multipart message types
|
||||||
$mimepre = '';
|
$mimepre = '';
|
||||||
switch ($this->message_type) {
|
switch ($this->message_type) {
|
||||||
@@ -3206,12 +3144,12 @@ class PHPMailer
|
|||||||
if ($this->isError()) {
|
if ($this->isError()) {
|
||||||
$body = '';
|
$body = '';
|
||||||
if ($this->exceptions) {
|
if ($this->exceptions) {
|
||||||
throw new Exception(self::lang('empty_message'), self::STOP_CRITICAL);
|
throw new Exception($this->lang('empty_message'), self::STOP_CRITICAL);
|
||||||
}
|
}
|
||||||
} elseif ($this->sign_key_file) {
|
} elseif ($this->sign_key_file) {
|
||||||
try {
|
try {
|
||||||
if (!defined('PKCS7_TEXT')) {
|
if (!defined('PKCS7_TEXT')) {
|
||||||
throw new Exception(self::lang('extension_missing') . 'openssl');
|
throw new Exception($this->lang('extension_missing') . 'openssl');
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = tempnam(sys_get_temp_dir(), 'srcsign');
|
$file = tempnam(sys_get_temp_dir(), 'srcsign');
|
||||||
@@ -3249,7 +3187,7 @@ class PHPMailer
|
|||||||
$body = $parts[1];
|
$body = $parts[1];
|
||||||
} else {
|
} else {
|
||||||
@unlink($signed);
|
@unlink($signed);
|
||||||
throw new Exception(self::lang('signing') . openssl_error_string());
|
throw new Exception($this->lang('signing') . openssl_error_string());
|
||||||
}
|
}
|
||||||
} catch (Exception $exc) {
|
} catch (Exception $exc) {
|
||||||
$body = '';
|
$body = '';
|
||||||
@@ -3394,7 +3332,7 @@ class PHPMailer
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
if (!static::fileIsAccessible($path)) {
|
if (!static::fileIsAccessible($path)) {
|
||||||
throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
|
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If a MIME type is not specified, try to work it out from the file name
|
//If a MIME type is not specified, try to work it out from the file name
|
||||||
@@ -3407,7 +3345,7 @@ class PHPMailer
|
|||||||
$name = $filename;
|
$name = $filename;
|
||||||
}
|
}
|
||||||
if (!$this->validateEncoding($encoding)) {
|
if (!$this->validateEncoding($encoding)) {
|
||||||
throw new Exception(self::lang('encoding') . $encoding);
|
throw new Exception($this->lang('encoding') . $encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->attachment[] = [
|
$this->attachment[] = [
|
||||||
@@ -3568,11 +3506,11 @@ class PHPMailer
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (!static::fileIsAccessible($path)) {
|
if (!static::fileIsAccessible($path)) {
|
||||||
throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
|
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
|
||||||
}
|
}
|
||||||
$file_buffer = file_get_contents($path);
|
$file_buffer = file_get_contents($path);
|
||||||
if (false === $file_buffer) {
|
if (false === $file_buffer) {
|
||||||
throw new Exception(self::lang('file_open') . $path, self::STOP_CONTINUE);
|
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
|
||||||
}
|
}
|
||||||
$file_buffer = $this->encodeString($file_buffer, $encoding);
|
$file_buffer = $this->encodeString($file_buffer, $encoding);
|
||||||
|
|
||||||
@@ -3625,9 +3563,9 @@ class PHPMailer
|
|||||||
$encoded = $this->encodeQP($str);
|
$encoded = $this->encodeQP($str);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$this->setError(self::lang('encoding') . $encoding);
|
$this->setError($this->lang('encoding') . $encoding);
|
||||||
if ($this->exceptions) {
|
if ($this->exceptions) {
|
||||||
throw new Exception(self::lang('encoding') . $encoding);
|
throw new Exception($this->lang('encoding') . $encoding);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3733,42 +3671,6 @@ class PHPMailer
|
|||||||
return trim(static::normalizeBreaks($encoded));
|
return trim(static::normalizeBreaks($encoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode an RFC2047-encoded header value
|
|
||||||
* Attempts multiple strategies so it works even when the mbstring extension is disabled.
|
|
||||||
*
|
|
||||||
* @param string $value The header value to decode
|
|
||||||
* @param string $charset The target charset to convert to, defaults to ISO-8859-1 for BC
|
|
||||||
*
|
|
||||||
* @return string The decoded header value
|
|
||||||
*/
|
|
||||||
public static function decodeHeader($value, $charset = self::CHARSET_ISO88591)
|
|
||||||
{
|
|
||||||
if (!is_string($value) || $value === '') {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
// Detect the presence of any RFC2047 encoded-words
|
|
||||||
$hasEncodedWord = (bool) preg_match('/=\?.*\?=/s', $value);
|
|
||||||
if ($hasEncodedWord && defined('MB_CASE_UPPER')) {
|
|
||||||
$origCharset = mb_internal_encoding();
|
|
||||||
// Always decode to UTF-8 to provide a consistent, modern output encoding.
|
|
||||||
mb_internal_encoding($charset);
|
|
||||||
if (PHP_VERSION_ID < 80300) {
|
|
||||||
// Undo any RFC2047-encoded spaces-as-underscores.
|
|
||||||
$value = str_replace('_', '=20', $value);
|
|
||||||
} else {
|
|
||||||
// PHP 8.3+ already interprets underscores as spaces. Remove additional
|
|
||||||
// linear whitespace between adjacent encoded words to avoid double spacing.
|
|
||||||
$value = preg_replace('/(\?=)\s+(=\?)/', '$1$2', $value);
|
|
||||||
}
|
|
||||||
// Decode the header value
|
|
||||||
$value = mb_decode_mimeheader($value);
|
|
||||||
mb_internal_encoding($origCharset);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a string contains multi-byte characters.
|
* Check if a string contains multi-byte characters.
|
||||||
*
|
*
|
||||||
@@ -3938,7 +3840,7 @@ class PHPMailer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->validateEncoding($encoding)) {
|
if (!$this->validateEncoding($encoding)) {
|
||||||
throw new Exception(self::lang('encoding') . $encoding);
|
throw new Exception($this->lang('encoding') . $encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Append to $attachment array
|
//Append to $attachment array
|
||||||
@@ -3997,7 +3899,7 @@ class PHPMailer
|
|||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
if (!static::fileIsAccessible($path)) {
|
if (!static::fileIsAccessible($path)) {
|
||||||
throw new Exception(self::lang('file_access') . $path, self::STOP_CONTINUE);
|
throw new Exception($this->lang('file_access') . $path, self::STOP_CONTINUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
//If a MIME type is not specified, try to work it out from the file name
|
//If a MIME type is not specified, try to work it out from the file name
|
||||||
@@ -4006,7 +3908,7 @@ class PHPMailer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->validateEncoding($encoding)) {
|
if (!$this->validateEncoding($encoding)) {
|
||||||
throw new Exception(self::lang('encoding') . $encoding);
|
throw new Exception($this->lang('encoding') . $encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME);
|
$filename = (string) static::mb_pathinfo($path, PATHINFO_BASENAME);
|
||||||
@@ -4072,7 +3974,7 @@ class PHPMailer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->validateEncoding($encoding)) {
|
if (!$this->validateEncoding($encoding)) {
|
||||||
throw new Exception(self::lang('encoding') . $encoding);
|
throw new Exception($this->lang('encoding') . $encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Append to $attachment array
|
//Append to $attachment array
|
||||||
@@ -4329,7 +4231,7 @@ class PHPMailer
|
|||||||
}
|
}
|
||||||
if (strpbrk($name . $value, "\r\n") !== false) {
|
if (strpbrk($name . $value, "\r\n") !== false) {
|
||||||
if ($this->exceptions) {
|
if ($this->exceptions) {
|
||||||
throw new Exception(self::lang('invalid_header'));
|
throw new Exception($this->lang('invalid_header'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -4353,15 +4255,15 @@ class PHPMailer
|
|||||||
if ('smtp' === $this->Mailer && null !== $this->smtp) {
|
if ('smtp' === $this->Mailer && null !== $this->smtp) {
|
||||||
$lasterror = $this->smtp->getError();
|
$lasterror = $this->smtp->getError();
|
||||||
if (!empty($lasterror['error'])) {
|
if (!empty($lasterror['error'])) {
|
||||||
$msg .= ' ' . self::lang('smtp_error') . $lasterror['error'];
|
$msg .= ' ' . $this->lang('smtp_error') . $lasterror['error'];
|
||||||
if (!empty($lasterror['detail'])) {
|
if (!empty($lasterror['detail'])) {
|
||||||
$msg .= ' ' . self::lang('smtp_detail') . $lasterror['detail'];
|
$msg .= ' ' . $this->lang('smtp_detail') . $lasterror['detail'];
|
||||||
}
|
}
|
||||||
if (!empty($lasterror['smtp_code'])) {
|
if (!empty($lasterror['smtp_code'])) {
|
||||||
$msg .= ' ' . self::lang('smtp_code') . $lasterror['smtp_code'];
|
$msg .= ' ' . $this->lang('smtp_code') . $lasterror['smtp_code'];
|
||||||
}
|
}
|
||||||
if (!empty($lasterror['smtp_code_ex'])) {
|
if (!empty($lasterror['smtp_code_ex'])) {
|
||||||
$msg .= ' ' . self::lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
|
$msg .= ' ' . $this->lang('smtp_code_ex') . $lasterror['smtp_code_ex'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4486,21 +4388,21 @@ class PHPMailer
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected static function lang($key)
|
protected function lang($key)
|
||||||
{
|
{
|
||||||
if (count(self::$language) < 1) {
|
if (count($this->language) < 1) {
|
||||||
self::setLanguage(); //Set the default language
|
$this->setLanguage(); //Set the default language
|
||||||
}
|
}
|
||||||
|
|
||||||
if (array_key_exists($key, self::$language)) {
|
if (array_key_exists($key, $this->language)) {
|
||||||
if ('smtp_connect_failed' === $key) {
|
if ('smtp_connect_failed' === $key) {
|
||||||
//Include a link to troubleshooting docs on SMTP connection failure.
|
//Include a link to troubleshooting docs on SMTP connection failure.
|
||||||
//This is by far the biggest cause of support questions
|
//This is by far the biggest cause of support questions
|
||||||
//but it's usually not PHPMailer's fault.
|
//but it's usually not PHPMailer's fault.
|
||||||
return self::$language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
|
return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$language[$key];
|
return $this->language[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return the key as a fallback
|
//Return the key as a fallback
|
||||||
@@ -4515,7 +4417,7 @@ class PHPMailer
|
|||||||
*/
|
*/
|
||||||
private function getSmtpErrorMessage($base_key)
|
private function getSmtpErrorMessage($base_key)
|
||||||
{
|
{
|
||||||
$message = self::lang($base_key);
|
$message = $this->lang($base_key);
|
||||||
$error = $this->smtp->getError();
|
$error = $this->smtp->getError();
|
||||||
if (!empty($error['error'])) {
|
if (!empty($error['error'])) {
|
||||||
$message .= ' ' . $error['error'];
|
$message .= ' ' . $error['error'];
|
||||||
@@ -4559,7 +4461,7 @@ class PHPMailer
|
|||||||
//Ensure name is not empty, and that neither name nor value contain line breaks
|
//Ensure name is not empty, and that neither name nor value contain line breaks
|
||||||
if (empty($name) || strpbrk($name . $value, "\r\n") !== false) {
|
if (empty($name) || strpbrk($name . $value, "\r\n") !== false) {
|
||||||
if ($this->exceptions) {
|
if ($this->exceptions) {
|
||||||
throw new Exception(self::lang('invalid_header'));
|
throw new Exception($this->lang('invalid_header'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -4952,7 +4854,7 @@ class PHPMailer
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$this->setError(self::lang('variable_set') . $name);
|
$this->setError($this->lang('variable_set') . $name);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -5090,7 +4992,7 @@ class PHPMailer
|
|||||||
{
|
{
|
||||||
if (!defined('PKCS7_TEXT')) {
|
if (!defined('PKCS7_TEXT')) {
|
||||||
if ($this->exceptions) {
|
if ($this->exceptions) {
|
||||||
throw new Exception(self::lang('extension_missing') . 'openssl');
|
throw new Exception($this->lang('extension_missing') . 'openssl');
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return '';
|
||||||
|
|||||||
2
vendor/phpmailer/phpmailer/src/POP3.php
vendored
2
vendor/phpmailer/phpmailer/src/POP3.php
vendored
@@ -46,7 +46,7 @@ class POP3
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const VERSION = '6.11.1';
|
const VERSION = '6.12.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default POP3 port number.
|
* Default POP3 port number.
|
||||||
|
|||||||
53
vendor/phpmailer/phpmailer/src/SMTP.php
vendored
53
vendor/phpmailer/phpmailer/src/SMTP.php
vendored
@@ -35,7 +35,7 @@ class SMTP
|
|||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const VERSION = '6.11.1';
|
const VERSION = '6.12.0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SMTP line break constant.
|
* SMTP line break constant.
|
||||||
@@ -205,7 +205,6 @@ class SMTP
|
|||||||
'Haraka' => '/[\d]{3} Message Queued \((.*)\)/',
|
'Haraka' => '/[\d]{3} Message Queued \((.*)\)/',
|
||||||
'ZoneMTA' => '/[\d]{3} Message queued as (.*)/',
|
'ZoneMTA' => '/[\d]{3} Message queued as (.*)/',
|
||||||
'Mailjet' => '/[\d]{3} OK queued as (.*)/',
|
'Mailjet' => '/[\d]{3} OK queued as (.*)/',
|
||||||
'Gsmtp' => '/[\d]{3} 2\.0\.0 OK (.*) - gsmtp/',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -634,41 +633,10 @@ class SMTP
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$oauth = $OAuth->getOauth64();
|
$oauth = $OAuth->getOauth64();
|
||||||
/*
|
|
||||||
* An SMTP command line can have a maximum length of 512 bytes, including the command name,
|
//Start authentication
|
||||||
* so the base64-encoded OAUTH token has a maximum length of:
|
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
|
||||||
* 512 - 13 (AUTH XOAUTH2) - 2 (CRLF) = 497 bytes
|
return false;
|
||||||
* If the token is longer than that, the command and the token must be sent separately as described in
|
|
||||||
* https://www.rfc-editor.org/rfc/rfc4954#section-4
|
|
||||||
*/
|
|
||||||
if ($oauth === '') {
|
|
||||||
//Sending an empty auth token is legitimate, but it must be encoded as '='
|
|
||||||
//to indicate it's not a 2-part command
|
|
||||||
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 =', 235)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} elseif (strlen($oauth) <= 497) {
|
|
||||||
//Authenticate using a token in the initial-response part
|
|
||||||
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//The token is too long, so we need to send it in two parts.
|
|
||||||
//Send the auth command without a token and expect a 334
|
|
||||||
if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2', 334)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//Send the token
|
|
||||||
if (!$this->sendCommand('OAuth TOKEN', $oauth, [235, 334])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//If the server answers with 334, send an empty line and wait for a 235
|
|
||||||
if (
|
|
||||||
substr($this->last_reply, 0, 3) === '334'
|
|
||||||
&& $this->sendCommand('AUTH End', '', 235)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1341,16 +1309,7 @@ class SMTP
|
|||||||
|
|
||||||
//stream_select returns false when the `select` system call is interrupted
|
//stream_select returns false when the `select` system call is interrupted
|
||||||
//by an incoming signal, try the select again
|
//by an incoming signal, try the select again
|
||||||
if (
|
if (stripos($message, 'interrupted system call') !== false) {
|
||||||
stripos($message, 'interrupted system call') !== false ||
|
|
||||||
(
|
|
||||||
// on applications with a different locale than english, the message above is not found because
|
|
||||||
// it's translated. So we also check for the SOCKET_EINTR constant which is defined under
|
|
||||||
// Windows and UNIX-like platforms (if available on the platform).
|
|
||||||
defined('SOCKET_EINTR') &&
|
|
||||||
stripos($message, 'stream_select(): Unable to select [' . SOCKET_EINTR . ']') !== false
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
$this->edebug(
|
$this->edebug(
|
||||||
'SMTP -> get_lines(): retrying stream_select',
|
'SMTP -> get_lines(): retrying stream_select',
|
||||||
self::DEBUG_LOWLEVEL
|
self::DEBUG_LOWLEVEL
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ jobs:
|
|||||||
- '8.1'
|
- '8.1'
|
||||||
- '8.2'
|
- '8.2'
|
||||||
- '8.3'
|
- '8.3'
|
||||||
|
- '8.4'
|
||||||
steps:
|
steps:
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
@@ -75,6 +76,7 @@ jobs:
|
|||||||
- '8.1'
|
- '8.1'
|
||||||
- '8.2'
|
- '8.2'
|
||||||
- '8.3'
|
- '8.3'
|
||||||
|
- '8.4'
|
||||||
steps:
|
steps:
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
|
|||||||
2
vendor/phpoffice/math/docs/index.md
vendored
2
vendor/phpoffice/math/docs/index.md
vendored
@@ -48,7 +48,7 @@ Math is an open source project licensed under the terms of [MIT](https://github.
|
|||||||
| **Simple** | Fraction | :material-check: | :material-check: |
|
| **Simple** | Fraction | :material-check: | :material-check: |
|
||||||
| | Superscript | :material-check: | |
|
| | Superscript | :material-check: | |
|
||||||
| **Architectural** | Row | :material-check: | :material-check: |
|
| **Architectural** | Row | :material-check: | :material-check: |
|
||||||
| | Semantics | | |
|
| | Semantics | :material-check: | |
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
4
vendor/phpoffice/math/mkdocs.yml
vendored
4
vendor/phpoffice/math/mkdocs.yml
vendored
@@ -57,7 +57,9 @@ nav:
|
|||||||
- Writers: 'usage/writers.md'
|
- Writers: 'usage/writers.md'
|
||||||
- Credits: 'credits.md'
|
- Credits: 'credits.md'
|
||||||
- Releases:
|
- Releases:
|
||||||
- '0.1.0 (WIP)': 'changes/0.1.0.md'
|
- '0.3.0 (WIP)': 'changes/0.3.0.md'
|
||||||
|
- '0.2.0': 'changes/0.2.0.md'
|
||||||
|
- '0.1.0': 'changes/0.1.0.md'
|
||||||
- Developers:
|
- Developers:
|
||||||
- 'Coveralls': 'https://coveralls.io/github/PHPOffice/Math'
|
- 'Coveralls': 'https://coveralls.io/github/PHPOffice/Math'
|
||||||
- 'Code Coverage': 'coverage/index.html'
|
- 'Code Coverage': 'coverage/index.html'
|
||||||
|
|||||||
12
vendor/phpoffice/math/src/Math/Reader/MathML.php
vendored
12
vendor/phpoffice/math/src/Math/Reader/MathML.php
vendored
@@ -10,6 +10,7 @@ use PhpOffice\Math\Element;
|
|||||||
use PhpOffice\Math\Exception\InvalidInputException;
|
use PhpOffice\Math\Exception\InvalidInputException;
|
||||||
use PhpOffice\Math\Exception\NotImplementedException;
|
use PhpOffice\Math\Exception\NotImplementedException;
|
||||||
use PhpOffice\Math\Math;
|
use PhpOffice\Math\Math;
|
||||||
|
use PhpOffice\Math\Reader\Security\XmlScanner;
|
||||||
|
|
||||||
class MathML implements ReaderInterface
|
class MathML implements ReaderInterface
|
||||||
{
|
{
|
||||||
@@ -22,8 +23,17 @@ class MathML implements ReaderInterface
|
|||||||
/** @var DOMXPath */
|
/** @var DOMXPath */
|
||||||
private $xpath;
|
private $xpath;
|
||||||
|
|
||||||
|
/** @var XmlScanner */
|
||||||
|
private $xmlScanner;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->xmlScanner = XmlScanner::getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
public function read(string $content): ?Math
|
public function read(string $content): ?Math
|
||||||
{
|
{
|
||||||
|
$content = $this->xmlScanner->scan($content);
|
||||||
$content = str_replace(
|
$content = str_replace(
|
||||||
[
|
[
|
||||||
'⁢',
|
'⁢',
|
||||||
@@ -35,7 +45,7 @@ class MathML implements ReaderInterface
|
|||||||
);
|
);
|
||||||
|
|
||||||
$this->dom = new DOMDocument();
|
$this->dom = new DOMDocument();
|
||||||
$this->dom->loadXML($content, LIBXML_DTDLOAD);
|
$this->dom->loadXML($content);
|
||||||
|
|
||||||
$this->math = new Math();
|
$this->math = new Math();
|
||||||
$this->parseNode(null, $this->math);
|
$this->parseNode(null, $this->math);
|
||||||
|
|||||||
23
vendor/phpoffice/math/src/Math/Writer/MathML.php
vendored
23
vendor/phpoffice/math/src/Math/Writer/MathML.php
vendored
@@ -40,6 +40,26 @@ class MathML implements WriterInterface
|
|||||||
{
|
{
|
||||||
$tagName = $this->getElementTagName($element);
|
$tagName = $this->getElementTagName($element);
|
||||||
|
|
||||||
|
// Element\AbstractGroupElement
|
||||||
|
if ($element instanceof Element\Semantics) {
|
||||||
|
$this->output->startElement($tagName);
|
||||||
|
// Write elements
|
||||||
|
foreach ($element->getElements() as $childElement) {
|
||||||
|
$this->writeElementItem($childElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write annotations
|
||||||
|
foreach ($element->getAnnotations() as $encoding => $annotation) {
|
||||||
|
$this->output->startElement('annotation');
|
||||||
|
$this->output->writeAttribute('encoding', $encoding);
|
||||||
|
$this->output->text($annotation);
|
||||||
|
$this->output->endElement();
|
||||||
|
}
|
||||||
|
$this->output->endElement();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Element\AbstractGroupElement
|
// Element\AbstractGroupElement
|
||||||
if ($element instanceof Element\AbstractGroupElement) {
|
if ($element instanceof Element\AbstractGroupElement) {
|
||||||
$this->output->startElement($tagName);
|
$this->output->startElement($tagName);
|
||||||
@@ -121,6 +141,9 @@ class MathML implements WriterInterface
|
|||||||
if ($element instanceof Element\Operator) {
|
if ($element instanceof Element\Operator) {
|
||||||
return 'mo';
|
return 'mo';
|
||||||
}
|
}
|
||||||
|
if ($element instanceof Element\Semantics) {
|
||||||
|
return 'semantics';
|
||||||
|
}
|
||||||
|
|
||||||
throw new NotImplementedException(sprintf(
|
throw new NotImplementedException(sprintf(
|
||||||
'%s : The element of the class `%s` has no tag name',
|
'%s : The element of the class `%s` has no tag name',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Tests\PhpOffice\Math\Reader;
|
|||||||
use PhpOffice\Math\Element;
|
use PhpOffice\Math\Element;
|
||||||
use PhpOffice\Math\Exception\InvalidInputException;
|
use PhpOffice\Math\Exception\InvalidInputException;
|
||||||
use PhpOffice\Math\Exception\NotImplementedException;
|
use PhpOffice\Math\Exception\NotImplementedException;
|
||||||
|
use PhpOffice\Math\Exception\SecurityException;
|
||||||
use PhpOffice\Math\Math;
|
use PhpOffice\Math\Math;
|
||||||
use PhpOffice\Math\Reader\MathML;
|
use PhpOffice\Math\Reader\MathML;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
@@ -294,4 +295,15 @@ class MathMLTest extends TestCase
|
|||||||
$reader = new MathML();
|
$reader = new MathML();
|
||||||
$math = $reader->read($content);
|
$math = $reader->read($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testReadSecurity(): void
|
||||||
|
{
|
||||||
|
$this->expectException(SecurityException::class);
|
||||||
|
$this->expectExceptionMessage('Detected use of ENTITY in XML, loading aborted to prevent XXE/XEE attacks');
|
||||||
|
|
||||||
|
$content = '<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE x SYSTEM "php://filter/convert.base64-decode/zlib.inflate/resource=data:,7Ztdb9owFIbv%2bRVZJ9armNjOZ2k7QUaL%2bRYO2nqFUnBFNQaMptP272cnNFuTsBbSskg1iATZzvGxn/ccX3A4fdfoecS7UsrK1A98hV5Rr9FVjlaz1UmlcnM7D9i6MlkufrB1AK79O2bqKltMllMWt96KL6ADwci7sJ4Yu0vr9/tlwKbqan27CPzrOXvevFGrbRvOGIseaCa7TAxok1x44xahXzQEcdKPKZPevap3RZw920I0VscWGLlU1efPsy0c5cbV1AoI7ZuOMCZW12nkcP9Q2%2bQObBNmL6ajg8s6xJqmJTrq5NIArX6zVk8Zcwwt4fPuLvHnbeBSvpdIQ6g93MvUv3CHqKNrmtEW4EYmCr5gDT5QzyNWE4x6xO1/aqQmgMhGYgaVDFUnScKltbFnaJoKHRuHK0L1pIkuaYselMe9cPUqRmm5C51u00kkhy1S3aBougkl7e4d6RGaTYeSehdCjAG/O/p%2bYfKyQsoLmgdlmsFYQFDjh6GWJyGE0ZfMX08EZtwNTdAYud7nLcksnwppA2UnqpCzgyDo1QadAU3vLOQZ82EHMxAi0KVcq7rzas5xD6AQoeqkYkgk02abukkJ/z%2bNvkj%2bjUy16Ba5d/S8anhBLwt44EgGkoFkIBlIBpKBZCAZSAaSgWQgGUgGkoFkIBlIBpKBZCAZSAaSgWQgGUgGxWOwW2nF7kt%2by7/Kb3ag2GUTUgBvXAAxiKxt4Is3sB4WniVrOvhwzB0CXerg5GN9esGRQv7RgQdMmMO9sIwtc/sIJUOCsY4ee7f7FIWu2Si4euKan8wg58nFsEIXxYGntgZqMog3Z2FrgPhgyzIOlsmijowqwb0jyMqMoGEbarqdOpP/iqFISMkSVFG1Z5p8f3OK%2bxAZ7gClpgUPg70rq0T2RIkcup/0newQ7NbcUXv/DPl4LL/N7hdfn2dp07pmd8v79YSdVVgwqcyWd8HC/8aOzkunf6r%2b2c8bpSxK/6uPmlf%2br/nSnyrHcduH99iqKiz7HwLxTLMgEM0QWUDjb3ji8NdHPslZmV%2bqR%2bfH56Xyxni1VGbV0m8=" []><foo></foo>M';
|
||||||
|
|
||||||
|
$reader = new MathML();
|
||||||
|
$math = $reader->read($content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,35 @@ class MathMLTest extends WriterTestCase
|
|||||||
$this->assertIsSchemaMathMLValid($output);
|
$this->assertIsSchemaMathMLValid($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testWriteSemantics(): void
|
||||||
|
{
|
||||||
|
$opTimes = new Element\Operator('⁢');
|
||||||
|
|
||||||
|
$math = new Math();
|
||||||
|
|
||||||
|
$semantics = new Element\Semantics();
|
||||||
|
$semantics->add(new Element\Identifier('y'));
|
||||||
|
$semantics->addAnnotation('application/x-tex', ' y ');
|
||||||
|
|
||||||
|
$math->add($semantics);
|
||||||
|
|
||||||
|
$writer = new MathML();
|
||||||
|
$output = $writer->write($math);
|
||||||
|
|
||||||
|
$expected = '<?xml version="1.0" encoding="UTF-8"?>'
|
||||||
|
. PHP_EOL
|
||||||
|
. '<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">'
|
||||||
|
. '<math xmlns="http://www.w3.org/1998/Math/MathML">'
|
||||||
|
. '<semantics>'
|
||||||
|
. '<mi>y</mi>'
|
||||||
|
. '<annotation encoding="application/x-tex"> y </annotation>'
|
||||||
|
. '</semantics>'
|
||||||
|
. '</math>'
|
||||||
|
. PHP_EOL;
|
||||||
|
$this->assertEquals($expected, $output);
|
||||||
|
$this->assertIsSchemaMathMLValid($output);
|
||||||
|
}
|
||||||
|
|
||||||
public function testWriteNotImplemented(): void
|
public function testWriteNotImplemented(): void
|
||||||
{
|
{
|
||||||
$this->expectException(NotImplementedException::class);
|
$this->expectException(NotImplementedException::class);
|
||||||
|
|||||||
2
vendor/phpoffice/phpword/LICENSE
vendored
2
vendor/phpoffice/phpword/LICENSE
vendored
@@ -1,6 +1,6 @@
|
|||||||
PHPWord, a pure PHP library for reading and writing word processing documents.
|
PHPWord, a pure PHP library for reading and writing word processing documents.
|
||||||
|
|
||||||
Copyright (c) 2010-2016 PHPWord.
|
Copyright (c) 2010-2025 PHPWord.
|
||||||
|
|
||||||
PHPWord is free software: you can redistribute it and/or modify
|
PHPWord is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU Lesser General Public License version 3 as published by
|
it under the terms of the GNU Lesser General Public License version 3 as published by
|
||||||
|
|||||||
11
vendor/phpoffice/phpword/README.md
vendored
11
vendor/phpoffice/phpword/README.md
vendored
@@ -1,11 +1,11 @@
|
|||||||
# 
|
# 
|
||||||
|
|
||||||
[](https://packagist.org/packages/phpoffice/phpword)
|
[](https://packagist.org/packages/phpoffice/phpword)
|
||||||
[](https://coveralls.io/github/PHPOffice/PHPWord?branch=master)
|
[](https://coveralls.io/github/PHPOffice/PHPWord?branch=master)
|
||||||
[](https://packagist.org/packages/phpoffice/phpword)
|
[](https://packagist.org/packages/phpoffice/phpword)
|
||||||
[](https://packagist.org/packages/phpoffice/phpword)
|
[](https://packagist.org/packages/phpoffice/phpword)
|
||||||
[](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml)
|
|
||||||
[](https://gitter.im/PHPOffice/PHPWord)
|
Branch Master : [](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml)
|
||||||
|
|
||||||
PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF.
|
PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF.
|
||||||
|
|
||||||
@@ -81,7 +81,6 @@ The following is a basic usage example of the PHPWord library.
|
|||||||
|
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
require_once 'bootstrap.php';
|
|
||||||
|
|
||||||
// Creating the new document...
|
// Creating the new document...
|
||||||
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
$phpWord = new \PhpOffice\PhpWord\PhpWord();
|
||||||
|
|||||||
91
vendor/phpoffice/phpword/composer.json
vendored
91
vendor/phpoffice/phpword/composer.json
vendored
@@ -8,7 +8,7 @@
|
|||||||
],
|
],
|
||||||
"homepage": "https://phpoffice.github.io/PHPWord/",
|
"homepage": "https://phpoffice.github.io/PHPWord/",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0-only",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Mark Baker"
|
"name": "Mark Baker"
|
||||||
@@ -36,20 +36,67 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": [
|
"test": [
|
||||||
"phpunit --color=always"
|
"@php vendor/bin/phpunit --color=always"
|
||||||
],
|
],
|
||||||
"test-no-coverage": [
|
"test-no-coverage": [
|
||||||
"phpunit --color=always --no-coverage"
|
"@php vendor/bin/phpunit --color=always --no-coverage"
|
||||||
],
|
],
|
||||||
"check": [
|
"check": [
|
||||||
"php-cs-fixer fix --ansi --dry-run --diff",
|
"@php vendor/bin/php-cs-fixer fix --ansi --dry-run --diff",
|
||||||
"phpcs --report-width=200 --report-summary --report-full samples/ src/ tests/ --ignore=src/PhpWord/Shared/PCLZip --standard=PSR2 -n",
|
"@php vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php",
|
||||||
"phpmd src/,tests/ text ./phpmd.xml.dist --exclude pclzip.lib.php",
|
|
||||||
"@test-no-coverage",
|
"@test-no-coverage",
|
||||||
"phpstan analyse --ansi"
|
"@php vendor/bin/phpstan analyse --ansi"
|
||||||
],
|
],
|
||||||
"fix": [
|
"fix": [
|
||||||
"php-cs-fixer fix --ansi"
|
"@php vendor/bin/php-cs-fixer fix --ansi"
|
||||||
|
],
|
||||||
|
"samples": [
|
||||||
|
"php samples/Sample_01_SimpleText.php",
|
||||||
|
"php samples/Sample_02_TabStops.php",
|
||||||
|
"php samples/Sample_03_Sections.php",
|
||||||
|
"php samples/Sample_04_Textrun.php",
|
||||||
|
"php samples/Sample_05_Multicolumn.php",
|
||||||
|
"php samples/Sample_06_Footnote.php",
|
||||||
|
"php samples/Sample_07_TemplateCloneRow.php",
|
||||||
|
"php samples/Sample_08_ParagraphPagination.php",
|
||||||
|
"php samples/Sample_09_Tables.php",
|
||||||
|
"php samples/Sample_10_EastAsianFontStyle.php",
|
||||||
|
"php samples/Sample_11_ReadWord97.php",
|
||||||
|
"php samples/Sample_11_ReadWord2007.php",
|
||||||
|
"php samples/Sample_12_HeaderFooter.php",
|
||||||
|
"php samples/Sample_13_Images.php",
|
||||||
|
"php samples/Sample_14_ListItem.php",
|
||||||
|
"php samples/Sample_15_Link.php",
|
||||||
|
"php samples/Sample_16_Object.php",
|
||||||
|
"php samples/Sample_17_TitleTOC.php",
|
||||||
|
"php samples/Sample_18_Watermark.php",
|
||||||
|
"php samples/Sample_19_TextBreak.php",
|
||||||
|
"php samples/Sample_20_BGColor.php",
|
||||||
|
"php samples/Sample_21_TableRowRules.php",
|
||||||
|
"php samples/Sample_22_CheckBox.php",
|
||||||
|
"php samples/Sample_23_TemplateBlock.php",
|
||||||
|
"php samples/Sample_24_ReadODText.php",
|
||||||
|
"php samples/Sample_25_TextBox.php",
|
||||||
|
"php samples/Sample_26_Html.php",
|
||||||
|
"php samples/Sample_27_Field.php",
|
||||||
|
"php samples/Sample_28_ReadRTF.php",
|
||||||
|
"php samples/Sample_29_Line.php",
|
||||||
|
"php samples/Sample_30_ReadHTML.php",
|
||||||
|
"php samples/Sample_31_Shape.php",
|
||||||
|
"php samples/Sample_32_Chart.php",
|
||||||
|
"php samples/Sample_33_FormField.php",
|
||||||
|
"php samples/Sample_34_SDT.php",
|
||||||
|
"php samples/Sample_35_InternalLink.php",
|
||||||
|
"php samples/Sample_36_RTL.php",
|
||||||
|
"php samples/Sample_37_Comments.php",
|
||||||
|
"php samples/Sample_38_Protection.php",
|
||||||
|
"php samples/Sample_39_TrackChanges.php",
|
||||||
|
"php samples/Sample_40_TemplateSetComplexValue.php",
|
||||||
|
"php samples/Sample_41_TemplateSetChart.php",
|
||||||
|
"php samples/Sample_42_TemplateSetCheckbox.php",
|
||||||
|
"php samples/Sample_43_RTLDefault.php",
|
||||||
|
"php samples/Sample_44_ExtractVariablesFromReaderWord2007.php",
|
||||||
|
"php samples/Sample_45_Autoloader.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts-descriptions": {
|
"scripts-descriptions": {
|
||||||
@@ -58,34 +105,28 @@
|
|||||||
"check": "Runs PHP CheckStyle and PHP Mess detector",
|
"check": "Runs PHP CheckStyle and PHP Mess detector",
|
||||||
"fix": "Fixes issues found by PHP-CS"
|
"fix": "Fixes issues found by PHP-CS"
|
||||||
},
|
},
|
||||||
"config": {
|
|
||||||
"platform": {
|
|
||||||
"php": "8.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.1|^8.0",
|
"php": "^7.1|^8.0",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
|
"ext-gd": "*",
|
||||||
|
"ext-zip": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-xml": "*",
|
"ext-xml": "*",
|
||||||
"phpoffice/math": "^0.2"
|
"phpoffice/math": "^0.3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-zip": "*",
|
|
||||||
"ext-gd": "*",
|
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
"dompdf/dompdf": "^2.0",
|
"dompdf/dompdf": "^2.0 || ^3.0",
|
||||||
"mpdf/mpdf": "^8.1",
|
|
||||||
"phpmd/phpmd": "^2.13",
|
|
||||||
"phpunit/phpunit": ">=7.0",
|
|
||||||
"tecnickcom/tcpdf": "^6.5",
|
|
||||||
"symfony/process": "^4.4 || ^5.0",
|
|
||||||
"friendsofphp/php-cs-fixer": "^3.3",
|
"friendsofphp/php-cs-fixer": "^3.3",
|
||||||
"phpstan/phpstan-phpunit": "@stable"
|
"mpdf/mpdf": "^7.0 || ^8.0",
|
||||||
|
"phpmd/phpmd": "^2.13",
|
||||||
|
"phpstan/phpstan": "^0.12.88 || ^1.0.0",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0 || ^2.0",
|
||||||
|
"phpunit/phpunit": ">=7.0",
|
||||||
|
"symfony/process": "^4.4 || ^5.0",
|
||||||
|
"tecnickcom/tcpdf": "^6.5"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-zip": "Allows writing OOXML and ODF",
|
|
||||||
"ext-gd2": "Allows adding images",
|
|
||||||
"ext-xmlwriter": "Allows writing OOXML and ODF",
|
"ext-xmlwriter": "Allows writing OOXML and ODF",
|
||||||
"ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template",
|
"ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template",
|
||||||
"dompdf/dompdf": "Allows writing PDF"
|
"dompdf/dompdf": "Allows writing PDF"
|
||||||
|
|||||||
5
vendor/phpoffice/phpword/mkdocs.yml
vendored
5
vendor/phpoffice/phpword/mkdocs.yml
vendored
@@ -63,6 +63,7 @@ nav:
|
|||||||
- OLE Object: 'usage/elements/oleobject.md'
|
- OLE Object: 'usage/elements/oleobject.md'
|
||||||
- Page Break: 'usage/elements/pagebreak.md'
|
- Page Break: 'usage/elements/pagebreak.md'
|
||||||
- Preserve Text: 'usage/elements/preservetext.md'
|
- Preserve Text: 'usage/elements/preservetext.md'
|
||||||
|
- Ruby: 'usage/elements/ruby.md'
|
||||||
- Text: 'usage/elements/text.md'
|
- Text: 'usage/elements/text.md'
|
||||||
- TextBox: 'usage/elements/textbox.md'
|
- TextBox: 'usage/elements/textbox.md'
|
||||||
- Text Break: 'usage/elements/textbreak.md'
|
- Text Break: 'usage/elements/textbreak.md'
|
||||||
@@ -87,7 +88,9 @@ nav:
|
|||||||
- Credits: 'credits.md'
|
- Credits: 'credits.md'
|
||||||
- Releases:
|
- Releases:
|
||||||
- '1.x':
|
- '1.x':
|
||||||
- '1.3.0 (WIP)': 'changes/1.x/1.3.0.md'
|
- '1.5.0 (WIP)': 'changes/1.x/1.5.0.md'
|
||||||
|
- '1.4.0': 'changes/1.x/1.4.0.md'
|
||||||
|
- '1.3.0': 'changes/1.x/1.3.0.md'
|
||||||
- '1.2.0': 'changes/1.x/1.2.0.md'
|
- '1.2.0': 'changes/1.x/1.2.0.md'
|
||||||
- '1.1.0': 'changes/1.x/1.1.0.md'
|
- '1.1.0': 'changes/1.x/1.1.0.md'
|
||||||
- '1.0.0': 'changes/1.x/1.0.0.md'
|
- '1.0.0': 'changes/1.x/1.0.0.md'
|
||||||
|
|||||||
140
vendor/phpoffice/phpword/phpstan-baseline.neon
vendored
140
vendor/phpoffice/phpword/phpstan-baseline.neon
vendored
@@ -375,11 +375,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Shared/Drawing.php
|
path: src/PhpWord/Shared/Drawing.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Binary operation \"\\*\" between string and 50 results in an error\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Shared/Html.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#"
|
message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -435,6 +430,11 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Shared/Html.php
|
path: src/PhpWord/Shared/Html.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseRuby\\(\\) has no return type specified\\.$#"
|
||||||
|
count: 1
|
||||||
|
path: src/PhpWord/Shared/Html.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyleDeclarations\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyleDeclarations\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -447,7 +447,7 @@ parameters:
|
|||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#1 \\$attribute of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyle\\(\\) expects DOMAttr, DOMNode given\\.$#"
|
message: "#^Parameter \\#1 \\$attribute of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyle\\(\\) expects DOMAttr, DOMNode given\\.$#"
|
||||||
count: 1
|
count: 3
|
||||||
path: src/PhpWord/Shared/Html.php
|
path: src/PhpWord/Shared/Html.php
|
||||||
|
|
||||||
-
|
-
|
||||||
@@ -685,11 +685,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Style/Cell.php
|
path: src/PhpWord/Style/Cell.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\:\\:\\$shading is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Cell.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:getMajorTickPosition\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:getMajorTickPosition\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -760,41 +755,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Style/Font.php
|
path: src/PhpWord/Style/Font.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$allCaps is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$doubleStrikethrough is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$lang is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$paragraph is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$shading is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$smallCaps is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$strikethrough is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Font.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Line\\:\\:\\$weight \\(int\\) does not accept float\\|int\\|null\\.$#"
|
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Line\\:\\:\\$weight \\(int\\) does not accept float\\|int\\|null\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -815,21 +775,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Style/Paragraph.php
|
path: src/PhpWord/Style/Paragraph.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$indentation is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Paragraph.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$shading is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Paragraph.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$spacing is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Paragraph.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Result of && is always false\\.$#"
|
message: "#^Result of && is always false\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -840,36 +785,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Style/Section.php
|
path: src/PhpWord/Style/Section.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Section\\:\\:\\$lineNumbering is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Section.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$extrusion is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Shape.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$fill is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Shape.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$frame is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Shape.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$outline is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Shape.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$shadow is never written, only read\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Style/Shape.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\TOC\\:\\:setTabLeader\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\TOC but returns PhpOffice\\\\PhpWord\\\\Style\\\\Tab\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\TOC\\:\\:setTabLeader\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\TOC but returns PhpOffice\\\\PhpWord\\\\Style\\\\Tab\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -1120,11 +1035,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Writer/AbstractWriter.php
|
path: src/PhpWord/Writer/AbstractWriter.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \\*\", expected variable at offset 78$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Writer/AbstractWriter.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -1146,14 +1056,14 @@ parameters:
|
|||||||
path: src/PhpWord/Writer/ODText/Element/Table.php
|
path: src/PhpWord/Writer/ODText/Element/Table.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$text with no type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$text with no type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Writer/ODText/Element/Text.php
|
path: src/PhpWord/Writer/ODText/Element/AbstractElement.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Writer/ODText/Element/Text.php
|
path: src/PhpWord/Writer/ODText/Element/AbstractElement.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:writeChangeInsertion\\(\\) has parameter \\$start with no type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:writeChangeInsertion\\(\\) has parameter \\$start with no type specified\\.$#"
|
||||||
@@ -1315,11 +1225,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: src/PhpWord/Writer/RTF/Style/Border.php
|
path: src/PhpWord/Writer/RTF/Style/Border.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \", expected variable at offset 86$#"
|
|
||||||
count: 1
|
|
||||||
path: src/PhpWord/Writer/Word2007.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
@@ -1426,29 +1331,29 @@ parameters:
|
|||||||
path: tests/PhpWordTests/AbstractTestReader.php
|
path: tests/PhpWordTests/AbstractTestReader.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php
|
path: tests/PhpWordTests/AbstractWebServerEmbedded.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php
|
path: tests/PhpWordTests/AbstractWebServerEmbedded.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php
|
path: tests/PhpWordTests/AbstractWebServerEmbedded.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#"
|
message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php
|
path: tests/PhpWordTests/AbstractWebServerEmbedded.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:\\$httpServer has no type specified\\.$#"
|
message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:\\$httpServer has no type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php
|
path: tests/PhpWordTests/AbstractWebServerEmbedded.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Parameter \\#1 \\$width of class PhpOffice\\\\PhpWord\\\\Element\\\\Cell constructor expects int\\|null, string given\\.$#"
|
message: "#^Parameter \\#1 \\$width of class PhpOffice\\\\PhpWord\\\\Element\\\\Cell constructor expects int\\|null, string given\\.$#"
|
||||||
@@ -1789,6 +1694,11 @@ parameters:
|
|||||||
message: "#^Cannot access property \\$length on DOMNodeList\\<DOMNode\\>\\|false\\.$#"
|
message: "#^Cannot access property \\$length on DOMNodeList\\<DOMNode\\>\\|false\\.$#"
|
||||||
count: 9
|
count: 9
|
||||||
path: tests/PhpWordTests/Writer/HTML/ElementTest.php
|
path: tests/PhpWordTests/Writer/HTML/ElementTest.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: "#^Cannot access property \\$length on DOMNodeList\\<DOMNode\\>\\|false\\.$#"
|
||||||
|
count: 2
|
||||||
|
path: tests/PhpWordTests/Writer/HTML/Element/RubyTest.php
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Cannot call method item\\(\\) on DOMNodeList\\<DOMNode\\>\\|false\\.$#"
|
message: "#^Cannot call method item\\(\\) on DOMNodeList\\<DOMNode\\>\\|false\\.$#"
|
||||||
|
|||||||
1
vendor/phpoffice/phpword/phpword.ini.dist
vendored
1
vendor/phpoffice/phpword/phpword.ini.dist
vendored
@@ -14,6 +14,7 @@ outputEscapingEnabled = false
|
|||||||
|
|
||||||
defaultFontName = Arial
|
defaultFontName = Arial
|
||||||
defaultFontSize = 10
|
defaultFontSize = 10
|
||||||
|
defaultFontColor = 000000
|
||||||
|
|
||||||
[Paper]
|
[Paper]
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -21,6 +22,7 @@ namespace PhpOffice\PhpWord\Collection;
|
|||||||
* Collection abstract class.
|
* Collection abstract class.
|
||||||
*
|
*
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
|
*
|
||||||
* @template T
|
* @template T
|
||||||
*/
|
*/
|
||||||
abstract class AbstractCollection
|
abstract class AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -23,6 +24,7 @@ use PhpOffice\PhpWord\Element\Bookmark;
|
|||||||
* Bookmarks collection.
|
* Bookmarks collection.
|
||||||
*
|
*
|
||||||
* @since 0.12.0
|
* @since 0.12.0
|
||||||
|
*
|
||||||
* @extends AbstractCollection<Bookmark>
|
* @extends AbstractCollection<Bookmark>
|
||||||
*/
|
*/
|
||||||
class Bookmarks extends AbstractCollection
|
class Bookmarks extends AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -23,6 +24,7 @@ use PhpOffice\PhpWord\Element\Chart;
|
|||||||
* Charts collection.
|
* Charts collection.
|
||||||
*
|
*
|
||||||
* @since 0.12.0
|
* @since 0.12.0
|
||||||
|
*
|
||||||
* @extends AbstractCollection<Chart>
|
* @extends AbstractCollection<Chart>
|
||||||
*/
|
*/
|
||||||
class Charts extends AbstractCollection
|
class Charts extends AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -23,6 +24,7 @@ use PhpOffice\PhpWord\Element\Comment;
|
|||||||
* Comments collection.
|
* Comments collection.
|
||||||
*
|
*
|
||||||
* @since 0.12.0
|
* @since 0.12.0
|
||||||
|
*
|
||||||
* @extends AbstractCollection<Comment>
|
* @extends AbstractCollection<Comment>
|
||||||
*/
|
*/
|
||||||
class Comments extends AbstractCollection
|
class Comments extends AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -23,6 +24,7 @@ use PhpOffice\PhpWord\Element\Endnote;
|
|||||||
* Endnotes collection.
|
* Endnotes collection.
|
||||||
*
|
*
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
|
*
|
||||||
* @extends AbstractCollection<Endnote>
|
* @extends AbstractCollection<Endnote>
|
||||||
*/
|
*/
|
||||||
class Endnotes extends AbstractCollection
|
class Endnotes extends AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -23,6 +24,7 @@ use PhpOffice\PhpWord\Element\Footnote;
|
|||||||
* Footnotes collection.
|
* Footnotes collection.
|
||||||
*
|
*
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
|
*
|
||||||
* @extends AbstractCollection<Footnote>
|
* @extends AbstractCollection<Footnote>
|
||||||
*/
|
*/
|
||||||
class Footnotes extends AbstractCollection
|
class Footnotes extends AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -23,6 +24,7 @@ use PhpOffice\PhpWord\Element\Title;
|
|||||||
* Titles collection.
|
* Titles collection.
|
||||||
*
|
*
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
|
*
|
||||||
* @extends AbstractCollection<Title>
|
* @extends AbstractCollection<Title>
|
||||||
*/
|
*/
|
||||||
class Titles extends AbstractCollection
|
class Titles extends AbstractCollection
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -49,6 +50,7 @@ use ReflectionClass;
|
|||||||
* @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)
|
* @method FormField addFormField(string $type, mixed $fStyle = null, mixed $pStyle = null)
|
||||||
* @method SDT addSDT(string $type)
|
* @method SDT addSDT(string $type)
|
||||||
* @method Formula addFormula(Math $math)
|
* @method Formula addFormula(Math $math)
|
||||||
|
* @method Ruby addRuby(TextRun $baseText, TextRun $rubyText, \PhpOffice\PhpWord\ComplexType\RubyProperties $properties)
|
||||||
* @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead
|
* @method \PhpOffice\PhpWord\Element\OLEObject addObject(string $source, mixed $style = null) deprecated, use addOLEObject instead
|
||||||
*
|
*
|
||||||
* @since 0.10.0
|
* @since 0.10.0
|
||||||
@@ -58,7 +60,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Elements collection.
|
* Elements collection.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Element\AbstractElement[]
|
* @var AbstractElement[]
|
||||||
*/
|
*/
|
||||||
protected $elements = [];
|
protected $elements = [];
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
* @param mixed $function
|
* @param mixed $function
|
||||||
* @param mixed $args
|
* @param mixed $args
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\AbstractElement
|
* @return AbstractElement
|
||||||
*/
|
*/
|
||||||
public function __call($function, $args)
|
public function __call($function, $args)
|
||||||
{
|
{
|
||||||
@@ -90,7 +92,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
|
'Footnote', 'Endnote', 'CheckBox', 'TextBox', 'Field',
|
||||||
'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
|
'Line', 'Shape', 'Title', 'TOC', 'PageBreak',
|
||||||
'Chart', 'FormField', 'SDT', 'Comment',
|
'Chart', 'FormField', 'SDT', 'Comment',
|
||||||
'Formula',
|
'Formula', 'Ruby',
|
||||||
];
|
];
|
||||||
$functions = [];
|
$functions = [];
|
||||||
foreach ($elements as $element) {
|
foreach ($elements as $element) {
|
||||||
@@ -130,7 +132,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
*
|
*
|
||||||
* @param string $elementName
|
* @param string $elementName
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\AbstractElement
|
* @return AbstractElement
|
||||||
*/
|
*/
|
||||||
protected function addElement($elementName)
|
protected function addElement($elementName)
|
||||||
{
|
{
|
||||||
@@ -149,7 +151,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
$elementArgs = $args;
|
$elementArgs = $args;
|
||||||
array_shift($elementArgs); // Shift the $elementName off the beginning of array
|
array_shift($elementArgs); // Shift the $elementName off the beginning of array
|
||||||
|
|
||||||
/** @var \PhpOffice\PhpWord\Element\AbstractElement $element Type hint */
|
/** @var AbstractElement $element Type hint */
|
||||||
$element = $reflection->newInstanceArgs($elementArgs);
|
$element = $reflection->newInstanceArgs($elementArgs);
|
||||||
|
|
||||||
// Set parent container
|
// Set parent container
|
||||||
@@ -165,7 +167,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get all elements.
|
* Get all elements.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\AbstractElement[]
|
* @return AbstractElement[]
|
||||||
*/
|
*/
|
||||||
public function getElements()
|
public function getElements()
|
||||||
{
|
{
|
||||||
@@ -177,7 +179,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
*
|
*
|
||||||
* @param int $index
|
* @param int $index
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Element\AbstractElement
|
* @return null|AbstractElement
|
||||||
*/
|
*/
|
||||||
public function getElement($index)
|
public function getElement($index)
|
||||||
{
|
{
|
||||||
@@ -191,13 +193,13 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Removes the element at requested index.
|
* Removes the element at requested index.
|
||||||
*
|
*
|
||||||
* @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove
|
* @param AbstractElement|int $toRemove
|
||||||
*/
|
*/
|
||||||
public function removeElement($toRemove): void
|
public function removeElement($toRemove): void
|
||||||
{
|
{
|
||||||
if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) {
|
if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) {
|
||||||
unset($this->elements[$toRemove]);
|
unset($this->elements[$toRemove]);
|
||||||
} elseif ($toRemove instanceof \PhpOffice\PhpWord\Element\AbstractElement) {
|
} elseif ($toRemove instanceof AbstractElement) {
|
||||||
foreach ($this->elements as $key => $element) {
|
foreach ($this->elements as $key => $element) {
|
||||||
if ($element->getElementId() === $toRemove->getElementId()) {
|
if ($element->getElementId() === $toRemove->getElementId()) {
|
||||||
unset($this->elements[$key]);
|
unset($this->elements[$key]);
|
||||||
@@ -253,7 +255,7 @@ abstract class AbstractContainer extends AbstractElement
|
|||||||
'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'],
|
'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'],
|
||||||
'Endnote' => ['Section', 'TextRun', 'Cell'],
|
'Endnote' => ['Section', 'TextRun', 'Cell'],
|
||||||
'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'],
|
'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'],
|
||||||
'Title' => ['Section', 'Cell'],
|
'Title' => ['Section', 'Cell', 'Header'],
|
||||||
'TOC' => ['Section'],
|
'TOC' => ['Section'],
|
||||||
'PageBreak' => ['Section'],
|
'PageBreak' => ['Section'],
|
||||||
'Chart' => ['Section', 'Cell'],
|
'Chart' => ['Section', 'Cell'],
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -148,8 +149,6 @@ abstract class AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get PhpWord.
|
* Get PhpWord.
|
||||||
*
|
|
||||||
* @return ?PhpWord
|
|
||||||
*/
|
*/
|
||||||
public function getPhpWord(): ?PhpWord
|
public function getPhpWord(): ?PhpWord
|
||||||
{
|
{
|
||||||
@@ -256,7 +255,7 @@ abstract class AbstractElement
|
|||||||
*/
|
*/
|
||||||
public function setElementId(): void
|
public function setElementId(): void
|
||||||
{
|
{
|
||||||
$this->elementId = substr(md5(mt_rand()), 0, 6);
|
$this->elementId = substr(md5((string) mt_rand()), 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -291,8 +290,6 @@ abstract class AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get comments start.
|
* Get comments start.
|
||||||
*
|
|
||||||
* @return Comments
|
|
||||||
*/
|
*/
|
||||||
public function getCommentsRangeStart(): ?Comments
|
public function getCommentsRangeStart(): ?Comments
|
||||||
{
|
{
|
||||||
@@ -301,8 +298,6 @@ abstract class AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get comment start.
|
* Get comment start.
|
||||||
*
|
|
||||||
* @return Comment
|
|
||||||
*/
|
*/
|
||||||
public function getCommentRangeStart(): ?Comment
|
public function getCommentRangeStart(): ?Comment
|
||||||
{
|
{
|
||||||
@@ -339,8 +334,6 @@ abstract class AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get comments end.
|
* Get comments end.
|
||||||
*
|
|
||||||
* @return Comments
|
|
||||||
*/
|
*/
|
||||||
public function getCommentsRangeEnd(): ?Comments
|
public function getCommentsRangeEnd(): ?Comments
|
||||||
{
|
{
|
||||||
@@ -349,8 +342,6 @@ abstract class AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get comment end.
|
* Get comment end.
|
||||||
*
|
|
||||||
* @return Comment
|
|
||||||
*/
|
*/
|
||||||
public function getCommentRangeEnd(): ?Comment
|
public function getCommentRangeEnd(): ?Comment
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -39,7 +40,7 @@ class Cell extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Cell style.
|
* Cell style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Cell
|
* @var ?CellStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -47,7 +48,7 @@ class Cell extends AbstractContainer
|
|||||||
* Create new instance.
|
* Create new instance.
|
||||||
*
|
*
|
||||||
* @param null|int $width
|
* @param null|int $width
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Cell $style
|
* @param array|CellStyle $style
|
||||||
*/
|
*/
|
||||||
public function __construct($width = null, $style = null)
|
public function __construct($width = null, $style = null)
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ class Cell extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Get cell style.
|
* Get cell style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Cell
|
* @return ?CellStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -50,7 +51,7 @@ class Chart extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Chart style.
|
* Chart style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Chart
|
* @var ?ChartStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -120,7 +121,7 @@ class Chart extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get chart style.
|
* Get chart style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Chart
|
* @return ?ChartStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -89,7 +90,7 @@ class Comment extends TrackChange
|
|||||||
/**
|
/**
|
||||||
* Get the element where this comment starts.
|
* Get the element where this comment starts.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\AbstractElement
|
* @return AbstractElement
|
||||||
*/
|
*/
|
||||||
public function getStartElement()
|
public function getStartElement()
|
||||||
{
|
{
|
||||||
@@ -108,7 +109,7 @@ class Comment extends TrackChange
|
|||||||
/**
|
/**
|
||||||
* Get the element where this comment ends.
|
* Get the element where this comment ends.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\AbstractElement
|
* @return AbstractElement
|
||||||
*/
|
*/
|
||||||
public function getEndElement()
|
public function getEndElement()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -128,16 +129,16 @@ class Field extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Font style.
|
* Font style.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Style\Font|string
|
* @var Font|string
|
||||||
*/
|
*/
|
||||||
protected $fontStyle;
|
protected $fontStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Font style.
|
* Set Font style.
|
||||||
*
|
*
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Font|string $style
|
* @param array|Font|string $style
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Font|string
|
* @return Font|string
|
||||||
*/
|
*/
|
||||||
public function setFontStyle($style = null)
|
public function setFontStyle($style = null)
|
||||||
{
|
{
|
||||||
@@ -158,7 +159,7 @@ class Field extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Font style.
|
* Get Font style.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Font|string
|
* @return Font|string
|
||||||
*/
|
*/
|
||||||
public function getFontStyle()
|
public function getFontStyle()
|
||||||
{
|
{
|
||||||
@@ -172,7 +173,7 @@ class Field extends AbstractElement
|
|||||||
* @param array $properties
|
* @param array $properties
|
||||||
* @param array $options
|
* @param array $options
|
||||||
* @param null|string|TextRun $text
|
* @param null|string|TextRun $text
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Font|string $fontStyle
|
* @param array|Font|string $fontStyle
|
||||||
*/
|
*/
|
||||||
public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null)
|
public function __construct($type = null, $properties = [], $options = [], $text = null, $fontStyle = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -29,7 +30,7 @@ class Footnote extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Paragraph style.
|
* Paragraph style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @var null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
protected $paragraphStyle;
|
protected $paragraphStyle;
|
||||||
|
|
||||||
@@ -43,7 +44,7 @@ class Footnote extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Create new instance.
|
* Create new instance.
|
||||||
*
|
*
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle
|
* @param array|Paragraph|string $paragraphStyle
|
||||||
*/
|
*/
|
||||||
public function __construct($paragraphStyle = null)
|
public function __construct($paragraphStyle = null)
|
||||||
{
|
{
|
||||||
@@ -54,7 +55,7 @@ class Footnote extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Get paragraph style.
|
* Get paragraph style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @return null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function getParagraphStyle()
|
public function getParagraphStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -27,7 +28,7 @@ class Line extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Line style.
|
* Line style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Line
|
* @var ?LineStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ class Line extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get line style.
|
* Get line style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Line
|
* @return ?LineStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -43,14 +44,14 @@ class Link extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Font style.
|
* Font style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Font|string
|
* @var null|Font|string
|
||||||
*/
|
*/
|
||||||
private $fontStyle;
|
private $fontStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paragraph style.
|
* Paragraph style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @var null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
private $paragraphStyle;
|
private $paragraphStyle;
|
||||||
|
|
||||||
@@ -98,10 +99,8 @@ class Link extends AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get link text.
|
* Get link text.
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
public function getText()
|
public function getText(): string
|
||||||
{
|
{
|
||||||
return $this->text;
|
return $this->text;
|
||||||
}
|
}
|
||||||
@@ -109,7 +108,7 @@ class Link extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Text style.
|
* Get Text style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Font|string
|
* @return null|Font|string
|
||||||
*/
|
*/
|
||||||
public function getFontStyle()
|
public function getFontStyle()
|
||||||
{
|
{
|
||||||
@@ -119,7 +118,7 @@ class Link extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Paragraph style.
|
* Get Paragraph style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @return null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function getParagraphStyle()
|
public function getParagraphStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -28,14 +29,14 @@ class ListItem extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Element style.
|
* Element style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\ListItem
|
* @var ?ListItemStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text object.
|
* Text object.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Element\Text
|
* @var Text
|
||||||
*/
|
*/
|
||||||
private $textObject;
|
private $textObject;
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ class ListItem extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get style.
|
* Get style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\ListItem
|
* @return ?ListItemStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
@@ -81,7 +82,7 @@ class ListItem extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Text object.
|
* Get Text object.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\Text
|
* @return Text
|
||||||
*/
|
*/
|
||||||
public function getTextObject()
|
public function getTextObject()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -32,7 +33,7 @@ class ListItemRun extends TextRun
|
|||||||
/**
|
/**
|
||||||
* ListItem Style.
|
* ListItem Style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\ListItem
|
* @var ?ListItemStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -66,7 +67,7 @@ class ListItemRun extends TextRun
|
|||||||
/**
|
/**
|
||||||
* Get ListItem style.
|
* Get ListItem style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\ListItem
|
* @return ?ListItemStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -35,7 +36,7 @@ class OLEObject extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Image Style.
|
* Image Style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Image
|
* @var ?ImageStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ class OLEObject extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get object style.
|
* Get object style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Image
|
* @return ?ImageStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -36,14 +37,14 @@ class PreserveText extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Text style.
|
* Text style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Font|string
|
* @var null|Font|string
|
||||||
*/
|
*/
|
||||||
private $fontStyle;
|
private $fontStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paragraph style.
|
* Paragraph style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @var null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
private $paragraphStyle;
|
private $paragraphStyle;
|
||||||
|
|
||||||
@@ -69,7 +70,7 @@ class PreserveText extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Text style.
|
* Get Text style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Font|string
|
* @return null|Font|string
|
||||||
*/
|
*/
|
||||||
public function getFontStyle()
|
public function getFontStyle()
|
||||||
{
|
{
|
||||||
@@ -79,7 +80,7 @@ class PreserveText extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Paragraph style.
|
* Get Paragraph style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @return null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function getParagraphStyle()
|
public function getParagraphStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -36,14 +37,14 @@ class Row extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Row style.
|
* Row style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Row
|
* @var ?RowStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Row cells.
|
* Row cells.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Element\Cell[]
|
* @var Cell[]
|
||||||
*/
|
*/
|
||||||
private $cells = [];
|
private $cells = [];
|
||||||
|
|
||||||
@@ -65,7 +66,7 @@ class Row extends AbstractElement
|
|||||||
* @param int $width
|
* @param int $width
|
||||||
* @param mixed $style
|
* @param mixed $style
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\Cell
|
* @return Cell
|
||||||
*/
|
*/
|
||||||
public function addCell($width = null, $style = null)
|
public function addCell($width = null, $style = null)
|
||||||
{
|
{
|
||||||
@@ -79,7 +80,7 @@ class Row extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get all cells.
|
* Get all cells.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\Cell[]
|
* @return Cell[]
|
||||||
*/
|
*/
|
||||||
public function getCells()
|
public function getCells()
|
||||||
{
|
{
|
||||||
@@ -89,7 +90,7 @@ class Row extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get row style.
|
* Get row style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Row
|
* @return ?RowStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -31,7 +32,7 @@ class Section extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Section style.
|
* Section style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Section
|
* @var ?SectionStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ class Section extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Get section style.
|
* Get section style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Section
|
* @return ?SectionStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
@@ -196,14 +197,14 @@ class Section extends AbstractContainer
|
|||||||
*/
|
*/
|
||||||
private function addHeaderFooter($type = Header::AUTO, $header = true)
|
private function addHeaderFooter($type = Header::AUTO, $header = true)
|
||||||
{
|
{
|
||||||
$containerClass = substr(static::class, 0, strrpos(static::class, '\\')) . '\\' .
|
$containerClass = substr(static::class, 0, strrpos(static::class, '\\') ?: 0) . '\\' .
|
||||||
($header ? 'Header' : 'Footer');
|
($header ? 'Header' : 'Footer');
|
||||||
$collectionArray = $header ? 'headers' : 'footers';
|
$collectionArray = $header ? 'headers' : 'footers';
|
||||||
$collection = &$this->$collectionArray;
|
$collection = &$this->$collectionArray;
|
||||||
|
|
||||||
if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) {
|
if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) {
|
||||||
$index = count($collection);
|
$index = count($collection);
|
||||||
/** @var \PhpOffice\PhpWord\Element\AbstractContainer $container Type hint */
|
/** @var AbstractContainer $container Type hint */
|
||||||
$container = new $containerClass($this->sectionId, ++$index, $type);
|
$container = new $containerClass($this->sectionId, ++$index, $type);
|
||||||
$container->setPhpWord($this->phpWord);
|
$container->setPhpWord($this->phpWord);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -36,7 +37,7 @@ class Shape extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Shape style.
|
* Shape style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Shape
|
* @var ?ShapeStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -80,7 +81,7 @@ class Shape extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get shape style.
|
* Get shape style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\Shape
|
* @return ?ShapeStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -29,14 +30,14 @@ class TOC extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* TOC style.
|
* TOC style.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Style\TOC
|
* @var TOCStyle
|
||||||
*/
|
*/
|
||||||
private $tocStyle;
|
private $tocStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Font style.
|
* Font style.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Style\Font|string
|
* @var Font|string
|
||||||
*/
|
*/
|
||||||
private $fontStyle;
|
private $fontStyle;
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ class TOC extends AbstractElement
|
|||||||
|
|
||||||
$titles = $this->phpWord->getTitles()->getItems();
|
$titles = $this->phpWord->getTitles()->getItems();
|
||||||
foreach ($titles as $i => $title) {
|
foreach ($titles as $i => $title) {
|
||||||
/** @var \PhpOffice\PhpWord\Element\Title $title Type hint */
|
/** @var Title $title Type hint */
|
||||||
$depth = $title->getDepth();
|
$depth = $title->getDepth();
|
||||||
if ($this->minDepth > $depth) {
|
if ($this->minDepth > $depth) {
|
||||||
unset($titles[$i]);
|
unset($titles[$i]);
|
||||||
@@ -110,7 +111,7 @@ class TOC extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get TOC Style.
|
* Get TOC Style.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\TOC
|
* @return TOCStyle
|
||||||
*/
|
*/
|
||||||
public function getStyleTOC()
|
public function getStyleTOC()
|
||||||
{
|
{
|
||||||
@@ -120,7 +121,7 @@ class TOC extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Font Style.
|
* Get Font Style.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Font|string
|
* @return Font|string
|
||||||
*/
|
*/
|
||||||
public function getStyleFont()
|
public function getStyleFont()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -27,14 +28,14 @@ class Table extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Table style.
|
* Table style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\Table
|
* @var ?TableStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table rows.
|
* Table rows.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Element\Row[]
|
* @var Row[]
|
||||||
*/
|
*/
|
||||||
private $rows = [];
|
private $rows = [];
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ class Table extends AbstractElement
|
|||||||
* @param int $height
|
* @param int $height
|
||||||
* @param mixed $style
|
* @param mixed $style
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\Row
|
* @return Row
|
||||||
*/
|
*/
|
||||||
public function addRow($height = null, $style = null)
|
public function addRow($height = null, $style = null)
|
||||||
{
|
{
|
||||||
@@ -78,7 +79,7 @@ class Table extends AbstractElement
|
|||||||
* @param int $width
|
* @param int $width
|
||||||
* @param mixed $style
|
* @param mixed $style
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\Cell
|
* @return Cell
|
||||||
*/
|
*/
|
||||||
public function addCell($width = null, $style = null)
|
public function addCell($width = null, $style = null)
|
||||||
{
|
{
|
||||||
@@ -92,7 +93,7 @@ class Table extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get all rows.
|
* Get all rows.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Element\Row[]
|
* @return Row[]
|
||||||
*/
|
*/
|
||||||
public function getRows()
|
public function getRows()
|
||||||
{
|
{
|
||||||
@@ -102,7 +103,7 @@ class Table extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get table style.
|
* Get table style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Table|string
|
* @return null|string|TableStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
@@ -140,7 +141,7 @@ class Table extends AbstractElement
|
|||||||
|
|
||||||
$rowCount = count($this->rows);
|
$rowCount = count($this->rows);
|
||||||
for ($i = 0; $i < $rowCount; ++$i) {
|
for ($i = 0; $i < $rowCount; ++$i) {
|
||||||
/** @var \PhpOffice\PhpWord\Element\Row $row Type hint */
|
/** @var Row $row Type hint */
|
||||||
$row = $this->rows[$i];
|
$row = $this->rows[$i];
|
||||||
$cellCount = count($row->getCells());
|
$cellCount = count($row->getCells());
|
||||||
if ($columnCount < $cellCount) {
|
if ($columnCount < $cellCount) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -36,14 +37,14 @@ class Text extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Text style.
|
* Text style.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Style\Font|string
|
* @var Font|string
|
||||||
*/
|
*/
|
||||||
protected $fontStyle;
|
protected $fontStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paragraph style.
|
* Paragraph style.
|
||||||
*
|
*
|
||||||
* @var \PhpOffice\PhpWord\Style\Paragraph|string
|
* @var Paragraph|string
|
||||||
*/
|
*/
|
||||||
protected $paragraphStyle;
|
protected $paragraphStyle;
|
||||||
|
|
||||||
@@ -64,10 +65,10 @@ class Text extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Set Text style.
|
* Set Text style.
|
||||||
*
|
*
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Font|string $style
|
* @param array|Font|string $style
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Paragraph|string $paragraphStyle
|
* @param array|Paragraph|string $paragraphStyle
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Font|string
|
* @return Font|string
|
||||||
*/
|
*/
|
||||||
public function setFontStyle($style = null, $paragraphStyle = null)
|
public function setFontStyle($style = null, $paragraphStyle = null)
|
||||||
{
|
{
|
||||||
@@ -90,7 +91,7 @@ class Text extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Text style.
|
* Get Text style.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Font|string
|
* @return Font|string
|
||||||
*/
|
*/
|
||||||
public function getFontStyle()
|
public function getFontStyle()
|
||||||
{
|
{
|
||||||
@@ -100,9 +101,9 @@ class Text extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Set Paragraph style.
|
* Set Paragraph style.
|
||||||
*
|
*
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style
|
* @param array|Paragraph|string $style
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Paragraph|string
|
* @return Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function setParagraphStyle($style = null)
|
public function setParagraphStyle($style = null)
|
||||||
{
|
{
|
||||||
@@ -123,7 +124,7 @@ class Text extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Paragraph style.
|
* Get Paragraph style.
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Paragraph|string
|
* @return Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function getParagraphStyle()
|
public function getParagraphStyle()
|
||||||
{
|
{
|
||||||
@@ -146,10 +147,8 @@ class Text extends AbstractElement
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Text content.
|
* Get Text content.
|
||||||
*
|
|
||||||
* @return ?string
|
|
||||||
*/
|
*/
|
||||||
public function getText()
|
public function getText(): ?string
|
||||||
{
|
{
|
||||||
return $this->text;
|
return $this->text;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -34,7 +35,7 @@ class TextBox extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* TextBox style.
|
* TextBox style.
|
||||||
*
|
*
|
||||||
* @var ?\PhpOffice\PhpWord\Style\TextBox
|
* @var ?TextBoxStyle
|
||||||
*/
|
*/
|
||||||
private $style;
|
private $style;
|
||||||
|
|
||||||
@@ -51,7 +52,7 @@ class TextBox extends AbstractContainer
|
|||||||
/**
|
/**
|
||||||
* Get textbox style.
|
* Get textbox style.
|
||||||
*
|
*
|
||||||
* @return ?\PhpOffice\PhpWord\Style\TextBox
|
* @return ?TextBoxStyle
|
||||||
*/
|
*/
|
||||||
public function getStyle()
|
public function getStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -28,14 +29,14 @@ class TextBreak extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Paragraph style.
|
* Paragraph style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @var null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
private $paragraphStyle;
|
private $paragraphStyle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Text style.
|
* Text style.
|
||||||
*
|
*
|
||||||
* @var null|\PhpOffice\PhpWord\Style\Font|string
|
* @var null|Font|string
|
||||||
*/
|
*/
|
||||||
private $fontStyle;
|
private $fontStyle;
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ class TextBreak extends AbstractElement
|
|||||||
* @param mixed $style
|
* @param mixed $style
|
||||||
* @param mixed $paragraphStyle
|
* @param mixed $paragraphStyle
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Font|string
|
* @return Font|string
|
||||||
*/
|
*/
|
||||||
public function setFontStyle($style = null, $paragraphStyle = null)
|
public function setFontStyle($style = null, $paragraphStyle = null)
|
||||||
{
|
{
|
||||||
@@ -82,7 +83,7 @@ class TextBreak extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Text style.
|
* Get Text style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Font|string
|
* @return null|Font|string
|
||||||
*/
|
*/
|
||||||
public function getFontStyle()
|
public function getFontStyle()
|
||||||
{
|
{
|
||||||
@@ -92,9 +93,9 @@ class TextBreak extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Set Paragraph style.
|
* Set Paragraph style.
|
||||||
*
|
*
|
||||||
* @param array|\PhpOffice\PhpWord\Style\Paragraph|string $style
|
* @param array|Paragraph|string $style
|
||||||
*
|
*
|
||||||
* @return \PhpOffice\PhpWord\Style\Paragraph|string
|
* @return Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function setParagraphStyle($style = null)
|
public function setParagraphStyle($style = null)
|
||||||
{
|
{
|
||||||
@@ -113,7 +114,7 @@ class TextBreak extends AbstractElement
|
|||||||
/**
|
/**
|
||||||
* Get Paragraph style.
|
* Get Paragraph style.
|
||||||
*
|
*
|
||||||
* @return null|\PhpOffice\PhpWord\Style\Paragraph|string
|
* @return null|Paragraph|string
|
||||||
*/
|
*/
|
||||||
public function getParagraphStyle()
|
public function getParagraphStyle()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
@@ -85,6 +86,9 @@ class TextRun extends AbstractContainer
|
|||||||
foreach ($this->getElements() as $element) {
|
foreach ($this->getElements() as $element) {
|
||||||
if ($element instanceof Text) {
|
if ($element instanceof Text) {
|
||||||
$outstr .= $element->getText();
|
$outstr .= $element->getText();
|
||||||
|
} elseif ($element instanceof Ruby) {
|
||||||
|
$outstr .= $element->getBaseTextRun()->getText() .
|
||||||
|
' (' . $element->getRubyTextRun()->getText() . ')';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is part of PHPWord - A pure PHP library for reading and writing
|
* This file is part of PHPWord - A pure PHP library for reading and writing
|
||||||
* word processing documents.
|
* word processing documents.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user