Location: PHPKode > projects > Kirby CMS > bastianallgeier-kirbycms-691bb66/kirby/lib/site.php
<?php

// direct access protection
if(!defined('KIRBY')) die('Direct access is not allowed');

class site extends obj {
  
  var $modified = false;
  var $cacheEnabled = false;
  var $dataCacheEnabled = false;
  var $htmlCacheEnabled = false;
    
  function __construct() {
              
    $this->urlSetup();                  
    $this->languageSetup();    
        
    // check if the cache is enabled at all
    $this->cacheEnabled = (c::get('cache') && (c::get('cache.html') || c::get('cache.data'))) ? true : false;

    if($this->cacheEnabled) {

      $this->dataCacheEnabled = c::get('cache.data');
      $this->htmlCacheEnabled = c::get('cache.html');    

      if(c::get('cache.autoupdate')) {
        $this->modified = dir::modified(c::get('root.content'));                
      } else {
        $this->modified = 0;
      }

    }

    $cacheID = $this->dataCacheID();
    $cacheModified = time();
    $cacheData = null;
        
    // data cache    
    if($this->dataCacheEnabled) {

      // find the latest modifed date from all content subdirs
      // if the cache is enabled and autoupdate is activated.
      // otherwise the last modified date will be false so the cache
      // will stay valid forever
      
      // check when the data cache has been modified
      $cacheModified = cache::modified($cacheID);

      // check if the cache is still valid
      if($cacheModified >= $this->modified) {
        $cacheData = cache::get($cacheID);
      } 
            
    }
                               
    if(empty($cacheData)) {

      // get the first set of pages
      $this->rootPages();
      // get the additional site info from content/site.txt
      $this->info();
            
      if($this->dataCacheEnabled) cache::set($cacheID, $this->_);
      
    } else {
      $this->_ = $cacheData;
    }
        
    // attach the uri after caching
    $this->uri = new uri();
                                                        
  }

  function __toString() {
    return '<a href="' . $this->url() . '">' . $this->url() . '</a>';
  }

  function load() {

    // initiate the site and make pages and page
    // globally available
    $pages = $this->pages;
    $page  = $this->pages->active();
    
    // check for ssl
    if(c::get('ssl')) {
      // if there's no https in the url
      if(!server::get('https')) go(str_replace('http://', 'https://', $page->url()));
    }

    // check for index.php in rewritten urls and rewrite them
    if(c::get('rewrite') && preg_match('!index.php\/!i', $this->uri->original)) {
      go($page->url());    
    }
        
    // check for a misconfigured subfolder install
    if($page->isErrorPage()) {
                  
      // if you want to store subfolders in the homefolder for blog articles i.e. and you
      // want urls like http://yourdomain.com/article-title you can set 
      // RedirectMatch 301 ^/home/(.*)$ /$1 in your htaccess file and those
      // next lines will take care of delivering the right pages. 
      $uri = c::get('home') . '/' . $this->uri->path();
        
      if($redirected = $this->pages()->find($uri)) {
        if($redirected->uri() == $uri) {
          $page = $redirected;
          $this->pages->active = $page;
          $this->uri = new uri($uri);
        }
      }
      
      // try to rewrite broken translated urls
      // this will only work for default uris
      if(c::get('lang.support')) {
        
        $path  = $this->uri->path->toArray();
        $obj   = $pages;
        $found = false;
    
        foreach($path as $p) {    
          
          // first try to find the page by uid
          $next = $obj->{'_' . $p};
                                        
          if(!$next) {
            
            // go through each translation for each child page 
            // and try to find the url_key or uid there
            foreach($obj as $child) {
              foreach(c::get('lang.available') as $lang) {
                $c = $child->content($lang);   
                // redirect to the url if a translated url has been found
                if($c && $c->url_key() == $p && !$child->isErrorPage()) $next = $child;
              }
            }

            if(!$next) break;
          }
    
          $found = $next;
          $obj   = $next->children();
        }
        
        if($found && !$found->isErrorPage()) go($found->url());
                
      }      
      
    }
    
    // redirect file urls (file:image.jpg)
    if($this->uri->param('file')) {
      // get the local file
      $file = $page->files()->find($this->uri->param('file'));
      if($file) go($file->url());
    }

    // redirect /home to /
    if($this->uri->path() == c::get('home')) go(url());
        
    // redirect tinyurls
    if($this->uri->path(1) == c::get('tinyurl.folder') && c::get('tinyurl.enabled')) {
      $hash = $this->uri->path(2);
      
      if(!empty($hash)) {
        $resolved = $this->pages->findByHash($hash)->first();
        // redirect to the original page
        if($resolved) go(url($resolved->uri));
      }  
      
    }
    
    // set the global template vars
    tpl::set('site',  $this);
    tpl::set('pages', $pages);
    tpl::set('page',  $page);

    $cacheID = $this->htmlCacheID();
    $cacheModified = time();
    $cacheData = null;
    
    if($this->htmlCacheEnabled) {
                        
      // check if the cache is disabled for some reason
      $this->htmlCacheEnabled = ($page->isErrorPage() || in_array($page->uri(), c::get('cache.ignore', array()))) ? false : true;
      
      // check for the last modified date of the cache file
      $cacheModified = cache::modified($cacheID);

      // check if the files have been modified
      // since the last html cache file has been written   
      if($this->htmlCacheEnabled && $cacheModified >= $this->modified) {
        $cacheData = cache::get($cacheID, true);
      } 

    }
    
    // send a 404 header if this is the error page
    if($page->isErrorPage()) header("HTTP/1.0 404 Not Found");
            
    if(empty($cacheData)) {
      // load the main template
      $html = tpl::load($page->template(), false, true);
      if($this->htmlCacheEnabled) cache::set($cacheID, (string)$html, true);
    } else {
      $html = $cacheData;
    }

    die($html);
    
  }
  
