确认删除下面的内容?删除后所有访客都将无法再获取它。
<?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
公开中转站:所有人都能查看、下载和删除。默认 24 小时后过期,请勿上传敏感资料。