996 lines
25 KiB
PHP
Executable File
996 lines
25 KiB
PHP
Executable File
<?php
|
|
|
|
/**
|
|
* TODO List
|
|
* save before quit / read
|
|
* Signature automatique (ajouter dans settings)
|
|
* connexion : diary cover + cadenas
|
|
* writing pad : open book (2 pages) ou plusieurs feuilles superposées
|
|
* separate textarea / text layout
|
|
* all hovering / active images on the same one + positioning
|
|
* thougt layout ! replace " with image quote
|
|
*/
|
|
|
|
class PhpObject
|
|
{
|
|
private $asMessageStack;
|
|
private $iExtractMode;
|
|
|
|
const ERROR_TAB = 'error';
|
|
const WARNING_TAB = 'warning';
|
|
const MODE_ARRAY = 0;
|
|
const MODE_TEXT = 1;
|
|
const MODE_FILE = 2;
|
|
|
|
function __construct()
|
|
{
|
|
$this->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("</p><p>", $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', '<p style="font-weight:bold;">'.date('r')."</p><p>".$sErrorStack.'</p>', FILE_APPEND);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
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(Db::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(Db::USERS_TABLE, $asData);
|
|
return $this->logMeIn($sLogin, $sPass);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public function logMeIn($sLogin, $sPass)
|
|
{
|
|
$bResult = false;
|
|
$asUser = $this->oMySql->selectRow(Db::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[Db::getId(Db::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[Db::getId(Db::USERS_TABLE)] = $iUserId;
|
|
}
|
|
return $this->oMySql->selectValue(Db::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<part>\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 '<!-- [PART] '.$sPartName.' ['.$sAction.'] -->';
|
|
}
|
|
|
|
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 Db();
|
|
$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 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 updateThought($iThoughtId, $sThought)
|
|
{
|
|
$asValues = array('thought'=>$this->encodeThought($sThought));
|
|
$asConstraints = array( Db::getId(Db::THOUGHTS_TABLE)=>$iThoughtId,
|
|
Db::getId(Db::USERS_TABLE)=>$this->oSession->getUserId());
|
|
$this->oMySql->updateRow(Db::THOUGHTS_TABLE, $asConstraints, $asValues);
|
|
}
|
|
|
|
|
|
|
|
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(Db::getText(Db::SETTINGS_TABLE)=>$sSettingName, Db::getId(Db::USERS_TABLE)=>$this->oSession->getUserId());
|
|
$oValue = $this->oMySql->selectValue(Db::SETTINGS_TABLE, 'value', $asConstraint);
|
|
$this->asSettings[$sSettingName] = (!$oValue)?self::getDefaultSetting($sSettingName):$oValue;
|
|
}
|
|
return $this->asSettings[$sSettingName];
|
|
}
|
|
|
|
private function setSetting($sValue, $sSettingName)
|
|
{
|
|
$this->oMySql->insertUpdateRow(Db::SETTINGS_TABLE, array('setting'=>$sSettingName, Db::getId(Db::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( Db::getId(Db::THOUGHTS_TABLE)=>$iThoughtId,
|
|
Db::getId(Db::USERS_TABLE)=>$this->oSession->getUserId());
|
|
$asThought = $this->oMySql->selectRow(Db::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, Db::getId(Db::USERS_TABLE)=>$this->oSession->getUserId());
|
|
$asThougths = $this->oMySql->selectRows(array('from'=>Db::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();
|
|
}
|
|
|
|
}
|
|
|
|
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 ".Db::THOUGHTS_TABLE."
|
|
WHERE ".Db::getId(Db::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 '<fieldset class="rounded"><legend class="rounded">'.$sTitle.'</legend><pre>'.print_r($sText, true).'</pre></fieldset>';
|
|
if($bDie)
|
|
{
|
|
die('[die() called by the test function '.__FUNCTION__.'()]');
|
|
}
|
|
}
|
|
?>
|