first draft, only one (main) page

This commit is contained in:
2014-06-02 11:53:18 +02:00
parent c25d541a7d
commit 8be00a6c46
17 changed files with 1312 additions and 33 deletions

234
classmanagement.php Normal file
View File

@@ -0,0 +1,234 @@
<?php
/**
* Manage includes
* @author franzz
* @version 1.0
*/
class ClassManagement extends PhpObject
{
const INC_FOLDER = 'inc/';
const INC_EXT = '.php';
const SETTINGS_FILE = 'settings.php';
const TOOLBOX_CLASS = 'toolbox';
private $asIncFiles;
function __construct($sMainClass)
{
parent::__construct(__CLASS__, true);
$this->asIncFiles = array();
//try to include default files
$this->incFile(self::SETTINGS_FILE);
$this->incClass(self::TOOLBOX_CLASS);
//Include main class
$this->incClass($sMainClass);
}
function __destruct()
{
parent::__destruct();
}
public function incClass($sClassName)
{
return $this->incFile(self::INC_FOLDER.$sClassName.self::INC_EXT);
}
public function incFile($sFilePath, $bMandatory=true)
{
$bIncluded = false;
if(!in_array($sFilePath, $this->asIncFiles))
{
$sMissingFile = 'File "'.$sFilePath.'" missing.';
if(file_exists($sFilePath))
{
$bIncluded = require_once($sFilePath);
$this->asIncFiles[] = $sFilePath;
}
elseif($bMandatory)
{
die($sMissingFile.' Stopping process.');
}
else
{
$this->addError($sMissingFile);
}
}
return $bIncluded;
}
}
/**
*
* @author franzz
* @version 1.0a
*/
class PhpObject
{
//Log file name
const LOG_FILENAME = 'log.html';
//Message types
const NOTICE_TAB = 'Notice';
const WARNING_TAB = 'Warning';
const ERROR_TAB = 'Error';
const ALL_TAB = 'All';
//Extraction mode
const MODE_ARRAY = 0;
const MODE_TEXT = 1;
const MODE_HTML = 2;
const MODE_FILE = 3;
//Class variables
private $asMessageStack;
private $iExtractMode;
private $sChildClass;
protected $bDebug;
function __construct($sClass='', $bDebug=false, $iExtractMode=self::MODE_FILE)
{
$this->resetMessageStack();
$this->iExtractMode = $iExtractMode;
$this->sChildClass = $sClass;
$this->bDebug = $bDebug;
}
private static function getLogPath()
{
return dirname(__FILE__).'/'.self::LOG_FILENAME;
}
private function resetMessageStack($sType=self::ALL_TAB)
{
if($sType==self::ALL_TAB)
{
$this->resetMessageStack(self::NOTICE_TAB);
$this->resetMessageStack(self::WARNING_TAB);
$this->resetMessageStack(self::ERROR_TAB);
}
else
{
$this->asMessageStack[$sType] = array();
}
}
protected function addNotice($sNotice)
{
$this->addMessage(self::NOTICE_TAB, $sNotice);
}
protected function addWarning($sWarning)
{
$this->addMessage(self::WARNING_TAB, $sWarning);
}
protected function addError($sError)
{
$this->addMessage(self::ERROR_TAB, $sError);
}
private function addMessage($sType, $sMessage)
{
$this->asMessageStack[$sType][] = $sMessage;
}
protected function getCleanMessageStack($sType=self::ALL_TAB)
{
$asMessages = ($sType==self::ALL_TAB)?$this->asMessageStack:$this->asMessageStack[$sType];
$this->resetMessageStack($sType);
return $this->glueMessages($asMessages);
}
protected function cleanMessageStack()
{
$sErrorStack = $this->getCleanMessageStack($this->bDebug?self::ALL_TAB:self::ERROR_TAB);
if($sErrorStack!='')
{
switch($this->iExtractMode)
{
case self::MODE_TEXT:
echo $sErrorStack;
break;
case self::MODE_HTML:
echo $sErrorStack;
break;
case self::MODE_ARRAY:
break;
case self::MODE_FILE:
@file_put_contents(self::getLogPath(), "\n\n".$this->sChildClass.' - '.date('r')."\n".$sErrorStack, FILE_APPEND);
break;
}
}
}
protected function getCleanMessageStacks($aoExtsources, $sType=self::ALL_TAB)
{
$aoExtsources[] = $this;
$aoMessages = array();
foreach($aoExtsources as $oExtSource)
{
$oMessages = $oExtSource->getCleanMessageStack($sType);
if($oMessages!='')
{
$aoMessages[get_class($oExtSource)] = $oMessages;
}
}
return $this->glueMessages($aoMessages);
}
private function glueMessages($asMessages)
{
switch($this->iExtractMode)
{
case self::MODE_TEXT:
$oMessageStack = self::recursiveImplode("\n", $asMessages);
break;
case self::MODE_HTML:
$oMessageStack = self::recursiveImplode('<br />', $asMessages);
break;
case self::MODE_ARRAY:
$oMessageStack = $asMessages;
break;
case self::MODE_FILE:
$oMessageStack = self::recursiveImplode("\n", $asMessages);
break;
}
return $oMessageStack;
}
private static function flattenMessageStack($asTab, $sGlobalKey='')
{
$asFlatTab = array();
foreach($asTab as $oKey=>$oRow)
{
$sKey = is_numeric($oKey)?$sGlobalKey:$oKey.' - ';
if(is_array($oRow))
{
$asFlatTab = array_merge($asFlatTab, self::flattenMessageStack($oRow, $sKey));
}
else
{
$asFlatTab[] = $sKey.$oRow;
}
}
return $asFlatTab;
}
private static function recursiveImplode($sGlue, $asTab)
{
$asTab = self::flattenMessageStack($asTab);
return implode($sGlue, $asTab);
}
function __destruct()
{
$this->cleanMessageStack();
}
}
?>

231
inc/mask.php Normal file
View File

