123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733 |
- <?php
- /**
- * Request router
- *
- * @author Christopher Han <xiphux@gmail.com>
- * @copyright Copyright (c) 2010 Christopher Han
- * @package GitPHP
- * @subpackage Router
- */
- class GitPHP_Router
- {
- /**
- * Route map
- *
- * @var array
- */
- protected $routes = array();
- /**
- * Query parameter map
- *
- * @var array
- */
- protected $queryParameters = array();
- /**
- * Clean url flag
- *
- * @var boolean
- */
- protected $cleanurl = false;
- /**
- * Abbreviate hashes flag
- *
- * @var boolean
- */
- protected $abbreviate = false;
- /**
- * Base url
- *
- * @var string
- */
- protected $baseurl;
- /**
- * Full url
- *
- * @var string
- */
- protected $fullurl;
- /**
- * Constructor
- *
- * @param boolean $cleanurl true to generate clean urls
- * @param boolean $abbreviate true to abbreviate hashes
- */
- public function __construct($cleanurl = false, $abbreviate = false)
- {
- $this->cleanurl = $cleanurl;
- $this->abbreviate = $abbreviate;
- $this->baseurl = GitPHP_Util::BaseUrl();
- if (empty($this->baseurl))
- $this->baseurl = '/';
- $this->fullurl = GitPHP_Util::BaseUrl(true);
- $this->InitializeRoutes();
- $this->InitializeQueryParameters();
- }
- /**
- * Get clean url setting
- *
- * @return boolean
- */
- public function GetCleanUrl()
- {
- return $this->cleanurl;
- }
- /**
- * Set clean url setting
- *
- * @param boolean $cleanurl true to generate clean urls
- */
- public function SetCleanUrl($cleanurl)
- {
- $this->cleanurl = $cleanurl;
- }
- /**
- * Get abbreviate hash setting
- *
- * @return boolean
- */
- public function GetAbbreviate()
- {
- return $this->abbreviate;
- }
- /**
- * Set abbreviate hash setting
- *
- * @param boolean $abbreviate abbreviate
- */
- public function SetAbbreviate($abbreviate)
- {
- $this->abbreviate = $abbreviate;
- }
- /**
- * Get base url
- *
- * @param boolean $full true to return full base url (include protocol and hostname)
- * @return string base url
- */
- public function GetBaseUrl($full = false)
- {
- if ($full)
- return $this->fullurl;
- return $this->baseurl;
- }
- /**
- * Set base url
- *
- * @param string $baseurl base url
- */
- public function SetBaseUrl($baseurl)
- {
- $this->baseurl = $baseurl;
- $this->fullurl = $baseurl;
- }
- /**
- * Initialize route map
- */
- private function InitializeRoutes()
- {
- // project view
- $projectroute = new GitPHP_Route('projects/:project', array(
- 'project' => '[^\?]+'
- ));
- // project-specific action with hash and output method
- $this->routes[] = new GitPHP_Route(':action/:hash/:output', array(
- 'action' => 'blobs',
- 'hash' => '[0-9A-Fa-f]{4,40}|HEAD',
- 'output' => 'plain'
- ), array(), $projectroute);
- // project-specific action with hash
- $this->routes[] = new GitPHP_Route(':action/:hash', array(
- 'action' => 'commits|trees|blobs|search|snapshot|commitdiff|blobdiff|blame',
- 'hash' => '[0-9A-Fa-f]{4,40}|HEAD'
- ), array(), $projectroute);
- // project-specific action with hash or ref
- $this->routes[] = new GitPHP_Route(':action/:hash', array(
- 'action' => 'shortlog|log',
- 'hash' => '[^\?]+'
- ), array(), $projectroute);
- // map heads to shortlog
- $this->routes[] = new GitPHP_Route(':action/:hash', array(
- 'action' => 'heads',
- 'hash' => '[^\?]+'
- ), array(
- 'action' => 'shortlog'
- ), $projectroute);
- // project-specific graphs
- $this->routes[] = new GitPHP_Route(':action/:graphtype', array(
- 'action' => 'graphs',
- 'graphtype' => '[a-z]+'
- ), array(), $projectroute);
- // project-specific tag
- $this->routes[] = new GitPHP_Route(':action/:tag', array(
- 'action' => 'tags',
- 'tag' => '[^\?]+'
- ), array(), $projectroute);
- $formats = GitPHP_Archive::SupportedFormats();
- if (count($formats) > 0) {
- $formatconstraint = implode("|", array_keys($formats));
- // project specific snapshot format with hash
- $this->routes[] = new GitPHP_Route(':format/:hash', array(
- 'format' => $formatconstraint,
- 'hash' => '[0-9A-Fa-f]{4,40}|HEAD'
- ), array(
- 'action' => 'snapshot'
- ), $projectroute);
- // project specific snapshot format
- $this->routes[] = new GitPHP_Route(':format', array(
- 'format' => $formatconstraint
- ), array(
- 'action' => 'snapshot'
- ), $projectroute);
- }
- // project-specific action only
- $this->routes[] = new GitPHP_Route(':action', array(
- 'action' => 'tags|heads|shortlog|log|search|atom|rss|snapshot|commits|graphs|trees|blobs|history|commitdiff|blobdiff'
- ), array(), $projectroute);
- $this->routes[] = $projectroute;
- // non-project action
- $this->routes[] = new GitPHP_Route(':action', array(
- 'action' => 'opml|projectindex|login|logout'
- ));
- usort($this->routes, array('GitPHP_Route', 'CompareRoute'));
- }
- /**
- * Initialize query parameter map
- */
- private function InitializeQueryParameters()
- {
- $this->queryParameters = array(
- 'project' => 'p',
- 'action' => 'a',
- 'hash' => 'h',
- 'hashbase' => 'hb',
- 'hashparent' => 'hp',
- 'graphtype' => 'g',
- 'output' => 'o',
- 'format' => 'fmt',
- 'tag' => 't',
- 'page' => 'pg',
- 'search' => 's',
- 'searchtype' => 'st',
- 'diffmode' => 'd',
- 'file' => 'f',
- 'mark' => 'm',
- 'prefix' => 'prefix',
- 'sort' => 'sort',
- 'lang' => 'l',
- 'redirect' => 'redirect'
- );
- }
- /**
- * Convert a parameter array to a query variable array
- *
- * @param array $params parameter array
- * @return array query variable array
- */
- private function ParameterArrayToQueryVarArray($params)
- {
- $queryvars = array();
- if (count($params) < 1)
- return $queryvars;
- foreach ($params as $param => $val) {
- if (empty($val))
- continue;
- if (empty($this->queryParameters[$param]))
- continue;
- $queryvar = $this->queryParameters[$param];
- if (!empty($queryvar))
- $queryvars[$queryvar] = $val;
- }
- return $queryvars;
- }
- /**
- * Convert a query variable array to a parameter array
- *
- * @param array $queryvars query variable array
- * @return array parameter array
- */
- private function QueryVarArrayToParameterArray($queryvars)
- {
- $params = array();
- if (count($queryvars) < 1)
- return $params;
- foreach ($queryvars as $var => $val) {
- if (empty($val))
- continue;
- $param = array_search($var, $this->queryParameters);
- if (!empty($param))
- $params[$param] = $val;
- }
- return $params;
- }
- /**
- * Build route from url parameters
- *
- * @param array $urlparams url parameters
- */
- private function BuildRoute($urlparams)
- {
- foreach ($this->routes as $route) {
- if (!$route->Valid($urlparams))
- continue;
- $path = $route->Build($urlparams);
- $usedparams = $route->GetUsedParameters();
- return array($path, $usedparams);
- }
- return array(null, array());
- }
- /**
- * Find route matching query
- *
- * @param string $query query
- * @return array query parameters
- */
- private function FindRoute($query)
- {
- if (empty($query))
- return array();
- foreach ($this->routes as $route) {
- $params = $route->Match($query);
- if ($params === false)
- continue;
- return $params;
- }
- return array();
- }
- /**
- * Gets a controller for an action
- *
- * @return GitPHP_ControllerBase
- */
- public function GetController()
- {
- $params = $this->QueryVarArrayToParameterArray($_GET);
- if (!empty($_POST)) {
- $params = array_merge($params, $this->QueryVarArrayToParameterArray($_POST));
- }
- if (!empty($_GET['q'])) {
- $restparams = GitPHP_Router::ReadCleanUrl($_SERVER['REQUEST_URI']);
- if (count($restparams) > 0)
- $params = array_merge($params, $restparams);
- }
- $controller = null;
- $action = null;
- if (!empty($params['action']))
- $action = $params['action'];
- switch ($action) {
- case 'search':
- $controller = new GitPHP_Controller_Search();
- break;
- case 'commitdiff':
- case 'commitdiff_plain':
- $controller = new GitPHP_Controller_Commitdiff();
- if ($action === 'commitdiff_plain')
- $controller->SetParam('output', 'plain');
- break;
- case 'blobdiff':
- case 'blobdiff_plain':
- $controller = new GitPHP_Controller_Blobdiff();
- if ($action === 'blobdiff_plain')
- $controller->SetParam('output', 'plain');
- break;
- case 'history':
- $controller = new GitPHP_Controller_History();
- break;
- case 'shortlog':
- case 'log':
- $controller = new GitPHP_Controller_Log();
- if ($action === 'shortlog')
- $controller->SetParam('short', true);
- break;
- case 'snapshot':
- $controller = new GitPHP_Controller_Snapshot();
- break;
- case 'tree':
- case 'trees':
- $controller = new GitPHP_Controller_Tree();
- break;
- case 'tags':
- if (empty($params['tag'])) {
- $controller = new GitPHP_Controller_Tags();
- break;
- }
- case 'tag':
- $controller = new GitPHP_Controller_Tag();
- break;
- case 'heads':
- $controller = new GitPHP_Controller_Heads();
- break;
- case 'blame':
- $controller = new GitPHP_Controller_Blame();
- break;
- case 'blob':
- case 'blobs':
- case 'blob_plain':
- $controller = new GitPHP_Controller_Blob();
- if ($action === 'blob_plain')
- $controller->SetParam('output', 'plain');
- break;
- case 'atom':
- case 'rss':
- $controller = new GitPHP_Controller_Feed();
- if ($action == 'rss')
- $controller->SetParam('format', GitPHP_Controller_Feed::RssFormat);
- else if ($action == 'atom')
- $controller->SetParam('format', GitPHP_Controller_Feed::AtomFormat);
- break;
- case 'commit':
- case 'commits':
- $controller = new GitPHP_Controller_Commit();
- break;
- case 'summary':
- $controller = new GitPHP_Controller_Project();
- break;
- case 'project_index':
- case 'projectindex':
- $controller = new GitPHP_Controller_ProjectList();
- $controller->SetParam('txt', true);
- break;
- case 'opml':
- $controller = new GitPHP_Controller_ProjectList();
- $controller->SetParam('opml', true);
- break;
- case 'login':
- $controller = new GitPHP_Controller_Login();
- if (!empty($_POST['username']))
- $controller->SetParam('username', $_POST['username']);
- if (!empty($_POST['password']))
- $controller->SetParam('password', $_POST['password']);
- break;
- case 'logout':
- $controller = new GitPHP_Controller_Logout();
- break;
- case 'graph':
- case 'graphs':
- //$controller = new GitPHP_Controller_Graph();
- //break;
- case 'graphdata':
- //$controller = new GitPHP_Controller_GraphData();
- //break;
- default:
- if (!empty($params['project'])) {
- $controller = new GitPHP_Controller_Project();
- } else {
- $controller = new GitPHP_Controller_ProjectList();
- }
- }
- foreach ($params as $paramname => $paramval) {
- if ($paramname !== 'action')
- $controller->SetParam($paramname, $paramval);
- }
- $controller->SetRouter($this);
- return $controller;
- }
- /**
- * Get message controller
- *
- * @return GitPHP_ControllerBase
- */
- public function GetMessageController()
- {
- $params = $this->QueryVarArrayToParameterArray($_GET);
- if (!empty($_GET['q'])) {
- $restparams = GitPHP_Router::ReadCleanUrl($_SERVER['REQUEST_URI']);
- if (count($restparams) > 0)
- $params = array_merge($params, $restparams);
- }
- $controller = new GitPHP_Controller_Message();
- foreach ($params as $paramname => $paramval) {
- if ($paramname !== 'action')
- $controller->SetParam($paramname, $paramval);
- }
- $controller->SetRouter($this);
- return $controller;
- }
- /**
- * Read a rest-style clean url
- *
- * @param string $url url
- * @return array request parameters from url
- */
- private function ReadCleanUrl($url)
- {
- $querypos = strpos($url, '?');
- if ($querypos !== false)
- $url = substr($url, 0, $querypos);
- $url = rtrim($url, "/");
- $baseurl = GitPHP_Util::AddSlash(GitPHP_Util::BaseUrl(), false);
- if (empty($baseurl))
- $baseurl = '/';
- if (strncmp($baseurl, $url, strlen($baseurl)) === 0)
- $url = substr($url, strlen($baseurl));
- return $this->FindRoute($url);
- }
- /**
- * Generate a url
- *
- * @param array $params request parameters
- * @param boolean $full true to get full url (include protocol and hostname)
- */
- public function GetUrl($params = array(), $full = false)
- {
- if ($full)
- $baseurl = $this->fullurl;
- else
- $baseurl = $this->baseurl;
- if ($this->cleanurl) {
- if (substr_compare($baseurl, 'index.php', -9) === 0) {
- $baseurl = dirname($baseurl);
- }
- $baseurl = GitPHP_Util::AddSlash($baseurl, false);
- } else {
- if (substr_compare($baseurl, 'index.php', -9) !== 0) {
- $baseurl = GitPHP_Util::AddSlash($baseurl, false);
- }
- }
- if (count($params) < 1)
- return $baseurl;
- $abbreviate = $this->abbreviate;
- if ($abbreviate && !empty($params['project']) && ($params['project'] instanceof GitPHP_Project)) {
- if ($params['project']->GetCompat())
- $abbreviate = false;
- }
- foreach ($params as $paramname => $paramval) {
- switch ($paramname) {
- case 'hash':
- case 'hashbase':
- case 'hashparent':
- case 'mark':
- $params[$paramname] = GitPHP_Router::GetHash($paramval, $abbreviate);
- break;
- case 'tag':
- $params[$paramname] = GitPHP_Router::GetTag($paramval);
- break;
- case 'project':
- $params[$paramname] = GitPHP_Router::GetProject($paramval);
- break;
- }
- }
- if ($this->cleanurl) {
- if (!empty($params['action'])) {
- switch ($params['action']) {
- case 'blob':
- case 'commit':
- case 'tree':
- case 'graph':
- case 'tag':
- // these actions are plural in clean urls
- $params['action'] = $params['action'] . 's';
- break;
- }
- }
- list($queryurl, $exclude) = $this->BuildRoute($params);
- $baseurl .= $queryurl;
- foreach ($exclude as $excludeparam) {
- unset($params[$excludeparam]);
- }
- }
- $querystr = GitPHP_Router::GetQueryString($params);
- if (empty($querystr))
- return $baseurl;
- return $baseurl . '?' . $querystr;
- }
- /**
- * Gets query parameters for a url
- *
- * @param array $params query parameters
- * @return string query string
- */
- private function GetQueryString($params = array())
- {
- if (count($params) < 1)
- return null;
- $query = $this->ParameterArrayToQueryVarArray($params);
- if (count($query) < 1)
- return null;
- $querystr = null;
- foreach ($query as $var => $val) {
- if (empty($val))
- continue;
- if (!empty($querystr))
- $querystr .= '&';
- $querystr .= $var . '=' . rawurlencode($val);
- }
- return $querystr;
- }
- /**
- * Gets a hash for a string or hash-identified object
- *
- * @param string|GitPHP_GitObject $value string or hashed object
- * @param boolean $abbreviate true to abbreviate hash
- * @return string hash
- */
- private static function GetHash($value, $abbreviate = false)
- {
- if ($value instanceof GitPHP_GitObject)
- return $value->GetHash($abbreviate);
- else if (is_string($value))
- return $value;
- return null;
- }
- /**
- * Gets an identifier for a tag
- *
- * @param string|GitPHP_Tag $value string or tag
- * @return string hash
- */
- private static function GetTag($value)
- {
- if ($value instanceof GitPHP_Tag)
- return $value->GetName();
- else if (is_string($value))
- return $value;
- return null;
- }
- /**
- * Gets a project identifier for a project
- *
- * @param string|GitPHP_Project $value string or project
- * @return string identifier
- */
- private static function GetProject($value)
- {
- if ($value instanceof GitPHP_Project) {
- return $value->GetProject();
- } else if (is_string($value)) {
- return $value;
- }
- }
- }
|