mirror of https://github.com/itflow-org/itflow
1721 lines
85 KiB
PHP
1721 lines
85 KiB
PHP
<?php
|
||
|
||
if (file_exists("../config.php")) {
|
||
include "../config.php";
|
||
|
||
}
|
||
|
||
include "../functions.php"; // Global Functions
|
||
include "setup_functions.php"; // Setup Only Functions
|
||
include "../includes/database_version.php";
|
||
|
||
if (!isset($config_enable_setup)) {
|
||
$config_enable_setup = 1;
|
||
}
|
||
|
||
if ($config_enable_setup == 0) {
|
||
header("Location: /login.php");
|
||
exit;
|
||
}
|
||
|
||
$mysqli_available = isset($mysqli) && $mysqli instanceof mysqli;
|
||
$can_show_restore = false;
|
||
$should_skip_to_user = false;
|
||
|
||
if (file_exists("../config.php") && $mysqli_available) {
|
||
$table_result = mysqli_query($mysqli, "SHOW TABLES LIKE 'users'");
|
||
if ($table_result && mysqli_num_rows($table_result) > 0) {
|
||
$can_show_restore = true;
|
||
$should_skip_to_user = true;
|
||
} else {
|
||
// If DB exists but doesn't have user table yet, maybe still allow restore
|
||
$all_tables = mysqli_query($mysqli, "SHOW TABLES");
|
||
if ($all_tables && mysqli_num_rows($all_tables) > 0) {
|
||
$can_show_restore = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
include_once "../includes/settings_localization_array.php";
|
||
$errorLog = ini_get('error_log') ?: "Debian/Ubuntu default is usually /var/log/apache2/error.log";
|
||
|
||
// Get a list of all available timezones
|
||
$timezones = DateTimeZone::listIdentifiers();
|
||
|
||
if (isset($_POST['add_database'])) {
|
||
|
||
// Check if database has been set up already. If it has, direct user to edit directly instead.
|
||
if (file_exists('../config.php')) {
|
||
$_SESSION['alert_message'] = "Database already configured. Any further changes should be made by editing the config.php file.";
|
||
header("Location: ?user");
|
||
exit;
|
||
}
|
||
|
||
$host = filter_var(trim($_POST['host']), FILTER_SANITIZE_STRING);
|
||
$database = filter_var(trim($_POST['database']), FILTER_SANITIZE_STRING);
|
||
$username = filter_var(trim($_POST['username']), FILTER_SANITIZE_STRING);
|
||
$password = filter_var(trim($_POST['password']), FILTER_SANITIZE_STRING);
|
||
$config_base_url = $_SERVER['HTTP_HOST'] . dirname($_SERVER['REQUEST_URI']);
|
||
$config_base_url = rtrim($config_base_url, '/');
|
||
|
||
$installation_id = randomString(32);
|
||
|
||
// Ensure variables meet specific criteria (very basic examples)
|
||
if (!preg_match('/^[a-zA-Z0-9.-]+$/', $host)) {
|
||
die('Invalid host format.');
|
||
}
|
||
|
||
// Test database connection before writing it to config.php
|
||
|
||
$conn = mysqli_connect($host, $username, $password, $database);
|
||
if (!$conn) {
|
||
exit("<b>Database connection failed - please check and try again</b> <br> <br>" . mysqli_connect_error());
|
||
}
|
||
|
||
$new_config = "<?php\n\n";
|
||
$new_config .= "\$dbhost = " . var_export($host, true) . ";\n";
|
||
$new_config .= "\$dbusername = " . var_export($username, true) . ";\n";
|
||
$new_config .= "\$dbpassword = " . var_export($password, true) . ";\n";
|
||
$new_config .= "\$database = " . var_export($database, true) . ";\n";
|
||
$new_config .= "\$mysqli = mysqli_connect(\$dbhost, \$dbusername, \$dbpassword, \$database) or die('Database Connection Failed');\n";
|
||
$new_config .= "\$config_app_name = 'ITFlow';\n";
|
||
$new_config .= sprintf("\$config_base_url = '%s';\n", addslashes($config_base_url));
|
||
$new_config .= "\$config_https_only = TRUE;\n";
|
||
$new_config .= "\$repo_branch = 'master';\n";
|
||
$new_config .= "\$installation_id = '$installation_id';\n";
|
||
|
||
if (file_put_contents("../config.php", $new_config) !== false && file_exists('../config.php')) {
|
||
|
||
include "../config.php";
|
||
|
||
|
||
// Name of the file
|
||
$filename = '../db.sql';
|
||
// Temporary variable, used to store current query
|
||
$templine = '';
|
||
// Read in entire file
|
||
$lines = file($filename);
|
||
// Loop through each line
|
||
foreach ($lines as $line) {
|
||
// Skip it if it's a comment
|
||
if (substr($line, 0, 2) == '--' || $line == '')
|
||
continue;
|
||
|
||
// Add this line to the current segment
|
||
$templine .= $line;
|
||
// If it has a semicolon at the end, it's the end of the query
|
||
if (substr(trim($line), -1, 1) == ';') {
|
||
// Perform the query
|
||
mysqli_query($mysqli, $templine);
|
||
// Reset temp variable to empty
|
||
$templine = '';
|
||
}
|
||
}
|
||
|
||
$_SESSION['alert_message'] = "Database successfully added, now lets add a user.";
|
||
header("Location: ?user");
|
||
exit;
|
||
|
||
} else {
|
||
// There was an error writing the file
|
||
// Display an error message and redirect to the setup page
|
||
$_SESSION['alert_message'] = "Did not successfully write the config.php file to the filesystem, Please Input the database information again.";
|
||
header("Location: ?database");
|
||
exit;
|
||
}
|
||
|
||
}
|
||
|
||
if (isset($_POST['restore'])) {
|
||
|
||
// ---------- Inline helpers (guarded) ----------
|
||
if (!function_exists('recursiveCopy')) {
|
||
function recursiveCopy(string $src, string $dst): void {
|
||
if (!is_dir($src)) throw new RuntimeException("Source directory missing: $src");
|
||
if (!is_dir($dst) && !mkdir($dst, 0750, true)) {
|
||
throw new RuntimeException("Failed to create destination: $dst");
|
||
}
|
||
$dir = opendir($src);
|
||
if (!$dir) throw new RuntimeException("Failed to open source: $src");
|
||
while (($file = readdir($dir)) !== false) {
|
||
if ($file === '.' || $file === '..') continue;
|
||
$from = $src . DIRECTORY_SEPARATOR . $file;
|
||
$to = $dst . DIRECTORY_SEPARATOR . $file;
|
||
if (is_dir($from)) {
|
||
recursiveCopy($from, $to);
|
||
} else {
|
||
if (!copy($from, $to)) {
|
||
closedir($dir);
|
||
throw new RuntimeException("Copy failed: $from → $to");
|
||
}
|
||
@chmod($to, 0640);
|
||
}
|
||
}
|
||
closedir($dir);
|
||
}
|
||
}
|
||
|
||
if (!function_exists('robustDirMove')) {
|
||
function robustDirMove(string $src, string $dst): void {
|
||
if (@rename($src, $dst)) return; // fast path (same filesystem)
|
||
recursiveCopy($src, $dst); // cross-FS fallback
|
||
deleteDir($src);
|
||
}
|
||
}
|
||
|
||
if (!function_exists('listTopLevel')) {
|
||
function listTopLevel(string $dir): array {
|
||
if (!is_dir($dir)) return [];
|
||
$items = [];
|
||
$dh = opendir($dir);
|
||
if (!$dh) return [];
|
||
while (($e = readdir($dh)) !== false) {
|
||
if ($e === '.' || $e === '..') continue;
|
||
$items[] = $e;
|
||
}
|
||
closedir($dh);
|
||
sort($items);
|
||
return $items;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('countFilesRecursive')) {
|
||
function countFilesRecursive(string $dir): int {
|
||
if (!is_dir($dir)) return 0;
|
||
$it = new RecursiveIteratorIterator(
|
||
new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS)
|
||
);
|
||
$count = 0;
|
||
foreach ($it as $f) {
|
||
if ($f->isFile()) $count++;
|
||
}
|
||
return $count;
|
||
}
|
||
}
|
||
|
||
if (!function_exists('setConfigFlagAtomic')) {
|
||
function setConfigFlagAtomic(string $file, string $key, $value): void {
|
||
clearstatcache(true, $file);
|
||
if (!file_exists($file)) throw new RuntimeException("config.php not found: $file");
|
||
if (!is_readable($file)) throw new RuntimeException("config.php not readable: $file");
|
||
if (!is_writable($file)) throw new RuntimeException("config.php not writable: $file");
|
||
|
||
$cfg = file_get_contents($file);
|
||
if ($cfg === false) throw new RuntimeException("Failed to read config.php");
|
||
$cfg = str_replace("\r\n", "\n", $cfg);
|
||
|
||
$scalar = is_bool($value) ? ($value ? 'true' : 'false') : var_export($value, true);
|
||
$line = '$' . $key . ' = ' . $scalar . ';';
|
||
|
||
$pattern = '/^\s*\$' . preg_quote($key, '/') . '\s*=\s*.*?;\s*$/m';
|
||
if (preg_match($pattern, $cfg)) {
|
||
$cfg = preg_replace($pattern, $line, $cfg, 1);
|
||
} else {
|
||
if (preg_match('/\?>\s*$/', $cfg)) {
|
||
$cfg = preg_replace('/\?>\s*$/', "\n$line\n?>\n", $cfg, 1);
|
||
} else {
|
||
if ($cfg !== '' && substr($cfg, -1) !== "\n") $cfg .= "\n";
|
||
$cfg .= $line . "\n";
|
||
}
|
||
}
|
||
|
||
$dir = dirname($file);
|
||
$temp = tempnam($dir, 'cfg_');
|
||
if ($temp === false) throw new RuntimeException("Failed to create temp file in $dir");
|
||
if (file_put_contents($temp, $cfg, LOCK_EX) === false) {
|
||
@unlink($temp);
|
||
throw new RuntimeException("Failed to write temp config");
|
||
}
|
||
|
||
$perms = @fileperms($file);
|
||
if ($perms !== false) { @chmod($temp, $perms & 0777); }
|
||
if (!@rename($temp, $file)) {
|
||
@unlink($temp);
|
||
throw new RuntimeException("Failed to atomically replace config.php");
|
||
}
|
||
if (function_exists('opcache_invalidate')) {
|
||
@opcache_invalidate($file, true);
|
||
}
|
||
}
|
||
}
|
||
// ---------- /inline helpers ----------
|
||
|
||
// --- Basic env guards for long operations ---
|
||
@set_time_limit(0);
|
||
if (function_exists('ini_set')) { @ini_set('memory_limit', '1024M'); }
|
||
|
||
// --- 1) Validate uploaded file ---
|
||
if (!isset($_FILES['backup_zip']) || $_FILES['backup_zip']['error'] !== UPLOAD_ERR_OK) {
|
||
die("No backup file uploaded or upload failed.");
|
||
}
|
||
$file = $_FILES['backup_zip'];
|
||
|
||
if ($file['size'] > 4 * 1024 * 1024 * 1024) {
|
||
die("Backup archive is too large.");
|
||
}
|
||
|
||
$fi = new finfo(FILEINFO_MIME_TYPE);
|
||
$mime = $fi->file($file['tmp_name']);
|
||
if ($mime !== 'application/zip' && $mime !== 'application/x-zip-compressed') {
|
||
die("Invalid archive type; only .zip is supported.");
|
||
}
|
||
|
||
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||
if ($ext !== 'zip') {
|
||
die("Only .zip files are allowed.");
|
||
}
|
||
|
||
// --- 2) Move to secure temp location ---
|
||
$timestamp = date('YmdHis');
|
||
$tempZip = tempnam(sys_get_temp_dir(), "restore_{$timestamp}_");
|
||
if (!move_uploaded_file($file["tmp_name"], $tempZip)) {
|
||
die("Failed to save uploaded backup file.");
|
||
}
|
||
@chmod($tempZip, 0600);
|
||
|
||
// --- 3) Extract the OUTER backup zip to a unique temp dir ---
|
||
$tempDir = sys_get_temp_dir() . "/restore_temp_" . bin2hex(random_bytes(6));
|
||
if (!mkdir($tempDir, 0700, true)) {
|
||
@unlink($tempZip);
|
||
die("Failed to create temp directory.");
|
||
}
|
||
|
||
$zip = new ZipArchive;
|
||
if ($zip->open($tempZip) !== TRUE) {
|
||
@unlink($tempZip);
|
||
deleteDir($tempDir);
|
||
die("Failed to open backup zip file.");
|
||
}
|
||
|
||
try {
|
||
safeExtractZip($zip, $tempDir);
|
||
} catch (Throwable $e) {
|
||
$zip->close();
|
||
@unlink($tempZip);
|
||
deleteDir($tempDir);
|
||
die("Invalid backup archive: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'));
|
||
}
|
||
$zip->close();
|
||
@unlink($tempZip);
|
||
|
||
// --- Expected inner files ---
|
||
$sqlPath = $tempDir . "/db.sql";
|
||
$uploadsZip = $tempDir . "/uploads.zip"; // <- inner uploads zip
|
||
$versionTxt = $tempDir . "/version.txt";
|
||
|
||
if (!is_file($sqlPath) || !is_readable($sqlPath)) {
|
||
deleteDir($tempDir);
|
||
die("Missing db.sql in the backup archive.");
|
||
}
|
||
if (!is_file($uploadsZip) || !is_readable($uploadsZip)) {
|
||
deleteDir($tempDir);
|
||
die("Missing uploads.zip in the backup archive.");
|
||
}
|
||
|
||
// --- 4) Optional: check DB version compatibility ---
|
||
if (defined('LATEST_DATABASE_VERSION') && is_file($versionTxt)) {
|
||
$txt = @file_get_contents($versionTxt) ?: '';
|
||
if (preg_match('/^Database Version:\s*(.+)$/mi', $txt, $m)) {
|
||
$backupVersion = trim($m[1]);
|
||
$running = LATEST_DATABASE_VERSION;
|
||
if (version_compare($backupVersion, $running, '>')) {
|
||
deleteDir($tempDir);
|
||
die("Backup schema ($backupVersion) is newer than this app ($running). Please upgrade ITFlow first, then retry restore.");
|
||
}
|
||
}
|
||
}
|
||
|
||
// --- 5) Restore SQL (drop + import) ---
|
||
mysqli_query($mysqli, "SET FOREIGN_KEY_CHECKS = 0");
|
||
$tables = mysqli_query($mysqli, "SHOW TABLES");
|
||
if ($tables) {
|
||
while ($row = mysqli_fetch_array($tables)) {
|
||
$tbl = $row[0];
|
||
mysqli_query($mysqli, "DROP TABLE IF EXISTS `".$mysqli->real_escape_string($tbl)."`");
|
||
}
|
||
}
|
||
mysqli_query($mysqli, "SET FOREIGN_KEY_CHECKS = 1");
|
||
|
||
try {
|
||
importSqlFile($mysqli, $sqlPath);
|
||
} catch (Throwable $e) {
|
||
deleteDir($tempDir);
|
||
die("SQL import failed: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'));
|
||
}
|
||
|
||
// --- 6) Restore UPLOADS (the inner uploads.zip) via staging + robust swap ---
|
||
$appRoot = realpath(__DIR__ . "/..");
|
||
$uploadDir = realpath($appRoot . "/uploads");
|
||
if ($uploadDir === false) {
|
||
$uploadDir = $appRoot . "/uploads";
|
||
if (!mkdir($uploadDir, 0750, true)) {
|
||
deleteDir($tempDir);
|
||
die("Failed to create uploads directory.");
|
||
}
|
||
$uploadDir = realpath($uploadDir);
|
||
}
|
||
if ($uploadDir === false || strpos($uploadDir, $appRoot) !== 0) {
|
||
deleteDir($tempDir);
|
||
die("Uploads directory path invalid.");
|
||
}
|
||
if (!is_writable(dirname($uploadDir))) {
|
||
deleteDir($tempDir);
|
||
die("Uploads restore failed: target parent dir is not writable by web server.");
|
||
}
|
||
|
||
$staging = $appRoot . "/uploads_restoring_" . bin2hex(random_bytes(4));
|
||
if (!mkdir($staging, 0700, true)) {
|
||
deleteDir($tempDir);
|
||
die("Failed to create staging directory.");
|
||
}
|
||
|
||
$uz = new ZipArchive;
|
||
if ($uz->open($uploadsZip) !== TRUE) {
|
||
deleteDir($staging);
|
||
deleteDir($tempDir);
|
||
die("Failed to open uploads.zip in backup.");
|
||
}
|
||
|
||
// Validate + buffer all entries; no writes if any issue (scan-report mode)
|
||
$result = extractUploadsZipWithValidationReport($uz, $staging, [
|
||
'max_file_bytes' => 200 * 1024 * 1024,
|
||
'blocked_exts' => [
|
||
'php','php3','php4','php5','php7','php8','phtml','phar',
|
||
'cgi','pl','sh','bash','zsh','exe','dll','bat','cmd','com',
|
||
'ps1','vbs','vb','jar','jsp','asp','aspx','so','dylib','bin'
|
||
],
|
||
]);
|
||
$uz->close();
|
||
|
||
if (!$result['ok']) {
|
||
$lines = ["Unsafe file(s) detected in uploads.zip:"];
|
||
foreach ($result['issues'] as $issue) {
|
||
$p = htmlspecialchars($issue['path'], ENT_QUOTES, 'UTF-8');
|
||
$r = htmlspecialchars($issue['reason'], ENT_QUOTES, 'UTF-8');
|
||
$lines[] = "• {$p} — {$r}";
|
||
}
|
||
deleteDir($staging);
|
||
deleteDir($tempDir);
|
||
$_SESSION['alert_message'] = nl2br(implode("\n", $lines));
|
||
header("Location: ?restore");
|
||
exit;
|
||
}
|
||
|
||
// If the inner zip has a single top-level folder (e.g., "uploads/"), promote it
|
||
$roots = listTopLevel($staging);
|
||
if (count($roots) === 1) {
|
||
$candidate = $staging . DIRECTORY_SEPARATOR . $roots[0];
|
||
if (is_dir($candidate)) {
|
||
$stagingPromoted = $staging . "_promoted";
|
||
if (!@rename($candidate, $stagingPromoted)) {
|
||
recursiveCopy($candidate, $stagingPromoted); // cross-FS fallback
|
||
deleteDir($candidate);
|
||
}
|
||
$old = $staging;
|
||
$staging = $stagingPromoted;
|
||
deleteDir($old);
|
||
}
|
||
}
|
||
|
||
// Ensure staging has content
|
||
if (countFilesRecursive($staging) === 0) {
|
||
deleteDir($staging);
|
||
deleteDir($tempDir);
|
||
die("Uploads restore failed: extracted staging is empty. The inner uploads.zip may be malformed or all files were blocked.");
|
||
}
|
||
|
||
// Rotate current uploads out; robust moves on both steps
|
||
$backupOld = $appRoot . "/uploads_old_" . time();
|
||
try {
|
||
if (is_dir($uploadDir)) {
|
||
if (!@rename($uploadDir, $backupOld)) {
|
||
recursiveCopy($uploadDir, $backupOld); // cross-FS fallback
|
||
deleteDir($uploadDir);
|
||
}
|
||
}
|
||
robustDirMove($staging, $uploadDir);
|
||
} catch (Throwable $e) {
|
||
// rollback if possible
|
||
if (is_dir($backupOld) && !is_dir($uploadDir)) {
|
||
@rename($backupOld, $uploadDir);
|
||
}
|
||
deleteDir($staging);
|
||
deleteDir($tempDir);
|
||
die("Uploads restore failed during swap: " . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8'));
|
||
}
|
||
|
||
// Verify restored uploads; rollback if empty
|
||
$restoredCount = countFilesRecursive($uploadDir);
|
||
if ($restoredCount === 0) {
|
||
if (is_dir($backupOld)) {
|
||
@rename($uploadDir, $uploadDir . "_bad_" . time());
|
||
@rename($backupOld, $uploadDir);
|
||
}
|
||
deleteDir($tempDir);
|
||
die("Uploads restore appears empty after swap. Rolled back to old uploads.");
|
||
}
|
||
// Optionally delete the old uploads after a grace period:
|
||
// deleteDir($backupOld);
|
||
|
||
// --- 7) Log version info (optional) ---
|
||
if (is_file($versionTxt)) {
|
||
$versionInfo = @file_get_contents($versionTxt);
|
||
if ($versionInfo !== false) {
|
||
logAction("Backup Restore", "Version Info", $versionInfo);
|
||
}
|
||
}
|
||
|
||
// --- 8) Cleanup temp dir ---
|
||
deleteDir($tempDir);
|
||
|
||
// --- 9) Finalize setup flag atomically (and clear OPcache) ---
|
||
try {
|
||
setConfigFlagAtomic(__DIR__ . "/../config.php", "config_enable_setup", 0);
|
||
} catch (Throwable $e) {
|
||
// Fallback append (best-effort) and allow login
|
||
@file_put_contents(__DIR__ . "/../config.php", "\n\$config_enable_setup = 0;\n", FILE_APPEND);
|
||
$_SESSION['alert_message'] =
|
||
"Backup restored, but couldn’t finalize setup flag automatically: " .
|
||
htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
|
||
header("Location: ../login.php");
|
||
exit;
|
||
}
|
||
|
||
// --- 10) Done ---
|
||
$_SESSION['alert_message'] = "Full backup restored successfully. Restored {$restoredCount} upload file(s).";
|
||
header("Location: ../login.php");
|
||
exit;
|
||
}
|
||
|
||
|
||
if (isset($_POST['add_user'])) {
|
||
$user_count = mysqli_num_rows(mysqli_query($mysqli,"SELECT COUNT(*) FROM users"));
|
||
if ($user_count < 0) {
|
||
$_SESSION['alert_message'] = "Users already exist in the database. Clear them to reconfigure here.";
|
||
header("Location: ?company");
|
||
exit;
|
||
}
|
||
|
||
$name = sanitizeInput($_POST['name']);
|
||
$email = sanitizeInput($_POST['email']);
|
||
$password = password_hash(trim($_POST['password']), PASSWORD_DEFAULT);
|
||
|
||
//Generate master encryption key
|
||
$site_encryption_master_key = randomString();
|
||
|
||
//Generate user specific key
|
||
$user_specific_encryption_ciphertext = setupFirstUserSpecificKey(trim($_POST['password']), $site_encryption_master_key);
|
||
|
||
mysqli_query($mysqli,"INSERT INTO users SET user_name = '$name', user_email = '$email', user_password = '$password', user_specific_encryption_ciphertext = '$user_specific_encryption_ciphertext', user_role_id = 3");
|
||
|
||
mkdirMissing("../uploads/users/1");
|
||
|
||
//Check to see if a file is attached
|
||
if ($_FILES['file']['tmp_name'] != '') {
|
||
|
||
// get details of the uploaded file
|
||
$file_error = 0;
|
||
$file_tmp_path = $_FILES['file']['tmp_name'];
|
||
$file_name = $_FILES['file']['name'];
|
||
$file_size = $_FILES['file']['size'];
|
||
$file_type = $_FILES['file']['type'];
|
||
$file_extension = strtolower(end(explode('.',$_FILES['file']['name'])));
|
||
|
||
// sanitize file-name
|
||
$new_file_name = md5(time() . $file_name) . '.' . $file_extension;
|
||
|
||
// check if file has one of the following extensions
|
||
$allowed_file_extensions = array('jpg', 'jpeg', 'gif', 'png', 'webp');
|
||
|
||
if (in_array($file_extension,$allowed_file_extensions) === false) {
|
||
$file_error = 1;
|
||
}
|
||
|
||
//Check File Size
|
||
if ($file_size > 2097152) {
|
||
$file_error = 1;
|
||
}
|
||
|
||
if ($file_error == 0) {
|
||
// directory in which the uploaded file will be moved
|
||
$upload_file_dir = "../uploads/users/1/";
|
||
$dest_path = $upload_file_dir . $new_file_name;
|
||
|
||
move_uploaded_file($file_tmp_path, $dest_path);
|
||
|
||
//Set Avatar
|
||
mysqli_query($mysqli,"UPDATE users SET user_avatar = '$new_file_name' WHERE user_id = 1");
|
||
|
||
$_SESSION['alert_message'] = 'File successfully uploaded.';
|
||
} else {
|
||
|
||
$_SESSION['alert_message'] = 'There was an error moving the file to upload directory. Please make sure the upload directory is writable by web server.';
|
||
}
|
||
}
|
||
|
||
//Create Settings
|
||
mysqli_query($mysqli,"INSERT INTO user_settings SET user_id = 1");
|
||
|
||
$_SESSION['alert_message'] = "User <strong>$name</strong> created";
|
||
|
||
header("Location: ?company");
|
||
exit;
|
||
|
||
}
|
||
|
||
if (isset($_POST['add_company_settings'])) {
|
||
|
||
$name = sanitizeInput($_POST['name']);
|
||
$country = sanitizeInput($_POST['country']);
|
||
$address = sanitizeInput($_POST['address']);
|
||
$city = sanitizeInput($_POST['city']);
|
||
$state = sanitizeInput($_POST['state']);
|
||
$zip = sanitizeInput($_POST['zip']);
|
||
$phone = preg_replace("/[^0-9]/", '',$_POST['phone']);
|
||
$email = sanitizeInput($_POST['email']);
|
||
$website = sanitizeInput($_POST['website']);
|
||
$tax_id = sanitizeInput($_POST['tax_id']);
|
||
|
||
mysqli_query($mysqli,"INSERT INTO companies SET company_name = '$name', company_address = '$address', company_city = '$city', company_state = '$state', company_zip = '$zip', company_country = '$country', company_phone = '$phone', company_email = '$email', company_website = '$website', company_tax_id = '$tax_id'");
|
||
|
||
//Check to see if a file is attached
|
||
if ($_FILES['file']['tmp_name'] != '') {
|
||
|
||
// get details of the uploaded file
|
||
$file_error = 0;
|
||
$file_tmp_path = $_FILES['file']['tmp_name'];
|
||
$file_name = $_FILES['file']['name'];
|
||
$file_size = $_FILES['file']['size'];
|
||
$file_type = $_FILES['file']['type'];
|
||
$file_extension = strtolower(end(explode('.',$_FILES['file']['name'])));
|
||
|
||
// sanitize file-name
|
||
$new_file_name = md5(time() . $file_name) . '.' . $file_extension;
|
||
|
||
// check if file has one of the following extensions
|
||
$allowed_file_extensions = array('jpg', 'jpeg', 'png');
|
||
|
||
if (in_array($file_extension,$allowed_file_extensions) === false) {
|
||
$file_error = 1;
|
||
}
|
||
|
||
//Check File Size
|
||
if ($file_size > 2097152) {
|
||
$file_error = 1;
|
||
}
|
||
|
||
if ($file_error == 0) {
|
||
// directory in which the uploaded file will be moved
|
||
$upload_file_dir = "../uploads/settings/";
|
||
$dest_path = $upload_file_dir . $new_file_name;
|
||
|
||
move_uploaded_file($file_tmp_path, $dest_path);
|
||
|
||
mysqli_query($mysqli,"UPDATE companies SET company_logo = '$new_file_name' WHERE company_id = 1");
|
||
|
||
$_SESSION['alert_message'] = 'File successfully uploaded.';
|
||
} else {
|
||
|
||
$_SESSION['alert_message'] = 'There was an error moving the file to upload directory. Please make sure the upload directory is writable by web server.';
|
||
}
|
||
}
|
||
|
||
$latest_database_version = LATEST_DATABASE_VERSION;
|
||
mysqli_query($mysqli,"INSERT INTO settings SET company_id = 1, config_current_database_version = '$latest_database_version', config_invoice_prefix = 'INV-', config_invoice_next_number = 1, config_recurring_invoice_prefix = 'REC-', config_invoice_overdue_reminders = '1,3,7', config_quote_prefix = 'QUO-', config_quote_next_number = 1, config_default_net_terms = 30, config_ticket_next_number = 1, config_ticket_prefix = 'TCK-'");
|
||
|
||
// Create Categories
|
||
// Expense Categories Examples
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Office Supplies', category_type = 'Expense', category_color = 'blue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Travel', category_type = 'Expense', category_color = 'purple'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Advertising', category_type = 'Expense', category_color = 'orange'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Processing Fee', category_type = 'Expense', category_color = 'gray'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Shipping and Postage', category_type = 'Expense', category_color = 'teal'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Software', category_type = 'Expense', category_color = 'lightblue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Bank Fees', category_type = 'Expense', category_color = 'yellow'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Payroll', category_type = 'Expense', category_color = 'green'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Professional Services', category_type = 'Expense', category_color = 'darkblue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Contractor', category_type = 'Expense', category_color = 'brown'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Insurance', category_type = 'Expense', category_color = 'red'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Infrastructure', category_type = 'Expense', category_color = 'darkgreen'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Equipment', category_type = 'Expense', category_color = 'gray'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Education', category_type = 'Expense', category_color = 'lightyellow'");
|
||
|
||
// Income Categories Examples
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Managed Services', category_type = 'Income', category_color = 'green'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Consulting', category_type = 'Income', category_color = 'blue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Projects', category_type = 'Income', category_color = 'purple'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Hardware Sales', category_type = 'Income', category_color = 'silver'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Software Sales', category_type = 'Income', category_color = 'lightblue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Cloud Services', category_type = 'Income', category_color = 'skyblue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Support', category_type = 'Income', category_color = 'yellow'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Training', category_type = 'Income', category_color = 'lightyellow'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Telecom Services', category_type = 'Income', category_color = 'orange'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Backup', category_type = 'Income', category_color = 'darkblue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Security', category_type = 'Income', category_color = 'red'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Licensing', category_type = 'Income', category_color = 'green'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Monitoring', category_type = 'Income', category_color = 'teal'");
|
||
|
||
// Referral Examples
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Friend', category_type = 'Referral', category_color = 'blue'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Search', category_type = 'Referral', category_color = 'orange'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Social Media', category_type = 'Referral', category_color = 'green'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Email', category_type = 'Referral', category_color = 'yellow'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Partner', category_type = 'Referral', category_color = 'purple'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Event', category_type = 'Referral', category_color = 'red'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Affiliate', category_type = 'Referral', category_color = 'pink'");
|
||
mysqli_query($mysqli,"INSERT INTO categories SET category_name = 'Client', category_type = 'Referral', category_color = 'lightblue'");
|
||
|
||
// Payment Methods
|
||
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = 'Cash'");
|
||
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = 'Check'");
|
||
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = 'Bank Transfer'");
|
||
mysqli_query($mysqli,"INSERT INTO payment_methods SET payment_method_name = 'Credit Card'");
|
||
|
||
// Default Calendar
|
||
mysqli_query($mysqli,"INSERT INTO calendars SET calendar_name = 'Default', calendar_color = 'blue'");
|
||
|
||
// Add default ticket statuses
|
||
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'New', ticket_status_color = '#dc3545'"); // Default ID for new tickets is 1
|
||
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Open', ticket_status_color = '#007bff'"); // 2
|
||
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'On Hold', ticket_status_color = '#28a745'"); // 3
|
||
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Resolved', ticket_status_color = '#343a40'"); // 4 (was auto-close)
|
||
mysqli_query($mysqli, "INSERT INTO ticket_statuses SET ticket_status_name = 'Closed', ticket_status_color = '#343a40'"); // 5
|
||
|
||
// Add default modules
|
||
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_client', module_description = 'General client & contact management'");
|
||
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_support', module_description = 'Access to ticketing, assets and documentation'");
|
||
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_credential', module_description = 'Access to client credentials - usernames, passwords and 2FA codes'");
|
||
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_sales', module_description = 'Access to quotes, invoices and products'");
|
||
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_financial', module_description = 'Access to payments, accounts, expenses and budgets'");
|
||
mysqli_query($mysqli, "INSERT INTO modules SET module_name = 'module_reporting', module_description = 'Access to all reports'");
|
||
|
||
// Add default roles
|
||
mysqli_query($mysqli, "INSERT INTO user_roles SET role_id = 1, role_name = 'Accountant', role_description = 'Built-in - Limited access to financial-focused modules'");
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 1, user_role_permission_level = 1"); // Read clients
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 2, user_role_permission_level = 1"); // Read support
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 4, user_role_permission_level = 1"); // Read sales
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 5, user_role_permission_level = 2"); // Modify financial
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 1, module_id = 6, user_role_permission_level = 1"); // Read reports
|
||
|
||
mysqli_query($mysqli, "INSERT INTO user_roles SET role_id = 2, role_name = 'Technician', role_description = 'Built-in - Limited access to technical-focused modules'");
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 1, user_role_permission_level = 2"); // Modify clients
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 2, user_role_permission_level = 2"); // Modify support
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 3, user_role_permission_level = 2"); // Modify credentials
|
||
mysqli_query($mysqli, "INSERT INTO user_role_permissions SET user_role_id = 2, module_id = 4, user_role_permission_level = 2"); // Modify sales
|
||
|
||
mysqli_query($mysqli, "INSERT INTO user_roles SET role_id = 3, role_name = 'Administrator', role_description = 'Built-in - Full administrative access to all modules (including user management)', role_is_admin = 1");
|
||
|
||
// Custom Links
|
||
mysqli_query($mysqli,"INSERT INTO custom_links SET custom_link_name = 'Docs', custom_link_uri = 'https://docs.itflow.org', custom_link_new_tab = 1, custom_link_icon = 'question-circle'");
|
||
|
||
|
||
$_SESSION['alert_message'] = "Company <strong>$name</strong> created";
|
||
|
||
header("Location: ?localization");
|
||
|
||
}
|
||
|
||
if (isset($_POST['add_localization_settings'])) {
|
||
|
||
$locale = sanitizeInput($_POST['locale']);
|
||
$currency_code = sanitizeInput($_POST['currency_code']);
|
||
$timezone = sanitizeInput($_POST['timezone']);
|
||
|
||
mysqli_query($mysqli,"UPDATE companies SET company_locale = '$locale', company_currency = '$currency_code' WHERE company_id = 1");
|
||
|
||
mysqli_query($mysqli,"UPDATE settings SET config_timezone = '$timezone' WHERE company_id = 1");
|
||
|
||
// Create Default Cash Account
|
||
mysqli_query($mysqli,"INSERT INTO accounts SET account_name = 'Cash', account_currency_code = '$currency_code'");
|
||
|
||
|
||
$_SESSION['alert_message'] = "Localization Info saved";
|
||
|
||
header("Location: ?telemetry");
|
||
|
||
}
|
||
|
||
if (isset($_POST['add_telemetry'])) {
|
||
|
||
if (isset($_POST['share_data']) && $_POST['share_data'] == 1) {
|
||
|
||
mysqli_query($mysqli,"UPDATE settings SET config_telemetry = 2");
|
||
|
||
$comments = sanitizeInput($_POST['comments']);
|
||
|
||
$sql = mysqli_query($mysqli,"SELECT * FROM companies WHERE company_id = 1");
|
||
$row = mysqli_fetch_array($sql);
|
||
|
||
$company_name = $row['company_name'];
|
||
$website = $row['company_website'];
|
||
$city = $row['company_city'];
|
||
$state = $row['company_state'];
|
||
$country = $row['company_country'];
|
||
$currency = $row['company_currency'];
|
||
|
||
$postdata = http_build_query(
|
||
array(
|
||
'installation_id' => "$installation_id",
|
||
'company_name' => "$company_name",
|
||
'website' => "$website",
|
||
'city' => "$city",
|
||
'state' => "$state",
|
||
'country' => "$country",
|
||
'currency' => "$currency",
|
||
'comments' => "$comments",
|
||
'collection_method' => 1
|
||
)
|
||
);
|
||
|
||
$opts = array('http' =>
|
||
array(
|
||
'method' => 'POST',
|
||
'header' => 'Content-type: application/x-www-form-urlencoded',
|
||
'content' => $postdata
|
||
)
|
||
);
|
||
|
||
$context = stream_context_create($opts);
|
||
|
||
$result = file_get_contents('https://telemetry.itflow.org', false, $context);
|
||
|
||
echo $result;
|
||
|
||
}
|
||
|
||
//final setup stages
|
||
$myfile = fopen("../config.php", "a");
|
||
|
||
$txt = "\$config_enable_setup = 0;\n\n";
|
||
|
||
fwrite($myfile, $txt);
|
||
|
||
fclose($myfile);
|
||
|
||
header("Location: ../login.php");
|
||
exit;
|
||
|
||
}
|
||
|
||
?>
|
||
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||
|
||
<title>ITFlow Setup</title>
|
||
|
||
<!-- Font Awesome Icons -->
|
||
<link rel="stylesheet" href="/plugins/fontawesome-free/css/all.min.css">
|
||
<!-- Theme style -->
|
||
<link rel="stylesheet" href="/plugins/adminlte/css/adminlte.min.css">
|
||
<!-- Custom Style Sheet -->
|
||
<link href="/plugins/select2/css/select2.min.css" rel="stylesheet" type="text/css">
|
||
<link href="/plugins/select2-bootstrap4-theme/select2-bootstrap4.min.css" rel="stylesheet" type="text/css">
|
||
|
||
</head>
|
||
|
||
<body class="hold-transition sidebar-mini">
|
||
|
||
<div class="wrapper text-sm">
|
||
|
||
<!-- Navbar -->
|
||
<nav class="main-header navbar navbar-expand navbar-primary navbar-dark">
|
||
|
||
<!-- Left navbar links -->
|
||
<ul class="navbar-nav">
|
||
<li class="nav-item">
|
||
<a class="nav-link" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a>
|
||
</li>
|
||
</ul>
|
||
|
||
<!-- Right navbar links -->
|
||
<ul class="navbar-nav">
|
||
</ul>
|
||
</nav>
|
||
<!-- /.navbar -->
|
||
|
||
<!-- Main Sidebar Container -->
|
||
<aside class="main-sidebar sidebar-dark-primary elevation-4">
|
||
|
||
<!-- Brand Logo -->
|
||
<a href="https://itflow.org" class="brand-link">
|
||
<h3 class="brand-text font-weight-light"><i class="fas fa-paper-plane text-primary mr-2"></i><span class="text-primary text-bold">IT</span>Flow</h3>
|
||
</a>
|
||
|
||
<!-- Sidebar -->
|
||
<div class="sidebar">
|
||
|
||
<!-- Sidebar Menu -->
|
||
<nav class="mt-2">
|
||
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
|
||
<li class="nav-item">
|
||
<a href="index.php" class="nav-link <?php if (!isset($_GET) || empty($_GET)) { echo 'active'; } ?>">
|
||
<i class="nav-icon fas fa-home text-info"></i>
|
||
<p>1 - Welcome</p>
|
||
</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a href="?checks" class="nav-link <?php if (isset($_GET['checks'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-check"></i>
|
||
<p>2 - Checks</p>
|
||
</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a href="?database" class="nav-link <?php if (isset($_GET['database'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-database"></i>
|
||
<p>3 - Database</p>
|
||
</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a href="?user" class="nav-link <?php if (isset($_GET['user'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-user"></i>
|
||
<p>4 - User</p>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a href="?company" class="nav-link <?php if (isset($_GET['company'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-briefcase"></i>
|
||
<p>5 - Company</p>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a href="?localization" class="nav-link <?php if (isset($_GET['localization'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-globe-americas"></i>
|
||
<p>6 - Localization</p>
|
||
</a>
|
||
</li>
|
||
<li class="nav-item">
|
||
<a href="?telemetry" class="nav-link <?php if (isset($_GET['telemetry'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-share-alt"></i>
|
||
<p>7 - Telemetry</p>
|
||
</a>
|
||
</li>
|
||
|
||
<li class="nav-header">Utilities</li>
|
||
|
||
<li class="nav-item">
|
||
<a href="?restore" class="nav-link <?php if (isset($_GET['restore'])) { echo "active"; } ?>">
|
||
<i class="nav-icon fas fa-upload text-warning"></i>
|
||
<p>Restore Backup</p>
|
||
</a>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- Content Wrapper. Contains page content -->
|
||
<div class="content-wrapper">
|
||
|
||
<!-- Main content -->
|
||
<div class="content mt-3">
|
||
<div class="container-fluid">
|
||
|
||
<?php
|
||
//Alert Feedback
|
||
if (!empty($_SESSION['alert_message'])) {
|
||
?>
|
||
<div class="alert alert-info" id="alert">
|
||
<?php echo nullable_htmlentities($_SESSION['alert_message']); ?>
|
||
<button class='close' data-dismiss='alert'>×</button>
|
||
</div>
|
||
<?php
|
||
$_SESSION['alert_type'] = '';
|
||
$_SESSION['alert_message'] = '';
|
||
}
|
||
?>
|
||
|
||
<?php if (isset($_GET['checks'])) {
|
||
|
||
$checks = [];
|
||
|
||
// Section: PHP Extensions
|
||
$phpExtensions = [];
|
||
$extensions = [
|
||
'php-mysqli' => 'mysqli',
|
||
'php-intl' => 'intl',
|
||
'php-curl' => 'curl',
|
||
'php-mbstring' => 'mbstring',
|
||
'php-gd' => 'gd',
|
||
];
|
||
|
||
foreach ($extensions as $name => $ext) {
|
||
$loaded = extension_loaded($ext);
|
||
$phpExtensions[] = [
|
||
'name' => "$name installed",
|
||
'passed' => $loaded,
|
||
'value' => $loaded ? 'Installed' : 'Not Installed',
|
||
];
|
||
}
|
||
|
||
// Section: PHP Configuration
|
||
$phpConfig = [];
|
||
|
||
// Check if shell_exec is enabled
|
||
$disabled_functions = explode(',', ini_get('disable_functions'));
|
||
$disabled_functions = array_map('trim', $disabled_functions);
|
||
$shell_exec_enabled = !in_array('shell_exec', $disabled_functions);
|
||
|
||
$phpConfig[] = [
|
||
'name' => 'shell_exec is enabled',
|
||
'passed' => $shell_exec_enabled,
|
||
'value' => $shell_exec_enabled ? 'Enabled' : 'Disabled',
|
||
];
|
||
|
||
// Check upload_max_filesize and post_max_size >= 500M
|
||
function return_bytes($val) {
|
||
$val = trim($val);
|
||
$unit = strtolower(substr($val, -1));
|
||
$num = (float)$val;
|
||
switch ($unit) {
|
||
case 'g':
|
||
$num *= 1024;
|
||
case 'm':
|
||
$num *= 1024;
|
||
case 'k':
|
||
$num *= 1024;
|
||
}
|
||
return $num;
|
||
}
|
||
|
||
$required_bytes = 500 * 1024 * 1024; // 500M in bytes
|
||
|
||
$upload_max_filesize = ini_get('upload_max_filesize');
|
||
$post_max_size = ini_get('post_max_size');
|
||
|
||
$upload_passed = return_bytes($upload_max_filesize) >= $required_bytes;
|
||
$post_passed = return_bytes($post_max_size) >= $required_bytes;
|
||
|
||
$phpConfig[] = [
|
||
'name' => 'upload_max_filesize >= 500M',
|
||
'passed' => $upload_passed,
|
||
'value' => $upload_max_filesize,
|
||
];
|
||
|
||
$phpConfig[] = [
|
||
'name' => 'post_max_size >= 500M',
|
||
'passed' => $post_passed,
|
||
'value' => $post_max_size,
|
||
];
|
||
|
||
// Check PHP version >= 8.2.0
|
||
$php_version = PHP_VERSION;
|
||
$php_passed = version_compare($php_version, '8.2.0', '>=');
|
||
|
||
$phpConfig[] = [
|
||
'name' => 'PHP version >= 8.2.0',
|
||
'passed' => $php_passed,
|
||
'value' => $php_version,
|
||
];
|
||
|
||
// Section: Shell Commands
|
||
$shellCommands = [];
|
||
|
||
if ($shell_exec_enabled) {
|
||
$commands = ['whois', 'dig', 'git'];
|
||
|
||
foreach ($commands as $command) {
|
||
$which = trim(shell_exec("which $command 2>/dev/null"));
|
||
$exists = !empty($which);
|
||
$shellCommands[] = [
|
||
'name' => "Command '$command' available",
|
||
'passed' => $exists,
|
||
'value' => $exists ? $which : 'Not Found',
|
||
];
|
||
}
|
||
} else {
|
||
// If shell_exec is disabled, mark commands as unavailable
|
||
foreach (['whois', 'dig', 'git'] as $command) {
|
||
$shellCommands[] = [
|
||
'name' => "Command '$command' available",
|
||
'passed' => false,
|
||
'value' => 'shell_exec Disabled',
|
||
];
|
||
}
|
||
}
|
||
|
||
// Section: SSL Checks
|
||
$sslChecks = [];
|
||
|
||
// Check if accessing via HTTPS
|
||
$https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443;
|
||
$sslChecks[] = [
|
||
'name' => 'Accessing via HTTPS',
|
||
'passed' => $https,
|
||
'value' => $https ? 'Yes' : 'No',
|
||
];
|
||
|
||
// SSL Certificate Validity Check
|
||
if ($https) {
|
||
$streamContext = stream_context_create(["ssl" => ["capture_peer_cert" => true]]);
|
||
$socket = @stream_socket_client("ssl://{$_SERVER['HTTP_HOST']}:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $streamContext);
|
||
|
||
if ($socket) {
|
||
$params = stream_context_get_params($socket);
|
||
$cert = $params['options']['ssl']['peer_certificate'];
|
||
$certInfo = openssl_x509_parse($cert);
|
||
|
||
$validFrom = $certInfo['validFrom_time_t'];
|
||
$validTo = $certInfo['validTo_time_t'];
|
||
$currentTime = time();
|
||
|
||
$certValid = ($currentTime >= $validFrom && $currentTime <= $validTo);
|
||
|
||
$sslChecks[] = [
|
||
'name' => 'SSL Certificate is valid',
|
||
'passed' => $certValid,
|
||
'value' => $certValid ? 'Valid' : 'Invalid or Expired',
|
||
];
|
||
} else {
|
||
$sslChecks[] = [
|
||
'name' => 'SSL Certificate is valid',
|
||
'passed' => false,
|
||
'value' => 'Unable to retrieve certificate',
|
||
];
|
||
}
|
||
} else {
|
||
$sslChecks[] = [
|
||
'name' => 'SSL Certificate is valid',
|
||
'passed' => false,
|
||
'value' => 'Not using HTTPS',
|
||
];
|
||
}
|
||
|
||
// Section: Domain Checks
|
||
$domainChecks = [];
|
||
|
||
// Check if the site has a valid FQDN
|
||
$fqdn = $_SERVER['HTTP_HOST'];
|
||
$isValidFqdn = (bool) filter_var('http://' . $fqdn, FILTER_VALIDATE_URL) && preg_match('/^[a-z0-9.-]+\.[a-z]{2,}$/i', $fqdn);
|
||
|
||
$domainChecks[] = [
|
||
'name' => 'Site has a valid FQDN',
|
||
'passed' => $isValidFqdn,
|
||
'value' => $fqdn,
|
||
];
|
||
|
||
// Section: File Permissions
|
||
$filePermissions = [];
|
||
|
||
// Check if web user has write access to webroot directory
|
||
$webroot = $_SERVER['DOCUMENT_ROOT'];
|
||
$writable = is_writable($webroot);
|
||
$filePermissions[] = [
|
||
'name' => 'Web user has write access to webroot directory',
|
||
'passed' => $writable,
|
||
'value' => $webroot,
|
||
];
|
||
?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-check mr-2"></i>Step 1 - Setup Checks</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<table class="table table-sm table-bordered">
|
||
<tbody>
|
||
<!-- PHP Extensions Section -->
|
||
<tr class="bg-light">
|
||
<th colspan="3">PHP Extensions</th>
|
||
</tr>
|
||
<?php foreach ($phpExtensions as $check): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($check['name']); ?></td>
|
||
<td style="width: 50px; text-align: center;">
|
||
<?php if ($check['passed']): ?>
|
||
<i class="fa fa-check" style="color:green"></i>
|
||
<?php else: ?>
|
||
<i class="fa fa-times" style="color:red"></i>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= htmlspecialchars($check['value']); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
|
||
<!-- PHP Configuration Section -->
|
||
<tr class="bg-light">
|
||
<th colspan="3">PHP Configuration</th>
|
||
</tr>
|
||
<?php foreach ($phpConfig as $check): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($check['name']); ?></td>
|
||
<td style="width: 50px; text-align: center;">
|
||
<?php if ($check['passed']): ?>
|
||
<i class="fa fa-check" style="color:green"></i>
|
||
<?php else: ?>
|
||
<i class="fa fa-times" style="color:red"></i>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= htmlspecialchars($check['value']); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
|
||
<!-- Shell Commands Section -->
|
||
<tr class="bg-light">
|
||
<th colspan="3">Shell Commands</th>
|
||
</tr>
|
||
<?php foreach ($shellCommands as $check): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($check['name']); ?></td>
|
||
<td style="width: 50px; text-align: center;">
|
||
<?php if ($check['passed']): ?>
|
||
<i class="fa fa-check" style="color:green"></i>
|
||
<?php else: ?>
|
||
<i class="fa fa-times" style="color:red"></i>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= htmlspecialchars($check['value']); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
|
||
<!-- SSL Checks Section -->
|
||
<tr class="bg-light">
|
||
<th colspan="3">SSL Checks</th>
|
||
</tr>
|
||
<?php foreach ($sslChecks as $check): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($check['name']); ?></td>
|
||
<td style="width: 50px; text-align: center;">
|
||
<?php if ($check['passed']): ?>
|
||
<i class="fa fa-check" style="color:green"></i>
|
||
<?php else: ?>
|
||
<i class="fa fa-times" style="color:red"></i>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= htmlspecialchars($check['value']); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
|
||
<!-- Domain Checks Section -->
|
||
<tr class="bg-light">
|
||
<th colspan="3">Domain Checks</th>
|
||
</tr>
|
||
<?php foreach ($domainChecks as $check): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($check['name']); ?></td>
|
||
<td style="width: 50px; text-align: center;">
|
||
<?php if ($check['passed']): ?>
|
||
<i class="fa fa-check" style="color:green"></i>
|
||
<?php else: ?>
|
||
<i class="fa fa-times" style="color:red"></i>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= htmlspecialchars($check['value']); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
|
||
<!-- File Permissions Section -->
|
||
<tr class="bg-light">
|
||
<th colspan="3">File Permissions</th>
|
||
</tr>
|
||
<?php foreach ($filePermissions as $check): ?>
|
||
<tr>
|
||
<td><?= htmlspecialchars($check['name']); ?></td>
|
||
<td style="width: 50px; text-align: center;">
|
||
<?php if ($check['passed']): ?>
|
||
<i class="fa fa-check" style="color:green"></i>
|
||
<?php else: ?>
|
||
<i class="fa fa-times" style="color:red"></i>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= htmlspecialchars($check['value']); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
|
||
<hr>
|
||
|
||
<a href="?database" class="btn btn-primary text-bold">Next (Database)<i class="fa fa-fw fa-arrow-circle-right ml-2"></i></a>
|
||
</div>
|
||
</div>
|
||
|
||
<?php } elseif (isset($_GET['database'])) { ?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-database mr-2"></i>Step 2 - Connect your Database</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<?php
|
||
if (file_exists('../config.php')) {
|
||
|
||
echo "<p>Database is already configured. Any further changes should be made by editing the <code>config.php</code> file.</p>";
|
||
|
||
if (@$mysqli) {
|
||
echo "<a href='?user' class='btn btn-success text-bold mt-3'>Next Step (User Setup) <i class='fa fa-fw fa-arrow-circle-right ml-2'></i></a>";
|
||
} else {
|
||
echo "<div class='alert alert-danger mt-3'>Database connection failed. Check <code>config.php</code>.</div>";
|
||
}
|
||
|
||
} else {
|
||
?>
|
||
<form method="post" autocomplete="off">
|
||
|
||
<h5>Database Connection Details</h5>
|
||
|
||
<div class="form-group">
|
||
<label>Database Name <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-database"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="database" placeholder="Database name" autofocus required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Database Host <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-server"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="host" value="localhost" placeholder="Database Host" required>
|
||
</div>
|
||
</div>
|
||
|
||
<br>
|
||
<h5>Database Authentication Details</h5>
|
||
|
||
<div class="form-group">
|
||
<label>Database User <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="username" placeholder="Database user account" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Database Password <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
|
||
</div>
|
||
<input type="password" class="form-control" data-toggle="password" name="password" placeholder="Database user password" autocomplete="new-password" required>
|
||
<div class="input-group-append">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<hr>
|
||
<button type="submit" name="add_database" class="btn btn-primary text-bold">
|
||
Next (First User)<i class="fas fa-fw fa-arrow-circle-right ml-2"></i>
|
||
</button>
|
||
</form>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
|
||
<?php } elseif (isset($_GET['restore'])) { ?>
|
||
|
||
<?php if (!$can_show_restore) { ?>
|
||
<div class="card card-danger">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-exclamation-triangle mr-2"></i>Database Not Ready</h3>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<p>You must configure the database before restoring a backup.</p>
|
||
<a href="?database" class="btn btn-primary text-bold">
|
||
Go to Database Setup <i class="fas fa-arrow-right ml-2"></i>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<?php } else { ?>
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-database mr-2"></i>Restore from Backup</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<form method="post" enctype="multipart/form-data" autocomplete="off">
|
||
<label>Restore ITFlow Backup (.zip)</label>
|
||
<input type="file" name="backup_zip" accept=".zip" required>
|
||
<p class="text-muted mt-2 mb-0"><small>Large restores may take several minutes. Do not close this page.</small></p>
|
||
<hr>
|
||
<button type="submit" name="restore" class="btn btn-primary text-bold">
|
||
Restore Backup<i class="fas fa-fw fa-upload ml-2"></i>
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<?php } ?>
|
||
|
||
<?php } elseif (isset($_GET['user'])) { ?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-user mr-2"></i>Step 3 - Create your first user</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
|
||
<form method="post" enctype="multipart/form-data" autocomplete="off">
|
||
<div class="form-group">
|
||
<label>Name <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="name" placeholder="Full Name" autofocus required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Email <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
|
||
</div>
|
||
<input type="email" class="form-control" name="email" placeholder="Email Address" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Password <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
|
||
</div>
|
||
<input type="password" class="form-control" data-toggle="password" name="password" placeholder="Enter a Password" autocomplete="new-password" required minlength="8">
|
||
<div class="input-group-append">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Avatar</label>
|
||
<input type="file" class="form-control-file" accept="image/*;capture=camera" name="file">
|
||
</div>
|
||
|
||
<hr>
|
||
|
||
<button type="submit" name="add_user" class="btn btn-primary text-bold">Next (Company details) <i class="fa fa-fw fa-arrow-circle-right"></i></button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<?php } elseif (isset($_GET['company'])) { ?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-briefcase mr-2"></i>Step 4 - Company Details</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<form method="post" enctype="multipart/form-data" autocomplete="off">
|
||
|
||
<div class="form-group">
|
||
<label>Company Name <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-building"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="name" placeholder="Company Name" autofocus required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Logo</label>
|
||
<input type="file" class="form-control-file" name="file" accept=".jpg, .jpeg, .png">
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Address</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-map-marker-alt"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="address" placeholder="Street Address">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>City</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-city"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="city" placeholder="City">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>State / Province</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-flag"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="state" placeholder="State or Province">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Postal Code</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fab fa-fw fa-usps"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="zip" placeholder="Zip or Postal Code">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Country <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-globe-americas"></i></span>
|
||
</div>
|
||
<select class="form-control select2" name="country" required>
|
||
<option value="">- Country -</option>
|
||
<?php foreach($countries_array as $country_name) { ?>
|
||
<option><?php echo $country_name; ?></option>
|
||
<?php } ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Phone</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
|
||
</div>
|
||
<input type="tel" class="form-control" name="phone" placeholder="Phone Number">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Email</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-envelope"></i></span>
|
||
</div>
|
||
<input type="email" class="form-control" name="email" placeholder="Company Email address eg: info@company.com">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Website</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-globe"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="website" placeholder="Website address">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Tax ID</label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-balance-scale"></i></span>
|
||
</div>
|
||
<input type="text" class="form-control" name="tax_id" placeholder="Tax ID" maxlength="200">
|
||
</div>
|
||
</div>
|
||
|
||
<hr>
|
||
|
||
<button type="submit" name="add_company_settings" class="btn btn-primary text-bold">
|
||
Next (Localization)<i class="fas fa-fw fa-arrow-circle-right ml-2"></i>
|
||
</button>
|
||
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<?php } elseif (isset($_GET['localization'])) { ?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-globe-americas mr-2"></i>Step 5 - Region and Language</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<form method="post" autocomplete="off">
|
||
|
||
<div class="form-group">
|
||
<label>Language <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-language"></i></span>
|
||
</div>
|
||
<select class="form-control select2" name="locale" required>
|
||
<option value="">- Select a Language -</option>
|
||
<?php foreach($locales_array as $locale_code => $locale_name) { ?>
|
||
<option value="<?php echo $locale_code; ?>"><?php echo $locale_name; ?></option>
|
||
<?php } ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Currency <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-money-bill"></i></span>
|
||
</div>
|
||
<select class="form-control select2" name="currency_code" required>
|
||
<option value="">- Select a Currency -</option>
|
||
<?php foreach($currencies_array as $currency_code => $currency_name) { ?>
|
||
<option value="<?php echo $currency_code; ?>"><?php echo "$currency_code - $currency_name"; ?></option>
|
||
<?php } ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label>Timezone <strong class="text-danger">*</strong></label>
|
||
<div class="input-group">
|
||
<div class="input-group-prepend">
|
||
<span class="input-group-text"><i class="fa fa-fw fa-business-time"></i></span>
|
||
</div>
|
||
<select class="form-control select2" name="timezone" required>
|
||
<option value="">- Select a Timezone -</option>
|
||
<?php foreach ($timezones as $tz) { ?>
|
||
<option value="<?php echo $tz; ?>"><?php echo $tz; ?></option>
|
||
<?php } ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<hr>
|
||
|
||
<button type="submit" name="add_localization_settings" class="btn btn-primary text-bold">
|
||
Next (Telemetry Settings)<i class="fas fa-fw fa-arrow-circle-right ml-2"></i>
|
||
</button>
|
||
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<?php } elseif (isset($_GET['telemetry'])) { ?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-broadcast-tower mr-2"></i>Step 6 - Telemetry</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<form method="post" autocomplete="off">
|
||
<h5>Would you like to share some data with us?</h5>
|
||
|
||
<hr>
|
||
|
||
<div class="form-check">
|
||
<input type="checkbox" class="form-check-input" name="share_data" value="1">
|
||
<label class="form-check-label ml-2">Share <small class="form-text"><a href="https://docs.itflow.org/telemetry" target="_blank">Click Here for additional details regarding the information we gather <i class="fas fa-external-link-alt"></i></a></small></label>
|
||
</div>
|
||
|
||
<br>
|
||
|
||
<div class="form-group">
|
||
<label>Comments</label>
|
||
<textarea class="form-control" rows="4" name="comments" placeholder="Any Comments?"></textarea>
|
||
</div>
|
||
|
||
<hr>
|
||
|
||
<h5>Post installation steps: </h5>
|
||
<p>A few <a href="https://docs.itflow.org/installation#post-installation_essential_housekeeping">housekeeping steps</a> are required to ensure everything runs smoothly, namely:</p>
|
||
<ul>
|
||
<li><a href="https://docs.itflow.org/backups">Setup backups</a></li>
|
||
<li><a href="https://docs.itflow.org/cron">Setup cron</a> *If Installing via script cron jobs will be automatically setup for you.</li>
|
||
<li>Star ITFlow on <a href="https://github.com/itflow-org/itflow">Github</a> :)</li>
|
||
</ul>
|
||
|
||
<hr>
|
||
|
||
<button type="submit" name="add_telemetry" class="btn btn-primary text-bold">
|
||
Finish and Sign in<i class="fas fa-fw fa-check-circle ml-2"></i>
|
||
</button>
|
||
|
||
</form>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<?php } else { ?>
|
||
|
||
<div class="card card-dark">
|
||
<div class="card-header">
|
||
<h3 class="card-title"><i class="fas fa-fw fa-cube mr-2"></i>ITFlow Setup</h3>
|
||
</div>
|
||
<div class="card-body">
|
||
<h2><b>Thank you</b> for choosing to try ITFlow!</h2>
|
||
<p>This is the start of your journey towards amazing client management </p>
|
||
<p>A few tips:</p>
|
||
<ul>
|
||
<li>Please take a look over the install <a href="https://docs.itflow.org/installation">docs</a>, if you haven't already</li>
|
||
<li>Don't hesitate to reach out on the <a href="https://forum.itflow.org/t/support" target="_blank">forums</a> if you need any assistance</li>
|
||
<li><i>Apache/PHP Error log: <?php echo $errorLog ?></i></li>
|
||
</ul>
|
||
<br><p>A database must be created before proceeding - click on the button below to get started.</p>
|
||
<br><hr>
|
||
<p class="text-muted">ITFlow is <b>free software</b>: you can redistribute and/or modify it under the terms of the <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GNU General Public License</a>. <br> It is distributed in the hope that it will be useful, but <b>without any warranty</b>; without even the implied warranty of merchantability or fitness for a particular purpose.</p>
|
||
<?php
|
||
// Check that there is access to write to the current directory
|
||
if (!is_writable('.')) {
|
||
echo "<div class='alert alert-danger'>Warning: The current directory is not writable. Ensure the webserver process has write access (chmod/chown). Check the <a href='https://docs.itflow.org/installation'>docs</a> for info.</div>";
|
||
}
|
||
?>
|
||
<hr>
|
||
<div class="text-center">
|
||
<?php if ($should_skip_to_user): ?>
|
||
<a href="?user" class="btn btn-primary text-bold mr-2">
|
||
Create First User <i class="fas fa-fw fa-user ml-2"></i>
|
||
</a>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($can_show_restore): ?>
|
||
<a href="?restore" class="btn btn-warning text-bold">
|
||
Restore from Backup <i class="fas fa-fw fa-upload ml-2"></i>
|
||
</a>
|
||
<?php endif; ?>
|
||
|
||
<?php if (!$should_skip_to_user && !$can_show_restore): ?>
|
||
<a href="?checks" class="btn btn-primary text-bold">
|
||
Begin Setup <i class="fas fa-fw fa-arrow-alt-circle-right ml-2"></i>
|
||
</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php } ?>
|
||
|
||
</div><!-- /.container-fluid -->
|
||
</div>
|
||
<!-- /.content -->
|
||
</div>
|
||
<!-- /.content-wrapper -->
|
||
</div>
|
||
<!-- ./wrapper -->
|
||
|
||
<!-- REQUIRED SCRIPTS -->
|
||
|
||
<!-- jQuery -->
|
||
<script src="/plugins/jquery/jquery.min.js"></script>
|
||
<!-- Bootstrap 4 -->
|
||
<script src="/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||
<!-- Custom js-->
|
||
<script src='/plugins/select2/js/select2.min.js'></script>
|
||
<script src="/plugins/Show-Hide-Passwords-Bootstrap-4/bootstrap-show-password.min.js"></script>
|
||
<!-- AdminLTE App -->
|
||
<script src="/plugins/adminlte/js/adminlte.min.js"></script>
|
||
|
||
<!-- Custom js-->
|
||
<script src="/js/app.js"></script>
|
||
|
||
</body>
|
||
|
||
</html>
|