File manager - Edit - /home/cipherteam/htdocs/cipherteam.in/admin3/bunny.php
Back
<?php include 'config.php'; session_start(); if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) { header("Location: login.php"); exit; } // BunnyCDN FTP Config $ftp_host = "storage.bunnycdn.com"; $ftp_user = "smipo"; $ftp_pass = "4fed9253-cd11-4cd3-bd6d1976382a-cd32-485c"; $ftp_port = 21; $cdn_base_url = "https://smipo.b-cdn.net/"; // BunnyCDN pull zone URL $uploadResults = []; $errors = []; if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_FILES['images']['name'][0])) { // Connect FTP $ftp = ftp_connect($ftp_host, $ftp_port, 30); if (!$ftp) { $errors[] = "Could not connect to BunnyCDN FTP server."; } else { $login = ftp_login($ftp, $ftp_user, $ftp_pass); if (!$login) { $errors[] = "FTP login failed. Check credentials."; } else { ftp_pasv($ftp, true); $fileCount = count($_FILES['images']['name']); for ($i = 0; $i < $fileCount; $i++) { $tmpName = $_FILES['images']['tmp_name'][$i]; $origName = $_FILES['images']['name'][$i]; $fileSize = $_FILES['images']['size'][$i]; $fileErr = $_FILES['images']['error'][$i]; if ($fileErr !== UPLOAD_ERR_OK) { $errors[] = "Upload error for '$origName': code $fileErr"; continue; } // Validate image $allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']; $mime = mime_content_type($tmpName); if (!in_array($mime, $allowed)) { $errors[] = "'$origName' is not a supported image type ($mime)."; continue; } // Max 10MB if ($fileSize > 10 * 1024 * 1024) { $errors[] = "'$origName' exceeds 10MB limit."; continue; } // Generate unique filename $ext = pathinfo($origName, PATHINFO_EXTENSION); $safeName = preg_replace('/[^a-zA-Z0-9_\-]/', '_', pathinfo($origName, PATHINFO_FILENAME)); $uniqueName = $safeName . '_' . time() . '_' . $i . '.' . $ext; $remotePath = "/" . $uniqueName; // Upload via FTP $uploaded = ftp_put($ftp, $remotePath, $tmpName, FTP_BINARY); if ($uploaded) { $cdnUrl = $cdn_base_url . $uniqueName; $uploadResults[] = [ 'name' => $origName, 'url' => $cdnUrl, 'size' => $fileSize ]; } else { $errors[] = "FTP upload failed for '$origName'."; } } ftp_close($ftp); } } } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Image Uploader — BunnyCDN</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="preconnect" href="https://fonts.googleapis.com"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <style> :root { --primary: #4f46e5; --primary-light: #e0e7ff; --primary-dark: #3730a3; --surface: #ffffff; --surface-alt: #f8fafc; --border: #e2e8f0; --text: #1e293b; --text-muted: #64748b; --success: #059669; --success-light: #ecfdf5; --danger: #dc2626; --danger-light: #fef2f2; --warning: #d97706; --warning-light: #fffbeb; --radius: 12px; --radius-sm: 8px; --shadow-sm: 0 1px 2px rgba(0,0,0,0.05); --shadow: 0 1px 3px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04); --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.08), 0 2px 4px -2px rgba(0,0,0,0.04); --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 4px 6px -4px rgba(0,0,0,0.04); } * { box-sizing: border-box; } body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background: #f1f5f9; color: var(--text); min-height: 100vh; margin: 0; padding: 0; } /* ── Top Bar ── */ .top-bar { background: var(--surface); border-bottom: 1px solid var(--border); padding: 16px 0; position: sticky; top: 0; z-index: 100; box-shadow: var(--shadow-sm); } .top-bar .inner { max-width: 860px; margin: 0 auto; padding: 0 24px; display: flex; align-items: center; justify-content: space-between; } .brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 20px; color: var(--primary); } .brand-icon { width: 36px; height: 36px; background: var(--primary); color: #fff; border-radius: 10px; display: grid; place-items: center; font-size: 18px; flex-shrink: 0; } .btn-back { background: var(--surface-alt); color: var(--text-muted); border: 1px solid var(--border); padding: 8px 18px; border-radius: var(--radius-sm); font-weight: 500; font-size: 13px; text-decoration: none; transition: all 0.2s; display: inline-flex; align-items: center; gap: 6px; } .btn-back:hover { background: var(--primary-light); color: var(--primary); border-color: var(--primary); } /* ── Main ── */ .main-wrap { max-width: 860px; margin: 0 auto; padding: 28px 24px 40px; } /* ── Alerts ── */ .alert-modern { border-radius: var(--radius-sm); padding: 14px 20px; font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 8px; margin-bottom: 16px; animation: slideDown 0.3s ease; } .alert-success-m { background: var(--success-light); color: var(--success); border: 1px solid #a7f3d0; } .alert-danger-m { background: var(--danger-light); color: var(--danger); border: 1px solid #fecaca; } @keyframes slideDown { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } /* ── Upload Card ── */ .upload-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; margin-bottom: 24px; } .upload-header { padding: 24px 28px 0; text-align: center; } .upload-icon { width: 56px; height: 56px; background: var(--primary-light); color: var(--primary); border-radius: 14px; display: inline-grid; place-items: center; font-size: 26px; margin-bottom: 14px; } .upload-title { font-size: 20px; font-weight: 700; color: var(--text); margin-bottom: 4px; } .upload-subtitle { font-size: 13px; color: var(--text-muted); margin-bottom: 0; } .upload-body { padding: 24px 28px 28px; } /* ── Drop Zone ── */ .drop-zone { border: 2px dashed var(--border); border-radius: var(--radius); padding: 40px 20px; text-align: center; cursor: pointer; transition: all 0.2s; background: var(--surface-alt); position: relative; margin-bottom: 16px; } .drop-zone:hover, .drop-zone.dragover { border-color: var(--primary); background: var(--primary-light); } .drop-zone input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; } .drop-icon { font-size: 36px; margin-bottom: 10px; } .drop-text { font-size: 14px; font-weight: 600; color: var(--text); } .drop-hint { font-size: 12px; color: var(--text-muted); margin-top: 4px; } /* ── File Preview List ── */ .file-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; max-height: 240px; overflow-y: auto; } .file-item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: var(--surface-alt); border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 13px; animation: slideDown 0.2s ease; } .file-thumb { width: 36px; height: 36px; border-radius: 6px; object-fit: cover; border: 1px solid var(--border); flex-shrink: 0; } .file-info { flex: 1; min-width: 0; } .file-name { font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .file-size { font-size: 11px; color: var(--text-muted); } .file-remove { width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer; display: grid; place-items: center; font-size: 12px; transition: all 0.2s; flex-shrink: 0; } .file-remove:hover { background: var(--danger-light); color: var(--danger); border-color: #fecaca; } /* ── Upload Button ── */ .btn-upload { width: 100%; padding: 13px; border: none; border-radius: var(--radius-sm); background: var(--primary); color: #fff; font-size: 15px; font-weight: 700; cursor: pointer; transition: all 0.2s; } .btn-upload:hover { background: var(--primary-dark); transform: translateY(-1px); box-shadow: var(--shadow-md); } .btn-upload:disabled { opacity: 0.5; cursor: not-allowed; transform: none; box-shadow: none; } /* ── Results Section ── */ .results-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; } .results-header { padding: 16px 24px; background: var(--surface-alt); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; } .results-title { font-size: 14px; font-weight: 700; color: var(--text); margin: 0; display: flex; align-items: center; gap: 8px; } .results-count { background: var(--success-light); color: var(--success); padding: 2px 10px; border-radius: 20px; font-size: 12px; font-weight: 700; } .results-body { padding: 0; } .result-item { padding: 16px 24px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 14px; transition: background 0.15s; } .result-item:last-child { border-bottom: none; } .result-item:hover { background: var(--surface-alt); } .result-thumb { width: 48px; height: 48px; border-radius: var(--radius-sm); object-fit: cover; border: 1px solid var(--border); background: linear-gradient(45deg, #e2e8f0 25%, transparent 25%), linear-gradient(-45deg, #e2e8f0 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #e2e8f0 75%), linear-gradient(-45deg, transparent 75%, #e2e8f0 75%); background-size: 8px 8px; background-position: 0 0, 0 4px, 4px -4px, -4px 0; flex-shrink: 0; } .result-info { flex: 1; min-width: 0; } .result-name { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 4px; } .result-url-wrap { display: flex; align-items: center; gap: 6px; } .result-url { font-size: 11px; color: var(--text-muted); font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; background: var(--surface-alt); border: 1px solid var(--border); padding: 4px 10px; border-radius: 4px; } .btn-copy { padding: 6px 14px; border-radius: 6px; font-size: 11px; font-weight: 600; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer; transition: all 0.2s; white-space: nowrap; flex-shrink: 0; } .btn-copy:hover { background: var(--primary-light); color: var(--primary); border-color: var(--primary); } .btn-copy.copied { background: var(--success-light); color: var(--success); border-color: #a7f3d0; } .btn-copy-all { padding: 7px 16px; border-radius: 6px; font-size: 12px; font-weight: 600; border: 1px solid var(--border); background: var(--surface); color: var(--text-muted); cursor: pointer; transition: all 0.2s; } .btn-copy-all:hover { background: var(--primary-light); color: var(--primary); border-color: var(--primary); } .result-size { font-size: 11px; color: #94a3b8; } /* ── Responsive ── */ @media (max-width: 640px) { .main-wrap { padding: 16px; } .upload-header { padding: 20px 20px 0; } .upload-body { padding: 20px; } .drop-zone { padding: 28px 16px; } .result-item { padding: 14px 16px; flex-wrap: wrap; } .result-url { font-size: 10px; } } </style> </head> <body> <!-- Top Bar --> <div class="top-bar"> <div class="inner"> <div class="brand"> <div class="brand-icon">☁️</div> CDN Upload </div> <a href="index.php" class="btn-back">← Back to List</a> </div> </div> <div class="main-wrap"> <!-- Errors --> <?php if (!empty($errors)): ?> <?php foreach ($errors as $err): ?> <div class="alert-modern alert-danger-m">⚠️ <?= htmlspecialchars($err) ?></div> <?php endforeach; ?> <?php endif; ?> <!-- Success count --> <?php if (!empty($uploadResults)): ?> <div class="alert-modern alert-success-m">✅ <?= count($uploadResults) ?> image<?= count($uploadResults) > 1 ? 's' : '' ?> uploaded successfully to BunnyCDN!</div> <?php endif; ?> <!-- Upload Card --> <div class="upload-card"> <div class="upload-header"> <div class="upload-icon">📤</div> <div class="upload-title">Upload to BunnyCDN</div> <p class="upload-subtitle">Drag & drop or select images — supports JPG, PNG, GIF, WebP, SVG (max 10MB each)</p> </div> <div class="upload-body"> <form method="POST" enctype="multipart/form-data" id="uploadForm"> <div class="drop-zone" id="dropZone"> <input type="file" name="images[]" id="fileInput" accept="image/*" multiple> <div class="drop-icon">☁️</div> <div class="drop-text">Click or drag images here</div> <div class="drop-hint">Single or multiple files · Uploads to /smipo/ folder</div> </div> <div class="file-list" id="fileList" style="display:none;"></div> <button type="submit" class="btn-upload" id="uploadBtn" disabled> Upload to CDN </button> </form> </div> </div> <!-- Results --> <?php if (!empty($uploadResults)): ?> <div class="results-card"> <div class="results-header"> <p class="results-title">✅ Uploaded Images</p> <div style="display:flex; align-items:center; gap:10px;"> <span class="results-count"><?= count($uploadResults) ?> file<?= count($uploadResults) > 1 ? 's' : '' ?></span> <button class="btn-copy-all" onclick="copyAllUrls()">Copy All URLs</button> </div> </div> <div class="results-body"> <?php foreach ($uploadResults as $idx => $res): ?> <div class="result-item"> <img src="<?= htmlspecialchars($res['url']) ?>" alt="Thumb" class="result-thumb" onerror="this.style.display='none';"> <div class="result-info"> <div class="result-name"><?= htmlspecialchars($res['name']) ?></div> <div class="result-url-wrap"> <span class="result-url" id="url-<?= $idx ?>"><?= htmlspecialchars($res['url']) ?></span> <button class="btn-copy" onclick="copyUrl(<?= $idx ?>, this)">Copy</button> </div> <div class="result-size"><?= round($res['size'] / 1024, 1) ?> KB</div> </div> </div> <?php endforeach; ?> </div> </div> <?php endif; ?> </div> <script> const fileInput = document.getElementById('fileInput'); const fileList = document.getElementById('fileList'); const dropZone = document.getElementById('dropZone'); const uploadBtn = document.getElementById('uploadBtn'); const uploadForm = document.getElementById('uploadForm'); let selectedFiles = new DataTransfer(); function renderFileList() { const files = selectedFiles.files; if (files.length === 0) { fileList.style.display = 'none'; uploadBtn.disabled = true; uploadBtn.textContent = 'Upload to CDN'; return; } fileList.style.display = 'flex'; uploadBtn.disabled = false; uploadBtn.textContent = `Upload ${files.length} Image${files.length > 1 ? 's' : ''} to CDN`; fileList.innerHTML = ''; for (let i = 0; i < files.length; i++) { const file = files[i]; const thumb = URL.createObjectURL(file); const size = (file.size / 1024).toFixed(1); const item = document.createElement('div'); item.className = 'file-item'; item.innerHTML = ` <img src="${thumb}" class="file-thumb" alt=""> <div class="file-info"> <div class="file-name">${file.name}</div> <div class="file-size">${size} KB</div> </div> <button type="button" class="file-remove" data-idx="${i}" title="Remove">✕</button> `; fileList.appendChild(item); } // Remove buttons fileList.querySelectorAll('.file-remove').forEach(btn => { btn.addEventListener('click', function() { const idx = parseInt(this.dataset.idx); const dt = new DataTransfer(); for (let i = 0; i < selectedFiles.files.length; i++) { if (i !== idx) dt.items.add(selectedFiles.files[i]); } selectedFiles = dt; fileInput.files = selectedFiles.files; renderFileList(); }); }); } fileInput.addEventListener('change', function() { for (let i = 0; i < this.files.length; i++) { selectedFiles.items.add(this.files[i]); } fileInput.files = selectedFiles.files; renderFileList(); }); // Drag & Drop dropZone.addEventListener('dragover', (e) => { e.preventDefault(); dropZone.classList.add('dragover'); }); dropZone.addEventListener('dragleave', () => { dropZone.classList.remove('dragover'); }); dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.classList.remove('dragover'); const files = e.dataTransfer.files; for (let i = 0; i < files.length; i++) { if (files[i].type.startsWith('image/')) { selectedFiles.items.add(files[i]); } } fileInput.files = selectedFiles.files; renderFileList(); }); // Loading state on submit uploadForm.addEventListener('submit', function() { uploadBtn.disabled = true; uploadBtn.textContent = '⏳ Uploading...'; }); // Copy single URL function copyUrl(idx, btn) { const url = document.getElementById('url-' + idx).textContent; navigator.clipboard.writeText(url).then(() => { btn.textContent = '✓ Copied'; btn.classList.add('copied'); setTimeout(() => { btn.textContent = 'Copy'; btn.classList.remove('copied'); }, 2000); }); } // Copy all URLs function copyAllUrls() { const urls = []; document.querySelectorAll('.result-url').forEach(el => urls.push(el.textContent)); navigator.clipboard.writeText(urls.join('\n')).then(() => { const btn = document.querySelector('.btn-copy-all'); btn.textContent = '✓ All Copied!'; setTimeout(() => { btn.textContent = 'Copy All URLs'; }, 2000); }); } </script> </body> </html>
| ver. 1.4 |
Github
|
.
| PHP 8.2.9 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings