首页
▸
▾
点击发布(文字、图片、视频、文件)
文字 / 网址
粘贴
上传文件
手动刷新本页
名称 / 内容
大小 / 剩余时间
操作
咯咯咯咯咯咯
咯咯咯咯咯咯
18 B
约 1437 分钟后过期
复制
删除
确认删除
<?php /** * File share:文件秒共享。PHP 8.0 单文件公开中转站,核心功能不依赖 JavaScript。…
显示更多
收起
<?php /** * File share:文件秒共享。PHP 8.0 单文件公开中转站,核心功能不依赖 JavaScript。 * 复制、粘贴、上传进度条、多文件 / 文件夹上传、拖拽和粘贴截图为可选增强;不可用时仍可用普通表单。 * 上传此文件到 PHP 网站即可;数据必须放在网站目录之外。 * 上传大文件时,宝塔里 PHP 的「上传限制」和 Nginx 的 client_max_body_size 要一起调大。 * iOS 快捷指令接口:POST ?action=api,字段 text 发文字、file 发文件;op=text / op=file 取回最新一条。 */ declare(strict_types=1); ini_set('display_errors', '0'); umask(0077); $config = [ 'storage_dir' => '', // 空值沿用原版的站外 PHP 临时目录。可填站外可写绝对路径。 'ttl' => 24 * 3600, 'max_file' => 100 * 1024 * 1024, 'max_text' => 16 * 1024, 'max_total' => 1024 * 1024 * 1024, 'max_items' => 200, 'min_free' => 64 * 1024 * 1024, 'api_key' => '', // 快捷指令接口密钥。留空 = 不用密钥直接用;填了以后快捷指令要带上 key 字段。 ]; final class RelayError extends RuntimeException { public int $status; public function __construct(string $message, int $status = 400) { parent::__construct($message); $this->status = $status; } } function h(string $value): string { return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function iniBytes(string $value): int { $value = trim($value); if ($value === '' || $value === '0' || $value === '-1') return PHP_INT_MAX; $number = (float)$value; switch (strtolower(substr($value, -1))) { case 'g': $number *= 1024; case 'm': $number *= 1024; case 'k': $number *= 1024; } return (int)min($number, PHP_INT_MAX); } function isInside(string $path, string $root): bool { $root = rtrim($root, DIRECTORY_SEPARATOR); return $path === $root || str_starts_with($path, $root . DIRECTORY_SEPARATOR); } function storageDir(array $config): string { // 与旧版使用同一算法:在原路径覆盖 index.php 可以继续使用原来的数据。 $path = $config['storage_dir'] ?: rtrim(sys_get_temp_dir(), '/\\') . '/php-relay-' . substr(hash('sha256', __FILE__), 0, 20); if (!is_dir($path) && !is_link($path)) @mkdir($path, 0700, true); // 首次并发访问时,另一请求可能刚刚创建了目录;以最终状态判断。 if (is_link($path) || !is_dir($path)) { throw new RelayError('无法创建私有临时目录。请检查 PHP 临时目录权限,或将 storage_dir 设置为网站目录外、PHP 允许访问的可写绝对路径。', 503); } $real = realpath($path); $webRoot = !empty($_SERVER['DOCUMENT_ROOT']) ? realpath($_SERVER['DOCUMENT_ROOT']) : false; if ($real === false || isInside($real, __DIR__) || ($webRoot !== false && isInside($real, $webRoot))) { throw new RelayError('存储目录必须放在网站根目录之外,请修改 storage_dir;不要关闭服务器目录限制。', 503); } @chmod($real, 0700); if (!is_writable($real)) throw new RelayError('私有临时目录不可写,请检查目录权限和 PHP 目录限制。', 503); return $real; } function validId(mixed $id): bool { return is_string($id) && preg_match('/\A[a-f0-9]{32}\z/D', $id) === 1; } function saveIndex(string $dir, array $db): void { $temp = $dir . '/index-' . bin2hex(random_bytes(8)) . '.tmp'; try { $json = json_encode($db, JSON_UNESCAPED_UNICODE | JSON_INVALID_UTF8_SUBSTITUTE | JSON_THROW_ON_ERROR); if (@file_put_contents($temp, $json) !== strlen($json) || !@rename($temp, $dir . '/index.json')) { throw new RelayError('保存失败,请检查磁盘空间和目录权限。', 507); } } finally { if (is_file($temp)) @unlink($temp); } } function locked(string $dir, callable $operation): mixed { $lock = @fopen($dir . '/store.lock', 'c'); if ($lock === false) throw new RelayError('存储暂时不可用,请稍后重试。', 503); if (!flock($lock, LOCK_EX)) { fclose($lock); throw new RelayError('存储暂时不可用,请稍后重试。', 503); } try { $db = ['items' => [], 'rates' => []]; if (is_file($dir . '/index.json')) { $raw = file_get_contents($dir . '/index.json'); $db = json_decode($raw === false ? '' : $raw, true, 512, JSON_THROW_ON_ERROR); if (!is_array($db) || !isset($db['items'], $db['rates']) || !is_array($db['items']) || !is_array($db['rates'])) { throw new RelayError('存储索引损坏,请由网站维护者检查。', 503); } } $now = time(); $changed = false; foreach ($db['items'] as $id => $item) { if (!validId($id) || !is_array($item) || !isset($item['kind'], $item['expires_at'])) { throw new RelayError('存储索引格式不正确。', 503); } if ($item['expires_at'] <= $now) { $file = $dir . '/' . $id . '.bin'; if ($item['kind'] === 'file' && is_file($file) && !@unlink($file)) continue; unset($db['items'][$id]); $changed = true; } } foreach ($db['rates'] as $key => $rate) { if ($rate['until'] <= $now) { unset($db['rates'][$key]); $changed = true; } } if (($db['last_sweep'] ?? 0) < $now - 300) { foreach (glob($dir . '/*.bin') ?: [] as $path) { $id = basename($path, '.bin'); if (validId($id) && !isset($db['items'][$id]) && filemtime($path) < $now - 3600) @unlink($path); } foreach (glob($dir . '/index-*.tmp') ?: [] as $path) { if (filemtime($pa
5.9 KB
约 1436 分钟后过期
复制
删除
确认删除
公开中转站:所有人都能查看、下载和删除。默认 24 小时后过期,请勿上传敏感资料。