Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 27fdf0695f60e5f3fe495bb8ae2e24bdf6a62ead @DorianGray DorianGray committed Dec 21, 2011
Showing with 2,796 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +14 −0 README.markdown
  3. +56 −0 core/Classes/SessionHandler.class.php
  4. +32 −0 core/Classes/Singleton.class.php
  5. +32 −0 core/Common/Common.inc.php
  6. +147 −0 core/Common/functions.inc.php
  7. +13 −0 core/Config/Context.config.php
  8. +14 −0 core/Config/Core.config.php
  9. +79 −0 core/Config/Database.config.php
  10. +9 −0 core/Config/Log.config.php
  11. +105 −0 core/Context.class.php
  12. +131 −0 core/Controllers/Users.class.php
  13. +30 −0 core/Database/Collections/Collection.class.php
  14. +15 −0 core/Database/Collections/LogInterface.class.php
  15. +17 −0 core/Database/Collections/ModelInterface.class.php
  16. +126 −0 core/Database/Collections/MongoDB/Collection.class.php
  17. +33 −0 core/Database/Collections/MongoDB/LogCollection.class.php
  18. +52 −0 core/Database/Collections/MongoDB/SessionCollection.class.php
  19. +18 −0 core/Database/Collections/MongoDB/StatisticCollection.class.php
  20. +93 −0 core/Database/Collections/MongoDB/UserCollection.class.php
  21. +15 −0 core/Database/Collections/SessionInterface.class.php
  22. +15 −0 core/Database/Collections/StatisticInterface.class.php
  23. +17 −0 core/Database/Collections/UserInterface.class.php
  24. +42 −0 core/Database/Controller.class.php
  25. +23 −0 core/Database/Settings.class.php
  26. +195 −0 core/Log.class.php
  27. +5 −0 core/Mint.php
  28. +19 −0 core/Models/Model.class.php
  29. +19 −0 core/Models/Profile.class.php
  30. +26 −0 core/Models/Search.class.php
  31. +24 −0 core/Models/Session.class.php
  32. +37 −0 core/Models/User.class.php
  33. +59 −0 core/Router/AuthenticationHandler.class.php
  34. +98 −0 core/Router/Controller.class.php
  35. +65 −0 core/Router/Handler.class.php
  36. +28 −0 core/Router/SecureHandler.class.php
  37. +162 −0 core/Templates/Controller.class.php
  38. +889 −0 core/Templates/Mustache.class.php
  39. +20 −0 web/core-custom/Database/Collections/ItemInterface.class.php
  40. +18 −0 web/core-custom/Database/Collections/SearchInterface.class.php