  function breadcrumb() {
    
    if($this->breadcrumb) return $this->breadcrumb;
  
    $uri   = $this->uri->path->toArray();	
    $crumb = array();
  
    foreach($uri AS $u) {
      $tmp  = implode('/', $uri);
      $data = $this->pages->find($tmp);
            
      if(!$data || $data->isErrorPage()) {
        // add the error page to the crumb
        $crumb[] = $this->pages->find(c::get('404'));
        // don't move on with subpages, because there won't be 
        // any if the first page hasn't been found at all
        break;
      } else {      
        $crumb[] = $data;
      }
      array_pop($uri);				
    }
    
    // we've been moving through the uri from tail to head
    // so we need to reverse the array to get a proper crumb    
    $crumb = array_reverse($crumb);		

    // add the homepage to the beginning of the crumb array
    array_unshift($crumb, $this->pages->find(c::get('home')));
    
    // make it a pages object so we can handle it
    // like we handle all pages on the site  
    return $this->breadcrumb = new pages($crumb);
  
  }

  function url($lang=false) {
    $url = c::get('url');
    return ($lang && c::get('lang.support') && in_array($lang, c::get('lang.available', array()))) ? url(false, $lang) : $url;
  }

  function serialize() {
    return serialize($this);
  }

  function rootPages() {
  
    // get the first level in the content root
    $ignore = array_merge(array('.svn', '.git', '.htaccess'), (array)c::get('content.file.ignore', array()));
    $files  = dir::inspect(c::get('root.content'), $ignore);
    $pages  = array();
    
    // build the first set of pages     
    foreach($files['children'] as $file) {

      $child = dir::inspect($files['root'] . '/' . $file, $ignore);
      $page  = page::fromDir($child, false);
      
      // add false as parent page object because we are on the first level
      $page->parent = false;
      
      $pages[$page->uid] = $page;

    }

    $this->pages = new pages($pages);
  
  }

