asMessageStack = array(); $this->asMessageStack[self::ERROR_TAB] = array(); $this->asMessageStack[self::WARNING_TAB] = array(); $this->iExtractMode = self::MODE_ARRAY; } protected function addError($sError) { $this->addMessage(self::ERROR_TAB, $sError); } protected function addWarning($sWarning) { $this->addMessage(self::WARNING_TAB, $sError); } private function addMessage($sType, $sMessage) { $this->asMessageStack[$sType][] = $sMessage; } protected function getCleanErrorStack() { return $this->getCleanMessageStack(self::ERROR_TAB); } protected function getCleanWarningStack() { return $this->getCleanMessageStack(self::WARNING_TAB); } private function getCleanMessageStack($sType) { switch($this->iExtractMode) { case self::MODE_TEXT: $oMessageStack = implode("\n", $this->asMessageStack[$sType]); break; case self::MODE_ARRAY: $oMessageStack = $this->asMessageStack[$sType]; break; case self::MODE_FILE: $oMessageStack = implode("

", $this->asMessageStack[$sType]); break; } $this->asMessageStack[$sType] = array(); return $oMessageStack; } function __destruct() { $sErrorStack = $this->getCleanErrorStack(); switch($this->iExtractMode) { case self::MODE_TEXT: echo $sErrorStack; break; case self::MODE_ARRAY: if(count($sErrorStack)>0) { pre($sErrorStack, 'Error Stack'); } break; case self::MODE_FILE: if($sErrorStack!='') { @file_put_contents('log.html', '

'.date('r')."

".$sErrorStack.'

', FILE_APPEND); } break; } } } class MySqlManager extends PhpObject { const DB_SERVER = 'localhost'; const DB_LOGIN = 'root'; const DB_PASS = '0nadmin'; const DB_NAME = 'mythoughts'; const ID_TAG = 'id_'; const USERS_TABLE = 'users'; const THOUGHTS_TABLE = 'thoughts'; const SETTINGS_TABLE = 'settings'; private $oConnection; public function __construct() { parent::__construct(); $this->oConnection = mysql_connect(self::DB_SERVER, self::DB_LOGIN, self::DB_PASS); if(!$this->oConnection) { $this->addError('bug connection'); } else { if(!mysql_select_db(self::DB_NAME, $this->oConnection)) { $this->install(); } } } public function __destruct() { mysql_close($this->oConnection); } private function install() { $this->setQuery("DROP DATABASE IF EXISTS ".self::DB_NAME); $this->setQuery("CREATE /* ".basename(__FILE__)." ".__LINE__." */ DATABASE ".self::DB_NAME); mysql_select_db(self::DB_NAME, $this->oConnection); @array_walk(array_map(array($this, 'getInstallQuery'), $this->getTables()), array($this, 'setQuery')); } private function getInstallQuery($sTableName) { $asTableColumns = $this->getTableColumns($sTableName); $sQuery = "\n".implodeAll($asTableColumns, "` ", "\n", "`", ",")."\n".implode(", \n", $this->getTableConstraints($sTableName)); return "CREATE /* ".basename(__FILE__)." ".__LINE__." */ TABLE `{$sTableName}` ({$sQuery})"; } private function setQuery($sQuery, $sTypeQuery=__FUNCTION__) { return $this->getQuery($sQuery, $sTypeQuery); } private function getQuery($sQuery, $sTypeQuery=__FUNCTION__) { $oResult = mysql_query($sQuery, $this->oConnection); if(!$oResult) { $this->addError("\nErreur SQL : \n".$sQuery."\n".mysql_error()); } return $oResult; } public function getArrayQuery($sQuery, $bStringOnly=false, $sTypeQuery=__FUNCTION__) { $asResult = array(); $oResult = $this->getQuery($sQuery, true, $sTypeQuery); if($oResult!==false) { while($asCurrentRow = mysql_fetch_array($oResult)) { if($bStringOnly) { $asCurrentRow = $this->arrayKeyFilter($asCurrentRow, 'is_string'); } //One column case : collapse a level if(count($asCurrentRow)==1) { $asResult[] = array_shift($asCurrentRow); } else { $asResult[] = $asCurrentRow; } } } return $asResult; } private function arrayKeyFilter($asArray, $sCallBack) { $asValidKeys = array_flip(array_filter(array_keys($asArray), $sCallBack)); return array_intersect_key($asArray, $asValidKeys); } public static function getTables() { return array(self::USERS_TABLE, self::THOUGHTS_TABLE, self::SETTINGS_TABLE); } public static function getId($sTableName) { return self::ID_TAG.substr($sTableName, 0, -1); } public static function getText($sTableName) { return substr($sTableName, 0, -1); } private static function isId($sColumnName, $sTableName='') { $asTables = ($sTableName=='')?self::getTables():array($sTableName); $asTableIds = array_map(array('self', 'getId'), $asTables); return in_array($sColumnName, $asTableIds); } public static function getTablecolumns($sTableName) { $asTableColumns = array(self::getId($sTableName)); switch($sTableName) { case self::USERS_TABLE: $asTableColumns[] = 'user'; $asTableColumns[] = 'pass'; break; case self::THOUGHTS_TABLE: $asTableColumns[] = self::getId(self::USERS_TABLE); $asTableColumns[] = 'thought'; break; case self::SETTINGS_TABLE: $asTableColumns[] = self::getId(self::USERS_TABLE); $asTableColumns[] = 'setting'; $asTableColumns[] = 'value'; break; default: $this->addError('Function '.__FUNCTION__.', table '.$sTableName.' not found'); } $asTableColumns[] = 'led'; $asTableName = array_fill(0, count($asTableColumns), $sTableName); return array_combine($asTableColumns, array_map(array('self', 'getColumnType'), $asTableColumns, $asTableName)); } private static function getColumnType($sColumnName, $sTableName) { $sColumnType = ''; switch($sColumnName) { case 'user': $sColumnType = "varchar(20) NOT NULL"; break; case 'pass': $sColumnType = "varchar(128) NOT NULL"; break; case 'thought': $sColumnType = "longtext NOT NULL"; break; case 'setting': $sColumnType = "varchar(20) NOT NULL"; break; case 'value': $sColumnType = 'varchar(20) NOT NULL'; break; case 'led': $sColumnType = "TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT CURRENT_TIMESTAMP"; break; case self::isId($sColumnName, $sTableName): $sColumnType = "int(10) UNSIGNED auto_increment"; break; case self::isId($sColumnName): $sColumnType = "int(10) UNSIGNED NOT NULL"; break; } return $sColumnType; } private static function getTableConstraints($sTableName) { //primary key $asTableConstraints = array('PRIMARY' => "PRIMARY KEY (`".self::getId($sTableName)."`)"); //other constraints switch($sTableName) { case 'user' : break; case 'thought' : break; } return $asTableConstraints; } private function addQuotes($oData) { return array_map_encapsulate($oData, "'"); } private function getLastId() { return mysql_insert_id(); } public function insertRow($sTableName, $asData) { $this->cleanSql($sTableName); $this->cleanSql($asData); $asQueryValues = $this->addQuotes($asData); $sQuery = "INSERT /* ".basename(__FILE__)." ".__LINE__." */ INTO ".$sTableName." (`".implode("`, `", array_keys($asQueryValues))."`) VALUES (".implode(", ", $asQueryValues).")"; return $this->setQuery($sQuery)?$this->getLastId():false; } public function updateRow($sTableName, $asConstraints, $asData) { if(!is_array($asConstraints)) { $asConstraints = array($this->getId($sTableName)=>$asConstraints); } $iTableId = $this->cleanSql($sTableName); $this->cleanSql($iTableId); $this->cleanSql($asData); $this->cleanSql($asConstraints); $asQueryValues = $this->addQuotes($asData); $asConstraintsValues = $this->addQuotes($asConstraints); $sQuery = "UPDATE /* ".basename(__FILE__)." ".__LINE__." */ $sTableName SET ".implodeAll($asQueryValues, " = ", ", ")." WHERE ".implodeAll($asConstraintsValues, " = ", " AND ")." LIMIT 1"; return $this->setQuery($sQuery)?$this->selectValue($sTableName, $this->getId($sTableName), $asConstraints):false; } public function insertUpdateRow($sTableName, $asConstraints, $asData) { $iTableId = $this->selectValue($sTableName, $this->getId($sTableName), $asConstraints); if(!$iTableId) { $asData = array_merge($asConstraints, $asData); return $this->insertRow($sTableName, $asData); } else { return $this->updateRow($sTableName, $asConstraints, $asData); } } public function selectRow($sTableName, $asConstraints=array(), $sColumnName='*', $bStringOnly=false) { $asResult = $this->selectRows(array('select'=>$sColumnName, 'from'=>$sTableName, 'constraint'=>$asConstraints)); $iCountNb = count($asResult); switch($iCountNb) { case 0 : return false; case $iCountNb > 1 : $this->addError('Trop de résultats pour un selectRow() : '.$iCountNb); break; } return array_shift($asResult); } function selectValue($sTableName, $sColumnName, $asConstraints) { if(is_numeric($asConstraints)) { $asConstraints = array(self::getId($sTableName)=>$asConstraints); } return $this->selectRow($sTableName, $asConstraints, $sColumnName); } public function selectRows($asInfo, $bStringOnly=true) { $sAttributes = array('select'=>"SELECT", 'from'=>"FROM", 'constraint'=>"WHERE", 'groupBy'=>"GROUP BY", 'orderBy'=>"ORDER BY"); $asRowSeparators = array('select'=>", ", 'from'=>"", 'constraint'=>" AND ", 'groupBy'=>", ", 'orderBy'=>", "); $asOperators = array('constraint'=>" = ", 'orderBy'=>" "); $sQuery = "/* ".basename(__FILE__)." ".__LINE__." */"; foreach($sAttributes as $sStatement => $sKeyWord) { $asSelection = array_key_exists($sStatement, $asInfo)?$asInfo[$sStatement]:array(); if(!is_array($asSelection)) { $asSelection = array($asSelection); } //if provided values if(!empty($asSelection)) { $this->cleanSql($asSelection); if($sStatement=='constraint') { $asSelection = $this->addQuotes($asSelection); } $sQuery .= " ".$sKeyWord." "; //in case of double value input if(array_key_exists($sStatement, $asOperators)) { $sQuery .= implodeAll($asSelection, $asOperators[$sStatement], $asRowSeparators[$sStatement]); } else { $sQuery .= implode($asRowSeparators[$sStatement], $asSelection); } } //default value for select elseif($sStatement=='select') { $sQuery .= " ".$sKeyWord." * "; } } return $this->getArrayQuery($sQuery, $bStringOnly); } private function cleanSql(&$oData) { cleanData($oData, 'mysql_real_escape_string'); } } class Session extends PhpObject { private $iUserId; private $sLogin; private $sToken; private $sPostToken; private $oMySql; const SESSION_ID_USER = 'id_user'; const SESSION_USER = 'user'; const SESSION_TOKEN = 'token'; const SESSION_POST_TOKEN = 'post_token'; public function __construct($oMySql) { parent::__construct(); $this->iUserId = $this->sLogin = $this->sToken = $this->sPostToken = false; $this->oMySql = $oMySql; $this->syncSession(); } public function getUserId() { return $this->iUserId; } private function syncSession() { if(isset($_SESSION[self::SESSION_ID_USER])) { $this->iUserId = $_SESSION[self::SESSION_ID_USER]; } if(isset($_SESSION[self::SESSION_USER])) { $this->sLogin = $_SESSION[self::SESSION_USER]; } if(isset($_SESSION[self::SESSION_TOKEN])) { $this->sToken = $_SESSION[self::SESSION_TOKEN]; } if(isset($_SESSION[self::SESSION_POST_TOKEN])) { $this->sPostToken = $_SESSION[self::SESSION_POST_TOKEN]; } } private function setSession($iUserId, $sLogin) { $_SESSION[self::SESSION_ID_USER] = $iUserId; $_SESSION[self::SESSION_USER] = $sLogin; //Token $sToken = $this->createToken(); $_SESSION[self::SESSION_TOKEN] = $sToken; $this->setTokenCookie($sToken); $this->syncSession(); } public function register($asData) { $sLogin = strtolower($asData['user']); $sPass = $asData['pass']; if($sLogin=='' || $sPass=='') { $this->addError('Empty mandatory fields (Nickname or password)'); } elseif(htmlspecialchars($sLogin, ENT_QUOTES)!=$sLogin) { $this->addError('Nickname: HTML characters are forbidden'); } elseif($this->oMySql->selectRow(MySqlManager::USERS_TABLE, array('user'=>$sLogin))) { $this->addError('Nickname: This is already a user called by that name, choose a different one'); } else { $asData['pass'] = self::encryptPassword($sPass); $iUserId = $this->oMySql->insertRow(MySqlManager::USERS_TABLE, $asData); return $this->logMeIn($sLogin, $sPass); } return false; } public function logMeIn($sLogin, $sPass) { $bResult = false; $asUser = $this->oMySql->selectRow(MySqlManager::USERS_TABLE, array('user'=>$sLogin)); if(!$asUser) { $this->addError('Utilisateur inconnu'); } elseif(!$this->checkPassword($sPass, $asUser['pass'])) { $this->addError('mot de pass incorrect'); } else { $this->setSession($asUser[MySqlManager::getId(MySqlManager::USERS_TABLE)], $sLogin); $bResult = true; } return $bResult; } public function isLogguedIn() { $bLogguedIn = false; if($this->iUserId && $this->sLogin && $this->sToken) { //check if token is set and valid if($this->checkToken()) { //Check if user got a actual account in the database $bLogguedIn = $this->checkAccount($this->sLogin, $this->iUserId); } else { $this->addError('Authentication problem, please sign in again'); } } return $bLogguedIn; } private function checkAccount($sUserName, $iUserId=0) { $asConstraints = array('user'=>$sUserName); if($iUserId>0) { $asConstraints[MySqlManager::getId(MySqlManager::USERS_TABLE)] = $iUserId; } return $this->oMySql->selectValue(MySqlManager::USERS_TABLE, 'COUNT(1)', $asConstraints); } public function logMeOut() { $_SESSION = array(); $this->setTokenCookie('', -1); return session_destroy(); } private static function encryptPassword($sPass) { $sRandomText = 'F_RA-1H"2{bvj)5f?0sd3r#fP,K]U|w}hGiN@(sZ.sDe!7*x/:Mq+&'; for($iIndex=0; $iIndex < strlen($sPass); $iIndex++) { $sPass[$iIndex] = $sRandomText[$iIndex%strlen($sRandomText)] ^ $sPass[$iIndex]; } return md5($sPass); } private static function createToken() { return self::encryptPassword( $_SERVER['HTTP_USER_AGENT']. $_SERVER['REMOTE_ADDR']. $_SERVER['REQUEST_TIME']. strstr(microtime(), ' ', true). $_SERVER['SERVER_SIGNATURE']. $_SERVER['SERVER_ADMIN']); } //Session Token private static function setTokenCookie($sToken, $iTime=1) { setcookie(self::SESSION_TOKEN, $sToken, time()+60*60*24*$iTime); $_COOKIE[self::SESSION_TOKEN] = $sToken; } private function checkToken() { return ($this->sToken && array_key_exists(self::SESSION_TOKEN, $_COOKIE) && $_COOKIE[self::SESSION_TOKEN] == $this->sToken); } //Post Token private function refreshPostToken() { $this->sPostToken = self::createToken(); $_SESSION[self::SESSION_POST_TOKEN] = $this->sPostToken; } public function getNewPostToken() { $this->refreshPostToken(); return $this->sPostToken; } public function checkPostToken($sPostToken) { return ($this->sPostToken && $sPostToken!='' && $sPostToken == $this->sPostToken); } private static function checkPassword($sClearPass, $sEncodedPass) { return self::encryptPassword($sClearPass) == $sEncodedPass; } } class Mask extends PhpObject { public $sMaskName; public $sFilePath; private $sMask; private $asTags; private $asPartsSource; private $aoInstances; const MASK_FOLDER = 'mask/'; const START_TAG = 'START'; const END_TAG = 'END'; const TAG_MARK = '#'; public function __construct($sFileName='') { //init parent::__construct(); $this->sMaskName = ''; $this->sFilePath = ''; $this->sMask = ''; $this->asTags = array(); $this->asPartsSource = array(); $this->aoInstances = array(); $this->sFilePath = ''; //load file if($sFileName!='') { $this->initFile($sFileName); } } public function initFile($sFileName) { $sFilePath = self::MASK_FOLDER.$sFileName.'.html'; if(file_exists($sFilePath)) { $this->sFilePath = $sFilePath; $sSource = file_get_contents($this->sFilePath); $this->initMask($sFileName, $sSource); } else { $this->addError('Fichier introuvable à l\'adresse : '.$sFilePath); } } public function initFileFromString($sSource, $sPartName='', $iInstanceNb=0) { $this->initMask($sPartName.' (from row) '.$iInstanceNb, $sSource); } private function initMask($sMaskName, $sSource) { $this->sMaskName = $sMaskName; $this->sMask = $sSource; $this->setParts(); } private function setParts() { while(preg_match('/\<\!-- \[PART\] (?P\S+) \[START\] --\>/', $this->sMask, $asMatch)) { $sPartName = $asMatch['part']; $this->asPartsSource[$sPartName] = $this->getCleanPart($sPartName); $this->aoInstances[$sPartName] = array(); } } private function getCleanPart($sPartName) { $iStartPos = $this->getPartStartPos($sPartName); $iEndPos = $this->getPartEndPos($sPartName); $sPart = substr($this->sMask, $iStartPos, $iEndPos-$iStartPos); $sExtendedPart = $this->getPartPattern($sPartName, self::START_TAG).$sPart. $this->getPartPattern($sPartName, self::END_TAG); $this->sMask = str_replace($sExtendedPart, $this->getPartTagPattern($sPartName), $this->sMask); return $sPart; } private function getPartStartPos($sPartName) { $sPartStartPattern = $this->getPartPattern($sPartName, self::START_TAG); return strpos($this->sMask, $sPartStartPattern) + strlen($sPartStartPattern); } private function getPartEndPos($sPartName) { $sPartEndPattern = $this->getPartPattern($sPartName, self::END_TAG); return strpos($this->sMask, $sPartEndPattern); } private function getPartPattern($sPartName, $sAction) { return ''; } private function getPartTagPattern($sPartName, $bMark=true) { $sPartTag = 'PART '.$sPartName; return $bMark?$this->addTagMark($sPartTag):$sPartTag; } public function addInstance($sPartName, $asTags) { $this->newInstance($sPartName); foreach($asTags as $sTagName=>$sTagValue) { $this->setInstanceTag($sPartName, $sTagName, $sTagValue); } } public function newInstance($sPartName) { //Finding the part $oMask = &$this->findPart($this, $sPartName); //Retrieving source html $sPartSource = $oMask->asPartsSource[$sPartName]; //Creating new instance $oInstance = new Mask(); $oInstance->initFileFromString($sPartSource, $sPartName); $oMask->aoInstances[$sPartName][] = $oInstance; } public function setInstanceTag($sPartName, $sTagName, $sTagValue) { $oMask = &$this->findPart($this, $sPartName); $oMask->getCurrentInstance($sPartName)->setTag($sTagName, $sTagValue); } private function &findPart($oMask, $sPartName) { if(array_key_exists($sPartName, $oMask->aoInstances)) { return $oMask; } else //not tested { foreach($oMask->aoInstances as $sLevelPartName=>$aoInstances) { if(!empty($aoInstances)) { //take last instances return $this->findPart($oMask->getCurrentInstance($sLevelPartName), $sPartName); } } } $this->addError('No part found : '.$sPartName); } private function getCurrentInstance($sPartName) { if(!empty($this->aoInstances[$sPartName])) { return end($this->aoInstances[$sPartName]); } else { return false; } } public function setTag($sTagName, $sTagValue) { $this->asTags[$sTagName] = $sTagValue; } public function getMask() { $sCompletedMask = $this->sMask; //build parts foreach($this->aoInstances as $sPart=>$aoParts) { $sTagValue = ''; foreach($aoParts as $oInstance) { $sTagValue .= $oInstance->getMask(); } $this->setTag($this->getPartTagPattern($sPart, false), $sTagValue); } //replace tags if(!empty($this->asTags)) { $asTags = $this->addTagMark(array_keys($this->asTags)); $sCompletedMask = str_replace($asTags, $this->asTags, $sCompletedMask); } return $sCompletedMask; } private function addTagMark($oData) { return array_map_encapsulate($oData, self::TAG_MARK); } } class MyThoughts extends PhpObject { //Constants const URL_DATE_FORMAT = 'Ymd'; const LAYOUT_DATE_FORMAT = 'F \t\h\e jS, Y'; const MYSQL_DATE_FORMAT = 'Y-m-d'; const LAYOUT_TIME_FORMAT = 'G:i'; const WELCOME_MSG_FILE = 'welcome'; //settings const SETTING_LAYOUT = 'layout'; const LAYOUT_ONE_PAGE = '1'; const LAYOUT_TWO_PAGES = '2'; const SETTING_FONT = 'font'; const FONT_THOUGHTS = 'thoughts'; const FONT_ARIAL = 'Arial'; const FONT_VERDANA = 'Verdana'; const SETTING_SIZE = 'Size'; const SIZE_16 = '16'; const SIZE_18 = '18'; const SIZE_20 = '20'; //Objects private $oMySql; private $oSession; private $oCalendar; private $asSettings; //Masks private $oMainMask; private $oPageMask; private $oMenuMask; function __construct() { parent::__construct(); $this->oMySql = new MySqlManager(); $this->oSession = new Session($this->oMySql); $this->oCalendar = new Calendar($this->oMySql, $this->oSession); $this->oMainMask = new Mask('index'); $this->oPageMask = new Mask(); $this->oMenuMask = new Mask(); $this->asSettings = array(); } public function register($sLogin, $sPass) { $asData = array('user'=>$sLogin, 'pass'=>$sPass); $bRegistered = $this->oSession->register($asData); if($bRegistered) { $this->addThought(file_get_contents(self::WELCOME_MSG_FILE)); } return $bRegistered; } public function logMeIn($sLogin, $sPass) { return $this->oSession->logMeIn($sLogin, $sPass); } public function logMeOut() { $this->oSession->logMeOut(); self::relocate(); } public function isLogguedIn() { return $this->oSession->isLogguedIn(); } public function checkPostToken($sPostToken) { return $this->oSession->checkPostToken($sPostToken); } public function setPage($sPage) { $this->oPageMask->initFile($sPage); } public function setPageTitle($sTitle) { $this->oMainMask->setTag('title', $sTitle); } public function setCalendarDate($iYear=0, $iMonth=0) { $this->oCalendar->setDate($iYear, $iMonth); } private static function relocate($sPage='', $asVar=array()) { $asVar['p'] = $sPage; header('Location:index.php?'.implodeAll($asVar, '=', '&')); die(); } public function addThought($sThought) { $asThought = array('thought'=>$this->encodeThought($sThought)); $asThought[MySqlManager::getId(MySqlManager::USERS_TABLE)] = $this->oSession->getUserId(); return $this->oMySql->insertRow(MySqlManager::THOUGHTS_TABLE, $asThought); } public function updateThought($iThoughtId, $sThought) { $asValues = array('thought'=>$this->encodeThought($sThought)); $asConstraints = array( MySqlManager::getId(MySqlManager::THOUGHTS_TABLE)=>$iThoughtId, MySqlManager::getId(MySqlManager::USERS_TABLE)=>$this->oSession->getUserId()); $this->oMySql->updateRow(MySqlManager::THOUGHTS_TABLE, $asConstraints, $asValues); } private function encodeThought($sthought) { return base64_encode(serialize(explode("\n", $this->shuffleText($sthought)))); } private function decodeThought($sEncodedThought) { return $this->shuffleText(implode("\n", unserialize(base64_decode($sEncodedThought)))); } private function shuffleText($sText) { $sRandomText = "let's_mess%a&bit;with~it,!just§for¨the^sake*of-it"; for($iIndex=0; $iIndex < strlen($sText); $iIndex++) { $sText[$iIndex] = $sRandomText[$iIndex%strlen($sRandomText)] ^ $sText[$iIndex]; } return $sText; } public function activateMenu() { $this->oMenuMask->initFile('menu'); } //settings public static function getSettingsList() { //TODO Save on database (param table) return array(self::SETTING_FONT, self::SETTING_SIZE, self::SETTING_LAYOUT); } private static function getDefaultSetting($sSettingName) { switch($sSettingName) { case self::SETTING_FONT: return self::FONT_THOUGHTS; case self::SETTING_LAYOUT: return self::LAYOUT_ONE_PAGE; } return false; } private function getSetting($sSettingName) { if(!array_key_exists($sSettingName, $this->asSettings)) { $asConstraint = array(MySqlManager::getText(MySqlManager::SETTINGS_TABLE)=>$sSettingName, MySqlManager::getId(MySqlManager::USERS_TABLE)=>$this->oSession->getUserId()); $oValue = $this->oMySql->selectValue(MySqlManager::SETTINGS_TABLE, 'value', $asConstraint); $this->asSettings[$sSettingName] = (!$oValue)?self::getDefaultSetting($sSettingName):$oValue; } return $this->asSettings[$sSettingName]; } private function setSetting($sValue, $sSettingName) { $this->oMySql->insertUpdateRow(MySqlManager::SETTINGS_TABLE, array('setting'=>$sSettingName, MySqlManager::getId(MySqlManager::USERS_TABLE)=>$this->oSession->getUserId()), array('value'=>$sValue)); } public function setSettings($asSettings) { array_walk($asSettings, array($this, 'setSetting')); } /* Pages */ public function logonPage($sPreviousLogin) { $this->setPageTitle('Login'); $this->setPage('logon'); $sPreviousLogin = ($sPreviousLogin=='')?'':$sPreviousLogin; $this->oPageMask->setTag('login', $sPreviousLogin); } public function writingPage($iThoughtId=0) { $sThought = ''; $iThoughtTime = ''; if($iThoughtId!=0) { //load a thought $asConstraints = array( MySqlManager::getId(MySqlManager::THOUGHTS_TABLE)=>$iThoughtId, MySqlManager::getId(MySqlManager::USERS_TABLE)=>$this->oSession->getUserId()); $asThought = $this->oMySql->selectRow(MySqlManager::THOUGHTS_TABLE, $asConstraints); $sThought = $this->decodeThought($asThought['thought']); $iThoughtTime = 'Saved at '.date(self::LAYOUT_TIME_FORMAT, strtotime($asThought['led'])); } $this->setPage('write_thought'); $this->oPageMask->setTag('font', $this->getSetting(self::SETTING_FONT)); $this->oPageMask->setTag('size', $this->getSetting(self::SETTING_SIZE)); $this->oPageMask->setTag('thought', $sThought); $this->oPageMask->setTag('thought_id', $iThoughtId); $this->oPageMask->setTag('last_saved', $iThoughtTime); $this->setPageTitle('Talk to me'); } public function readingPage($iTimeStamp=0) { if($iTimeStamp==0) { $iTimeStamp = strtotime('now'); } $sMySqlDate = date(self::MYSQL_DATE_FORMAT, $iTimeStamp); $sLayoutDate = date(self::LAYOUT_DATE_FORMAT, $iTimeStamp); $asConstraints = array('DATE(led)'=>$sMySqlDate, MySqlManager::getId(MySqlManager::USERS_TABLE)=>$this->oSession->getUserId()); $asThougths = $this->oMySql->selectRows(array('from'=>MySqlManager::THOUGHTS_TABLE, 'constraint'=>$asConstraints)); $this->setPage('read_thought'); $this->setPageTitle('Thoughts on '.$sLayoutDate); $this->oPageMask->setTag('date', $sLayoutDate); foreach($asThougths as $asThought) { $asThoughtParagraphs = explode("\n", $this->decodeThought($asThought['thought'])); $this->oPageMask->newInstance('THOUGHT'); $this->oPageMask->setInstanceTag('THOUGHT', 'time', date(self::LAYOUT_TIME_FORMAT, strtotime($asThought['led']))); foreach($asThoughtParagraphs as $sParagraph) { $asParagraphTags = array('thought_paragraph'=>$sParagraph); $this->oPageMask->addInstance('THOUGHT_PARA', $asParagraphTags); } } //calendar update $this->setCalendarDate(date('Y', $iTimeStamp), date('m', $iTimeStamp)); return (count($asThougths)>0); } public function settingsPage() { $this->setPage('settings'); $this->setPageTitle('Settings'); $asSettingsOptions = array( self::SETTING_LAYOUT => array( 'One extensible page' => self::LAYOUT_ONE_PAGE, 'Two Pages, Diary like' => self::LAYOUT_TWO_PAGES), self::SETTING_FONT => array( 'AES Crawl' => self::FONT_THOUGHTS, 'Arial' => self::FONT_ARIAL, 'Verdana' => self::FONT_VERDANA), self::SETTING_SIZE => array( '16pt' => self::SIZE_16, '18pt' => self::SIZE_18, '20pt' => self::SIZE_20)); foreach(self::getSettingsList() as $sSettingName) { $this->oPageMask->newInstance('SETTING'); $this->oPageMask->setInstanceTag('SETTING', 'setting_name', $sSettingName); $sUserSetting = $this->getSetting($sSettingName); foreach($asSettingsOptions[$sSettingName] as $sOptionName=>$sOptionValue) { if($sOptionValue == self::getDefaultSetting($sSettingName)) { $sOptionName .= ' (Default)'; } $sSelectedOption = ($sUserSetting==$sOptionValue)?'selected':''; $asSettingOptions = array( 'setting_option_value'=>$sOptionValue, 'setting_option_selected'=>$sSelectedOption, 'setting_option_name'=>$sOptionName); $this->oPageMask->addInstance('SETTING_OPTION', $asSettingOptions); } } } /* Final processes */ private function collectErrors() { $asErrors = array_merge($this->getCleanErrorStack(), $this->oMySql->getCleanErrorStack(), $this->oSession->getCleanErrorStack(), $this->oCalendar->getCleanErrorStack(), $this->oMainMask->getCleanErrorStack(), $this->oPageMask->getCleanErrorStack(), $this->oMenuMask->getCleanErrorStack()); //$asErrors = array_map('getCleanErrorStack', array($this, $this->oMySql, $this->oSession, $this->oCalendar, $this->oMainMask, $this->oPageMask, $this->oMenuMask)); //pre($asErrors, 'static error stock', true); $oErrorMask = new Mask(); if(!empty($asErrors)) { $oErrorMask->initFile('errors'); foreach($asErrors as $sError) { $oErrorMask->addInstance('ERROR', array('error'=>$sError)); } } return $oErrorMask->getMask(); } public function getPage() { $this->oMenuMask->setTag('calendar', $this->oCalendar->getCalendar()); $this->oMainMask->setTag('menu', $this->oMenuMask->getMask()); $this->oMainMask->setTag('content', $this->oPageMask->getMask()); $this->oMainMask->setTag('errors', $this->collectErrors()); $this->oMainMask->setTag('post_token', $this->oSession->getNewPostToken()); return $this->oMainMask->getMask(); } } class Calendar extends PhpObject { const CAL_YEAR = 'cy'; const CAL_MONTH = 'cm'; private $oMySql; private $oSession; private $oMask; private $iUserId; private $iYear; private $iMonth; function __construct($oMySql, $oSession) { parent::__construct(); $this->oMySql = $oMySql; $this->oSession = $oSession; $this->oMask = new Mask('calendar'); $this->iYear = 0; $this->iMonth = 0; } public function setDate($iYear=0, $iMonth=0) { if($iYear==0) { $iYear = date('Y'); } if($iMonth==0) { $iMonth = date('m'); } $this->iYear = $iYear; $this->iMonth = $iMonth; } private function getThoughts() { //TODO essayer avec selectRows $sQuery = "SELECT DATE_FORMAT(led, '%d') AS day FROM ".MySqlManager::THOUGHTS_TABLE." WHERE ".MySqlManager::getId(MySqlManager::USERS_TABLE)." = ".$this->oSession->getUserId()." AND YEAR(led) = ".$this->iYear." AND MONTH(led) = ".$this->iMonth." GROUP BY day ORDER BY day"; return $this->oMySql->getArrayQuery($sQuery, true); } private function getUpdatedLink($asParams) { $sCurrentVariables = $_SERVER['QUERY_STRING']; $asCurrentVariables = explode('&', $sCurrentVariables); foreach($asCurrentVariables as $sParam) { $sKey = strstr($sParam, '=', true); $sValue = substr(strstr($sParam, '='), 1); $asVariables[$sKey] = $sValue; } return '?'.implodeAll(array_merge($asVariables, $asParams), '=', '&'); } private function getLink($iOffset) { $iTimeStamp = mktime(0, 0, 0, $this->iMonth + $iOffset, 1, $this->iYear); return $this->getUpdatedLink(array(self::CAL_MONTH=>date('n', $iTimeStamp), self::CAL_YEAR=>date('Y', $iTimeStamp))); } private function setMaskItems() { //week starting on the sunday : offset = 0, monday : offset = 1 $iOffset = 1; //days in the month $iMonthLastDay = date('d', mktime(0, 0, 0, $this->iMonth+1, 0, $this->iYear)); $asDays = range(1, $iMonthLastDay); $iDayNb = 1 - date($iOffset?'N':'w', mktime(0, 0, 0, $this->iMonth, 1, $this->iYear)) + $iOffset; $iCalendarLastDay = $iMonthLastDay + (7 - date($iOffset?'N':'w', mktime(0, 0, 0, $this->iMonth+1, 0, $this->iYear))) + $iOffset; //days with thoughts $asThoughts = $this->getThoughts(); while($iDayNb < $iCalendarLastDay) { $iCurrentDayTimeStamp = mktime(0, 0, 0, $this->iMonth, $iDayNb, $this->iYear); $sItemDate = date('d', $iCurrentDayTimeStamp); //new week if(date('w', $iCurrentDayTimeStamp) == $iOffset) { $this->oMask->newInstance('WEEK'); } //day within month if(date('n', $iCurrentDayTimeStamp)==$this->iMonth) { $bThoughts = in_array($iDayNb, $asThoughts); $sItemClass = $bThoughts?'full':'empty'; $sItemLink = $bThoughts?$this->getUpdatedLink(array('d'=>date(MyThoughts::URL_DATE_FORMAT, $iCurrentDayTimeStamp), 'p'=>'r')):'#'; $sItemLinkTitle = $bThoughts?'See my thoughts on '.date(MyThoughts::LAYOUT_DATE_FORMAT, $iCurrentDayTimeStamp):''; } else { $sItemClass = 'disabled'; $sItemLink = '#'; $sItemLinkTitle = ''; } $this->oMask->addInstance('DAY', array('item_day'=>$sItemDate, 'item_class'=>$sItemClass, 'item_link'=>$sItemLink, 'item_link_title'=>$sItemLinkTitle)); $iDayNb++; } //column titles $asDayNames = array('1'=>'Mon', '2'=>'Tue', '3'=>'Wed', '4'=>'Thu', '5'=>'Fri', '6'=>'Sat', $iOffset?'7':'0'=>'Sun'); ksort($asDayNames); foreach($asDayNames as $sDayName) { $this->oMask->addInstance('TITLE', array('day_name'=>$sDayName)); } } public function getCalendar() { $sResult = ''; if($this->iYear!=0 && $this->iMonth!=0) { $this->oMask->setTag('link_prev', $this->getLink(-1)); $this->oMask->setTag('current_month', date('F', mktime(0, 0, 0, $this->iMonth, 1, $this->iYear))); $this->oMask->setTag('link_next', $this->getLink(1)); $this->setMaskItems(); $sResult = $this->oMask->getMask(); } return $sResult; } } function arrayKeyFilter($asArray, $sCallBack) { $asValidKeys = array_flip(array_filter(array_keys($asArray), $sCallBack)); return array_intersect_key($asArray, $asValidKeys); } function array_map_encapsulate($oData, $sChar) { if(is_array($oData)) { $asChar = array_fill(1, count($oData), $sChar); return array_combine(array_keys($oData), array_map('array_map_encapsulate', $oData, $asChar)); } else { return $sChar.$oData.$sChar; } } function implodeAll($asText, $sKeyValueSeparator='', $sRowSeparator='', $sKeyPre='', $sValuePost=false) { if($sValuePost===false) { $sValuePost = $sKeyPre; } $asCombinedText = array(); foreach($asText as $sKey=>$sValue) { $asCombinedText[] = $sKeyPre.$sKey.$sKeyValueSeparator.$sValue.$sValuePost; } return implode($sRowSeparator, $asCombinedText); } function cleanPost(&$asData) { //get rid of magic quotes if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) { cleanData($asData, 'stripslashes'); } } function cleanData(&$oData, $sCleaningFunc) { if(!is_array($oData)) { $oData = call_user_func($sCleaningFunc, $oData); } elseif(!empty($oData)) { $asKeys = array_map($sCleaningFunc, array_keys($oData)); $asValues = array_map($sCleaningFunc, $oData); $oData = array_combine($asKeys, $asValues); } } //debug function pre($sText, $sTitle='Test', $bDie=false, $bLog=false) { if($bLog) { file_put_contents('log', ($sTitle!=''?$sTitle." :\n":'').print_r($sText, true)."\n\n"); } echo '
'.$sTitle.'
'.print_r($sText, true).'
'; if($bDie) { die('[die() called by the test function '.__FUNCTION__.'()]'); } } ?>