Download save.php from CatPtain/VvvebJs: direct link, hf CLI and curl.
- Browser
- Download file 15.7 kB
-
https://huggingface.co/spaces/CatPtain/VvvebJs/resolve/main/save.php
- Command line
-
hf download hf://spaces/CatPtain/VvvebJs/save.php
-
curl -L -o save.php https://huggingface.co/spaces/CatPtain/VvvebJs/resolve/main/save.php
15.7 kB
| /* | |
| Copyright 2017 Ziadin Givan | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| https://github.com/givanz/VvvebJs | |
| */ | |
| // Include storage classes | |
| require_once __DIR__ . '/storage.php'; | |
| require_once __DIR__ . '/user-manager.php'; | |
| // Enhanced error logging for debugging | |
| 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')); | |
| // Authentication check | |
| function checkAuth() { | |
| $userManager = new UserManager(); | |
| // Check if user is logged in via session | |
| if ($userManager->isLoggedIn()) { | |
| return true; | |
| } | |
| // Enhanced auth error logging | |
| error_log("VvvebJs Auth Failed - Session logged in: " . ($userManager->isLoggedIn() ? 'yes' : 'no')); | |
| error_log("VvvebJs Auth Failed - Session data: " . json_encode($_SESSION ?? [])); | |
| // For AJAX requests, return JSON error instead of redirect | |
| 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; | |
| } | |
| // No authentication found - redirect to index.html which is the login page | |
| header('Location: index.html'); | |
| exit; | |
| } | |
| // Check authentication | |
| $action = $_GET['action'] ?? $_POST['action'] ?? ''; | |
| // Enhanced debug logging for action detection | |
| 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'"); | |
| // Special handling for auth check | |
| 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(); | |
| // Initialize storage manager | |
| $storageManager = new StorageManager(); | |
| define('MAX_FILE_LIMIT', 1024 * 1024 * 2);//2 Megabytes max html file size | |
| define('ALLOW_PHP', false);//check if saved html contains php tag and don't save if not allowed | |
| 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/', | |
| ]);//load urls only from allowed websites for oembed | |
| function sanitizeFileName($file, $allowedExtension = 'html') { | |
| $basename = basename($file); | |
| $disallow = ['.htaccess', 'passwd']; | |
| if (in_array($basename, $disallow)) { | |
| showError('Filename not allowed!'); | |
| return ''; | |
| } | |
| //sanitize, remove double dot .. and remove get parameters if any | |
| $file = preg_replace('@\?.*$@' , '', preg_replace('@\.{2,}@' , '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file))); | |
| if (!$file) { | |
| return ''; | |
| } | |
| // For loadFile action, return the sanitized filename as-is for storage manager | |
| // Only add __DIR__ for local file operations | |
| $action = $_GET['action'] ?? $_POST['action'] ?? ''; | |
| if ($action === 'loadFile' || $action === 'listFiles') { | |
| // For external storage operations, just sanitize and add extension | |
| if ($allowedExtension) { | |
| $file = preg_replace('/\.[^.]+$/', '', $file) . ".$allowedExtension"; | |
| } | |
| return $file; | |
| } | |
| // For local file operations, add the full path | |
| $file = __DIR__ . DIRECTORY_SEPARATOR . $file; | |
| //allow only .html extension | |
| if ($allowedExtension) { | |
| $file = preg_replace('/\.[^.]+$/', '', $file) . ".$allowedExtension"; | |
| } | |
| return $file; | |
| } | |
| function showError($error) { | |
| // Enhanced error response for AJAX requests | |
| 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 (strpos($html, '<?php') !== false) { | |
| 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 !== '') { | |
| //file manager actions, delete and rename | |
| switch ($action) { | |
| case 'listFiles': | |
| // List files for current user with enhanced error handling | |
| try { | |
| $files = $storageManager->listFiles(); | |
| // Enhanced debugging | |
| $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': | |
| // Load a specific file for current user | |
| $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 { | |
| // Enhanced error information | |
| $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': | |
| // Check if user is authenticated | |
| 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) { | |
| // For user isolation, we need to handle this through storage manager | |
| $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': | |
| //block or section | |
| $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 { | |
| // No action specified - this should be a save request | |
| error_log("VvvebJs: No action specified, treating as save request"); | |
| error_log("VvvebJs Save Request Debug - POST data keys: " . implode(', ', array_keys($_POST))); | |
| //save page | |
| if ($html) { | |
| if ($file) { | |
| // Extract relative filename for external storage | |
| $relativePath = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $file); | |
| $relativePath = str_replace('\\', '/', $relativePath); | |
| // Enhanced debug logging | |
| 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()); | |
| // Try external storage first | |
| $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); | |
| } | |
| // Also save locally as backup/cache | |
| $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); | |
| } | |
| // Enhanced JSON response for AJAX requests | |
| 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; | |
| } | |
| // Traditional text response for non-AJAX requests | |
| 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)"; | |
| } | |
| // Additional GitHub debug info | |
| 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 { | |
| // For AJAX requests, return JSON error | |
| 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 { | |
| // For AJAX requests, return JSON error | |
| 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!'); | |
| } | |
| } | |