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("Database connection failed - please check and try again

" . mysqli_connect_error()); } $new_config = "isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname()); } @rmdir($dir); } } if (!function_exists('importSqlFile')) { /** * Import a SQL file via mysqli, supports DELIMITER and multi statements. */ function importSqlFile(mysqli $mysqli, string $path): void { if (!is_file($path) || !is_readable($path)) { throw new RuntimeException("SQL file not found or unreadable: $path"); } $fh = fopen($path, 'r'); if (!$fh) throw new RuntimeException("Failed to open SQL file"); $delimiter = ';'; $statement = ''; while (($line = fgets($fh)) !== false) { $trim = trim($line); // Skip comments/empty if ($trim === '' || str_starts_with($trim, '--') || str_starts_with($trim, '#')) { continue; } // Handle DELIMITER changes if (preg_match('/^DELIMITER\s+(.+)$/i', $trim, $m)) { $delimiter = $m[1]; continue; } $statement .= $line; // End of statement? if (substr(rtrim($statement), -strlen($delimiter)) === $delimiter) { $sql = substr($statement, 0, -strlen($delimiter)); if ($mysqli->multi_query($sql) === false) { fclose($fh); throw new RuntimeException("SQL error: " . $mysqli->error); } // Flush any result sets while ($mysqli->more_results() && $mysqli->next_result()) { /* discard */ } $statement = ''; } } fclose($fh); } } // ---------- 1) Validate uploaded backup ---------- if (!isset($_FILES['backup_zip']) || $_FILES['backup_zip']['error'] !== UPLOAD_ERR_OK) { die("No backup file uploaded or upload failed."); } $file = $_FILES['backup_zip']; $fileExt = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if ($fileExt !== "zip") { die("Only .zip files are allowed."); } // ---------- 2) Save to secure temp ---------- $tempZip = tempnam(sys_get_temp_dir(), "restore_"); if (!move_uploaded_file($file["tmp_name"], $tempZip)) { die("Failed to save uploaded backup file."); } @chmod($tempZip, 0600); $zip = new ZipArchive; if ($zip->open($tempZip) !== TRUE) { @unlink($tempZip); die("Failed to open backup zip file."); } // ---------- 3) Guard & extract OUTER zip ---------- $tempDir = sys_get_temp_dir() . "/restore_temp_" . uniqid("", true); if (!mkdir($tempDir, 0700, true)) { $zip->close(); @unlink($tempZip); die("Failed to create temp directory."); } // Zip-slip guard (outer) for ($i = 0; $i < $zip->numFiles; $i++) { $name = $zip->getNameIndex($i); if ($name === false) continue; if (strpos($name, '..') !== false || preg_match('#^(?:/|\\\\|[a-zA-Z]:[\\\\/])#', $name)) { $zip->close(); @unlink($tempZip); deleteDir($tempDir); die("Invalid file path in outer ZIP."); } } if (!$zip->extractTo($tempDir)) { $zip->close(); @unlink($tempZip); deleteDir($tempDir); die("Failed to extract backup contents."); } $zip->close(); @unlink($tempZip); // ---------- 4) Restore SQL (via PHP, no CLI) ---------- $sqlPath = "$tempDir/db.sql"; if (file_exists($sqlPath)) { // Drop-all first (foreign key safe) mysqli_query($mysqli, "SET FOREIGN_KEY_CHECKS = 0"); $tables = mysqli_query($mysqli, "SHOW TABLES"); if ($tables) { while ($row = mysqli_fetch_array($tables)) { mysqli_query($mysqli, "DROP TABLE IF EXISTS `" . $row[0] . "`"); } } 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')); } } else { deleteDir($tempDir); die("Missing db.sql in the backup archive."); } // ---------- 5) Restore uploads directory ---------- $uploadDir = rtrim(__DIR__ . "/../uploads", '/\\') . '/'; $uploadsZip = "$tempDir/uploads.zip"; if (!file_exists($uploadsZip)) { deleteDir($tempDir); die("Missing uploads.zip in the backup archive."); } $uploads = new ZipArchive; if ($uploads->open($uploadsZip) !== TRUE) { deleteDir($tempDir); die("Failed to open uploads.zip in backup."); } // Zip-slip guard (inner) for ($i = 0; $i < $uploads->numFiles; $i++) { $name = $uploads->getNameIndex($i); if ($name === false) continue; if (strpos($name, '..') !== false || preg_match('#^(?:/|\\\\|[a-zA-Z]:[\\\\/])#', $name)) { $uploads->close(); deleteDir($tempDir); die("Invalid file path in uploads.zip."); } } // Ensure uploads dir exists then clean it if (!is_dir($uploadDir)) { if (!mkdir($uploadDir, 0750, true)) { $uploads->close(); deleteDir($tempDir); die("Failed to create uploads directory."); } } else { foreach (new RecursiveIteratorIterator( new RecursiveDirectoryIterator($uploadDir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST ) as $item) { $item->isDir() ? @rmdir($item->getPathname()) : @unlink($item->getPathname()); } } // Extract uploads.zip directly into /uploads (your original, working behavior) if (!$uploads->extractTo($uploadDir)) { $uploads->close(); deleteDir($tempDir); die("Failed to extract uploads.zip into uploads directory."); } $uploads->close(); // Verify uploads isn’t empty $hasFiles = false; $fileCount = 0; $dirCount = 0; if (is_dir($uploadDir)) { $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($uploadDir, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST ); foreach ($it as $node) { if ($node->isDir()) $dirCount++; else { $fileCount++; $hasFiles = true; } } } if (!$hasFiles) { deleteDir($tempDir); die("Uploads restore appears empty after extraction."); } // ---------- 6) Optional: version info ---------- $versionTxt = "$tempDir/version.txt"; if (file_exists($versionTxt)) { $versionInfo = @file_get_contents($versionTxt); if ($versionInfo !== false) { logAction("Backup Restore", "Version Info", $versionInfo); } } // ---------- 7) Cleanup temp ---------- deleteDir($tempDir); // ---------- 8) Finalize setup flag (append safely) ---------- $configPath = __DIR__ . "/../config.php"; $append = "\n\$config_enable_setup = 0;\n\n"; if (!@file_put_contents($configPath, $append, FILE_APPEND | LOCK_EX)) { $_SESSION['alert_message'] = "Backup restored ($fileCount files, $dirCount folders), but couldn't update setup flag — please set \$config_enable_setup = 0 in config.php."; } else { $_SESSION['alert_message'] = "Full backup restored successfully ($fileCount files, $dirCount folders)."; } // ---------- 9) Done ---------- 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 $name 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 $name 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; } ?> ITFlow Setup
'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, ]; ?>

Step 1 - Setup Checks

PHP Extensions
PHP Configuration
Shell Commands
SSL Checks
Domain Checks
File Permissions

Next (Database)

Step 2 - Connect your Database

Database is already configured. Any further changes should be made by editing the config.php file.

"; if (@$mysqli) { echo "Next Step (User Setup) "; } else { echo "
Database connection failed. Check config.php.
"; } } else { ?>
Database Connection Details

Database Authentication Details

Database Not Ready

You must configure the database before restoring a backup.

Go to Database Setup

Restore from Backup

Large restores may take several minutes. Do not close this page.


Step 3 - Create your first user


Step 4 - Company Details


Step 5 - Region and Language


Step 6 - Telemetry

Would you like to share some data with us?



Post installation steps:

A few housekeeping steps are required to ensure everything runs smoothly, namely:


ITFlow Setup

Thank you for choosing to try ITFlow!

This is the start of your journey towards amazing client management

A few tips:

  • Please take a look over the install docs, if you haven't already
  • Don't hesitate to reach out on the forums if you need any assistance
  • Apache/PHP Error log:

A database must be created before proceeding - click on the button below to get started.



ITFlow is free software: you can redistribute and/or modify it under the terms of the GNU General Public License.
It is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.

Warning: The current directory is not writable. Ensure the webserver process has write access (chmod/chown). Check the docs for info.
"; } ?>