@@ -0,0 +1,231 @@
<?php
/**
* Mask Reader
* @author franzz
*
*/
class Mask extends PhpObject
{
public $sMaskName;
public $sFilePath;
private $sMask;
private $asTags;
private $asPartsSource;
private $aoInstances;
const MASK_FOLDER = 'masks/';
const MASK_EXT = '.html';
const START_TAG = 'START';
const END_TAG = 'END';
const TAG_MARK = '[#]';
public function __construct($sFileName='')
{
//init
parent::__construct(__CLASS__, Settings::DEBUG);
$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 static function getMaskFile($sFileName)
{
return self::MASK_FOLDER.$sFileName.self::MASK_EXT;
}
public function initFile($sFileName)
{
$sFilePath = self::getMaskFile(basename($sFileName));
if(file_exists($sFilePath))
{
$this->sFilePath = $sFilePath;
$sSource = file_get_contents($this->sFilePath);
$this->initMask($sFileName, $sSource);
}
else
{
$this->addError('Fichier introuvable &agrave; 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\] --\>/u', $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 = mb_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 mb_strpos($this->sMask, $sPartStartPattern) + strlen($sPartStartPattern);
}
private function getPartEndPos($sPartName)
{
$sPartEndPattern = $this->getPartPattern($sPartName, self::END_TAG);
return mb_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 is a pointer)
$oMask = $this->findPart($this, $sPartName);
if(!$oMask) $this->addError('No part found : '.$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);
if(!$oMask) $this->addError('No part found : '.$sPartName);
$oMask->getCurrentInstance($sPartName)->setTag($sTagName, $sTagValue);
}
private function findPart($oMask, $sPartName)
{
if(array_key_exists($sPartName, $oMask->aoInstances))
{
return $oMask;
}
else //going deeper to find the part
{
foreach($oMask->aoInstances as $sLevelPartName=>$aoInstances)
{
if(!empty($aoInstances))
{
//take last instances
$oTmpMask = $this->findPart($oMask->getCurrentInstance($sLevelPartName), $sPartName);
if($oTmpMask) return $oTmpMask;
}
}
}
return false;
}
private function getCurrentInstance($sPartName)
{
if(!empty($this->aoInstances[$sPartName]))
{
return end($this->aoInstances[$sPartName]);
}
else
{
return false;
}
}
public function getTags()
{
$sSafeTagMark = preg_quote(self::TAG_MARK);
$sPattern = '/'.$sSafeTagMark.'(?P<tag>\w+)'.$sSafeTagMark.'/u';
preg_match_all($sPattern, $this->sMask, $asMatches);
return array_unique(array_filter($asMatches['tag']));
}
public function setTag($sTagName, $sTagValue)
{
$this->asTags[$sTagName] = $sTagValue;
}
public function setTags($asTags)
{
foreach($asTags as $sTagName=>$sTagValue) $this->setTag($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 ToolBox::array_map_encapsulate($oData, self::TAG_MARK);
}
}
?>

265
inc/resume.php Normal file
View File

@@ -0,0 +1,265 @@
<?php
class Resume extends PhpObject
{
//Resume constants
const VERSION = '1.0.0';
const DEFAULT_PAGE = 'home';
const LOG_FILE = 'log';
const PIC_PATH = 'images/pic.png';
const PUBLIC_KEY_LENGTH = 13;
const MAX_REQUEST_TIME = 10;
//Mask constants
const RANDOM_TAG_PREFIX = 'uniqid_';
const LOC_API_KEY = Settings::LOC_API_KEY;
//Variables
private $oClassManagement;
private $sLang;
private $oTranslator;
private $asMasks;
private $iLoadTime;
/**
* Constructor
* @param ClassManagement $oClassManagement
* @param string $sLang
*/
public function __construct($oClassManagement, $sLang='')
{
parent::__construct(__CLASS__, Settings::DEBUG);
$this->oClassManagement = $oClassManagement;
//Browser <> PHP <> MySql synchronization
date_default_timezone_set(Settings::TIMEZONE);
ini_set('default_charset', Settings::TEXT_ENC);
header('Content-Type: text/html; charset='.Settings::TEXT_ENC);
mb_internal_encoding(Settings::TEXT_ENC);
mb_http_output(Settings::TEXT_ENC);
mb_http_input(Settings::TEXT_ENC);
mb_language('uni');
mb_regex_encoding(Settings::TEXT_ENC);
$this->oClassManagement->incClass('mask');
$this->oClassManagement->incClass('translator');
$this->setLanguage($sLang);
$this->setMasks();
$this->setPageMasks(array('index'));
$this->setLoadTime();
$this->oTranslator = new Translator($this->getLanguage());
}
private function getLanguage()
{
return $this->sLang;
}
private function setLanguage($sLang='')
{
if($sLang!='') $this->sLang = $sLang;
else
{
//$_SERVER['REMOTE_ADDR'] = '193.106.178.41'; //Test Spain
//$_SERVER['REMOTE_ADDR'] = '160.92.167.193'; //Test France
//$_SERVER['REMOTE_ADDR'] = '74.125.230.216'; //Test US
$asIpInfo = json_decode(file_get_contents('http://api.ipinfodb.com/v3/ip-country/?key='.self::LOC_API_KEY.'&format=json&ip='.$_SERVER['REMOTE_ADDR']), true);
if($asIpInfo['statusCode'] == 'OK') $this->sLang = $asIpInfo['countryCode'];
}
}
private function setLoadTime()
{
$this->iLoadTime = time();
}
private function getLoadTime()
{
return $this->iLoadTime;
}
private function setMasks()
{
//List all available masks
$asMaskPaths = glob(Mask::getMaskFile('*'));
$this->asMasks = array_map('basename', $asMaskPaths, array_fill(1, count($asMaskPaths), Mask::MASK_EXT));
}
private function setPageMasks($asNonMasks)
{
//Exclude structure pages
foreach($this->asMasks as $sMask)
{
$iIndex = array_search($sMask, $asNonMasks);
if($iIndex === false) $this->asPageMasks[] = $sMask;
}
}
private function isAccessiblePage($sPageName)
{
return in_array($sPageName, $this->asPageMasks);
}
public function getPage($sPageName, $bForceNoJson=false, $asForceTags=array())
{
$oResult = null;
if(in_array($sPageName, $this->asMasks))
{
//Create Mask
$oMask = new Mask($sPageName);
//Fill in with translated texts
$asTags = $oMask->getTags();
$iRandPrefixLen = mb_strlen(self::RANDOM_TAG_PREFIX);
foreach($asTags as $sTag)
{
$sTagValue = '';
if(array_key_exists($sTag, $asForceTags))
{
$sTagValue = $asForceTags[$sTag];
}
elseif(mb_substr($sTag, 0, $iRandPrefixLen) == self::RANDOM_TAG_PREFIX)
{
$sTagValue = uniqid();
}
else
{
$sTagValue = $this->oTranslator->getTranslation($sTag);
}
$oMask->setTag($sTag, $sTagValue);
}
//Page specific postprocessing
$asVars = array();
switch($sPageName)
{
case 'index':
$oMask->setTag('encoding', Settings::TEXT_ENC);
break;
}
//Get final mask
$oResult = $oMask->getMask();
//Add title if this page is one of the site page
if($this->isAccessiblePage($sPageName))
{
$oResult = array('title'=>$sPageName, 'page'=>$oResult, 'vars'=>$asVars);
}
}
return (!$bForceNoJson && $this->isAccessiblePage($sPageName))?self::jsonExport($oResult):$oResult;
}
public function getJavascript()
{
//Build picture key
$sPublicKey = uniqid();
$sSecretKey = $this->getLoadTime();
list($iWidth, $iHeight) = getimagesize(self::PIC_PATH);
file_put_contents(self::LOG_FILE, $sPublicKey.$sSecretKey."\n", FILE_APPEND);
//Display javascript functions
$asResult = array();
$asResult[] = "var cConfigPage = 'index.php'";
$asResult[] = "var s = '$sPublicKey';";
$asResult[] = "var iPicWidth = $iWidth;";
$asResult[] = "var iPicHeight = $iHeight;";
$asResult[] = file_get_contents('jquery/jquery.functions.js');
return implode("\n", $asResult);
}
public function getPic($sSerial)
{
if($this->checkSerial($sSerial))
{
header('Content-Type: image/jpeg');
return file_get_contents(self::PIC_PATH);
}
else
{
header('HTTP/1.1 403 Forbidden');
}
}
public function sendEmail($sName, $sEmail, $sSubject, $sMsg)
{
$sResult = '';
if($sName!='' && $sEmail!='' && $sSubject!='' && $sMsg!='')
{
//Message
$sHtmlMessage = 'From: '.$sName."<br />".
'Email: '.$sEmail."<br /><br />".
'Subject: '.$sSubject."<br />".
'Message: <br /><br />'.str_replace("\n", '<br />', $sMsg);
$sPlainMessage = strip_tags(str_replace('<br />', "\n", $sHtmlMessage));
//Email
$iBoundary = uniqid("HTMLEMAIL");
$sHeaders = 'From: Contact CV <www-data@lutran.fr>'."\r\n".
'Reply-To: Contact CV <www-data@lutran.fr>'."\r\n".
'Cc: Julien Lutran <julien@lutran.fr>'."\r\n".
'MIME-Version: 1.0'."\r\n".
'Content-Type: multipart/alternative;'.
'boundary = '.$iBoundary."\r\n\r\n".
'MIME encoded Message'.
'--'.$iBoundary."\r\n".
'Content-Type: text/plain; charset=UTF-8'."\r\n".
'Content-Transfer-Encoding: base64'."\r\n\r\n".
chunk_split(base64_encode($sPlainMessage)).
'--'.$iBoundary."\r\n".
'Content-Type: text/html; charset=UTF-8'."\r\n".
'Content-Transfer-Encoding: base64'."\r\n\r\n".
chunk_split(base64_encode($sHtmlMessage));
//Store in case email fails
@file_put_contents('log.html', '<br />----<br /><br />'.$sHtmlMessage, FILE_APPEND);
//Send
if(mail('julien.lutran@gmail.com', 'julien.lutran.fr - Contact Me Message', '', $sHeaders))
{
$sResult = 'ok';
}
else
{
$sResult = 'An unknown error occured.';
}
}
else
{
$sResult = 'An error occured: Some fields were empty.';
}
return $sResult;
}
private function checkSerial($sSerial)
{
$bResult = false;
if(strlen($sSerial)==self::PUBLIC_KEY_LENGTH && strpos($this->getAppPath(), $_SERVER['HTTP_REFERER'])===0)
{
$sFileContent = file_get_contents(self::LOG_FILE);
$asKeys = array_filter(explode("\n", $sFileContent));
foreach($asKeys as $sKey)
{
$iOffset = $this->getLoadTime() - substr($sKey, self::PUBLIC_KEY_LENGTH);
if($sSerial == substr($sKey, 0, self::PUBLIC_KEY_LENGTH) && $iOffset < self::MAX_REQUEST_TIME)
{
$bResult = true;
file_put_contents(self::LOG_FILE, str_replace($sKey."\n", '', $sFileContent));
break;
}
}
}
return $bResult;
}
private static function getAppPath()
{
$sAppPath = 'http://'.str_replace(array('http://', 'https://'), '', $_SERVER['SERVER_NAME'].dirname($_SERVER['SCRIPT_NAME']));
$sAppPath = $sAppPath.(substr($sAppPath, -1)!='/'?'/':'');
return $sAppPath;
}
}
?>

223
inc/toolbox.php Normal file
View File

@@ -0,0 +1,223 @@
<?php
/**
* ToolBox - Only static functions missing from php librairy
* @author franzz
*/
class ToolBox
{
public static function cleanPost(&$asData)
{
//get rid of magic quotes
if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
{
$asData = self::cleanData($asData, 'stripslashes');
}
}
public static function cleanData($oData, $sCleaningFunc)
{
if(!is_array($oData))
{
return call_user_func($sCleaningFunc, $oData);
}
elseif(count($oData)>0)
{
$asCleaningFunc = array_fill(1, count($oData), $sCleaningFunc);
$asKeys = array_map(array('self', 'cleanData'), array_keys($oData), $asCleaningFunc);
$asValues = array_map(array('self', 'cleanData'), $oData, $asCleaningFunc);
return array_combine($asKeys, $asValues);
}
}
public static function fixGlobalVars($argv)
{
//Add CLI arguments
if(defined('STDIN')) mb_parse_str(implode('&', array_slice($argv, 1)), $_GET);
//Add Server Name
$sServerName = array_key_exists('SERVER_NAME', $_SERVER)?$_SERVER['SERVER_NAME']:$_SERVER['PWD'];
$sAppPath = 'http://'.str_replace('http://', '', $sServerName.dirname($_SERVER['SCRIPT_NAME']));
$_GET['serv_name'] = $sAppPath.(mb_substr($sAppPath, -1)!='/'?'/':'');
}
public static 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('self', 'array_map_encapsulate'), $oData, $asChar));
}
else
{
return $sChar.$oData.$sChar;
}
}
public static function capitalizeWords($acText, $sCharList = '')
{
// Use ucwords if no delimiters are given
if($sCharList=='')
{
return Toolbox::mb_ucwords($acText);
}
// Go through all characters
$capitalizeNext = true;
$max = mb_strlen($acText);
for ($i = 0; $i < $max; $i++)
{
if(mb_strpos($sCharList, $acText[$i]) !== false)
{
$capitalizeNext = true;
}
elseif($capitalizeNext)
{
$capitalizeNext = false;
$acText[$i] = mb_strtoupper($acText[$i]);
}
}
return $acText;
}
public static function createThumbnail($sInPath, $iMaxWidth, $iMaxHeight, $sOutPath='', $bDeleteIn=false, $asImageExts=array('jpg', 'jpeg', 'gif', 'png'))
{
$asResult = array('error'=>'');
//Look up the extension to choose the image creator
//TODO use MIME types
$sInInfo = pathinfo($sInPath);
$sInName = mb_strtolower($sInInfo['basename']);
$sImageExt = mb_strtolower($sInInfo['extension']);
$sImageExt = ($sImageExt=='jpg')?'jpeg':$sImageExt;
//New Destination folder
if($sOutPath=='') $sOutPath = $sInPath;
elseif(mb_substr($sOutPath, -1)=='/') $sOutPath .= $sInName;
//New sizes
if(in_array($sImageExt, $asImageExts))
{
list($iWidth, $iHeight) = getimagesize($sInPath);
if($iWidth > $iMaxWidth || $iHeight > $iMaxHeight)
{
$dResizeDeltaWidth = $iWidth - $iMaxWidth;
$dResizeDeltaHeight = $iHeight - $iMaxHeight;
if($dResizeDeltaWidth > $dResizeDeltaHeight)
{
$iResizedWidth = $iMaxWidth;
$iResizedHeight = ($iResizedWidth / $iWidth) * $iHeight;
}
else
{
$iResizedHeight = $iMaxHeight;
$iResizedWidth = ($iResizedHeight / $iHeight) * $iWidth;
}
//create image from source
$oSource = call_user_func('imagecreatefrom'.$sImageExt, $sInPath);
//Resize
$oThumb = imagecreatetruecolor($iResizedWidth, $iResizedHeight);
imagecopyresized($oThumb, $oSource, 0, 0, 0, 0, $iResizedWidth, $iResizedHeight, $iWidth, $iHeight);
//Save
if(file_exists($sOutPath)) unlink($sOutPath);
if(!call_user_func_array('image'.$sImageExt, array($oThumb, $sOutPath)))
{
$asResult['error'] = 'Unable to create thumbnail : '.$sOutPath;
}
}
elseif($sInPath != $sOutPath)
{
$iResizedWidth = $iWidth;
$iResizedHeight = $iHeight;
if(!copy($sInPath, $sOutPath)) $asResult['error'] = 'Copy failed from '.$sInPath.' to '.$sOutPath;
}
$asResult['width'] = $iResizedWidth;
$asResult['height'] = $iResizedHeight;
$asResult['out'] = $sOutPath;
}
else $asResult['error'] = 'Wrong file type';
if($bDeleteIn && $asResult['error']=='' && $sInPath != $sOutPath) unlink($sInPath);
return $asResult;
}
public static function utf8_compliant($sText)
{
if(strlen($sText) == 0) return true;
return (preg_match('/^.{1}/us', $sText, $ar) == 1);
}
public static function mb_ucwords($sText)
{
return mb_convert_case($sText, MB_CASE_TITLE, "UTF-8");
}
public static function file_get_contents_utf8($oFile)
{
$sContent = file_get_contents($oFile);
return mb_convert_encoding($sContent, 'UTF-8', mb_detect_encoding($sContent, 'UTF-8, ISO-8859-1', true));
}
public static function rgbToHex($R, $G, $B)
{
$R = dechex($R);
if(strlen($R)<2) $R='0'.$R;
$G = dechex($G);
if(strlen($G)<2) $G='0'.$G;
$B = dechex($B);
if(strlen($B)<2) $B='0'.$B;
return $R.$G.$B;
}
public static function setCookie($sCookieName, $sCookieValue, $iDays)
{
$iTimeLimit = time()+60*60*24*$iDays;
setcookie($sCookieName, $sCookieValue, $iTimeLimit);
}
}
/* Debug */
function pre($sText, $sTitle='Test', $bDie=false, $sMode='log')
{
$sLog = '<fieldset class="rounded">
<legend class="rounded">'.$sTitle.'</legend>
<pre>'.print_r($sText, true).'</pre>
</fieldset>';
switch($sMode)
{
case 'echo':
echo $sLog;
break;
case 'return':
if($bDie) echo $sLog;
break;
case 'log':
file_put_contents('log.html', ($sTitle!=''?$sTitle." :\n":'').print_r($sText, true)."\n\n", FILE_APPEND);
break;
default:
break;
}
if($bDie)
{
die('die() called by the test function '.__FUNCTION__.'().'.($sMode=='log'?' Check log.html for details':''));
}
return $sLog;
}
function dlog($sText, $bDie=false, $sTitle='Test')
{
pre($sText, date('d/m/Y H:m:i').' - '.$sTitle, $bDie, 'log');
}
?>

