[
'css' => [
'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.2/css/bootstrap.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.15/themes/default/style.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/codemirror.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/lint/lint.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/dialog/dialog.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/theme/monokai.css',
empty(EDITOR_THEME) ? '' : 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/theme/' . EDITOR_THEME . '.css',
'https://cdnjs.cloudflare.com/ajax/libs/izitoast/1.4.0/css/iziToast.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css',
],
'js' => [
'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.0/jquery.js',
'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.1/umd/popper.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.2/js/bootstrap.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.15/jstree.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/codemirror.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/javascript/javascript.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/css/css.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/php/php.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/xml/xml.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/htmlmixed/htmlmixed.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/markdown/markdown.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/mode/clike/clike.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/jshint/2.13.6/jshint.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/jsonlint/1.6.0/jsonlint.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/lint/lint.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/lint/javascript-lint.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/lint/json-lint.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/lint/css-lint.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/search/search.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/search/searchcursor.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/search/jump-to-line.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.14/addon/dialog/dialog.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/izitoast/1.4.0/js/iziToast.min.js',
'https://cdnjs.cloudflare.com/ajax/libs/js-sha512/0.8.0/sha512.min.js'
],
],
'local' => [
'css' => [
'node_modules/bootstrap/dist/css/bootstrap.min.css',
'node_modules/jstree/dist/themes/default/style.min.css',
'node_modules/codemirror/lib/codemirror.css',
'node_modules/codemirror/addon/lint/lint.css',
'node_modules/codemirror/addon/dialog/dialog.css',
'node_modules/codemirror//theme/monokai.css',
empty(EDITOR_THEME) ? '' : 'node_modules/codemirror/theme/' . EDITOR_THEME . '.css',
'node_modules/izitoast/dist/css/iziToast.min.css',
'node_modules/@fortawesome/fontawesome-free/css/all.min.css',
],
'js' => [
'node_modules/jquery/dist/jquery.min.js',
'node_modules/bootstrap/dist/js/bootstrap.bundle.min.js',
'node_modules/jstree/dist/jstree.min.js',
'node_modules/codemirror/lib/codemirror.js',
'node_modules/codemirror/mode/javascript/javascript.js',
'node_modules/codemirror/mode/css/css.js',
'node_modules/codemirror/mode/php/php.js',
'node_modules/codemirror/mode/xml/xml.js',
'node_modules/codemirror/mode/htmlmixed/htmlmixed.js',
'node_modules/codemirror/mode/markdown/markdown.js',
'node_modules/codemirror/mode/clike/clike.js',
'node_modules/jshint/dist/jshint.js',
// 'node_modules/jsonlint/lib/jsonlint.js',
'node_modules/codemirror/addon/lint/lint.js',
'node_modules/codemirror/addon/lint/javascript-lint.js',
// 'node_modules/codemirror/addon/lint/json-lint.js',
'node_modules/codemirror/addon/lint/css-lint.js',
'node_modules/codemirror/addon/search/search.js',
'node_modules/codemirror/addon/search/searchcursor.js',
'node_modules/codemirror/addon/search/jump-to-line.js',
'node_modules/codemirror/addon/dialog/dialog.js',
'node_modules/izitoast/dist/js/iziToast.min.js',
'node_modules/js-sha512/build/sha512.min.js'
],
],
];
if (empty(ACCESS_IP) === false && ACCESS_IP != $_SERVER['REMOTE_ADDR']) {
die('Your IP address is not allowed to access this page.');
}
if (file_exists(LOG_FILE)) {
$log = unserialize(file_get_contents(LOG_FILE));
if (empty($log)) {
$log = [];
}
if (isset($log[$_SERVER['REMOTE_ADDR']]) && $log[$_SERVER['REMOTE_ADDR']]['num'] > 3 && time() - $log[$_SERVER['REMOTE_ADDR']]['time'] < 86400) {
die('This IP address is blocked due to unsuccessful login attempts.');
}
foreach ($log as $key => $value) {
if (time() - $value['time'] > 86400) {
unset($log[$key]);
$log_updated = true;
}
}
if (isset($log_updated)) {
file_put_contents(LOG_FILE, serialize($log));
}
}
session_set_cookie_params(86400, dirname($_SERVER['REQUEST_URI']));
session_name('pheditor');
session_start();
if (empty(PASSWORD) === false && (isset($_SESSION['pheditor_admin'], $_SESSION['pheditor_password']) === false || $_SESSION['pheditor_admin'] !== true || $_SESSION['pheditor_password'] != PASSWORD)) {
if (isset($_POST['pheditor_password']) && empty($_POST['pheditor_password']) === false) {
$password_hash = hash('sha512', $_POST['pheditor_password']);
if ($password_hash === PASSWORD) {
session_regenerate_id(true);
$_SESSION['pheditor_admin'] = true;
$_SESSION['pheditor_password'] = $password_hash;
redirect();
} else {
$error = 'The entry password is not correct.';
$log = file_exists(LOG_FILE) ? unserialize(file_get_contents(LOG_FILE)) : array();
if (isset($log[$_SERVER['REMOTE_ADDR']]) === false) {
$log[$_SERVER['REMOTE_ADDR']] = array('num' => 0, 'time' => 0);
}
$log[$_SERVER['REMOTE_ADDR']]['num'] += 1;
$log[$_SERVER['REMOTE_ADDR']]['time'] = time();
file_put_contents(LOG_FILE, serialize($log));
}
} else if (isset($_POST['action'])) {
header('HTTP/1.0 403 Forbidden');
die('Your session has expired.');
}
die('
Pheditor');
}
if (isset($_GET['logout'])) {
if ($_GET['logout'] == $_SESSION['pheditor_token']) {
unset($_SESSION['pheditor_admin']);
session_destroy();
}
redirect();
}
$permissions = explode(',', PERMISSIONS);
$permissions = array_map('trim', $permissions);
$permissions = array_filter($permissions);
if (count($permissions) < 1) {
$permissions = explode(',', 'newfile,newdir,editfile,deletefile,deletedir,renamefile,renamedir,changepassword,uploadfile');
}
if (isset($_GET['path'])) {
header('Content-Type: application/json');
$dir = realpath(rtrim(MAIN_DIR . DS . trim($_GET['path'], '/'), '/'));
if ($dir === false || check_path($dir) !== true) {
die('[]');
}
$files = array_slice(scandir($dir), 2);
$list = [];
asort($files);
foreach ($files as $key => $file) {
if (substr($file, 0, 1) === '.' || (SHOW_PHP_SELF === false && $dir . DS . $file == __FILE__)) {
continue;
}
if (is_dir($dir . DS . $file) && (empty(PATTERN_DIRECTORIES) || preg_match(PATTERN_DIRECTORIES, $file))) {
$dir_path = str_replace([MAIN_DIR, DS], ['', '/'], $dir . DS . $file . DS);
$list[] = [
'text' => $file,
'icon' => 'far fa-folder',
'children' => true,
'a_attr' => [
'href' => '#' . $dir_path,
'data-dir' => $dir_path
],
'state' => [
'selected' => false,
],
];
} else if (empty(PATTERN_FILES) || preg_match(PATTERN_FILES, $file)) {
$file_path = str_replace([MAIN_DIR, DS], ['', '/'], $dir . DS . $file);
$list[] = [
'text' => $file,
'icon' => 'far fa-file',
'a_attr' => [
'href' => '#' . $file_path,
'data-file' => $file_path
],
'state' => [
'selected' => false,
],
];
}
}
if (empty($_GET['path'])) {
$list = [
'text' => '/',
'icon' => 'far fa-folder',
'children' => $list,
'a_attr' => [
'href' => '#/',
'data-dir' => '/',
],
'state' => [
'selected' => false,
],
];
}
die(json_encode($list, JSON_UNESCAPED_UNICODE));
} else if (isset($_POST['action'])) {
header('Content-Type: application/json');
$post_token = $_POST['token'] ?? null;
$session_token = $_SESSION['pheditor_token'] ?? null;
if (empty($post_token) || $post_token != $session_token) {
die(json_error('Invalid token. Please reload the page.'));
}
if (isset($_POST['file']) && empty($_POST['file']) === false) {
$_POST['file'] = urldecode($_POST['file']);
if (empty(PATTERN_FILES) === false && !preg_match(PATTERN_FILES, basename($_POST['file']))) {
die(json_error('Invalid file pattern'));
}
}
foreach (['file', 'dir', 'path', 'name', 'destination'] as $value) {
if (isset($_POST[$value]) && empty($_POST[$value]) === false) {
$value = urldecode($_POST[$value]);
if (strpos($value, '../') !== false || strpos($value, '..\\') !== false) {
die(json_error('Invalid path'));
}
}
}
switch ($_POST['action']) {
case 'open':
$_POST['file'] = urldecode($_POST['file']);
if (isset($_POST['file']) && file_exists(MAIN_DIR . $_POST['file'])) {
die(json_success('OK', [
'data' => file_get_contents(MAIN_DIR . $_POST['file']),
]));
}
break;
case 'save':
$file = MAIN_DIR . $_POST['file'];
if (isset($_POST['file']) && isset($_POST['data']) && (file_exists($file) === false || is_writable($file))) {
if (file_exists($file) === false) {
if (in_array('newfile', $permissions) !== true) {
die(json_error('Permission denied', true));
}
file_put_contents($file, $_POST['data']);
if (function_exists('chmod')) {
chmod($file, DEFAULT_FILE_PERMISSION);
}
echo json_success('File saved successfully');
} else if (is_writable($file) === false) {
echo json_error('File is not writable');
} else {
if (in_array('editfile', $permissions) !== true) {
die(json_error('Permission denied'));
}
if (file_exists($file)) {
file_to_history($file);
}
file_put_contents($file, $_POST['data']);
echo json_success('File saved successfully');
}
}
break;
case 'make-dir':
if (in_array('newdir', $permissions) !== true) {
die(json_error('Permission denied'));
}
$dir = MAIN_DIR . $_POST['dir'];
if (file_exists($dir) === false) {
mkdir($dir, DEFAULT_DIR_PERMISSION);
if (function_exists('chmod')) {
chmod($dir, DEFAULT_DIR_PERMISSION);
}
echo json_success('Directory created successfully');
} else {
echo json_error('Directory already exists');
}
break;
case 'reload':
echo json_success('OK', [
'data' => files(MAIN_DIR),
]);
break;
case 'password':
if (in_array('changepassword', $permissions) !== true) {
die(json_error('Permission denied'));
}
if (isset($_POST['password']) && empty($_POST['password']) === false) {
$contents = file(__FILE__);
$password_hash = hash('sha512', $_POST['password']);
foreach ($contents as $key => $line) {
if (strpos($line, 'define(\'PASSWORD\'') !== false) {
$contents[$key] = "define('PASSWORD', '" . $password_hash . "');\n";
break;
}
}
if (is_writable(__FILE__) === false) {
die(json_error('File is not writable'));
}
file_put_contents(__FILE__, implode($contents));
$_SESSION['pheditor_password'] = $password_hash;
session_regenerate_id(true);
echo json_success('Password changed successfully');
}
break;
case 'delete':
if (isset($_POST['path']) && file_exists(MAIN_DIR . $_POST['path']) && check_path(MAIN_DIR . $_POST['path'])) {
$path = MAIN_DIR . $_POST['path'];
if ($_POST['path'] == '/') {
echo json_error('Unable to delete main directory');
} else if (is_dir($path)) {
if (count(scandir($path)) !== 2) {
echo json_error('Directory is not empty');
} else if (is_writable($path) === false) {
echo json_error('Unable to delete directory');
} else {
if (in_array('deletedir', $permissions) !== true) {
die(json_error('Permission denied'));
}
rmdir($path);
echo json_success('Directory deleted successfully');
}
} else {
if (empty(PATTERN_FILES) === false && !preg_match(PATTERN_FILES, basename($_POST['path']))) {
die(json_error('Invalid file patterna'));
}
file_to_history($path);
if (is_writable($path)) {
if (in_array('deletefile', $permissions) !== true) {
die(json_error('Permission denied'));
}
unlink($path);
echo json_success('File deleted successfully');
} else {
echo json_error('Unable to delete file');
}
}
}
break;
case 'rename':
if (isset($_POST['path']) && file_exists(MAIN_DIR . $_POST['path']) && isset($_POST['name']) && empty($_POST['name']) === false) {
$path = MAIN_DIR . $_POST['path'];
$new_path = str_replace(basename($path), '', dirname($path)) . DS . $_POST['name'];
if ($_POST['path'] == '/') {
echo json_error('Unable to rename main directory');
} else if (is_dir($path)) {
if (in_array('renamedir', $permissions) !== true) {
die(json_error('Permission denied'));
}
if (is_writable($path) === false) {
echo json_error('Unable to rename directory');
} else {
rename($path, $new_path);
echo json_success('Directory renamed successfully');
}
} else {
if (in_array('renamefile', $permissions) !== true) {
die(json_error('Permission denied'));
} else if (empty(PATTERN_FILES) === false && !preg_match(PATTERN_FILES, $_POST['name'])) {
die(json_error('Invalid file pattern: ' . htmlspecialchars($_POST['name'])));
}
file_to_history($path);
if (is_writable($path)) {
rename($path, $new_path);
echo json_success('File renamed successfully');
} else {
echo json_error('Unable to rename file');
}
}
}
break;
case 'upload-file':
$files = isset($_FILES['uploadfile']) ? $_FILES['uploadfile'] : [];
$destination = isset($_POST['destination']) ? rtrim($_POST['destination']) : null;
if (empty($destination) === false && (strpos($destination, '/..') !== false || strpos($destination, '\\..') !== false)) {
die(json_error('Invalid file destination'));
}
$destination = MAIN_DIR . $destination;
if (file_exists($destination) === false || is_dir($destination) === false) {
die(json_error('File destination does not exists'));
}
if (is_writable($destination) !== true) {
die(json_error('File destination is not writable'));
}
if (is_array($files) && count($files) > 0) {
for ($i = 0; $i < count($files['name']); $i += 1) {
if (empty(PATTERN_FILES) === false && !preg_match(PATTERN_FILES, $files['name'][$i])) {
die(json_error('Invalid file pattern: ' . htmlspecialchars($files['name'][$i])));
}
move_uploaded_file($files['tmp_name'][$i], $destination . '/' . $files['name'][$i]);
}
echo json_success('File' . (count($files['name']) > 1 ? 's' : null) . ' uploaded successfully');
}
break;
case 'terminal':
if (in_array('terminal', $permissions) !== false && isset($_POST['command'], $_POST['dir'])) {
if (function_exists('shell_exec') === false) {
echo json_error("shell_exec function is disabled\n");
exit;
}
set_time_limit(15);
$command = $_POST['command'];
$dir = $_POST['dir'];
if (strpos($command, '&') !== false || strpos($command, ';') !== false || strpos($command, '||') !== false) {
echo json_error("Illegal character(s) in command (& ; ||)\n");
exit;
}
$command_found = false;
$terminal_commands = explode(',', TERMINAL_COMMANDS);
foreach ($terminal_commands as $value) {
$value = trim($value);
if (strlen($command) >= strlen($value) && substr($command, 0, strlen($value)) == $value) {
$command_found = true;
break;
}
}
if ($command_found === false) {
foreach ($terminal_commands as $key => $value) {
$commands[$key % 3] = isset($commands[$key % 3]) ? $commands[$key % 3] . "\t" . $value : $value;
}
echo json_error("Command not allowed\nAvailable commands:\n" . implode("\n", $commands) . "\n");
exit;
}
$output = shell_exec((empty($dir) ? null : 'cd ' . $dir . ' && ') . $command . ' && echo \ ; pwd');
$output = trim($output);
if (empty($output)) {
$output = null;
$dir = null;
} else {
$output = explode("\n", $output);
$dir = end($output);
unset($output[count($output) - 1]);
$output = implode("\n", $output);
$output = trim($output) . "\n";
$output = htmlspecialchars($output);
}
echo json_success('OK', ['result' => $output, 'dir' => $dir]);
}
break;
}
exit;
}
function redirect($address = null)
{
if (empty($address)) {
$address = $_SERVER['SCRIPT_NAME'];
}
header('Location: ' . $address);
exit;
}
function file_to_history($file)
{
if (is_numeric(MAX_HISTORY_FILES) && MAX_HISTORY_FILES > 0) {
$file_dir = dirname($file);
$file_name = basename($file);
$file_history_dir = HISTORY_PATH . str_replace(MAIN_DIR, '', $file_dir);
foreach ([HISTORY_PATH, $file_history_dir] as $dir) {
if (file_exists($dir) === false || is_dir($dir) === false) {
mkdir($dir, 0777, true);
}
}
$history_files = scandir($file_history_dir);
foreach ($history_files as $key => $history_file) {
if (in_array($history_file, ['.', '..', '.DS_Store'])) {
unset($history_files[$key]);
}
}
$history_files = array_values($history_files);
if (count($history_files) >= MAX_HISTORY_FILES) {
foreach ($history_files as $key => $history_file) {
if ($key < 1) {
unlink($file_history_dir . DS . $history_file);
unset($history_files[$key]);
} else {
rename($file_history_dir . DS . $history_file, $file_history_dir . DS . $file_name . '.' . ($key - 1));
}
}
}
copy($file, $file_history_dir . DS . $file_name . '.' . count($history_files));
}
}
function json_error($message, $params = [])
{
return json_encode(array_merge([
'error' => true,
'message' => $message,
], $params), JSON_UNESCAPED_UNICODE);
}
function json_success($message, $params = [])
{
return json_encode(array_merge([
'error' => false,
'message' => $message,
], $params), JSON_UNESCAPED_UNICODE);
}
function check_path($path, $check_existence = true)
{
if ($check_existence === false) {
$path = dirname($path);
}
$real_path = realpath($path);
if (strpos($real_path, MAIN_DIR) === 0) {
return true;
}
return false;
}
$_SESSION['pheditor_token'] = bin2hex(random_bytes(32));
?>
Pheditor
You are using Pheditor with default password. Please click here to change password after installation.
Terminal
= implode(' ', $value[1]) ?>
= $value[0] ?>