├── .htaccess
├── README.md
├── _tmp
└── .htaccess
├── favicon.ico
├── favicon.svg
└── index.php
/.htaccess:
--------------------------------------------------------------------------------
1 | Options -Indexes
2 | RewriteEngine On
3 | RewriteRule ^([a-zA-Z0-9_-]+)$ index.php?note=$1 [QSA]
4 |
5 |
6 | Header set X-Robots-Tag: "noindex, nofollow"
7 |
8 |
9 | # Uncomment the lines below to enable basic authentication.
10 | # See https://httpd.apache.org/docs/current/programs/htpasswd.html for generating your .htpasswd
11 |
12 | # AuthType basic
13 | # AuthName "website.name"
14 | # AuthUserFile "/home/user/update-path-to.htpasswd"
15 | # Require valid-user
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TextShare
2 |
3 | TextShare 是一个简洁、轻量的在线文本共享工具,允许用户方便地创建、编辑和分享笔记。该项目基于 [minimalist-web-notepad](https://github.com/pereorga/minimalist-web-notepad) 改进,旨在提供一个简单易用的文字记录与分享平台。
4 |
5 | ## 功能
6 |
7 | * **简单易用**:无需注册,访问链接即可创建或编辑笔记。
8 | * **快速分享**:生成唯一链接和二维码,轻松分享笔记内容。
9 | * **支持编辑和只读模式**:可以在编辑模式下修改笔记,也可以通过只读模式查看笔记。
10 | * **自动保存**:编辑过程中,笔记内容会自动保存,防止数据丢失。
11 | * **暗黑模式**:支持深色主题,适应用户的系统设置。
12 | * **打印模式**:支持将笔记打印为纸质文档。
13 |
14 | ## 使用方法
15 |
16 | 1. **创建或查看笔记**:
17 |
18 | * 访问 `http://your-domain.com`,系统会自动为你生成一个新的笔记页面。
19 | * 你可以立即在页面中输入内容,系统会自动保存笔记。
20 | * 笔记保存后,可通过页面顶部的链接或生成的二维码分享给他人。
21 | 2. **编辑和切换模式**:
22 |
23 | * 默认进入编辑模式,你可以在页面输入笔记。
24 | * 点击页面中的“切换到只读模式”按钮,锁定笔记,防止进一步编辑。
25 | 3. **分享笔记**:
26 |
27 | * 你可以复制页面的链接或使用自动生成的二维码与他人分享笔记。
28 | * 其他用户访问该链接时,可以以只读模式查看笔记内容。
29 |
30 | ## API 功能
31 |
32 | TextShare 还提供了一些 API 功能,适合开发者或高级用户通过编程方式创建和管理笔记。
33 |
34 | ### API 端点
35 |
36 | 1. **新建随机地址笔记**:
37 |
38 | * 访问:`POST /?new&text=你的内容`
39 | * 功能:生成一个随机名称的笔记,并保存传入的文本内容。
40 | * 返回:包含新笔记 URL 的 JSON 响应。
41 | 2. **创建或修改指定名称的笔记**:
42 |
43 | * 访问:`POST /笔记名称?text=你的内容`
44 | * 功能:保存或更新指定名称的笔记,名称必须是字母、数字、下划线或连字符的组合,且不超过 64 个字符。
45 | 3. **获取笔记的原始内容**:
46 |
47 | * 访问:`GET /笔记名称?raw`
48 | * 功能:返回笔记的纯文本内容,适合在命令行工具中查看。
49 |
50 | ## 部署方法
51 |
52 | 1. 克隆仓库到你的服务器:
53 |
54 | ```bash
55 | git clone https://github.com/lgpay/textshare.git
56 |
57 | ```
58 | 2. 设置笔记保存的目录:
59 |
60 | * 确保 `index.php` 中定义的笔记保存目录(默认为 `_tmp`)存在且具有读写权限。
61 | 3. 将项目部署到你的 Web 服务器上即可使用。
62 |
63 | ## 示例
64 |
65 | 访问 `http://your-domain.com/` 创建和分享你的笔记。
66 |
67 | ## 致谢
68 |
69 | 本项目基于 [minimalist-web-notepad](https://github.com/pereorga/minimalist-web-notepad) 改进,感谢原作者的开源贡献。
70 |
--------------------------------------------------------------------------------
/_tmp/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | Require all denied
3 |
4 |
5 | Order allow,deny
6 |
7 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lgpay/textshare/573fdb62c06e532d8d9ccf7758255507edbfb64a/favicon.ico
--------------------------------------------------------------------------------
/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | 4 位十六进制字符)
18 | $random_bytes_length = 2; // 2 字节 = 4 位十六进制字符
19 |
20 | // API 处理逻辑
21 | // 1. 新建随机地址文本,/?new&text=xxxx,返回新建文本的URL
22 | if (isset($_GET['new']) && isset($_GET['text'])) {
23 | // 生成随机名称
24 | $random_note_name = bin2hex(random_bytes($random_bytes_length)); // 使用定义的字节长度
25 | $note_file_path = $absolute_notes_directory . DIRECTORY_SEPARATOR . $random_note_name;
26 |
27 | // 保存文本内容
28 | $note_content = $_GET['text'];
29 | if (strlen($note_content) > 1024 * 100) {
30 | die('Content too large');
31 | }
32 | file_put_contents($note_file_path, $note_content);
33 |
34 | // 返回新建文本的 URL
35 | header('Content-Type: application/json');
36 | echo json_encode([
37 | 'url' => $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'] . '/' . $random_note_name
38 | ]);
39 | exit;
40 | }
41 |
42 | // 获取笔记的名称(通过URL参数传递)
43 | $note_name = isset($_GET['note']) ? trim($_GET['note']) : null;
44 |
45 | // API 处理逻辑
46 | // 2. 新建或修改指定名称的笔记本,/name?text=xxxx,返回保存状态
47 | if ($note_name && isset($_GET['text'])) {
48 | // 验证笔记名称的合法性
49 | if (strlen($note_name) > 64 || !preg_match('/^[a-zA-Z0-9_-]+$/', $note_name)) {
50 | die('Invalid note name');
51 | }
52 |
53 | // 处理笔记文件路径
54 | $sanitized_note_name = basename($note_name);
55 | $note_file_path = $absolute_notes_directory . DIRECTORY_SEPARATOR . $sanitized_note_name;
56 |
57 | // 保存或更新文本内容
58 | $note_content = $_GET['text'];
59 | if (strlen($note_content) > 1024 * 100) {
60 | die('Content too large');
61 | }
62 |
63 | // 写入文件
64 | file_put_contents($note_file_path, $note_content);
65 |
66 | // 返回保存状态
67 | header('Content-Type: application/json');
68 | echo json_encode([
69 | 'status' => 'success',
70 | 'message' => 'Note saved successfully.'
71 | ]);
72 | exit;
73 | }
74 |
75 | // 验证笔记名称的合法性(为空、长度超出限制或包含非法字符)
76 | if (!$note_name || strlen($note_name) > 64 || !preg_match('/^[a-zA-Z0-9_-]+$/', $note_name)) {
77 | // 如果笔记名称不合法,生成一个随机名称(使用定义的字节长度),并重定向到该新名称的页面
78 | $random_note_name = bin2hex(random_bytes($random_bytes_length)); // 使用定义的字节长度
79 | header("Location: /" . $random_note_name); // 重定向到没有查询参数的URL
80 | exit;
81 | }
82 |
83 | // 使用basename函数确保笔记名称不包含路径信息,防止目录遍历攻击
84 | $sanitized_note_name = basename($note_name);
85 | $note_file_path = $absolute_notes_directory . DIRECTORY_SEPARATOR . $sanitized_note_name;
86 |
87 | // 验证文件路径是否位于笔记保存目录下,防止恶意路径注入
88 | if (strpos($note_file_path, $absolute_notes_directory) !== 0) {
89 | die('Invalid note path');
90 | }
91 |
92 | // API 处理逻辑
93 | // 3. 获取笔记内容,/name?raw,返回文本内容
94 | if (isset($_GET['raw'])) {
95 | if (is_file($note_file_path)) {
96 | header('Content-Type: text/plain');
97 | readfile($note_file_path);
98 | } else {
99 | header('HTTP/1.0 404 Not Found');
100 | echo 'Note not found';
101 | }
102 | exit;
103 | }
104 |
105 | // 定义笔记的最大允许大小(100KB),防止上传大文件造成服务器压力
106 | $MAX_NOTE_SIZE = 1024 * 100; // 100KB
107 |
108 | // 处理POST请求,用户可以通过POST请求创建或更新笔记内容
109 | if ($_SERVER['REQUEST_METHOD'] === 'POST') {
110 | $note_content = isset($_POST['text']) ? $_POST['text'] : file_get_contents("php://input");
111 |
112 | // 检查内容大小是否超出限制
113 | if (strlen($note_content) > $MAX_NOTE_SIZE) {
114 | die('Content too large');
115 | }
116 |
117 | try {
118 | // 使用文件锁防止并发写入问题
119 | $file_handle = fopen($note_file_path, 'c');
120 | if (flock($file_handle, LOCK_EX)) {
121 | // 如果有内容,则写入文件;如果为空,则删除文件
122 | if (strlen($note_content)) {
123 | if (file_put_contents($note_file_path, $note_content) === false) {
124 | error_log("Failed to save note to path: $note_file_path");
125 | die('Failed to save the note');
126 | }
127 | } elseif (is_file($note_file_path) && !unlink($note_file_path)) {
128 | error_log("Failed to delete the note at path: $note_file_path");
129 | die('Failed to delete the note');
130 | }
131 | flock($file_handle, LOCK_UN);
132 | }
133 | fclose($file_handle);
134 | } catch (Exception $e) {
135 | error_log('Error: ' . $e->getMessage());
136 | die('An error occurred: ' . $e->getMessage());
137 | }
138 | exit;
139 | }
140 |
141 | // 检查是否请求原始笔记内容(通常通过curl或wget等命令行工具请求)
142 | if (isset($_GET['raw']) || strpos($_SERVER['HTTP_USER_AGENT'], 'curl') === 0 || strpos($_SERVER['HTTP_USER_AGENT'], 'Wget') === 0) {
143 | if (is_file($note_file_path)) {
144 | header('Content-type: text/plain');
145 | readfile($note_file_path);
146 | } else {
147 | header('HTTP/1.0 404 Not Found');
148 | }
149 | exit;
150 | }
151 |
152 | // 判断笔记文件是否存在,以确定是否是新笔记
153 | $is_new_note = !is_file($note_file_path);
154 |
155 | // 读取现有笔记内容并转义特殊字符,防止XSS攻击
156 | $note_content_escaped = is_file($note_file_path) ? htmlspecialchars(file_get_contents($note_file_path), ENT_QUOTES, 'UTF-8') : '';
157 | $note_name_escaped = htmlspecialchars($sanitized_note_name, ENT_QUOTES, 'UTF-8');
158 |
159 | ?>
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
294 |
295 |
296 |
308 |
309 | 内容已复制到剪贴板
310 | 链接已复制到剪贴板
311 |
312 |
397 |
398 |
399 |
--------------------------------------------------------------------------------