4 .gitignore
@@ -0,0 +1,4 @@
+*.swp
+*.swo
+*.swn
+.DS_Store
14 README.markdown
@@ -0,0 +1,14 @@
+Mint
+====
+
+A superclean, superefficient PHP MVC framework that helps you build an API
+while you build your application.
+
+Documentation coming soon.
+
+License
+-------
+
+[MIT licensed](http://www.opensource.org/licenses/mit-license.php).
+
+Copyright 2011 Olivine Labs, LLC.
56 core/Classes/SessionHandler.class.php
@@ -0,0 +1,56 @@
+<?php
+/*---------------------------------------------------------------------------
+ SessionHandler 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Classes
+ Class : SessionHandler
+ - Static
+ - Abstracts session handling
+---------------------------------------------------------------------------*/
+namespace Classes;
+
+class SessionHandler
+{
+ private static $_session = null;
+
+ public static function Open($savePath, $sessionName)
+ {
+ return true;
+ }
+
+ public static function Close()
+ {
+ return true;
+ }
+
+ public static function Read($sessionId)
+ {
+ $aSession = new \Models\Session();
+ $aSession->SessionId = $sessionId;
+ \Database\Controller::getInstance()->Sessions->LoadBySessionId($aSession);
+ self::$_session = $aSession;
+ return self::$_session->Data;
+ }
+
+ public static function Write($sessionId, $data)
+ {
+ return \Database\Controller::getInstance()->Sessions->Save(self::$_session);
+ }
+
+ public static function Destroy($sessionId)
+ {
+ return \Database\Controller::getInstance()->Sessions->Remove(self::$_session);
+ }
+
+ public static function GC($maxLifeTime)
+ {
+ \Database\Controller::getInstance()->Sessions->Cleanup();
+ return true;
+ }
+
+ public static function getSession()
+ {
+ return self::$_session;
+ }
+}
+?>
32 core/Classes/Singleton.class.php
@@ -0,0 +1,32 @@
+<?php
+/*---------------------------------------------------------------------------
+ Singleton 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Classes
+ Class : Singleton
+ - Class
+---------------------------------------------------------------------------*/
+namespace Classes;
+
+abstract class Singleton
+{
+ protected static $_instance = array();
+
+ protected function __construct() { }
+
+ final private function __clone() { }
+
+ final public static function getInstance()
+ {
+ $class = get_called_class();
+ if(!array_key_exists($class, static::$_instance))
+ {
+ static::$_instance[$class] = new static();
+ static::$_instance[$class]->__init();
+ }
+ return static::$_instance[$class];
+ }
+
+ protected function __init(){}
+}
+?>
32 core/Common/Common.inc.php
@@ -0,0 +1,32 @@
+<?php
+ob_start();
+include './Config/Core.config.php';
+include './Common/functions.inc.php';
+
+spl_autoload_register('\Common\LoadClass');
+
+date_default_timezone_set($Timezone);
+
+set_exception_handler('\Log::ExceptionHandler');
+set_error_handler('\Log::ErrorHandler');
+
+session_set_save_handler(
+ array("\Classes\SessionHandler", "Open"),
+ array("\Classes\SessionHandler", "Close"),
+ array("\Classes\SessionHandler", "Read"),
+ array("\Classes\SessionHandler", "Write"),
+ array("\Classes\SessionHandler", "Destroy"),
+ array("\Classes\SessionHandler", "GC")
+);
+
+session_name($SessionName);
+session_start();
+
+register_shutdown_function(
+ '\Common\Shutdown',
+ new \Templates\Mustache(),
+ new \Templates\Controller(),
+ \Context::getInstance(),
+ new \Log()
+);
+?>
147 core/Common/functions.inc.php
@@ -0,0 +1,147 @@
+<?php
+namespace Common;
+
+function LoadClass($className)
+{
+ $pieces = explode("\\", $className);
+ $fileName = '';
+ foreach($pieces AS $piece)
+ $fileName .= $piece.'/';
+ $fileName[strlen($fileName)-1] = '.';
+ $fileName .= 'class.php';
+ if(file_exists(NAMESPACE_CUSTOM.$fileName))
+ $fileName = NAMESPACE_CUSTOM.$fileName;
+ else if(file_exists(MINT_ROOT.$fileName))
+ $fileName = MINT_ROOT.$fileName;
+ else
+ throw new \Exception('Class "'.$className.'" cannot be loaded. File not found.');
+ include($fileName);
+}
+
+function hash($string)
+{
+ return \hash('sha512', $string);
+}
+
+function Shutdown($renderer, $template, $context, $log)
+{
+ try
+ {
+ if($error = error_get_last())
+ $log::ErrorHandler($error['type'], $error['message'], $error['file'], $error['line'], array());
+
+ //Fill and output template with data
+ $template::Output($renderer, $context);
+ }
+ catch(\Exception $e)
+ {
+ $log::ExceptionHandler($e, $context);
+ $template::Output($renderer, $context);
+ }
+ ob_end_flush();
+}
+
+function UriToArray(&$Uri)
+{
+ $pathArray = explode('/', $Uri);
+ array_shift($pathArray);
+ if(!end($pathArray))
+ array_pop($pathArray);
+ return $pathArray;
+}
+
+function GetLastPhrase(&$Uri)
+{
+ $pathArray = explode('/', $Uri);
+ $tempArray = explode('?', $pathArray[count($pathArray)-1]);
+ $pathArray[count($pathArray)-1] = $tempArray[0];
+
+ return end($pathArray);
+}
+
+function GetSubDomain()
+{
+ $array = explode('.', preg_replace('/^(?:([^\.]+)\.)?domain\.com$/', '\1', $_SERVER['SERVER_NAME']));
+ array_pop($array);
+ return implode('.', $array);
+}
+
+/**
+ * UrlLinker - facilitates turning plaintext URLs into HTML links.
+ *
+ * Author: Søren Løvborg
+ *
+ * To the extent possible under law, Søren Løvborg has waived all copyright
+ * and related or neighboring rights to UrlLinker.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/**
+ * Transforms plain text into valid HTML, escaping special characters and
+ * turning URLs into links.
+ */
+function htmlEscapeAndLinkUrls($text)
+{
+ /*
+ * Regular expression bits used by htmlEscapeAndLinkUrls() to match URLs.
+ */
+
+ $rexProtocol = '(https?://)?';
+ $rexDomain = '((?:[-a-zA-Z0-9]{1,63}\.)+[-a-zA-Z0-9]{2,63}|(?:[0-9]{1,3}\.){3}[0-9]{1,3})';
+ $rexPort = '(:[0-9]{1,5})?';
+ $rexPath = '(/[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]*?)?';
+ $rexQuery = '(\?[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?';
+ $rexFragment = '(#[!$-/0-9:;=@_\':;!a-zA-Z\x7f-\xff]+?)?';
+ $rexUrlLinker = "{\\b$rexProtocol$rexDomain$rexPort$rexPath$rexQuery$rexFragment(?=[?.!,;:\"]?(\s|$))}";
+
+ /**
+ * $validTlds is an associative array mapping valid TLDs to the value true.
+ * Since the set of valid TLDs is not static, this array should be updated
+ * from time to time.
+ *
+ * List source: http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+ * Last updated: 2010-09-04
+ */
+ $validTlds = array_fill_keys(explode(" ", ".ac .ad .ae .aero .af .ag .ai .al .am .an .ao .aq .ar .arpa .as .asia .at .au .aw .ax .az .ba .bb .bd .be .bf .bg .bh .bi .biz .bj .bm .bn .bo .br .bs .bt .bv .bw .by .bz .ca .cat .cc .cd .cf .cg .ch .ci .ck .cl .cm .cn .co .com .coop .cr .cu .cv .cx .cy .cz .de .dj .dk .dm .do .dz .ec .edu .ee .eg .er .es .et .eu .fi .fj .fk .fm .fo .fr .ga .gb .gd .ge .gf .gg .gh .gi .gl .gm .gn .gov .gp .gq .gr .gs .gt .gu .gw .gy .hk .hm .hn .hr .ht .hu .id .ie .il .im .in .info .int .io .iq .ir .is .it .je .jm .jo .jobs .jp .ke .kg .kh .ki .km .kn .kp .kr .kw .ky .kz .la .lb .lc .li .lk .lr .ls .lt .lu .lv .ly .ma .mc .md .me .mg .mh .mil .mk .ml .mm .mn .mo .mobi .mp .mq .mr .ms .mt .mu .museum .mv .mw .mx .my .mz .na .name .nc .ne .net .nf .ng .ni .nl .no .np .nr .nu .nz .om .org .pa .pe .pf .pg .ph .pk .pl .pm .pn .pr .pro .ps .pt .pw .py .qa .re .ro .rs .ru .rw .sa .sb .sc .sd .se .sg .sh .si .sj .sk .sl .sm .sn .so .sr .st .su .sv .sy .sz .tc .td .tel .tf .tg .th .tj .tk .tl .tm .tn .to .tp .tr .travel .tt .tv .tw .tz .ua .ug .uk .us .uy .uz .va .vc .ve .vg .vi .vn .vu .wf .ws .xn--0zwm56d .xn--11b5bs3a9aj6g .xn--80akhbyknj4f .xn--9t4b11yi5a .xn--deba0ad .xn--fiqs8s .xn--fiqz9s .xn--fzc2c9e2c .xn--g6w251d .xn--hgbk6aj7f53bba .xn--hlcj6aya9esc7a .xn--j6w193g .xn--jxalpdlp .xn--kgbechtv .xn--kprw13d .xn--kpry57d .xn--mgbaam7a8h .xn--mgbayh7gpa .xn--mgberp4a5d4ar .xn--o3cw4h .xn--p1ai .xn--pgbs0dh .xn--wgbh1c .xn--xkc2al3hye2a .xn--ygbi2ammx .xn--zckzah .ye .yt .za .zm .zw"), true);
+
+ $result = "";
+
+ $position = 0;
+ while (preg_match($rexUrlLinker, $text, $match, PREG_OFFSET_CAPTURE, $position))
+ {
+ list($url, $urlPosition) = $match[0];
+
+ // Add the text leading up to the URL.
+ $result .= htmlspecialchars(substr($text, $position, $urlPosition - $position));
+
+ $domain = $match[2][0];
+ $port = $match[3][0];
+ $path = $match[4][0];
+
+ // Check that the TLD is valid or that $domain is an IP address.
+ $tld = strtolower(strrchr($domain, '.'));
+ if (preg_match('{^\.[0-9]{1,3}$}', $tld) || isset($validTlds[$tld]))
+ {
+ // Prepend http:// if no protocol specified
+ $completeUrl = $match[1][0] ? $url : "http://$url";
+
+ // Add the hyperlink.
+ $result .= '<a href="' . htmlspecialchars($completeUrl) . '" rel="nofollow" target="_blank">'
+ . htmlspecialchars("$domain$port$path")
+ . '</a>';
+ }
+ else
+ {
+ // Not a valid URL.
+ $result .= htmlspecialchars($url);
+ }
+
+ // Continue text parsing from after the URL.
+ $position = $urlPosition + strlen($url);
+ }
+
+ // Add the remainder of the text.
+ $result .= htmlspecialchars(substr($text, $position));
+ return $result;
+}
+?>
13 core/Config/Context.config.php
@@ -0,0 +1,13 @@
+<?php
+$this->Session = \Classes\SessionHandler::getSession();
+$this->CurrentUser = (object)((array_key_exists(\Models\Session::FIELD_USER, ($this->Session)?$this->Session->Data:array()))?(object)$this->Session->Data[\Models\Session::FIELD_USER]:new \Models\User());
+$this->CurrentUser->Profile = (object)$this->CurrentUser->Profile;
+$this->CurrentUser->LoggedIn = ($this->CurrentUser->UserName)?true:false;
+$this->CWD = getcwd();
+
+$this->Debug = false;
+if(file_exists('../../config/Context.config.php'))
+{
+ include('../../config/Context.config.php');
+}
+?>
14 core/Config/Core.config.php
@@ -0,0 +1,14 @@
+<?php
+define('MINT_ROOT', getcwd().'/');
+define('AKISMET_API_KEY', '4b66e21dd53c');
+define('NAMESPACE_CUSTOM', MINT_ROOT.'../../core-custom/');
+define('HANDLER_DIR', MINT_ROOT.'../../handlers/');
+define('VIEW_DIR', MINT_ROOT.'../../views/');
+define('CONFIG_DIR', MINT_ROOT.'../config/');
+$SessionName = 'mint';
+$Timezone = 'America/New_York';
+if(file_exists('../../config/Core.config.php'))
+{
+ include('../../config/Core.config.php');
+}
+?>
79 core/Config/Database.config.php
@@ -0,0 +1,79 @@
+<?php
+//Session Settings
+$Settings = new \Database\Settings();
+$Settings->Name = 'Sessions';
+$Settings->Driver = 'MongoDB';
+$Settings->Host = 'localhost';
+$Settings->Port = 27017;
+$Settings->User = 'Mint';
+$Settings->Password = 'Impervious*1';
+$Settings->Database = 'Mint';
+$Settings->Collection = 'Sessions';
+$Settings->ClassName = '\Database\Collections\MongoDB\SessionCollection';
+$this->addCollection($Settings);
+
+//User Settings
+$Settings = new \Database\Settings();
+$Settings->Name = 'Users';
+$Settings->Driver = 'MongoDB';
+$Settings->Host = 'localhost';
+$Settings->Port = 27017;
+$Settings->User = 'Mint';
+$Settings->Password = 'Impervious*1';
+$Settings->Database = 'Mint';
+$Settings->Collection = 'Users';
+$Settings->ClassName = '\Database\Collections\MongoDB\UserCollection';
+$this->addCollection($Settings);
+
+//Quotes Settings
+$Settings = new \Database\Settings();
+$Settings->Name = 'Quotes';
+$Settings->Driver = 'MongoDB';
+$Settings->Host = 'localhost';
+$Settings->Port = 27017;
+$Settings->User = 'Mint';
+$Settings->Password = 'Impervious*1';
+$Settings->Database = 'Mint';
+$Settings->Collection = 'Quotes';
+$Settings->ClassName = '\Database\Collections\MongoDB\QuoteCollection';
+$this->addCollection($Settings);
+
+//Domain Settings
+$Settings = new \Database\Settings();
+$Settings->Name = 'Domains';
+$Settings->Driver = 'MongoDB';
+$Settings->Host = 'localhost';
+$Settings->Port = 27017;
+$Settings->User = 'Mint';
+$Settings->Password = 'Impervious*1';
+$Settings->Database = 'Mint';
+$Settings->Collection = 'Domains';
+$Settings->ClassName = '\Database\Collections\MongoDB\DomainCollection';
+$this->addCollection($Settings);
+
+//Statistic Settings
+$Settings = new \Database\Settings();
+$Settings->Name = 'Statistics';
+$Settings->Driver = 'MongoDB';
+$Settings->Host = 'localhost';
+$Settings->Port = 27017;
+$Settings->User = 'Mint';
+$Settings->Password = 'Impervious*1';
+$Settings->Database = 'Mint';
+$Settings->Collection = 'Statistics';
+$Settings->ClassName = '\Database\Collections\MongoDB\StatisticCollection';
+$this->addCollection($Settings);
+
+//Log Settings
+$Settings = new \Database\Settings();
+$Settings->Name = 'Logs';
+$Settings->Driver = 'MongoDB';
+$Settings->Host = 'localhost';
+$Settings->Port = 27017;
+$Settings->User = 'Mint';
+$Settings->Password = 'Impervious*1';
+$Settings->Database = 'Mint';
+$Settings->Collection = 'Logs';
+$Settings->ClassName = '\Database\Collections\MongoDB\LogCollection';
+$this->addCollection($Settings);
+?>
9 core/Config/Log.config.php
@@ -0,0 +1,9 @@
+<?php
+$DatabaseEnabled = true;
+$FileEnabled = true;
+$TemplateEnabled = true;
+
+$TemplateFile = 'errors/500';
+$Verbose = true;
+$LogFile = './log.txt';
+?>
105 core/Context.class.php
@@ -0,0 +1,105 @@
+<?php
+/*---------------------------------------------------------------------------
+ Context 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : /
+ Class : Context
+---------------------------------------------------------------------------*/
+
+final class Context extends \Classes\Singleton
+ {
+ private $_data = array();
+ private $_value = '';
+
+ protected function __construct($value = '')
+ {
+ $this->_value = $value;
+ }
+
+ protected function __init()
+ {
+ include './Config/Context.config.php';
+ }
+
+ public function HasChildren()
+ {
+ foreach($this->_data as $item)
+ if($this->isChild($item))
+ return true;
+ return false;
+ }
+
+ protected function isChild($var)
+ {
+ if(is_object($var))
+ if(get_class($var) === __CLASS__)
+ return true;
+ return false;
+ }
+
+ public final function __set($index, $value)
+ {
+ switch(gettype($value))
+ {
+ case 'array':
+ case 'object':
+ $this->_data[$index] = $value;
+ break;
+ default:
+ $this->_data[$index] = new Context($value);
+ break;
+ }
+ }
+
+ public final function __get($index)
+ {
+ if(array_key_exists($index, $this->_data))
+ {
+ if($this->isChild($this->_data[$index]))
+ {
+ if(!$this->_data[$index]->HasChildren())
+ {
+ return $this->_data[$index]->_value;
+ }
+ }
+ return $this->_data[$index];
+ }
+ return $this->_data[$index] = new Context();
+ }
+
+ public final function __toString()
+ {
+ return $this->_value;
+ }
+
+ public final function ToObject($object = null)
+ {
+ if($object === null)
+ $object = new StdClass();
+
+ if($this->_value !== '')
+ {
+ $object = $this->_value;
+ }
+ else
+ {
+ foreach($this->_data AS $key=>&$value)
+ {
+ if($this->isChild($value))
+ {
+ $object->{$key} = new StdClass();
+ $object->{$key} = $value->ToObject($object->{$key});
+ if(!(array)$object->{$key})
+ unset($object->{$key});
+
+ }
+ else
+ {
+ $object->{$key} = $value;
+ }
+ }
+ }
+ return $object;
+ }
+ }
+?>
131 core/Controllers/Users.class.php
@@ -0,0 +1,131 @@
+<?php
+/*---------------------------------------------------------------------------
+ Users 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Controllers
+ Class : Users
+---------------------------------------------------------------------------*/
+namespace Controllers;
+
+class Users
+{
+ public static function Login(\Models\User &$user)
+ {
+ $aUser = new \Models\User();
+ $aUser->Email = strtolower($user->Email);
+ $aUser->Domain = \Common\GetSubDomain();
+ $aDatabase = \Database\Controller::getInstance();
+ if($aDatabase->Users->LoadByEmail($aUser))
+ {
+ $aSession = \Classes\SessionHandler::getSession();
+ if(\Common\hash($user->Password) == $aUser->Password)
+ {
+ $aUser->Password = null;
+ $user = $aUser;
+ $aSession->Data[\Models\Session::FIELD_USER] = (array)$aUser;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static function Logout()
+ {
+ $aSession = \Classes\SessionHandler::getSession();
+
+ if(array_key_exists(\Models\Session::FIELD_USER, $aSession->Data))
+ unset($aSession->Data[\Models\Session::FIELD_USER]);
+
+ return true;
+ }
+
+ public static function Register($user, $login = true)
+ {
+ $aDatabase = \Database\Controller::getInstance();
+ $user->Domain = \Common\GetSubDomain();
+ $user->Email = strtolower($user->Email);
+ $Password = $user->Password;
+ $user->Password = \Common\hash($user->Password);
+ $user->Token = uniqid('', true);
+ if($aDatabase->Users->Save($user))
+ {
+ if($login)
+ {
+ $user->Password = $Password;
+ $aSession = \Classes\SessionHandler::getSession();
+ self::Login($user);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public static function View(\Models\User $user)
+ {
+ $aDatabase = \Database\Controller::getInstance();
+ $user->Domain = \Common\GetSubDomain();
+
+ if($user->UserName){
+ if($aDatabase->Users->LoadByName($user))
+ {
+ return $user;
+ }
+ }else if($user->Email){
+ if($aDatabase->Users->LoadByEmail($user))
+ {
+ return $user;
+ }
+ }else if($user->Id){
+ if($aDatabase->Users->Load($user))
+ {
+ return $user;
+ }
+ }
+
+ return false;
+ }
+
+ public static function Edit(\Models\User $user)
+ {
+ $tempUser = new \Models\User();
+ $tempUser->Id = $user->Id;
+
+ $session = \Classes\SessionHandler::getSession();
+
+ if(array_key_exists(\Models\Session::FIELD_USER, $session->Data))
+ {
+ $database = \Database\Controller::getInstance();
+
+ if($database->Users->Load($tempUser))
+ {
+ $tempUser->Email = $user->Email;
+ $tempUser->Password = \Common\hash($user->Password);
+
+ if($database->Users->Save($tempUser)){
+ $session->Data[\Models\Session::FIELD_USER] = (array)$tempUser;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static function GetByToken($token)
+ {
+ $aDatabase = \Database\Controller::getInstance();
+
+ if($token)
+ {
+ $user = new \Models\User();
+ $user->Token = $token;
+ if($aDatabase->Users->LoadByToken($user))
+ {
+ return $user;
+ }
+ }
+ return null;
+ }
+}
+?>
30 core/Database/Collections/Collection.class.php
@@ -0,0 +1,30 @@
+<?php
+/*---------------------------------------------------------------------------
+ Collection 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections
+ Class : Collection
+ - Abstract class
+---------------------------------------------------------------------------*/
+namespace Database\Collections;
+
+abstract class Collection
+{
+ protected static $Type = null;
+ protected $Connection = null;
+ protected $Settings = null;
+ public $Connected = false;
+
+ public function __construct(\Database\Settings $settings)
+ {
+ $this->Settings = $settings;
+ $this->connect();
+ }
+
+ abstract protected function connect();
+
+ abstract public function transaction();
+ abstract public function commit();
+ abstract public function rollBack();
+}
+?>
15 core/Database/Collections/LogInterface.class.php
@@ -0,0 +1,15 @@
+<?php
+/*---------------------------------------------------------------------------
+ LogInterface 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections
+ Class : LogInterface
+ - Interface to LogCollection methods
+---------------------------------------------------------------------------*/
+namespace Database\Collections;
+
+interface LogInterface extends ModelInterface
+{
+ public function Add($subject, $message, $severity, $stackTrace);
+}
+?>
17 core/Database/Collections/ModelInterface.class.php
@@ -0,0 +1,17 @@
+<?php
+/*---------------------------------------------------------------------------
+ UserInterface 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections
+ Class : UserInterface
+ - Interface to UserCollection methods
+---------------------------------------------------------------------------*/
+namespace Database\Collections;
+
+interface ModelInterface
+{
+ public function Load(\Models\Model $model);
+ public function Save(\Models\Model $model);
+ public function Remove(\Models\Model $model);
+}
+?>
126 core/Database/Collections/MongoDB/Collection.class.php
@@ -0,0 +1,126 @@
+<?php
+/*---------------------------------------------------------------------------
+ Collection 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections\MongoDB
+ Class : Collection
+ - Abstract class
+---------------------------------------------------------------------------*/
+namespace Database\Collections\MongoDB;
+
+abstract class Collection extends \Database\Collections\Collection
+{
+ const FIELD_ID = '_id';
+
+ protected $Collection = null;
+
+ protected function connect()
+ {
+ try
+ {
+ if(class_exists('\\Mongo', false))
+ {
+ $this->Connection = new \Mongo(
+ 'mongodb://'.$this->Settings->User.':'.$this->Settings->Password.'@'.$this->Settings->Host.':'.$this->Settings->Port.'/'.$this->Settings->Database,
+ //'mongodb://'.$this->Settings->Host.':'.$this->Settings->Port.'/'.$this->Settings->Database,
+ array("persist" => "x")
+ );
+ $this->Connected = $this->Connection->connect();
+ $this->Collection = $this->Connection->selectCollection($this->Settings->Database, $this->Settings->Collection);
+ }
+ else
+ {
+ \Log::Message('SERVER', 'MongoDB Driver not installed', \Log::$Severity['FATAL'], debug_backtrace(), false, true);
+ }
+ }
+ catch(\Exception $e)
+ {
+ \Log::Message('DATABASE', 'Failed to connect to database.', \Log::$Severity['FATAL'], $e->getTrace(), false, true);
+ }
+ }
+
+ protected function fill(\Models\Model $model, $array)
+ {
+ foreach($array AS $property=>$value)
+ {
+ if($property === self::FIELD_ID)
+ {
+ $property = 'Id';
+ }
+ else if(is_object($value))
+ {
+ $class = get_class($value);
+ switch($class)
+ {
+ case 'MongoDate':
+ $value = $value->sec;
+ break;
+ }
+ }
+ $model->$property = $value;
+ }
+ }
+
+ protected function toArray(\Models\Model $model)
+ {
+ $result = array();
+ foreach($model AS $property=>$value)
+ {
+ $result[$property] = $value;
+ }
+
+ if(array_key_exists('Id', $result))
+ {
+ $id = $result['Id'];
+ $id = new \MongoId($id);
+ $result[self::FIELD_ID] = $id;
+ unset($result['Id']);
+ }
+ return $result;
+ }
+
+ public function Load(\Models\Model $model)
+ {
+ $id = $model->Id;
+ $id = new \MongoId($id);
+ $data = $this->Collection->findOne(array(self::FIELD_ID => $id));
+ if($data)
+ {
+ $this->fill($model, $data);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function Save(\Models\Model $model, $returnId = true)
+ {
+ try
+ {
+ $array = $this->toArray($model);
+ $this->Collection->save($array);
+ if($returnId)
+ $model->Id = $array[self::FIELD_ID];
+ }
+ catch(\Exception $e)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ public function Remove(\Models\Model $model)
+ {
+ $id = $model->Id;
+ $id = new \MongoId($id);
+ $data = $this->Collection->remove(array(self::FIELD_ID => $id));
+ return true;
+ }
+
+ final public function transaction(){ return true;/* Not supported */}
+ final public function commit(){ return true;/* Not supported */}
+ final public function rollBack(){ return true;/* Not supported */}
+}
+?>
33 core/Database/Collections/MongoDB/LogCollection.class.php
@@ -0,0 +1,33 @@
+<?php
+/*---------------------------------------------------------------------------
+ LogCollection 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections\MongoDB
+ Class : LogCollection
+ - Class containing methods to access logs in MongoDB
+---------------------------------------------------------------------------*/
+namespace Database\Collections\MongoDB;
+
+class LogCollection extends Collection implements \Database\Collections\LogInterface
+{
+ const FIELD_SUBJECT = 'Subject';
+ const FIELD_MESSAGE = 'Message';
+ const FIELD_SEVERITY = 'Severity';
+ const FIELD_STACKTRACE = 'StackTrace';
+ const FIELD_TIMESTAMP = 'TimeStamp';
+
+ public function Add($subject, $message, $severity, $stackTrace)
+ {
+ $timestamp = time();
+ $array = array(
+ self::FIELD_SUBJECT => $subject,
+ self::FIELD_MESSAGE => $message,
+ self::FIELD_SEVERITY => $severity,
+ self::FIELD_STACKTRACE=> $stackTrace,
+ self::FIELD_TIMESTAMP => new \MongoDate($timestamp)
+ );
+
+ return $this->Collection->save($array);
+ }
+}
+?>
52 core/Database/Collections/MongoDB/SessionCollection.class.php
@@ -0,0 +1,52 @@
+<?php
+/*---------------------------------------------------------------------------
+ SessionCollection 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections\MongoDB
+ Class : SessionCollection
+ - Class containing methods to access Sessions in MongoDB
+---------------------------------------------------------------------------*/
+namespace Database\Collections\MongoDB;
+
+class SessionCollection extends Collection implements \Database\Collections\SessionInterface
+{
+ const FIELD_DATA = 'Data';
+ const FIELD_LASTACCESS = 'LastAccess';
+ const FIELD_SESSIONID = 'SessionId';
+
+ protected function toArray(\Models\Model $model)
+ {
+ $result = parent::toArray($model);
+ $result[self::FIELD_LASTACCESS] = (array_key_exists(self::FIELD_LASTACCESS, $result))?new \MongoDate($result[self::FIELD_LASTACCESS]):new \MongoDate();
+ return $result;
+ }
+
+ public function LoadBySessionId(\Models\Model $model)
+ {
+ $id = $model->SessionId;
+ $data = $this->Collection->findOne(array(self::FIELD_SESSIONID => $id));
+ if($data)
+ {
+ $this->fill($model, $data);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function Cleanup($time)
+ {
+ try
+ {
+ $searchArray = array(self::FIELD_LASTACCESS =>array('$lte', new \MongoDate($time)));
+ $data = $this->Collection->remove($searchArray);
+ return true;
+ }
+ catch(\Exception $e)
+ {}
+ return false;
+ }
+}
+?>
18 core/Database/Collections/MongoDB/StatisticCollection.class.php
@@ -0,0 +1,18 @@
+<?php
+/*---------------------------------------------------------------------------
+ StatisticCollection 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections\MongoDB
+ Class : StatisticCollection
+ - Class containing methods to access statistics in MongoDB
+---------------------------------------------------------------------------*/
+namespace Database\Collections\MongoDB;
+
+class StatisticCollection extends Collection implements \Database\Collections\StatisticInterface
+{
+ public function Load($id)
+ {
+ return $this->Collection->findOne(array('_id' => new \MongoId($id)));
+ }
+}
+?>
93 core/Database/Collections/MongoDB/UserCollection.class.php
@@ -0,0 +1,93 @@
+<?php
+/*---------------------------------------------------------------------------
+ UserCollection 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections\MongoDB
+ Class : UserCollection
+ - Class containing methods to access users in MongoDB
+---------------------------------------------------------------------------*/
+namespace Database\Collections\MongoDB;
+
+class UserCollection extends Collection implements \Database\Collections\UserInterface
+{
+ const FIELD_NAME = 'UserName';
+ const FIELD_PASSWORD = 'Password';
+ const FIELD_EMAIL = 'Email';
+ const FIELD_DOMAIN = 'Domain';
+ const FIELD_PROFILE = 'Profile';
+ const FIELD_SCORE = 'Score';
+ const FIELD_TOKEN = 'Token';
+
+ protected function fill(\Models\Model $model, $array)
+ {
+ parent::fill($model, $array);
+ $user = $model;
+ $user->Profile = ($user->Profile)?(object)$user->Profile:new \Models\Profile();
+ }
+
+ public function LoadByName(\Models\User $user)
+ {
+ $data = $this->Collection->findOne(array(
+ self::FIELD_NAME => $user->UserName
+ ));
+ if($data)
+ {
+ self::fill($user, $data);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function LoadByEmail(\Models\User $user)
+ {
+ $data = $this->Collection->findOne(array(
+ self::FIELD_EMAIL => $user->Email
+ ));
+ if($data)
+ {
+ self::fill($user, $data);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function LoadByToken(\Models\User $user)
+ {
+ $data = $this->Collection->findOne(array(
+ self::FIELD_TOKEN => $user->Token
+ ));
+ if($data)
+ {
+ self::fill($user, $data);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public function ChangeScore(\Models\User $user)
+ {
+ try
+ {
+ $searchArray = array(self::FIELD_ID => new \MongoId($user->Id));
+
+ $incArray = array('$inc'=>array(self::FIELD_SCORE=>$user->Score));
+
+ $this->Collection->update($searchArray, $incArray);
+ }
+ catch(\Exception $e)
+ {
+ return false;
+ }
+ return true;
+ }
+}
+?>
15 core/Database/Collections/SessionInterface.class.php
@@ -0,0 +1,15 @@
+<?php
+/*---------------------------------------------------------------------------
+ SessionInterface 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections
+ Class : SessionInterface
+ - Interface to SessionCollection methods
+---------------------------------------------------------------------------*/
+namespace Database\Collections;
+
+interface SessionInterface extends ModelInterface
+{
+ public function Cleanup($time);
+}
+?>
15 core/Database/Collections/StatisticInterface.class.php
@@ -0,0 +1,15 @@
+<?php
+/*---------------------------------------------------------------------------
+ StatisticInterface 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections
+ Class : StatisticInterface
+ - Interface to StatisticCollection methods
+---------------------------------------------------------------------------*/
+namespace Database\Collections;
+
+interface StatisticInterface
+{
+ public function Load($id);
+}
+?>
17 core/Database/Collections/UserInterface.class.php
@@ -0,0 +1,17 @@
+<?php
+/*---------------------------------------------------------------------------
+ UserInterface 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database\Collections
+ Class : UserInterface
+ - Interface to UserCollection methods
+---------------------------------------------------------------------------*/
+namespace Database\Collections;
+
+interface UserInterface extends ModelInterface
+{
+ public function LoadByName(\Models\User $user);
+ public function LoadByEmail(\Models\User $user);
+ public function ChangeScore(\Models\User $user);
+}
+?>
42 core/Database/Controller.class.php
@@ -0,0 +1,42 @@
+<?php
+/*---------------------------------------------------------------------------
+ Database 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database
+ Class : Controller
+ - abstract class - descends from singleton
+---------------------------------------------------------------------------*/
+namespace Database;
+
+class Controller extends \Classes\Singleton
+{
+ protected static $_collectionTypes = array();
+ protected static $_collections = array();
+
+ protected function __construct()
+ {
+ include './Config/Database.config.php';
+ }
+
+ protected function addCollection($settings)
+ {
+ self::$_collectionTypes[$settings->Name] = $settings;
+ }
+
+ public function __get($property)
+ {
+ if(array_key_exists($property, self::$_collectionTypes))
+ {
+ if(!array_key_exists($property, self::$_collections))
+ {
+ self::$_collections[$property] = new self::$_collectionTypes[$property]->ClassName(self::$_collectionTypes[$property]);
+ }
+ }
+ else
+ {
+ throw new \Exception('Attempted to use non-existent database collection '.$property.'. Please ensure the collection exists and is set up properly.');
+ }
+ return self::$_collections[$property];
+ }
+}
+?>
23 core/Database/Settings.class.php
@@ -0,0 +1,23 @@
+<?php
+/*---------------------------------------------------------------------------
+ Settings 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Database
+ Class : Settings
+ - Stores connection settings
+---------------------------------------------------------------------------*/
+namespace Database;
+
+class Settings
+{
+ public $Name;
+ public $Driver;
+ public $Host;
+ public $Port;
+ public $Database;
+ public $Collection;
+ public $User;
+ public $Password;
+ public $ClassName;
+}
+?>
195 core/Log.class.php
@@ -0,0 +1,195 @@
+<?php
+/*---------------------------------------------------------------------------
+ Log 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : \
+ Class : Log
+ - Static
+ - Abstracts log file/database access
+---------------------------------------------------------------------------*/
+
+class LogErrorException extends Exception
+{
+ /**
+ * The PHP Error Context
+ *
+ * The fifth parameter is optional, errcontext, which is an array that points to the active symbol table at the point the error occurred. In other words, errcontext will contain an array of every variable that existed in the scope the error was triggered in. User error handler must not modify error context.
+ */
+ private $m_arContext;
+
+ /**
+ * Constructor
+ */
+ public function __construct($vMessage, $vCode, $vFile, $vLine, $arContext = null)
+ {
+ parent::__construct($vMessage, $vCode);
+
+ $this->file = $vFile;
+ $this->line = $vLine;
+
+ $this->m_arContext = $arContext;
+ }
+}
+
+
+class Log
+{
+ public static $Severity = array(
+ 'FATAL' =>200,
+ 'ERROR' =>100,
+ 'WARNING' =>50,
+ 'INFO' =>10,
+ 'DEBUG' =>0
+ );
+
+ public static $ErrorTemplate = null;
+ public static $File = null;
+
+ public static $Verbose = false;
+
+ public static $ToTemplate = true;
+ public static $ToDatabase = true;
+ public static $ToFile = true;
+
+ private static function toTemplate($subject, $message, $severity, $stackTrace, $context = null)
+ {
+ if(ob_get_level())
+ ob_end_clean();
+ ob_start();
+ if($context === null)
+ $context = \Context::getInstance();
+
+ $context->error->message = $message;
+ $context->error->severity = array_search($severity, self::$Severity);
+ $context->error->stackTrace = $stackTrace;
+ $context->error->subject = $subject;
+ $context->error->verbose = self::$Verbose;
+ $context->partials->header = \Templates\Controller::LoadTemplate('public/header');
+ $context->partials->footer = \Templates\Controller::LoadTemplate('public/footer');
+
+ \Templates\Controller::SetTemplate(self::$ErrorTemplate);
+ header("HTTP/1.0 500 Internal Server Error");
+ }
+
+ private static function toDatabase($subject, $message, $severity, $stackTrace)
+ {
+ \Database\Controller::getInstance()->Logs->Add(
+ $subject,
+ $message,
+ $severity,
+ $stackTrace
+ );
+ }
+
+ private static function toFile($subject, $message, $severity, $stackTrace)
+ {
+ file_put_contents(
+ self::$File,
+ date("Y/m/d h:i:s a", time())."\t".$subject."\t".$severity."\t".$message."\t".$stackTrace.PHP_EOL,
+ FILE_APPEND
+ );
+ }
+
+ private static function arrayToHTML($array)
+ {
+ ob_start();
+ var_dump($array);
+ $result = ob_get_contents();
+ ob_end_clean();
+ return $result;
+ }
+
+ public static function Message($subject, $message, $severity, $stackTrace, $context = null, $database=true, $die=false, $template=true)
+ {
+ if(is_array($stackTrace))
+ $stackTrace = self::arrayToHTML($stackTrace);
+
+ //Log to error template
+ if($template && self::$ToTemplate)
+ {
+ try
+ {
+ self::toTemplate(
+ $subject,
+ $message,
+ $severity,
+ $stackTrace,
+ $context
+ );
+ }
+ catch(\Exception $e){/* Do Nothing, cannot log */}
+ }
+
+ //Log to Database
+ if($database && self::$ToDatabase)
+ {
+ try
+ {
+ self::toDatabase(
+ $subject,
+ $message,
+ $severity,
+ $stackTrace
+ );
+ }
+ catch(\Exception $e){/* Do Nothing, cannot log */}
+ }
+
+ //Log to File
+ if(self::$ToFile)
+ {
+ try
+ {
+ self::toFile(
+ $subject,
+ $message,
+ $severity,
+ $stackTrace
+ );
+ }
+ catch(\Exception $e){/* Do Nothing, cannot log */}
+ }
+
+ if($die)
+ exit();
+ }
+
+ public static function ExceptionHandler($exception, $context = null)
+ {
+ if($context === null)
+ $context = \Context::getInstance();
+
+ $context->exception = $exception;
+
+ self::Message(
+ 'RUNTIME',
+ $exception->getMessage()." in ".$exception->getFile().":".$exception->getLine(),
+ self::$Severity['ERROR'],
+ $exception->getTrace(),
+ $context
+ );
+ }
+
+ public static function ErrorHandler($level, $message, $file, $line, $context)
+ {
+ throw new LogErrorException(
+ $message,
+ $level,
+ $file,
+ $line,
+ $context
+ );
+ }
+}
+
+include('./Config/Log.config.php');
+Log::$ErrorTemplate = $TemplateFile;
+Log::$File = $LogFile;
+
+Log::$Verbose = $Verbose;
+
+Log::$ToTemplate = $TemplateEnabled;
+Log::$ToDatabase = $DatabaseEnabled;
+Log::$ToFile = $FileEnabled;
+
+?>
5 core/Mint.php
@@ -0,0 +1,5 @@
+<?php
+include './Common/Common.inc.php';
+//Fill Context by executing request handler
+\Router\Controller::getInstance()->Execute(\Common\UriToArray($_SERVER['REQUEST_URI']));
+?>
19 core/Models/Model.class.php
@@ -0,0 +1,19 @@
+<?php
+/*---------------------------------------------------------------------------
+ Database 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Models
+ Class : Model
+---------------------------------------------------------------------------*/
+namespace Models;
+
+class Model
+{
+ public $Id = null;
+
+ public function __construct()
+ {
+
+ }
+}
+?>
19 core/Models/Profile.class.php
@@ -0,0 +1,19 @@
+<?php
+/*---------------------------------------------------------------------------
+ Profile 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Models
+ Class : Profile
+---------------------------------------------------------------------------*/
+namespace Models;
+
+class Profile extends Model
+{
+ public $Template = 'default';
+
+ public function __construct()
+ {
+ parent::__construct();
+ }
+}
+?>
26 core/Models/Search.class.php
@@ -0,0 +1,26 @@
+<?php
+/*---------------------------------------------------------------------------
+ Quote 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Models
+ Class : Search
+---------------------------------------------------------------------------*/
+namespace Models;
+
+class Search extends Model
+{
+ public $SortField = null;
+ public $SortDirection = 1;
+ public $Limit = 10;
+ public $Skip = 0;
+ public $Keywords = array();
+ public $Domain = null;
+ public $PostedBy = null;
+ public $PostedByName = null;
+
+ public function __construct()
+ {
+ parent::__construct();
+ }
+}
+?>
24 core/Models/Session.class.php
@@ -0,0 +1,24 @@
+<?php
+/*---------------------------------------------------------------------------
+ Session 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Models
+ Class : Session
+---------------------------------------------------------------------------*/
+namespace Models;
+
+class Session extends Model
+{
+ const FIELD_USER = 'User';
+ public $SessionId= null;
+ public $Data = array();
+
+ public $LastAccess = 0;
+
+ public function __construct()
+ {
+ parent::__construct();
+ $this->LastAccess = time();
+ }
+}
+?>
37 core/Models/User.class.php
@@ -0,0 +1,37 @@
+<?php
+/*---------------------------------------------------------------------------
+ User 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Models
+ Class : User
+---------------------------------------------------------------------------*/
+namespace Models;
+
+class User extends Model
+{
+ public $UserName = null;
+ public $Password = null;
+ public $Email = null;
+ public $Domain = null;
+ public $Profile = null;
+ public $Score = null;
+ public $Token = null;
+
+ public function __construct()
+ {
+ parent::__construct();
+ $this->Profile = new Profile();
+ }
+
+ public function Verify()
+ {
+ if(
+ ((strlen($this->UserName) > 0) || (!isset($this->UserName))) &&
+ ((strlen($this->Password) > 0) || (!isset($this->Password))) &&
+ ((strlen($this->Email) > 0) || (!isset($this->Email)))
+ )
+ return true;
+ return false;
+ }
+}
+?>
59 core/Router/AuthenticationHandler.class.php
@@ -0,0 +1,59 @@
+<?php
+/*---------------------------------------------------------------------------
+ AuthenticationHandler 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Router
+ Class : AuthenticationHandler
+---------------------------------------------------------------------------*/
+namespace Router;
+
+abstract class AuthenticationHandler extends \Router\Handler
+{
+ protected $_currentUser = null;
+
+ protected function isAuthenticated()
+ {
+ if(array_key_exists('_token', $this->_request))
+ {
+ $user = \Controllers\Users::GetByToken($this->_request['_token']);
+ if($user !== null)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if($this->_context->CurrentUser->LoggedIn)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected function currentUser()
+ {
+ if($this->_currentUser == null)
+ {
+ if(array_key_exists('_token', $this->_request))
+ {
+ $this::setCurrentContextUser(\Controllers\Users::GetByToken(trim($this->_request['_token'])));
+ }
+ else
+ {
+ $this->_currentUser = $this->_context->CurrentUser;
+ }
+ }
+
+ return $this->_currentUser;
+ }
+
+
+ protected function setCurrentContextUser(\Models\User $user)
+ {
+ $user->LoggedIn = true;
+ $this->_currentUser = $user;
+ $this->_context->CurrentUser = (array)$user;
+ }
+}
+?>
98 core/Router/Controller.class.php
@@ -0,0 +1,98 @@
+<?php
+/*---------------------------------------------------------------------------
+ Context 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Router
+ Class : Controller
+---------------------------------------------------------------------------*/
+namespace Router;
+
+class Controller extends \Classes\Singleton
+{
+ private $_parent = null;
+ private $_data = array();
+ private $_file = null;
+
+ protected $_currentIndex = null;
+
+ protected function __construct(\Router\Controller $parent = null, $index='')
+ {
+ $this->_parent = $parent;
+ $this->_currentIndex = $index;
+ }
+
+ public function GetRoute()
+ {
+ if($this->_currentIndex)
+ return $this->_parent->GetRoute().$this->_currentIndex.'/';
+ }
+
+ private static function getHandler($path, $file)
+ {
+ $handler = null;
+
+ while(!file_exists($handler = $path.$file) && $path != './')
+ {
+ $path = dirname($path).'/';
+ }
+
+ if($path == '.')
+ $handler = null;
+
+ return $handler;
+ }
+
+ private static function fillArray(&$array)
+ {
+ if($data = file_get_contents('php://input'))
+ parse_str($data, $array);
+ }
+
+ private static function ensureRequestMethod()
+ {
+ if(array_key_exists('_method', $_REQUEST))
+ {
+ $_SERVER['REQUEST_METHOD'] = strtoupper($_REQUEST['_method']);
+ }
+ }
+
+ public function Execute($pathArray = null)
+ {
+ $router = $this;
+
+ if($pathArray)
+ foreach($pathArray AS $key)
+ $router = $router->{$key};
+
+ self::ensureRequestMethod();
+
+ $routeHandlerPath = HANDLER_DIR.$router->GetRoute();
+ $handlerPath = null;
+
+ $handlerPath = self::getHandler($routeHandlerPath, $_SERVER['REQUEST_METHOD'].'.handler.php');
+
+ $context = \Context::getInstance();
+
+ if($handlerPath !== null)
+ {
+ include $handlerPath;
+
+ $handler = new \RequestHandler($context, $_REQUEST);
+ $handler->PreRequest();
+ $handler->Request();
+ }
+ else
+ {
+ header("HTTP/1.0 404 Not Found");
+ $context->partials->header = \Templates\Controller::LoadTemplate('public/header');
+ $context->partials->footer = \Templates\Controller::LoadTemplate('public/footer');
+ \Templates\Controller::SetTemplate('errors/404');
+ }
+ }
+
+ public final function __get($index)
+ {
+ return (array_key_exists($index, $this->_data))?$this->_data[$index]:$this->_data[$index] = new Controller($this, $index);
+ }
+}
+?>
65 core/Router/Handler.class.php
@@ -0,0 +1,65 @@
+<?php
+/*---------------------------------------------------------------------------
+ Handler 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Router
+ Class : Handler
+---------------------------------------------------------------------------*/
+namespace Router;
+
+abstract class Handler
+{
+ protected $_context = null;
+ protected $_request = null;
+
+ public function __construct(\Context $context, $request)
+ {
+ $this->_context = $context;
+ $this->_request = $request;
+ }
+
+ public function PreRequest()
+ {
+ $session = \Classes\SessionHandler::getSession();
+
+ if(!array_key_exists(\Models\Session::FIELD_USER, $session->Data) && array_key_exists("token", $this->_request)){
+ $user = \Controllers\Users::GetByToken($this->_request['_token']);
+
+ if($user !== null)
+ {
+ $user->LoggedIn = true;
+ $session->Data[\Models\Session::FIELD_USER] = $user;
+ }
+ }
+ }
+
+ public abstract function Request();
+
+ protected function redirect($url)
+ {
+ header('location: '.$url);
+ \Templates\Controller::SetTemplate(null);
+ exit;
+ }
+
+ protected function setTemplate($path)
+ {
+ \Templates\Controller::SetTemplate($path);
+ }
+
+ protected function addPartial($name, $path)
+ {
+ $this->_context->partials->$name = \Templates\Controller::LoadTemplate($path);
+ }
+
+ protected function setContentType($type)
+ {
+ \Templates\Controller::SetContentType($type);
+ }
+
+ protected function setHTTPStatusCode($code)
+ {
+ \Templates\Controller::SetHTTPStatusCode($type);
+ }
+}
+?>
28 core/Router/SecureHandler.class.php
@@ -0,0 +1,28 @@
+<?php
+/*---------------------------------------------------------------------------
+ SecureHandler 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Router
+ Class : SecureHandler
+---------------------------------------------------------------------------*/
+namespace Router;
+
+abstract class SecureHandler extends \Router\AuthenticationHandler
+{
+
+ public final function Request()
+ {
+ if($this->isAuthenticated())
+ {
+ $this->AuthenticatedRequest();
+ }
+ else
+ {
+ $this->AnonymousRequest();
+ }
+ }
+
+ protected abstract function AuthenticatedRequest();
+ protected abstract function AnonymousRequest();
+}
+?>
162 core/Templates/Controller.class.php
@@ -0,0 +1,162 @@
+<?php
+/*---------------------------------------------------------------------------
+ Controller 2011 Olivine Labs
+-----------------------------------------------------------------------------
+ Namespace : Templates
+ Class : Controller
+---------------------------------------------------------------------------*/
+namespace Templates;
+
+class Controller
+{
+ private static $_statusCode = 200;
+ private static $_template = 'public/index';
+ private static $_htmlTypes = array();
+
+ private static $_defaultStatusCodesByVerb = array("GET" => 200, "POST" => 201, "PUT" => 200, "DELETE" => 200);
+ private static $_fullStatusHeaders = array(200 => "200 OK", 201 => "201 Created", 202 => "202 Accepted", 301 => "301 Moved Permanently", 304 => "304 Not Modified", 307 => "307 Temporary Redirect", 403 => "403 Forbidden", 404 => "404 Not Found", 405 => "405 Method Not Allowed", 410 => "410 Gone", 500 => "500 Internal Server Error", 501 => "501 Not Implemented", 503 => "503 Service Unavailable");
+ private static $_contentType = null;
+
+ public static $Renderers = array();
+
+ private static function fillTypes()
+ {
+ if(!self::$_htmlTypes)
+ {
+ self::$_htmlTypes[] = 'x-www-form-urlencoded';
+ }
+ }
+
+ private static function getContentType()
+ {
+ self::fillTypes();
+ if(array_key_exists('_type', $_REQUEST))
+ return $_REQUEST['_type'];
+
+ if(self::$_contentType !== null)
+ return self::$_contentType;
+
+ if(array_key_exists('CONTENT_TYPE', $_SERVER))
+ {
+ if($_SERVER['CONTENT_TYPE'])
+ {
+ $temp = explode('/', $_SERVER['CONTENT_TYPE']);
+ if(is_array($temp))
+ $temp = end($temp);
+ if(in_array($temp, self::$_htmlTypes))
+ return 'html';
+ else
+ return $temp;
+ }
+ else
+ {
+ return 'html';
+ }
+ }
+ else
+ {
+ return 'html';
+ }
+ }
+
+ private static function getTemplateExt()
+ {
+ self::fillTypes();
+ $ext = '.mustache';
+ if(array_key_exists('CONTENT_TYPE', $_SERVER))
+ {
+ $temp = explode('/', $_SERVER['CONTENT_TYPE']);
+ if(is_array($temp))
+ $temp = end($temp);
+ if(!in_array($temp, self::$_htmlTypes))
+ $ext = '.php';
+ }
+ return $ext;
+ }
+
+ private static function render($file, $renderer = null, $context = null)
+ {
+ if(self::getTemplateExt() == '.php')
+ {
+ if(file_exists($file))
+ include $file;
+ return;
+ }
+ if($context === null)
+ $context = \Context::getInstance();
+ $template = false;
+ if(file_exists($file))
+ $template = file_get_contents($file);
+ if($template !== false)
+ {
+ $partials = array();
+ $contextObject = $context->ToObject();
+ if(property_exists($contextObject, 'partials'))
+ {
+ $partials = (array)$contextObject->partials;
+ }
+ $contextObject->partials = null;
+
+ if($renderer)
+ {
+ return $renderer->render(
+ $template,
+ $contextObject,
+ $partials
+ );
+ }
+ else
+ {
+ return $template;
+ }
+ }
+ else
+ {
+ return 'Failed to load template "'.$file.'"';
+ }
+ }
+
+ public static function SetTemplate($template)
+ {
+ self::$_template = $template;
+ }
+
+ public static function LoadTemplate($template)
+ {
+ $context = \Context::getInstance();
+ $file = VIEW_DIR.$context->CurrentUser->Profile->Template.'/'.self::getContentType().'/'.$template.self::getTemplateExt();
+ $template = self::render($file);
+ return $template;
+ }
+
+ public static function SetHTTPStatusCode($code)
+ {
+ if(array_key_exists($code, self::$_fullStatusHeaders)){
+ self::$_statusCode = $code;
+ }
+ }
+
+ public static function SetContentType($contentType)
+ {
+ self::$_contentType = $contentType;
+ }
+
+ public static function Output($renderer, $context = null)
+ {
+ if($context === null)
+ $context = \Context::getInstance();
+
+ if(self::$_statusCode == null){
+ self::$_statusCode = self::$_defaultStatusCodesByVerb[$_SERVER['REQUEST_METHOD']];
+ }
+
+ header(self::$_fullStatusHeaders[self::$_statusCode]);
+
+ if(self::$_template !== null)
+ {
+ $file = VIEW_DIR.$context->CurrentUser->Profile->Template.'/'.self::getContentType().'/'.self::$_template.self::getTemplateExt();
+ echo self::render($file, $renderer, $context);
+ }
+ }
+}
+?>
889 core/Templates/Mustache.class.php
@@ -0,0 +1,889 @@
+<?php
+namespace Templates;
+/**
+ * A Mustache implementation in PHP.
+ *
+ * {@link http://defunkt.github.com/mustache}
+ *
+ * Mustache is a framework-agnostic logic-less templating language. It enforces separation of view
+ * logic from template files. In fact, it is not even possible to embed logic in the template.
+ *
+ * This is very, very rad.
+ *
+ * @author Justin Hileman {@link http://justinhileman.com}
+ */
+class Mustache {
+
+ const VERSION = '0.8.1';
+ const SPEC_VERSION = '1.1.2';
+
+ /**
+ * Should this Mustache throw exceptions when it finds unexpected tags?
+ *
+ * @see self::_throwsException()
+ */
+ protected $_throwsExceptions = array(
+ MustacheException::UNKNOWN_VARIABLE => false,
+ MustacheException::UNCLOSED_SECTION => false,
+ MustacheException::UNEXPECTED_CLOSE_SECTION => false,
+ MustacheException::UNKNOWN_PARTIAL => false,
+ MustacheException::UNKNOWN_PRAGMA => false,
+ );
+
+ // Override charset passed to htmlentities() and htmlspecialchars(). Defaults to UTF-8.
+ protected $_charset = 'UTF-8';
+
+ /**
+ * Pragmas are macro-like directives that, when invoked, change the behavior or
+ * syntax of Mustache.
+ *
+ * They should be considered extremely experimental. Most likely their implementation
+ * will change in the future.
+ */
+
+ /**
+ * The {{%UNESCAPED}} pragma swaps the meaning of the {{normal}} and {{{unescaped}}}
+ * Mustache tags. That is, once this pragma is activated the {{normal}} tag will not be
+ * escaped while the {{{unescaped}}} tag will be escaped.
+ *
+ * Pragmas apply only to the current template. Partials, even those included after the
+ * {{%UNESCAPED}} call, will need their own pragma declaration.
+ *
+ * This may be useful in non-HTML Mustache situations.
+ */
+ const PRAGMA_UNESCAPED = 'UNESCAPED';
+
+ /**
+ * Constants used for section and tag RegEx
+ */
+ const SECTION_TYPES = '\^#\/';
+ const TAG_TYPES = '#\^\/=!<>\\{&';
+
+ protected $_otag = '{{';
+ protected $_ctag = '}}';
+
+ protected $_tagRegEx;
+
+ protected $_template = '';
+ protected $_context = array();
+ protected $_partials = array();
+ protected $_pragmas = array();
+
+ protected $_pragmasImplemented = array(
+ self::PRAGMA_UNESCAPED
+ );
+
+ protected $_localPragmas = array();
+
+ /**
+ * Mustache class constructor.
+ *
+ * This method accepts a $template string and a $view object. Optionally, pass an associative
+ * array of partials as well.
+ *
+ * Passing an $options array allows overriding certain Mustache options during instantiation:
+ *
+ * $options = array(
+ * // `charset` -- must be supported by `htmlspecialentities()`. defaults to 'UTF-8'
+ * 'charset' => 'ISO-8859-1',
+ *
+ * // opening and closing delimiters, as an array or a space-separated string
+ * 'delimiters' => '<% %>',
+ *
+ * // an array of pragmas to enable/disable
+ * 'pragmas' => array(
+ * Mustache::PRAGMA_UNESCAPED => true
+ * ),
+ * );
+ *
+ * @access public
+ * @param string $template (default: null)
+ * @param mixed $view (default: null)
+ * @param array $partials (default: null)
+ * @param array $options (default: array())
+ * @return void
+ */
+ public function __construct($template = null, $view = null, $partials = null, array $options = null) {
+ if ($template !== null) $this->_template = $template;
+ if ($partials !== null) $this->_partials = $partials;
+ if ($view !== null) $this->_context = array($view);
+ if ($options !== null) $this->_setOptions($options);
+ }
+
+ /**
+ * Helper function for setting options from constructor args.
+ *
+ * @access protected
+ * @param array $options
+ * @return void
+ */
+ protected function _setOptions(array $options) {
+ if (isset($options['charset'])) {
+ $this->_charset = $options['charset'];
+ }
+
+ if (isset($options['delimiters'])) {
+ $delims = $options['delimiters'];
+ if (!is_array($delims)) {
+ $delims = array_map('trim', explode(' ', $delims, 2));
+ }
+ $this->_otag = $delims[0];
+ $this->_ctag = $delims[1];
+ }
+
+ if (isset($options['pragmas'])) {
+ foreach ($options['pragmas'] as $pragma_name => $pragma_value) {
+ if (!in_array($pragma_name, $this->_pragmasImplemented, true)) {
+ throw new MustacheException('Unknown pragma: ' . $pragma_name, MustacheException::UNKNOWN_PRAGMA);
+ }
+ }
+ $this->_pragmas = $options['pragmas'];
+ }
+ }
+
+ /**
+ * Mustache class clone method.
+ *
+ * A cloned Mustache instance should have pragmas, delimeters and root context
+ * reset to default values.
+ *
+ * @access public
+ * @return void
+ */
+ public function __clone() {
+ $this->_otag = '{{';
+ $this->_ctag = '}}';
+ $this->_localPragmas = array();
+
+ if ($keys = array_keys($this->_context)) {
+ $last = array_pop($keys);
+ if ($this->_context[$last] instanceof Mustache) {
+ $this->_context[$last] =& $this;
+ }
+ }
+ }
+
+ /**
+ * Render the given template and view object.
+ *
+ * Defaults to the template and view passed to the class constructor unless a new one is provided.
+ * Optionally, pass an associative array of partials as well.