231 lines
6.2 KiB
PHP
Executable File
231 lines
6.2 KiB
PHP
Executable File
|
|
<?php
|
|
// Désactiver l'affichage d'erreurs dans la sortie
|
|
error_reporting(0);
|
|
ini_set('display_errors', 0);
|
|
|
|
// Headers JSON
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
exit(0);
|
|
}
|
|
|
|
// Fonction pour répondre en JSON
|
|
function jsonResponse($data) {
|
|
echo json_encode($data, JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
function jsonError($message) {
|
|
jsonResponse(['success' => false, 'error' => $message]);
|
|
}
|
|
|
|
try {
|
|
$action = isset($_GET['action']) ? $_GET['action'] : (isset($_POST['action']) ? $_POST['action'] : 'list');
|
|
$path = isset($_GET['path']) ? $_GET['path'] : (isset($_POST['path']) ? $_POST['path'] : '/opt/wevads');
|
|
|
|
switch ($action) {
|
|
case 'list':
|
|
listDirectory($path);
|
|
break;
|
|
|
|
case 'read':
|
|
$file = isset($_GET['file']) ? $_GET['file'] : (isset($_POST['file']) ? $_POST['file'] : '');
|
|
readFileContent($file);
|
|
break;
|
|
|
|
case 'terminal':
|
|
case 'shell':
|
|
$cmd = isset($_POST['command']) ? $_POST['command'] : '';
|
|
if(empty($cmd)){echo json_encode(['success'=>false,'error'=>'No command']);break;}
|
|
$blocked=['rm -rf /','mkfs',':(){ :|:'];
|
|
foreach($blocked as $b){if(stripos($cmd,$b)!==false){echo json_encode(['success'=>false,'error'=>'Blocked']);break 2;}}
|
|
$output=shell_exec('sudo '.$cmd.' 2>&1');
|
|
echo json_encode(['success'=>true,'output'=>$output,'command'=>$cmd]);
|
|
break;
|
|
|
|
case 'save':
|
|
$file = isset($_POST['file']) ? $_POST['file'] : '';
|
|
$content = isset($_POST['content']) ? $_POST['content'] : '';
|
|
saveFileContent($file, $content);
|
|
break;
|
|
|
|
case 'terminal':
|
|
$command = isset($_POST['command']) ? $_POST['command'] : '';
|
|
$cwd = isset($_POST['cwd']) ? $_POST['cwd'] : '/opt/wevads';
|
|
executeCommand($command, $cwd);
|
|
break;
|
|
|
|
default:
|
|
listDirectory('/opt/wevads');
|
|
}
|
|
} catch (Exception $e) {
|
|
jsonError($e->getMessage());
|
|
}
|
|
|
|
function listDirectory($path) {
|
|
// Valider le chemin
|
|
if (empty($path)) {
|
|
$path = '/opt/wevads';
|
|
}
|
|
|
|
// Résoudre le chemin réel
|
|
$realPath = @realpath($path);
|
|
if ($realPath === false) {
|
|
$realPath = '/opt/wevads';
|
|
}
|
|
|
|
if (!is_dir($realPath)) {
|
|
jsonError('Not a directory: ' . $path);
|
|
}
|
|
|
|
$items = [];
|
|
$files = @scandir($realPath);
|
|
|
|
if ($files === false) {
|
|
jsonError('Cannot read directory: ' . $realPath);
|
|
}
|
|
|
|
foreach ($files as $file) {
|
|
if ($file === '.' || $file === '..') continue;
|
|
|
|
$fullPath = $realPath . DIRECTORY_SEPARATOR . $file;
|
|
$isDir = is_dir($fullPath);
|
|
$ext = $isDir ? '' : strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
|
|
|
$items[] = [
|
|
'name' => $file,
|
|
'path' => $fullPath,
|
|
'type' => $isDir ? 'directory' : 'file',
|
|
'size' => $isDir ? 0 : (int)@filesize($fullPath),
|
|
'modified' => (int)@filemtime($fullPath),
|
|
'extension' => $ext
|
|
];
|
|
}
|
|
|
|
// Trier: dossiers d'abord
|
|
usort($items, function($a, $b) {
|
|
if ($a['type'] !== $b['type']) {
|
|
return $a['type'] === 'directory' ? -1 : 1;
|
|
}
|
|
return strcasecmp($a['name'], $b['name']);
|
|
});
|
|
|
|
jsonResponse([
|
|
'success' => true,
|
|
'path' => $realPath,
|
|
'parent' => dirname($realPath),
|
|
'items' => $items,
|
|
'count' => count($items)
|
|
]);
|
|
}
|
|
|
|
function readFileContent($file) {
|
|
if (empty($file)) {
|
|
jsonError('No file specified');
|
|
}
|
|
|
|
if (!file_exists($file)) {
|
|
jsonError('File not found: ' . $file);
|
|
}
|
|
|
|
if (is_dir($file)) {
|
|
jsonError('Is a directory');
|
|
}
|
|
|
|
$size = @filesize($file);
|
|
if ($size > 5 * 1024 * 1024) {
|
|
jsonError('File too large (max 5MB)');
|
|
}
|
|
|
|
$content = @file_get_contents($file);
|
|
if ($content === false) {
|
|
jsonError('Cannot read file');
|
|
}
|
|
|
|
// Vérifier si binaire
|
|
$isBinary = false;
|
|
if (strlen($content) > 0) {
|
|
$sample = substr($content, 0, 8192);
|
|
$isBinary = preg_match('/[\x00-\x08\x0E-\x1F]/', $sample) === 1;
|
|
}
|
|
|
|
jsonResponse([
|
|
'success' => true,
|
|
'file' => $file,
|
|
'name' => basename($file),
|
|
'content' => $isBinary ? '[Binary file]' : $content,
|
|
'size' => (int)$size,
|
|
'binary' => $isBinary,
|
|
'extension' => strtolower(pathinfo($file, PATHINFO_EXTENSION))
|
|
]);
|
|
}
|
|
|
|
function saveFileContent($file, $content) {
|
|
if (empty($file)) {
|
|
jsonError('No file specified');
|
|
}
|
|
|
|
$result = @file_put_contents($file, $content);
|
|
|
|
if ($result === false) {
|
|
jsonError('Cannot write file');
|
|
}
|
|
|
|
jsonResponse([
|
|
'success' => true,
|
|
'file' => $file,
|
|
'size' => (int)$result
|
|
]);
|
|
}
|
|
|
|
function executeCommand($command, $cwd) {
|
|
if (empty($command)) {
|
|
jsonError('No command');
|
|
}
|
|
|
|
// Commandes bloquées
|
|
$blocked = ['rm -rf /', 'rm -rf /*', 'mkfs', 'dd if=/dev'];
|
|
foreach ($blocked as $b) {
|
|
if (stripos($command, $b) !== false) {
|
|
jsonError('Command blocked');
|
|
}
|
|
}
|
|
|
|
if (!is_dir($cwd)) {
|
|
$cwd = '/opt/wevads';
|
|
}
|
|
|
|
$descriptors = [
|
|
0 => ['pipe', 'r'],
|
|
1 => ['pipe', 'w'],
|
|
2 => ['pipe', 'w']
|
|
];
|
|
|
|
$process = @proc_open($command, $descriptors, $pipes, $cwd, [
|
|
'PATH' => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
|
|
]);
|
|
|
|
if (!is_resource($process)) {
|
|
jsonError('Cannot execute command');
|
|
}
|
|
|
|
fclose($pipes[0]);
|
|
$stdout = stream_get_contents($pipes[1]);
|
|
$stderr = stream_get_contents($pipes[2]);
|
|
fclose($pipes[1]);
|
|
fclose($pipes[2]);
|
|
$exitCode = proc_close($process);
|
|
|
|
jsonResponse([
|
|
'success' => true,
|
|
'stdout' => $stdout,
|
|
'stderr' => $stderr,
|
|
'exitCode' => (int)$exitCode
|
|
]);
|
|
}
|
|
|