diff --git a/classes/Backup.php b/classes/Backup.php
new file mode 100644
index 0000000..59c2102
--- /dev/null
+++ b/classes/Backup.php
@@ -0,0 +1,100 @@
+fileClass = new File();
+ }
+
+ public function makeBackup($fileLoc, $fileName, $contents) {
+ global $ftpSite, $t, $ICEcoder;
+
+ $backupDirFormat = "Y-m-d";
+
+ // Establish the base, host and date dir parts...
+ $backupDirBase = str_replace("\\", "/", dirname(__FILE__)) . "/../data/backups/";
+ $backupDirHost = isset($ftpSite) ? parse_url($ftpSite, PHP_URL_HOST) : "localhost";
+ $backupDirDate = date($backupDirFormat);
+
+ // Establish an array of dirs from base to our file location
+ $subDirsArray = explode("/", ltrim($fileLoc, "/"));
+ array_unshift($subDirsArray, $backupDirHost, $backupDirDate);
+ // Make any dirs that don't exist if full path isn't there
+ if (!is_dir($backupDirBase . implode("/", $subDirsArray))) {
+ $pathIncr = "";
+ for ($i = 0; $i < count($subDirsArray); $i++) {
+ $pathIncr .= $subDirsArray[$i] . "/";
+ // If this subdir isn't there, make it
+ if (!is_dir($backupDirBase . $pathIncr)) {
+ mkdir($backupDirBase . $pathIncr);
+ }
+ }
+ }
+ // We should have our dir path now so set that
+ $backupDir = $backupDirBase . implode("/", $subDirsArray);
+ // Work out an available filename (we postfix a number in parens)
+ for ($i = 1; $i < 1000000000; $i++) {
+ if (!file_exists($backupDir . '/' . $fileName . " (" . $i . ")")) {
+ $backupFileName = $fileName . " (" . $i . ")";
+ $backupFileNum = $i;
+ $i = 1000000000;
+ }
+ }
+
+ // Now save within that backup dir and clear the statcache
+ $fh = fopen($backupDir . "/" . $backupFileName, "w") or die($t['Sorry, cannot save...']);
+ fwrite($fh, $contents);
+ fclose($fh);
+ clearstatcache();
+
+ // Log the version count in an index file, which contains saved version counts
+ $backupIndex = $backupDirBase . $backupDirHost . "/" . $backupDirDate . "/.versions-index";
+ // Have a version index already? Update contents
+ if (file_exists($backupIndex)) {
+ $versionsInfo = "";
+ $versionsInfoOrig = getData($backupIndex);
+ $versionsInfoOrig = explode("\n", $versionsInfoOrig);
+ $replacedLine = false;
+ // For each line, either re-set number or simply include the line
+ for ($i = 0; $i < count($versionsInfoOrig); $i++) {
+ if (0 === strpos($versionsInfoOrig[$i], $fileLoc . "/" . $fileName . " = ")) {
+ $versionsInfo .= $fileLoc . "/" . $fileName . " = " . $backupFileNum . PHP_EOL;
+ $replacedLine = true;
+ } else {
+ $versionsInfo .= $versionsInfoOrig[$i] . PHP_EOL;
+ }
+ }
+ // Didn't find our line in the file? Add it to the end
+ if (!$replacedLine) {
+ $versionsInfo .= $fileLoc . "/" . $fileName . " = " . $backupFileNum . PHP_EOL;
+ }
+ // No version file yet, set the first line
+ } else {
+ $versionsInfo = $fileLoc . "/" . $fileName . " = " . $backupFileNum . PHP_EOL;
+ }
+ $versionsInfo = rtrim($versionsInfo, PHP_EOL);
+ $fh = fopen($backupIndex, 'w') or die($t['Sorry, cannot save...']);
+ fwrite($fh, $versionsInfo);
+ fclose($fh);
+ clearstatcache();
+
+ // Finally, clear any old backup dirs than user set X days (inclusive)
+ $backupDirsList = scandir($backupDirBase . $backupDirHost);
+ $backupDirsKeep = array();
+ for ($i = 0; $i <= $ICEcoder["backupsDays"]; $i++) {
+ $backupDirsKeep[] = date($backupDirFormat, strtotime('-' . $i . ' day', strtotime($backupDirDate)));
+ }
+ for ($i = 0; $i < count($backupDirsList); $i++) {
+ if ("." !== $backupDirsList[$i] && ".." !== $backupDirsList[$i] && !in_array($backupDirsList[$i], $backupDirsKeep)) {
+ $this->fileClass->rrmdir($backupDirBase . $backupDirHost . "/" . $backupDirsList[$i]);
+ }
+ }
+ }
+}
diff --git a/classes/FTP.php b/classes/FTP.php
new file mode 100644
index 0000000..a504711
--- /dev/null
+++ b/classes/FTP.php
@@ -0,0 +1,63 @@
+system = new System();
+ }
+
+ public function writeFile() {
+ global $fileLoc, $fileName, $ftpConn, $ftpRoot, $ftpHost, $ftpMode, $ICEcoder, $doNext, $filemtime;
+
+ $ftpFilepath = ltrim($fileLoc . "/" . $fileName, "/");
+ if (isset($_POST['changes'])) {
+ // Get existing file contents as lines
+ $loadedFile = toUTF8noBOM(ftpGetContents($ftpConn, $ftpRoot . $fileLoc . "/" . $fileName, $ftpMode), false);
+ $fileLines = explode("\n", str_replace("\r", "", $loadedFile));
+ // Need to add a new line at the end of each because explode will lose them,
+ // want want to end up with same array that 'file($file)' produces for a local file
+ // - it keeps the line endings at the end of each array item
+ for ($i = 0; $i < count($fileLines); $i++) {
+ if ($i < count($fileLines) - 1) {
+ $fileLines[$i] .= $ICEcoder["lineEnding"];
+ }
+ }
+ // Stitch changes onto it
+ $contents = $this->system->stitchChanges($fileLines, $_POST['changes']);
+
+ // get old file contents and count stats on usage \n and \r there
+ // in this case we can keep line endings, which file had before, without
+ // making code version control systems going crazy about line endings change in whole file.
+ $unixNewLines = preg_match_all('/[^\r][\n]/u', $loadedFile);
+ $windowsNewLines = preg_match_all('/[\r][\n]/u', $loadedFile);
+ } else {
+ $contents = $_POST['contents'];
+ }
+
+ // replace \r\n (Windows), \r (old Mac) and \n (Linux) line endings with whatever we chose to be lineEnding
+ $contents = str_replace("\r\n", $ICEcoder["lineEnding"], $contents);
+ $contents = str_replace("\r", $ICEcoder["lineEnding"], $contents);
+ $contents = str_replace("\n", $ICEcoder["lineEnding"], $contents);
+ if (isset($_POST['changes']) && ($unixNewLines > 0) || ($windowsNewLines > 0)) {
+ if ($unixNewLines > $windowsNewLines){
+ $contents = str_replace($ICEcoder["lineEnding"], "\n", $contents);
+ } elseif ($windowsNewLines > $unixNewLines){
+ $contents = str_replace($ICEcoder["lineEnding"], "\r\n", $contents);
+ }
+ }
+ // Write our file contents
+ if (!ftpWriteFile($ftpConn, $ftpFilepath, $contents, $ftpMode)) {
+ $doNext .= 'ICEcoder.message("Sorry, could not write ' . $ftpFilepath . ' at ' . $ftpHost . '");';
+ } else {
+ $doNext .= 'ICEcoder.openFileMDTs[ICEcoder.selectedTab - 1]="' . $filemtime . '";';
+ $doNext .= '(function() {var x = ICEcoder.openFileVersions; var y = ICEcoder.selectedTab-1; x[y] = "undefined" != typeof x[y] ? x[y] + 1 : 1})(); ICEcoder.updateVersionsDisplay();';
+ }
+ }
+}
diff --git a/classes/File.php b/classes/File.php
new file mode 100644
index 0000000..976e5e3
--- /dev/null
+++ b/classes/File.php
@@ -0,0 +1,687 @@
+system = new System();
+ }
+
+ public function check() {
+ global $file, $fileOrig, $docRoot, $iceRoot, $fileLoc, $fileName, $error, $errorStr, $errorMsg;
+ // Replace pipes with slashes, then establish the actual name as we may have HTML entities in filename
+ $file = html_entity_decode(str_replace("|", "/", $file));
+
+ // Put the original $file var aside for use
+ $fileOrig = $file;
+
+ // Trim any +'s or spaces from the end of file
+ $file = rtrim(rtrim($file, '+'), ' ');
+
+ // Also remove [NEW] from $file, we can consider $_GET['action'] or $fileOrig to pick that up
+ $file = preg_replace('/\[NEW\]$/', '', $file);
+
+ // Make each path in $file a full path (; separated list)
+ $allFiles = explode(";", $file);
+ for ($i = 0; $i < count($allFiles); $i++) {
+ if (false === strpos($allFiles[$i],$docRoot) && "getRemoteFile" !== $_GET['action']) {
+ $allFiles[$i] = str_replace("|", "/", $docRoot . $iceRoot . $allFiles[$i]);
+ }
+ };
+ $file = implode(";", $allFiles);
+
+ // Establish the $fileLoc and $fileName (used in single file cases, eg opening. Multiple file cases, eg deleting, is worked out in that loop)
+ $fileLoc = substr(str_replace($docRoot, "", $file), 0, strrpos(str_replace($docRoot, "", $file), "/"));
+ $fileName = basename($file);
+
+ // Check through all files to make sure they're valid/safe
+ $allFiles = explode(";", $file);
+ for ($i = 0; $i < count($allFiles); $i++) {
+
+ // Uncomment to alert and console.log the action and file, useful for debugging
+ // echo ";alert('" . xssClean($_GET['action'], "html") . " : " . $allFiles[$i] . "');console.log('" . xssClean($_GET['action'], "html") . " : " . $allFiles[$i] . "');";
+
+ $bannedFileFound = false;
+ for ($j = 0; $j < count($_SESSION['bannedFiles']); $j++) {
+ $thisFile = str_replace("*", "", $_SESSION['bannedFiles'][$j]);
+ if ("" != $thisFile && false !== strpos($allFiles[$i], $thisFile)) {
+ $bannedFileFound = true;
+ }
+ }
+
+ // Die if the file requested isn't something we expect
+ if (
+ // On the banned file/dir list
+ ($bannedFileFound) ||
+ // A local folder that isn't the doc root or starts with the doc root
+ ("getRemoteFile" !== $_GET['action'] && !isset($ftpSite) &&
+ rtrim($allFiles[$i], "/") !== rtrim($docRoot, "/") &&
+ 0 !== strpos(realpath(rtrim(dirname($allFiles[$i]), "/")), realpath(rtrim($docRoot, "/")))
+ ) ||
+ // Or a remote URL that doesn't start http
+ ("getRemoteFile" === $_GET['action'] && 0 !== strpos($allFiles[$i], "http"))
+ ) {
+ $error = true;
+ $errorStr = "true";
+ $errorMsg = "Sorry! - problem with file requested";
+ };
+ }
+ }
+
+ public function updateUI($doNext) {
+ global $fileLoc, $fileName;
+
+ // Reload file manager, rename tab & remove old file highlighting if it was a new file
+ if (isset($_POST['newFileName']) && "" != $_POST['newFileName']) {
+ $doNext .= 'ICEcoder.selectedFiles=[]; ICEcoder.updateFileManagerList(\'add\', \'' . $fileLoc . '\', \'' . $fileName . '\', false, false, false, \'file\');';
+ $doNext .= 'ICEcoder.renameTab(ICEcoder.selectedTab, \'' . $fileLoc . "/" . $fileName . '\');';
+ if (!strpos($_REQUEST['file'], "[NEW]")) {
+ // We're saving as a new file, so unhighlight the old name in the file manager if visible
+ $doNext .= "fileLink = ICEcoder.filesFrame.contentWindow.document.getElementById('" . str_replace("/", "|", $fileLoc) . "|". basename($_REQUEST['file']). "');";
+ $doNext .= "if (fileLink) {fileLink.style.backgroundColor = ICEcoder.tabBGnormal; fileLink.style.color = ICEcoder.tabFGnormalFile};";
+ }
+ }
+
+ return $doNext;
+ }
+
+ public function updateFileManager($action, $fileLoc, $fileName, $perms, $oldFile, $uploaded, $fileOrFolder) {
+ global $doNext;
+ $doNext .= "ICEcoder.selectedFiles=[]; ICEcoder.updateFileManagerList('" .
+ $action . "', '" .
+ $fileLoc . "', '" .
+ $fileName . "', '" .
+ $perms . "', '" .
+ $oldFile . "', '" .
+ $uploaded . "', '" .
+ $fileOrFolder . "');";
+
+ return $doNext;
+ }
+
+ public function load() {
+ global $file, $fileLoc, $fileName, $t, $ftpConn, $ftpHost, $ftpLogin, $ftpRoot, $ftpUser, $ftpMode;
+ echo 'action="load";';
+ $lineNumber = max(isset($_REQUEST['lineNumber']) ? intval($_REQUEST['lineNumber']) : 1, 1);
+ // Check this file isn't on the banned list at all
+ $canOpen = true;
+ for ($i = 0; $i < count($_SESSION['bannedFiles']); $i++) {
+ if ("" !== str_replace("*", "", $_SESSION['bannedFiles'][$i]) && false !== strpos($file, str_replace("*", "", $_SESSION['bannedFiles'][$i]))) {
+ $canOpen = false;
+ }
+ }
+
+ if (false === $canOpen) {
+ echo 'fileType="nothing"; parent.parent.ICEcoder.message(\'' . $t['Sorry, could not...'] . ' ' . $fileLoc . "/" . $fileName . '\');';
+ } elseif (isset($ftpSite) || file_exists($file)) {
+ $finfo = "text";
+ // Determine what to do based on mime type
+ if (!isset($ftpSite) && function_exists('finfo_open')) {
+ $finfoMIME = finfo_open(FILEINFO_MIME);
+ $finfo = finfo_file($finfoMIME, $file);
+ finfo_close($finfoMIME);
+ } else {
+ $fileExt = explode(" ", pathinfo($file, PATHINFO_EXTENSION));
+ $fileExt = $fileExt[0];
+ if (false !== array_search($fileExt, ["gif", "jpg", "jpeg", "png"])) {
+ $finfo = "image";
+ };
+ if (false !== array_search($fileExt, ["doc", "docx", "ppt", "rtf", "pdf", "zip", "tar", "gz", "swf", "asx", "asf", "midi", "mp3", "wav", "aiff", "mov", "qt", "wmv", "mp4", "odt", "odg", "odp"])) {
+ $finfo = "other";
+ };
+ }
+ if (0 === strpos($finfo, "text") || 0 === strpos($finfo, "application/xml") || false !== strpos($finfo, "empty")) {
+ echo 'fileType="text";';
+ echo 'parent.parent.ICEcoder.shortURL = parent.parent.ICEcoder.thisFileFolderLink = "' . $fileLoc . "/" . $fileName . '";';
+
+ // Get file over FTP?
+ if (isset($ftpSite)) {
+ ftpStart();
+ // Show user warning if no good connection
+ if (!$ftpConn || !$ftpLogin) {
+ die('parent.parent.ICEcoder.message("Sorry, no FTP connection to ' . $ftpHost . ' for user ' . $ftpUser . '");parent.parent.ICEcoder.serverMessage();parent.parent.ICEcoder.serverQueue("del",0);');
+ }
+ // Get our file contents and close the FTP connection
+ $loadedFile = toUTF8noBOM(ftpGetContents($ftpConn, $ftpRoot . $fileLoc . "/" . $fileName, $ftpMode), false);
+ ftpEnd();
+ // Get local file
+ } else {
+ $loadedFile = toUTF8noBOM(getData($file), true);
+ }
+ $encoding = ini_get("default_charset");
+ if ("" == $encoding) {
+ $encoding = "UTF-8";
+ }
+ // Get content and set HTML entities on it according to encoding
+ $loadedFile = htmlentities($loadedFile, ENT_COMPAT, $encoding);
+ // Remove \r chars and replace \n with carriage return HTML entity char
+ $loadedFile = preg_replace('/\\r/', '', $loadedFile);
+ $loadedFile = preg_replace('/\\n/', '
', $loadedFile);
+ echo '