Files
MyTrack/Action.php
2026-02-23 19:45:59 +08:00

1133 lines
39 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* MyTrack 动作处理器
*
* @package MyTrack
*/
class MyTrack_Action extends Typecho_Widget implements Widget_Interface_Do
{
/**
* 数据库连接
*
* @access private
* @var PDO
*/
private $db;
/**
* 构造函数
*
* @access public
* @param mixed $request request对象
* @param mixed $response response对象
* @param mixed $params 参数列表
* @return void
*/
public function __construct($request, $response, $params = NULL)
{
parent::__construct($request, $response, $params);
$this->db = MyTrack_Plugin::getDbConnection();
}
/**
* 动作入口
*
* @access public
* @return void
*/
public function action()
{
$this->widget('Widget_User')->pass('administrator');
$this->on($this->request->is('do=add'))->add();
$this->on($this->request->is('do=update'))->update();
$this->on($this->request->is('do=delete'))->delete();
$this->on($this->request->is('do=get'))->get();
$this->on($this->request->is('do=getAll'))->getAll();
$this->on($this->request->is('do=getOne'))->get();
$this->on($this->request->is('do=list'))->list();
$this->on($this->request->is('do=batchDelete'))->batchDelete();
$this->on($this->request->is('do=import'))->import();
$this->on($this->request->is('do=export'))->export();
$this->on($this->request->is('do=exportSimple'))->exportSimple();
$this->on($this->request->is('do=getArticleImages'))->getArticleImages();
$this->on($this->request->is('do=getById'))->getById();
$this->on($this->request->is('do=getRelatedArticlesInfo'))->getRelatedArticlesInfo();
// 默认返回列表
$this->response->throwJson(array(
'success' => false,
'message' => '无效的操作'
));
}
/**
* 检测重复数据(基于经纬度)
*
* @access private
* @param float $latitude 纬度
* @param float $longitude 经度
* @param int $excludeId 要排除的ID更新时使用
* @return array|false 返回重复的数据信息false表示无重复
*/
private function checkDuplicate($latitude, $longitude, $excludeId = null)
{
try {
// 根据经纬度进行检测使用较高精度0.000001度约等于0.1米)
$sql = "SELECT id, name FROM plugin_track_footprint
WHERE ABS(latitude - ?) < 0.000001
AND ABS(longitude - ?) < 0.000001";
$params = array($latitude, $longitude);
if ($excludeId !== null) {
$sql .= " AND id != ?";
$params[] = $excludeId;
}
$sql .= " LIMIT 1";
$stmt = $this->db->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
return $result ? $result : false;
} catch (PDOException $e) {
error_log('检测重复数据失败: ' . $e->getMessage());
return false;
}
}
public function add()
{
// 原有的参数获取
$latitude = $this->request->get('latitude');
$longitude = $this->request->get('longitude');
$name = $this->request->get('name');
$description = $this->request->get('description');
$tags = $this->request->get('tags');
$article_cid = $this->request->get('article_cid');
$urlLabel = $this->request->get('urlLabel');
$url = $this->request->get('url');
$photos = $this->request->get('photos');
$date = $this->request->get('date');
// 新增字段
$address = $this->request->get('address');
$location_type = $this->request->get('location_type');
$rating_level = $this->request->get('rating_level', 0);
$categories = $this->request->get('categories');
$review = $this->request->get('review');
$markerColor = $this->request->get('markerColor');
$related_articles = $this->request->get('related_articles');
$highlights = $this->request->get('highlights');
// 如果提供了日期,确保格式为 YYYY-MM-DD HH:MM:SS
if (!empty($date)) {
$date = date('Y-m-d H:i:s', strtotime($date));
}
// 验证必填字段
if (empty($latitude) || empty($longitude) || empty($name)) {
$this->response->throwJson(array(
'success' => false,
'message' => '经纬度和地点名称不能为空'
));
}
// 检查重复数据(基于经纬度)
$duplicate = $this->checkDuplicate($latitude, $longitude);
if ($duplicate !== false && isset($duplicate['name']) && isset($duplicate['id'])) {
$this->response->throwJson(array(
'success' => false,
'message' => "该位置已存在地点:{$duplicate['name']}ID: {$duplicate['id']}),请勿重复添加"
));
}
try {
// 如果提供了文章CID获取文章信息和图片
if (!empty($article_cid)) {
$articleInfo = MyTrack_Plugin::getArticleInfo($article_cid);
// 如果没有提供图片链接尝试从文章中提取限制4张
if (empty($photos) && !empty($articleInfo['images'])) {
$limitedImages = array_slice($articleInfo['images'], 0, 4);
$photos = implode(',', $limitedImages);
}
// 如果没有提供文章标题,尝试从文章中获取
if (empty($urlLabel) && !empty($articleInfo['title'])) {
$urlLabel = $articleInfo['title'];
}
// 如果没有提供文章链接,尝试从文章中获取
if (empty($url) && !empty($articleInfo['link'])) {
$url = $articleInfo['link'];
}
// 如果没有提供标签,尝试从文章中获取
if (empty($tags) && !empty($articleInfo['tags'])) {
$tags = implode(',', $articleInfo['tags']);
}
}
$stmt = $this->db->prepare("INSERT INTO plugin_track_footprint
(latitude, longitude, name, address, location_type, rating_level, categories, review, description, tags, article_cid, urlLabel, url, photos, date, markerColor, related_articles, highlights)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute(array(
$latitude,
$longitude,
$name,
$address,
$location_type,
$rating_level,
$categories,
$review,
$description,
$tags,
$article_cid,
$urlLabel,
$url,
$photos,
$date,
$markerColor,
$related_articles,
$highlights
));
$id = $this->db->lastInsertId();
// 清除足迹缓存
$this->clearFootprintCache();
$this->response->throwJson(array(
'success' => true,
'message' => '足迹添加成功',
'data' => array(
'id' => $id
)
));
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '添加失败: ' . $e->getMessage()
));
}
}
public function update()
{
$id = $this->request->get('id');
$latitude = $this->request->get('latitude');
$longitude = $this->request->get('longitude');
$name = $this->request->get('name');
$description = $this->request->get('description');
$tags = $this->request->get('tags');
$article_cid = $this->request->get('article_cid');
$urlLabel = $this->request->get('urlLabel');
$url = $this->request->get('url');
$photos = $this->request->get('photos');
$date = $this->request->get('date');
// 新增字段
$address = $this->request->get('address');
$location_type = $this->request->get('location_type');
$rating_level = $this->request->get('rating_level', 0);
$categories = $this->request->get('categories');
$review = $this->request->get('review');
$markerColor = $this->request->get('markerColor');
$related_articles = $this->request->get('related_articles');
$highlights = $this->request->get('highlights');
// 验证必填字段
if (empty($id) || empty($latitude) || empty($longitude) || empty($name)) {
$this->response->throwJson(array(
'success' => false,
'message' => 'ID、经纬度和地点名称不能为空'
));
}
// 检查重复数据(基于经纬度,排除自身)
$duplicate = $this->checkDuplicate($latitude, $longitude, $id);
if ($duplicate !== false && isset($duplicate['name']) && isset($duplicate['id'])) {
$this->response->throwJson(array(
'success' => false,
'message' => "该位置已存在其他地点:{$duplicate['name']}ID: {$duplicate['id']}),请修改经纬度"
));
}
try {
// 如果提供了文章CID获取文章信息和图片
if (!empty($article_cid)) {
$articleInfo = MyTrack_Plugin::getArticleInfo($article_cid);
if (empty($photos) && !empty($articleInfo['images'])) {
$limitedImages = array_slice($articleInfo['images'], 0, 4);
$photos = implode(',', $limitedImages);
}
if (empty($urlLabel) && !empty($articleInfo['title'])) {
$urlLabel = $articleInfo['title'];
}
if (empty($url) && !empty($articleInfo['link'])) {
$url = $articleInfo['link'];
}
if (empty($tags) && !empty($articleInfo['tags'])) {
$tags = implode(',', $articleInfo['tags']);
}
}
$stmt = $this->db->prepare("UPDATE plugin_track_footprint
SET latitude = ?, longitude = ?, name = ?, address = ?, location_type = ?, rating_level = ?, categories = ?, review = ?, description = ?, tags = ?, article_cid = ?,
urlLabel = ?, url = ?, photos = ?, date = ?, markerColor = ?, related_articles = ?, highlights = ?
WHERE id = ?");
$result = $stmt->execute(array(
$latitude,
$longitude,
$name,
$address,
$location_type,
$rating_level,
$categories,
$review,
$description,
$tags,
$article_cid,
$urlLabel,
$url,
$photos,
$date,
$markerColor,
$related_articles,
$highlights,
$id
));
if ($result) {
// 清除足迹缓存
$this->clearFootprintCache();
$this->response->throwJson(array(
'success' => true,
'message' => '足迹更新成功'
));
} else {
$this->response->throwJson(array(
'success' => false,
'message' => '足迹不存在或更新失败'
));
}
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '更新失败: ' . $e->getMessage()
));
}
}
/**
* 获取关联文章信息
*
* @access public
* @return void
*/
public function getRelatedArticlesInfo()
{
$related_articles = $this->request->get('related_articles');
if (empty($related_articles)) {
$this->response->throwJson(array(
'success' => false,
'message' => '关联文章不能为空'
));
}
try {
$result = MyTrack_Plugin::getRelatedArticlesInfo($related_articles);
$this->response->throwJson(array(
'success' => true,
'data' => $result
));
} catch (Exception $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '获取关联文章信息失败: ' . $e->getMessage()
));
}
}
/**
* 批量删除足迹
*
* @access public
* @return void
*/
public function batchDelete()
{
$ids = $this->request->filter('int')->getArray('footprint');
if (empty($ids)) {
$rawIds = $this->request->get('footprint');
if (!empty($rawIds)) {
$ids = is_array($rawIds) ? $rawIds : array($rawIds);
$ids = array_map('intval', $ids);
}
}
if (empty($ids) || !is_array($ids)) {
$this->response->throwJson(array(
'success' => false,
'message' => '请选择要删除的足迹'
));
}
$ids = array_filter($ids, function($id) {
return is_numeric($id) && $id > 0;
});
if (empty($ids)) {
$this->response->throwJson(array(
'success' => false,
'message' => '无效的足迹ID'
));
}
try {
$placeholders = implode(',', array_fill(0, count($ids), '?'));
$stmt = $this->db->prepare("DELETE FROM plugin_track_footprint WHERE id IN ($placeholders)");
$result = $stmt->execute($ids);
if ($result) {
$this->clearFootprintCache();
$this->response->throwJson(array(
'success' => true,
'message' => '足迹删除成功'
));
} else {
$this->response->throwJson(array(
'success' => false,
'message' => '删除失败,请检查足迹是否存在'
));
}
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '删除失败: ' . $e->getMessage()
));
}
}
/**
* 删除足迹
*
* @access public
* @return void
*/
public function delete()
{
$id = $this->request->get('id');
if (empty($id)) {
$this->response->throwJson(array(
'success' => false,
'message' => 'ID不能为空'
));
}
try {
$stmt = $this->db->prepare("DELETE FROM plugin_track_footprint WHERE id = ?");
$result = $stmt->execute(array($id));
if ($result) {
$this->clearFootprintCache();
$this->response->throwJson(array(
'success' => true,
'message' => '足迹删除成功'
));
} else {
$this->response->throwJson(array(
'success' => false,
'message' => '足迹不存在或删除失败'
));
}
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '删除失败: ' . $e->getMessage()
));
}
}
/**
* 获取单个足迹
*
* @access public
* @return void
*/
public function get()
{
$id = $this->request->get('id');
if (empty($id)) {
$this->response->throwJson(array(
'success' => false,
'message' => 'ID不能为空'
));
}
try {
$stmt = $this->db->prepare("SELECT * FROM plugin_track_footprint WHERE id = ?");
$stmt->execute(array($id));
$footprint = $stmt->fetch(PDO::FETCH_ASSOC);
if ($footprint) {
if (!empty($footprint['related_articles'])) {
$footprint['related_articles_info'] = MyTrack_Plugin::getRelatedArticlesInfo($footprint['related_articles']);
}
$this->response->throwJson(array(
'success' => true,
'data' => $footprint
));
} else {
$this->response->throwJson(array(
'success' => false,
'message' => '足迹不存在'
));
}
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '查询失败: ' . $e->getMessage()
));
}
}
/**
* 通过ID获取单个足迹公开接口
*
* @access public
* @return void
*/
public function getById()
{
$id = $this->request->get('id');
if (empty($id)) {
$this->response->throwJson(array(
'success' => false,
'message' => 'ID不能为空'
));
}
try {
$stmt = $this->db->prepare("SELECT * FROM plugin_track_footprint WHERE id = ?");
$stmt->execute(array($id));
$footprint = $stmt->fetch(PDO::FETCH_ASSOC);
if ($footprint) {
if (!empty($footprint['categories'])) {
$footprint['categories'] = explode(',', $footprint['categories']);
} else {
$footprint['categories'] = array();
}
if (!empty($footprint['highlights'])) {
$footprint['highlights'] = explode(',', $footprint['highlights']);
} else {
$footprint['highlights'] = array();
}
if (!empty($footprint['article_cid'])) {
$articleInfo = MyTrack_Plugin::getArticleInfo($footprint['article_cid']);
if (!empty($articleInfo['title']) && empty($footprint['urlLabel'])) {
$footprint['urlLabel'] = $articleInfo['title'];
}
if (!empty($articleInfo['link']) && empty($footprint['url'])) {
$footprint['url'] = $articleInfo['link'];
}
}
if (!empty($footprint['related_articles'])) {
$footprint['related_articles_info'] = MyTrack_Plugin::getRelatedArticlesInfo($footprint['related_articles']);
}
$this->response->throwJson(array(
'success' => true,
'data' => $footprint
));
} else {
$this->response->throwJson(array(
'success' => false,
'message' => '足迹不存在'
));
}
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '查询失败: ' . $e->getMessage()
));
}
}
/**
* 获取足迹列表
*
* @access public
* @return void
*/
public function list()
{
$page = $this->request->get('page', 1);
$size = $this->request->get('size', 10);
$offset = ($page - 1) * $size;
try {
$countStmt = $this->db->query("SELECT COUNT(*) FROM plugin_track_footprint");
$total = $countStmt->fetchColumn();
$stmt = $this->db->prepare("SELECT * FROM plugin_track_footprint
ORDER BY date DESC, created_at DESC
LIMIT ? OFFSET ?");
$stmt->execute(array($size, $offset));
$footprints = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($footprints as &$footprint) {
if (!empty($footprint['related_articles'])) {
$footprint['related_articles_info'] = MyTrack_Plugin::getRelatedArticlesInfo($footprint['related_articles']);
}
}
$this->response->throwJson(array(
'success' => true,
'data' => array(
'total' => $total,
'page' => $page,
'size' => $size,
'pages' => ceil($total / $size),
'items' => $footprints
)
));
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '查询失败: ' . $e->getMessage()
));
}
}
/**
* 导入足迹
*
* @access public
* @return void
*/
public function import()
{
if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
$this->response->throwJson(array(
'success' => false,
'message' => '请上传有效的文件'
));
}
$file = $_FILES['file'];
$fileType = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($fileType, array('json'))) {
$this->response->throwJson(array(
'success' => false,
'message' => '只支持JSON格式的文件'
));
}
try {
$content = file_get_contents($file['tmp_name']);
$encoding = mb_detect_encoding($content, array('UTF-8', 'GBK', 'GB2312', 'ASCII'), true);
if ($encoding !== 'UTF-8' && $encoding !== false) {
$content = mb_convert_encoding($content, 'UTF-8', $encoding);
}
$data = json_decode($content, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception('JSON格式错误: ' . json_last_error_msg());
}
if (!is_array($data)) {
throw new Exception('JSON格式不正确应该是一个数组');
}
$successCount = 0;
$errorCount = 0;
$errors = array();
$this->db->beginTransaction();
foreach ($data as $index => $item) {
try {
if (empty($item['latitude']) || empty($item['longitude']) || empty($item['name'])) {
$errors[] = "" . ($index + 1) . "行: 缺少经纬度或地点名称";
$errorCount++;
continue;
}
// 导入时检查重复数据(基于经纬度)
$duplicate = $this->checkDuplicate($item['latitude'], $item['longitude']);
if ($duplicate !== false && isset($duplicate['name']) && isset($duplicate['id'])) {
$errors[] = "" . ($index + 1) . "行: 该位置已存在地点:{$duplicate['name']}ID: {$duplicate['id']}),跳过导入";
$errorCount++;
continue;
}
$categories = '';
if (isset($item['categories'])) {
if (is_array($item['categories'])) {
$categories = implode(',', $item['categories']);
} else {
$categories = $item['categories'];
}
}
$highlights = '';
if (isset($item['highlights'])) {
if (is_array($item['highlights'])) {
$highlights = implode(',', $item['highlights']);
} else {
$highlights = $item['highlights'];
}
}
$photos = '';
if (isset($item['photos'])) {
if (is_array($item['photos'])) {
$photos = implode(',', $item['photos']);
} else {
$photos = $item['photos'];
}
}
$related_articles = '';
if (isset($item['related_articles'])) {
if (is_array($item['related_articles'])) {
$related_articles = implode(',', $item['related_articles']);
} else {
$related_articles = $item['related_articles'];
}
}
$stmt = $this->db->prepare("INSERT INTO plugin_track_footprint
(latitude, longitude, name, address, location_type, rating_level, categories, review,
description, tags, article_cid, urlLabel, url, photos, date, markerColor,
related_articles, highlights, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
$result = $stmt->execute(array(
$item['latitude'] ?? null,
$item['longitude'] ?? null,
$item['name'] ?? '',
$item['address'] ?? null,
$item['location_type'] ?? null,
$item['rating_level'] ?? 0,
$categories,
$item['review'] ?? null,
$item['description'] ?? null,
$item['tags'] ?? null,
$item['article_cid'] ?? null,
$item['urlLabel'] ?? null,
$item['url'] ?? null,
$photos,
$item['date'] ?? null,
$item['markerColor'] ?? null,
$related_articles,
$highlights,
$item['created_at'] ?? date('Y-m-d H:i:s'),
$item['updated_at'] ?? date('Y-m-d H:i:s')
));
if ($result) {
$successCount++;
} else {
$errors[] = "" . ($index + 1) . "行: 插入失败";
$errorCount++;
}
} catch (PDOException $e) {
$errorCount++;
$errors[] = "" . ($index + 1) . "行: " . $e->getMessage();
}
}
$this->db->commit();
$this->clearFootprintCache();
$this->response->throwJson(array(
'success' => true,
'message' => "导入完成,成功: {$successCount},失败: {$errorCount}",
'data' => array(
'success' => $successCount,
'error' => $errorCount,
'errors' => $errors
)
));
} catch (Exception $e) {
$this->db->rollBack();
$this->response->throwJson(array(
'success' => false,
'message' => '导入失败: ' . $e->getMessage()
));
}
}
/**
* 导出足迹
*
* @access public
* @return void
*/
public function export()
{
$format = $this->request->get('format', 'json');
if (!in_array($format, array('json'))) {
$this->response->throwJson(array(
'success' => false,
'message' => '不支持的导出格式'
));
}
try {
$stmt = $this->db->query("SELECT
id,
latitude,
longitude,
name,
address,
location_type,
rating_level,
categories,
review,
description,
tags,
article_cid,
urlLabel,
url,
photos,
date,
markerColor,
related_articles,
highlights,
created_at,
updated_at
FROM plugin_track_footprint
ORDER BY date DESC, created_at DESC");
$footprints = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($footprints)) {
$this->response->throwJson(array(
'success' => false,
'message' => '没有数据可导出'
));
}
$filename = 'mytrack_footprints_' . date('Ymd_His') . '.json';
$content = json_encode($footprints, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . strlen($content));
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
echo $content;
exit;
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '导出失败: ' . $e->getMessage()
));
}
}
/**
* 精简导出足迹
*
* @access public
* @return void
*/
public function exportSimple()
{
$format = $this->request->get('format', 'json');
if (!in_array($format, array('json'))) {
$this->response->throwJson(array(
'success' => false,
'message' => '不支持的导出格式'
));
}
try {
$stmt = $this->db->query("SELECT
name,
latitude,
longitude,
date,
url,
urlLabel,
categories,
markerColor,
photos,
related_articles,
highlights
FROM plugin_track_footprint
ORDER BY date DESC");
$footprints = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (empty($footprints)) {
$this->response->throwJson(array(
'success' => false,
'message' => '没有数据可导出'
));
}
$locations = array();
foreach ($footprints as $footprint) {
$coordinates = $footprint['longitude'] . ',' . $footprint['latitude'];
$categories = array();
if (!empty($footprint['categories'])) {
$categoryArray = explode(',', $footprint['categories']);
foreach ($categoryArray as $category) {
$category = trim($category);
switch($category) {
case 'visited':
$categories[] = '去过';
break;
case 'want':
$categories[] = '想去';
break;
case 'plan':
$categories[] = '计划';
break;
default:
$categories[] = $category;
}
}
}
$highlights = !empty($footprint['highlights']) ? explode(',', $footprint['highlights']) : array();
$photos = !empty($footprint['photos']) ? explode(',', $footprint['photos']) : array();
$relatedArticles = !empty($footprint['related_articles']) ? explode(',', $footprint['related_articles']) : array();
$locations[] = array(
'name' => $footprint['name'] ?? '',
'coordinates' => $coordinates,
'date' => $footprint['date'] ?? '',
'url' => $footprint['url'] ?? '',
'urlLabel' => $footprint['urlLabel'] ?? '',
'categories' => $categories,
'highlights' => $highlights,
'markerColor' => $footprint['markerColor'] ?? '',
'photos' => $photos,
'relatedArticles' => $relatedArticles
);
}
$exportData = array('locations' => $locations);
$filename = 'mytrack_simple_' . date('Ymd_His') . '.json';
$content = json_encode($exportData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename="' . $filename . '"');
header('Content-Length: ' . strlen($content));
header('Cache-Control: no-cache, no-store, must-revalidate');
header('Pragma: no-cache');
header('Expires: 0');
echo $content;
exit;
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '导出失败: ' . $e->getMessage()
));
}
}
/**
* 获取所有足迹(用于前台地图显示)
*
* @access public
* @return void
*/
public function getAll()
{
try {
$options = Typecho_Widget::widget('Widget_Options')->plugin('MyTrack');
$cacheExpire = isset($options->cacheExpire) && is_numeric($options->cacheExpire) && $options->cacheExpire >= 0
? intval($options->cacheExpire) * 24 * 60 * 60
: 7 * 24 * 60 * 60;
$cacheKey = 'mytrack_footprints_data';
if ($cacheExpire > 0) {
$cacheFile = __DIR__ . '/cache/' . md5($cacheKey) . '.cache';
if (file_exists($cacheFile) && filemtime($cacheFile) + $cacheExpire > time()) {
$cachedData = unserialize(file_get_contents($cacheFile));
if ($cachedData !== false) {
$this->response->throwJson(array(
'success' => true,
'data' => $cachedData,
'from_cache' => true
));
return;
}
}
}
$stmt = $this->db->query("SELECT * FROM plugin_track_footprint ORDER BY date ASC, created_at ASC");
$footprints = $stmt->fetchAll(PDO::FETCH_ASSOC);
$validFootprints = array_filter($footprints, function($footprint) {
$longitude = is_numeric($footprint['longitude']) ? floatval($footprint['longitude']) : null;
$latitude = is_numeric($footprint['latitude']) ? floatval($footprint['latitude']) : null;
return $longitude !== null && $latitude !== null &&
!is_nan($longitude) && !is_nan($latitude) &&
$longitude >= -180 && $longitude <= 180 &&
$latitude >= -90 && $latitude <= 90;
});
$validFootprints = array_values($validFootprints);
foreach ($validFootprints as &$footprint) {
if (!empty($footprint['related_articles'])) {
$footprint['related_articles_info'] = MyTrack_Plugin::getRelatedArticlesInfo($footprint['related_articles']);
}
}
if ($cacheExpire > 0) {
$cacheDir = __DIR__ . '/cache';
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
$cacheFile = $cacheDir . '/' . md5($cacheKey) . '.cache';
file_put_contents($cacheFile, serialize($validFootprints));
}
$this->response->throwJson(array(
'success' => true,
'data' => $validFootprints,
'from_cache' => false
));
} catch (PDOException $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '查询失败: ' . $e->getMessage()
));
}
}
/**
* 获取文章图片
*
* @access public
* @return void
*/
public function getArticleImages()
{
$article_cid = $this->request->get('article_cid');
if (empty($article_cid)) {
$this->response->throwJson(array(
'success' => false,
'message' => '文章CID不能为空'
));
}
try {
$articleInfo = MyTrack_Plugin::getArticleInfo($article_cid);
if (!empty($articleInfo)) {
$response = array(
'success' => true,
'message' => '获取文章信息成功',
'images' => $articleInfo['images'] ?? array(),
'text' => $articleInfo['text'] ?? ''
);
if (!empty($articleInfo['title'])) {
$response['title'] = $articleInfo['title'];
}
if (!empty($articleInfo['link'])) {
$response['link'] = $articleInfo['link'];
}
if (!empty($articleInfo['tags'])) {
$response['tags'] = $articleInfo['tags'];
}
if (!empty($articleInfo['created'])) {
$response['created'] = $articleInfo['created'];
}
$this->response->throwJson($response);
} else {
$this->response->throwJson(array(
'success' => true,
'message' => '该文章中没有找到内容',
'images' => array(),
'text' => ''
));
}
} catch (Exception $e) {
$this->response->throwJson(array(
'success' => false,
'message' => '获取文章信息失败: ' . $e->getMessage()
));
}
}
/**
* 清除足迹缓存
*
* @access private
* @return void
*/
private function clearFootprintCache()
{
try {
$cacheDir = __DIR__ . '/cache';
if (!is_dir($cacheDir)) {
return;
}
$files = glob($cacheDir . '/*.cache');
foreach ($files as $file) {
if (is_file($file)) {
unlink($file);
}
}
} catch (Exception $e) {
error_log('清除MyTrack缓存失败: ' . $e->getMessage());
}
}
}