mirror of
https://git.beihong.wang/wangbeihong/blog-source.git
synced 2026-04-23 16:33:04 +08:00
962 lines
26 KiB
PHP
Executable File
962 lines
26 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Widget\Base;
|
|
|
|
use Typecho\Common;
|
|
use Typecho\Config;
|
|
use Typecho\Cookie;
|
|
use Typecho\Date;
|
|
use Typecho\Db\Exception;
|
|
use Typecho\Db\Query;
|
|
use Typecho\Plugin;
|
|
use Typecho\Router;
|
|
use Typecho\Router\ParamsDelegateInterface;
|
|
use Typecho\Widget;
|
|
use Utils\AutoP;
|
|
use Utils\Markdown;
|
|
use Widget\Base;
|
|
use Widget\Metas\Category\Rows;
|
|
use Widget\Upload;
|
|
use Widget\Users\Author;
|
|
use Widget\Metas\Category\Related as CategoryRelated;
|
|
use Widget\Metas\Tag\Related as TagRelated;
|
|
|
|
if (!defined('__TYPECHO_ROOT_DIR__')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* 内容基类
|
|
*
|
|
* @property int $cid
|
|
* @property string $title
|
|
* @property string $slug
|
|
* @property int $created
|
|
* @property int $modified
|
|
* @property string $text
|
|
* @property int $order
|
|
* @property int $authorId
|
|
* @property string $template
|
|
* @property string $type
|
|
* @property string $status
|
|
* @property string|null $password
|
|
* @property int $commentsNum
|
|
* @property bool $allowComment
|
|
* @property bool $allowPing
|
|
* @property bool $allowFeed
|
|
* @property int $parent
|
|
* @property-read Users $author
|
|
* @property-read string $permalink
|
|
* @property-read string $path
|
|
* @property-read string $url
|
|
* @property-read string $feedUrl
|
|
* @property-read string $feedRssUrl
|
|
* @property-read string $feedAtomUrl
|
|
* @property-read bool $isMarkdown
|
|
* @property-read bool $hidden
|
|
* @property-read Date $date
|
|
* @property-read string $dateWord
|
|
* @property-read string[] $directory
|
|
* @property-read array[] $tags
|
|
* @property-read array[] $categories
|
|
* @property-read string $excerpt
|
|
* @property-read string $plainExcerpt
|
|
* @property-read string $summary
|
|
* @property-read string $content
|
|
* @property-read Config $fields
|
|
* @property-read Config $attachment
|
|
* @property-read string $theId
|
|
* @property-read string $respondId
|
|
* @property-read string $commentUrl
|
|
* @property-read string $trackbackUrl
|
|
* @property-read string $responseUrl
|
|
* @property-read string $year
|
|
* @property-read string $month
|
|
* @property-read string $day
|
|
*/
|
|
class Contents extends Base implements QueryInterface, RowFilterInterface, PrimaryKeyInterface, ParamsDelegateInterface
|
|
{
|
|
/**
|
|
* @return string 获取主键
|
|
*/
|
|
public function getPrimaryKey(): string
|
|
{
|
|
return 'cid';
|
|
}
|
|
|
|
/**
|
|
* @param string $key
|
|
* @return string
|
|
*/
|
|
public function getRouterParam(string $key): string
|
|
{
|
|
switch ($key) {
|
|
case 'cid':
|
|
return $this->cid;
|
|
case 'slug':
|
|
return urlencode($this->slug);
|
|
case 'directory':
|
|
return implode('/', array_map('urlencode', $this->directory));
|
|
case 'category':
|
|
return empty($this->categories) ? '' : urlencode($this->categories[0]['slug']);
|
|
case 'year':
|
|
return $this->date->year;
|
|
case 'month':
|
|
return $this->date->month;
|
|
case 'day':
|
|
return $this->date->day;
|
|
default:
|
|
return '{' . $key . '}';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 获取查询对象
|
|
*
|
|
* @param mixed $fields
|
|
* @return Query
|
|
*/
|
|
public function select(...$fields): Query
|
|
{
|
|
return $this->db->select(...$fields)->from('table.contents');
|
|
}
|
|
|
|
/**
|
|
* 插入内容
|
|
*
|
|
* @param array $rows 内容数组
|
|
* @return integer
|
|
* @throws Exception
|
|
*/
|
|
public function insert(array $rows): int
|
|
{
|
|
/** 构建插入结构 */
|
|
$insertStruct = [
|
|
'title' => !isset($rows['title']) || strlen($rows['title']) === 0
|
|
? null : htmlspecialchars($rows['title']),
|
|
'created' => empty($rows['created']) ? $this->options->time : $rows['created'],
|
|
'modified' => $this->options->time,
|
|
'text' => Common::strBy($rows['text'] ?? null),
|
|
'order' => empty($rows['order']) ? 0 : intval($rows['order']),
|
|
'authorId' => $rows['authorId'] ?? $this->user->uid,
|
|
'template' => Common::strBy($rows['template'] ?? null),
|
|
'type' => Common::strBy($rows['type'] ?? null, 'post'),
|
|
'status' => Common::strBy($rows['status'] ?? null, 'publish'),
|
|
'password' => Common::strBy($rows['password'] ?? null),
|
|
'commentsNum' => empty($rows['commentsNum']) ? 0 : $rows['commentsNum'],
|
|
'allowComment' => !empty($rows['allowComment']) && 1 == $rows['allowComment'] ? 1 : 0,
|
|
'allowPing' => !empty($rows['allowPing']) && 1 == $rows['allowPing'] ? 1 : 0,
|
|
'allowFeed' => !empty($rows['allowFeed']) && 1 == $rows['allowFeed'] ? 1 : 0,
|
|
'parent' => empty($rows['parent']) ? 0 : intval($rows['parent'])
|
|
];
|
|
|
|
if (!empty($rows['cid'])) {
|
|
$insertStruct['cid'] = $rows['cid'];
|
|
}
|
|
|
|
/** 首先插入部分数据 */
|
|
$insertId = $this->db->query($this->db->insert('table.contents')->rows($insertStruct));
|
|
|
|
/** 更新缩略名 */
|
|
if ($insertId > 0) {
|
|
$this->applySlug(Common::strBy($rows['slug'] ?? null), $insertId, $insertStruct['title']);
|
|
}
|
|
|
|
return $insertId;
|
|
}
|
|
|
|
/**
|
|
* 为内容应用缩略名
|
|
*
|
|
* @param string|null $slug 缩略名
|
|
* @param mixed $cid 内容id
|
|
* @param string $title 标题
|
|
* @return string
|
|
* @throws Exception
|
|
*/
|
|
public function applySlug(?string $slug, $cid, string $title = ''): string
|
|
{
|
|
if ($cid instanceof Query) {
|
|
$cid = $this->db->fetchObject($cid->select('cid')
|
|
->from('table.contents')->limit(1))->cid;
|
|
}
|
|
|
|
/** 生成一个非空的缩略名 */
|
|
if ((!isset($slug) || strlen($slug) === 0) && preg_match_all("/\w+/", $title, $matches)) {
|
|
$slug = implode('-', $matches[0]);
|
|
}
|
|
|
|
$slug = Common::slugName($slug, $cid);
|
|
$result = $slug;
|
|
|
|
/** 对草稿的slug做特殊处理 */
|
|
$draft = $this->db->fetchObject($this->db->select('type', 'parent')
|
|
->from('table.contents')->where('cid = ?', $cid));
|
|
|
|
if ('revision' === $draft->type && $draft->parent) {
|
|
$result = '@' . $result;
|
|
}
|
|
|
|
/** 判断是否在数据库中已经存在 */
|
|
$count = 1;
|
|
while (
|
|
$this->db->fetchObject($this->db->select(['COUNT(cid)' => 'num'])
|
|
->from('table.contents')->where('slug = ? AND cid <> ?', $result, $cid))->num > 0
|
|
) {
|
|
$result = $slug . '-' . $count;
|
|
$count++;
|
|
}
|
|
|
|
$this->db->query($this->db->update('table.contents')->rows(['slug' => $result])
|
|
->where('cid = ?', $cid));
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 更新内容
|
|
*
|
|
* @param array $rows 内容数组
|
|
* @param Query $condition 更新条件
|
|
* @return integer
|
|
* @throws Exception
|
|
*/
|
|
public function update(array $rows, Query $condition): int
|
|
{
|
|
/** 首先验证写入权限 */
|
|
if (!$this->isWriteable(clone $condition)) {
|
|
return 0;
|
|
}
|
|
|
|
/** 构建更新结构 */
|
|
$preUpdateStruct = [
|
|
'title' => !isset($rows['title']) || strlen($rows['title']) === 0
|
|
? null : htmlspecialchars($rows['title']),
|
|
'order' => empty($rows['order']) ? 0 : intval($rows['order']),
|
|
'text' => Common::strBy($rows['text'] ?? null),
|
|
'template' => Common::strBy($rows['template'] ?? null),
|
|
'type' => Common::strBy($rows['type'] ?? null, 'post'),
|
|
'status' => Common::strBy($rows['status'] ?? null, 'publish'),
|
|
'password' => Common::strBy($rows['password'] ?? null),
|
|
'allowComment' => !empty($rows['allowComment']) && 1 == $rows['allowComment'] ? 1 : 0,
|
|
'allowPing' => !empty($rows['allowPing']) && 1 == $rows['allowPing'] ? 1 : 0,
|
|
'allowFeed' => !empty($rows['allowFeed']) && 1 == $rows['allowFeed'] ? 1 : 0,
|
|
'parent' => empty($rows['parent']) ? 0 : intval($rows['parent'])
|
|
];
|
|
|
|
$updateStruct = [];
|
|
foreach ($rows as $key => $val) {
|
|
if (array_key_exists($key, $preUpdateStruct)) {
|
|
$updateStruct[$key] = $preUpdateStruct[$key];
|
|
}
|
|
}
|
|
|
|
/** 更新创建时间 */
|
|
if (isset($rows['created'])) {
|
|
$updateStruct['created'] = $rows['created'];
|
|
}
|
|
|
|
$updateStruct['modified'] = $this->options->time;
|
|
|
|
/** 首先插入部分数据 */
|
|
$updateCondition = clone $condition;
|
|
$updateRows = $this->db->query($condition->update('table.contents')->rows($updateStruct));
|
|
|
|
/** 更新缩略名 */
|
|
if ($updateRows > 0 && isset($rows['slug'])) {
|
|
$this->applySlug(strlen($rows['slug']) === 0 ? null : $rows['slug'], $updateCondition);
|
|
}
|
|
|
|
return $updateRows;
|
|
}
|
|
|
|
/**
|
|
* 内容是否可以被修改
|
|
*
|
|
* @param Query $condition 条件
|
|
* @return bool
|
|
* @throws Exception
|
|
*/
|
|
public function isWriteable(Query $condition): bool
|
|
{
|
|
$post = $this->db->fetchRow($condition->select('authorId')->from('table.contents')->limit(1));
|
|
return $post && ($this->user->pass('editor', true) || $post['authorId'] == $this->user->uid);
|
|
}
|
|
|
|
/**
|
|
* 删除内容
|
|
*
|
|
* @param Query $condition 查询对象
|
|
* @return integer
|
|
* @throws Exception
|
|
*/
|
|
public function delete(Query $condition): int
|
|
{
|
|
return $this->db->query($condition->delete('table.contents'));
|
|
}
|
|
|
|
/**
|
|
* 按照条件计算内容数量
|
|
*
|
|
* @param Query $condition 查询对象
|
|
* @return integer
|
|
* @throws Exception
|
|
*/
|
|
public function size(Query $condition): int
|
|
{
|
|
return $this->db->fetchObject($condition
|
|
->select(['COUNT(DISTINCT table.contents.cid)' => 'num'])
|
|
->from('table.contents')
|
|
->cleanAttribute('group'))->num;
|
|
}
|
|
|
|
/**
|
|
* 获取当前所有自定义模板
|
|
*
|
|
* @return array
|
|
*/
|
|
public function getTemplates(): array
|
|
{
|
|
$files = glob($this->options->themeFile($this->options->theme, '*.php'));
|
|
$result = [];
|
|
|
|
foreach ($files as $file) {
|
|
$info = Plugin::parseInfo($file);
|
|
$file = basename($file);
|
|
|
|
if ('index.php' != $file && 'custom' == $info['title']) {
|
|
$result[$file] = $info['description'];
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 将每行的值压入堆栈
|
|
*
|
|
* @param array $value 每行的值
|
|
* @return array
|
|
*/
|
|
public function push(array $value): array
|
|
{
|
|
$value = $this->filter($value);
|
|
return parent::push($value);
|
|
}
|
|
|
|
/**
|
|
* 通用过滤器
|
|
*
|
|
* @param array $row 需要过滤的行数据
|
|
* @return array
|
|
*/
|
|
public function filter(array $row): array
|
|
{
|
|
/** 处理默认空值 */
|
|
$row['title'] = $row['title'] ?? '';
|
|
$row['text'] = $row['text'] ?? '';
|
|
$row['slug'] = $row['slug'] ?? '';
|
|
$row['password'] = $row['password'] ?? '';
|
|
$row['date'] = new Date($row['created']);
|
|
|
|
return Contents::pluginHandle()->filter('filter', $row, $this);
|
|
}
|
|
|
|
/**
|
|
* 输出文章发布日期
|
|
*
|
|
* @param string|null $format 日期格式
|
|
*/
|
|
public function date(?string $format = null)
|
|
{
|
|
echo $this->date->format(empty($format) ? $this->options->postDateFormat : $format);
|
|
}
|
|
|
|
/**
|
|
* 输出文章内容
|
|
*
|
|
* @param mixed $more 文章截取后缀
|
|
*/
|
|
public function content($more = false)
|
|
{
|
|
echo false !== $more && false !== strpos($this->text, '<!--more-->') ?
|
|
$this->excerpt
|
|
. "<p class=\"more\"><a href=\"{$this->permalink}\" title=\"{$this->title}\">{$more}</a></p>"
|
|
: $this->content;
|
|
}
|
|
|
|
/**
|
|
* 输出文章摘要
|
|
*
|
|
* @param integer $length 摘要截取长度
|
|
* @param string $trim 摘要后缀
|
|
*/
|
|
public function excerpt(int $length = 100, string $trim = '...')
|
|
{
|
|
echo Common::subStr(strip_tags($this->excerpt), 0, $length, $trim);
|
|
}
|
|
|
|
/**
|
|
* 输出标题
|
|
*
|
|
* @param integer $length 标题截取长度
|
|
* @param string $trim 截取后缀
|
|
*/
|
|
public function title(int $length = 0, string $trim = '...')
|
|
{
|
|
$title = Contents::pluginHandle()->trigger($plugged)->filter('title', $this->title, $this);
|
|
if (!$plugged) {
|
|
echo $length > 0 ? Common::subStr($this->title, 0, $length, $trim) : $this->title;
|
|
} else {
|
|
echo $title;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 输出文章评论数
|
|
*
|
|
* @param ...$args
|
|
*/
|
|
public function commentsNum(...$args)
|
|
{
|
|
if (empty($args)) {
|
|
$args[] = '%d';
|
|
}
|
|
|
|
$num = intval($this->commentsNum);
|
|
echo sprintf($args[$num] ?? array_pop($args), $num);
|
|
}
|
|
|
|
/**
|
|
* 获取文章权限
|
|
*
|
|
* @param ...$permissions
|
|
*/
|
|
public function allow(...$permissions): bool
|
|
{
|
|
$allow = true;
|
|
|
|
foreach ($permissions as $permission) {
|
|
$permission = strtolower($permission);
|
|
|
|
if ('edit' == $permission) {
|
|
$allow &= ($this->user->pass('editor', true) || $this->authorId == $this->user->uid);
|
|
} else {
|
|
/** 对自动关闭反馈功能的支持 */
|
|
if (
|
|
('ping' == $permission || 'comment' == $permission) && $this->options->commentsPostTimeout > 0 &&
|
|
$this->options->commentsAutoClose
|
|
) {
|
|
if ($this->options->time - $this->created > $this->options->commentsPostTimeout) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
$allow &= ($this->row['allow' . ucfirst($permission)] == 1) && !$this->hidden;
|
|
}
|
|
}
|
|
|
|
return $allow;
|
|
}
|
|
|
|
/**
|
|
* 输出文章分类
|
|
*
|
|
* @param string $split 多个分类之间分隔符
|
|
* @param boolean $link 是否输出链接
|
|
* @param string|null $default 如果没有则输出
|
|
*/
|
|
public function category(string $split = ',', bool $link = true, ?string $default = null)
|
|
{
|
|
if (!empty($this->categories)) {
|
|
$result = [];
|
|
|
|
foreach ($this->categories as $category) {
|
|
$result[] = $link ? "<a href=\"{$category['permalink']}\">{$category['name']}</a>" : $category['name'];
|
|
}
|
|
|
|
echo implode($split, $result);
|
|
} else {
|
|
echo $default;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 输出文章多级分类
|
|
*
|
|
* @param string $split 多个分类之间分隔符
|
|
* @param boolean $link 是否输出链接
|
|
* @param string|null $default 如果没有则输出
|
|
* @throws Widget\Exception
|
|
*/
|
|
public function directory(string $split = '/', bool $link = true, ?string $default = null)
|
|
{
|
|
$category = $this->categories[0];
|
|
$directory = Rows::alloc()->getAllParents($category['mid']);
|
|
$directory[] = $category;
|
|
|
|
if ($directory) {
|
|
$result = [];
|
|
|
|
foreach ($directory as $category) {
|
|
$result[] = $link ? '<a href="' . $category['permalink'] . '">'
|
|
. $category['name'] . '</a>' : $category['name'];
|
|
}
|
|
|
|
echo implode($split, $result);
|
|
} else {
|
|
echo $default;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 输出文章标签
|
|
*
|
|
* @param string $split 多个标签之间分隔符
|
|
* @param boolean $link 是否输出链接
|
|
* @param string|null $default 如果没有则输出
|
|
*/
|
|
public function tags(string $split = ',', bool $link = true, ?string $default = null)
|
|
{
|
|
if (!empty($this->tags)) {
|
|
$result = [];
|
|
|
|
foreach ($this->tags as $tag) {
|
|
$result[] = $link ? "<a href=\"{$tag['permalink']}\">{$tag['name']}</a>" : $tag['name'];
|
|
}
|
|
|
|
echo implode($split, $result);
|
|
} else {
|
|
echo $default;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 输出当前作者
|
|
*
|
|
* @param string $item 需要输出的项目
|
|
*/
|
|
public function author(string $item = 'screenName')
|
|
{
|
|
if ($this->have()) {
|
|
echo $this->author->{$item};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___title(): string
|
|
{
|
|
return $this->hidden ? _t('此内容被密码保护') : $this->row['title'];
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___text(): string
|
|
{
|
|
if ('attachment' == $this->type) {
|
|
if ($this->attachment->isImage) {
|
|
return '<img src="' . $this->attachment->url . '" alt="' .
|
|
$this->title . '" />';
|
|
} else {
|
|
return '<a href="' . $this->attachment->url . '" title="' .
|
|
$this->title . '">' . $this->title . '</a>';
|
|
}
|
|
} elseif ($this->hidden) {
|
|
return '<form class="protected" action="' . $this->security->getTokenUrl($this->permalink)
|
|
. '" method="post">' .
|
|
'<p class="word">' . _t('请输入密码访问') . '</p>' .
|
|
'<p><input type="password" class="text" name="protectPassword" />
|
|
<input type="hidden" name="protectCID" value="' . $this->cid . '" />
|
|
<input type="submit" class="submit" value="' . _t('提交') . '" /></p>' .
|
|
'</form>';
|
|
}
|
|
|
|
return $this->isMarkdown ? substr($this->row['text'], 15) : $this->row['text'];
|
|
}
|
|
|
|
/**
|
|
* @return bool
|
|
*/
|
|
protected function ___isMarkdown(): bool
|
|
{
|
|
return 0 === strpos($this->row['text'], '<!--markdown-->');
|
|
}
|
|
|
|
/**
|
|
* 是否为隐藏文章
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function ___hidden(): bool
|
|
{
|
|
if (
|
|
strlen($this->password) > 0 &&
|
|
$this->password !== Cookie::get('protectPassword_' . $this->cid) &&
|
|
$this->authorId != $this->user->uid &&
|
|
!$this->user->pass('editor', true)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___path(): string
|
|
{
|
|
return Router::url($this->type, $this);
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___permalink(): string
|
|
{
|
|
return Common::url($this->path, $this->options->index);
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___url(): string
|
|
{
|
|
return $this->permalink;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___feedUrl(): string
|
|
{
|
|
return Router::url($this->type, $this, $this->options->feedUrl);
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___feedRssUrl(): string
|
|
{
|
|
return Router::url($this->type, $this, $this->options->feedRssUrl);
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___feedAtomUrl(): string
|
|
{
|
|
return Router::url($this->type, $this, $this->options->feedAtomUrl);
|
|
}
|
|
|
|
/**
|
|
* 多级目录结构
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function ___directory(): array
|
|
{
|
|
$directory = [];
|
|
|
|
if (!empty($this->categories)) {
|
|
$directory = Rows::alloc()->getAllParentsSlug($this->categories[0]['mid']);
|
|
$directory[] = $this->categories[0]['slug'];
|
|
}
|
|
|
|
return $directory;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___category(): string
|
|
{
|
|
return empty($this->categories) ? '' : $this->categories[0]['slug'];
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
protected function ___categories(): array
|
|
{
|
|
return CategoryRelated::allocWithAlias($this->cid, ['cid' => $this->cid])
|
|
->toArray(['mid', 'name', 'slug', 'description', 'order', 'parent', 'count', 'permalink']);
|
|
}
|
|
|
|
/**
|
|
* 将tags取出
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function ___tags(): array
|
|
{
|
|
return TagRelated::allocWithAlias($this->cid, ['cid' => $this->cid])
|
|
->toArray(['mid', 'name', 'slug', 'description', 'count', 'permalink']);
|
|
}
|
|
|
|
/**
|
|
* 文章作者
|
|
*
|
|
* @return Users
|
|
*/
|
|
protected function ___author(): Users
|
|
{
|
|
return Author::allocWithAlias($this->cid, ['uid' => $this->authorId]);
|
|
}
|
|
|
|
/**
|
|
* 获取词义化日期
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function ___dateWord(): string
|
|
{
|
|
return $this->date->word();
|
|
}
|
|
|
|
/**
|
|
* 对文章的简短纯文本描述
|
|
*
|
|
* @deprecated
|
|
* @return string|null
|
|
*/
|
|
protected function ___description(): ?string
|
|
{
|
|
return $this->plainExcerpt;
|
|
}
|
|
|
|
/**
|
|
* @return Config|null
|
|
*/
|
|
protected function ___attachment(): ?Config
|
|
{
|
|
if ('attachment' == $this->type) {
|
|
$content = json_decode($this->row['text'], true);
|
|
|
|
//增加数据信息
|
|
$attachment = new Config($content);
|
|
$attachment->isImage = in_array($content['type'], [
|
|
'jpg', 'jpeg', 'gif', 'png', 'tiff', 'bmp', 'webp', 'avif'
|
|
]);
|
|
$attachment->url = Upload::attachmentHandle($attachment);
|
|
|
|
return $attachment;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* ___fields
|
|
*
|
|
* @return Config
|
|
* @throws Exception
|
|
*/
|
|
protected function ___fields(): Config
|
|
{
|
|
$fields = [];
|
|
$rows = $this->db->fetchAll($this->db->select()->from('table.fields')
|
|
->where('cid = ?', $this->cid));
|
|
|
|
foreach ($rows as $row) {
|
|
$value = 'json' == $row['type'] ? json_decode($row['str_value'], true) : $row[$row['type'] . '_value'];
|
|
$fields[$row['name']] = $value;
|
|
}
|
|
|
|
return new Config($fields);
|
|
}
|
|
|
|
/**
|
|
* 获取文章内容摘要
|
|
*
|
|
* @return string|null
|
|
*/
|
|
protected function ___excerpt(): ?string
|
|
{
|
|
if ($this->hidden) {
|
|
return $this->text;
|
|
}
|
|
|
|
$content = Contents::pluginHandle()->filter('excerpt', $this->content, $this);
|
|
[$excerpt] = explode('<!--more-->', $content);
|
|
|
|
return Common::fixHtml(Contents::pluginHandle()->filter('excerptEx', $excerpt, $this));
|
|
}
|
|
|
|
/**
|
|
* 对文章的简短纯文本描述
|
|
*
|
|
* @return string|null
|
|
*/
|
|
protected function ___plainExcerpt(): ?string
|
|
{
|
|
$plainText = str_replace("\n", '', trim(strip_tags($this->excerpt)));
|
|
$plainText = $plainText ?: $this->title;
|
|
return Common::subStr($plainText, 0, 100);
|
|
}
|
|
|
|
/**
|
|
* markdown
|
|
*
|
|
* @param string|null $text
|
|
* @return string|null
|
|
*/
|
|
protected function markdown(?string $text): ?string
|
|
{
|
|
$html = Contents::pluginHandle()->trigger($parsed)->filter('markdown', $text);
|
|
|
|
if (!$parsed) {
|
|
$html = Markdown::convert($text);
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* autoP
|
|
*
|
|
* @param string|null $text
|
|
* @return string|null
|
|
*/
|
|
protected function autoP(?string $text): ?string
|
|
{
|
|
$html = Contents::pluginHandle()->trigger($parsed)->filter('autoP', $text);
|
|
|
|
if (!$parsed && $text) {
|
|
static $parser;
|
|
|
|
if (empty($parser)) {
|
|
$parser = new AutoP();
|
|
}
|
|
|
|
$html = $parser->parse($text);
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* 获取文章内容
|
|
*
|
|
* @return string|null
|
|
*/
|
|
protected function ___content(): ?string
|
|
{
|
|
if ($this->hidden) {
|
|
return $this->text;
|
|
}
|
|
|
|
$content = Contents::pluginHandle()->trigger($plugged)->filter('content', $this->text, $this);
|
|
|
|
if (!$plugged) {
|
|
$content = $this->isMarkdown ? $this->markdown($content)
|
|
: $this->autoP($content);
|
|
}
|
|
|
|
return Contents::pluginHandle()->filter('contentEx', $content, $this);
|
|
}
|
|
|
|
/**
|
|
* 输出文章的第一行作为摘要
|
|
*
|
|
* @return string|null
|
|
*/
|
|
protected function ___summary(): ?string
|
|
{
|
|
$content = $this->content;
|
|
$parts = preg_split("/(<\/\s*(?:p|blockquote|q|pre|table)\s*>)/i", $content, 2, PREG_SPLIT_DELIM_CAPTURE);
|
|
if (!empty($parts)) {
|
|
$content = $parts[0] . $parts[1];
|
|
}
|
|
|
|
return $content;
|
|
}
|
|
|
|
/**
|
|
* 锚点id
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function ___theId(): string
|
|
{
|
|
return $this->type . '-' . $this->cid;
|
|
}
|
|
|
|
/**
|
|
* 回复框id
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function ___respondId(): string
|
|
{
|
|
return 'respond-' . $this->theId;
|
|
}
|
|
|
|
/**
|
|
* 评论地址
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function ___commentUrl(): string
|
|
{
|
|
/** 生成反馈地址 */
|
|
/** 评论 */
|
|
return Router::url(
|
|
'feedback',
|
|
['type' => 'comment', 'permalink' => $this->path],
|
|
$this->options->index
|
|
);
|
|
}
|
|
|
|
/**
|
|
* trackback地址
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function ___trackbackUrl(): string
|
|
{
|
|
return Router::url(
|
|
'feedback',
|
|
['type' => 'trackback', 'permalink' => $this->path],
|
|
$this->options->index
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 回复地址
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function ___responseUrl(): string
|
|
{
|
|
return $this->permalink . '#' . $this->respondId;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___year(): string
|
|
{
|
|
return $this->date->year;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___month(): string
|
|
{
|
|
return $this->date->month;
|
|
}
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
protected function ___day(): string
|
|
{
|
|
return $this->date->day;
|
|
}
|
|
}
|