| <?php |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| require_once __DIR__ . '/storage.php'; |
| require_once __DIR__ . '/user-manager.php'; |
|
|
| |
| error_log("VvvebJs Save Request - Method: " . ($_SERVER['REQUEST_METHOD'] ?? 'unknown')); |
| error_log("VvvebJs Save Request - Action: " . ($_GET['action'] ?? $_POST['action'] ?? 'none')); |
| error_log("VvvebJs Save Request - Has HTML: " . (isset($_POST['html']) ? 'yes' : 'no')); |
| error_log("VvvebJs Save Request - Has File: " . (isset($_POST['file']) ? 'yes' : 'no')); |
|
|
| |
| function checkAuth() { |
| $userManager = new UserManager(); |
| |
| |
| if ($userManager->isLoggedIn()) { |
| return true; |
| } |
| |
| |
| error_log("VvvebJs Auth Failed - Session logged in: " . ($userManager->isLoggedIn() ? 'yes' : 'no')); |
| error_log("VvvebJs Auth Failed - Session data: " . json_encode($_SESSION ?? [])); |
| |
| |
| if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { |
| header('Content-Type: application/json'); |
| http_response_code(401); |
| echo json_encode(['success' => false, 'message' => 'Authentication required', 'redirect' => 'index.html']); |
| exit; |
| } |
| |
| |
| header('Location: index.html'); |
| exit; |
| } |
|
|
| |
| $action = $_GET['action'] ?? $_POST['action'] ?? ''; |
|
|
| |
| error_log("VvvebJs Action Debug - GET action: " . ($_GET['action'] ?? 'none')); |
| error_log("VvvebJs Action Debug - POST action: " . ($_POST['action'] ?? 'none')); |
| error_log("VvvebJs Action Debug - Final action: '$action'"); |
|
|
| |
| if ($action === 'checkAuth') { |
| $userManager = new UserManager(); |
| if ($userManager->isLoggedIn()) { |
| http_response_code(200); |
| echo json_encode(['authenticated' => true, 'user' => $userManager->getCurrentUser()]); |
| } else { |
| http_response_code(401); |
| echo json_encode(['authenticated' => false]); |
| } |
| exit; |
| } |
|
|
| checkAuth(); |
|
|
| |
| $storageManager = new StorageManager(); |
|
|
| define('MAX_FILE_LIMIT', 1024 * 1024 * 2); |
| define('ALLOW_PHP', false); |
| define('ALLOWED_OEMBED_DOMAINS', [ |
| 'https://www.youtube.com/', |
| 'https://www.vimeo.com/', |
| 'https://www.x.com/', |
| 'https://x.com/', |
| 'https://publish.twitter.com/', |
| 'https://www.twitter.com/', |
| 'https://www.reddit.com/', |
| ]); |
|
|
| function sanitizeFileName($file, $allowedExtension = 'html') { |
| $basename = basename($file); |
| $disallow = ['.htaccess', 'passwd']; |
| if (in_array($basename, $disallow)) { |
| showError('Filename not allowed!'); |
| return ''; |
| } |
| |
| |
| $file = preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file))); |
| |
| if (!$file) { |
| return ''; |
| } |
| |
| |
| |
| $action = $_GET['action'] ?? $_POST['action'] ?? ''; |
| if ($action === 'loadFile' || $action === 'listFiles') { |
| |
| if ($allowedExtension) { |
| $file = preg_replace('/\.[^.]+$/', '', $file) . ".$allowedExtension"; |
| } |
| return $file; |
| } |
| |
| |
| $file = __DIR__ . DIRECTORY_SEPARATOR . $file; |
| |
| |
| if ($allowedExtension) { |
| $file = preg_replace('/\.[^.]+$/', '', $file) . ".$allowedExtension"; |
| } |
| return $file; |
| } |
|
|
| function showError($error) { |
| |
| if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { |
| header('Content-Type: application/json'); |
| http_response_code(500); |
| echo json_encode(['success' => false, 'message' => $error]); |
| exit; |
| } |
| |
| header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500); |
| die($error); |
| } |
|
|
| function validOembedUrl($url) { |
| foreach (ALLOWED_OEMBED_DOMAINS as $domain) { |
| if (strpos($url, $domain) === 0) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
|
|
| $html = ''; |
| $file = ''; |
|
|
| if (isset($_POST['startTemplateUrl']) && !empty($_POST['startTemplateUrl'])) { |
| $startTemplateUrl = sanitizeFileName($_POST['startTemplateUrl']); |
| $html = ''; |
| if ($startTemplateUrl) { |
| $html = file_get_contents($startTemplateUrl); |
| } |
| } else if (isset($_POST['html'])){ |
| $html = substr($_POST['html'], 0, MAX_FILE_LIMIT); |
| if (!ALLOW_PHP) { |
| |
| if (preg_match('@<\?php|<\? |<\?=|<\s*script\s*language\s*=\s*"\s*php\s*"\s*>@', $html)) { |
| showError('PHP not allowed!'); |
| } |
| } |
| } |
|
|
| if (isset($_POST['file'])) { |
| $file = sanitizeFileName($_POST['file']); |
| } |
|
|
| if ($action && $action !== '') { |
| |
| switch ($action) { |
| case 'listFiles': |
| |
| try { |
| $files = $storageManager->listFiles(); |
| |
| |
| $github = StorageConfig::getGitHubConfig(); |
| $debug = [ |
| 'hasToken' => !empty($github['token']), |
| 'owner' => $github['owner'], |
| 'repo' => $github['repo'], |
| 'branch' => $github['branch'], |
| 'path' => $github['path'], |
| 'user' => $storageManager->getCurrentUser(), |
| 'userPath' => $storageManager->getUserPath() |
| ]; |
| |
| error_log("GitHub List Files Debug: " . json_encode($debug)); |
| error_log("Files found: " . count($files)); |
| |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => true, |
| 'files' => $files, |
| 'user' => $storageManager->getCurrentUser(), |
| 'userPath' => $storageManager->getUserPath(), |
| 'debug' => $debug |
| ]); |
| } catch (Exception $e) { |
| error_log("GitHub List Files Error: " . $e->getMessage()); |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => false, |
| 'message' => 'Error loading files: ' . $e->getMessage(), |
| 'user' => $storageManager->getCurrentUser(), |
| 'files' => [] |
| ]); |
| } |
| exit; |
| |
| case 'loadFile': |
| |
| $filename = sanitizeFileName($_GET['file'] ?? ''); |
| error_log("VvvebJs LoadFile Debug - Original filename: " . ($_GET['file'] ?? '')); |
| error_log("VvvebJs LoadFile Debug - Sanitized filename: " . $filename); |
| |
| if ($filename) { |
| try { |
| $content = $storageManager->getFile($filename); |
| error_log("VvvebJs LoadFile Debug - Content length: " . ($content !== false ? strlen($content) : 'false')); |
| |
| if ($content !== false) { |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => true, |
| 'content' => $content, |
| 'filename' => $filename |
| ]); |
| } else { |
| |
| $github = StorageConfig::getGitHubConfig(); |
| $debugInfo = [ |
| 'filename' => $filename, |
| 'user' => $storageManager->getCurrentUser(), |
| 'userPath' => $storageManager->getUserPath(), |
| 'fullPath' => $github['path'] . $storageManager->getUserPath() . $filename, |
| 'hasToken' => !empty($github['token']), |
| 'repo' => $github['owner'] . '/' . $github['repo'] |
| ]; |
| |
| error_log("VvvebJs LoadFile Error - Debug info: " . json_encode($debugInfo)); |
| |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => false, |
| 'message' => 'File not found or access denied', |
| 'debug' => $debugInfo |
| ]); |
| } |
| } catch (Exception $e) { |
| error_log("VvvebJs LoadFile Exception: " . $e->getMessage()); |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => false, |
| 'message' => 'Error loading file: ' . $e->getMessage(), |
| 'filename' => $filename |
| ]); |
| } |
| } else { |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => false, |
| 'message' => 'Invalid filename' |
| ]); |
| } |
| exit; |
| |
| case 'checkAuth': |
| |
| header('Content-Type: application/json'); |
| echo json_encode([ |
| 'success' => true, |
| 'user' => $storageManager->getCurrentUser(), |
| 'authenticated' => true |
| ]); |
| exit; |
| |
| case 'rename': |
| $newfile = sanitizeFileName($_POST['newfile']); |
| if ($file && $newfile) { |
| |
| $content = $storageManager->getFile($file); |
| if ($content !== false) { |
| if ($storageManager->saveFile($newfile, $content)) { |
| $storageManager->deleteFile($file); |
| echo "File '$file' renamed to '$newfile'"; |
| } else { |
| showError("Error renaming file '$file' to '$newfile'"); |
| } |
| } else { |
| showError("File '$file' not found"); |
| } |
| } |
| break; |
| |
| case 'delete': |
| if ($file) { |
| if ($storageManager->deleteFile($file)) { |
| echo "File '$file' deleted"; |
| } else { |
| showError("Error deleting file '$file'"); |
| } |
| } |
| break; |
| |
| case 'saveReusable': |
| |
| $type = $_POST['type'] ?? false; |
| $name = $_POST['name'] ?? false; |
| $html = $_POST['html'] ?? false; |
| |
| if ($type && $name && $html) { |
| |
| $file = sanitizeFileName("$type/$name"); |
| if ($file) { |
| $dir = dirname($file); |
| if (!is_dir($dir)) { |
| echo "$dir folder does not exist\n"; |
| if (mkdir($dir, 0777, true)) { |
| echo "$dir folder was created\n"; |
| } else { |
| showError("Error creating folder '$dir'\n"); |
| } |
| } |
| |
| if (file_put_contents($file, $html)) { |
| echo "File saved '$file'"; |
| } else { |
| showError("Error saving file '$file'\nPossible causes are missing write permission or incorrect file path!"); |
| } |
| } else { |
| showError('Invalid filename!'); |
| } |
| } else { |
| showError("Missing reusable element data!\n"); |
| } |
| break; |
| case 'oembedProxy': |
| $url = $_GET['url'] ?? ''; |
| if (validOembedUrl($url)) { |
| $options = array( |
| 'http'=>array( |
| 'method'=>"GET", |
| 'header'=> 'User-Agent: ' . $_SERVER['HTTP_USER_AGENT'] . "\r\n" |
| ) |
| ); |
| $context = stream_context_create($options); |
| header('Content-Type: application/json'); |
| echo file_get_contents($url, false, $context ); |
| } else { |
| showError('Invalid url!'); |
| } |
| break; |
| } |
| } else { |
| |
| error_log("VvvebJs: No action specified, treating as save request"); |
| error_log("VvvebJs Save Request Debug - POST data keys: " . implode(', ', array_keys($_POST))); |
| |
| |
| if ($html) { |
| if ($file) { |
| |
| $relativePath = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $file); |
| $relativePath = str_replace('\\', '/', $relativePath); |
| |
| |
| error_log("VvvebJs Save Debug - File: $relativePath"); |
| error_log("VvvebJs Save Debug - HTML length: " . strlen($html)); |
| error_log("VvvebJs Save Debug - Storage type: " . StorageConfig::getStorageType()); |
| error_log("VvvebJs Save Debug - Current user: " . $storageManager->getCurrentUser()); |
| |
| |
| $externalSuccess = false; |
| $externalError = ''; |
| |
| try { |
| $externalSuccess = $storageManager->saveFile($relativePath, $html); |
| if (!$externalSuccess) { |
| $externalError = 'Storage manager returned false'; |
| } |
| } catch (Exception $e) { |
| $externalError = $e->getMessage(); |
| error_log("VvvebJs Save Error: " . $externalError); |
| } |
| |
| |
| $dir = dirname($file); |
| $localSuccess = false; |
| if (!is_dir($dir)) { |
| if (mkdir($dir, 0777, true)) { |
| error_log("VvvebJs: Created directory $dir"); |
| } |
| } |
| |
| if (is_dir($dir)) { |
| $localSuccess = file_put_contents($file, $html); |
| } |
| |
| |
| if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { |
| header('Content-Type: application/json'); |
| |
| if ($externalSuccess || $localSuccess) { |
| echo json_encode([ |
| 'success' => true, |
| 'message' => 'File saved successfully', |
| 'file' => $relativePath, |
| 'external_storage' => $externalSuccess, |
| 'local_cache' => $localSuccess !== false, |
| 'user' => $storageManager->getCurrentUser() |
| ]); |
| } else { |
| $github = StorageConfig::getGitHubConfig(); |
| echo json_encode([ |
| 'success' => false, |
| 'message' => 'Failed to save file', |
| 'external_error' => $externalError, |
| 'debug_info' => [ |
| 'has_token' => !empty($github['token']), |
| 'owner' => $github['owner'], |
| 'repo' => $github['repo'], |
| 'target_file' => $relativePath, |
| 'user' => $storageManager->getCurrentUser() |
| ] |
| ]); |
| } |
| exit; |
| } |
| |
| |
| if ($externalSuccess || $localSuccess) { |
| $message = "File saved '$file'"; |
| if ($externalSuccess) { |
| $message .= " β
(external storage SUCCESS)"; |
| } else { |
| $message .= " β (external storage FAILED: $externalError)"; |
| } |
| if ($localSuccess) { |
| $message .= " β
(local cache SUCCESS)"; |
| } else { |
| $message .= " β (local cache FAILED)"; |
| } |
| |
| |
| if (!$externalSuccess) { |
| $github = StorageConfig::getGitHubConfig(); |
| $message .= "\n\nπ Debug Info:"; |
| $message .= "\n- GitHub Token: " . (empty($github['token']) ? 'β Missing' : 'β
Present'); |
| $message .= "\n- GitHub Owner: " . ($github['owner'] ?: 'β Missing'); |
| $message .= "\n- GitHub Repo: " . ($github['repo'] ?: 'β Missing'); |
| $message .= "\n- GitHub Path: " . ($github['path'] ?: 'root'); |
| $message .= "\n- Target file: " . $relativePath; |
| } |
| |
| echo $message; |
| } else { |
| showError("Error saving file '$file'\nExternal: $externalError\nLocal: File write failed\nPossible causes are missing write permission or incorrect file path!"); |
| } |
| } else { |
| |
| if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { |
| header('Content-Type: application/json'); |
| echo json_encode(['success' => false, 'message' => 'Filename is empty!']); |
| exit; |
| } |
| showError('Filename is empty!'); |
| } |
| } else { |
| |
| if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { |
| header('Content-Type: application/json'); |
| echo json_encode(['success' => false, 'message' => 'Html content is empty!']); |
| exit; |
| } |
| showError('Html content is empty!'); |
| } |
| } |
|
|