Implementato backup client CBS

This commit is contained in:
Riccardo Di Dato
2016-02-26 12:07:22 +01:00
parent 8c8da9890d
commit 5ec979d6eb
64 changed files with 2996 additions and 170 deletions
+3 -2
View File
@@ -16,6 +16,7 @@ APACHE2_DOCUMENTROOT="/var/www"
SYSTEM_LOG_PATH="/var/log/asdynamics"
SYSTEM_PRIVATE="/home/asdynamics/private"
SYSTEM_STORAGE="/home/asdynamics/storage"
SYSTEM_TMP="/tmp/asdynamics"
###################################
@@ -33,8 +34,8 @@ APPLICATION_XSENDFILE_PATH="/tmp/xsend/$APPLICATION_BUILDNAME"
##### OTHER APPLICATION PATHS ######
####################################
APPLICATION_MEDIA_PATH="$APPLICATION_STORAGE/media"
APPLICATION_BACKUPS_PATH="$APPLICATION_STORAGE/backups"
APPLICATION_TMP_PATH="$APPLICATION_STORAGE/tmp"
APPLICATION_BACKUPS_PATH="$APPLICATION_STORAGE/backup"
APPLICATION_TMP_PATH="$SYSTEM_TMP/$APPLICATION_BUILDNAME"
APPLICATION_CONFIG_PATH="$APPLICATION_PRIVATE/common"
APPLICATION_BINARY_PATH="$APPLICATION_PRIVATE/bin"
APPLICATION_CRON_PATH="$APPLICATION_PRIVATE/crontab"
+6 -3
View File
@@ -15,12 +15,13 @@ $database->dbName = "fdn2";
$database->connectionString = "mongodb://10.0.0.2:27017";
$currentSystem = new stdClass();
$currentSystem->storageBaseDir = "/home/asdynamics/storage"; // Il path con storage ecc in cui mettere immagini, file temporanei ecc
$currentSystem->storageBaseDir = "/home/asdynamics/storage"; // Il path con storage ecc in cui mettere i contenuti dell'applicazione (immagini, dump db ecc)
$currentSystem->privateBaseDir = "/home/asdynamics/private"; // Il path in cui inserire la cartella con lib, task, binari ecc
$currentSystem->tmpBaseDir = "/tmp/asdynamics";
$currentSystem->logBaseDir = "/var/log/asdynamics"; // Il path dei log....
$currentSystem->xSendFileDir = "/tmp/xsend";
$currentSystem->safeStorage = "/home/cbs/storage";
// $currentSystem->safeStorage = "/home/cbs/storage";
$currentSystem->apache = new StdClass();
$currentSystem->apache->user = "var-www";
@@ -29,7 +30,9 @@ $currentSystem->apache->workdir = "/var/www"; // Il path in cui inserire la car
$currentSystem->remoteLocationPath = "/fdn2/";
$backupSystem = new stdClass();
$backupSystem->account = "40a911e14db8ad6faf0a0e7385e7c267";
$backupSystem->passphrase = "a54af48c2ec44bba903666b6d12290750178154a6965c9165d3b387e7fd0f14c5f2d62cb93f468be640d469c80f1260feed3ad98f5f52d52c045b0487e59981bf365f4037f6c7cb93572cdd5d20daeb8185afcc65dba1bd2067829f827d9b795451f6e5e8fafe5e1fbe29675feb93e7d208a6b53a14df5aeec62d97fbf34d56a";
// $config->locations = new stdClass();
+9 -2
View File
@@ -40,6 +40,7 @@ $config->paths->storage = $currentSystem->storageBaseDir . "/" . $project->buil
$config->paths->private = $currentSystem->privateBaseDir . "/" . $project->buildName;
$config->paths->public = $currentSystem->apache->workdir . "/" . $project->buildName;
$config->paths->log = $currentSystem->logBaseDir . "/" . $project->buildName;
$config->paths->tmp = $currentSystem->tmpBaseDir . "/" . $project->buildName;
$config->paths->backup = $config->paths->storage . "/backup";
@@ -47,12 +48,13 @@ $config->paths->binaries = $config->paths->private . "/bin";
$config->paths->common = $config->paths->private . "/common";
$config->paths->libraries = $config->paths->private . "/lib";
$config->paths->task = $config->paths->private . "/task";
$config->paths->cbsQueue = $config->paths->tmp . "/cbsQueue";
$config->paths->backupTmp = $config->paths->tmp . "/bak";
$config->paths->pubImages = $config->paths->public . "/style/images";
$config->paths->media = $config->paths->storage . "/media";
// $config->paths->defMedia = $config->paths->pubImages . "/defaults";
$config->paths->tmp = $config->paths->storage . "/tmp";
$config->paths->xsendfile = $currentSystem->xSendFileDir . "/" . $project->buildName;
@@ -65,6 +67,7 @@ $config->files->task_log = $config->paths->log . "/task.log";
$config->files->general_log = $config->paths->log . "/general.log";
$config->files->gui_log = $config->paths->log . "/gui.log";
$config->files->mail_log = $config->paths->log . "/mail.log";
$config->files->api_log = $config->paths->log . "/api.log";
// Pages
$config->pages = new StdClass();
@@ -79,9 +82,13 @@ $config->emails->info = "info@ifattidinapoli.it";
$config->emails->system = "system@ifattidinapoli.it";
$config->emails->postmaster = "postmaster@ifattidinapoli.it";
// $config->pages->index = $currentSystem->remoteLocation . "/index.php";
// $config->pages->login = $currentSystem->remoteLocation . "/login.php";
// $config->pages->logout = $currentSystem->remoteLocation . "/logout.php";
$config->api = new stdClass();
$config->api->account = $backupSystem->account;
$config->api->passphrase = $backupSystem->passphrase;
?>
+5 -2
View File
@@ -19,10 +19,11 @@ $database->connectionString = null;
$currentSystem = new stdClass();
$currentSystem->storageBaseDir = "/home/asdynamics/storage"; // Il path con storage ecc in cui mettere immagini, file temporanei ecc
$currentSystem->privateBaseDir = "/home/asdynamics/private"; // Il path in cui inserire la cartella con lib, task, binari ecc
$currentSystem->tmpBaseDir = "/tmp/asdynamics";
$currentSystem->logBaseDir = "/var/log/asdynamics"; // Il path dei log....
$currentSystem->xSendFileDir = "/tmp/xsend";
$currentSystem->safeStorage = "/home/cbs/storage";
// $currentSystem->safeStorage = "/home/cbs/storage";
$currentSystem->apache = new StdClass();
$currentSystem->apache->user = "var-www";
@@ -31,7 +32,9 @@ $currentSystem->apache->workdir = "/var/www"; // Il path in cui inserire la car
$currentSystem->remoteLocationPath = "/";
$backupSystem = new stdClass();
$backupSystem->account = "1582528f056a7ea7f391149fddc75553";
$backupSystem->passphrase = "232728b3e504a400a62a9f94893a9a962ecc6543ed7d3c293340414b259aac727f14d60a4f2cd52e228c9694a55774ff5652520b38d120a299394715247645b8293a880901162f268c8c8777a3ee9c6e410455cb4c8137f58f9d7162d45582ab363679ed456e56bf3b36d0384368b62eced40abd0fe117f04c9322f07ee33a7c";
// $config->locations = new stdClass();
+7 -1
View File
@@ -18,10 +18,11 @@ $database->connectionString = null;
$currentSystem = new stdClass();
$currentSystem->storageBaseDir = "/home"; // Il path con storage ecc in cui mettere immagini, file temporanei ecc
$currentSystem->privateBaseDir = "/home/asdynamics"; // Il path in cui inserire la cartella con lib, task, binari ecc
$currentSystem->tmpBaseDir = "/tmp/asdynamics";
$currentSystem->logBaseDir = "/var/log"; // Il path dei log....
$currentSystem->xSendFileDir = "/tmp/xsend";
$currentSystem->safeStorage = "/home/cbs/storage";
// $currentSystem->safeStorage = "/home/cbs/storage";
$currentSystem->apache = new StdClass();
$currentSystem->apache->user = "var-www";
@@ -31,6 +32,11 @@ $currentSystem->apache->workdir = "/var/www"; // Il path in cui inserire la car
$currentSystem->remoteLocationPath = "/";
$backupSystem = new stdClass();
$backupSystem->account = "40a911e14db8ad6faf0a0e7385e7c267";
$backupSystem->passphrase = "a54af48c2ec44bba903666b6d12290750178154a6965c9165d3b387e7fd0f14c5f2d62cb93f468be640d469c80f1260feed3ad98f5f52d52c045b0487e59981bf365f4037f6c7cb93572cdd5d20daeb8185afcc65dba1bd2067829f827d9b795451f6e5e8fafe5e1fbe29675feb93e7d208a6b53a14df5aeec62d97fbf34d56a";
// $config->locations = new stdClass();
+21
View File
@@ -2,6 +2,27 @@
<?php
require_once(dirname(__FILE__). "/../load.php");
$tasks = array("SendBackupTask");
if (sizeof($tasks)>0){
foreach ($tasks as $taskName){
try {
if ($taskName::isActive()){
LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_INFO,"Executing task '".$taskName::getLabel()."' ");
$taskName::execute();
LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_INFO,"Task '".$taskName::getLabel()."' completed successfully");
}
}catch (CoreException $ex){
$msg = "Error while executing task '".$taskName::getLabel()."' with message '".$ex->getMessage()."'";
LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_ERROR,$msg);
}
catch (Exception $ex){
$msg = "Unexpected error while executing task '".$taskName::getLabel()."' with message '".$ex->getMessage()."'";
LoggingFacilityManager::getLogger("task")->log(LoggingFacility::$LEVEL_ERROR,$msg);
}
}
}
// try {
+1 -1
View File
@@ -6,7 +6,7 @@ Creation Date: 27/gen/2016
class AnalyticsHelper {
private static $COOKIE_NAME = "FDN_STAT_NUM";
// Switch this value to +1 year in production environment
//TODO: Switch this value to +1 year in production environment
private static $COOKIE_TIME = "+5 minutes";
public static function savePageImpression($ip, $content, $source){
+132
View File
@@ -0,0 +1,132 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 05/feb/2016
*/
class PipelineHelper {
public static function getDailyVisualizationPipeline($startDate){
$rval = array(
array(
'$match'=>array(
'statType'=>StatisticModel::STAT_TYPE_PAGE,
'date'=>array(
'$gte'=>new MongoDate($startDate)
)
)
),
array(
'$group'=>array(
"_id"=>array(
'date'=>array(
"day"=>array('$dayOfMonth'=>'$date'),
"month"=>array('$month'=>'$date'),
"year"=>array('$year'=>'$date')
),
'user'=>'$user.id',
),
"visualizzazioni"=>array(
'$sum'=>1
),
"isNew"=>array(
'$sum'=>array(
'$cond'=>array(
array('$eq'=>array('$user.isNew',true)),
1,
0
)
)
)
)
),
array(
'$group'=>array(
"_id"=>array(
'date'=>'$_id.date'
),
"visualizzazioni"=>array(
'$sum'=>'$visualizzazioni'
),
"unici"=>array(
'$sum'=>'$isNew'
),
"visitatori"=>array(
'$sum'=>1
)
)
),
array(
'$sort'=>array(
"_id.date.year"=>1,
"_id.date.month"=>1,
"_id.date.day"=>1
)
)
);
return $rval;
}
public static function getMonthlyVisualizationPipeline($startDate){
$rval = array(
array(
'$match'=>array(
'statType'=>StatisticModel::STAT_TYPE_PAGE,
'date'=>array(
'$gte'=>new MongoDate($startDate)
)
)
),
array(
'$group'=>array(
"_id"=>array(
'date'=>array(
"month"=>array('$month'=>'$date'),
"year"=>array('$year'=>'$date')
),
'user'=>'$user.id',
),
"visualizzazioni"=>array(
'$sum'=>1
),
"isNew"=>array(
'$sum'=>array(
'$cond'=>array(
array('$eq'=>array('$user.isNew',true)),
1,
0
)
)
)
)
),
array(
'$group'=>array(
"_id"=>array(
'date'=>'$_id.date'
),
"visualizzazioni"=>array(
'$sum'=>'$visualizzazioni'
),
"unici"=>array(
'$sum'=>'$isNew'
),
"visitatori"=>array(
'$sum'=>1
)
)
),
array(
'$sort'=>array(
"_id.date.year"=>1,
"_id.date.month"=>1
)
)
);
return $rval;
}
}
?>
+112
View File
@@ -0,0 +1,112 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 19/feb/2016
*/
class FDN2CBS_DataStorage extends CBSClient_DataStorageBase{
/**
* Restituisce un mongoID (stringa)
* @see CBSClient_DataStorageBase::getNextOperationId()
*/
public function getNextOperationId(){
$rval = 1;
$conf = GlobalVariables::get("dao")->getFirst("ConfigModel",array("name"=>"cbsQueue"));
if (!is_null($conf)){
$rval = $conf->lastOperationId+1;
}
return $rval;
// $cur = GlobalVariables::get("dao")->getFirst("CBSQueueModel",array(),array("sort"=>"operationId"));
// if (is_null($cur)){
// return 1;
// }
// else {
// return $cur->operationId+1;
// }
}
/**
* (non-PHPdoc)
* @see CBSClient_DataStorageBase::setMaxOperationId()
*/
public function setMaxOperationId($id){
$conf = GlobalVariables::get("dao")->getFirst("ConfigModel",array("name"=>"cbsQueue"));
if (is_null($conf)){
$obj = new stdClass();
$obj->name="cbsQueue";
$conf = new ConfigModel($obj);
}
$conf->lastOperationId = $id;
GlobalVariables::get("dao")->save($conf);
}
/**
* @see CBSClient_DataStorageBase::queueUncompletedRequest()
*/
public function queueUncompletedRequest($id, RAPI_RequestDetails $req){
$queueFolder = GlobalVariables::get("config")->paths->cbsQueue;
$obj = new stdClass();
$obj->operationId = $id;
$obj->retry = 0;
$queueObj = new CBSQueueModel($obj);
GlobalVariables::get("dao")->save($queueObj);
if (!SFSManager::fileExists($queueFolder)){
SFSManager::createDirectory($queueFolder);
}
$path = $queueFolder."/".$queueObj->id;
SFSManager::writeFile(serialize($req), $path);
}
/**
* @see CBSClient_DataStorageBase::getUncompletedRequests()
*/
public function getUncompletedRequests($limit = null){
$rval = array();
$basePath = GlobalVariables::get("config")->paths->cbsQueue;
$opt = array("sort"=>array("retry"=>1));
if (!is_null($limit)){
$opt["limit"] = $limit;
}
$requests = GlobalVariables::get("dao")->query("CBSQueueModel", array(), $opt);
if (sizeof($requests)>0){
foreach ($requests as $request){
$path = $basePath."/".$queueObj->id;
$cont = implode("",SFSManager::readFile($path));
$rval[] = unserialize($cont);
}
}
return $rval;
}
/**
* @see CBSClient_DataStorageBase::onRequestCompletedFromQueue()
*/
public function onRequestCompletedFromQueue($id){
$queueObj = GlobalVariables::get("dao")->getFirst("CBSQueueModel", array("operationId"=>$id));
$path = GlobalVariables::get("config")->paths->cbsQueue."/".$queueObj->id;
SFSManager::deleteFile($path);
GlobalVariables::get("dao")->delete($queueObj);
}
/**
* @see CBSClient_DataStorageBase::onRequestFailedFromQueue()
*/
public function onRequestFailedFromQueue($id){
$queueObj = GlobalVariables::get("dao")->getFirst("CBSQueueModel", array("operationId"=>$id));
$queueObj->retry = $queueObj->retry+1;
GlobalVariables::get("dao")->save($queueObj);
}
// private function getOperationIdFile(){
// $config = GlobalVariables::get("config");
// return $config->paths->common."/RAPI_maxOperationId";
// }
}
?>
+55
View File
@@ -0,0 +1,55 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 19/feb/2016
*/
class FDN2CBS_Logger implements RAPI_Logger{
/**
* (non-PHPdoc)
* @see LoggingFacility::log()
*/
public function log($level, $message){
LoggingFacilityManager::getLogger("api")->log($this->convertToCbsLogLevel($level),$message);
}
/**
* (non-PHPdoc)
* @see RAPI_Logger::generateSecurityWarning()
*/
public function generateSecurityWarning($severity, $message, RAPI_Request $request){
LoggingFacilityManager::getLogger("api")->log(LoggingFacility::$LEVEL_WARNING,"CBS SECURITY WARNING - ".$message);
}
/**
* (non-PHPdoc)
* @see RAPI_Logger::generateSecurityOperationWarning()
*/
public function generateSecurityOperationWarning($severity, $message, RAPI_Request $request, RAPI_Operation $op){
}
private function convertToCbsLogLevel($level){
switch ($level){
case RAPI_Logger::LOG_LEVEL_DEBUG:
$rval = LoggingFacility::$LEVEL_DEBUG;
break;
case RAPI_Logger::LOG_LEVEL_INFO:
$rval = LoggingFacility::$LEVEL_INFO;
break;
case RAPI_Logger::LOG_LEVEL_WARNING:
$rval = LoggingFacility::$LEVEL_WARNING;
break;
case RAPI_Logger::LOG_LEVEL_ERROR:
$rval = LoggingFacility::$LEVEL_ERROR;
break;
}
return $rval;
}
}
?>
@@ -0,0 +1,29 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 18/feb/2016
*/
/**
* Classe semplificare l'implementazione del client
* @author Riccardo Di Dato
*/
class CBSClient extends RAPI_ClientHelper{
/**
* La classe si occupa già di costruire il RAPI_Client e di implementare i metodi dell'helper
* @param RAPI_Logger $logger
* @param RAPI_DataStorage $dataStorage
* @param string $receivedAttachmentPath
*/
public function __construct(RAPI_Logger $logger, CBSClient_DataStorageBase $dataStorage, $receivedAttachmentPath){
parent::__construct(new CBS_RAPIClientImplementation($logger, $dataStorage, $receivedAttachmentPath));
$this->defineRequest("getBackups", "RAPI_BackupListRequestDetails", new RAPI_SingleValueResponseFetcher("list"));
$this->defineRequest("sendBackup", "RAPI_CreateBackupRequestDetails", new RAPI_SingleValueResponseFetcher("id"));
// $this->defineRequest("getBackup", "RAPI_GetBackupRequestDetails", new RAPI_StandardResponseFetcher(function($d){$d->content = utf8_decode($d->content); return $d; }));
$this->defineRequest("getBackup", "RAPI_GetBackupRequestDetails", new RAPI_StandardResponseFetcher());
}
}
?>
@@ -0,0 +1,66 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 18/feb/2016
*/
abstract class CBSClient_DataStorageBase implements RAPI_DataStorage{
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::getRapiPassphrase()
*/
public function getRapiPassphrase(){
return GlobalVariables::get("config")->api->passphrase;
}
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::getRapiAccount()
*/
public function getRapiAccount(){
return GlobalVariables::get("config")->api->account;
}
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::getRapiUser()
*/
public function getRapiUser(){
return "1";
}
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::getNextOperationId()
*/
abstract public function getNextOperationId();
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::setMaxOperationId()
*/
abstract public function setMaxOperationId($id);
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::queueUncompletedRequest()
*/
abstract public function queueUncompletedRequest($id, RAPI_RequestDetails $req);
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::getUncompletedRequests()
*/
abstract public function getUncompletedRequests($limit = null);
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::onRequestCompletedFromQueue()
*/
abstract public function onRequestCompletedFromQueue($id);
/**
* (non-PHPdoc)
* @see RAPI_DataStorage::onRequestFailedFromQueue()
*/
abstract public function onRequestFailedFromQueue($id);
}
?>
@@ -0,0 +1,45 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/feb/2016
*/
class CBS_RAPIClientImplementation extends RAPI_Client {
private $fh;
private $attachmentPath;
public function __construct($logger, $dataStorage, $attachmentPath){
parent::__construct($logger, $dataStorage);
$this->attachmentPath = $attachmentPath;
}
protected function openConnection(){
$service_port = getservbyname('rapi', 'tcp');
$address = RAPI_Config::RAPI_SERVER_ADDRESS;
$this->fh = stream_socket_client("tcp://$address:$service_port", $errno, $errstr, 30);
}
protected function closeConnection(){
fclose($this->fh);
}
protected function sendMessage($msg){
fwrite($this->fh, $msg);
}
protected function getMessage($bufferSize = null){
if (is_null($bufferSize)){
return fgets($this->fh);
}
else {
return fgets($this->fh,$bufferSize);
}
}
protected function getReceivedAttachmentPath(){
return $this->attachmentPath;
}
}
?>
@@ -0,0 +1,28 @@
<?php
/*
* Per usare il client basta estendere le classi RAPI_Logger e CBSClient_DataStorageBase ed utilizzarle per implementare CBSClient
Author: Riccardo Di Dato
Creation Date: 18/feb/2016
*/
require_once(dirname(__FILE__)."/rapi/rapi_client/RAPI_Client.php");
// TEST IMPLEMENTATIONS
require_once(dirname(__FILE__)."/messages/request/RAPI_BackupListRequestDetails.php");
require_once(dirname(__FILE__)."/messages/request/RAPI_CreateBackupRequestDetails.php");
require_once(dirname(__FILE__)."/messages/request/RAPI_GetBackupRequestDetails.php");
require_once(dirname(__FILE__)."/messages/response/RAPI_BackupListResponseDetails.php");
require_once(dirname(__FILE__)."/messages/response/RAPI_CreateBackupResponseDetails.php");
require_once(dirname(__FILE__)."/messages/response/RAPI_GetBackupResponseDetails.php");
require_once(dirname(__FILE__)."/CBSClient_DataStorageBase.php");
require_once(dirname(__FILE__)."/CBS_RAPIClientImplementation.php");
require_once(dirname(__FILE__)."/CBSClient.php");
RAPI_BackupListRequestDetails::registerToFactory();
RAPI_CreateBackupRequestDetails::registerToFactory();
RAPI_GetBackupRequestDetails::registerToFactory();
?>
@@ -0,0 +1,51 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 20/gen/2016
*/
/**
* Parametri Nessuno
* Ritorna la lista Backup dell'account richiedente
*
* @author Riccardo Di Dato
*/
class RAPI_BackupListRequestDetails extends RAPI_RequestDetails {
/**
* Returns true if the operation requires an
* operationId (like for writes and deletion)
*/
public static function usesOperationId(){
return false;
}
/**
* Returns the name of the operation used by the request factory (NOT THE RAPI_Operation !!!!!)
* @return string
*/
public static function getOperationName(){
return "BackupList";
}
/**
* @see RAPI_RequestDetails::getResponseDetailsClass()
*/
public static function getResponseDetailsClass(){
return "RAPI_BackupListResponseDetails";
}
/**
* @see RAPI_RequestDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("options");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
@@ -0,0 +1,51 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 10/feb/2016
*/
/**
* Parametri {fileContent}.
* Salva {fileContent} come nuovo backup
*
* @author Riccardo Di Dato
*/
class RAPI_CreateBackupRequestDetails extends RAPI_RequestDetails {
/**
* Returns true if the operation requires an
* operationId (for writes and deletion)
*/
public static function usesOperationId(){
return true;
}
/**
* Returns the name of the operation used by the request factory (NOT THE RAPI_Operation !!!!!)
* @return string
*/
public static function getOperationName(){
return "CreateBackup";
}
/**
* @see RAPI_RequestDetails::getResponseDetailsClass()
*/
public static function getResponseDetailsClass(){
return "RAPI_CreateBackupResponseDetails";
}
/**
* @see RAPI_RequestDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("filename");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array("backup");
}
}
?>
@@ -0,0 +1,52 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 11/feb/2016
*/
/**
* Parametri ID
* Ritorna un backup con dati e contenuto file
*
* @author Riccardo Di Dato
*/
class RAPI_GetBackupRequestDetails extends RAPI_RequestDetails {
/**
* Returns true if the operation requires an
* operationId (like for writes and deletion)
*/
public static function usesOperationId(){
return false;
}
/**
* Returns the name of the operation used by the request factory (NOT THE RAPI_Operation !!!!!)
* @return string
*/
public static function getOperationName(){
return "GetBackup";
}
/**
* @see RAPI_RequestDetails::getResponseDetailsClass()
*/
public static function getResponseDetailsClass(){
return "RAPI_GetBackupResponseDetails";
}
/**
* @see RAPI_RequestDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("id");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
?>
@@ -0,0 +1,24 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 20/gen/2016
*/
class RAPI_BackupListResponseDetails extends RAPI_ResponseDetails {
/**
* @see RAPI_MessageDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("list");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
?>
@@ -0,0 +1,23 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 10/feb/2016
*/
class RAPI_CreateBackupResponseDetails extends RAPI_ResponseDetails {
/**
* @see RAPI_MessageDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("id");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
?>
@@ -0,0 +1,23 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 11/feb/2016
*/
class RAPI_GetBackupResponseDetails extends RAPI_ResponseDetails {
/**
* @see RAPI_MessageDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("info","content");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array("backup");
}
}
?>
@@ -0,0 +1,45 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 24/giu/2015
*/
class RAPI_Config {
/**
* Versione del protocollo
* @var string
*/
const RAPI_VERSION = "RAPI-1.2";
/**
* Tempo massimo valido tra l'invio della richiesta e la sua ricezione (in minuti)
* @var int
*/
// const REQUEST_TIMEOUT = 3;
const REQUEST_TIMEOUT = 100000;
/**
* Timeout della richiesta oltre il quale il sistema genera un warning di sicurezza (minuti)
* @var int
*/
const REQUEST_TIMEOUT_WARNING = 180;
/**
* Debug variables
* @var bool
*/
const DISABLE_DIGEST = false;
/*
* CLIENT ONLY
*/
/**
* L'ip del server con installato rapi server
* @var string
*/
const RAPI_SERVER_ADDRESS = "cbs.asdynamics.com";
}
?>
@@ -0,0 +1,48 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/giu/2015
*/
class RAPI_CryptUtils{
/**
* Genera un digest
* @param string $user Identificativo dell'utente
* @param int $timestamp Timestamp in microsecondi
* @param string $details Corpo della richiesta in JSON
* @param string $passphrase Password per la cifratura
* @return string
*/
private static function getDigest($user, $timestamp, $details, $passphrase) {
return hash_hmac("sha256",$user.$timestamp.substr($details,0,1000),$passphrase);
}
/**
* Genera un digest a partire da un messaggio
* @param string $user Identificativo dell'utente
* @param int $timestamp Timestamp in microsecondi
* @param string $details Corpo della richiesta in JSON
* @param string $passphrase Password per la cifratura
* @return string
*/
public static function getDigestForMessage(RAPI_Message $msg, $passphrase){
$user = null;
if ($msg instanceof RAPI_Request){
$user = $msg->getUser();
}
else if ($msg instanceof RAPI_Response){
$user = $msg->getRelatedRequest()->getUser();
}
else {
throw new RAPI_Exception("Invalid usage of CryptUtils::getDigestForMessage(); Unimplemented message type ('".get_class($msg)."')");
}
$timestamp = $msg->getTime();
$details = $msg->getDetails(true);
return self::getDigest($user, $timestamp, $details, $passphrase);
}
}
?>
@@ -0,0 +1,44 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 24/giu/2015
*/
interface RAPI_Logger {
const LOG_LEVEL_DEBUG = 1;
const LOG_LEVEL_INFO = 2;
const LOG_LEVEL_WARNING = 3;
const LOG_LEVEL_ERROR = 4;
const WARNING_SEVERITY_LOW = 1;
const WARNING_SEVERITY_MEDIUM = 2;
const WARNING_SEVERITY_HIGH = 3;
const WARNING_SEVERITY_CRITICAL = 4;
/**
* Una riga di log
* @param int $level Livello del log
* @param string $message Messaggio da scrivere nel log
*/
public function log($level, $message);
/**
* Genera un warning di sicurezza.
* @param int $level Importanza del warning
* @param string $message Messaggio da scrivere nel log
* @param RAPI_Message $request RAPI_Message che ha generato il warning
*/
public function generateSecurityWarning($severity, $message, RAPI_Request $request);
/**
* Come il warning sulla richiesta, ma include i dettagli dell'operazione
* @param int $level Importanza del warning
* @param string $message Messaggio da scrivere nel log
* @param RAPI_Message $request RAPI_Message associato all'operazione
* @param RAPI_Operation $op Operazione che ha generato il warning
*/
public function generateSecurityOperationWarning($severity, $message, RAPI_Request $request, RAPI_Operation $op);
}
?>
@@ -0,0 +1,16 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 24/giu/2015
*/
/**
* Eccezione generica lanciata dal sistema RAPI
* @author Riccardo Di Dato
*/
class RAPI_Exception extends Exception{
}
?>
@@ -0,0 +1,40 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/giu/2015
*/
/**
* Eccezione lanciata in caso di errore di validazione.
* Contiene la causa per cui la richiesta non è valida
* @author rik
*
*/
class RAPI_ValidationException extends RAPI_Exception{
/**
* Lo status code che ha causato l'eccezione
* @var int
*/
private $status;
/**
* Costruisce la validation exception con un messaggio di default e salvando al suo interno lo status code.
* @param int $status
*/
public function __construct($status){
$this->status = $status;
parent::__construct("RAPI_ValidationException 'Status $status'");
}
/**
* Restituisce lo status code che ha causato l'eccezione
* @return int
*/
public function getStatus (){
return $this->status;
}
}
?>
@@ -0,0 +1,30 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/giu/2015
*/
require_once(dirname(__FILE__)."/exceptions/RAPI_Exception.php");
require_once(dirname(__FILE__)."/exceptions/RAPI_ValidationException.php");
require_once(dirname(__FILE__)."/RAPI_Config.php");
require_once(dirname(__FILE__)."/RAPI_CryptUtils.php");
require_once(dirname(__FILE__)."/RAPI_Logger.php");
require_once(dirname(__FILE__)."/messages/RAPI_Message.php");
require_once(dirname(__FILE__)."/messages/RAPI_MessageDetails.php");
require_once(dirname(__FILE__)."/messages/RAPI_Request.php");
require_once(dirname(__FILE__)."/messages/RAPI_RequestDetails.php");
require_once(dirname(__FILE__)."/messages/RAPI_Response.php");
require_once(dirname(__FILE__)."/messages/RAPI_ResponseDetails.php");
require_once(dirname(__FILE__)."/messages/request/RAPI_UnreadableRequestDetails.php");
require_once(dirname(__FILE__)."/messages/request/RAPI_UnreadableRequest.php");
require_once(dirname(__FILE__)."/messages/response/RAPI_EmptyResponseDetails.php");
require_once(dirname(__FILE__)."/messages/response/RAPI_SimpleMessageResponseDetails.php");
require_once(dirname(__FILE__)."/messages/RAPI_RequestDetailsFactory.php");
?>
@@ -0,0 +1,256 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 24/giu/2015
*/
/**
* Message example:
* {
* version: ${protocol_version},
* time: ${timestamp_microseconds},
* digest: ${digest},
* details: ${request}
* }
* @author Riccardo Di Dato
*
*/
abstract class RAPI_Message {
private $encryptedCache = null;
/*
* Attributi, setters e getters
*/
/**
* Versione del protocollo RAPI
* @var string
*/
private $protocolVersion;
public function getProtocolVersion(){
return $this->protocolVersion;
}
/**
* Timestamp in microsecondi
* @var int
*/
private $time;
public function getTime(){
return $this->time;
}
/**
* Digest per valutare l'autenticità
* @var string
*/
private $digest;
public function getDigest(){
return $this->digest;
}
/**
* Imposta il digest per il messaggio
* @param string $digest il digest da impostare
*/
public function setDigest($digest){
$this->digest = $digest;
}
/**
* Una classe contenente i dettagli per generare l'operazione
* @var RAPI_MessageDetails
*/
private $details;
/**
* @param string $encoded
* @return string|RAPI_MessageDetails
*/
public function getDetails($encoded = false){
if ($encoded){
return json_encode($this->details);
}
else {
return $this->details;
}
}
/**
* Metodo di utility che richiama il metodo omonimo del message details.
* @return stdClass
*/
public function getAttachmentData($name){
return $this->getDetails()->getAttachmentData($name);
}
/**
* Metodo di utility che richiama il metodo omonimo del message details per l'istanza utilizzata all'interno
* @return stdClass
*/
public function getAttachmentList(){
return $this->getDetails()->getAttachmentList();
}
/**
* Metodo di utility che richiama il metodo omonimo del message details per l'istanza utilizzata all'interno
*/
public function setAttachmentLocalFileReference($name, $path){
$this->getDetails()->setAttachmentLocalFileReference($name,$path);
}
/**
* Metodo di utility che richiama il metodo omonimo del message details per l'istanza utilizzata all'interno
*/
public function getAttachmentLocalFileReference($name){
return $this->details->getAttachmentLocalFileReference($name);
}
/*
* Costruttore
*/
/**
* @param string $protocolVersion La versione del protocollo RAPI
* @param RAPI_MessageDetails $details Il contenuto del messaggio
* @param int $time Timestamp in microsecondi
* @param string $digest Digest per valutare l'autenticità del messaggio
*/
public function __construct($protocolVersion, RAPI_MessageDetails $details, $time = null, $digest = null){
$this->protocolVersion = $protocolVersion;
$this->time = is_null($time)?array_sum( explode( ' ' , microtime() ) ):$time;
$this->details = $details;
$this->digest = $digest;
}
/*
* Metodi per la SERIALIZZAZIONE
*/
/**
* Genera un oggetto standard da utilizzare per
* la serializzazione.
* Questa versione genera solo gli attributi
* relativi a RAPI_Message
* @return stdClass
*/
protected function generateEncryptionBaseObject(){
$rval = new stdClass();
$rval->version = $this->protocolVersion;
$rval->time = $this->time;
$rval->digest = $this->digest;
$rval->details = $this->details->generateEncryptionObject();
return $rval;
}
/**
* Restituisce la serializzazione dell'oggetto
* @return string
*/
public function getEncryption(){
if (is_null($this->encryptedCache)){
$this->testEncryption();
}
return $this->encryptedCache;
}
public function testEncryption(){
$this->encryptedCache = null;
$enc = json_encode($this->generateEncryptionObject());
if ($enc === false){
throw new RAPI_Exception("JSON Encoding failed. Message '".json_last_error_msg()."'");
}
$this->encryptedCache = $enc;
}
/*
* Metodi di DE-SERIALIZZAZIONE
*/
/**
* Deserializza la stringa e ritorna un oggetto RAPI_Message
* valido.
* @param string $string
* @param array $additionalData Parametro opzionale per aggiungere attributi (già decodificati) all'oggetto dopo la decodifica
* @throws RAPI_Exception Se non riesce a parsare la stringa
* @return RAPI_Message
*/
public static function fromEncrypted($string, array $additionalData = array()){
$appoggio = json_decode(trim($string));
if (!is_null($appoggio)){
if (sizeof($additionalData)>0){
foreach ($additionalData as $key => $val){
$appoggio->$key = $val;
}
}
}
else {
$errMsg = "Invalid request format ";
switch (json_last_error()) {
case JSON_ERROR_NONE:
$errMsg.= ' (No JSON errors)';
break;
case JSON_ERROR_DEPTH:
$errMsg.= ' (JSON - Maximum stack depth exceeded)';
break;
case JSON_ERROR_STATE_MISMATCH:
$errMsg.= ' (JSON - Underflow or the modes mismatch)';
break;
case JSON_ERROR_CTRL_CHAR:
$errMsg.= ' (JSON - Unexpected control character found)';
break;
case JSON_ERROR_SYNTAX:
$errMsg.= ' (JSON - Syntax error, malformed JSON)';
break;
case JSON_ERROR_UTF8:
$errMsg.= ' (JSON - Malformed UTF-8 characters, possibly incorrectly encoded)';
break;
default:
$errMsg.= ' (JSON - Unknown error)';
break;
}
throw new RAPI_Exception($errMsg);
}
return static::createFromObject($appoggio);
}
/**
* Ritorna true se l'oggetto ha gli
* attributi per costruire un RAPI_Message.
* @param stdClass $obj
* @return bool
*/
protected static function isValidObjectForCreationBase($obj){
return property_exists($obj, "version") &&
property_exists($obj, "time") &&
property_exists($obj, "digest") &&
property_exists($obj, "details");
}
/*
* Abstract
*/
/**
* Genera un oggetto che contiene tutti
* i valori da encodare (con JSON).
* Utilizza generateEncryptionBaseObject e gli aggiunge
* tutti gli attributi da includere nel messaggio
* @return stdClass
*/
protected abstract function generateEncryptionObject();
/**
* Ritorna true se l'oggetto ha gli
* attributi per costruire un RAPI_Message.
* Utilizzare isValidObjectForCreationBase e dopo
* valutare gli attributi della sottoclasse
* @param stdClass $obj
* @return bool
*/
protected static abstract function isValidObjectForCreation($obj);
/**
* Costruisce un message a partire da una stdClass.
* @param stdClass $obj
* @return RAPI_Message
* @throws RAPI_Exception
*/
public static abstract function createFromObject($obj);
}
?>
@@ -0,0 +1,135 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 01/lug/2015
*/
abstract class RAPI_MessageDetails {
/**
* @var stdClass
*/
private $data;
/**
* @var stdClass
*/
private $attachments = array();
/**
* @return stdClass
*/
public function getData(){
return $this->data;
}
/**
* @return stdClass
*/
public function getAttachmentData($name){
if (!array_key_exists($name, $this->attachments)){
throw new RAPI_Exception("Invalid attachment name ($name) passed to '".get_called_class()."::getAttachmentData()'");
}
return $this->attachments[$name];
}
/**
* Imposta il file di appoggio LOCALE per un attachment
* @param string $name nome dell'attachment
* @param string $path il path del file
* @throws RAPI_Exception
*/
public function setAttachmentLocalFileReference($name, $path){
if (!array_key_exists($name, $this->attachments)){
throw new RAPI_Exception("Invalid attachment name ($name) passed to '".get_called_class()."::setAttachmentLocalFileReference()'");
}
$this->attachments[$name]->localReference = $path;
}
public function getAttachmentLocalFileReference($name){
if (!array_key_exists($name, $this->attachments)){
throw new RAPI_Exception("Invalid attachment name ($name) passed to '".get_called_class()."::getAttachmentLocalFileReference()'");
}
return $this->attachments[$name]->localReference;
}
/**
* Il parametro $data deve avere come attributi almeno quelli restituiti da getArgumentList()
* @param stdClass $data
* @throws RAPI_Exception
*/
public function __construct(stdClass $data, array $attachments = array()){
foreach (static::getArgumentList() as $arg){
if (!property_exists($data, $arg)){
throw new RAPI_Exception("Invalid data object passed to '".get_called_class()."'. Missing property '$arg'");
}
}
$requiredAttachments = static::getAttachmentList();
$requiredFields = array("md5","size","name");
if (sizeof($attachments)>0){
foreach ($attachments as $attachment){
foreach ($requiredFields as $field){
if (!property_exists($attachment, $field)){
throw new RAPI_Exception("Invalid attachment data object passed to '".get_called_class()."'. Missing property '$field' for attachment '$attachName'");
}
}
$this->attachments[$attachment->name] = $attachment;
if ( ($key = array_search($attachment->name, $requiredAttachments)) !== false ){
unset($requiredAttachments[$key]);
}
}
}
if (sizeof($requiredAttachments)>0){
throw new RAPI_Exception("Invalid attachment array passed to '".get_called_class()."'. Missing attachments '".implode(", ", $requiredAttachments)."'");
}
$this->data = $data;
}
/**
* Restituisce la codifica JSON del messaggio
* @return string
*/
public function __toString(){
return json_encode($this->generateEncryptionObject());
}
/**
* Restituisce una stdClass utilizzabile per rigenerare l'oggetto
* @return stdClass
*/
public function generateEncryptionObject(){
$tmp = new stdClass();
$tmp->data = new stdClass();
foreach (static::getArgumentList() as $argName){
$tmp->data->$argName = $this->data->$argName;
}
$tmp->attachments = array();
foreach (static::getAttachmentList() as $attachName){
$ele = new stdClass();
$ele->name = $attachName;
$ele->md5 = $this->attachments[$attachName]->md5;
$ele->size = $this->attachments[$attachName]->size;
$tmp->attachments[] = $ele;
}
return $tmp;
}
/*
* Abstract Methods
*/
/**
* Returns the list of arguments
* @return string[]
*/
public static abstract function getArgumentList();
/**
* Returns the list of attachments
* @var stdClass[]
*/
public static abstract function getAttachmentList();
}
?>
@@ -0,0 +1,143 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/giu/2015
*/
/**
* Request example:
* {
* version: ${protocol_version},
* account: ${acc_id},
* user: ${user_id},
* time: ${timestamp_microseconds},
* msg_id: ${request_id},
* digest: ${digest},
* details: ${request}
* }
* @author Riccardo Di Dato
*
*/
class RAPI_Request extends RAPI_Message{
/*
* Attributi, setters e getters
*/
/**
* Account utilizzato per la richiesta
* @var string
*/
private $account;
public function getAccount(){
return $this->account;
}
/**
* Utente dell'account
* @var string
*/
private $user;
public function getUser(){
return $this->user;
}
/**
* Identificativo della richiesta (NULL in lettura)
* @var string
*/
private $operationId;
public function getOperationId(){
return $this->operationId;
}
/*
* Metodi propri della classe
*/
/**
* @param string $account Il token dell'account che fa la richiesta
* @param string $user L'identificativo dell'utente (collegato all'account) che fa la richiesta
* @param string $operationId Identificativo univoco del messaggio. UTILIZZARE SOLO IN SCRITTURA, IN LETTURA UTILIZZARE null
* @param string $protocolVersion La versione del protocollo RAPI
* @param RAPI_RequestDetails $details Il contenuto della richiesta
* @param int $time Timestamp in microsecondi
* @param string $digest Digest per valutare l'autenticità del messaggio
*/
public function __construct($account, $user, $operationId, $protocolVersion, RAPI_RequestDetails $details, $time = null, $digest = null){
parent::__construct($protocolVersion, $details, $time, $digest);
$this->account = $account;
$this->user = $user;
$this->operationId = $operationId;
}
/**
* Metodo di utility che richiama il metodo omonimo del request details.
* Se una delle request è un checksumFake confronta solo i due checksum.
* @param RAPI_Request $req
* @return boolean
*/
public function isEqual(RAPI_Request $req){
return strcmp($this->getProtocolVersion(),$req->getProtocolVersion())==0 &&
strcmp($this->account,$req->account)==0 &&
strcmp($this->user,$req->user)==0 &&
strcmp($this->operationId,$req->operationId)==0 &&
$this->getDetails()->isEqual($req->getDetails());
}
/**
* Metodo di utility che richiama il metodo omonimo del request details.
* @return bool
*/
public function isChecksumFake(){
return $this->getDetails()->isChecksumFake();
}
/**
* Genera la versione checksumFake della rapi request.
* @return RAPI_Request
*/
public function generateChecksumFake(){
$rval = new RAPI_Request($this->account, $this->user, $this->getOperationId(), $this->getProtocolVersion(), $this->getDetails()->generateChecksumFake(), $this->getTime(), $this->getDigest());
return $rval;
}
/*
* Abstract Implementations
*/
/**
* @see RAPI_Message::generateEncryptionObject()
*/
protected function generateEncryptionObject(){
$rval = $this->generateEncryptionBaseObject();
$rval->account = $this->account;
$rval->user = $this->user;
$rval->operationId = $this->operationId;
return $rval;
}
/**
* @see RAPI_Message::isValidObjectForCreation()
*/
protected static function isValidObjectForCreation($obj){
return self::isValidObjectForCreationBase($obj) &&
property_exists($obj, "account") &&
property_exists($obj, "user") &&
property_exists($obj, "operationId");
}
/**
* @see RAPI_Message::createFromObject()
*/
public static function createFromObject($obj){
if (self::isValidObjectForCreation($obj)){
$details = RAPI_RequestDetailsFactory::generateFromEncryptionObject($obj->details);
return new RAPI_Request($obj->account, $obj->user, $obj->operationId, $obj->version, $details, $obj->time, $obj->digest);
}
else {
throw new RAPI_Exception("Invalid request format");
}
}
}
?>
@@ -0,0 +1,135 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 01/lug/2015
*/
/**
*
* @author Riccardo Di Dato
*/
abstract class RAPI_RequestDetails extends RAPI_MessageDetails{
/**
* Stringa md5 usata come checksum.
* L'attributo è valorizzato solo per i checksumFake
* @var string
*/
private $md5 = null;
/*
* Checksum e checksumFake
*/
/**
* Restituisce il checksum (Indipendentemente che si tratti o meno di un checksumFake).
* @return string
*/
public function getChecksum(){
$rval = $this->md5;
if (is_null($rval)){
$rval = md5(strval($this));
}
return $rval;
}
/**
* Forza il valore della variabile interna contenente il checkusm.
* ATTENZIONE! I non checksumFake non dovrebbero avere questo attributo valorizzato
* @param string $md5
*/
public function forceChecksum($md5){
$this->md5 = $md5;
}
/**
* Genera la versione checksumFake di un rapi request details.
* @return RAPI_RequestDetails
*/
public function generateChecksumFake(){
$tmp = new stdClass();
if (sizeof(static::getArgumentList())>0){
foreach (static::getArgumentList() as $arg){
$tmp->$arg = "";
}
}
$obj = new static($tmp);
$obj->md5 = $this->getChecksum();
return $obj;
}
/**
* Restituisce true se si tratta di un checksum fake.
* @return boolean
*/
public function isChecksumFake(){
return !is_null($this->md5);
}
/*
* Metodi propri della classe
*/
/**
* Valuta l'uguaglianza delle request details
* NOTA: Funziona anche se un requestDetails è un checksumFake, ma in tal caso confronta solo i due checksum.
* @param RAPI_Request $req
* @return boolean
*/
public function isEqual(RAPI_RequestDetails $req){
$rval = ( strcmp($this->getChecksum(), $req->getChecksum())==0 ) ;
if (!$this->isChecksumFake() && !$req->isChecksumFake()){
$rval = strcmp($this, $req);
}
return $rval;
}
/**
* @see RAPI_MessageDetails::generateEncryptionObject()
*/
public function generateEncryptionObject(){
$tmp = parent::generateEncryptionObject();
$tmp->operation = static::getOperationName();
if ($this->isChecksumFake()){
$tmp->md5 = $this->getChecksum();
}
return $tmp;
}
/*
* Factory
*/
/**
* Registra il details alla factory
*/
public static function registerToFactory(){
RAPI_RequestDetailsFactory::addToRegister(static::getOperationName(), get_called_class());
}
/*
* Metodi astratti
*/
/**
* Returns true if the operation requires an
* operationId (like for writes and deletion)
* @return bool
*/
public static abstract function usesOperationId();
/**
* Returns the name of the operation used by the request factory (NOT THE RAPI_Operation !!!!!)
* @return string
*/
public static abstract function getOperationName();
/**
* Returns the class name of the response details to use
* @return string
*/
public static abstract function getResponseDetailsClass();
}
?>
@@ -0,0 +1,52 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 01/lug/2015
*/
class RAPI_RequestDetailsFactory{
private static $REGISTER = array();
public static function addToRegister($operationName,$requestDetails){
self::$REGISTER[$operationName] = $requestDetails;
}
public static function getRequestDetailsClassnameByOperationName($operationName){
if (array_key_exists($operationName, self::$REGISTER)){
return self::$REGISTER[$operationName];
}
else {
throw new RAPI_Exception("Invalid operation name passed to RAPI_RequestDetailsFactory::getRequestDetailsClassnameByOperationName '$operationName'");
}
}
/**
*
* @param stdClass $tmp
* @throws RAPI_Exception
* @return RAPI_RequestDetails
*/
public static function generateFromEncryptionObject(stdClass $tmp){
if (!property_exists($tmp, 'operation')) {
throw new RAPI_Exception("Invalid encryptionObject passed to RAPI_RequestDetailsFactory::generateFromEncryptionObject (operation field missing)");
}
else if (!property_exists($tmp, 'data')) {
throw new RAPI_Exception("Invalid encryptionObject passed to RAPI_RequestDetailsFactory::generateFromEncryptionObject (data field missing)");
}
else if (!property_exists($tmp, 'attachments')) {
throw new RAPI_Exception("Invalid encryptionObject passed to RAPI_RequestDetailsFactory::generateFromEncryptionObject (attachment field missing)");
}
else {
$classname = self::getRequestDetailsClassnameByOperationName($tmp->operation);
$rval = new $classname($tmp->data,$tmp->attachments);
if (property_exists($tmp, 'md5')){
$rval->forceChecksum($tmp->md5);
}
return $rval;
}
}
}
?>
@@ -0,0 +1,172 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/giu/2015
*/
/**
* Response example:
* {
* version: ${protocol_version},
* time: ${timestamp_microseconds},
* status: ${response_status},
* digest: ${digest},
* details: ${request}
* }
* @author Riccardo Di Dato
*
*/
class RAPI_Response extends RAPI_Message{
/*
* Class Static
*/
const STATUS_OK = 0;
const STATUS_MALFORMED = 1;
const STATUS_UNAUTHORIZED = 2;
const STATUS_INVALID = 3;
const STATUS_EXPIRED = 4;
const STATUS_INTERNAL_SERVER_ERROR = 5;
private static $STATUS_DATA = array(
self::STATUS_MALFORMED => array("message"=>"MALFORMED"),
self::STATUS_UNAUTHORIZED => array("message"=>"UNAUTHORIZED"),
self::STATUS_INVALID => array("message"=>"INVALID"),
self::STATUS_EXPIRED => array("message"=>"EXPIRED"),
self::STATUS_INTERNAL_SERVER_ERROR => array("message"=>"INTERNAL_SERVER_ERROR")
);
public static function getStatusDataMessage($status){
$rval = "UNKNOWN";
if (array_key_exists($status, self::$STATUS_DATA)){
return self::$STATUS_DATA[$status]["message"];
}
}
/*
* Attribute, setters e getters
*/
/**
* La richiesta relativa a questa risposta
* @var RAPI_Request
*/
private $related_request;
/**
* Restituisce la richiesta associata alla risposta
* @return RAPI_Request
*/
public function getRelatedRequest(){
return $this->related_request;
}
/**
* Lo stato della richiesta.
* In caso di richiesta non valida digest e details saranno vuoti
* @var int
*/
private $status;
/**
* Restituisce lo stato della richiesta
* @return int
*/
public function getStatus(){
return $this->status;
}
/*
* Costruttore
*/
/**
* @param RAPI_Request $relatedRequest La richiesta relativa a questa risposta
* @param string $protocolVersion La versione del protocollo RAPI
* @param RAPI_ResponseDetails $details Il contenuto del messaggio
* @param int $time Timestamp in microsecondi
* @param string $digest Digest per valutare l'autenticità del messaggio
*/
public function __construct(RAPI_Request $relatedRequest, $status, $protocolVersion, RAPI_ResponseDetails $details = NULL, $time = null, $digest = null){
$this->related_request = $relatedRequest;
$this->status = $status;
if ($this->status > 0){
// $details = new stdClass();
// $details->message = self::$STATUS_DATA[$this->status]["message"];
$details = new RAPI_SimpleMessageResponseDetails(self::$STATUS_DATA[$this->status]["message"]);
// $details = "{'message':'".self::$STATUS_DATA[$this->status]["message"]."'}";
}
else if (is_null($details)){
throw new RAPI_Exception("Building a RAPI_Response without passing a valid details object");
}
parent::__construct($protocolVersion, $details, $time, $digest);
}
/*
* Metodi propri della classe
*/
/**
* Ritorna true se la request corrisponde
* alla request che ha generato questa response
* @param RAPI_Request $req
* @return boolean
*/
public function fromSameRequest(RAPI_Request $req){
return $this->related_request->isEqual($req);
}
/**
* La funzione esegue l'operazione solo se la response ha come related una
* request in versione checksum, se le request corrispondono aggiorna
* la versione locale con quella completa, altrimenti lancia eccezione.
* @param RAPI_Request $req
* @return boolean
* @throws RAPI_Exception
*/
public function updateRelatedRequestChecksum(RAPI_Request $req){
if ($this->fromSameRequest($req)){
$this->related_request = $req;
}
else {
throw new RAPI_Exception("Calling function RAPI_Response::updateRelatedRequestChecksum() on not corresponding requests");
}
}
/*
* Abstract
*/
/**
* @see RAPI_Message::generateEncryptionObject()
*/
protected function generateEncryptionObject(){
$rval = $this->generateEncryptionBaseObject();
$rval->status = $this->status;
return $rval;
}
/**
* NOTA: All'oggetto va aggiunta la relatedRequest !
* @see RAPI_Message::isValidObjectForCreation()
*/
protected static function isValidObjectForCreation($obj){
return self::isValidObjectForCreationBase($obj) &&
property_exists($obj, "status") &&
property_exists($obj, "relatedRequest") &&
($obj->relatedRequest instanceof RAPI_Request);
}
/**
* @see RAPI_Message::createFromObject()
*/
public static function createFromObject($obj){
if (self::isValidObjectForCreation($obj)){
$details = null;
if ($obj->status == RAPI_Response::STATUS_OK){
$requestClass = get_class($obj->relatedRequest->getDetails());
$responseClass = $requestClass::getResponseDetailsClass();
$details = new $responseClass($obj->details->data,$obj->details->attachments);
}
return new RAPI_Response($obj->relatedRequest, $obj->status, $obj->version, $details, $obj->time, $obj->digest);
}
else {
throw new RAPI_Exception("Invalid request format");
}
}
}
?>
@@ -0,0 +1,11 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 01/lug/2015
*/
abstract class RAPI_ResponseDetails extends RAPI_MessageDetails{
}
?>
@@ -0,0 +1,18 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 02/lug/2015
*/
/**
*
* @author Riccardo Di Dato
*/
class RAPI_UnreadableRequest extends RAPI_Request{
public function __construct(){
parent::__construct("NONE", "NONE", null, RAPI_Config::RAPI_VERSION, new RAPI_UnreadableRequestDetails());
}
}
?>
@@ -0,0 +1,51 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 02/lug/2015
*/
class RAPI_UnreadableRequestDetails extends RAPI_RequestDetails {
/**
* Returns true if the operation requires an
* operationId (like for writes and deletion)
*/
public static function usesOperationId(){
return false;
}
/**
* Returns the name of the operation used by the request factory (NOT THE RAPI_Operation !!!!!)
* @return string
*/
public static function getOperationName(){
return "UNREADABLE";
}
public function __construct(){
parent::__construct(new stdClass());
}
/**
* @see RAPI_RequestDetails::getArgumentList()
*/
public static function getArgumentList(){
return array();
}
/**
* @see RAPI_RequestDetails::getResponseDetailsClass()
*/
public static function getResponseDetailsClass(){
return "RAPI_EmptyResponseDetails";
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
?>
@@ -0,0 +1,24 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 08/lug/2015
*/
class RAPI_EmptyResponseDetails extends RAPI_ResponseDetails{
/**
* @see RAPI_ResponseDetails::getArgumentList()
*/
public static function getArgumentList(){
return array();
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
?>
@@ -0,0 +1,33 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 08/lug/2015
*/
class RAPI_SimpleMessageResponseDetails extends RAPI_ResponseDetails{
/**
* @param string $message
*/
public function __construct($message){
$obj = new stdClass();
$obj->message = $message;
parent::__construct($obj);
}
/**
* @see RAPI_ResponseDetails::getArgumentList()
*/
public static function getArgumentList(){
return array("message");
}
/**
* @see RAPI_MessageDetails::getAttachmentList()
*/
public static function getAttachmentList(){
return array();
}
}
?>
@@ -0,0 +1,383 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 29/giu/2015
*/
require_once(dirname(__FILE__)."/client_include.php");
abstract class RAPI_Client {
/**
* @var RAPI_DataStorage
*/
private $dataStorage;
/**
* @var RAPI_Logger
*/
private $logger;
public function __construct(RAPI_Logger $logger, RAPI_DataStorage $dataStorage){
$this->logger = $logger;
$this->dataStorage = $dataStorage;
}
/**
* Wrapper per la funzione del logger, metodo di utilità.
* @param int $level Livello di log
* @param string $message Messaggio da scrivere nel log
*/
private function log($level, $message){
$this->logger->log($level, $message);
}
/**
* Genera un warning di sicurezza.
* @param int $level Importanza del warning
* @param string $message Messaggio da scrivere nel log
* @param RAPI_Response $data RAPI_Response che ha generato il warning
*/
private function generateSecurityWarning($severity, $message, RAPI_Response $request){
$this->logger->generateSecurityWarning($severity, $message, $request);
}
/**
* Effettua la chiamata al server per la richiesta inserita.
* Se la richiesta fallisce lancia eccezione e mette la richiesta in coda (SOLO SE USA OPERATION_ID).
* @param RAPI_RequestDetails $det
* @throws RAPI_ClientException (ANY)
* @return RAPI_ResponseDetails
*/
public function request(RAPI_RequestDetails $details){
try {
$req = $this->getRequestFromRequestDetails($details);
$response = $this->executeRequest($req);
$responseDetails = $response->getDetails();
}
catch (Exception $ex){
if ($details->usesOperationId()){
$this->dataStorage->queueUncompletedRequest($req->getOperationId(),$details);
}
throw $ex;
}
return $responseDetails;
}
/**
* Esegue una richiesta (in caso di fallimento lancia eccezione)
* @param RAPI_Request $req
* @throws RAPI_ClientException
* @return RAPI_Response
*/
private function executeRequest(RAPI_Request $req){
$this->openConnection();
$this->sendMessage($req->getEncryption());
$this->sendMessage("\n");
$attachmentList = $req->getAttachmentList();
if (sizeof($attachmentList)>0){
foreach ($attachmentList as $attachment){
$msg = $this->getMessage(2048);
if (strcmp($msg, "<< ----- ACK / $attachment ----- >>\n")!=0){
$this->logger->log(RAPI_Logger::LOG_LEVEL_ERROR, "Invalid protocol use, client not sending ACK message for attachment '$attachment'. The request will be rejected");
throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE);
}
$buffer = "";
$filePath = $req->getAttachmentLocalFileReference($attachment);
$fh = fopen($filePath, "rb");
do {
$buffer = fread($fh, 32768);
$this->sendMessage($buffer);
}
while(!feof($fh));
// while ( ($buffer = fread($fh, 2048)) !== false ) {
// $this->sendMessage($buffer);
// }
fclose($fh);
$this->sendMessage("\n");
}
}
$textResponse = $this->getMessage();
$response = RAPI_Response::fromEncrypted($textResponse,array("relatedRequest"=>$req));
$this->validateResponse($response);
$attachmentList = $response->getAttachmentList();
if ($response->getStatus() == RAPI_Response::STATUS_OK && sizeof($attachmentList)>0){
foreach ($attachmentList as $attachment){
$data = $response->getAttachmentData($attachment);
$buffer = "";
$this->sendMessage("<< ----- ACK / $attachment ----- >>");
$this->sendMessage("\n");
$filePath = $this->getReceivedAttachmentPath()."/".uniqid($attachment."_");
$fh = fopen($filePath, "wb");
$next = $this->getMessage(32768);
while ($next!==false) {
$current = $next;
$length = strlen($current);
$next = $this->getMessage(32768);
if ($next===false){
$length = $length-1;
}
fwrite($fh,$current,$length);
}
// while ( ($buffer = $this->getMessage(2048)) !== false ){
// fwrite($fh,$buffer);
// }
fclose($fh);
if (filesize($filePath)!=$data->size){
$this->logger->log(RAPI_Logger::LOG_LEVEL_ERROR, "The received file has invalid size for attachment '$attachment'. The request will be rejected");
throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE);
}
if ( strcmp(md5_file($filePath),$data->md5)!=0 ){
$this->logger->log(RAPI_Logger::LOG_LEVEL_ERROR, "The received file has invalid MD5 for attachment '$attachment'. The request will be rejected");
throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE);
}
$response->setAttachmentLocalFileReference($attachment,$filePath);
}
}
$this->closeConnection();
return $response;
}
// /**
// * Esegue una richiesta e restituisce la risposta
// * @param RAPI_Request $req
// * @param string $forceOperationId se null usa il prossimo libero, altrimenti usa quello ricevuto
// * @throws RAPI_ClientException
// * @return RAPI_Response
// */
// private function getResponse(RAPI_Request $req){
// $ans = $this->sendMessage($req->getEncryption());
// try {
// $response = RAPI_Response::fromEncrypted($ans,array("relatedRequest"=>$req));
// }
// catch (RAPI_Exception $rex){
// $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Impossible to parse response. Reason: '".$rex->getMessage()."'");
// throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE);
// }
// $this->validateResponse($response);
// return $response;
// }
/**
* Riprova ad eseguire le operazioni in pending.
* Limit limita il numero di operazioni da riprovare ad eseguire.
* @param int $limit per limitare la quantità di operazioni
* @throws RAPI_ClientException
*/
public function executePendingRequests($limit = null){
$reqsDetails = $this->dataStorage->getUncompletedRequests($limit);
if (sizeof($reqsDetails)>0){
$excs = array();
foreach ($reqsDetails as $id=>$details){
try {
$req = $this->getRequestFromRequestDetails($details,$id);
$resp = $this->executeRequest($req);
$this->dataStorage->onRequestCompletedFromQueue($id);
}
catch (Exception $ex){
$excs[] = "(".$ex->getMessage().")";
$this->dataStorage->onRequestFailedFromQueue($id);
}
}
if (sizeof($excs)>0){
$this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Errors while executing queue in ".sizeof($excs)." requests. Messages: ".implode(", ", $excs));
throw new RAPI_ClientException(RAPI_ClientException::INVALID_UNPARSABLE);
}
}
}
// /**
// * Restituisce la stringa col messaggio
// * @param string $msg
// * @returns string
// */
// private function sendMessage($msg){
// $service_port = getservbyname('rapi', 'tcp');
// $address = RAPI_Config::RAPI_SERVER_ADDRESS;
// $this->log(RAPI_Logger::LOG_LEVEL_INFO,"Connecting to '$address:$service_port'");
// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Creating TCP socket");
// $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// if ($socket === false) {
// $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Impossible to create TCP socket. Reason: '".socket_strerror(socket_last_error())."'");
// throw new RAPI_ClientException(RAPI_ClientException::CONNECTION_ERROR);
// }
// else {
// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"TCP Socket created successfully");
// }
// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Connecting to '$address:$service_port'");
// $result = socket_connect($socket, $address, $service_port);
// if ($result === false) {
// $this->log(RAPI_Logger::LOG_LEVEL_ERROR,"Impossible to connect to '$address:$service_port'. Reason: '".socket_strerror(socket_last_error($socket))."'");
// throw new RAPI_ClientException(RAPI_ClientException::CONNECTION_ERROR);
// }
// else {
// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"TCP Socket connection complete");
// }
// $this->log(RAPI_Logger::LOG_LEVEL_INFO,"Sending request to '$address:$service_port'");
// socket_write($socket, $msg, strlen($msg));
// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Reading response from '$address:$service_port'");
// $out = '';
// $acc = '';
// while ($out = socket_read($socket, 2048)) {
// $acc .= $out;
// }
// $this->log(RAPI_Logger::LOG_LEVEL_DEBUG,"Response from '$address:$service_port' complete");
// $this->log(RAPI_Logger::LOG_LEVEL_INFO,"Closing connection to '$address:$service_port'");
// socket_close($socket);
// return $acc;
// }
// /**
// * Genera una RAPI_Request a partire da una RAPI_RequestDetails.
// * @param RAPI_RequestDetails $details
// * @param string $forceOperationId se null usa il prossimo libero, altrimenti usa quello ricevuto
// * @return RAPI_Request
// */
// private function wrapRequest(RAPI_RequestDetails $details, $forceOperationId = null){
// $account = $this->dataStorage->getRapiAccount();
// $user = $this->dataStorage->getRapiUser();
// $operationId = $details::usesOperationId()?(is_null($forceOperationId)?$this->dataStorage->getNextOperationId():$forceOperationId):null;
// $protocolVersion = RAPI_Config::RAPI_VERSION;
// $req = new RAPI_Request($account, $user, $operationId, $protocolVersion, $details);
// $req->setDigest(RAPI_CryptUtils::getDigestForMessage($req, $this->dataStorage->getRapiPassphrase()));
// return $req;
// }
/**
* Genera una RAPI_Request a partire da una RAPI_RequestDetails.
* @param RAPI_RequestDetails $details
* @param string $forceOperationId se null usa il prossimo libero, altrimenti usa quello ricevuto
* @return RAPI_Request
*/
private function getRequestFromRequestDetails(RAPI_RequestDetails $details, $forceOperationId = null){
$account = $this->dataStorage->getRapiAccount();
$user = $this->dataStorage->getRapiUser();
$operationId = null;
if ($details::usesOperationId()){
if (is_null($forceOperationId)){
$operationId = $this->dataStorage->getNextOperationId();
$this->dataStorage->setMaxOperationId($operationId);
}
else {
$operationId = $forceOperationId;
}
}
$protocolVersion = RAPI_Config::RAPI_VERSION;
$req = new RAPI_Request($account, $user, $operationId, $protocolVersion, $details);
$req->setDigest(RAPI_CryptUtils::getDigestForMessage($req, $this->dataStorage->getRapiPassphrase()));
return $req;
}
/**
* Valuta che la versione del protocollo utilizzata nella risposta sia la stessa del client.
* Lancia eccezione in caso di richiesta non valida
* @param RAPI_Response $req La risposta
* @throws RAPI_ClientException (INVALID_PROTOCOL)
*/
private function validateProtocolVersion(RAPI_Response $resp){
if (RAPI_Config::RAPI_VERSION != $resp->getProtocolVersion()){
$this->log(RAPI_Logger::LOG_LEVEL_WARNING, "Invalid protocol version detected (".$resp->getProtocolVersion()."). The response will be rejected");
throw new RAPI_ClientException(RAPI_ClientException::INVALID_PROTOCOL);
}
}
/**
* Valuta che la risposta sia in status OK.
* Lancia eccezione in caso di status non valido
* @param RAPI_Response $req La risposta
* @throws RAPI_ClientException (INVALID_STATUS)
*/
private function validateStatus(RAPI_Response $resp){
if (RAPI_Response::STATUS_OK != $resp->getStatus()){
$this->log(RAPI_Logger::LOG_LEVEL_INFO, "Invalid status detected (".RAPI_Response::getStatusDataMessage($resp->getStatus())."). The response will be rejected");
throw new RAPI_ClientException(RAPI_ClientException::INVALID_STATUS);
}
}
/**
* Valuta che il digest della risposta sia valido.
* Lancia eccezione in caso di digest non valido
* @param RAPI_Response $req La risposta
* @throws RAPI_ClientException (INVALID_DIGEST)
*/
private function validateDigest(RAPI_Response $resp){
if ( strcmp("", $resp->getDigest())==0 ){
$this->log(RAPI_Logger::LOG_LEVEL_INFO, "Invalid digest detected. The incident will be reported");
$this->generateSecurityWarning(RAPI_Logger::WARNING_SEVERITY_HIGH, "Rejecting a connection because has no digest", $resp);
throw new RAPI_ClientException(RAPI_ClientException::INVALID_DIGEST);
}
else if ($resp->getDigest() != RAPI_CryptUtils::getDigestForMessage($resp, $this->dataStorage->getRapiPassphrase())){
$this->log(RAPI_Logger::LOG_LEVEL_INFO, "Invalid digest detected. The incident will be reported");
$this->generateSecurityWarning(RAPI_Logger::WARNING_SEVERITY_CRITICAL, "Rejecting a connection because has an invalid digest", $resp);
throw new RAPI_ClientException(RAPI_ClientException::INVALID_DIGEST);
}
}
/**
* Effettua i vari controlli sulla risposta.
* Lancia eccezione in caso di risposta non valida
* @param RAPI_Response $req La risposta
* @throws RAPI_ClientException (INVALID_DIGEST INVALID_STATUS INVALID_PROTOCOL)
*/
private function validateResponse(RAPI_Response $resp){
$this->validateProtocolVersion($resp);
$this->validateStatus($resp);
$this->validateDigest($resp);
}
/**
* Opens a connection (socket, file stream ecc)
*/
protected abstract function openConnection();
/**
* Closes a connection (socket, file stream ecc)
*/
protected abstract function closeConnection();
/**
* Sends a message
*/
protected abstract function sendMessage($msg);
/**
* Reads a message. BufferSize rappresenta la dimensione del buffer da utilizzare,
* la funzione ritorna false se non c'è niente da leggere
*/
protected abstract function getMessage($bufferSize = null);
/**
* Write attachment step
*/
protected abstract function getReceivedAttachmentPath();
}
?>
@@ -0,0 +1,34 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 01/lug/2015
*/
class RAPI_ClientException extends RAPI_Exception{
const CONNECTION_ERROR = 1;
const INVALID_PROTOCOL = 2;
const INVALID_STATUS = 3;
const INVALID_DIGEST = 4;
const INVALID_UNPARSABLE = 5;
private $status;
private static $ERROR_NAMES = array(
self::CONNECTION_ERROR => "CONNECTION_ERROR",
self::INVALID_PROTOCOL => "INVALID_PROTOCOL",
self::INVALID_STATUS => "INVALID_STATUS",
self::INVALID_DIGEST => "INVALID_DIGEST",
self::INVALID_UNPARSABLE => "INVALID_UNPARSABLE"
);
public function __construct($status){
$this->status = $status;
parent::__construct("RAPI_ClientException 'Status $status' - ".self::$ERROR_NAMES[$this->status]);
}
public function getStatus (){
return $this->status;
}
}
?>
@@ -0,0 +1,120 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 02/lug/2015
*/
/**
* Classe a cui è possibile aggiungere metodi a partire da RAPI_Request.
* Utilizzare defineRequest per aggiungere metodi.
*
* @author Riccardo Di Dato
*
*/
class RAPI_ClientHelper {
private $client;
private $requests = array();
public function __construct(RAPI_Client $client){
$this->client = $client;
}
/**
* Chiama il metodo richiesto e ne fetcha il risultato.
*
* @param string $name Nome del metodo
* @param mixed $values Argomenti da passare al metodo
* @throws RAPI_ClientException Rilancia le eccezioni del client
* @throws RAPI_Exception Se il metodo non esiste o gli argomenti non sono validi o se il fetcher lancia eccezione
* @return mixed In base al fetcher
*/
public function __call($name, array $values){
if (!array_key_exists($name, $this->requests)){
throw new RAPI_Exception("Call to undefined function RAPI_ClientHelper::$methodName");
}
$resp = $this->client->request($this->generateDetails($name, $values));
return $this->fetchResponse($name, $resp);
}
/**
* Aggiunge un metodo all'helper.
*
* @param string $name Il nome con cui si desidera chiamare il metodo
* @param string $className Nome della RAPI_RequestDetails associata alla request
* @param RAPI_ResponseFetcher $respFetcher Il metodo per fetchare la risposta
*/
public function defineRequest($name, $className, RAPI_ResponseFetcher $respFetcher){
if (class_exists($className) && (is_subclass_of($className, "RAPI_RequestDetails") ) ){
$this->requests[$name]['class'] = $className;
$this->requests[$name]['fetcher'] = $respFetcher;
}
else {
if (!class_exists($className)){
throw new RAPI_Exception("Invalid method definition. Undefined class '$className'");
}
else {
throw new RAPI_Exception("Invalid method definition. Class '$className' is not a RAPI_RequestDetails");
}
}
}
/**
* Genera una RAPI_RequestDetails a partire dal nome del metodo chiamato e dagli
* argomenti da passargli.
* Lancia eccezione se il numero di argomenti passati non corrisponde a quelli
* del metodo chiamato o se il metodo non esiste.
*
* @param string $methodName Nome del metodo chiamato
* @param array $args Gli argomenti da passare alla RAPI_RequestDetails
* @throws RAPI_Exception Se il metodo non esiste o se $args non è valido
* @return RAPI_RequestDetails I details da utilizzare per il metodo chiamato
*/
private function generateDetails($methodName, array $args){
$className = $this->requests[$methodName]['class'];
$argList = $className::getArgumentList();
$attList = $className::getAttachmentList();
if (sizeof($args) != (sizeof($argList) + sizeof($attList)) ){
$paramString = implode(", ",array_map(function($d){return "\$".$d."";}, array_merge($argList,$attList)));
throw new RAPI_Exception("Invalid arguments passed to function RAPI_ClientHelper::$methodName($paramString). (Received ".sizeof($args)." arguments)");
}
$constructObj = new stdClass();
$i = 0;
foreach ($argList as $argName){
$constructObj->$argName = $args[$i++];
}
$constructAtt = array();
foreach ($attList as $argName){
$localFile = $args[$i++];
$attData = new stdClass();
$attData->name = $argName;
$attData->size = filesize($localFile);
$attData->md5 = md5_file($localFile);
$attData->localReference = $localFile;
$constructAtt[] = $attData;
}
return new $className($constructObj,$constructAtt);
}
/**
* Chiama il fetcher del metodo passandogli la RAPI_ResponseDetails.
* Fetcha il risultato e lo restituisce.
*
* @param string $methodName Nome del metodo chiamato
* @param RAPI_ReponseDetails $response Risposta da fetchare
* @throws RAPI_Exception Se il metodo non esiste o se il fetcher lancia eccezione
* @return mixed In base a ciò che ritorna il fetch
*/
private function fetchResponse($methodName, RAPI_ResponseDetails $response){
// if (!array_key_exists($methodName, $this->requests)){
// throw new RAPI_Exception("Invalid call to RAPI_ClientHelper::fetchResponse for method '$methodName'. (The method is undefined)");
// }
return $this->requests[$methodName]['fetcher']($response);
}
}
?>
@@ -0,0 +1,70 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 29/giu/2015
*/
interface RAPI_DataStorage {
/**
* Returns the passphrase
* @return string
*/
public function getRapiPassphrase();
/**
* Returns the account
* @return string
*/
public function getRapiAccount();
/**
* Returns the user
* @return string
*/
public function getRapiUser();
/**
* Returns the next valid operationId
* @return id
*/
public function getNextOperationId();
/**
* Set max operationId
* @param int $id
*/
public function setMaxOperationId($id);
/**
* Queue uncompleted operations
* @param string $id operationID
* @param RAPI_RequestDetails $req
*/
public function queueUncompletedRequest($id, RAPI_RequestDetails $req);
/**
* Returns the list of uncompleted requests. The array keys are the operationIds.
*
* NOTE: This function doesn't remove items from the list, to delete
* elements from the list use RAPI_DataStorage::onRequestCompletedFromQueue()
* @param int $limit null for no limit
* @return RAPI_RequestDetails[]
*/
public function getUncompletedRequests($limit = null);
/**
* Operazione eseguita quando la richiesta viene completata con SUCCESSO dalla coda
* @param string $id operationID
*/
public function onRequestCompletedFromQueue($id);
/**
* Operazione eseguita quando la richiesta fallisce dalla coda
* @param string $id operationID
*/
public function onRequestFailedFromQueue($id);
}
?>
@@ -0,0 +1,20 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 25/giu/2015
*/
require_once(dirname(__FILE__)."/../include.php");
require_once(dirname(__FILE__)."/RAPI_ClientException.php");
require_once(dirname(__FILE__)."/RAPI_DataStorage.php");
require_once(dirname(__FILE__)."/RAPI_ClientHelper.php");
require_once(dirname(__FILE__)."/request_helper/RAPI_ResponseFetcher.php");
require_once(dirname(__FILE__)."/request_helper/RAPI_SingleValueResponseFetcher.php");
require_once(dirname(__FILE__)."/request_helper/RAPI_StandardResponseFetcher.php");
?>
@@ -0,0 +1,13 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 02/lug/2015
*/
interface RAPI_ResponseFetcher {
public function __invoke(RAPI_ResponseDetails $resp);
}
?>
@@ -0,0 +1,26 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 09/lug/2015
*/
class RAPI_SingleValueResponseFetcher implements RAPI_ResponseFetcher {
private $paramName;
private $callback;
public function __construct($paramName, callable $callback = null){
$this->paramName = $paramName;
$this->callback = $callback;
}
public function __invoke(RAPI_ResponseDetails $resp){
$rval = $resp->getData()->{$this->paramName};
if (!is_null($this->callback)){
$cb = $this->callback;
$rval = $cb($rval);
}
return $rval;
}
}
?>
@@ -0,0 +1,33 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 09/lug/2015
*/
class RAPI_StandardResponseFetcher implements RAPI_ResponseFetcher {
private $callback;
public function __construct(callable $callback = null){
$this->callback = $callback;
}
public function __invoke(RAPI_ResponseDetails $resp){
$rval = new stdClass();
$rval->data = $resp->getData();
$rval->attachments = array();
$attList = $resp->getAttachmentList();
if (sizeof($attList)>0){
foreach ($attList as $att){
$rval->attachments[$att] = $resp->getAttachmentLocalFileReference($att);
}
}
if (!is_null($this->callback)){
$cb = $this->callback;
$rval = $cb($rval);
}
return $rval;
}
}
?>
+18
View File
@@ -0,0 +1,18 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 23/feb/2016
*/
require_once(dirname(__FILE__)."/cbsClient/cbs.client.include.php");
require_once(dirname(__FILE__)."/FDN2CBS_Logger.php");
require_once(dirname(__FILE__)."/FDN2CBS_DataStorage.php");
$cbsLogger = new FDN2CBS_Logger();
$cbsDataStorage = new FDN2CBS_DataStorage();
$cbsClient = new CBSClient($cbsLogger, $cbsDataStorage,GlobalVariables::get("config")->paths->backupTmp);
GlobalVariables::set("backupClient",$cbsClient);
?>
+10
View File
@@ -8,6 +8,7 @@ class GenericDao{
private $mongoObj;
private $database;
private $dbName;
/**
* La connection string viene passata interamente a MongoClient, richiede formato 'mongo://server:port'.
* host1 e database sono obbligatori
@@ -25,8 +26,17 @@ class GenericDao{
$this->mongoObj = new MongoClient($connectionString);
}
$this->dbName = $dbName;
$this->database = $this->mongoObj->$dbName;
}
/**
* Restituisce il nome del database attualmente in uso
* @return string
*/
public function getDbName(){
return $this->dbName;
}
/**
* Ritorna un array di model
+3 -1
View File
@@ -33,9 +33,11 @@ require_once(dirname(__FILE__)."/models/AccessModel.php");
require_once(dirname(__FILE__)."/models/LogModel.php");
require_once(dirname(__FILE__)."/models/StatisticModel.php");
require_once(dirname(__FILE__)."/models/BannerModel.php");
require_once(dirname(__FILE__)."/models/CBSQueueModel.php");
$dao = new GenericDao($database->dbName,$database->connectionString);
GlobalVariables::set("dao", $dao);
?>
+23
View File
@@ -0,0 +1,23 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 22/feb/2016
*/
class CBSQueueModel extends Model{
public function __construct($saveableObject = null){
parent::__construct($saveableObject);
if (!$this->hasProperty("retry")){
$this->retry = 0;
}
}
public static function getCollectionName(){
return "CBS_queue";
}
}
?>
+1 -1
View File
@@ -7,7 +7,7 @@ Creation Date: 14/gen/2016
class HTMLHelper {
public static function generateAdminHead() {
echo '<div class="admin_head"><img alt="" src="'.GUIHandler::getImagesUrl()."header.png".'"></div>';
echo '<div class="admin_head"><img alt="" src="'.GUIHandler::getImagesUrl()."admin/header.png".'"></div>';
}
public static function generateModelsTable(array $columnInfo, array $models, array $datatableOpts = array()) {
+2
View File
@@ -35,11 +35,13 @@ require_once(dirname(__FILE__)."/dao/lib.inclusion.php");
require_once(dirname(__FILE__)."/task/lib.inclusion.php");
require_once(dirname(__FILE__)."/backup/lib.inclusion.php");
// Special utility modules
require_once(dirname(__FILE__)."/FDN_MailHelper.php");
require_once(dirname(__FILE__)."/AnalyticsHelper.php");
require_once(dirname(__FILE__)."/PipelineHelper.php");
?>
+6
View File
@@ -64,4 +64,10 @@ LoggingFacilityManager::addLogger(
);
LoggingFacilityManager::getLogger("mail")->setLoggingLevel(LoggingFacility::$LEVEL_DEBUG);
LoggingFacilityManager::addLogger(
"api",
new FileLogger("API",$systemCatalogManager,$config->files->api_log,true)
);
LoggingFacilityManager::getLogger("api")->setLoggingLevel(LoggingFacility::$LEVEL_DEBUG);
?>
+4
View File
@@ -158,4 +158,8 @@ abstract class FSObject {
*/
public abstract function lsDir($path);
public abstract function createArchive($path,$origin);
public abstract function deleteDirectory($source,$destination,$sudo);
}?>
+15
View File
@@ -123,5 +123,20 @@ class SFSManager {
}
}
// Accepts file array or single directory
public static function createArchive($source,$dest){
$fso=self::getFSObjByPath($dest);
if($fso!=null){
return $fso->createArchive($dest,$source);
}
}
public static function deleteDirectory($path,$sudo=false){
$fso=self::getFSObjByPath($path);
if($fso!=null){
return $fso->deleteDirectory($path,$sudo);
}
}
}
?>
+4
View File
@@ -74,6 +74,10 @@ class SystemController {
return self::shellExec("rm",'"'.$path.'"',$useSudo);
}
public static function rmDir($path,$useSudo=false){
return self::shellExec("rm",'-r "'.$path.'"',$useSudo);
}
public static function wget($targetPage,$destFile,$useSudo=false){
return self::shellExec("wget",'-O "'.$destFile.'" '.$targetPage,$useSudo);
}
@@ -168,4 +168,56 @@ class LocallyMountedFS extends FSObject {
}
return $rval;
}
/**
* (non-PHPdoc)
* @see FSObject::createArchive()
*/
public function createArchive($path,$origin){
if ($this->accessMode==self::$ACCESSMODE_RO || $this->writeLaw==parent::$WRITELAW_NOT_WRITEABLE){
throw new SFSException('fsobj.not_writeable',$this->name);
}
else if ($this->writeLaw==parent::$WRITELAW_NORMALLY_W) {
$matches= array();
if (preg_match("/^(.*)\.gz$/",$path,$matches)){
$path = $matches[1];
}
$a = new PharData($path);
if (is_array($origin) && sizeof($origin)>0){
foreach ($origin as $file){
$a->addFile($file);
}
}
else {
$a->buildFromDirectory($origin);
}
$a->compress(Phar::GZ); // Crea il file .tar.gz
unset($a);
$this->deleteFile($path); // Cancella il tar (non il tar.gz)
}
else if ($this->writeLaw==parent::$WRITELAW_NORMALLY_RO) {
SystemController::mountRw($this->mountPoint);
$matches= array();
if (preg_match("/^(.*)\.gz$/",$path,$matches)){
$path = $matches[1];
}
$a = new PharData($path);
if (is_array($origin) && sizeof($origin)>0){
foreach ($origin as $file){
$a->addFile($file);
}
}
else {
$a->buildFromDirectory($origin);
}
$a->compress(Phar::GZ); // Crea il file .tar.gz
unset($a);
$this->deleteFile($path); // Cancella il tar (non il tar.gz)
SystemController::mountRw($this->mountPoint);
}
}
public function deleteDirectory($source,$destination,$useSudo=false){
$this->useSysFunction("rmDir",$source,$destination,$useSudo);
}
}
+7 -1
View File
@@ -61,5 +61,11 @@ SFSManager::addFilesystem(new LocallyMountedFS(
$config->paths->xsendfile,
"XSendFile Filesystem")
);
SFSManager::addFilesystem(new LocallyMountedFS(
FSObject::$DEVICE_TYPE_HARD_DRIVE,
FSObject::$WRITELAW_NORMALLY_W,
LocallyMountedFS::$ACCESSMODE_RW,
$config->paths->cbsQueue,
"CBS Queue Filesystem")
);
?>
+36
View File
@@ -0,0 +1,36 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 23/feb/2016
*/
class SendBackupTask extends Task {
public static function getName(){
return "sendBackup";
}
public static function getLabel(){
return "Invio backup";
}
public static function execute(){
$config = GlobalVariables::get("config");
$dbName = GlobalVariables::get("dao")->getDbName();
$backDir = $config->paths->backup."/mongoDump";
SystemController::shellExec("mongodump","-d $dbName -o $backDir");
$archive = $config->paths->tmp."/backup.tar.gz";
// if (SFSManager::fileExists($archive)){
// SFSManager::deleteFile($archive);
// }
// SFSManager::createArchive($config->paths->storage, $archive);
GlobalVariables::get("backupClient")->sendBackup("backup_".date("d-m-Y").".tar.gz",$archive);
// OLD
// GlobalVariables::get("backupClient")->sendBackup(utf8_encode(file_get_contents($archive)),"backup_".date("d-m-Y").".tar.gz");
}
}
?>
+2
View File
@@ -8,4 +8,6 @@ require_once(dirname(__FILE__)."/Task.php");
require_once(dirname(__FILE__)."/MailSendTask.php");
require_once(dirname(__FILE__)."/NewsletterCheckTask.php");
require_once(dirname(__FILE__)."/SendBackupTask.php");
?>
+1 -1
View File
@@ -20,7 +20,7 @@ MenuGenerator::generateMenu();
HTMLHelper::generateAdminHead();
$taskList = array("MailSendTask","NewsletterCheckTask");
$taskList = array("MailSendTask","NewsletterCheckTask","SendBackupTask");
$saved = false;
$action = PostHandler::get("action");
+2 -3
View File
@@ -35,10 +35,9 @@ echo '<body class="white">';
?>
<div id="login_page">
<div class="pageHead">
<img class="scritta" src="../images/header.png" />
<img class="scritta" src="../images/admin/header.png" />
</div>
<div class="loginArea">
<p>Login</p>
<div style="text-align:center;">
<table style="margin-left:auto;margin-right:auto;"><tr><td>
<div id="loginformdiv">
@@ -51,7 +50,7 @@ echo '<body class="white">';
<div class="formRow">
<input id="pass_fld" type="password" name="pass" value="" placeholder="Password"></input>
</div>
<div class="btnDiv">
<div class="formBtns">
<a href="#" onClick="javascript:$('#loginformdiv form').submit();return false;" class="btn">Login</a>
</div>
</form>
+71 -151
View File
@@ -20,69 +20,25 @@ MenuGenerator::generateMenu();
HTMLHelper::generateAdminHead();
$pipeline = array(
array(
'$match'=>array(
'statType'=>StatisticModel::STAT_TYPE_PAGE
)
),
array(
'$group'=>array(
"_id"=>array(
'date'=>array(
"day"=>array('$dayOfMonth'=>'$date'),
"month"=>array('$month'=>'$date'),
"year"=>array('$year'=>'$date')
),
'user'=>'$user.id',
),
"visualizzazioni"=>array(
'$sum'=>1
),
"isNew"=>array(
'$sum'=>array(
'$cond'=>array(
array('$eq'=>array('$user.isNew',true)),
1,
0
)
)
)
)
),
array(
'$group'=>array(
"_id"=>array(
'date'=>'$_id.date'
),
"visualizzazioni"=>array(
'$sum'=>'$visualizzazioni'
),
"unici"=>array(
'$sum'=>'$isNew'
),
"visitatori"=>array(
'$sum'=>1
)
)
)
);
// Pipeline Visualizzazioni, Visitatori, Unici Ultimo mese
$result = GlobalVariables::get("dao")->aggregate("StatisticModel",$pipeline);
$result = GlobalVariables::get("dao")->aggregate("StatisticModel",PipelineHelper::getDailyVisualizationPipeline(strtotime("-1 month")));
for ($i=0; $i<sizeof($result); $i++){
$ele = $result[$i];
$result[$i]["mktime"] = mktime(1,0,0,$ele["_id"]["date"]["month"],$ele["_id"]["date"]["day"],$ele["_id"]["date"]["year"]) *1000;
}
?>
<div>
<?php
var_dump($result);
?>
<div id="container"></div>
<div id="containerDaily"></div>
<hr/>
<div id="containerMonthly"></div>
</div>
<script type="text/javascript">
$(function () {
$('#container').highcharts({
$('#containerDaily').highcharts({
title: {
text: 'Visualizzazioni e visitatori'
text: 'Visualizzazioni questo mese'
},
tooltip:{
@@ -93,7 +49,7 @@ $(function () {
xAxis:{
type:'datetime',
// tickInterval: 3600*1000,
tickInterval: 24*3600*1000,
labels:{
formatter: function() {
return Highcharts.dateFormat("%d/%m/%Y", this.value, false);
@@ -101,12 +57,18 @@ $(function () {
}
},
yAxis:{
title:{
text:"Visite"
}
},
series: [{
name: 'Visualizzazioni',
data: [<?php
$i = 0;
foreach ($result as $ele){
echo ($i++==0?"":", ")."[".(mktime(null,null,null,$ele["_id"]["date"]["month"],$ele["_id"]["date"]["day"],$ele["_id"]["date"]["year"]) ).",".$ele["visualizzazioni"]."]";
echo ($i++==0?"":", ")."[".($ele["mktime"]).",".$ele["visualizzazioni"]."]";
}
?>]
}, {
@@ -114,7 +76,7 @@ $(function () {
data: [<?php
$i = 0;
foreach ($result as $ele){
echo ($i++==0?"":", ").$ele["visitatori"];
echo ($i++==0?"":", ")."[".($ele["mktime"]).",".$ele["visitatori"]."]";
}
?>]
}, {
@@ -122,115 +84,73 @@ $(function () {
data: [<?php
$i = 0;
foreach ($result as $ele){
echo ($i++==0?"":", ").$ele["unici"];
echo ($i++==0?"":", ")."[".($ele["mktime"]).",".$ele["unici"]."]";
}
?>]
}]
});
$('#zzz').highcharts({
title: {
text: 'Visualizzazioni e visitatori'
<?php
$result = GlobalVariables::get("dao")->aggregate("StatisticModel",PipelineHelper::getMonthlyVisualizationPipeline(strtotime("-1 year")));
for ($i=0; $i<sizeof($result); $i++){
$ele = $result[$i];
$result[$i]["mktime"] = mktime(1,0,0,$ele["_id"]["date"]["month"],1,$ele["_id"]["date"]["year"]) *1000;
}
?>
$('#containerMonthly').highcharts({
title: {
text: 'Visualizzazioni quest\'anno'
},
subtitle: {
text: 'Source: ASDynamics'
tooltip:{
xDateFormat:"%m - %Y",
crosshairs:[true],
shared: true
},
xAxis: {
tickInterval: 7 * 24 * 3600 * 1000, // one week
tickWidth: 0,
gridLineWidth: 1,
labels: {
align: 'left',
x: 3,
y: -3
}
xAxis:{
type:'datetime',
// tickInterval: 30*24*3600*1000,
labels:{
formatter: function() {
return Highcharts.dateFormat("%m - %Y", this.value, false);
}
}
},
yAxis: [{ // left y axis
title: {
text: null
},
labels: {
align: 'left',
x: 3,
y: 16,
format: '{value:.,0f}'
},
showFirstLabel: false
}, { // right y axis
linkedTo: 0,
gridLineWidth: 0,
opposite: true,
title: {
text: null
},
labels: {
align: 'right',
x: -3,
y: 16,
format: '{value:.,0f}'
},
showFirstLabel: false
}],
legend: {
align: 'left',
verticalAlign: 'top',
y: 20,
floating: true,
borderWidth: 0
},
tooltip: {
shared: true,
crosshairs: true
},
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function (e) {
hs.htmlExpand(null, {
pageOrigin: {
x: e.pageX || e.clientX,
y: e.pageY || e.clientY
},
headingText: this.series.name,
maincontentText: Highcharts.dateFormat('%A, %b %e, %Y', this.x) + ':<br/> ' +
this.y + ' visits',
width: 200
});
}
}
},
marker: {
lineWidth: 1
}
}
yAxis:{
title:{
text:"Visite"
}
},
series: [{
name: 'Tokyo',
data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
name: 'Visualizzazioni',
data: [<?php
$i = 0;
foreach ($result as $ele){
echo ($i++==0?"":", ")."[".($ele["mktime"]).",".$ele["visualizzazioni"]."]";
}
?>]
}, {
name: 'New York',
data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
name: 'Visitatori',
data: [<?php
$i = 0;
foreach ($result as $ele){
echo ($i++==0?"":", ")."[".($ele["mktime"]).",".$ele["visitatori"]."]";
}
?>]
}, {
name: 'Berlin',
data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
}, {
name: 'London',
data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
name: 'Unici',
data: [<?php
$i = 0;
foreach ($result as $ele){
echo ($i++==0?"":", ")."[".($ele["mktime"]).",".$ele["unici"]."]";
}
?>]
}]
});
});
});
</script>
</script>
+32
View File
@@ -0,0 +1,32 @@
<?php
/*
Author: Riccardo Di Dato
Creation Date: 05/feb/2016
*/
require_once(dirname(__FILE__)."/load.php");
try {
$articolo = null;
if (array_key_exists("id", $_GET)){
$articolo = GlobalVariables::get("dao")->getFirst("NotiziaModel",array("id"=>$_GET["id"]));
}
if (is_null($articolo)){
GUIHandler::redirect("index.php");
}
AnalyticsHelper::logNotiziaImpression($articolo->id);
AnalyticsHelper::logPageImpression();
GUIHandler::generateHtmlHeaders();
echo $articolo->titolo;
}catch(GUIException $ex){
$error = $ex->getMessage();
}catch (Exception $exec){
$msg = LogModel::fromException($exec);
GlobalVariables::get("dao")->save($msg);
GUIHandler::redirect("index.php");
}
?>
+12 -1
View File
@@ -12,7 +12,7 @@
#admin_menu ul ul li a{padding-left:25px; }
#admin_menu ul ul{height:0px;}
.admin_head{margin-left:300px;}
.admin_head{margin-left:300px; text-align:center;}
.admin_head + div{margin-left:300px; padding: 20px; position:relative;min-height:50px;}
@@ -24,6 +24,17 @@ table.dataTable tr.even td{background-color:rgba(126, 151, 214, 0.4); }
.dataTables_wrapper .toolbar > *{vertical-align:middle;}
/*
_ _ ____
| | ___ __ _(_)_ __ | _ \ __ _ __ _ ___
| | / _ \ / _` | | '_ \ | |_) / _` |/ _` |/ _ \
| |__| (_) | (_| | | | | | | __/ (_| | (_| | __/
|_____\___/ \__, |_|_| |_| |_| \__,_|\__, |\___|
|___/ |___/
*/
#login_page .pageHead{text-align:center;}
#login_page .formRow input{padding:9px 6px;}
/*
_____
| ___|__ _ __ _ __ ___