112
inc/translator.php Normal file
View File

@@ -0,0 +1,112 @@
<?php
class Translator extends PhpObject
{
private $sLang;
private $asLanguages;
private $asTranslations; // [lang][key_word] = translation
const LANG_FOLDER = 'languages/';
const LANG_EXT = '.lang';
const LANG_SEP = '=';
const DEFAULT_LANG = 'FR';
public function __construct($sLang='')
{
parent::__construct(__CLASS__, Settings::DEBUG);
$this->asLanguages = array();
$this->asTranslations = array();
$this->loadLanguages();
$this->setLanguage($sLang);
}
public function setLanguage($sLang)
{
$this->sLang = in_array($sLang, $this->asLanguages)?$sLang:self::DEFAULT_LANG;
}
public function getTranslation($sTransKey, $sLang='')
{
$sTransText = false;
//Select language
if($sLang=='')
{
$sLang = $this->sLang;
}
//Look up in the selected language dictionary
if(in_array($sLang, $this->asLanguages) && array_key_exists($sTransKey, $this->asTranslations[$sLang]))
{
$sTransText = $this->asTranslations[$sLang][$sTransKey];
}
//Look up in the default language dictionary
elseif(array_key_exists($sTransKey, $this->asTranslations[self::DEFAULT_LANG]))
{
$this->addWarning('Missing translation in "'.$sLang.'" for the key "'.$sTransKey.'", falling back to "'.self::DEFAULT_LANG.'"');
$sTransText = $this->asTranslations[self::DEFAULT_LANG][$sTransKey];
}
else $this->addWarning('Missing translation in "'.$sLang.'" for the key "'.$sTransKey.'"');
return $sTransText;
}
public function getHashToPage($asMenuPages)
{
$asHashToPage = array();
foreach($asMenuPages as $sHash)
{
foreach($this->asLanguages as $sLang)
{
$asHashToPage[$this->getTranslation('menu_'.$sHash.'_key', $sLang)] = $sHash;
}
}
return $asHashToPage;
}
public function getPageToHash($asMenuPages)
{
$asPageToHash = array();
foreach($asMenuPages as $sHash)
{
$asPageToHash[$sHash] = $this->getTranslation('menu_'.$sHash.'_key');
}
return $asPageToHash;
}
private function loadLanguages()
{
//List all available languages
$asLangPaths = glob(self::getLangPath('*'));
$this->asLanguages = array_map('basename', $asLangPaths, array_fill(1, count($asLangPaths), self::LANG_EXT));
//Load languages
array_walk($this->asLanguages, array($this, 'loadLanguageFile'));
}
private function loadLanguageFile($sLang)
{
if(!in_array($sLang, $this->asTranslations))
{
$sData = file_get_contents(self::getLangPath($sLang));
$asData = explode("\n", $sData);
foreach($asData as $sTranslation)
{
$iSepPos = stripos($sTranslation, self::LANG_SEP);
if($iSepPos!==false)
{
$sTransKey = trim(substr($sTranslation, 0, $iSepPos));
$sTransText = /*htmlspecialchars(*/trim(substr($sTranslation, $iSepPos+1))/*, ENT_QUOTES)*/; //TODO when all entities have been removed
$this->asTranslations[$sLang][$sTransKey] = $sTransText;
}
}
}
}
private static function getLangPath($sLang)
{
return self::LANG_FOLDER.$sLang.self::LANG_EXT;
}
}
?>

