├── .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 | <?php echo $note_name_escaped; ?> 167 | 168 | 169 | 294 | 295 | 296 |
297 |
298 | 299 | 300 |
301 |
302 | 303 | 304 | 305 |
306 |
307 |
308 |

309 |     
内容已复制到剪贴板
310 | 311 | 312 | 397 | 398 | 399 | --------------------------------------------------------------------------------