db = Typecho_Db::get(); $this->prefix = $this->db->getPrefix(); $this->request = $request ?: Typecho_Request::getInstance(); $this->response = $response ?: Typecho_Response::getInstance(); } /** * 添加历史记录 - 修复:使用Typecho正确的SQL构建方法 */ public function addHistory($data) { try { $now = new Typecho_Date(Typecho_Date::gmtTime()); $insert = array( 'content' => $data['content'], 'event_date' => $data['event_date'], 'post_cids' => isset($data['post_cids']) ? $this->cleanCids($data['post_cids']) : '', 'created' => $now->format('Y-m-d H:i:s'), 'modified' => $now->format('Y-m-d H:i:s'), 'status' => 1 ); // 使用Typecho的查询构建器,但先验证数据 $this->validateInsertData($insert); // 修复:正确构建并执行插入查询 // 在Typecho中,insert()->rows()需要调用query()方法来执行 $query = $this->db->insert($this->prefix . 'development_history')->rows($insert); // 执行查询 $this->db->query($query); // 获取最后插入的ID - Typecho的方式 $row = $this->db->fetchRow($this->db->select('LAST_INSERT_ID() as id')); return $row ? $row['id'] : 0; } catch (Exception $e) { error_log("addHistory Error: " . $e->getMessage()); error_log("Data: " . print_r($data, true)); throw new Exception("发布失败: " . $e->getMessage()); } } /** * 验证插入数据 */ private function validateInsertData(&$data) { // 确保所有必需字段都有值 if (empty($data['content'])) { throw new Exception("内容不能为空"); } if (empty($data['event_date'])) { throw new Exception("日期不能为空"); } // 验证日期格式 if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $data['event_date'])) { throw new Exception("日期格式错误,应为YYYY-MM-DD"); } // 清理和转义内容 $data['content'] = trim($data['content']); if (empty($data['content'])) { throw new Exception("内容不能为空"); } // 确保所有字段都是字符串 foreach ($data as $key => $value) { if (!is_string($value) && !is_numeric($value)) { $data[$key] = (string)$value; } } } /** * 批量添加历史记录(按事件时间排序插入,越近的ID越大) */ public function batchAddHistories($histories) { // 按事件时间排序,越近的时间越晚插入,这样ID越大 usort($histories, function($a, $b) { return strtotime($a['event_date']) - strtotime($b['event_date']); }); $now = new Typecho_Date(Typecho_Date::gmtTime()); $nowStr = $now->format('Y-m-d H:i:s'); foreach ($histories as $history) { $insert = array( 'content' => $history['content'], 'event_date' => $history['event_date'], 'post_cids' => '', 'created' => $nowStr, 'modified' => $nowStr, 'status' => 1 ); $query = $this->db->insert($this->prefix . 'development_history')->rows($insert); $this->db->query($query); } } /** * 更新历史记录 */ public function updateHistory($data) { try { $now = new Typecho_Date(Typecho_Date::gmtTime()); $update = array( 'content' => $data['edit_content'], 'event_date' => $data['edit_event_date'], 'post_cids' => isset($data['edit_post_cids']) ? $this->cleanCids($data['edit_post_cids']) : '', 'modified' => $now->format('Y-m-d H:i:s') ); $query = $this->db->update($this->prefix . 'development_history') ->rows($update) ->where('id = ?', intval($data['edit_id'])); $this->db->query($query); } catch (Exception $e) { error_log("updateHistory Error: " . $e->getMessage()); throw new Exception("更新失败: " . $e->getMessage()); } } /** * 删除历史记录 */ public function deleteHistory($id) { $query = $this->db->delete($this->prefix . 'development_history')->where('id = ?', intval($id)); $this->db->query($query); } /** * 批量删除 */ public function deleteHistories($ids) { foreach ($ids as $id) { $this->deleteHistory(intval($id)); } } /** * 获取历史记录 */ public function getHistories($page = 1, $perPage = 10) { $offset = ($page - 1) * $perPage; $query = $this->db->select() ->from($this->prefix . 'development_history') ->where('status = ?', 1) ->order('id', Typecho_Db::SORT_DESC) ->limit($perPage) ->offset($offset); return $this->db->fetchAll($query); } /** * 获取所有历史记录(用于导出) */ public function getAllHistories() { $query = $this->db->select() ->from($this->prefix . 'development_history') ->where('status = ?', 1) ->order('id', Typecho_Db::SORT_DESC); return $this->db->fetchAll($query); } /** * 获取总记录数 */ public function getTotalCount() { $query = $this->db->select('COUNT(*) as count') ->from($this->prefix . 'development_history') ->where('status = ?', 1); $result = $this->db->fetchRow($query); return $result['count']; } /** * 获取单条记录 */ public function getHistory($id) { $query = $this->db->select() ->from($this->prefix . 'development_history') ->where('id = ?', $id) ->limit(1); return $this->db->fetchRow($query); } /** * 根据文章CID获取文章信息 */ public function getPostByCid($cid) { try { $query = $this->db->select('cid, title, slug, created') ->from($this->prefix . 'contents') ->where('cid = ?', intval($cid)) ->where('type = ?', 'post') ->where('status = ?', 'publish') ->limit(1); $post = $this->db->fetchRow($query); if ($post) { $options = Typecho_Widget::widget('Widget_Options'); if (!empty($post['slug'])) { $post['url'] = Typecho_Common::url($post['slug'] . '.html', $options->index); } else { $post['url'] = Typecho_Common::url('archives/' . $post['cid'], $options->index); } } return $post; } catch (Exception $e) { return null; } } /** * 清理CID字符串 */ private function cleanCids($cids) { if (empty($cids)) { return ''; } $cidsArray = array_filter(array_map('trim', explode(',', $cids))); $validCids = array(); foreach ($cidsArray as $cid) { if (is_numeric($cid) && $cid > 0) { $validCids[] = intval($cid); } } // 去重并返回逗号分隔的字符串 return implode(',', array_unique($validCids)); } /** * 导出数据为文本格式 */ public function exportData() { $histories = $this->getAllHistories(); $content = ''; foreach ($histories as $history) { // 使用 Y.m.d 格式导出 $date = date('Y.m.d', strtotime($history['event_date'])); $text = str_replace(array("\r\n", "\r", "\n"), " ", $history['content']); $content .= $date . ' ' . $text . "\n"; } return $content; } /** * 导入数据(增强版,支持调试) */ public function importData($text) { // 标准化换行符 $text = str_replace("\r\n", "\n", $text); $text = str_replace("\r", "\n", $text); $lines = explode("\n", $text); $imported = 0; $failed = 0; $failReasons = array(); // 记录失败原因 $histories = array(); foreach ($lines as $lineNum => $line) { $line = trim($line); if (empty($line)) continue; // 移除行尾的分号(如果有) if (substr($line, -1) === ';') { $line = substr($line, 0, -1); $line = trim($line); } // 找到第一个空格的位置来分割日期和内容 $firstSpacePos = strpos($line, ' '); if ($firstSpacePos === false) { $failed++; $failReasons[] = "第 " . ($lineNum + 1) . " 行:找不到空格分隔日期和内容 - '{$line}'"; continue; } $date = trim(substr($line, 0, $firstSpacePos)); $content = trim(substr($line, $firstSpacePos + 1)); // 验证日期格式 - 支持单个数字的月份和日期 // 允许的格式:YYYY.M.D, YYYY.MM.D, YYYY.M.DD, YYYY.MM.DD $datePattern = '/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/'; if (!preg_match($datePattern, $date, $matches)) { $failed++; $failReasons[] = "第 " . ($lineNum + 1) . " 行:日期格式错误,应为 YYYY.M[M].D[D] - '{$date}'"; continue; } // 检查日期是否有效 $year = intval($matches[1]); $month = intval($matches[2]); $day = intval($matches[3]); if (!checkdate($month, $day, $year)) { $failed++; $failReasons[] = "第 " . ($lineNum + 1) . " 行:无效的日期 - {$date}"; continue; } // 转换日期格式为 Y-m-d 以便数据库存储,补零成两位数字 $dbDate = sprintf('%04d-%02d-%02d', $year, $month, $day); // 验证内容 if (empty($content)) { $failed++; $failReasons[] = "第 " . ($lineNum + 1) . " 行:内容为空"; continue; } $histories[] = array( 'event_date' => $dbDate, 'content' => $content ); $imported++; } if (!empty($histories)) { $this->batchAddHistories($histories); } // 返回包含失败原因的结果 return array( 'imported' => $imported, 'failed' => $failed, 'fail_reasons' => $failReasons ); } }