119 lines
4.1 KiB
PHP
119 lines
4.1 KiB
PHP
<?php
|
||||
|
|
// ============================================
|
|||
|
|
// 文件: lib/storage/local.php
|
|||
|
|
// 说明: 本地硬盘存储驱动(默认,行为与改造前一致)
|
|||
|
|
// ============================================
|
|||
|
|
|
|||
|
|
class StorageLocal {
|
|||
|
|
|
|||
|
|
public function id() { return 'local'; }
|
|||
|
|
|
|||
|
|
public function label() { return '本地硬盘'; }
|
|||
|
|
|
|||
|
|
// 把文件落到站点目录下(先尝试 rename,跨文件系统时退化为 copy+unlink)
|
|||
|
|
public function putFile($srcPath, $key, $mime = null) {
|
|||
|
|
$target = $this->absPath($key);
|
|||
|
|
$dir = dirname($target);
|
|||
|
|
if (!is_dir($dir) && !@mkdir($dir, 0755, true)) {
|
|||
|
|
return ['ok' => false, 'error' => "无法创建目录:{$dir}"];
|
|||
|
|
}
|
|||
|
|
if (@rename($srcPath, $target)) {
|
|||
|
|
@chmod($target, 0644);
|
|||
|
|
return ['ok' => true, 'error' => ''];
|
|||
|
|
}
|
|||
|
|
if (@copy($srcPath, $target)) {
|
|||
|
|
@unlink($srcPath);
|
|||
|
|
@chmod($target, 0644);
|
|||
|
|
return ['ok' => true, 'error' => ''];
|
|||
|
|
}
|
|||
|
|
return ['ok' => false, 'error' => "写入文件失败:{$key}(请检查目录权限)"];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function putContents($binary, $key, $mime = null) {
|
|||
|
|
$target = $this->absPath($key);
|
|||
|
|
$dir = dirname($target);
|
|||
|
|
if (!is_dir($dir) && !@mkdir($dir, 0755, true)) {
|
|||
|
|
return ['ok' => false, 'error' => "无法创建目录:{$dir}"];
|
|||
|
|
}
|
|||
|
|
if (@file_put_contents($target, $binary) === false) {
|
|||
|
|
return ['ok' => false, 'error' => "写入文件失败:{$key}(请检查目录权限)"];
|
|||
|
|
}
|
|||
|
|
@chmod($target, 0644);
|
|||
|
|
return ['ok' => true, 'error' => ''];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function delete($key) {
|
|||
|
|
$target = $this->absPath($key);
|
|||
|
|
if (is_file($target)) {
|
|||
|
|
return @unlink($target);
|
|||
|
|
}
|
|||
|
|
return true; // 不存在视为成功
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function url($key) {
|
|||
|
|
return '/' . ltrim((string)$key, '/');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function exists($key) {
|
|||
|
|
return is_file($this->absPath($key));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 服务端读取对象。本地驱动直接读盘。
|
|||
|
|
* 返回结构与 storageHttp() 同构(etag / last-modified 供 media.php 做 304 判断)。
|
|||
|
|
*/
|
|||
|
|
public function get($key, array $extra = []) {
|
|||
|
|
$abs = $this->absPath($key);
|
|||
|
|
if (!is_file($abs) || !is_readable($abs)) {
|
|||
|
|
return ['ok' => false, 'status' => 404, 'headers' => [], 'body' => '', 'error' => '对象不存在'];
|
|||
|
|
}
|
|||
|
|
$body = @file_get_contents($abs);
|
|||
|
|
if ($body === false) {
|
|||
|
|
return ['ok' => false, 'status' => 500, 'headers' => [], 'body' => '', 'error' => '读取文件失败'];
|
|||
|
|
}
|
|||
|
|
return [
|
|||
|
|
'ok' => true,
|
|||
|
|
'status' => 200,
|
|||
|
|
'headers' => [
|
|||
|
|
'content-type' => storageMimeOfFile($abs),
|
|||
|
|
'content-length' => (string)strlen($body),
|
|||
|
|
'etag' => '"' . md5($body) . '"',
|
|||
|
|
'last-modified' => gmdate('D, d M Y H:i:s \G\M\T', (int)@filemtime($abs)),
|
|||
|
|
],
|
|||
|
|
'body' => $body,
|
|||
|
|
'error' => '',
|
|||
|
|
];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function test() {
|
|||
|
|
// 验证上传目录可写
|
|||
|
|
$probe = UPLOAD_DIR . '.storage_test_' . uniqid();
|
|||
|
|
if (@file_put_contents($probe, 'ok') === false) {
|
|||
|
|
return ['ok' => false, 'error' => '上传目录不可写:' . UPLOAD_DIR];
|
|||
|
|
}
|
|||
|
|
@unlink($probe);
|
|||
|
|
$free = @disk_free_space(ROOT_DIR);
|
|||
|
|
$msg = '本地存储正常,上传目录可写。';
|
|||
|
|
if ($free !== false) {
|
|||
|
|
$msg .= ' 剩余空间 ' . formatBytes($free) . '。';
|
|||
|
|
}
|
|||
|
|
return ['ok' => true, 'error' => '', 'message' => $msg];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private function absPath($key) {
|
|||
|
|
return ROOT_DIR . '/' . ltrim((string)$key, '/');
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 字节数格式化(设置页展示用)
|
|||
|
|
function formatBytes($bytes, $precision = 2) {
|
|||
|
|
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|||
|
|
$bytes = max(0, (float)$bytes);
|
|||
|
|
$i = 0;
|
|||
|
|
while ($bytes >= 1024 && $i < count($units) - 1) {
|
|||
|
|
$bytes /= 1024;
|
|||
|
|
$i++;
|
|||
|
|
}
|
|||
|
|
return round($bytes, $i === 0 ? 0 : $precision) . ' ' . $units[$i];
|
|||
|
|
}
|