  function info($lang=false) {
    
    // first run: fetch all the things we need    
    if(!$this->info) {              

      $root = c::get('root.content');

      if(c::get('lang.support')) {

        $defaultLang = c::get('lang.default');
        $currentLang = c::get('lang.current');
      
        foreach(c::get('lang.available') as $lang) {
          $file = $root . '/site.' . $lang . '.' . c::get('content.file.extension', 'txt');
          if(!file_exists($file)) continue;
  
          // fetch the site info from the defaulf file. 
          $fetched = variables::fetch($file);
          $data    = $fetched['data'];
          $data['filecontent'] = $fetched['raw'];
                  
          $this->_['info'][$lang] = $data;
          
        }
  
        // if there's no default language
        if(!isset($this->_['info'][$defaultLang])) {
          
          $file = $root . '/site.' . c::get('content.file.extension', 'txt');
  
          if(file_exists($file)) {
  
            // fetch the site info from the defaulf file. 
            $fetched = variables::fetch($file);
            $data    = $fetched['data'];
            $data['filecontent'] = $fetched['raw'];
                  
            $this->_['info'][$defaultLang] = $data;
          
          } else {
            $this->_['info'][$defaultLang] = array();
          }
          
        }
        
        foreach($this->_['info'] as $key => $value) {
          if($key == $defaultLang) continue;

          $merged = array_merge($this->_['info'][$defaultLang], $value);
          $this->_['info'][$key] = new siteinfo($merged);
        }
        
        // bake the default language stuff into an object finally
        $this->_['info'][$defaultLang] = new siteinfo($this->_['info'][$defaultLang]);        
        
        // get the current variables
        $current = (isset($this->_['info'][$currentLang])) ? $this->_['info'][$currentLang] : $this->_['info'][$defaultLang];
                                    
      } else {
  
        $file = $root . '/site.' . c::get('content.file.extension', 'txt');
  
        if(file_exists($file)) {
  
          // fetch the site info from the defaulf file. 
          $fetched = variables::fetch($file);
          $data    = $fetched['data'];
          $data['filecontent'] = $fetched['raw'];
                
          $this->_['info'] = new siteinfo($data);
        } else {
          $this->_['info'] = new siteinfo(array());
        }
        
        $current = $this->_['info'];
        
      }
      
      // add all variables        
      $vars = $current->_;
      
      // don't add the filecontent var, 
      // because this is not a custom var
      unset($vars['filecontent']);

      $this->variables = $vars;

      // merge the current site info with the additional
      // info from the info file(s)    
      $this->_ = array_merge($this->_, $current->_);  

    }

    // now get the stuff the user wants
    if(c::get('lang.support')) {
      
      $currentLang = c::get('lang.current');
      $defaultLang = c::get('lang.default');
      
      if($lang && in_array($lang, c::get('lang.available'))) {
        return (isset($this->info[$lang])) ? $this->info[$lang] : $this->info[$defaultLang];
      }
      
      return (isset($this->info[$currentLang])) ? $this->info[$currentLang] : $this->info[$defaultLang];

    } else {
      return $this->info;
    }
        
  }
  
  function modified() {
    return ($this->modified) ? $this->modified : time();
  }

  function dataCacheID() {
    return (c::get('lang.support')) ? 'site.' . c::get('lang.current') . '.php' : 'site.php';  
  }
  
  function htmlCacheID() {
    return (c::get('lang.support')) ? $this->uri->toCacheID() . '.' . c::get('lang.current') . '.php' : $this->uri->toCacheID() . '.php';  
  }

  function languageSetup() {

    // check for activated language support
    if(!c::get('lang.support')) return false;

    // get the available languages
    $available = c::get('lang.available');

    // sanitize the available languages
    if(!is_array($available)) {
      
      // switch off language support      
      c::set('lang.support', false);
      return false;      
            
    }

    // get the raw uri
    $uri = uri::raw();
       
    // get the current language code      
    $code = a::first(explode('/', $uri));

    // try to detect the language code if the code is empty
    if(empty($code)) {
      
      if(c::get('lang.detect')) {      
        // detect the current language
        $detected = str::split(server::get('http_accept_language'), '-');
        $detected = str::trim(a::first($detected));
        $detected = (!in_array($detected, $available)) ? c::get('lang.default') : $detected;

        // set the detected code as current code          
        $code = $detected;

      } else {
        $code = c::get('lang.default');
      }
      
      // go to the default homepage      
      go(url(false, $code));
          
    }
    
    // http://yourdomain.com/error
    // will redirect to http://yourdomain.com/en/error
    if($code == c::get('404')) go(url('error', c::get('lang.default')));
            
    // validate the code and switch back to the homepage if it is invalid
    if(!in_array($code, c::get('lang.available'))) go(url());

    // set the current language
    c::set('lang.current', $code);
    
    // mark if this is a translated version or the default version
    ($code != c::get('lang.default')) ? c::set('lang.translated', true) : c::set('lang.translated', false);
    
    // load the additional language files if available
    load::language();  

  }

  function urlSetup() {

    // auto-detect the url if it is not set
    $url = (c::get('url') === false) ? c::get('scheme') . server::get('http_host') : rtrim(c::get('url'), '/');
      
    // try to detect the subfolder      
    $subfolder = (c::get('subfolder')) ? trim(c::get('subfolder'), '/') : trim(dirname($_SERVER['SCRIPT_NAME']), '/\\');

    if($subfolder) {
      c::set('subfolder', $subfolder);
      
      // check if the url already contains the subfolder      
      // so it's not included twice
      if(!preg_match('!' . preg_quote($subfolder) . '$!i', $url)) $url .= '/' . $subfolder;
    }
            
    // set the final url
    c::set('url', $url);  

  }

  function hasPlugin($plugin) {
    return (file_exists(c::get('root.plugins') . '/' . $plugin . '.php') || file_exists(c::get('root.plugins') . '/' . $plugin . '/' . $plugin . '.php')) ? true : false;  
  }
         
}

class siteinfo extends obj {
  
  function __toString() {
    return $this->filecontent;
  }
  
}
Return current item: Kirby CMS