[ 'timeout' => 30, 'header' => "User-Agent: TaskFlow-Installer\r\n", 'follow_location' => true ] ]); } // Download a single file from GitHub raw function downloadFile($owner, $repo, $branch, $path, $destDir) { $url = "https://raw.githubusercontent.com/$owner/$repo/$branch/$path"; $content = @file_get_contents($url, false, ghContext()); if ($content === false) return false; $destPath = $destDir . '/' . $path; $destFolder = dirname($destPath); if (!is_dir($destFolder)) @mkdir($destFolder, 0755, true); return file_put_contents($destPath, $content) !== false; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = $_POST['action'] ?? ''; if ($action === 'download') { // Step 1: Get file list from GitHub API (tree) $apiUrl = "https://api.github.com/repos/$repoOwner/$repoName/git/trees/$branch?recursive=1"; $treeJson = @file_get_contents($apiUrl, false, ghContext()); if ($treeJson === false) { $error = 'Could not connect to GitHub API. Check your internet connection.'; } else { $tree = json_decode($treeJson, true); if (!isset($tree['tree'])) { $error = 'Invalid response from GitHub API.'; } else { // Filter files (skip data/*.json, install.php, .git*) $files = []; foreach ($tree['tree'] as $item) { if ($item['type'] !== 'blob') continue; $path = $item['path']; // Skip files we don't want if ($path === 'install.php') continue; if (preg_match('#^data/(users|projects)\.json$#', $path)) continue; if (strpos($path, '.git') === 0 && $path !== '.gitignore') continue; $files[] = $path; } // Download each file $total = count($files); $ok = 0; $failed = []; foreach ($files as $file) { if (downloadFile($repoOwner, $repoName, $branch, $file, $installDir)) { $ok++; } else { $failed[] = $file; } } $downloaded = $ok; if (empty($failed)) { // Create data dir if needed if (!is_dir($dataDir)) @mkdir($dataDir, 0755, true); $filesExist = true; } else { $error = "Downloaded $ok/$total files. Failed: " . implode(', ', array_slice($failed, 0, 5)); if (count($failed) > 5) $error .= ' ...and ' . (count($failed) - 5) . ' more'; } } } } if ($action === 'createuser') { // Step 2: Create admin user $name = trim($_POST['name'] ?? ''); $username = trim($_POST['username'] ?? ''); $password = $_POST['password'] ?? ''; $passwordConfirm = $_POST['password_confirm'] ?? ''; if (!$name || !$username || !$password) { $error = 'Please fill in all fields.'; } elseif (strlen($password) < 4) { $error = 'Password must be at least 4 characters.'; } elseif ($password !== $passwordConfirm) { $error = 'Passwords do not match.'; } else { if (!is_dir($dataDir)) { @mkdir($dataDir, 0755, true); } if (!is_writable($dataDir)) { $error = 'The /data directory is not writable. Set permissions: chmod 755 data'; } else { // .htaccess $htaccess = $dataDir . '/.htaccess'; if (!file_exists($htaccess)) { file_put_contents($htaccess, "Order deny,allow\nDeny from all\n"); } $users = [[ 'id' => 1, 'username' => $username, 'password' => password_hash($password, PASSWORD_DEFAULT), 'name' => $name, 'role' => 'admin', 'createdAt' => date('c') ]]; $usersOk = file_put_contents($dataDir . '/users.json', json_encode($users, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); $projectsOk = file_put_contents($dataDir . '/projects.json', json_encode([], JSON_PRETTY_PRINT)); if ($usersOk !== false && $projectsOk !== false) { $success = true; @unlink(__FILE__); } else { $error = 'Could not write data files.'; } } } } } ?> TaskFlow - Installation
1
2
Installation complete!
TaskFlow has been set up successfully. The installer has been removed.
Open TaskFlow
1
2
Create Admin Account
Set up your administrator login
0): ?>
files downloaded successfully.
1
2
Installation
Download TaskFlow from GitHub
This will download all files from
github.com//