v2.2.0: includes/Tools/FileManagerTools.php
This commit is contained in:
@@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
namespace AskTamMCP\Tools;
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FileManagerTools — sandboxed to /wp-content/uploads/
|
||||||
|
*/
|
||||||
|
class FileManagerTools {
|
||||||
|
|
||||||
|
private static function safePath(string $rel): string {
|
||||||
|
$uploads = wp_upload_dir();
|
||||||
|
$base_dir = rtrim($uploads['basedir'], '/');
|
||||||
|
// Strip leading slashes and normalize
|
||||||
|
$rel = ltrim(str_replace(['..', '\\'], '', $rel), '/');
|
||||||
|
$full = $base_dir . '/' . $rel;
|
||||||
|
// Double-check it's still inside uploads
|
||||||
|
if (strpos(realpath($full) ?: $full, $base_dir) !== 0) {
|
||||||
|
throw new \RuntimeException("Path outside uploads directory.");
|
||||||
|
}
|
||||||
|
return $full;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function listDir(array $args): array {
|
||||||
|
$rel = $args['path'] ?? '';
|
||||||
|
$path = self::safePath($rel);
|
||||||
|
if (!is_dir($path)) throw new \RuntimeException("Directory not found: $rel");
|
||||||
|
|
||||||
|
$items = [];
|
||||||
|
foreach (scandir($path) as $entry) {
|
||||||
|
if ($entry === '.' || $entry === '..') continue;
|
||||||
|
$full = $path . '/' . $entry;
|
||||||
|
$items[] = [
|
||||||
|
'name' => $entry,
|
||||||
|
'type' => is_dir($full) ? 'dir' : 'file',
|
||||||
|
'size' => is_file($full) ? filesize($full) : null,
|
||||||
|
'modified' => date('Y-m-d H:i:s', filemtime($full)),
|
||||||
|
'url' => is_file($full) ? wp_upload_dir()['baseurl'] . '/' . ltrim($rel . '/' . $entry, '/') : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
usort($items, fn($a,$b) => ($a['type'] === $b['type']) ? strcmp($a['name'],$b['name']) : ($a['type']==='dir'?-1:1));
|
||||||
|
return ['path'=>$rel?:'/','items'=>$items,'count'=>count($items)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function readFile(array $args): array {
|
||||||
|
$rel = $args['path'] ?? '';
|
||||||
|
$path = self::safePath($rel);
|
||||||
|
if (!is_file($path)) throw new \RuntimeException("File not found: $rel");
|
||||||
|
|
||||||
|
$mime = mime_content_type($path) ?: 'application/octet-stream';
|
||||||
|
$size = filesize($path);
|
||||||
|
$text_mimes = ['text/','application/json','application/xml','application/javascript'];
|
||||||
|
$is_text = array_filter($text_mimes, fn($m) => str_starts_with($mime, $m));
|
||||||
|
|
||||||
|
return [
|
||||||
|
'path' => $rel,
|
||||||
|
'size' => $size,
|
||||||
|
'mime' => $mime,
|
||||||
|
'modified' => date('Y-m-d H:i:s', filemtime($path)),
|
||||||
|
'content' => $is_text ? file_get_contents($path) : base64_encode(file_get_contents($path)),
|
||||||
|
'encoding' => $is_text ? 'text' : 'base64',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function deleteFile(array $args): array {
|
||||||
|
$rel = $args['path'] ?? '';
|
||||||
|
$path = self::safePath($rel);
|
||||||
|
if (!file_exists($path)) throw new \RuntimeException("File not found: $rel");
|
||||||
|
if (is_dir($path)) throw new \RuntimeException("Use delete_directory to remove directories.");
|
||||||
|
if (!unlink($path)) throw new \RuntimeException("Failed to delete: $rel");
|
||||||
|
return ['path'=>$rel,'deleted'=>true];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function deleteDirectory(array $args): array {
|
||||||
|
$rel = $args['path'] ?? '';
|
||||||
|
if (empty($rel)) throw new \RuntimeException("Cannot delete uploads root.");
|
||||||
|
$path = self::safePath($rel);
|
||||||
|
if (!is_dir($path)) throw new \RuntimeException("Directory not found: $rel");
|
||||||
|
|
||||||
|
$files = new \RecursiveIteratorIterator(
|
||||||
|
new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||||
|
\RecursiveIteratorIterator::CHILD_FIRST
|
||||||
|
);
|
||||||
|
foreach ($files as $f) {
|
||||||
|
$f->isDir() ? rmdir($f->getRealPath()) : unlink($f->getRealPath());
|
||||||
|
}
|
||||||
|
rmdir($path);
|
||||||
|
return ['path'=>$rel,'deleted'=>true];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getUploadsInfo(array $args): array {
|
||||||
|
$uploads = wp_upload_dir();
|
||||||
|
$base = $uploads['basedir'];
|
||||||
|
$size = 0;
|
||||||
|
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($base)) as $f) {
|
||||||
|
if ($f->isFile()) $size += $f->getSize();
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'base_dir' => $base,
|
||||||
|
'base_url' => $uploads['baseurl'],
|
||||||
|
'total_size' => $size,
|
||||||
|
'total_size_human' => size_format($size),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user