更新 z.ai/notes/index.php
This commit is contained in:
+160
-17
@@ -4,6 +4,7 @@ session_start();
|
|||||||
// 配置
|
// 配置
|
||||||
define('DB_FILE', 'notes.db');
|
define('DB_FILE', 'notes.db');
|
||||||
define('UPLOAD_DIR', 'uploads');
|
define('UPLOAD_DIR', 'uploads');
|
||||||
|
define('IMAGES_DIR', 'uploads/images');
|
||||||
define('APP_NAME', '简约记事本');
|
define('APP_NAME', '简约记事本');
|
||||||
define('VERSION', '1.0.0');
|
define('VERSION', '1.0.0');
|
||||||
define('NOTES_PER_PAGE', 25);
|
define('NOTES_PER_PAGE', 25);
|
||||||
@@ -14,6 +15,11 @@ if (!file_exists(UPLOAD_DIR)) {
|
|||||||
mkdir(UPLOAD_DIR, 0755, true);
|
mkdir(UPLOAD_DIR, 0755, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保图片目录存在
|
||||||
|
if (!file_exists(IMAGES_DIR)) {
|
||||||
|
mkdir(IMAGES_DIR, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
// 获取当前页面基础URL
|
// 获取当前页面基础URL
|
||||||
function getBaseUrl() {
|
function getBaseUrl() {
|
||||||
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
|
||||||
@@ -59,6 +65,134 @@ class Encryption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理内容中的链接和图片
|
||||||
|
function processContent($content) {
|
||||||
|
// 自动下载外部图片并替换为本地链接
|
||||||
|
$content = processExternalImages($content);
|
||||||
|
|
||||||
|
// 自动识别URL并转换为Markdown链接格式
|
||||||
|
$content = autoFormatLinks($content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动下载外部图片
|
||||||
|
function processExternalImages($content) {
|
||||||
|
// 匹配Markdown图片格式
|
||||||
|
$pattern = '/!\[(.*?)\]\((https?:\/\/[^\s)]+)\)/';
|
||||||
|
|
||||||
|
$content = preg_replace_callback($pattern, function($matches) {
|
||||||
|
$alt = $matches[1];
|
||||||
|
$url = $matches[2];
|
||||||
|
|
||||||
|
// 检查是否是外部图片URL
|
||||||
|
if (isExternalImage($url)) {
|
||||||
|
$localPath = downloadAndSaveImage($url);
|
||||||
|
if ($localPath) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $matches[0];
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
// 匹配纯图片URL(非Markdown格式)
|
||||||
|
$pattern = '/(?<!\]\()https?:\/\/[^\s]*\.(jpg|jpeg|png|gif|webp)(?!\))/i';
|
||||||
|
|
||||||
|
$content = preg_replace_callback($pattern, function($matches) {
|
||||||
|
$url = $matches[0];
|
||||||
|
|
||||||
|
// 检查是否是外部图片URL
|
||||||
|
if (isExternalImage($url)) {
|
||||||
|
$localPath = downloadAndSaveImage($url);
|
||||||
|
if ($localPath) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $url;
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是外部图片URL
|
||||||
|
function isExternalImage($url) {
|
||||||
|
// 检查是否是HTTP/HTTPS URL
|
||||||
|
if (!preg_match('/^https?:\/\//', $url)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是当前域名的URL
|
||||||
|
$baseUrl = getBaseUrl();
|
||||||
|
if (strpos($url, $baseUrl) === 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查URL是否包含图片扩展名
|
||||||
|
$imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
|
||||||
|
$extension = strtolower(pathinfo($url, PATHINFO_EXTENSION));
|
||||||
|
|
||||||
|
return in_array($extension, $imageExtensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载并保存图片
|
||||||
|
function downloadAndSaveImage($url) {
|
||||||
|
try {
|
||||||
|
// 获取图片内容
|
||||||
|
$imageData = file_get_contents($url);
|
||||||
|
if (!$imageData) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取图片信息
|
||||||
|
$imageInfo = getimagesizefromstring($imageData);
|
||||||
|
if (!$imageInfo) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成唯一文件名
|
||||||
|
$extension = image_type_to_extension($imageInfo[2]);
|
||||||
|
$filename = uniqid() . $extension;
|
||||||
|
$filepath = IMAGES_DIR . '/' . $filename;
|
||||||
|
|
||||||
|
// 保存图片
|
||||||
|
if (file_put_contents($filepath, $imageData)) {
|
||||||
|
// 返回相对于当前脚本的路径
|
||||||
|
return IMAGES_DIR . '/' . $filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动格式化链接
|
||||||
|
function autoFormatLinks($content) {
|
||||||
|
// 匹配非Markdown格式的URL
|
||||||
|
$pattern = '/(?<!\]\()https?:\/\/[^\s\)]+(?!\))/i';
|
||||||
|
|
||||||
|
$content = preg_replace_callback($pattern, function($matches) {
|
||||||
|
$url = $matches[0];
|
||||||
|
|
||||||
|
// 如果已经是Markdown链接格式,则跳过
|
||||||
|
if (preg_match('/\[' . preg_quote($url, '/') . '\]\(' . preg_quote($url, '/') . '\)/', $content)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果是图片URL,则跳过(已在processExternalImages中处理)
|
||||||
|
if (isExternalImage($url)) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为Markdown链接格式
|
||||||
|
return '[' . $url . '](' . $url . ')';
|
||||||
|
}, $content);
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化数据库
|
// 初始化数据库
|
||||||
function initDatabase() {
|
function initDatabase() {
|
||||||
try {
|
try {
|
||||||
@@ -74,11 +208,11 @@ function initDatabase() {
|
|||||||
)
|
)
|
||||||
');
|
');
|
||||||
|
|
||||||
// 创建笔记表(加密存储)
|
// 创建笔记表(标题不加密,内容加密)
|
||||||
$db->exec('
|
$db->exec('
|
||||||
CREATE TABLE IF NOT EXISTS notes (
|
CREATE TABLE IF NOT EXISTS notes (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
title_enc TEXT NOT NULL,
|
title TEXT NOT NULL,
|
||||||
content_enc TEXT NOT NULL,
|
content_enc TEXT NOT NULL,
|
||||||
tags TEXT,
|
tags TEXT,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
@@ -101,6 +235,7 @@ function initDatabase() {
|
|||||||
');
|
');
|
||||||
|
|
||||||
// 创建索引
|
// 创建索引
|
||||||
|
$db->exec('CREATE INDEX IF NOT EXISTS idx_notes_title ON notes(title)');
|
||||||
$db->exec('CREATE INDEX IF NOT EXISTS idx_notes_tags ON notes(tags)');
|
$db->exec('CREATE INDEX IF NOT EXISTS idx_notes_tags ON notes(tags)');
|
||||||
$db->exec('CREATE INDEX IF NOT EXISTS idx_notes_created ON notes(created_at)');
|
$db->exec('CREATE INDEX IF NOT EXISTS idx_notes_created ON notes(created_at)');
|
||||||
$db->exec('CREATE INDEX IF NOT EXISTS idx_attachments_note_id ON attachments(note_id)');
|
$db->exec('CREATE INDEX IF NOT EXISTS idx_attachments_note_id ON attachments(note_id)');
|
||||||
@@ -167,10 +302,11 @@ function getNotesCount($search = '', $tag = '') {
|
|||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
if ($search) {
|
if ($search) {
|
||||||
// 搜索需要解密,这里简化处理,只搜索标签
|
// 现在可以搜索标题了
|
||||||
$sql .= ' AND tags LIKE ?';
|
$sql .= ' AND (title LIKE ? OR tags LIKE ?)';
|
||||||
$searchParam = '%' . $search . '%';
|
$searchParam = '%' . $search . '%';
|
||||||
$params[] = $searchParam;
|
$params[] = $searchParam;
|
||||||
|
$params[] = $searchParam;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($tag) {
|
if ($tag) {
|
||||||
@@ -195,7 +331,8 @@ function getNotes($page = 1, $search = '', $tag = '') {
|
|||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
if ($search) {
|
if ($search) {
|
||||||
$sql .= ' AND tags LIKE ?';
|
$sql .= ' AND (title LIKE ? OR tags LIKE ?)';
|
||||||
|
$params[] = '%' . $search . '%';
|
||||||
$params[] = '%' . $search . '%';
|
$params[] = '%' . $search . '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,10 +354,9 @@ function getNotes($page = 1, $search = '', $tag = '') {
|
|||||||
$notes = [];
|
$notes = [];
|
||||||
|
|
||||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||||
// 解密数据
|
// 只解密内容,标题不需要解密
|
||||||
$row['title'] = Encryption::decrypt($row['title_enc']);
|
|
||||||
$row['content'] = Encryption::decrypt($row['content_enc']);
|
$row['content'] = Encryption::decrypt($row['content_enc']);
|
||||||
unset($row['title_enc'], $row['content_enc']);
|
unset($row['content_enc']);
|
||||||
$notes[] = $row;
|
$notes[] = $row;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,10 +372,9 @@ function getNote($id) {
|
|||||||
$note = $result->fetchArray(SQLITE3_ASSOC);
|
$note = $result->fetchArray(SQLITE3_ASSOC);
|
||||||
|
|
||||||
if ($note) {
|
if ($note) {
|
||||||
// 解密数据
|
// 只解密内容,标题不需要解密
|
||||||
$note['title'] = Encryption::decrypt($note['title_enc']);
|
|
||||||
$note['content'] = Encryption::decrypt($note['content_enc']);
|
$note['content'] = Encryption::decrypt($note['content_enc']);
|
||||||
unset($note['title_enc'], $note['content_enc']);
|
unset($note['content_enc']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $note;
|
return $note;
|
||||||
@@ -248,9 +383,13 @@ function getNote($id) {
|
|||||||
// 创建笔记
|
// 创建笔记
|
||||||
function createNote($title, $content, $tags) {
|
function createNote($title, $content, $tags) {
|
||||||
$db = getDB();
|
$db = getDB();
|
||||||
$stmt = $db->prepare('INSERT INTO notes (title_enc, content_enc, tags) VALUES (?, ?, ?)');
|
|
||||||
$stmt->bindValue(1, Encryption::encrypt($title), SQLITE3_TEXT);
|
// 处理内容中的链接和图片
|
||||||
$stmt->bindValue(2, Encryption::encrypt($content), SQLITE3_TEXT);
|
$processedContent = processContent($content);
|
||||||
|
|
||||||
|
$stmt = $db->prepare('INSERT INTO notes (title, content_enc, tags) VALUES (?, ?, ?)');
|
||||||
|
$stmt->bindValue(1, $title, SQLITE3_TEXT);
|
||||||
|
$stmt->bindValue(2, Encryption::encrypt($processedContent), SQLITE3_TEXT);
|
||||||
$stmt->bindValue(3, $tags, SQLITE3_TEXT);
|
$stmt->bindValue(3, $tags, SQLITE3_TEXT);
|
||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
return $db->lastInsertRowID();
|
return $db->lastInsertRowID();
|
||||||
@@ -259,9 +398,13 @@ function createNote($title, $content, $tags) {
|
|||||||
// 更新笔记
|
// 更新笔记
|
||||||
function updateNote($id, $title, $content, $tags) {
|
function updateNote($id, $title, $content, $tags) {
|
||||||
$db = getDB();
|
$db = getDB();
|
||||||
$stmt = $db->prepare('UPDATE notes SET title_enc = ?, content_enc = ?, tags = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
|
|
||||||
$stmt->bindValue(1, Encryption::encrypt($title), SQLITE3_TEXT);
|
// 处理内容中的链接和图片
|
||||||
$stmt->bindValue(2, Encryption::encrypt($content), SQLITE3_TEXT);
|
$processedContent = processContent($content);
|
||||||
|
|
||||||
|
$stmt = $db->prepare('UPDATE notes SET title = ?, content_enc = ?, tags = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
|
||||||
|
$stmt->bindValue(1, $title, SQLITE3_TEXT);
|
||||||
|
$stmt->bindValue(2, Encryption::encrypt($processedContent), SQLITE3_TEXT);
|
||||||
$stmt->bindValue(3, $tags, SQLITE3_TEXT);
|
$stmt->bindValue(3, $tags, SQLITE3_TEXT);
|
||||||
$stmt->bindValue(4, $id, SQLITE3_INTEGER);
|
$stmt->bindValue(4, $id, SQLITE3_INTEGER);
|
||||||
return $stmt->execute();
|
return $stmt->execute();
|
||||||
|
|||||||
Reference in New Issue
Block a user