<?php require_once __DIR__ . '/RepositoryList.php'; require_once __DIR__ . '/git/Git.php'; require_once __DIR__ . '/pages/CommitsPage.php'; require_once __DIR__ . '/pages/DiffPage.php'; require_once __DIR__ . '/pages/HomePage.php'; require_once __DIR__ . '/pages/FilePage.php'; require_once __DIR__ . '/pages/RawPage.php'; require_once __DIR__ . '/pages/TagsPage.php'; require_once __DIR__ . '/pages/ClonePage.php'; class Router { private $repos = []; private $git; public function __construct( string $reposPath ) { $this->git = new Git( $reposPath ); $list = new RepositoryList( $reposPath ); $list->eachRepository( function( $repo ) { $this->repos[] = $repo; } ); } public function route(): Page { $reqRepo = $_GET['repo'] ?? ''; $action = $_GET['action'] ?? 'file'; $hash = $this->sanitize( $_GET['hash'] ?? '' ); $subPath = ''; $uri = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ); $scriptName = $_SERVER['SCRIPT_NAME']; if( strpos( $uri, $scriptName ) === 0 ) { $uri = substr( $uri, strlen( $scriptName ) ); } if( preg_match( '#^/([^/]+)\.git(?:/(.*))?$#', $uri, $matches ) ) { $reqRepo = urldecode( $matches[1] ); $subPath = isset( $matches[2] ) ? ltrim( $matches[2], '/' ) : ''; $action = 'clone'; } $currRepo = null; $decoded = urldecode( $reqRepo ); foreach( $this->repos as $repo ) { if( $repo['safe_name'] === $reqRepo || $repo['name'] === $decoded ) { $currRepo = $repo; break; } $prefix = $repo['safe_name'] . '/'; if( strpos( $reqRepo, $prefix ) === 0 ) { $currRepo = $repo; $subPath = substr( $reqRepo, strlen( $prefix ) ); $action = 'clone'; break; } } if( $currRepo ) { $this->git->setRepository( $currRepo['path'] ); } $routes = [ 'home' => fn() => new HomePage( $this->repos, $this->git ), 'file' => fn() => new FilePage( $this->repos, $currRepo, $this->git, $hash ), 'raw' => fn() => new RawPage( $this->git, $hash ), 'commit' => fn() => new DiffPage( $this->repos, $currRepo, $this->git, $hash ), 'commits' => fn() => new CommitsPage( $this->repos, $currRepo, $this->git, $hash ), 'tags' => fn() => new TagsPage( $this->repos, $currRepo, $this->git ), 'clone' => fn() => new ClonePage( $this->git, $subPath ), ]; $action = !$currRepo ? 'home' : $action; return ($routes[$action] ?? $routes['file'])(); } private function sanitize( $path ) { $path = str_replace( [ '..', '\\', "\0" ], [ '', '/', '' ], $path ); return preg_replace( '/[^a-zA-Z0-9_\-\.\/]/', '', $path ); } }