View File

@@ -4,7 +4,7 @@
ob_start(); ob_start();
$sType = isset($_REQUEST['t'])?$_REQUEST['t']:''; $sType = isset($_REQUEST['t'])?$_REQUEST['t']:'';
$sSerial = isset($_GET['a'])?$_GET['a']:''; $sSerial = isset($_GET['s'])?$_GET['s']:'';
$sName = isset($_POST['name'])?$_POST['name']:''; $sName = isset($_POST['name'])?$_POST['name']:'';
$sEmail = isset($_POST['email'])?$_POST['email']:''; $sEmail = isset($_POST['email'])?$_POST['email']:'';
$sSubject = isset($_POST['subject'])?$_POST['subject']:''; $sSubject = isset($_POST['subject'])?$_POST['subject']:'';

70
index.php Normal file
View File

@@ -0,0 +1,70 @@
<?php
/*
Wedding Project
http://git.lutran.fr/wedding.git
Copyright (C) 2014 François Lutran
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses
*/
//Start buffering
ob_start();
require_once 'classmanagement.php';
$oClassManagement = new ClassManagement('resume');
ToolBox::cleanPost($_POST);
ToolBox::cleanPost($_GET);
ToolBox::cleanPost($_REQUEST);
//Add server name
$sAppPath = 'http://'.str_replace('http://', '', $_SERVER['SERVER_NAME'].dirname($_SERVER['SCRIPT_NAME']));
$_GET['serv_name'] = $sAppPath.(substr($sAppPath, -1)!='/'?'/':'');
//Available variables
$sAction = isset($_GET['a'])?$_GET['a']:'';
$sPage = isset($_GET['p'])?$_GET['p']:'index';
$sLang = isset($_GET['l'])?$_GET['l']:(isset($_COOKIE['l'])?$_COOKIE['l']:'');
$sSerial = isset($_GET['s'])?$_GET['s']:'';
$sName = isset($_POST['name'])?$_POST['name']:'';
$sEmail = isset($_POST['email'])?$_POST['email']:'';
$sSubject = isset($_POST['subject'])?$_POST['subject']:'';
$sMsg = isset($_POST['message'])?$_POST['message']:'';
//Initiate main class
$oResume = new Resume($oClassManagement, $sLang);
//Check requested action
switch($sAction)
{
case 'javascript':
$sResult = $oResume->getJavascript();
break;
case 'pic':
$sResult = $oResume->getPic($sSerial);
break;
case 'mail':
$sResult = $oResume->sendEmail($sName, $sEmail, $sSubject, $sMsg);
break;
default:
$sResult = $oResume->getPage($sPage);
break;
}
//Log and clean buffer
$sDebug = ob_get_clean();
if(Settings::DEBUG && $sDebug!='') dlog($sDebug, true);
echo $sResult;
?>

