123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- <?php
- /**
- * Base class that all controllers extend
- *
- * @author Christopher Han <xiphux@gmail.com
- * @copyright Copyright (c) 2010 Christopher Han
- * @package GitPHP
- * @subpackage Controller
- */
- abstract class GitPHP_ControllerBase
- {
- /**
- * Config handler instance
- *
- * @var GitPHP_Config
- */
- protected $config;
- /**
- * User list instance
- *
- * @var GitPHP_UserList
- */
- protected $userList;
- /**
- * Resource handler instance
- *
- * @var GitPHP_Resource
- */
- protected $resource;
- /**
- * Smarty instance
- *
- * @var Smarty
- */
- protected $tpl;
- /**
- * Project list
- *
- * @var GitPHP_ProjectListBase
- */
- protected $projectList;
- /**
- * Current project
- *
- * @var GitPHP_Project
- */
- protected $project;
- /**
- * Flag if this is a multi project controller
- *
- * @var boolean
- */
- protected $multiProject;
- /**
- * Parameters
- *
- * @var array
- */
- protected $params = array();
- /**
- * HTTP Headers
- *
- * @var string[]
- */
- protected $headers = array();
- /**
- * Flag to preserve whitespace in output (for non-html output)
- *
- * @var boolean
- */
- protected $preserveWhitespace = false;
- /**
- * Logger instance
- *
- * @var GitPHP_DebugLog
- */
- protected $log;
- /**
- * Git executable instance
- *
- * @var GitPHP_GitExe
- */
- protected $exe;
- /**
- * Url router instance
- *
- * @var GitPHP_Router
- */
- protected $router;
- /**
- * Initialize controller
- */
- public function Initialize()
- {
- $this->InitializeConfig();
- $this->InitializeResource();
- $this->InitializeUserList();
- $this->EnableLogging();
- $this->InitializeGitExe();
- $this->InitializeProjectList();
- $this->InitializeSmarty();
- if ($this->multiProject) {
- $this->projectList->LoadProjects();
- }
- if (!empty($this->params['project'])) {
- $project = $this->projectList->GetProject($this->params['project']);
- if (!$project) {
- throw new GitPHP_InvalidProjectParameterException($this->params['project']);
- }
- if ($this->userList && ($this->userList->GetCount() > 0)) {
- if (!$project->UserCanAccess((!empty($_SESSION['gitphpuser']) ? $_SESSION['gitphpuser'] : null))) {
- throw new GitPHP_UnauthorizedProjectException($this->params['project']);
- }
- }
- $this->project = $project->GetProject();
- }
- if (!($this->project || $this->multiProject)) {
- throw new GitPHP_MissingProjectParameterException();
- }
- }
- /**
- * Initialize config
- */
- protected function InitializeConfig()
- {
- $this->config = new GitPHP_Config();
- $this->config->LoadConfig(GITPHP_CONFIGDIR . 'gitphp.conf.php');
- }
- /**
- * Initialize resource manager
- */
- protected function InitializeResource()
- {
- $locale = null;
- $baseurl = GitPHP_Util::BaseUrl();
- if (empty($baseurl) && $this->config->GetValue('cleanurl'))
- $baseurl = '/';
- if (!empty($this->params['lang'])) {
- /*
- * User picked something
- */
- setcookie(GitPHP_Resource::LocaleCookie, $this->params['lang'], time()+GitPHP_Resource::LocaleCookieLifetime, $baseurl);
- $locale = $this->params['lang'];
- } else if (!empty($_COOKIE[GitPHP_Resource::LocaleCookie])) {
- /**
- * Returning user with a preference
- */
- $locale = $_COOKIE[GITPHP_Resource::LocaleCookie];
- } else {
- /*
- * User's first time here, try by HTTP_ACCEPT_LANGUAGE
- */
- if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
- $locale = GitPHP_Resource::FindPreferredLocale($_SERVER['HTTP_ACCEPT_LANGUAGE']);
- if (!empty($locale)) {
- setcookie(GitPHP_Resource::LocaleCookie, $locale, time()+GitPHP_Resource::LocaleCookieLifetime, $baseurl);
- }
- }
- }
- if (empty($locale) && $this->config) {
- /*
- * No preference, fall back on setting
- */
- $locale = $this->config->GetValue('locale');
- }
- if (!empty($locale) && ($locale != 'en_US')) {
- try {
- $this->resource = new GitPHP_Resource($locale);
- } catch (Exception $e) {
- }
- }
- }
- /**
- * Initialize user list
- */
- public function InitializeUserList()
- {
- $this->userList = new GitPHP_UserList();
- $this->userList->LoadUsers(GITPHP_CONFIGDIR . 'users.conf.php');
- if ($this->userList->GetCount() > 0) {
- if (!isset($_SESSION))
- session_start();
- }
- }
- /**
- * Initialize executable
- *
- * @param boolean $validate whether the exe should be validated
- */
- protected function InitializeGitExe($validate = true)
- {
- $this->exe = new GitPHP_GitExe($this->config->GetValue('gitbin'));
- if ($this->log)
- $this->exe->AddObserver($this->log);
- if ($validate && !$this->exe->Valid()) {
- throw new GitPHP_InvalidGitExecutableException($this->exe->GetBinary());
- }
- }
- /**
- * Initialize project list
- */
- protected function InitializeProjectList()
- {
- if (file_exists(GITPHP_CONFIGDIR . 'projects.conf.php')) {
- $this->projectList = GitPHP_ProjectList::Instantiate($this->config, GITPHP_CONFIGDIR . 'projects.conf.php', false);
- } else {
- $this->projectList = GitPHP_ProjectList::Instantiate($this->config, GITPHP_CONFIGDIR . 'gitphp.conf.php', true);
- }
- $this->projectList->SetMemoryCache(new GitPHP_MemoryCache($this->config->GetValue('objectmemory')));
- if ($this->config->GetValue('objectcache')) {
- $strategy = null;
- $servers = $this->config->GetValue('memcache');
- if ($servers) {
- if (class_exists('Memcached')) {
- $strategy = new GitPHP_Cache_Memcached($servers);
- } else if (class_exists('Memcache')) {
- $strategy = new GitPHP_Cache_Memcache($servers);
- } else {
- throw new GitPHP_MissingMemcacheException();
- }
- } else {
- $strategy = new GitPHP_Cache_File(GITPHP_CACHEDIR . 'objects', $this->config->GetValue('objectcachecompress'));
- }
- $cache = new GitPHP_Cache($strategy);
- $cache->SetLifetime($this->config->GetValue('objectcachelifetime'));
- $this->projectList->SetCache($cache);
- }
- $this->projectList->SetExe($this->exe);
- if ($this->log)
- $this->projectList->AddObserver($this->log);
- }
- /**
- * Initialize smarty
- */
- protected function InitializeSmarty()
- {
- require_once(GITPHP_SMARTYDIR . 'Smarty.class.php');
- $this->tpl = new Smarty;
- $this->tpl->error_reporting = E_ALL & ~E_NOTICE;
- $this->tpl->merge_compiled_includes = true;
- $this->tpl->addPluginsDir(GITPHP_INCLUDEDIR . 'smartyplugins');
- if ($this->config->GetValue('cache')) {
- $cacheDir = GITPHP_CACHEDIR . 'templates';
- if (file_exists($cacheDir)) {
- if (!is_dir($cacheDir)) {
- throw new Exception($cacheDir . ' exists but is not a directory');
- } else if (!is_writable($cacheDir)) {
- throw new Exception($cacheDir . ' is not writable');
- }
- } else {
- if (!mkdir($cacheDir, 0777))
- throw new Exception($cacheDir . ' could not be created');
- chmod($cacheDir, 0777);
- }
- $this->tpl->setCacheDir($cacheDir);
- $this->tpl->caching = Smarty::CACHING_LIFETIME_SAVED;
- if ($this->config->HasKey('cachelifetime')) {
- $this->tpl->cache_lifetime = $this->config->GetValue('cachelifetime');
- }
- $servers = $this->config->GetValue('memcache');
- if (isset($servers) && is_array($servers) && (count($servers) > 0)) {
- $this->tpl->registerCacheResource('memcache', new GitPHP_CacheResource_Memcache($servers));
- $this->tpl->caching_type = 'memcache';
- }
- }
- }
- /**
- * Set router instance
- *
- * @param GitPHP_Router $router router
- */
- public function SetRouter($router)
- {
- $this->router = $router;
- }
- /**
- * Get config instance
- *
- * @return GitPHP_Config
- */
- public function GetConfig()
- {
- return $this->config;
- }
- /**
- * Get log instance
- *
- * @return GitPHP_DebugLog
- */
- public function GetLog()
- {
- return $this->log;
- }
- /**
- * Enable logging
- */
- public function EnableLogging()
- {
- if ($this->log)
- return;
- $debug = $this->config->GetValue('debug');
- if ($debug) {
- $this->log = GitPHP_DebugLog::GetInstance();
- $this->log->init($debug, $this->config->GetValue('benchmark'));
- $this->log->SetStartTime(GITPHP_START_TIME);
- $this->log->SetStartMemory(GITPHP_START_MEM);
- if ($this->exe)
- $this->exe->AddObserver($this->log);
- if ($this->projectList)
- $this->projectList->AddObserver($this->log);
- }
- }
- /**
- * Disable logging
- */
- protected function DisableLogging()
- {
- if (!$this->log)
- return;
- if ($this->projectList)
- $this->projectList->RemoveObserver($this->log);
- if ($this->exe)
- $this->exe->RemoveObserver($this->log);
- $this->log->SetEnabled(false);
- $this->log = null;
- }
- /**
- * Gets the project for this controller
- *
- * @return GitPHP_Project|null project
- */
- public function GetProject()
- {
- if ($this->project)
- return $this->projectList->GetProject($this->project);
- return null;
- }
- /**
- * Gets the template for this controller
- *
- * @return string template filename
- */
- protected abstract function GetTemplate();
- /**
- * Gets the cache key for this controller
- *
- * @return string cache key
- */
- protected abstract function GetCacheKey();
- /**
- * Get the prefix for all cache keys
- *
- * @param boolean $projectKeys include project-specific key pieces
- * @return string cache key prefix
- */
- private function GetCacheKeyPrefix($projectKeys = true)
- {
- if ($this->resource)
- $cacheKeyPrefix = $this->resource->GetLocale();
- else
- $cacheKeyPrefix = 'en_US';
- if ($this->projectList) {
- $cacheKeyPrefix .= '|' . sha1(serialize($this->projectList->GetProjectListConfig())) . '|' . sha1(serialize($this->projectList->GetProjectSettings()));
- }
- if ($this->project && $projectKeys) {
- $cacheKeyPrefix .= '|' . sha1($this->project);
- }
- return $cacheKeyPrefix;
- }
- /**
- * Get the full cache key
- *
- * @return string full cache key
- */
- protected function GetFullCacheKey()
- {
- $cacheKey = $this->GetCacheKeyPrefix();
- $subCacheKey = $this->GetCacheKey();
- if (!empty($subCacheKey))
- $cacheKey .= '|' . $subCacheKey;
- if (strlen($cacheKey) > 100) {
- $cacheKey = sha1($cacheKey);
- }
- return $cacheKey;
- }
- /**
- * Gets the name of this controller's action
- *
- * @param boolean $local true if caller wants the localized action name
- * @return string action name
- */
- public abstract function GetName($local = false);
- /**
- * Set a parameter
- *
- * @param string $key key to set
- * @param mixed $value value to set
- */
- public function SetParam($key, $value)
- {
- if (empty($key))
- return;
- if (empty($value))
- unset($this->params[$key]);
- if (is_string($value))
- $value = str_replace(chr(0), '', $value);
- $this->params[$key] = $value;
- }
- /**
- * Loads headers for this template
- */
- protected function LoadHeaders()
- {
- $this->headers[] = 'Content-Type: text/html; charset=UTF-8';
- }
- /**
- * Loads data for this template
- */
- protected abstract function LoadData();
- /**
- * Loads common data used by all templates
- */
- private function LoadCommonData()
- {
- global $gitphp_version, $gitphp_appstring;
- $this->tpl->assign('version', $gitphp_version);
- $stylesheet = $this->config->GetValue('stylesheet');
- if ($stylesheet == 'gitphp.css') {
- // backwards compatibility
- $stylesheet = 'gitphpskin.css';
- }
- $this->tpl->assign('stylesheet', preg_replace('/\.css$/', '', $stylesheet));
- $this->tpl->assign('javascript', $this->config->GetValue('javascript'));
- $this->tpl->assign('googlejs', $this->config->GetValue('googlejs'));
- if ($this->config->HasKey('title')) {
- $this->tpl->assign('pagetitle', $this->config->GetValue('title'));
- } else {
- $this->tpl->assign('pagetitle', $gitphp_appstring);
- }
- if ($this->config->HasKey('homelink')) {
- $this->tpl->assign('homelink', $this->config->GetValue('homelink'));
- } else {
- if ($this->resource)
- $this->tpl->assign('homelink', $this->resource->translate('projects'));
- else
- $this->tpl->assign('homelink', 'projects');
- }
- $this->tpl->assign('action', $this->GetName());
- $this->tpl->assign('actionlocal', $this->GetName(true));
- if ($this->project)
- $this->tpl->assign('project', $this->GetProject());
- if ($this->config->GetValue('search'))
- $this->tpl->assign('enablesearch', true);
- if ($this->config->GetValue('filesearch'))
- $this->tpl->assign('filesearch', true);
- if (isset($this->params['search']))
- $this->tpl->assign('search', $this->params['search']);
- if (isset($this->params['searchtype']))
- $this->tpl->assign('searchtype', $this->params['searchtype']);
- if ($this->resource) {
- $this->tpl->assign('currentlocale', $this->resource->GetLocale());
- $this->tpl->assign('currentprimarylocale', $this->resource->GetPrimaryLocale());
- $this->tpl->assign('resource', $this->resource);
- } else {
- $this->tpl->assign('currentlocale', 'en_US');
- $this->tpl->assign('currentprimarylocale', 'en');
- }
- $this->tpl->assign('supportedlocales', GitPHP_Resource::SupportedLocales(true));
- if ($this->config->GetValue('graphs'))
- $this->tpl->assign('enablegraphs', true);
- $this->tpl->assign('baseurl', GitPHP_Util::BaseUrl());
- $requesturl = $_SERVER['REQUEST_URI'];
- $querypos = strpos($requesturl, '?');
- if ($querypos !== false)
- $requesturl = substr($requesturl, 0, $querypos);
- $this->tpl->assign('requesturl', $requesturl);
- if ($this->router) {
- $this->router->SetCleanUrl($this->config->GetValue('cleanurl') ? true : false);
- $this->router->SetAbbreviate($this->config->GetValue('abbreviateurl') ? true : false);
- if ($this->config->GetValue('self')) {
- $this->router->SetBaseUrl($this->config->GetValue('self'));
- }
- $this->tpl->assign('router', $this->router);
- }
- $getvars = array();
- if (isset($_SERVER['QUERY_STRING'])) {
- $getvars = explode('&', $_SERVER['QUERY_STRING']);
- }
- $getvarsmapped = array();
- foreach ($getvars as $varstr) {
- $eqpos = strpos($varstr, '=');
- if ($eqpos > 0) {
- $var = substr($varstr, 0, $eqpos);
- $val = substr($varstr, $eqpos + 1);
- if (!(empty($var) || empty($val) || ($var == 'q'))) {
- $getvarsmapped[$var] = urldecode($val);
- }
- }
- }
- $this->tpl->assign('requestvars', $getvarsmapped);
- $this->tpl->assign('snapshotformats', GitPHP_Archive::SupportedFormats());
- if ($this->userList && ($this->userList->GetCount() > 0)) {
- $this->tpl->assign('loginenabled', true);
- if (!empty($_SESSION['gitphpuser'])) {
- $user = $this->userList->GetUser($_SESSION['gitphpuser']);
- if ($user) {
- $this->tpl->assign('loggedinuser', $user->GetUsername());
- }
- }
- }
- if ($this->log && $this->log->GetEnabled()) {
- $this->tpl->assign('debug', true);
- }
- }
- /**
- * Renders any special headers
- */
- public function RenderHeaders()
- {
- $this->LoadHeaders();
- if (count($this->headers) > 0) {
- $hascontenttype = false;
- foreach ($this->headers as $hdr) {
- if (empty($hdr))
- continue;
- if (strncmp($hdr, 'Content-Type:', 13) === 0) {
- if ($hascontenttype)
- throw new Exception('Duplicate Content-Type header');
- $hascontenttype = true;
- }
- header($hdr);
- }
- }
- }
- /**
- * Renders the output
- */
- public function Render()
- {
- if (($this->config->GetValue('cache') == true) && ($this->config->GetValue('cacheexpire') === true))
- $this->CacheExpire();
- $log = GitPHP_DebugLog::GetInstance();
- if (!$this->tpl->isCached($this->GetTemplate(), $this->GetFullCacheKey())) {
- $this->tpl->clearAllAssign();
- $log->TimerStart();
- $this->LoadCommonData();
- $log->TimerStop('Common data');
- $log->TimerStart();
- $this->LoadData();
- $log->TimerStop('Data');
- }
- if (!$this->preserveWhitespace) {
- //$this->tpl->loadFilter('output', 'trimwhitespace');
- }
- $log->TimerStart();
- $this->tpl->display($this->GetTemplate(), $this->GetFullCacheKey());
- $log->TimerStop('Render');
- $this->tpl->clearAllAssign();
- if ($this->projectList)
- $log->Log('MemoryCache', 'Count: ' . $this->projectList->GetMemoryCache()->GetCount());
- if ($log->GetEnabled()) {
- $this->tpl->assign('debuglog', $log);
- $this->tpl->display('debug.tpl');
- }
- }
- /**
- * Expires the cache
- *
- * @param boolean $expireAll expire the whole cache
- */
- public function CacheExpire($expireAll = false)
- {
- if ($expireAll) {
- $this->tpl->clearAllCache();
- return;
- }
- if (!$this->project)
- return;
- $epoch = $this->GetProject()->GetEpoch();
- if (empty($epoch))
- return;
- $age = $this->GetProject()->GetAge();
- $this->tpl->clearCache(null, $this->GetCacheKeyPrefix(), null, $age);
- $this->tpl->clearCache('projectlist.tpl', $this->GetCacheKeyPrefix(false), null, $age);
- }
- }
|