Skip to main content
Glama
filesystem.php•8.2 kB
<?php /** * WPMCP File System Operations */ if (!defined('ABSPATH')) exit; class WPMCP_FileSystem { private $allowed_dirs = ['wp-content/themes', 'wp-content/plugins', 'wp-content/uploads', 'wp-content/mu-plugins']; private $allowed_extensions = ['php', 'js', 'css', 'scss', 'json', 'html', 'xml', 'txt', 'md', 'svg', 'jpg', 'png', 'gif']; private $max_file_size = 10485760; private $backup_dir = 'wp-content/wpmcp-backups'; public function __construct() { add_action('rest_api_init', [$this, 'register_routes']); $this->ensure_backup_dir(); } private function ensure_backup_dir() { $backup_path = ABSPATH . $this->backup_dir; if (!file_exists($backup_path)) { wp_mkdir_p($backup_path); file_put_contents($backup_path . '/.htaccess', "Deny from all\n"); } } public function register_routes() { $ns = 'wpmcp/v1'; register_rest_route($ns, '/file/read', ['methods' => 'POST', 'callback' => [$this, 'read_file'], 'permission_callback' => [$this, 'check_permissions']]); register_rest_route($ns, '/file/list', ['methods' => 'POST', 'callback' => [$this, 'list_files'], 'permission_callback' => [$this, 'check_permissions']]); register_rest_route($ns, '/file/info', ['methods' => 'POST', 'callback' => [$this, 'file_info'], 'permission_callback' => [$this, 'check_permissions']]); register_rest_route($ns, '/file/write', ['methods' => 'POST', 'callback' => [$this, 'write_file'], 'permission_callback' => [$this, 'check_permissions']]); register_rest_route($ns, '/file/delete', ['methods' => 'POST', 'callback' => [$this, 'delete_file'], 'permission_callback' => [$this, 'check_permissions']]); register_rest_route($ns, '/file/copy', ['methods' => 'POST', 'callback' => [$this, 'copy_file'], 'permission_callback' => [$this, 'check_permissions']]); register_rest_route($ns, '/file/move', ['methods' => 'POST', 'callback' => [$this, 'move_file'], 'permission_callback' => [$this, 'check_permissions']]); } public function check_permissions() { return current_user_can('edit_themes') && current_user_can('edit_plugins'); } private function validate_path($path) { $path = str_replace(['../', '..\\'], '', $path); $path = ltrim($path, '/\\'); foreach ($this->allowed_dirs as $dir) { if (strpos($path, $dir) === 0) { $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); if ($ext && !in_array($ext, $this->allowed_extensions)) { return new WP_Error('invalid_extension', 'Extension not allowed'); } return ABSPATH . $path; } } return new WP_Error('invalid_path', 'Path not allowed'); } private function create_backup($file_path) { if (!file_exists($file_path)) return null; $backup_id = uniqid('backup_', true); $backup_file = ABSPATH . $this->backup_dir . '/' . $backup_id . '.bak'; if (copy($file_path, $backup_file)) { $meta = ['original_path' => str_replace(ABSPATH, '', $file_path), 'timestamp' => current_time('mysql'), 'user_id' => get_current_user_id()]; file_put_contents($backup_file . '.meta', json_encode($meta)); return $backup_id; } return null; } public function read_file($request) { $file_path = $this->validate_path($request->get_param('path')); if (is_wp_error($file_path)) return $file_path; if (!file_exists($file_path)) return new WP_Error('file_not_found', 'File not found'); return ['content' => file_get_contents($file_path), 'size' => filesize($file_path), 'modified' => date('Y-m-d H:i:s', filemtime($file_path))]; } public function list_files($request) { $dir_path = $this->validate_path($request->get_param('path')); if (is_wp_error($dir_path)) return $dir_path; if (!is_dir($dir_path)) return new WP_Error('not_directory', 'Not a directory'); $files = []; $iterator = $request->get_param('recursive') ? new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir_path, RecursiveDirectoryIterator::SKIP_DOTS)) : new DirectoryIterator($dir_path); foreach ($iterator as $file) { if ($file->isDot()) continue; $files[] = [ 'path' => str_replace(ABSPATH, '', $file->getPathname()), 'name' => $file->getFilename(), 'type' => $file->isDir() ? 'directory' : 'file', 'size' => $file->isFile() ? $file->getSize() : 0, 'modified' => date('Y-m-d H:i:s', $file->getMTime()) ]; } return ['files' => $files]; } public function file_info($request) { $file_path = $this->validate_path($request->get_param('path')); if (is_wp_error($file_path)) return $file_path; if (!file_exists($file_path)) return new WP_Error('file_not_found', 'File not found'); return [ 'size' => filesize($file_path), 'modified' => date('Y-m-d H:i:s', filemtime($file_path)), 'permissions' => substr(sprintf('%o', fileperms($file_path)), -4), 'type' => is_dir($file_path) ? 'directory' : 'file' ]; } public function write_file($request) { $file_path = $this->validate_path($request->get_param('path')); if (is_wp_error($file_path)) return $file_path; $content = $request->get_param('content'); if (strlen($content) > $this->max_file_size) return new WP_Error('file_too_large', 'File too large'); $backup_id = null; if ($request->get_param('createBackup') && file_exists($file_path)) { $backup_id = $this->create_backup($file_path); } $dir = dirname($file_path); if (!is_dir($dir)) wp_mkdir_p($dir); $result = file_put_contents($file_path, $content); return $result !== false ? ['success' => true, 'backup' => $backup_id, 'bytes_written' => $result] : new WP_Error('write_failed', 'Write failed'); } public function delete_file($request) { $file_path = $this->validate_path($request->get_param('path')); if (is_wp_error($file_path)) return $file_path; if (!file_exists($file_path)) return new WP_Error('file_not_found', 'File not found'); $backup_id = $request->get_param('createBackup') ? $this->create_backup($file_path) : null; return unlink($file_path) ? ['success' => true, 'backup' => $backup_id] : new WP_Error('delete_failed', 'Delete failed'); } public function copy_file($request) { $source_path = $this->validate_path($request->get_param('source')); if (is_wp_error($source_path)) return $source_path; $dest_path = $this->validate_path($request->get_param('destination')); if (is_wp_error($dest_path)) return $dest_path; if (!file_exists($source_path)) return new WP_Error('source_not_found', 'Source not found'); $dir = dirname($dest_path); if (!is_dir($dir)) wp_mkdir_p($dir); return copy($source_path, $dest_path) ? ['success' => true] : new WP_Error('copy_failed', 'Copy failed'); } public function move_file($request) { $source_path = $this->validate_path($request->get_param('source')); if (is_wp_error($source_path)) return $source_path; $dest_path = $this->validate_path($request->get_param('destination')); if (is_wp_error($dest_path)) return $dest_path; if (!file_exists($source_path)) return new WP_Error('source_not_found', 'Source not found'); $dir = dirname($dest_path); if (!is_dir($dir)) wp_mkdir_p($dir); return rename($source_path, $dest_path) ? ['success' => true] : new WP_Error('move_failed', 'Move failed'); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/RaheesAhmed/wordpress-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server