File diff suppressed because one or more lines are too long

View File

@@ -8,7 +8,7 @@ $(document).ready
var $Pic = $('#pic'); var $Pic = $('#pic');
$Pic.css('height', iPicHeight+'px'); $Pic.css('height', iPicHeight+'px');
$('.person').css('marginTop', Math.round(($('#header').height() - $Pic.outerHeight())/2)); $('.person').css('marginTop', Math.round(($('#header').height() - $Pic.outerHeight())/2));
$Pic.attr('src', cConfigPage+'?t=pic&a='+a); $Pic.attr('src', cConfigPage+'?a=pic&s='+s);
} }
//Fix IE //Fix IE
@@ -29,7 +29,7 @@ $(document).ready
Cufon.replace('h1', {fontFamily:'Candara'}); Cufon.replace('h1', {fontFamily:'Candara'});
Cufon.replace('.item h2', {fontFamily:'Puritan 2.0'}); Cufon.replace('.item h2', {fontFamily:'Puritan 2.0'});
Cufon.replace('.item h3', {fontFamily:'Puritan 2.0'}); Cufon.replace('.item h3', {fontFamily:'Puritan 2.0'});
Cufon.replace('h2.section_name', {fontFamily:'Hattori Hanzo Light'}); Cufon.replace('h2.section_name', {fontFamily:'Andika Basic'});
//Contact panel events //Contact panel events
$('#contact_me_btn, #contact_me_link').click $('#contact_me_btn, #contact_me_link').click
@@ -146,7 +146,7 @@ $(document).ready
$('a[href^=#]').click(function(e){$(this).jump(e);}); $('a[href^=#]').click(function(e){$(this).jump(e);});
//To-the-top Button //To-the-top Button
iProfileHeight = $('#profile').offset().top; iProfileHeight = $('#presentation').offset().top;
$(window).scroll $(window).scroll
( (
function() function()
@@ -203,7 +203,9 @@ $.prototype.jump = function(e)
var sElem = this.attr('href'); var sElem = this.attr('href');
if(sElem != '#') if(sElem != '#')
{ {
e.preventDefault(); if($(this).parent().parent().attr('id')!='menu') e.preventDefault();
else sElem += '_ln';
this.blur(); this.blur();
var $Elem = $(sElem); var $Elem = $(sElem);
var iOffSet = ($Elem.length>0)?($Elem.offset().top - 15):0; var iOffSet = ($Elem.length>0)?($Elem.offset().top - 15):0;

View File

1
languages/.htaccess Normal file
View File

@@ -0,0 +1 @@
deny from all

2
languages/EN.lang Normal file
View File

@@ -0,0 +1,2 @@
language=EN
name=TOTO

22
languages/FR.lang Normal file
View File

@@ -0,0 +1,22 @@
language=FR
header_name=Julien Lutran
header_title=Ingenieur Stockage SAN
menu_prez=Présentation
menu_prez_key=presentation
menu_xp=Expérience
menu_xp_key=experience
menu_lang=Langues
menu_lang_key=langues
menu_skills=Compétences
menu_skills_key=competences
menu_edu=Formation
menu_edu_key=formation
menu_switch_lang=English
menu_switch_lang_key=EN
card_xp=8 années d'experience
card_certif=Certification NetApp NCDA
card_edu=License Professionnelle
card_contact_me=Contactez-moi
profile_par1=Après 6 ans d'administration système sur les environnements de production de plusieurs grands comptes, j'ai eu l'opportunité d'intégrer une équipe d'ingénierie en infrastructure. Ce poste m'a permis de me spécialiser dans le domaine du stockage SAN et de concevoir des solutions pour des clients implantés à l'international
profile_par2=Toujours curieux et passionné par les nouvelles technologies, mon expérience me permet de m'adapter rapidement afin de relever avec succès chaque nouveau challenge professionnel que l'on peut me confier
profile_more_info=pour plus d'informations

43
log Normal file
View File

@@ -0,0 +1,43 @@
538a4c65e8f1e1401572453
538a4c8daea991401572493
538a4c91cd3cd1401572497
538a4c9cd4b741401572508
538a4df5a548d1401572853
538a4e1332b4e1401572883
538a4e18a4cbf1401572888
538a4e3a08c4b1401572922
538a4e40869781401572928
538a4e56e79591401572950
538a4e586a9ae1401572952
538a4e59244d71401572953
538a4ee9806811401573097
538a4f6c6107e1401573228
538a4f81e0c5d1401573249
538a4f89c124f1401573257
538a504d24efd1401573453
538a512251e7f1401573666
538a5180a63b31401573760
538a51ae726161401573806
538a51e8a53df1401573864
538a521b5fe1c1401573915
538a52b42e41f1401574068
538a52dbb9f871401574107
538a52dd785221401574109
538a52de1ef961401574110
538a52de923711401574110
538a52ded943a1401574110
538a52df278891401574111
538a540ca032e1401574412
538a5432014be1401574450
538a543951f711401574457
538a545a3426a1401574490
538a549e48e081401574558
538a54a9ee9141401574569
538a54d8d1ae61401574616
538c3979b77ca1401698681
538c3a10ced641401698832
538c3a1277b3a1401698834
538c47e69c3271401702374
538c4845a805c1401702469
538c4890535f21401702544
538c494a8de161401702730

View File

@@ -3,7 +3,7 @@
<head> <head>
<title>Julien Lutran </title> <title>Julien Lutran </title>
<meta name="robots" content="noimageindex" /> <meta name="robots" content="noimageindex" />
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /> <meta http-equiv="Content-Type" content="text/html; charset=[#]encoding[#]" />
<meta name="description" content="cv Julien Lutran" /> <meta name="description" content="cv Julien Lutran" />
<meta name="keywords" content="cv ingenieur stockage SAN" /> <meta name="keywords" content="cv ingenieur stockage SAN" />
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico" /> <link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico" />
@@ -19,16 +19,24 @@
<script src="jquery/cufon.fonts.js" type="text/javascript"></script> <script src="jquery/cufon.fonts.js" type="text/javascript"></script>
<script src="jquery/jquery.min.js" type="text/javascript"></script> <script src="jquery/jquery.min.js" type="text/javascript"></script>
<script src="jquery/jquery.tipsy.min.js" type="text/javascript"></script> <script src="jquery/jquery.tipsy.min.js" type="text/javascript"></script>
<script src="includes/config.php?t=javascript" type="text/javascript"></script> <script src="index.php?a=javascript" type="text/javascript"></script>
</head> </head>
<body> <body>
<div id="cv"> <div id="cv">
<div id="menu">
<div><a href="#[#]menu_prez_key[#]">[#]menu_prez[#]</a></div>
<div><a href="#[#]menu_xp_key[#]">[#]menu_xp[#]</a></div>
<div><a href="#[#]menu_lang_key[#]">[#]menu_lang[#]</a></div>
<div><a href="#[#]menu_skills_key[#]">[#]menu_skills[#]</a></div>
<div><a href="#[#]menu_edu_key[#]">[#]menu_edu[#]</a></div>
<div><a href="#[#]menu_switch_lang_key[#]">[#]menu_switch_lang[#]</a></div>
</div>
<div id="header" class="section header fixed"> <div id="header" class="section header fixed">
<div class="paperclip"></div> <div class="paperclip"></div>
<div class="person"> <div class="person">
<img oncontextmenu="return false;" id="pic" src="images/pic.gif" alt="Julien Lutran" /> <img oncontextmenu="return false;" id="pic" src="images/pic.gif" alt="Julien Lutran" />
<h1>Julien Lutran</h1> <h1>[#]header_name[#]</h1>
<h2><span>Ingenieur Stockage SAN</span></h2> <h2><span>[#]header_title[#]</span></h2>
</div> </div>
<div id="card"> <div id="card">
<ul class="card_buttons"> <ul class="card_buttons">
@@ -38,11 +46,11 @@
<li><a href="#" id="print" title="Print this page" class="tip_link"><img src="images/print.png" alt="Print"/></a></li> <li><a href="#" id="print" title="Print this page" class="tip_link"><img src="images/print.png" alt="Print"/></a></li>
</ul> </ul>
<ul class="card_items"> <ul class="card_items">
<li class="xp"><a href="#work">8 ann&eacute;es d'experience</a></li> <li class="xp"><a href="#work">[#]card_xp[#]</a></li>
<li class="globe"><a href="#certif">Certification NetApp NCDA</a></li> <li class="globe"><a href="#certif">[#]card_certif[#]</a></li>
<li class="university"><a href="#licence">License Professionnelle</a></li> <li class="university"><a href="#licence">[#]card_edu[#]</a></li>
</ul> </ul>
<a id="contact_me_btn" class="contact_me_btn clickable" href="#">Contactez-moi</a> <a id="contact_me_btn" class="contact_me_btn clickable" href="#">[#]card_contact_me[#]</a>
</div> </div>
</div> </div>
<div id="contact_me_box" class="section contact fixed hide"> <div id="contact_me_box" class="section contact fixed hide">
@@ -59,17 +67,17 @@
</form> </form>
</div> </div>
</div> </div>
<div id="profile" class="section profile fixed"> <div id="[#]menu_prez_key[#]_ln" class="section profile fixed">
<h2 class="section_name">Presentation</h2> <h2 class="section_name">[#]menu_prez[#]</h2>
<div class="section_items"> <div class="section_items">
<div class="item last_item"> <div class="item last_item">
<p>Après 6 ans d'administration système sur les environnements de production de plusieurs grands comptes, j'ai eu l'opportunité d'intégrer une équipe d'ingénierie en infrastructure. Ce poste m'a permis de me spécialiser dans le domaine du stockage SAN et de concevoir des solutions pour des clients implantés à l'international.</p> <p>[#]profile_par1[#].</p>
<p>Toujours curieux et passionné par les nouvelles technologies, mon expérience me permet de m'adapter rapidement afin de relever avec succès chaque nouveau challenge professionnel que l'on peut me confier.</p> <p>[#]profile_par2[#].</p>
<p class="last"><a id="contact_me_link" class="no_print_link" href="#contact_me">Contactez-moi <span id="mail"></span>pour plus d'informations</a>.</p> <p class="last"><a id="contact_me_link" class="no_print_link" href="#contact_me">[#]card_contact_me[#] <span id="mail"></span>[#]profile_more_info[#]</a>.</p>
</div> </div>
</div> </div>
</div> </div>
<div id="work" class="section work fixed"> <div id="[#]menu_xp_key[#]_ln" class="section work fixed">
<h2 class="section_name">Experience professionnelle</h2> <h2 class="section_name">Experience professionnelle</h2>
<div class="section_items"> <div class="section_items">
<div class="item"> <div class="item">
@@ -92,8 +100,8 @@
<li class="action">Analyse et conception de solutions de stockage EMC et NetApp</li> <li class="action">Analyse et conception de solutions de stockage EMC et NetApp</li>
<li class="action">Test et validation des nouveaux produits, r&eacute;daction de documentations techniques</li> <li class="action">Test et validation des nouveaux produits, r&eacute;daction de documentations techniques</li>
<li class="action">Support aux &eacute;quipes d'avant-vente et d'impl&eacute;mentation</li> <li class="action">Support aux &eacute;quipes d'avant-vente et d'impl&eacute;mentation</li>
<li class="action">Support aux &eacute;quipes BackOffice pour la résolution d'incidents complexes</li> <li class="action">Support aux &eacute;quipes BackOffice pour la résolution d'incidents complexes</li>
<li class="action">Analyse et r&eacute;solution de problèmes performances sur les infrastructures de stockage client</li> <li class="action">Analyse et r&eacute;solution de problèmes performances sur les infrastructures de stockage client</li>
<li class="action">D&eacute;veloppement de scripts d'industrialisation</li> <li class="action">D&eacute;veloppement de scripts d'industrialisation</li>
<li class="action">Veille technologique</li> <li class="action">Veille technologique</li>
</ul> </ul>
@@ -138,7 +146,7 @@
</ul> </ul>
</div></div> </div></div>
<ul> <ul>
<li class="subtitle">Expertise UNIX et réalisation de projets techniques</li> <li class="subtitle">Expertise UNIX et réalisation de projets techniques</li>
<li class="action">Administration des environnements de production (SI des bureaux de Poste, automates d'affranchissement, etc...)</li> <li class="action">Administration des environnements de production (SI des bureaux de Poste, automates d'affranchissement, etc...)</li>
<li class="action">Expertise technique sur l'infrastructure virtuelle existante : IBM pSeries (LPAR), Zones Solaris et hyperviseurs ESX</li> <li class="action">Expertise technique sur l'infrastructure virtuelle existante : IBM pSeries (LPAR), Zones Solaris et hyperviseurs ESX</li>
<li class="action">Impl&eacute;mentation syst&egrave;me AIX, Solaris et Linux RedHat</li> <li class="action">Impl&eacute;mentation syst&egrave;me AIX, Solaris et Linux RedHat</li>
@@ -166,11 +174,11 @@
</div></div> </div></div>
<ul> <ul>
<li class="subtitle">Administration UNIX / Linux pour EDF R&D</li> <li class="subtitle">Administration UNIX / Linux pour EDF R&D</li>
<li class="action">Migration des bases métier vers Oracle 10g</li> <li class="action">Migration des bases métier vers Oracle 10g</li>
<li class="action">Installation d'une plateforme de stockage HP EVA 8100 et rédaction de procédures d'exploitation</li> <li class="action">Installation d'une plateforme de stockage HP EVA 8100 et rédaction de procédures d'exploitation</li>
<li class="action">Etude et migration de l'authentification centralisée de NIS vers OpenLDAP <li class="action">Etude et migration de l'authentification centralisée de NIS vers OpenLDAP
<li class="action">Exploitation de cluster HPC IBM Blue Gene/L et Blue Gene/P</li> <li class="action">Exploitation de cluster HPC IBM Blue Gene/L et Blue Gene/P</li>
<li class="action">Gestion des sauvegardes serveurs: politique, rétention, externalisation</li> <li class="action">Gestion des sauvegardes serveurs: politique, rétention, externalisation</li>
</ul> </ul>
</li> </li>
<li> <li>
@@ -184,7 +192,7 @@
</ul> </ul>
</div></div> </div></div>
<ul> <ul>
<li class="subtitle">Installation et dépannage sur site EDF R&D</li> <li class="subtitle">Installation et dépannage sur site EDF R&D</li>
<li class="action">Gestion des changements et incidents de niveau 2 sur stations de travail (Linux Debian et Windows 2000/XP)</li> <li class="action">Gestion des changements et incidents de niveau 2 sur stations de travail (Linux Debian et Windows 2000/XP)</li>
<li class="action">C&acirc;blage et configuration des &eacute;quipements r&eacute;seau</li> <li class="action">C&acirc;blage et configuration des &eacute;quipements r&eacute;seau</li>
</ul> </ul>
@@ -193,7 +201,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="section language fixed"> <div id="[#]menu_lang_key[#]_ln" class="section language fixed">
<h2 class="section_name">Langues</h2> <h2 class="section_name">Langues</h2>
<div class="section_items"> <div class="section_items">
<div class="item"> <div class="item">
@@ -206,7 +214,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="section technical fixed"> <div id="[#]menu_skills_key[#]_ln" class="section technical fixed">
<h2 class="section_name">Competences techniques</h2> <h2 class="section_name">Competences techniques</h2>
<div class="section_items"> <div class="section_items">
<div class="item"> <div class="item">
@@ -254,7 +262,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="section education fixed"> <div id="[#]menu_edu_key[#]_ln" class="section education fixed">
<h2 class="section_name">Formation</h2> <h2 class="section_name">Formation</h2>
<div class="section_items"> <div class="section_items">
<div class="item" id="certif"> <div class="item" id="certif">

23
settings.php Normal file
View File

@@ -0,0 +1,23 @@
<?php
class Settings
{
const LOC_API_KEY = 'get a API key from http://ipinfodb.com/';
const MAIL_SCRIPT = 'your mail script (optional)';
const MAIL_API_KEY = 'your mail API key (optional)';
const MAIL_ADDRESS = 'admin email address';
const CONSUMER_KEY = 'Your Twitter API KEY (consumer)';
const CONSUMER_SECRET = 'Your Twitter API KEY (consumer secret)';
const OAUTH_TOKEN = 'Your Twitter API KEY (OAuth token)';
const OAUTH_TOKEN_SECRET = 'Your Twitter API KEY (OAuth token secret)';
const DB_SERVER = 'localhost';
const DB_LOGIN = 'root';
const DB_PASS = '';
const DB_NAME = 'wedding';
const DB_ENC = 'utf8mb4';
const TEXT_ENC = 'UTF-8';
const TIMEZONE = 'Europe/Paris';
const DEBUG = false;
}
?>

View File

@@ -278,6 +278,47 @@ h2.section_name {
padding:0 0 40px; padding:0 0 40px;
} }
/* Menu */
#menu {
padding:0;
margin:0 auto;
}
#menu div {
display:inline-block;
width:16%;
padding:5px;
text-align:center;
/*border-left:1px solid #DEDEDE;*/
border-right:1px solid #DEDEDE;
box-sizing:border-box;
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
}
#menu div:hover {
background:rgb(99, 123, 255);
}
#menu div:hover a {
color:white;
}
#menu a {
font-size:14px;
color:#4B5564;
}
#card {
float:right;
border-style:solid;
border-width: 1px 2px 2px 1px;
border-color: #DEDEDE #808080 #808080 #DEDEDE;
padding:10px;
background:#FFFFFF;
}
/* Header */ /* Header */
.header { .header {