| | * Git-related functions for repository operations |
| | */ |
| | +function getRepoPath($repo) { |
| | + return REPOS_PATH . '/' . basename($repo); |
| | +} |
| | |
| | /** |
| | * Executes a Git command and caches the output. |
| | */ |
| | function execGitCached($repo, $command) { |
| | - $cache_key = md5($repo . '|' . $command); |
| | - $cache_file = CACHE_DIR . '/' . $cache_key . '.cache'; |
| | + $cache_key = md5($repo . '|' . $command); |
| | + $cache_file = CACHE_DIR . '/' . $cache_key . '.cache'; |
| | |
| | - if (file_exists($cache_file) && (time() - filemtime($cache_file) < CACHE_EXPIRY)) { |
| | - return file_get_contents($cache_file); |
| | - } |
| | + if (file_exists($cache_file) && (time() - filemtime($cache_file) < CACHE_EXPIRY)) { |
| | + return file_get_contents($cache_file); |
| | + } |
| | |
| | - $repoPath = REPOS_PATH . '/' . basename($repo); |
| | - $isBare = is_file($repoPath . '/HEAD') && !is_dir($repoPath . '/.git'); |
| | + $repoPath = getRepoPath($repo); |
| | + $isBare = is_file($repoPath . '/HEAD') && !is_dir($repoPath . '/.git'); |
| | |
| | - if ($isBare) { |
| | - $cmd = "git --git-dir=" . escapeshellarg($repoPath) . " " . $command . " 2>&1"; |
| | + // Note: $command should be built using escapeshellarg() by the caller |
| | + if ($isBare) { |
| | + $cmd = "git --git-dir=" . escapeshellarg($repoPath) . " " . $command . " 2>&1"; |
| | + } else { |
| | + if (!is_dir($repoPath . '/.git')) { |
| | + $output = ''; |
| | } else { |
| | - if (!is_dir($repoPath . '/.git')) { |
| | - $output = ''; |
| | - } else { |
| | - $cmd = "cd " . escapeshellarg($repoPath) . " && git " . $command . " 2>&1"; |
| | - } |
| | + $cmd = "cd " . escapeshellarg($repoPath) . " && git " . $command . " 2>&1"; |
| | } |
| | + } |
| | |
| | - $output = isset($cmd) ? shell_exec($cmd) : ''; |
| | + $output = isset($cmd) ? shell_exec($cmd) : ''; |
| | |
| | - if (!empty($output)) { |
| | - file_put_contents($cache_file, $output); |
| | - } |
| | + if (!empty($output)) { |
| | + file_put_contents($cache_file, $output); |
| | + } |
| | |
| | - return $output; |
| | + return $output; |
| | } |
| | |
| | /** |
| | * Executes a raw Git command without caching. |
| | */ |
| | function execGitRaw($repo, $command) { |
| | - $repoPath = REPOS_PATH . '/' . basename($repo); |
| | - $isBare = is_file($repoPath . '/HEAD') && !is_dir($repoPath . '/.git'); |
| | + $repoPath = getRepoPath($repo); |
| | + $isBare = is_file($repoPath . '/HEAD') && !is_dir($repoPath . '/.git'); |
| | |
| | - if ($isBare) { |
| | - $cmd = "git --git-dir=" . escapeshellarg($repoPath) . " " . $command . " 2>&1"; |
| | - } else { |
| | - if (!is_dir($repoPath . '/.git')) { |
| | - return ''; |
| | - } |
| | - $cmd = "cd " . escapeshellarg($repoPath) . " && git " . $command . " 2>&1"; |
| | + if ($isBare) { |
| | + $cmd = "git --git-dir=" . escapeshellarg($repoPath) . " " . $command . " 2>&1"; |
| | + } else { |
| | + if (!is_dir($repoPath . '/.git')) { |
| | + return ''; |
| | } |
| | + $cmd = "cd " . escapeshellarg($repoPath) . " && git " . $command . " 2>&1"; |
| | + } |
| | |
| | - return shell_exec($cmd); |
| | + return shell_exec($cmd); |
| | } |
| | |
| | -/** |
| | - * Main Git execution function (routes to cached version). |
| | - */ |
| | function execGit($repo, $command) { |
| | - return execGitCached($repo, $command); |
| | + return execGitCached($repo, $command); |
| | } |
| | |
| | /** |
| | * Gets blob content as binary data (with caching). |
| | */ |
| | function getBlobBinary($repo, $hash) { |
| | - $cache_key = md5($repo . '|blob_binary|' . $hash); |
| | - $cache_file = CACHE_DIR . '/' . $cache_key . '.cache'; |
| | + $cache_key = md5($repo . '|blob_binary|' . $hash); |
| | + $cache_file = CACHE_DIR . '/' . $cache_key . '.cache'; |
| | |
| | - if (file_exists($cache_file) && (time() - filemtime($cache_file) < CACHE_EXPIRY)) { |
| | - return file_get_contents($cache_file); |
| | - } |
| | + if (file_exists($cache_file) && (time() - filemtime($cache_file) < CACHE_EXPIRY)) { |
| | + return file_get_contents($cache_file); |
| | + } |
| | |
| | - $repoPath = REPOS_PATH . '/' . basename($repo); |
| | - $isBare = is_file($repoPath . '/HEAD') && !is_dir($repoPath . '/.git'); |
| | + $repoPath = getRepoPath($repo); |
| | + $isBare = is_file($repoPath . '/HEAD') && !is_dir($repoPath . '/.git'); |
| | |
| | - if ($isBare) { |
| | - $cmd = "git --git-dir=" . escapeshellarg($repoPath) . " cat-file blob " . escapeshellarg($hash); |
| | - } else { |
| | - $cmd = "cd " . escapeshellarg($repoPath) . " && git cat-file blob " . escapeshellarg($hash); |
| | - } |
| | + // Strictly escape the hash |
| | + $safeHash = escapeshellarg($hash); |
| | |
| | - $descriptors = [ |
| | - 0 => ['pipe', 'r'], |
| | - 1 => ['pipe', 'w'], |
| | - 2 => ['pipe', 'w'] |
| | - ]; |
| | + if ($isBare) { |
| | + $cmd = "git --git-dir=" . escapeshellarg($repoPath) . " cat-file blob " . $safeHash; |
| | + } else { |
| | + $cmd = "cd " . escapeshellarg($repoPath) . " && git cat-file blob " . $safeHash; |
| | + } |
| | |
| | - $process = proc_open($cmd, $descriptors, $pipes); |
| | - if (is_resource($process)) { |
| | - fclose($pipes[0]); |
| | - $output = stream_get_contents($pipes[1]); |
| | - fclose($pipes[1]); |
| | - fclose($pipes[2]); |
| | - proc_close($process); |
| | + $descriptors = [ |
| | + 1 => ['pipe', 'w'], |
| | + 2 => ['pipe', 'w'] |
| | + ]; |
| | |
| | - if (!empty($output)) { |
| | - file_put_contents($cache_file, $output); |
| | - } |
| | + $process = proc_open($cmd, $descriptors, $pipes); |
| | + if (is_resource($process)) { |
| | + $output = stream_get_contents($pipes[1]); |
| | + fclose($pipes[1]); |
| | + fclose($pipes[2]); |
| | + proc_close($process); |
| | |
| | - return $output; |
| | + if (!empty($output)) { |
| | + file_put_contents($cache_file, $output); |
| | } |
| | - return ''; |
| | + |
| | + return $output; |
| | + } |
| | + return ''; |
| | } |
| | |