Initial Commit
This commit is contained in:
111
core/Api/ExecuteSelect.class.php
Normal file
111
core/Api/ExecuteSelect.class.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
|
||||
class ExecuteSelect extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
'query' => new StringType('query')
|
||||
));
|
||||
|
||||
$this->isPublic = false;
|
||||
$this->variableParamCount = true;
|
||||
}
|
||||
|
||||
public function getDescription() { return 'Führt ein SELECT Statement aus.'; }
|
||||
public function getSection() { return "Internal"; }
|
||||
|
||||
public function execute($aValues = array()) {
|
||||
if(!parent::execute($aValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->success = false;
|
||||
$this->result['rows'] = array();
|
||||
|
||||
if(count($this->params) === 1) {
|
||||
$res = $this->user->getSQL()->query($this->getParam('query'));
|
||||
if(!$res) {
|
||||
$this->lastError = 'Database Error: query() failed with ' . $this->user->getSQL()->getLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
while($row = $res->fetch_assoc()) {
|
||||
array_push($this->result['rows'], $row);
|
||||
}
|
||||
|
||||
$this->success = true;
|
||||
$res->close();
|
||||
} else {
|
||||
$aSqlParams = array('');
|
||||
foreach($this->params as $param) {
|
||||
if($param->name === 'query') continue;
|
||||
|
||||
$value = $param->value;
|
||||
switch($param->type) {
|
||||
case Parameter::TYPE_BOOLEAN:
|
||||
$value = $param->value ? 1 : 0;
|
||||
case Parameter::TYPE_INT:
|
||||
$aSqlParams[0] .= 'i';
|
||||
break;
|
||||
case Parameter::TYPE_FLOAT:
|
||||
$aSqlParams[0] .= 'd';
|
||||
break;
|
||||
case Parameter::TYPE_DATE:
|
||||
$value = $value->format('Y-m-d');
|
||||
$aSqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_TIME:
|
||||
$value = $value->format('H:i:s');
|
||||
$aSqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_DATE_TIME:
|
||||
$value = $value->format('Y-m-d H:i:s');
|
||||
$aSqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_EMAIL:
|
||||
default:
|
||||
$aSqlParams[0] .= 's';
|
||||
}
|
||||
|
||||
$aSqlParams[] = $value;
|
||||
}
|
||||
|
||||
$tmp = array();
|
||||
foreach($aSqlParams as $key => $value) $tmp[$key] = &$aSqlParams[$key];
|
||||
if($stmt = $this->user->getSQL()->connection->prepare($this->getParam('query'))) {
|
||||
if(call_user_func_array(array($stmt, "bind_param"), $tmp))
|
||||
{
|
||||
if($stmt->execute()) {
|
||||
$res = $stmt->get_result();
|
||||
if($res) {
|
||||
while($row = $res->fetch_assoc()) {
|
||||
array_push($this->result['rows'], $row);
|
||||
}
|
||||
$res->close();
|
||||
$this->success = true;
|
||||
} else {
|
||||
$this->lastError = 'Database Error: execute() failed with ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
} else {
|
||||
$this->lastError = 'Database Error: get_result() failed with ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
} else {
|
||||
$this->lastError = 'Database Error: bind_param() failed with ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
} else {
|
||||
$this->lastError = 'Database Error: prepare failed with() ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
97
core/Api/ExecuteStatement.class.php
Normal file
97
core/Api/ExecuteStatement.class.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
|
||||
class ExecuteStatement extends Request {
|
||||
|
||||
public function __construct($user, $externCall = false) {
|
||||
parent::__construct($user, $externCall, array(
|
||||
'query' => new StringType('query')
|
||||
));
|
||||
|
||||
$this->isPublic = false;
|
||||
$this->variableParamCount = true;
|
||||
}
|
||||
|
||||
public function execute($aValues = array()) {
|
||||
if(!parent::execute($aValues)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->success = false;
|
||||
$this->result['rows'] = array();
|
||||
|
||||
if(count($this->params) == 1) {
|
||||
$this->success = $this->user->getSQL()->execute($this->getParam('query'));
|
||||
if(!$this->success) {
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
}
|
||||
} else {
|
||||
$aSqlParams = array('');
|
||||
foreach($this->params as $param) {
|
||||
if($param->name === 'query') continue;
|
||||
|
||||
$value = $param->value;
|
||||
if(is_null($value)) {
|
||||
$aSqlParams[0] .= 's';
|
||||
} else {
|
||||
switch($param->type) {
|
||||
case Parameter::TYPE_BOOLEAN:
|
||||
$value = $param->value ? 1 : 0;
|
||||
$aSqlParams[0] .= 'i';
|
||||
break;
|
||||
case Parameter::TYPE_INT:
|
||||
$aSqlParams[0] .= 'i';
|
||||
break;
|
||||
case Parameter::TYPE_FLOAT:
|
||||
$aSqlParams[0] .= 'd';
|
||||
break;
|
||||
case Parameter::TYPE_DATE:
|
||||
$value = $value->format('Y-m-d');
|
||||
$aSqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_TIME:
|
||||
$value = $value->format('H:i:s');
|
||||
$aSqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_DATE_TIME:
|
||||
$value = $value->format('Y-m-d H:i:s');
|
||||
$aSqlParams[0] .= 's';
|
||||
break;
|
||||
case Parameter::TYPE_EMAIL:
|
||||
default:
|
||||
$aSqlParams[0] .= 's';
|
||||
}
|
||||
}
|
||||
|
||||
$aSqlParams[] = $value;
|
||||
}
|
||||
|
||||
$tmp = array();
|
||||
foreach($aSqlParams as $key => $value) $tmp[$key] = &$aSqlParams[$key];
|
||||
if($stmt = $this->user->getSQL()->connection->prepare($this->getParam('query'))) {
|
||||
if(call_user_func_array(array($stmt, "bind_param"), $tmp)) {
|
||||
if($stmt->execute()) {
|
||||
$this->result['rows'] = $stmt->affected_rows;
|
||||
$this->success = true;
|
||||
} else {
|
||||
$this->lastError = 'Database Error: execute() failed with ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
} else {
|
||||
$this->lastError = 'Database Error: bind_param() failed with ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
} else {
|
||||
$this->lastError = 'Database Error: prepare() failed with ' . $this->user->getSQL()->getLastError();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
161
core/Api/Parameter/Parameter.class.php
Normal file
161
core/Api/Parameter/Parameter.class.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Api\Parameter;
|
||||
|
||||
class Parameter {
|
||||
const TYPE_INT = 0;
|
||||
const TYPE_FLOAT = 1;
|
||||
const TYPE_BOOLEAN = 2;
|
||||
const TYPE_STRING = 3;
|
||||
const TYPE_DATE = 4;
|
||||
const TYPE_TIME = 5;
|
||||
const TYPE_DATE_TIME = 6;
|
||||
const TYPE_EMAIL = 7;
|
||||
|
||||
// only internal access
|
||||
const TYPE_RAW = 8;
|
||||
const TYPE_ARRAY = 9;
|
||||
|
||||
const names = array('Integer', 'Float', 'Boolean', 'String', 'Date', 'Time', 'DateTime', 'E-Mail', 'Raw', 'Array');
|
||||
|
||||
public $name;
|
||||
public $value;
|
||||
public $optional;
|
||||
public $type;
|
||||
public $typeName;
|
||||
|
||||
public function __construct($name, $type, $optional = FALSE, $defaultValue = NULL) {
|
||||
$this->name = $name;
|
||||
$this->optional = $optional;
|
||||
$this->value = $defaultValue;
|
||||
$this->type = $type;
|
||||
$this->typeName = $this->getTypeName();
|
||||
}
|
||||
|
||||
public function getTypeName() {
|
||||
return ($this->type >= 0 && $this->type < count(Parameter::names)) ? Parameter::names[$this->type] : "INVALID";
|
||||
}
|
||||
|
||||
public function toString() {
|
||||
$typeName = Parameter::names[$this->type];
|
||||
|
||||
$str = "$typeName $this->name";
|
||||
$defaultValue = (is_null($this->value) ? 'NULL' : $this->value);
|
||||
if($this->optional) {
|
||||
$str = "[$str = $defaultValue]";
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
public static function parseType($value) {
|
||||
if(is_array($value))
|
||||
return Parameter::TYPE_ARRAY;
|
||||
else if(is_numeric($value) && intval($value) == $value)
|
||||
return Parameter::TYPE_INT;
|
||||
else if(is_float($value) || (is_numeric($value) && floatval($value) == $value))
|
||||
return Parameter::TYPE_FLOAT;
|
||||
else if(is_bool($value) || $value == "true" || $value == "false")
|
||||
return Parameter::TYPE_BOOLEAN;
|
||||
else if(is_a($value, 'DateTime'))
|
||||
return Parameter::TYPE_DATE_TIME;
|
||||
else if(($d = \DateTime::createFromFormat('Y-m-d', $value)) && $d->format('Y-m-d') === $value)
|
||||
return Parameter::TYPE_DATE;
|
||||
else if(($d = \DateTime::createFromFormat('H:i:s', $value)) && $d->format('H:i:s') === $value)
|
||||
return Parameter::TYPE_TIME;
|
||||
else if(($d = \DateTime::createFromFormat('Y-m-d H:i:s', $value)) && $d->format('Y-m-d H:i:s') === $value)
|
||||
return Parameter::TYPE_DATE_TIME;
|
||||
else if (filter_var($value, FILTER_VALIDATE_EMAIL))
|
||||
return Parameter::TYPE_EMAIL;
|
||||
else
|
||||
return Parameter::TYPE_STRING;
|
||||
}
|
||||
|
||||
public function parseParam($value) {
|
||||
switch($this->type) {
|
||||
case Parameter::TYPE_INT:
|
||||
if(is_numeric($value) && intval($value) == $value) {
|
||||
$this->value = intval($value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Parameter::TYPE_FLOAT:
|
||||
if(is_numeric($value) && (floatval($value) == $value || intval($value) == $value)) {
|
||||
$this->value = floatval($value);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Parameter::TYPE_BOOLEAN:
|
||||
if(strcasecmp($value, 'true') === 0)
|
||||
$this->value = true;
|
||||
else if(strcasecmp($value, 'false') === 0)
|
||||
$this->value = false;
|
||||
else if(is_bool($value))
|
||||
$this->value = (bool)$value;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
|
||||
case Parameter::TYPE_DATE:
|
||||
if(is_a($value, "DateTime")) {
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
$d = DateTime::createFromFormat('Y-m-d', $value);
|
||||
if($d && $d->format('Y-m-d') === $value) {
|
||||
$this->value = $d;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Parameter::TYPE_TIME:
|
||||
if(is_a($value, "DateTime")) {
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
$d = DateTime::createFromFormat('H:i:s', $value);
|
||||
if($d && $d->format('H:i:s') === $value) {
|
||||
$this->value = $d;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Parameter::TYPE_DATE_TIME:
|
||||
if(is_a($value, 'DateTime')) {
|
||||
$this->value = $value;
|
||||
return true;
|
||||
} else {
|
||||
$d = DateTime::createFromFormat('Y-m-d H:i:s', $value);
|
||||
if($d && $d->format('Y-m-d H:i:s') === $value) {
|
||||
$this->value = $d;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
case Parameter::TYPE_EMAIL:
|
||||
if (filter_var($value, FILTER_VALIDATE_EMAIL)) {
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case Parameter::TYPE_ARRAY:
|
||||
if(is_array($value)) {
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
43
core/Api/Parameter/StringType.class.php
Normal file
43
core/Api/Parameter/StringType.class.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Api\Parameter;
|
||||
|
||||
class StringType extends Parameter {
|
||||
|
||||
public $maxLength;
|
||||
public function __construct($name, $maxLength = -1, $optional = FALSE, $defaultValue = NULL) {
|
||||
parent::__construct($name, Parameter::TYPE_STRING, $optional, $defaultValue);
|
||||
$this->maxLength = $maxLength;
|
||||
}
|
||||
|
||||
public function parseParam($value) {
|
||||
if(!is_string($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->maxLength > 0 && strlen($value) > $this->maxLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTypeName() {
|
||||
$maxLength = ($this->maxLength > 0 ? "($this->maxLength)" : "");
|
||||
return parent::getTypeName() . $maxLength;
|
||||
}
|
||||
|
||||
public function toString() {
|
||||
$typeName = $this->getTypeName();
|
||||
$str = "$typeName $this->name";
|
||||
$defaultValue = (is_null($this->value) ? 'NULL' : $this->value);
|
||||
if($this->optional) {
|
||||
$str = "[$str = $defaultValue]";
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
195
core/Api/Request.class.php
Normal file
195
core/Api/Request.class.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
namespace Api;
|
||||
|
||||
class Request {
|
||||
|
||||
protected $user;
|
||||
protected $params;
|
||||
protected $lastError;
|
||||
protected $result;
|
||||
protected $success;
|
||||
protected $isPublic;
|
||||
protected $loginRequired;
|
||||
protected $variableParamCount;
|
||||
protected $isDisabled;
|
||||
protected $apiKeyAllowed;
|
||||
|
||||
private $aDefaultParams;
|
||||
private $allowedMethods;
|
||||
private $externCall;
|
||||
|
||||
public function __construct($user, $externCall = false, $params = array()) {
|
||||
$this->user = $user;
|
||||
$this->aDefaultParams = $params;
|
||||
$this->lastError = '';
|
||||
$this->success = false;
|
||||
$this->result = array();
|
||||
$this->externCall = $externCall;
|
||||
$this->isPublic = true;
|
||||
$this->isDisabled = false;
|
||||
$this->loginRequired = false;
|
||||
$this->variableParamCount = false;
|
||||
$this->apiKeyAllowed = true;
|
||||
$this->allowedMethods = array("GET", "POST");
|
||||
}
|
||||
|
||||
protected function forbidMethod($method) {
|
||||
if (($key = array_search($method, $this->allowedMethods)) !== false) {
|
||||
unset($this->allowedMethods[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getParamsString() {
|
||||
$str = "";
|
||||
$count = count($this->params);
|
||||
$i = 0;
|
||||
foreach($this->params as $param) {
|
||||
$str .= $param->toString();
|
||||
if($i < $count - 1) $str .= ", ";
|
||||
$i++;
|
||||
}
|
||||
|
||||
return "($str)";
|
||||
}
|
||||
|
||||
public function parseParams($aValues) {
|
||||
foreach($this->params as $name => $param) {
|
||||
$value = (isset($aValues[$name]) ? $aValues[$name] : NULL);
|
||||
|
||||
if(!$param->optional && is_null($value)) {
|
||||
$this->lastError = 'Missing parameter: ' . $name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!is_null($value)) {
|
||||
if(!$param->parseParam($value)) {
|
||||
$value = print_r($value, true);
|
||||
$this->lastError = "Invalid Type for parameter: $name '$value' (Required: " . $param->getTypeName() . ")";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function parseVariableParams($aValues) {
|
||||
foreach($aValues as $name => $value) {
|
||||
if(isset($this->params[$name])) continue;
|
||||
$type = Parameter\Parameter::parseType($value);
|
||||
$param = new Parameter\Parameter($name, $type, true);
|
||||
$param->parseParam($value);
|
||||
$this->params[$name] = $param;
|
||||
}
|
||||
}
|
||||
|
||||
public function execute($aValues = array()) {
|
||||
$this->params = $this->aDefaultParams;
|
||||
$this->success = false;
|
||||
$this->result = array();
|
||||
$this->lastError = '';
|
||||
|
||||
if($this->user->isLoggedIn()) {
|
||||
$this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds();
|
||||
}
|
||||
|
||||
if($this->externCall) {
|
||||
$aValues = $_REQUEST;
|
||||
if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_SERVER["CONTENT_TYPE"]) && in_array("application/json", explode(";", $_SERVER["CONTENT_TYPE"]))) {
|
||||
$jsonData = json_decode(file_get_contents('php://input'), true);
|
||||
$aValues = array_merge($aValues, $jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->isDisabled) {
|
||||
$this->lastError = "This function is currently disabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->externCall && !$this->isPublic) {
|
||||
$this->lastError = 'This function is private.';
|
||||
header('HTTP 1.1 403 Forbidden');
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!in_array($_SERVER['REQUEST_METHOD'], $this->allowedMethods)) {
|
||||
$this->lastError = 'This method is not allowed';
|
||||
header('HTTP 1.1 405 Method Not Allowed');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if($this->loginRequired) {
|
||||
$authorized = false;
|
||||
if(isset($aValues['api_key']) && $this->apiKeyAllowed) {
|
||||
$apiKey = $aValues['api_key'];
|
||||
$authorized = $this->user->authorize($apiKey);
|
||||
}
|
||||
|
||||
if(!$this->user->isLoggedIn() && !$authorized) {
|
||||
$this->lastError = 'You are not logged in.';
|
||||
header('HTTP 1.1 401 Unauthorized');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!$this->parseParams($aValues))
|
||||
return false;
|
||||
|
||||
if($this->variableParamCount)
|
||||
$this->parseVariableParams($aValues);
|
||||
|
||||
if(!$this->user->getSQL()->isConnected()) {
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->user->getSQL()->setLastError('');
|
||||
$this->success = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isValidString($str, $regex) {
|
||||
return preg_replace($regex, "", $str) === $str;
|
||||
}
|
||||
|
||||
protected function createError($err) {
|
||||
$this->success = false;
|
||||
$this->lastError = $err;
|
||||
return false;
|
||||
}
|
||||
//
|
||||
// public static function callDirectly($class, $db) {
|
||||
// header('Content-Type: application/json');
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/sql.php';
|
||||
//
|
||||
// $sql = connectSQL(getSqlData($db));
|
||||
// $user = new CUser($sql);
|
||||
// $request = new $class($user, true);
|
||||
// $request->execute();
|
||||
// $sql->close();
|
||||
// $user->sendCookies();
|
||||
// return $request->getJsonResult();
|
||||
// }
|
||||
|
||||
protected function getParam($name) { return isset($this->params[$name]) ? $this->params[$name]->value : NULL; }
|
||||
public function isPublic() { return $this->isPublic; }
|
||||
public function getDescription() { return ''; }
|
||||
public function getSection() { return 'Default'; }
|
||||
public function getLastError() { return $this->lastError; }
|
||||
public function getResult() { return $this->result; }
|
||||
public function success() { return $this->success; }
|
||||
public function loginRequired() { return $this->loginRequired; }
|
||||
public function isExternCall() { return $this->externCall; }
|
||||
|
||||
public function getJsonResult() {
|
||||
$this->result['success'] = $this->success;
|
||||
$this->result['msg'] = $this->lastError;
|
||||
return json_encode($this->result);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
?>
|
||||
4
core/Configuration/.gitignore
vendored
Normal file
4
core/Configuration/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Mail\.class\.php
|
||||
JWT\.class\.php
|
||||
Database\.class\.php
|
||||
Google\.class\.php
|
||||
1
core/Configuration/.htaccess
Normal file
1
core/Configuration/.htaccess
Normal file
@@ -0,0 +1 @@
|
||||
DENY FROM ALL
|
||||
106
core/Configuration/Configuration.class.php
Normal file
106
core/Configuration/Configuration.class.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Configuration;
|
||||
|
||||
class Configuration {
|
||||
|
||||
private $database;
|
||||
private $mail;
|
||||
private $jwt;
|
||||
private $google;
|
||||
|
||||
function __construct() {
|
||||
}
|
||||
|
||||
public function load() {
|
||||
try {
|
||||
|
||||
$classes = array(
|
||||
\Configuration\Database::class => &$this->database,
|
||||
\Configuration\Mail::class => &$this->mail,
|
||||
\Configuration\JWT::class => &$this->jwt,
|
||||
\Configuration\Google::class => &$this->google,
|
||||
);
|
||||
|
||||
$success = true;
|
||||
foreach($classes as $class => &$ref) {
|
||||
$path = getClassPath($class);
|
||||
if(!file_exists($path)) {
|
||||
$success = false;
|
||||
} else {
|
||||
include_once $path;
|
||||
if(class_exists($class)) {
|
||||
$ref = new $class();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
} catch(\Error $e) {
|
||||
die($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function getDatabase() { return $this->database; }
|
||||
public function getJWT() { return $this->jwt; }
|
||||
public function getMail() { return $this->mail; }
|
||||
|
||||
public function isFilePresent($className) {
|
||||
$path = getClassPath("\\Configuration\\$className");
|
||||
return file_exists($path);
|
||||
}
|
||||
|
||||
public function create($className, $data) {
|
||||
$path = getClassPath("\\Configuration\\$className");
|
||||
|
||||
if($data) {
|
||||
|
||||
// TODO: Generalize this...
|
||||
$superClass = get_class($data);
|
||||
$host = addslashes($data->getHost());
|
||||
$port = intval($data->getPort());
|
||||
$login = addslashes($data->getLogin());
|
||||
$password = addslashes($data->getPassword());
|
||||
|
||||
$properties = "";
|
||||
foreach($data->getProperties() as $key => $val) {
|
||||
$key = addslashes($key);
|
||||
$val = is_string($val) ? "'" . addslashes($val) . "'" : $val;
|
||||
$properties .= "\n\$this->setProperty('$key', $val);";
|
||||
}
|
||||
|
||||
$code = intendCode(
|
||||
"<?php
|
||||
|
||||
namespace Configuration;
|
||||
|
||||
class $className extends \\$superClass {
|
||||
|
||||
public function __construct() {
|
||||
parent::__construct('$host', $port, '$login', '$password');$properties
|
||||
}
|
||||
}
|
||||
|
||||
?>", false
|
||||
);
|
||||
} else {
|
||||
$code = intendCode(
|
||||
"<?php
|
||||
|
||||
?>", false);
|
||||
}
|
||||
|
||||
return file_put_contents($path, $code);
|
||||
}
|
||||
|
||||
public function delete($className) {
|
||||
$path = getClassPath("\\Configuration\\$className");
|
||||
if(file_exists($path)) {
|
||||
return unlink($path);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
59
core/Configuration/database.sql
Normal file
59
core/Configuration/database.sql
Normal file
@@ -0,0 +1,59 @@
|
||||
--
|
||||
-- API
|
||||
--
|
||||
CREATE TABLE IF NOT EXISTS User (
|
||||
`uid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`email` VARCHAR(256) UNIQUE DEFAULT NULL,
|
||||
`name` VARCHAR(32) UNIQUE NOT NULL,
|
||||
`salt` varchar(16) NOT NULL,
|
||||
`password` varchar(64) NOT NULL,
|
||||
`uidLanguage` int(11) DEFAULT 1
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS UserInvitation (
|
||||
`email` VARCHAR(256) NOT NULL,
|
||||
`token` VARCHAR(36) UNIQUE NOT NULL,
|
||||
`valid_until` DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `Group` (
|
||||
`gid` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`name` VARCHAR(32) NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO `Group` (gid, name) VALUES (1, "Default"), (2, "Administrator")
|
||||
ON DUPLICATE KEY UPDATE name=name;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS UserGroup (
|
||||
`uid` INTEGER NOT NULL,
|
||||
`gid` INTEGER NOT NULL,
|
||||
UNIQUE(`uid`, `gid`)
|
||||
);
|
||||
|
||||
CREATE TABLE Session IF NOT EXISTS (
|
||||
`uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`expires` timestamp NOT NULL,
|
||||
`uidUser` int(11) NOT NULL,
|
||||
`ipAddress` varchar(45) NOT NULL,
|
||||
`os` varchar(64) NOT NULL,
|
||||
`browser` varchar(64) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ApiKey (
|
||||
`uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`uidUser` int(11) NOT NULL,
|
||||
`api_key` VARCHAR(64) NOT NULL,
|
||||
`valid_until` DATETIME NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS Language (
|
||||
`uid` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
`code` VARCHAR(5) UNIQUE NOT NULL,
|
||||
`name` VARCHAR(32) UNIQUE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS ExternalSiteCache (
|
||||
`url` VARCHAR(256) PRIMARY KEY,
|
||||
`data` TEXT NOT NULL,
|
||||
`expires` TIMESTAMP DEFAULT NULL
|
||||
);
|
||||
721
core/Documents/Install.class.php
Normal file
721
core/Documents/Install.class.php
Normal file
@@ -0,0 +1,721 @@
|
||||
<?php
|
||||
|
||||
namespace Documents {
|
||||
class Install extends \Elements\Document {
|
||||
public function __construct($user) {
|
||||
parent::__construct($user, Install\Head::class, Install\Body::class);
|
||||
$this->databseRequired = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Documents\Install {
|
||||
|
||||
class Head extends \Elements\Head {
|
||||
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
|
||||
protected function initSources() {
|
||||
$this->loadJQuery();
|
||||
$this->loadBootstrap();
|
||||
$this->loadFontawesome();
|
||||
$this->addJS(\Elements\Script::CORE);
|
||||
$this->addCSS(\Elements\Link::CORE);
|
||||
$this->addJS(\Elements\Script::INSTALL);
|
||||
}
|
||||
|
||||
protected function initMetas() {
|
||||
return array(
|
||||
array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'),
|
||||
array('name' => 'format-detection', 'content' => 'telephone=yes'),
|
||||
array('charset' => 'utf-8'),
|
||||
array("http-equiv" => 'expires', 'content' => '0'),
|
||||
array("name" => 'robots', 'content' => 'noarchive'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function initRawFields() {
|
||||
return array();
|
||||
}
|
||||
|
||||
protected function initTitle() {
|
||||
return "WebBase - Installation";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Body extends \Elements\Body {
|
||||
|
||||
// Status enum
|
||||
const NOT_STARTED = 0;
|
||||
const PENDING = 1;
|
||||
const SUCCESFULL = 2;
|
||||
const ERROR = 3;
|
||||
|
||||
// Step enum
|
||||
const CHECKING_REQUIRMENTS = 1;
|
||||
const DATABASE_CONFIGURATION = 2;
|
||||
const CREATE_USER = 3;
|
||||
const ADD_MAIL_SERVICE = 4;
|
||||
const ADD_GOOGLE_SERVICE = 5;
|
||||
|
||||
//
|
||||
private $configDirectory;
|
||||
private $databaseScript;
|
||||
|
||||
function __construct($document) {
|
||||
parent::__construct($document);
|
||||
|
||||
// TODO: make better
|
||||
$this->configDirectory = getWebRoot() . '/core/Configuration';
|
||||
$this->databaseScript = getWebRoot() . '/core/Configuration/database.sql';
|
||||
}
|
||||
|
||||
private function getParameter($name) {
|
||||
if(isset($_REQUEST[$name]) && is_string($_REQUEST[$name])) {
|
||||
return trim($_REQUEST[$name]);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private function getCurrentStep() {
|
||||
|
||||
if(!$this->checkRequirements()) {
|
||||
return self::CHECKING_REQUIRMENTS;
|
||||
}
|
||||
|
||||
$user = $this->getDocument()->getUser();
|
||||
$config = $user->getConfiguration();
|
||||
|
||||
// Check if database configuration exists
|
||||
if(!$config->getDatabase()) {
|
||||
return self::DATABASE_CONFIGURATION;
|
||||
}
|
||||
|
||||
$query = "SELECT * FROM User";
|
||||
$sql = $user->getSQL();
|
||||
if(!is_null($sql) && $sql->isConnected()) {
|
||||
$this->getDocument()->getUser()->setSql($sql);
|
||||
$res = $sql->query($query);
|
||||
if($res) {
|
||||
if($res->num_rows === 0) {
|
||||
$step = self::CREATE_USER;
|
||||
} else {
|
||||
$step = self::ADD_MAIL_SERVICE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$step = self::DATABASE_CONFIGURATION;
|
||||
}
|
||||
|
||||
if($step == self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) {
|
||||
$step = self::ADD_GOOGLE_SERVICE;
|
||||
}
|
||||
|
||||
return $step;
|
||||
}
|
||||
|
||||
private function checkRequirements() {
|
||||
|
||||
$msg = "";
|
||||
$success = true;
|
||||
$failedRequirements = array();
|
||||
|
||||
if(!is_writeable($this->configDirectory)) {
|
||||
$failedRequirements[] = "<b>$this->configDirectory</b> is not writeable. Try running <b>chmod 600</b>";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if(!is_readable($this->databaseScript)) {
|
||||
$failedRequirements[] = "<b>$this->databaseScript</b> is not readable.";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if(version_compare(PHP_VERSION, '7.1', '<')) {
|
||||
$failedRequirements[] = "PHP Version <b>>= 7.1</b> is required. Got: <b>" . PHP_VERSION . "</b>";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if(!function_exists('mysqli_connect')) {
|
||||
$link = $this->createExternalLink("https://secure.php.net/manual/en/mysqli.setup.php");
|
||||
$failedRequirements[] = "mysqli is not enabled yet. See: $link";
|
||||
$success = false;
|
||||
}
|
||||
|
||||
if(!$success) {
|
||||
$msg = "The following requirements failed the check:<br>" .
|
||||
$this->createUnorderedList($failedRequirements);
|
||||
}
|
||||
|
||||
return array("success" => $success, "msg" => $msg);
|
||||
}
|
||||
|
||||
private function databaseConfiguration() {
|
||||
|
||||
$host = $this->getParameter("host");
|
||||
$port = $this->getParameter("port");
|
||||
$username = $this->getParameter("username");
|
||||
$password = $this->getParameter("password");
|
||||
$database = $this->getParameter("database");
|
||||
$success = true;
|
||||
|
||||
$missingInputs = array();
|
||||
if(is_null($host) || empty($host)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Host";
|
||||
}
|
||||
|
||||
if(is_null($port) || empty($port)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Port";
|
||||
}
|
||||
|
||||
if(is_null($username) || empty($username)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Username";
|
||||
}
|
||||
|
||||
if(is_null($password)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Password";
|
||||
}
|
||||
|
||||
if(is_null($database) || empty($database)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Database";
|
||||
}
|
||||
|
||||
if(!$success) {
|
||||
$msg = "Please fill out the following inputs:<br>" .
|
||||
$this->createUnorderedList($missingInputs);
|
||||
} else if(!is_numeric($port) || ($port = intval($port)) < 1 || $port > 65535) {
|
||||
$msg = "Port must be in range of 1-65535.";
|
||||
$success = false;
|
||||
} else {
|
||||
$connectionData = new \Objects\ConnectionData($host, $port, $username, $password);
|
||||
$connectionData->setProperty('database', $database);
|
||||
$connectionData->setProperty('encoding', 'utf8');
|
||||
$sql = new \Driver\SQL($connectionData);
|
||||
$success = $sql->connect();
|
||||
|
||||
if(!$success) {
|
||||
$msg = "Error connecting to database:<br>" . $sql->getLastError();
|
||||
} else {
|
||||
try {
|
||||
$msg = "Error loading database script $this->databaseScript";
|
||||
$commands = file_get_contents($this->databaseScript);
|
||||
$success = $sql->executeMulti($commands);
|
||||
if(!$success) {
|
||||
$msg = $sql->getLastError();
|
||||
} else if(!$this->getDocument()->getUser()->getConfiguration()->create("Database", $connectionData)) {
|
||||
$success = false;
|
||||
$msg = "Unable to write file";
|
||||
} else {
|
||||
$msg = "";
|
||||
}
|
||||
} catch(Exception $e) {
|
||||
$success = false;
|
||||
$msg .= ": " . $e->getMessage();
|
||||
}
|
||||
|
||||
if($sql) {
|
||||
$sql->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array("success" => $success, "msg" => $msg);
|
||||
}
|
||||
|
||||
private function createUser() {
|
||||
|
||||
$user = $this->getDocument()->getUser();
|
||||
if($this->getParameter("prev") === "true") {
|
||||
$success = $user->getConfiguration()->delete("Database");
|
||||
$msg = $success ? "" : error_get_last();
|
||||
return array("success" => $success, "msg" => $msg);
|
||||
}
|
||||
|
||||
$username = $this->getParameter("username");
|
||||
$password = $this->getParameter("password");
|
||||
$confirmPassword = $this->getParameter("confirmPassword");
|
||||
|
||||
$msg = "";
|
||||
$success = true;
|
||||
$missingInputs = array();
|
||||
|
||||
if(is_null($username) || empty($username)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Username";
|
||||
}
|
||||
|
||||
if(is_null($password) || empty($password)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Password";
|
||||
}
|
||||
|
||||
if(is_null($confirmPassword) || empty($confirmPassword)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Confirm Password";
|
||||
}
|
||||
|
||||
if(!$success) {
|
||||
$msg = "Please fill out the following inputs:<br>" .
|
||||
$this->createUnorderedList($missingInputs);
|
||||
} else if(strlen($username) < 5 || strlen($username) > 32) {
|
||||
$msg = "The username should be between 5 and 32 characters long";
|
||||
$success = false;
|
||||
} else if(strcmp($password, $confirmPassword) !== 0) {
|
||||
$msg = "The given passwords do not match";
|
||||
$success = false;
|
||||
} else if(strlen($password) < 6) {
|
||||
$msg = "The password should be at least 6 characters long";
|
||||
$success = false;
|
||||
} else {
|
||||
$salt = generateRandomString(16);
|
||||
$hash = hash('sha256', $password . $salt);
|
||||
$query = "INSERT INTO User (name, salt, password) VALUES (?,?,?)";
|
||||
$req = new \Api\ExecuteStatement($user);
|
||||
$success = $req->execute(array("query" => $query, $username, $salt, $hash));
|
||||
$nsg = $req->getLastError();
|
||||
}
|
||||
|
||||
return array("msg" => $msg, "success" => $success);
|
||||
}
|
||||
|
||||
private function addMailService() {
|
||||
|
||||
$user = $this->getDocument()->getUser();
|
||||
if($this->getParameter("prev") === "true") {
|
||||
$req = new \Api\ExecuteStatement($user);
|
||||
$success = $req->execute(array("query" => "TRUNCATE User"));
|
||||
$msg = $req->getLastError();
|
||||
return array("success" => $success, "msg" => $msg);
|
||||
}
|
||||
|
||||
$success = true;
|
||||
$msg = "";
|
||||
if($this->getParameter("skip") === "true") {
|
||||
if(!$user->getConfiguration()->create("Mail", null)) {
|
||||
$success = false;
|
||||
$msg = "Unable to create file";
|
||||
}
|
||||
} else {
|
||||
|
||||
$address = $this->getParameter("address");
|
||||
$port = $this->getParameter("port");
|
||||
$username = $this->getParameter("username");
|
||||
$password = $this->getParameter("password");
|
||||
$success = true;
|
||||
|
||||
$missingInputs = array();
|
||||
if(is_null($address) || empty($address)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "SMTP Address";
|
||||
}
|
||||
|
||||
if(is_null($port) || empty($port)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Port";
|
||||
}
|
||||
|
||||
if(is_null($username) || empty($username)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Username";
|
||||
}
|
||||
|
||||
if(is_null($password)) {
|
||||
$success = false;
|
||||
$missingInputs[] = "Password";
|
||||
}
|
||||
|
||||
if(!$success) {
|
||||
$msg = "Please fill out the following inputs:<br>" .
|
||||
$this->createUnorderedList($missingInputs);
|
||||
} else if(!is_numeric($port) || ($port = intval($port)) < 1 || $port > 65535) {
|
||||
$msg = "Port must be in range of 1-65535.";
|
||||
$success = false;
|
||||
} else {
|
||||
$success = false;
|
||||
|
||||
$mail = new \External\PHPMailer\PHPMailer(true);
|
||||
$mail->IsSMTP();
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = $username;
|
||||
$mail->Password = $password;
|
||||
$mail->Host = $address;
|
||||
$mail->Port = $port;
|
||||
$mail->SMTPSecure = 'tls';
|
||||
$mail->Timeout = 10;
|
||||
|
||||
try {
|
||||
$success = $mail->SmtpConnect();
|
||||
if(!$success) {
|
||||
$error = empty($mail->ErrorInfo) ? "Unknown Error" : $mail->ErrorInfo;
|
||||
$msg = "Could not connect to SMTP Server: $error";
|
||||
} else {
|
||||
$success = true;
|
||||
$msg = "";
|
||||
$mail->smtpClose();
|
||||
}
|
||||
} catch(\External\PHPMailer\Exception $error) {
|
||||
$msg = "Could not connect to SMTP Server: " . $error->errorMessage();
|
||||
}
|
||||
|
||||
if($success) {
|
||||
$connectionData = new \Objects\ConnectionData($address, $port, $username, $password);
|
||||
if(!$user->getConfiguration()->create("Mail", $connectionData)) {
|
||||
$success = false;
|
||||
$msg = "Unable to create file";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array("success" => $success, "msg" => $msg);
|
||||
}
|
||||
|
||||
private function addGoogleService() {
|
||||
// return array("success" => $success, "msg" => $msg);
|
||||
}
|
||||
|
||||
private function performStep() {
|
||||
|
||||
switch($this->currentStep) {
|
||||
|
||||
case self::CHECKING_REQUIRMENTS:
|
||||
return $this->checkRequirements();
|
||||
|
||||
case self::DATABASE_CONFIGURATION:
|
||||
return $this->databaseConfiguration();
|
||||
|
||||
case self::CREATE_USER:
|
||||
return $this->createUser();
|
||||
|
||||
case self::ADD_MAIL_SERVICE:
|
||||
return $this->addMailService();
|
||||
|
||||
case self::ADD_GOOGLE_SERVICE:
|
||||
return $this->addGoogleService();
|
||||
|
||||
default:
|
||||
return array(
|
||||
"success" => false,
|
||||
"msg" => "Invalid step number"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function createProgressSidebar() {
|
||||
$items = array();
|
||||
foreach($this->steps as $num => $step) {
|
||||
|
||||
$title = $step["title"];
|
||||
$status = $step["status"];
|
||||
$currentStep = ($num == $this->currentStep) ? " id=\"currentStep\"" : "";
|
||||
|
||||
switch($status) {
|
||||
case self::PENDING:
|
||||
$statusIcon = '<i class="fas fa-spin fa-spinner"></i>';
|
||||
$statusText = "Loading…";
|
||||
$statusColor = "muted";
|
||||
break;
|
||||
|
||||
case self::SUCCESFULL:
|
||||
$statusIcon = '<i class="fas fa-check-circle"></i>';
|
||||
$statusText = "Successfull";
|
||||
$statusColor = "success";
|
||||
break;
|
||||
|
||||
case self::ERROR:
|
||||
$statusIcon = '<i class="fas fa-times-circle"></i>';
|
||||
$statusText = "Failed";
|
||||
$statusColor = "danger";
|
||||
break;
|
||||
|
||||
case self::NOT_STARTED:
|
||||
default:
|
||||
$statusIcon = '<i class="far fa-circle"></i>';
|
||||
$statusText = "Pending";
|
||||
$statusColor = "muted";
|
||||
break;
|
||||
}
|
||||
|
||||
$items[] = "
|
||||
<li class=\"list-group-item d-flex justify-content-between lh-condensed\"$currentStep>
|
||||
<div>
|
||||
<h6 class=\"my-0\">$title</h6>
|
||||
<small class=\"text-$statusColor\">$statusText</small>
|
||||
</div>
|
||||
<span class=\"text-$statusColor\">$statusIcon</span>
|
||||
</li>";
|
||||
}
|
||||
|
||||
return implode("", $items);
|
||||
}
|
||||
|
||||
private function createFormItem($formItem, $inline=false) {
|
||||
|
||||
$title = $formItem["title"];
|
||||
$name = $formItem["name"];
|
||||
$type = $formItem["type"];
|
||||
|
||||
$attributes = array(
|
||||
"name" => $name,
|
||||
"id" => $name,
|
||||
"class" => "form-control",
|
||||
"type" => $type,
|
||||
);
|
||||
|
||||
if(isset($formItem["required"]) && $formItem["required"]) {
|
||||
$attributes["required"] = "";
|
||||
}
|
||||
|
||||
if(isset($formItem["value"]) && $formItem["value"]) {
|
||||
$attributes["value"] = $formItem["value"];
|
||||
}
|
||||
|
||||
if($type === "number") {
|
||||
if(isset($formItem["min"]) && is_numeric($formItem["min"]))
|
||||
$attributes["min"] = $formItem["min"];
|
||||
if(isset($formItem["max"]) && is_numeric($formItem["max"]))
|
||||
$attributes["max"] = $formItem["max"];
|
||||
if(isset($formItem["step"]) && is_numeric($formItem["step"]))
|
||||
$attributes["step"] = $formItem["step"];
|
||||
}
|
||||
|
||||
$attributes = str_replace("+", " ", str_replace("&", "\" ", str_replace("=", "=\"", http_build_query($attributes)))) . "\"";
|
||||
|
||||
if(!$inline) {
|
||||
return
|
||||
"<div class=\"d-block my-3\">
|
||||
<label for=\"$name\">$title</label>
|
||||
<input $attributes>
|
||||
</div>";
|
||||
} else {
|
||||
return
|
||||
"<div class=\"col-md-6 mb-3\">
|
||||
<label for=\"$name\">$title</label>
|
||||
<input $attributes>
|
||||
</div>";
|
||||
}
|
||||
}
|
||||
|
||||
private function createProgessMainview() {
|
||||
|
||||
$views = array(
|
||||
self::CHECKING_REQUIRMENTS => array(
|
||||
"title" => "Application Requirements",
|
||||
"progressText" => "Checking requirements, please wait a moment…"
|
||||
),
|
||||
self::DATABASE_CONFIGURATION => array(
|
||||
"title" => "Database configuration",
|
||||
"form" => array(
|
||||
array("title" => "Username", "name" => "username", "type" => "text", "required" => true),
|
||||
array("title" => "Password", "name" => "password", "type" => "password"),
|
||||
array("title" => "Database", "name" => "database", "type" => "text", "required" => true),
|
||||
array("type" => "row", "items" => array(
|
||||
array(
|
||||
"title" => "Address", "name" => "host", "type" => "text", "required" => true,
|
||||
"value" => "localhost", "row" => true
|
||||
),
|
||||
array(
|
||||
"title" => "Port", "name" => "port", "type" => "number", "required" => true,
|
||||
"value" => "3306", "min" => "1", "max" => "65535", "row" => true
|
||||
)
|
||||
)),
|
||||
)
|
||||
),
|
||||
self::CREATE_USER => array(
|
||||
"title" => "Create a User",
|
||||
"form" => array(
|
||||
array("title" => "Username", "name" => "username", "type" => "text", "required" => true),
|
||||
array("title" => "Password", "name" => "password", "type" => "password", "required" => true),
|
||||
array("title" => "Confirm Password", "name" => "confirmPassword", "type" => "password", "required" => true),
|
||||
)
|
||||
),
|
||||
self::ADD_MAIL_SERVICE => array(
|
||||
"title" => "Optional: Add Mail Service",
|
||||
"form" => array(
|
||||
array("title" => "Username", "name" => "username", "type" => "text", "required" => true),
|
||||
array("title" => "Password", "name" => "password", "type" => "password"),
|
||||
array("type" => "row", "items" => array(
|
||||
array(
|
||||
"title" => "SMTP Address", "name" => "address", "type" => "text", "required" => true,
|
||||
"value" => "localhost", "row" => true
|
||||
),
|
||||
array(
|
||||
"title" => "Port", "name" => "port", "type" => "number", "required" => true,
|
||||
"value" => "587", "min" => "1", "max" => "65535", "row" => true
|
||||
)
|
||||
)),
|
||||
),
|
||||
"skip" => true
|
||||
),
|
||||
self::ADD_GOOGLE_SERVICE => array(
|
||||
"title" => "Optional: Add Google Services",
|
||||
)
|
||||
);
|
||||
|
||||
if(!isset($views[$this->currentStep])) {
|
||||
return "";
|
||||
}
|
||||
|
||||
$prevDisabled = ($this->currentStep <= self::DATABASE_CONFIGURATION);
|
||||
$currentView = $views[$this->currentStep];
|
||||
$spinnerIcon = $this->createIcon("spinner");
|
||||
$title = $currentView["title"];
|
||||
|
||||
$html = "<h4 class=\"mb-3\">$title</h4><hr class=\"mb-4\">";
|
||||
|
||||
if(isset($currentView["progressText"])) {
|
||||
$progressText = $currentView["progressText"];
|
||||
$html .= "<div id=\"progressText\" class=\"my-3\">$progressText$spinnerIcon</i></div>";
|
||||
}
|
||||
|
||||
if(isset($currentView["form"])) {
|
||||
$html .= "<form id=\"installForm\">";
|
||||
|
||||
foreach($currentView["form"] as $formItem) {
|
||||
|
||||
if($formItem["type"] === "row") {
|
||||
$html .= "<div class=\"row\">";
|
||||
foreach($formItem["items"] as $item) {
|
||||
$html .= $this->createFormItem($item, true);
|
||||
}
|
||||
$html .= "</div>";
|
||||
} else {
|
||||
$html .= $this->createFormItem($formItem);
|
||||
}
|
||||
}
|
||||
|
||||
$html .= "
|
||||
</form>";
|
||||
}
|
||||
|
||||
$buttons = array(
|
||||
array("title" => "Go Back", "type" => "info", "id" => "btnPrev", "float" => "left", "disabled" => $prevDisabled),
|
||||
array("title" => "Submit", "type" => "success", "id" => "btnSubmit", "float" => "right")
|
||||
);
|
||||
|
||||
if(isset($currentView["skip"])) {
|
||||
$buttons[] = array("title" => "Skip", "type" => "secondary", "id" => "btnSkip", "float" => "right");
|
||||
}
|
||||
|
||||
$buttonsLeft = "";
|
||||
$buttonsRight = "";
|
||||
|
||||
foreach($buttons as $button) {
|
||||
$title = $button["title"];
|
||||
$type = $button["type"];
|
||||
$id = $button["id"];
|
||||
$float = $button["float"];
|
||||
$disabled = (isset($button["disabled"]) && $button["disabled"]) ? " disabled" : "";
|
||||
$button = "<button type=\"button\" id=\"$id\" class=\"btn btn-$type margin-xs\"$disabled>$title</button>";
|
||||
|
||||
if($float === "left") {
|
||||
$buttonsLeft .= $button;
|
||||
} else {
|
||||
$buttonsRight .= $button;
|
||||
}
|
||||
}
|
||||
|
||||
$html .=
|
||||
"<div class=\"row\">
|
||||
<div class=\"col-6 float-left text-left\">$buttonsLeft</div>
|
||||
<div class=\"col-6 float-right text-right\">$buttonsRight</div>
|
||||
</div>";
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
function getCode() {
|
||||
$html = parent::getCode();
|
||||
|
||||
$this->steps = array(
|
||||
self::CHECKING_REQUIRMENTS => array(
|
||||
"title" => "Checking requirements",
|
||||
"status" => self::NOT_STARTED
|
||||
),
|
||||
self::DATABASE_CONFIGURATION => array(
|
||||
"title" => "Database configuration",
|
||||
"status" => self::NOT_STARTED
|
||||
),
|
||||
self::CREATE_USER => array(
|
||||
"title" => "Create User",
|
||||
"status" => self::NOT_STARTED
|
||||
),
|
||||
self::ADD_MAIL_SERVICE => array(
|
||||
"title" => "Add Mail Service",
|
||||
"status" => self::NOT_STARTED
|
||||
),
|
||||
self::ADD_GOOGLE_SERVICE => array(
|
||||
"title" => "Add Google Services",
|
||||
"status" => self::NOT_STARTED
|
||||
),
|
||||
);
|
||||
|
||||
$this->currentStep = $this->getCurrentStep();
|
||||
|
||||
// set status
|
||||
for($step = self::CHECKING_REQUIRMENTS; $step < $this->currentStep; $step++) {
|
||||
$this->steps[$step]["status"] = self::SUCCESFULL;
|
||||
}
|
||||
|
||||
// POST
|
||||
if($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$response = $this->performStep();
|
||||
die(json_encode($response));
|
||||
}
|
||||
|
||||
if($this->currentStep == self::CHECKING_REQUIRMENTS) {
|
||||
$this->getDocument()->getHead()->addJSCode("
|
||||
$(document).ready(function() {
|
||||
retry();
|
||||
});
|
||||
");
|
||||
}
|
||||
|
||||
$progressSidebar = $this->createProgressSidebar();
|
||||
$progressMainview = $this->createProgessMainview();
|
||||
|
||||
$html .= "
|
||||
<body class=\"bg-light\">
|
||||
<div class=\"container\">
|
||||
<div class=\"py-5 text-center\">
|
||||
<h2>WebBase - Installation</h2>
|
||||
<p class=\"lead\">
|
||||
Process the following steps and fill out the required forms to install your WebBase-Installation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class=\"row\">
|
||||
<div class=\"col-md-4 order-md-2 mb-4\">
|
||||
<h4 class=\"d-flex justify-content-between align-items-center mb-3\">
|
||||
<span class=\"text-muted\">Progress</span>
|
||||
</h4>
|
||||
|
||||
<ul class=\"list-group mb-3\">
|
||||
$progressSidebar
|
||||
</ul>
|
||||
</div>
|
||||
<div class=\"col-md-8 order-md-1\">
|
||||
$progressMainview
|
||||
<div class=\"alert margin-top-m\" id=\"status\" style=\"display:none\"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>";
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
124
core/Driver/SQL.class.php
Normal file
124
core/Driver/SQL.class.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Driver;
|
||||
|
||||
class SQL {
|
||||
|
||||
public $connection;
|
||||
public $lastError;
|
||||
private $connectionData;
|
||||
|
||||
public function __construct($connectionData) {
|
||||
$this->connection = NULL;
|
||||
$this->lastError = 'Not connected';
|
||||
$this->connectionData = $connectionData;
|
||||
}
|
||||
|
||||
public function connect() {
|
||||
if(!is_null($this->connection))
|
||||
return true;
|
||||
|
||||
@$this->connection = mysqli_connect(
|
||||
$this->connectionData->getHost(),
|
||||
$this->connectionData->getLogin(),
|
||||
$this->connectionData->getPassword(),
|
||||
$this->connectionData->getProperty('database'),
|
||||
$this->connectionData->getPort()
|
||||
);
|
||||
|
||||
if (mysqli_connect_errno($this->connection)) {
|
||||
$this->lastError = "Failed to connect to MySQL: " . mysqli_connect_error();
|
||||
$this->connection = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
mysqli_set_charset($this->connection, $this->connectionData->getProperty('encoding'));
|
||||
return true;
|
||||
}
|
||||
|
||||
public function disconnect() {
|
||||
if(is_null($this->connection))
|
||||
return;
|
||||
|
||||
mysqli_close($this->connection);
|
||||
$this->connection = NULL;
|
||||
}
|
||||
|
||||
public function isConnected() {
|
||||
return !is_null($this->connection);
|
||||
}
|
||||
|
||||
public function getLastError() {
|
||||
return empty(trim($this->lastError)) ? mysqli_error($this->connection) . " " . $this->getLastErrorNumber() : trim($this->lastError);
|
||||
}
|
||||
|
||||
public function setLastError($str) {
|
||||
$this->lastError = $str;
|
||||
}
|
||||
|
||||
public function getLastErrorNumber() {
|
||||
return mysqli_errno($this->connection);
|
||||
}
|
||||
|
||||
public function getLastInsertId() {
|
||||
return $this->connection->insert_id;
|
||||
}
|
||||
|
||||
public function close() {
|
||||
if(!is_null($this->connection)) {
|
||||
$this->connection->close();
|
||||
}
|
||||
}
|
||||
|
||||
public function getAffectedRows() {
|
||||
return $this->connection->affected_rows;
|
||||
}
|
||||
|
||||
public function execute($query) {
|
||||
if(!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!mysqli_query($this->connection, $query)) {
|
||||
$this->lastError = mysqli_error($this->connection);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function executeMulti($queries) {
|
||||
if(!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!$this->connection->multi_query($queries)) {
|
||||
$this->lastError = mysqli_error($this->connection);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function query($query) {
|
||||
if(!$this->isConnected()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$res = mysqli_query($this->connection, $query);
|
||||
if(!$res) {
|
||||
$this->lastError = mysqli_error($this->connection);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function createConnection($connectionData) {
|
||||
$sql = new SQL($connectionData);
|
||||
$sql->connect();
|
||||
return $sql;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
10
core/Elements/Body.class.php
Normal file
10
core/Elements/Body.class.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class Body extends \View {
|
||||
public function __construct($document) {
|
||||
parent::__construct($document);
|
||||
}
|
||||
};
|
||||
?>
|
||||
80
core/Elements/Document.class.php
Normal file
80
core/Elements/Document.class.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class Document {
|
||||
|
||||
protected $head;
|
||||
protected $body;
|
||||
protected $user;
|
||||
protected $databseRequired;
|
||||
|
||||
public function __construct($user, $headClass, $bodyClass) {
|
||||
$this->head = new $headClass($this);
|
||||
$this->body = new $bodyClass($this);
|
||||
$this->user = $user;
|
||||
$this->databseRequired = true;
|
||||
}
|
||||
|
||||
public function getHead() { return $this->head; }
|
||||
public function getBody() { return $this->body; }
|
||||
public function getSQL() { return $this->user->getSQL(); }
|
||||
public function getUser() { return $this->user; }
|
||||
|
||||
protected function sendHeaders() {
|
||||
header("X-Frame-Options: DENY");
|
||||
}
|
||||
|
||||
public static function createSearchableDocument($documentClass, $user) {
|
||||
return new $documentClass($user);
|
||||
}
|
||||
|
||||
public static function createDocument($class) {
|
||||
// TODO: check instance, configuration, ..
|
||||
|
||||
require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/sql.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/conf/config.php';
|
||||
// require_once realpath($_SERVER['DOCUMENT_ROOT']) . "/php/pages/$file.php";
|
||||
require_once realpath($_SERVER['DOCUMENT_ROOT']) . '/php/api/objects/User.php';
|
||||
|
||||
$connectionData = getSqlData($database);
|
||||
$sql = connectSQL($connectionData);
|
||||
if(!$sql->isConnected()) {
|
||||
http_response_code(500);
|
||||
die('Internal Database error');
|
||||
}
|
||||
|
||||
$user = new CUser($sql);
|
||||
$document = new $class($user);
|
||||
$code = $document->getCode();
|
||||
|
||||
$document->sendHeaders();
|
||||
$user->sendCookies();
|
||||
die($code);
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
|
||||
if ($this->databseRequired) {
|
||||
$sql = $this->user->getSQL();
|
||||
if (is_null($sql)) {
|
||||
die("Database is not configured yet.");
|
||||
} else {
|
||||
die("Database is not connected: " . $sql->getLastError());
|
||||
}
|
||||
}
|
||||
|
||||
$body = $this->body->getCode();
|
||||
$head = $this->head->getCode();
|
||||
|
||||
$html = "<!DOCTYPE html>";
|
||||
$html .= "<html>";
|
||||
$html .= $head;
|
||||
$html .= $body;
|
||||
$html .= "</html>";
|
||||
return $html;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
?>
|
||||
126
core/Elements/Head.class.php
Normal file
126
core/Elements/Head.class.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
abstract class Head extends \View {
|
||||
|
||||
protected $sources;
|
||||
protected $title;
|
||||
protected $metas;
|
||||
protected $rawFields;
|
||||
protected $keywords;
|
||||
protected $description;
|
||||
protected $baseUrl;
|
||||
|
||||
function __construct($document) {
|
||||
parent::__construct($document);
|
||||
$this->sources = array();
|
||||
$this->metas = $this->initMetas();
|
||||
$this->rawFields = $this->initRawFields();
|
||||
$this->title = $this->initTitle();
|
||||
$this->initSources();
|
||||
$this->init();
|
||||
}
|
||||
|
||||
protected abstract function initSources();
|
||||
protected abstract function initMetas();
|
||||
protected abstract function initRawFields();
|
||||
protected abstract function initTitle();
|
||||
|
||||
protected function init() {
|
||||
$this->keywords = array();
|
||||
$this->description = "";
|
||||
$this->baseUrl = "";
|
||||
}
|
||||
|
||||
public function setBaseUrl($baseUrl) { $this->baseUrl = $baseUrl; }
|
||||
public function setDescription($description) { $this->description = $description; }
|
||||
public function setKeywords($keywords) { $this->keywords = $keywords; }
|
||||
public function setTitle($title) { $this->title = $title; }
|
||||
public function getSources() { return $this->sources; }
|
||||
public function addScript($type, $url, $js = '') { $this->sources[] = new Script($type, $url, $js); }
|
||||
public function addRawField($rawField) { $this->rawFields[] = $rawField; }
|
||||
public function addMeta($aMeta) { $this->metas[] = $aMeta; }
|
||||
public function addLink($rel, $href, $type = "") { $this->sources[] = new Link($rel, $href, $type); }
|
||||
public function addKeywords($keywords) { array_merge($this->keywords, $keywords); }
|
||||
public function getTitle() { return $this->title; }
|
||||
|
||||
public function addCSS($href, $type = Link::MIME_TEXT_CSS) { $this->sources[] = new Link("stylesheet", $href, $type); }
|
||||
public function addStyle($style) { $this->sources[] = new Style($style); }
|
||||
public function addJS($url) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, $url, ""); }
|
||||
public function addJSCode($code) { $this->sources[] = new Script(Script::MIME_TEXT_JAVASCRIPT, "", $code); }
|
||||
|
||||
public function loadFontawesome() {
|
||||
$this->addCSS(Link::FONTAWESOME);
|
||||
}
|
||||
|
||||
public function loadSyntaxHighlighting() {
|
||||
$this->addJS(Script::HIGHLIGHT);
|
||||
$this->addJSCode(Script::HIGHLIGHT_JS_LOADER);
|
||||
$this->addCSS(Link::HIGHLIGHT);
|
||||
$this->addCSS(Link::HIGHLIGHT_THEME);
|
||||
}
|
||||
|
||||
public function loadJQueryTerminal($unixFormatting = true) {
|
||||
$this->addJS(Script::JQUERY_TERMINAL);
|
||||
if($unixFormatting) $this->addJS(Script::JQUERY_TERMINAL_UNIX);
|
||||
$this->addCSS(Link::JQUERY_TERMINAL);
|
||||
}
|
||||
|
||||
public function loadGoogleRecaptcha($siteKey) {
|
||||
$this->addJS("https://www.google.com/recaptcha/api.js?render=$siteKey");
|
||||
}
|
||||
|
||||
public function loadJQuery() {
|
||||
$this->addJS(Script::JQUERY);
|
||||
}
|
||||
|
||||
public function loadBootstrap() {
|
||||
$this->addCSS(Link::BOOTSTRAP);
|
||||
$this->addJS(Script::BOOTSTRAP);
|
||||
}
|
||||
|
||||
public function loadChartJS() {
|
||||
$this->addJS(Script::MOMENT);
|
||||
$this->addJS(Script::CHART);
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
$header = "<head>";
|
||||
|
||||
foreach($this->metas as $aMeta) {
|
||||
$header .= '<meta';
|
||||
foreach($aMeta as $key => $val) {
|
||||
$header .= " $key=\"$val\"";
|
||||
}
|
||||
$header .= ' />';
|
||||
}
|
||||
|
||||
if(!empty($this->description)) {
|
||||
$header .= "<meta name=\"description\" content=\"$this->description\" />";
|
||||
}
|
||||
|
||||
if(!empty($this->keywords)) {
|
||||
$keywords = implode(", ", $this->keywords);
|
||||
$header .= "<meta name=\"keywords\" content=\"$keywords\" />";
|
||||
}
|
||||
|
||||
if(!empty($this->baseUrl)) {
|
||||
$header .= "<base href=\"$this->baseUrl\">";
|
||||
}
|
||||
|
||||
$header .= "<title>$this->title</title>";
|
||||
|
||||
foreach($this->sources as $src) {
|
||||
$header .= $src->getCode();
|
||||
}
|
||||
|
||||
foreach($this->rawFields as $raw) {
|
||||
$header .= $raw;
|
||||
}
|
||||
|
||||
$header .= "</head>";
|
||||
return $header;
|
||||
}
|
||||
}
|
||||
?>
|
||||
42
core/Elements/Link.class.php
Normal file
42
core/Elements/Link.class.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Link extends Source {
|
||||
|
||||
const STYLESHEET = "stylesheet";
|
||||
const MIME_TEXT_CSS = "text/css";
|
||||
|
||||
const FONTAWESOME = '/css/fontawesome.min.css';
|
||||
// const JQUERY_UI = '/css/jquery-ui.css';
|
||||
// const JQUERY_TERMINAL = '/css/jquery.terminal.min.css';
|
||||
const BOOTSTRAP = '/css/bootstrap.min.css';
|
||||
// const BOOTSTRAP_THEME = '/css/bootstrap-theme.min.css';
|
||||
// const BOOTSTRAP_DATEPICKER_CSS = '/css/bootstrap-datepicker.standalone.min.css';
|
||||
// const BOOTSTRAP_DATEPICKER3_CSS = '/css/bootstrap-datepicker.standalone.min.css';
|
||||
// const HIGHLIGHT = '/css/highlight.css';
|
||||
// const HIGHLIGHT_THEME = '/css/theme.css';
|
||||
const CORE = "/css/style.css";
|
||||
// const ADMIN = "/css/admin.css";
|
||||
// const HOME = "/css/home.css";
|
||||
// const REVEALJS = "/css/reveal.css";
|
||||
// const REVEALJS_THEME_MOON = "/css/reveal_moon.css";
|
||||
// const REVEALJS_THEME_BLACK = "/css/reveal_black.css";
|
||||
|
||||
private $type;
|
||||
private $rel;
|
||||
|
||||
function __construct($rel, $href, $type = "") {
|
||||
parent::__construct('link', $href);
|
||||
$this->type = $type;
|
||||
$this->rel = $rel;
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
$type = (empty($this->type) ? "" : " type=\"$this->type\"");
|
||||
$link = "<link rel=\"$this->rel\" href=\"$this->url\" $type/>";
|
||||
return $link;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
53
core/Elements/Script.class.php
Normal file
53
core/Elements/Script.class.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Script extends Source {
|
||||
|
||||
const MIME_TEXT_JAVASCRIPT = "text/javascript";
|
||||
|
||||
const CORE = "/js/script.js";
|
||||
// const HOME = "/js/home.js";
|
||||
// const ADMIN = "/js/admin.js";
|
||||
// const SORTTABLE = "/js/sorttable.js";
|
||||
const JQUERY = "/js/jquery.min.js";
|
||||
// const JQUERY_UI = "/js/jquery-ui.js";
|
||||
// const JQUERY_MASKED_INPUT = "/js/jquery.maskedinput.min.js";
|
||||
// const JQUERY_CONTEXT_MENU = "/js/jquery.contextmenu.min.js";
|
||||
// const JQUERY_TERMINAL = "/js/jquery.terminal.min.js";
|
||||
// const JQUERY_TERMINAL_UNIX = "/js/unix_formatting.js";
|
||||
// const JSCOLOR = "/js/jscolor.min.js";
|
||||
// const SYNTAX_HIGHLIGHTER = "/js/syntaxhighlighter.js";
|
||||
// const HIGHLIGHT = "/js/highlight.pack.js";
|
||||
// const GOOGLE_CHARTS = "/js/loader.js";
|
||||
const BOOTSTRAP = "/js/bootstrap.min.js";
|
||||
// const BOOTSTRAP_DATEPICKER_JS = "/js/bootstrap-datepicker.min.js";
|
||||
// const POPPER = "/js/popper.min.js";
|
||||
// const JSMPEG = "/js/jsmpeg.min.js";
|
||||
// const MOMENT = "/js/moment.min.js";
|
||||
// const CHART = "/js/chart.js";
|
||||
// const REVEALJS = "/js/reveal.js";
|
||||
// const REVEALJS_PLUGIN_NOTES = "/js/reveal_notes.js";
|
||||
const INSTALL = "/js/install.js";
|
||||
|
||||
const HIGHLIGHT_JS_LOADER = "\$(document).ready(function(){\$('code').each(function(i, block) { hljs.highlightBlock(block); }); })";
|
||||
|
||||
private $type;
|
||||
private $content;
|
||||
|
||||
function __construct($type, $src, $content = "") {
|
||||
parent::__construct('script', $src);
|
||||
$this->type = $type;
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
$src = (empty($this->url) ? "" : " src=\"$this->url\"");
|
||||
$script = "<script type=\"$this->type\"$src>";
|
||||
$script .= $this->content;
|
||||
$script .= '</script>';
|
||||
return $script;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
22
core/Elements/Source.class.php
Normal file
22
core/Elements/Source.class.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Source extends \View {
|
||||
|
||||
protected $sourceType;
|
||||
protected $url;
|
||||
|
||||
public function __construct($sourceType, $url) {
|
||||
$this->sourceType = $sourceType;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function getCode() {
|
||||
return "<$sourceType />";
|
||||
}
|
||||
|
||||
public function getUrl() { return $this->url; }
|
||||
}
|
||||
|
||||
?>
|
||||
19
core/Elements/Style.class.php
Normal file
19
core/Elements/Style.class.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Elements;
|
||||
|
||||
class Style extends Source {
|
||||
|
||||
private $style;
|
||||
|
||||
function __construct($style) {
|
||||
parent::__construct('style', '');
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
function getCode() {
|
||||
return "<style>$this->style</style>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
39
core/External/PHPMailer/Exception.php
vendored
Normal file
39
core/External/PHPMailer/Exception.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer Exception class.
|
||||
* PHP Version 5.5.
|
||||
*
|
||||
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
*
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2017 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
namespace External\PHPMailer;
|
||||
|
||||
/**
|
||||
* PHPMailer exception handler.
|
||||
*
|
||||
* @author Marcus Bointon <phpmailer@synchromedia.co.uk>
|
||||
*/
|
||||
class Exception extends \Exception
|
||||
{
|
||||
/**
|
||||
* Prettify error message output.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function errorMessage()
|
||||
{
|
||||
return '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n";
|
||||
}
|
||||
}
|
||||
138
core/External/PHPMailer/OAuth.php
vendored
Normal file
138
core/External/PHPMailer/OAuth.php
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer - PHP email creation and transport class.
|
||||
* PHP Version 5.5.
|
||||
*
|
||||
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
*
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2015 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
namespace External\PHPMailer;
|
||||
|
||||
use League\OAuth2\Client\Grant\RefreshToken;
|
||||
use League\OAuth2\Client\Provider\AbstractProvider;
|
||||
use League\OAuth2\Client\Token\AccessToken;
|
||||
|
||||
/**
|
||||
* OAuth - OAuth2 authentication wrapper class.
|
||||
* Uses the oauth2-client package from the League of Extraordinary Packages.
|
||||
*
|
||||
* @see http://oauth2-client.thephpleague.com
|
||||
*
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
*/
|
||||
class OAuth
|
||||
{
|
||||
/**
|
||||
* An instance of the League OAuth Client Provider.
|
||||
*
|
||||
* @var AbstractProvider
|
||||
*/
|
||||
protected $provider;
|
||||
|
||||
/**
|
||||
* The current OAuth access token.
|
||||
*
|
||||
* @var AccessToken
|
||||
*/
|
||||
protected $oauthToken;
|
||||
|
||||
/**
|
||||
* The user's email address, usually used as the login ID
|
||||
* and also the from address when sending email.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauthUserEmail = '';
|
||||
|
||||
/**
|
||||
* The client secret, generated in the app definition of the service you're connecting to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauthClientSecret = '';
|
||||
|
||||
/**
|
||||
* The client ID, generated in the app definition of the service you're connecting to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauthClientId = '';
|
||||
|
||||
/**
|
||||
* The refresh token, used to obtain new AccessTokens.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $oauthRefreshToken = '';
|
||||
|
||||
/**
|
||||
* OAuth constructor.
|
||||
*
|
||||
* @param array $options Associative array containing
|
||||
* `provider`, `userName`, `clientSecret`, `clientId` and `refreshToken` elements
|
||||
*/
|
||||
public function __construct($options)
|
||||
{
|
||||
$this->provider = $options['provider'];
|
||||
$this->oauthUserEmail = $options['userName'];
|
||||
$this->oauthClientSecret = $options['clientSecret'];
|
||||
$this->oauthClientId = $options['clientId'];
|
||||
$this->oauthRefreshToken = $options['refreshToken'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new RefreshToken.
|
||||
*
|
||||
* @return RefreshToken
|
||||
*/
|
||||
protected function getGrant()
|
||||
{
|
||||
return new RefreshToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new AccessToken.
|
||||
*
|
||||
* @return AccessToken
|
||||
*/
|
||||
protected function getToken()
|
||||
{
|
||||
return $this->provider->getAccessToken(
|
||||
$this->getGrant(),
|
||||
['refresh_token' => $this->oauthRefreshToken]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a base64-encoded OAuth token.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOauth64()
|
||||
{
|
||||
// Get a new token if it's not available or has expired
|
||||
if (null === $this->oauthToken || $this->oauthToken->hasExpired()) {
|
||||
$this->oauthToken = $this->getToken();
|
||||
}
|
||||
|
||||
return base64_encode(
|
||||
'user=' .
|
||||
$this->oauthUserEmail .
|
||||
"\001auth=Bearer " .
|
||||
$this->oauthToken .
|
||||
"\001\001"
|
||||
);
|
||||
}
|
||||
}
|
||||
4778
core/External/PHPMailer/PHPMailer.php
vendored
Normal file
4778
core/External/PHPMailer/PHPMailer.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
419
core/External/PHPMailer/POP3.php
vendored
Normal file
419
core/External/PHPMailer/POP3.php
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
<?php
|
||||
/**
|
||||
* PHPMailer POP-Before-SMTP Authentication Class.
|
||||
* PHP Version 5.5.
|
||||
*
|
||||
* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
|
||||
*
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
* @author Brent R. Matzelle (original founder)
|
||||
* @copyright 2012 - 2019 Marcus Bointon
|
||||
* @copyright 2010 - 2012 Jim Jagielski
|
||||
* @copyright 2004 - 2009 Andy Prevost
|
||||
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
|
||||
* @note This program is distributed in the hope that it will be useful - WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
namespace External\PHPMailer;
|
||||
|
||||
/**
|
||||
* PHPMailer POP-Before-SMTP Authentication Class.
|
||||
* Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
|
||||
* 1) This class does not support APOP authentication.
|
||||
* 2) Opening and closing lots of POP3 connections can be quite slow. If you need
|
||||
* to send a batch of emails then just perform the authentication once at the start,
|
||||
* and then loop through your mail sending script. Providing this process doesn't
|
||||
* take longer than the verification period lasts on your POP3 server, you should be fine.
|
||||
* 3) This is really ancient technology; you should only need to use it to talk to very old systems.
|
||||
* 4) This POP3 class is deliberately lightweight and incomplete, implementing just
|
||||
* enough to do authentication.
|
||||
* If you want a more complete class there are other POP3 classes for PHP available.
|
||||
*
|
||||
* @author Richard Davey (original author) <rich@corephp.co.uk>
|
||||
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
|
||||
* @author Jim Jagielski (jimjag) <jimjag@gmail.com>
|
||||
* @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
|
||||
*/
|
||||
class POP3
|
||||
{
|
||||
/**
|
||||
* The POP3 PHPMailer Version number.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '6.1.4';
|
||||
|
||||
/**
|
||||
* Default POP3 port number.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const DEFAULT_PORT = 110;
|
||||
|
||||
/**
|
||||
* Default timeout in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const DEFAULT_TIMEOUT = 30;
|
||||
|
||||
/**
|
||||
* Debug display level.
|
||||
* Options: 0 = no, 1+ = yes.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $do_debug = 0;
|
||||
|
||||
/**
|
||||
* POP3 mail server hostname.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $host;
|
||||
|
||||
/**
|
||||
* POP3 port number.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $port;
|
||||
|
||||
/**
|
||||
* POP3 Timeout Value in seconds.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $tval;
|
||||
|
||||
/**
|
||||
* POP3 username.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $username;
|
||||
|
||||
/**
|
||||
* POP3 password.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $password;
|
||||
|
||||
/**
|
||||
* Resource handle for the POP3 connection socket.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
protected $pop_conn;
|
||||
|
||||
/**
|
||||
* Are we connected?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $connected = false;
|
||||
|
||||
/**
|
||||
* Error container.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $errors = [];
|
||||
|
||||
/**
|
||||
* Line break constant.
|
||||
*/
|
||||
const LE = "\r\n";
|
||||
|
||||
/**
|
||||
* Simple static wrapper for all-in-one POP before SMTP.
|
||||
*
|
||||
* @param string $host The hostname to connect to
|
||||
* @param int|bool $port The port number to connect to
|
||||
* @param int|bool $timeout The timeout value
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param int $debug_level
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function popBeforeSmtp(
|
||||
$host,
|
||||
$port = false,
|
||||
$timeout = false,
|
||||
$username = '',
|
||||
$password = '',
|
||||
$debug_level = 0
|
||||
) {
|
||||
$pop = new self();
|
||||
|
||||
return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level);
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate with a POP3 server.
|
||||
* A connect, login, disconnect sequence
|
||||
* appropriate for POP-before SMTP authorisation.
|
||||
*
|
||||
* @param string $host The hostname to connect to
|
||||
* @param int|bool $port The port number to connect to
|
||||
* @param int|bool $timeout The timeout value
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param int $debug_level
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0)
|
||||
{
|
||||
$this->host = $host;
|
||||
// If no port value provided, use default
|
||||
if (false === $port) {
|
||||
$this->port = static::DEFAULT_PORT;
|
||||
} else {
|
||||
$this->port = (int) $port;
|
||||
}
|
||||
// If no timeout value provided, use default
|
||||
if (false === $timeout) {
|
||||
$this->tval = static::DEFAULT_TIMEOUT;
|
||||
} else {
|
||||
$this->tval = (int) $timeout;
|
||||
}
|
||||
$this->do_debug = $debug_level;
|
||||
$this->username = $username;
|
||||
$this->password = $password;
|
||||
// Reset the error log
|
||||
$this->errors = [];
|
||||
// connect
|
||||
$result = $this->connect($this->host, $this->port, $this->tval);
|
||||
if ($result) {
|
||||
$login_result = $this->login($this->username, $this->password);
|
||||
if ($login_result) {
|
||||
$this->disconnect();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We need to disconnect regardless of whether the login succeeded
|
||||
$this->disconnect();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to a POP3 server.
|
||||
*
|
||||
* @param string $host
|
||||
* @param int|bool $port
|
||||
* @param int $tval
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function connect($host, $port = false, $tval = 30)
|
||||
{
|
||||
// Are we already connected?
|
||||
if ($this->connected) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//On Windows this will raise a PHP Warning error if the hostname doesn't exist.
|
||||
//Rather than suppress it with @fsockopen, capture it cleanly instead
|
||||
set_error_handler([$this, 'catchWarning']);
|
||||
|
||||
if (false === $port) {
|
||||
$port = static::DEFAULT_PORT;
|
||||
}
|
||||
|
||||
// connect to the POP3 server
|
||||
$this->pop_conn = fsockopen(
|
||||
$host, // POP3 Host
|
||||
$port, // Port #
|
||||
$errno, // Error Number
|
||||
$errstr, // Error Message
|
||||
$tval
|
||||
); // Timeout (seconds)
|
||||
// Restore the error handler
|
||||
restore_error_handler();
|
||||
|
||||
// Did we connect?
|
||||
if (false === $this->pop_conn) {
|
||||
// It would appear not...
|
||||
$this->setError(
|
||||
"Failed to connect to server $host on port $port. errno: $errno; errstr: $errstr"
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Increase the stream time-out
|
||||
stream_set_timeout($this->pop_conn, $tval, 0);
|
||||
|
||||
// Get the POP3 server response
|
||||
$pop3_response = $this->getResponse();
|
||||
// Check for the +OK
|
||||
if ($this->checkResponse($pop3_response)) {
|
||||
// The connection is established and the POP3 server is talking
|
||||
$this->connected = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log in to the POP3 server.
|
||||
* Does not support APOP (RFC 2828, 4949).
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function login($username = '', $password = '')
|
||||
{
|
||||
if (!$this->connected) {
|
||||
$this->setError('Not connected to POP3 server');
|
||||
}
|
||||
if (empty($username)) {
|
||||
$username = $this->username;
|
||||
}
|
||||
if (empty($password)) {
|
||||
$password = $this->password;
|
||||
}
|
||||
|
||||
// Send the Username
|
||||
$this->sendString("USER $username" . static::LE);
|
||||
$pop3_response = $this->getResponse();
|
||||
if ($this->checkResponse($pop3_response)) {
|
||||
// Send the Password
|
||||
$this->sendString("PASS $password" . static::LE);
|
||||
$pop3_response = $this->getResponse();
|
||||
if ($this->checkResponse($pop3_response)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from the POP3 server.
|
||||
*/
|
||||
public function disconnect()
|
||||
{
|
||||
$this->sendString('QUIT');
|
||||
//The QUIT command may cause the daemon to exit, which will kill our connection
|
||||
//So ignore errors here
|
||||
try {
|
||||
@fclose($this->pop_conn);
|
||||
} catch (Exception $e) {
|
||||
//Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a response from the POP3 server.
|
||||
*
|
||||
* @param int $size The maximum number of bytes to retrieve
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getResponse($size = 128)
|
||||
{
|
||||
$response = fgets($this->pop_conn, $size);
|
||||
if ($this->do_debug >= 1) {
|
||||
echo 'Server -> Client: ', $response;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send raw data to the POP3 server.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function sendString($string)
|
||||
{
|
||||
if ($this->pop_conn) {
|
||||
if ($this->do_debug >= 2) { //Show client messages when debug >= 2
|
||||
echo 'Client -> Server: ', $string;
|
||||
}
|
||||
|
||||
return fwrite($this->pop_conn, $string, strlen($string));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the POP3 server response.
|
||||
* Looks for for +OK or -ERR.
|
||||
*
|
||||
* @param string $string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkResponse($string)
|
||||
{
|
||||
if (strpos($string, '+OK') !== 0) {
|
||||
$this->setError("Server reported an error: $string");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error to the internal error store.
|
||||
* Also display debug output if it's enabled.
|
||||
*
|
||||
* @param string $error
|
||||
*/
|
||||
protected function setError($error)
|
||||
{
|
||||
$this->errors[] = $error;
|
||||
if ($this->do_debug >= 1) {
|
||||
echo '<pre>';
|
||||
foreach ($this->errors as $e) {
|
||||
print_r($e);
|
||||
}
|
||||
echo '</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of error messages, if any.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* POP3 connection error handler.
|
||||
*
|
||||
* @param int $errno
|
||||
* @param string $errstr
|
||||
* @param string $errfile
|
||||
* @param int $errline
|
||||
*/
|
||||
protected function catchWarning($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
$this->setError(
|
||||
'Connecting to the POP3 server raised a PHP warning:' .
|
||||
"errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline"
|
||||
);
|
||||
}
|
||||
}
|
||||
1370
core/External/PHPMailer/SMTP.php
vendored
Normal file
1370
core/External/PHPMailer/SMTP.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
199
core/External/jwt.php
vendored
Normal file
199
core/External/jwt.php
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* JSON Web Token implementation, based on this spec:
|
||||
* http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-06
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Authentication
|
||||
* @package Authentication_JWT
|
||||
* @author Neuman Vong <neuman@twilio.com>
|
||||
* @author Anant Narayanan <anant@php.net>
|
||||
* @license http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
|
||||
* @link https://github.com/firebase/php-jwt
|
||||
*/
|
||||
|
||||
namespace External;
|
||||
|
||||
class JWT
|
||||
{
|
||||
/**
|
||||
* Decodes a JWT string into a PHP object.
|
||||
*
|
||||
* @param string $jwt The JWT
|
||||
* @param string|null $key The secret key
|
||||
* @param bool $verify Don't skip verification process
|
||||
*
|
||||
* @return object The JWT's payload as a PHP object
|
||||
* @throws UnexpectedValueException Provided JWT was invalid
|
||||
* @throws DomainException Algorithm was not provided
|
||||
*
|
||||
* @uses jsonDecode
|
||||
* @uses urlsafeB64Decode
|
||||
*/
|
||||
public static function decode($jwt, $key = null, $verify = true)
|
||||
{
|
||||
$tks = explode('.', $jwt);
|
||||
if (count($tks) != 3) {
|
||||
throw new UnexpectedValueException('Wrong number of segments');
|
||||
}
|
||||
list($headb64, $bodyb64, $cryptob64) = $tks;
|
||||
if (null === ($header = JWT::jsonDecode(JWT::urlsafeB64Decode($headb64)))) {
|
||||
throw new UnexpectedValueException('Invalid segment encoding');
|
||||
}
|
||||
if (null === $payload = JWT::jsonDecode(JWT::urlsafeB64Decode($bodyb64))) {
|
||||
throw new UnexpectedValueException('Invalid segment encoding');
|
||||
}
|
||||
$sig = JWT::urlsafeB64Decode($cryptob64);
|
||||
if ($verify) {
|
||||
if (empty($header->alg)) {
|
||||
throw new DomainException('Empty algorithm');
|
||||
}
|
||||
if ($sig != JWT::sign("$headb64.$bodyb64", $key, $header->alg)) {
|
||||
throw new UnexpectedValueException('Signature verification failed');
|
||||
}
|
||||
}
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts and signs a PHP object or array into a JWT string.
|
||||
*
|
||||
* @param object|array $payload PHP object or array
|
||||
* @param string $key The secret key
|
||||
* @param string $algo The signing algorithm. Supported
|
||||
* algorithms are 'HS256', 'HS384' and 'HS512'
|
||||
*
|
||||
* @return string A signed JWT
|
||||
* @uses jsonEncode
|
||||
* @uses urlsafeB64Encode
|
||||
*/
|
||||
public static function encode($payload, $key, $algo = 'HS256')
|
||||
{
|
||||
$header = array('typ' => 'JWT', 'alg' => $algo);
|
||||
|
||||
$segments = array();
|
||||
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($header));
|
||||
$segments[] = JWT::urlsafeB64Encode(JWT::jsonEncode($payload));
|
||||
$signing_input = implode('.', $segments);
|
||||
|
||||
$signature = JWT::sign($signing_input, $key, $algo);
|
||||
$segments[] = JWT::urlsafeB64Encode($signature);
|
||||
|
||||
return implode('.', $segments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a string with a given key and algorithm.
|
||||
*
|
||||
* @param string $msg The message to sign
|
||||
* @param string $key The secret key
|
||||
* @param string $method The signing algorithm. Supported
|
||||
* algorithms are 'HS256', 'HS384' and 'HS512'
|
||||
*
|
||||
* @return string An encrypted message
|
||||
* @throws DomainException Unsupported algorithm was specified
|
||||
*/
|
||||
public static function sign($msg, $key, $method = 'HS256')
|
||||
{
|
||||
$methods = array(
|
||||
'HS256' => 'sha256',
|
||||
'HS384' => 'sha384',
|
||||
'HS512' => 'sha512',
|
||||
);
|
||||
if (empty($methods[$method])) {
|
||||
throw new DomainException('Algorithm not supported');
|
||||
}
|
||||
return hash_hmac($methods[$method], $msg, $key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a JSON string into a PHP object.
|
||||
*
|
||||
* @param string $input JSON string
|
||||
*
|
||||
* @return object Object representation of JSON string
|
||||
* @throws DomainException Provided string was invalid JSON
|
||||
*/
|
||||
public static function jsonDecode($input)
|
||||
{
|
||||
$obj = json_decode($input);
|
||||
if (function_exists('json_last_error') && $errno = json_last_error()) {
|
||||
JWT::_handleJsonError($errno);
|
||||
} else if ($obj === null && $input !== 'null') {
|
||||
throw new DomainException('Null result with non-null input');
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a PHP object into a JSON string.
|
||||
*
|
||||
* @param object|array $input A PHP object or array
|
||||
*
|
||||
* @return string JSON representation of the PHP object or array
|
||||
* @throws DomainException Provided object could not be encoded to valid JSON
|
||||
*/
|
||||
public static function jsonEncode($input)
|
||||
{
|
||||
$json = json_encode($input);
|
||||
if (function_exists('json_last_error') && $errno = json_last_error()) {
|
||||
JWT::_handleJsonError($errno);
|
||||
} else if ($json === 'null' && $input !== null) {
|
||||
throw new DomainException('Null result with non-null input');
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a string with URL-safe Base64.
|
||||
*
|
||||
* @param string $input A Base64 encoded string
|
||||
*
|
||||
* @return string A decoded string
|
||||
*/
|
||||
public static function urlsafeB64Decode($input)
|
||||
{
|
||||
$remainder = strlen($input) % 4;
|
||||
if ($remainder) {
|
||||
$padlen = 4 - $remainder;
|
||||
$input .= str_repeat('=', $padlen);
|
||||
}
|
||||
return base64_decode(strtr($input, '-_', '+/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a string with URL-safe Base64.
|
||||
*
|
||||
* @param string $input The string you want encoded
|
||||
*
|
||||
* @return string The base64 encode of what you passed in
|
||||
*/
|
||||
public static function urlsafeB64Encode($input)
|
||||
{
|
||||
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to create a JSON error.
|
||||
*
|
||||
* @param int $errno An error number from json_last_error()
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function _handleJsonError($errno)
|
||||
{
|
||||
$messages = array(
|
||||
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
|
||||
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
|
||||
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
|
||||
);
|
||||
throw new DomainException(
|
||||
isset($messages[$errno])
|
||||
? $messages[$errno]
|
||||
: 'Unknown JSON error: ' . $errno
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
5702
core/External/phpQuery.php
vendored
Normal file
5702
core/External/phpQuery.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
14
core/Objects/ApiObject.class.php
Normal file
14
core/Objects/ApiObject.class.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Objects;
|
||||
|
||||
abstract class ApiObject implements \JsonSerializable {
|
||||
|
||||
public abstract function jsonSerialize();
|
||||
|
||||
public function __construct() { }
|
||||
public function __toString() { return json_encode($this); }
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
46
core/Objects/ConnectionData.class.php
Normal file
46
core/Objects/ConnectionData.class.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Objects;
|
||||
|
||||
class ConnectionData {
|
||||
|
||||
private $host;
|
||||
private $port;
|
||||
private $login;
|
||||
private $password;
|
||||
private $properties;
|
||||
|
||||
public function __construct($host, $port, $login, $password) {
|
||||
$this->host = $host;
|
||||
$this->port = $port;
|
||||
$this->login = $login;
|
||||
$this->password = $password;
|
||||
$this->properties = array();
|
||||
}
|
||||
|
||||
public function getProperties() {
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
public function getProperty($key) {
|
||||
if(isset($this->properties[$key]))
|
||||
return $this->properties[$key];
|
||||
else
|
||||
return '';
|
||||
}
|
||||
|
||||
public function setProperty($key, $val) {
|
||||
if(!is_string($val)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->properties[$key] = $val;
|
||||
}
|
||||
|
||||
public function getHost() { return $this->host; }
|
||||
public function getPort() { return $this->port; }
|
||||
public function getLogin() { return $this->login; }
|
||||
public function getPassword() { return $this->password; }
|
||||
}
|
||||
|
||||
?>
|
||||
133
core/Objects/Language.class.php
Normal file
133
core/Objects/Language.class.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Objects;
|
||||
|
||||
class Language extends ApiObject {
|
||||
|
||||
const LANG_CODE_PATTERN = "/^[a-zA-Z]+_[a-zA-Z]+$/";
|
||||
|
||||
private $languageId;
|
||||
private $langCode;
|
||||
private $langName;
|
||||
private $modules;
|
||||
|
||||
protected $entries;
|
||||
|
||||
public function __construct($languageId, $langCode, $langName) {
|
||||
$this->languageId = $languageId;
|
||||
$this->langCode = $langCode;
|
||||
$this->langName = $langName;
|
||||
$this->entries = array();
|
||||
$this->modules = array();
|
||||
}
|
||||
|
||||
public function getId() { return $this->languageId; }
|
||||
public function getCode() { return $this->langCode; }
|
||||
public function getShortCode() { return substr($this->langCode, 0, 2); }
|
||||
public function getName() { return $this->langName; }
|
||||
public function getIconPath() { return "/img/icons/lang/$this->langCode.gif"; }
|
||||
public function getEntries() { return $this->entries; }
|
||||
public function getModules() { return $this->modules; }
|
||||
|
||||
public function loadModule($module) {
|
||||
if(!is_object($module))
|
||||
$module = new $module;
|
||||
|
||||
$aModuleEntries = $module->getEntries($this->langCode);
|
||||
$this->entries = array_merge($this->entries, $aModuleEntries);
|
||||
$this->modules[] = $module;
|
||||
}
|
||||
|
||||
public function translate($key) {
|
||||
if(isset($this->entries[$key]))
|
||||
return $this->entries[$key];
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
public function sendCookie() {
|
||||
setcookie('lang', $this->langCode, 0, "/", "");
|
||||
}
|
||||
|
||||
public function jsonSerialize() {
|
||||
return array(
|
||||
'uid' => $this->languageId,
|
||||
'code' => $this->langCode,
|
||||
'name' => $this->langName,
|
||||
);
|
||||
}
|
||||
|
||||
public static function newInstance($languageId, $langCode, $langName) {
|
||||
|
||||
if(!preg_match(Language::LANG_CODE_PATTERN, $langCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: include dynamically wanted Language
|
||||
return new Language($languageId, $langCode, $langName);
|
||||
|
||||
// $className = $langCode
|
||||
// return new $className($languageId, $langCode);
|
||||
}
|
||||
|
||||
public function load() {
|
||||
global $LANGUAGE;
|
||||
$LANGUAGE = $this;
|
||||
}
|
||||
|
||||
public static function DEFAULT_LANGUAGE() {
|
||||
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
|
||||
$acceptLanguage = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
||||
$aSplit = explode(',',$acceptLanguage);
|
||||
foreach($aSplit as $code) {
|
||||
if(strlen($code) == 2) {
|
||||
$code = $code . '_' . strtoupper($code);
|
||||
}
|
||||
|
||||
$code = str_replace("-", "_", $code);
|
||||
if(strlen($code) != 5)
|
||||
continue;
|
||||
|
||||
$lang = Language::newInstance(0, $code, "");
|
||||
if($lang)
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
|
||||
return Language::newInstance(1, "en_US", "American English");
|
||||
}
|
||||
};
|
||||
|
||||
function L($key) {
|
||||
if(!array_key_exists('LANGUAGE', $GLOBALS))
|
||||
return $key;
|
||||
|
||||
global $LANGUAGE;
|
||||
return $LANGUAGE->translate($key);
|
||||
}
|
||||
|
||||
function LANG_NAME() {
|
||||
if(!array_key_exists('LANGUAGE', $GLOBALS))
|
||||
return "LANG_NAME";
|
||||
|
||||
global $LANGUAGE;
|
||||
return $LANGUAGE->getName();
|
||||
}
|
||||
|
||||
function LANG_CODE() {
|
||||
if(!array_key_exists('LANGUAGE', $GLOBALS))
|
||||
return "LANG_CODE";
|
||||
|
||||
global $LANGUAGE;
|
||||
return $LANGUAGE->getCode();
|
||||
}
|
||||
|
||||
function SHORT_LANG_CODE() {
|
||||
if(!array_key_exists('LANGUAGE', $GLOBALS))
|
||||
return "SHORT_LANG_CODE";
|
||||
|
||||
global $LANGUAGE;
|
||||
return $LANGUAGE->getShortCode();
|
||||
}
|
||||
|
||||
?>
|
||||
105
core/Objects/Session.class.php
Normal file
105
core/Objects/Session.class.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Objects;
|
||||
|
||||
class Session extends ApiObject {
|
||||
|
||||
const DURATION = 120;
|
||||
|
||||
private $sessionId;
|
||||
private $user;
|
||||
private $expires;
|
||||
private $ipAddress;
|
||||
private $os;
|
||||
private $browser;
|
||||
|
||||
public function __construct($user, $sessionId = NULL) {
|
||||
$this->user = $user;
|
||||
$this->sessionId = $sessionId;
|
||||
}
|
||||
|
||||
private function updateMetaData() {
|
||||
$userAgent = get_browser($_SERVER['HTTP_USER_AGENT'], true);
|
||||
$this->expires = time() + Session::DURATION * 60;
|
||||
$this->ipAddress = $_SERVER['REMOTE_ADDR'];
|
||||
$this->os = $userAgent['platform'];
|
||||
$this->browser = $userAgent['parent'];
|
||||
}
|
||||
|
||||
public function sendCookie() {
|
||||
$this->updateMetaData();
|
||||
$token = array('userId' => $this->user->getId(), 'sessionId' => $this->sessionId);
|
||||
$sessionCookie = JWT::encode($token, getJwtKey());
|
||||
setcookie('session', $sessionCookie, $this->expires, "/", "", true);
|
||||
}
|
||||
|
||||
public function getExpiresTime() {
|
||||
return $this->expires;
|
||||
}
|
||||
|
||||
public function getExpiresSeconds() {
|
||||
return ($this->expires - time());
|
||||
}
|
||||
|
||||
public function jsonSerialize() {
|
||||
return array(
|
||||
'uid' => $this->sessionId,
|
||||
'uidUser' => $this->user->getId(),
|
||||
'expires' => $this->expires,
|
||||
'ipAddress' => $this->ipAddress,
|
||||
'os' => $this->os,
|
||||
'browser' => $this->browser,
|
||||
);
|
||||
}
|
||||
|
||||
public function insert() {
|
||||
$this->updateMetaData();
|
||||
$query = 'INSERT INTO Session (expires, uidUser, ipAddress, os, browser)
|
||||
VALUES (DATE_ADD(NOW(), INTERVAL ? MINUTE),?,?,?,?)';
|
||||
$request = new CExecuteStatement($this->user);
|
||||
|
||||
$success = $request->execute(array(
|
||||
'query' => $query,
|
||||
Session::DURATION,
|
||||
$this->user->getId(),
|
||||
$this->ipAddress,
|
||||
$this->os,
|
||||
$this->browser,
|
||||
));
|
||||
|
||||
if($success) {
|
||||
$this->sessionId = $this->user->getSQL()->getLastInsertId();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function destroy() {
|
||||
$query = 'DELETE FROM Session WHERE Session.uid=? OR Session.expires<=NOW()';
|
||||
$request = new CExecuteStatement($this->user);
|
||||
$success = $request->execute(array('query' => $query, $this->sessionId));
|
||||
return $success;
|
||||
}
|
||||
|
||||
public function update() {
|
||||
$this->updateMetaData();
|
||||
$query = 'UPDATE Session
|
||||
SET Session.expires=DATE_ADD(NOW(), INTERVAL ? MINUTE), Session.ipAddress=?,
|
||||
Session.os=?, Session.browser=?
|
||||
WHERE Session.uid=?';
|
||||
$request = new CExecuteStatement($this->user);
|
||||
$success = $request->execute(array(
|
||||
'query' => $query,
|
||||
Session::DURATION,
|
||||
$this->ipAddress,
|
||||
$this->os,
|
||||
$this->browser,
|
||||
$this->sessionId,
|
||||
));
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
189
core/Objects/User.class.php
Normal file
189
core/Objects/User.class.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Objects;
|
||||
|
||||
class User extends ApiObject {
|
||||
|
||||
private $sql;
|
||||
private $configuration;
|
||||
private $loggedIn;
|
||||
private $session;
|
||||
private $uid;
|
||||
private $username;
|
||||
private $language;
|
||||
|
||||
public function __construct($configuration) {
|
||||
$this->configuration = $configuration;
|
||||
$this->setLangauge(Language::DEFAULT_LANGUAGE());
|
||||
$this->reset();
|
||||
$this->connectDb();
|
||||
$this->parseCookies();
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if($this->sql && $this->sql->isConnected()) {
|
||||
$this->sql->close();
|
||||
}
|
||||
}
|
||||
|
||||
private function connectDb() {
|
||||
$databaseConf = $this->configuration->getDatabase();
|
||||
if($databaseConf) {
|
||||
$this->sql = \Driver\SQL::createConnection($databaseConf);
|
||||
}
|
||||
}
|
||||
|
||||
public function setSql($sql) { $this->sql = $sql; }
|
||||
public function getId() { return $this->uid; }
|
||||
public function isLoggedIn() { return $this->loggedIn; }
|
||||
public function getUsername() { return $this->username; }
|
||||
public function getSQL() { return $this->sql; }
|
||||
public function getLanguage() { return $this->language; }
|
||||
public function setLangauge($language) { $this->language = $language; $language->load(); }
|
||||
public function getSession() { return $this->session; }
|
||||
public function getConfiguration() { return $this->configuration; }
|
||||
|
||||
public function __debugInfo() {
|
||||
$debugInfo = array(
|
||||
'loggedIn' => $this->loggedIn,
|
||||
'language' => $this->language->getName(),
|
||||
);
|
||||
|
||||
if($this->loggedIn) {
|
||||
$debugInfo['uid'] = $this->uid;
|
||||
$debugInfo['username'] = $this->username;
|
||||
}
|
||||
|
||||
return $debugInfo;
|
||||
}
|
||||
|
||||
public function jsonSerialize() {
|
||||
return array(
|
||||
'uid' => $this->uid,
|
||||
'name' => $this->username,
|
||||
'language' => $this->language,
|
||||
'session' => $this->session,
|
||||
);
|
||||
}
|
||||
|
||||
private function reset() {
|
||||
$this->uid = 0;
|
||||
$this->username = '';
|
||||
$this->loggedIn = false;
|
||||
$this->session = false;
|
||||
}
|
||||
|
||||
public function logout() {
|
||||
if($this->loggedIn) {
|
||||
$this->session->destroy();
|
||||
$this->reset();
|
||||
}
|
||||
}
|
||||
|
||||
public function updateLanguage($lang) {
|
||||
$request = new CSetLanguage($this);
|
||||
return $request->execute(array("langCode" => $lang));
|
||||
}
|
||||
|
||||
public function sendCookies() {
|
||||
if($this->loggedIn) {
|
||||
$this->session->sendCookie();
|
||||
}
|
||||
|
||||
$this->language->sendCookie();
|
||||
}
|
||||
|
||||
public function readData($userId, $sessionId, $sessionUpdate = true) {
|
||||
$query = 'SELECT User.name as userName, Language.uid as langId, Language.code as langCode
|
||||
FROM User
|
||||
INNER JOIN Session ON User.uid=Session.uidUser
|
||||
LEFT JOIN Language ON User.uidLanguage=Language.uid
|
||||
WHERE User.uid=? AND Session.uid=? AND Session.expires>now()';
|
||||
$request = new CExecuteSelect($this);
|
||||
$success = $request->execute(array('query' => $query, $userId, $sessionId));
|
||||
|
||||
if($success) {
|
||||
if(count($request->getResult()['rows']) === 0) {
|
||||
$success = false;
|
||||
} else {
|
||||
$row = $request->getResult()['rows'][0];
|
||||
$this->username = $row['userName'];
|
||||
$this->uid = $userId;
|
||||
$this->session = new CSession($this, $sessionId);
|
||||
if($sessionUpdate) $this->session->update();
|
||||
$this->loggedIn = true;
|
||||
|
||||
if(!is_null($row['langId'])) {
|
||||
$this->setLangauge(CLanguage::newInstance($row['langId'], $row['langCode']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
private function parseCookies() {
|
||||
if(isset($_COOKIE['session'])
|
||||
&& is_string($_COOKIE['session'])
|
||||
&& !empty($_COOKIE['session'])
|
||||
&& ($jwt = $this->configuration->getJWT())) {
|
||||
try {
|
||||
$token = $_COOKIE['session'];
|
||||
$decoded = (array)External\JWT::decode($token, $jwt->getKey());
|
||||
if(!is_null($decoded)) {
|
||||
$userId = (isset($decoded['userId']) ? $decoded['userId'] : NULL);
|
||||
$sessionId = (isset($decoded['sessionId']) ? $decoded['sessionId'] : NULL);
|
||||
if(!is_null($userId) && !is_null($sessionId)) {
|
||||
$this->readData($userId, $sessionId);
|
||||
}
|
||||
}
|
||||
} catch(Exception $e) {
|
||||
echo $e;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_GET['lang']) && is_string($_GET["lang"]) && !empty($_GET["lang"])) {
|
||||
$this->updateLanguage($_GET['lang']);
|
||||
} else if(isset($_COOKIE['lang']) && is_string($_COOKIE["lang"]) && !empty($_COOKIE["lang"])) {
|
||||
$this->updateLanguage($_COOKIE['lang']);
|
||||
}
|
||||
}
|
||||
|
||||
public function createSession($userId) {
|
||||
$this->uid = $userId;
|
||||
$this->session = new Session($this);
|
||||
$this->loggedIn = $this->session->insert();
|
||||
return $this->loggedIn;
|
||||
}
|
||||
|
||||
public function authorize($apiKey) {
|
||||
if($this->loggedIn)
|
||||
return true;
|
||||
|
||||
$query = 'SELECT ApiKey.uidUser as uid, User.name as username, Language.uid as langId, Language.code as langCode
|
||||
FROM ApiKey, User
|
||||
LEFT JOIN Language ON User.uidLanguage=Language.uid
|
||||
WHERE api_key=? AND valid_until > now() AND User.uid = ApiKey.uidUser';
|
||||
|
||||
$request = new CExecuteSelect($this);
|
||||
$success = $request->execute(array('query' => $query, $apiKey));
|
||||
|
||||
if($success) {
|
||||
if(count($request->getResult()['rows']) === 0) {
|
||||
$success = false;
|
||||
} else {
|
||||
$row = $request->getResult()['rows'][0];
|
||||
$this->uid = $row['uid'];
|
||||
$this->username = $row['username'];
|
||||
|
||||
if(!is_null($row['langId'])) {
|
||||
$this->setLangauge(Language::newInstance($row['langId'], $row['langCode']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
17
core/Objects/lang/General.php
Normal file
17
core/Objects/lang/General.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
require_once './LanguageModule.php';
|
||||
|
||||
abstract class CLanguageModuleGeneral {
|
||||
|
||||
public static function getEntries($langCode) {
|
||||
switch($langCode) {
|
||||
case "de_DE":
|
||||
$this->entries[""] = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
9
core/Objects/lang/LanguageModule.php
Normal file
9
core/Objects/lang/LanguageModule.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
abstract class CLanguageModule {
|
||||
|
||||
public abstract static function getEntries($langCode);
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
229
core/View.class.php
Normal file
229
core/View.class.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
abstract class View {
|
||||
|
||||
private $document;
|
||||
private $loadView;
|
||||
protected $searchable;
|
||||
protected $reference;
|
||||
protected $title;
|
||||
protected $langModules;
|
||||
|
||||
public function __construct($document, $loadView = true) {
|
||||
$this->document = $document;
|
||||
$this->searchable = false;
|
||||
$this->printable = false;
|
||||
$this->reference = "";
|
||||
$this->title = "Untitled View";
|
||||
$this->langModules = array();
|
||||
$this->loadView = $loadView;
|
||||
}
|
||||
|
||||
public function getTitle() { return $this->title; }
|
||||
public function __toString() { return $this->getCode(); }
|
||||
public function getDocument() { return $this->document; }
|
||||
public function isSearchable() { return $this->searchable; }
|
||||
public function getReference() { return $this->reference; }
|
||||
|
||||
private function loadLanguageModules() {
|
||||
$lang = $this->document->getUser()->getLanguage();
|
||||
foreach($this->langModules as $langModule) {
|
||||
$lang->loadModule($langModule);
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual Methods
|
||||
public function loadView() { }
|
||||
|
||||
public function getCode() {
|
||||
|
||||
// Load translations
|
||||
$this->loadLanguageModules();
|
||||
|
||||
// Load Meta Data + Head (title, scripts, includes, ...)
|
||||
if($this->loadView) {
|
||||
$this->loadView();
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
// UI Functions
|
||||
|
||||
// TODO: do we need this in our general web-base?
|
||||
public function createFileIcon($mimeType) {
|
||||
$mimeType = htmlspecialchars($mimeType);
|
||||
return "<img src=\"/img/icons/admin/getIcon.php?mimeType=$mimeType\" class=\"file-icon\" alt=\"[$mimeType icon]\">";
|
||||
}
|
||||
|
||||
public function createParagraph($title, $id, $content) {
|
||||
$id = replaceCssSelector($id);
|
||||
$iconId = urlencode("$id-icon");
|
||||
return "
|
||||
<div class=\"row\">
|
||||
<div class=\"col-12\">
|
||||
<i class=\"fas fa-link\" style=\"display:none;position:absolute\" id=\"$iconId\"></i>
|
||||
<h2 id=\"$id\" data-target=\"$iconId\" class=\"inlineLink\">$title</h2>
|
||||
<div class=\"margin-bottom-xl\"><hr>$content</div>
|
||||
</div>
|
||||
</div>";
|
||||
}
|
||||
|
||||
public function createSimpleParagraph($content, $class="") {
|
||||
if($class) $class = " class=\"$class\"";
|
||||
return "<p$class>$content</p>";
|
||||
}
|
||||
|
||||
private function createList($items, $tag) {
|
||||
if(count($items) === 0)
|
||||
return "<$tag></$tag>";
|
||||
else
|
||||
return "<$tag><li>" . implode("</li><li>", $items) . "</li></$tag>";
|
||||
}
|
||||
|
||||
public function createOrderedList($items=array()) {
|
||||
return $this->createList($items, "ol");
|
||||
}
|
||||
|
||||
public function createUnorderedList($items=array()) {
|
||||
return $this->createList($items, "ul");
|
||||
}
|
||||
|
||||
public function createJumbotron($content, $lastModified=false) {
|
||||
$lastModified = ($lastModified ? "<span class=\"float-right text-xxs margin-top-xxxl\">Last modified: $lastModified</span>" : "");
|
||||
return "
|
||||
<div class=\"row\">
|
||||
<div class=\"col-12\">
|
||||
<div class=\"jumbotron\">
|
||||
$content
|
||||
$lastModified
|
||||
</div>
|
||||
</div>
|
||||
</div>";
|
||||
}
|
||||
|
||||
protected function createLink($link, $title=null) {
|
||||
if(is_null($title)) $title=$link;
|
||||
return "<a href=\"$link\">$title</a>";
|
||||
}
|
||||
|
||||
protected function createExternalLink($link, $title=null) {
|
||||
if(is_null($title)) $title=$link;
|
||||
return "<a href=\"$link\" target=\"_blank\" class=\"external\">$title</a>";
|
||||
}
|
||||
|
||||
protected function createCodeBlock($code, $lang="") {
|
||||
if($lang) $lang = " class=\"$lang\"";
|
||||
$html = "<pre><code$lang>";
|
||||
$html .= intendCode($code);
|
||||
$html .= "</code></pre>";
|
||||
return $html;
|
||||
}
|
||||
|
||||
protected function createIcon($icon, $margin = NULL) {
|
||||
$marginStr = (is_null($margin) ? "" : " margin-$margin");
|
||||
$iconClass = $this->getIconClass($icon);
|
||||
return "<i class=\"$iconClass$marginStr\"></i>";
|
||||
}
|
||||
|
||||
protected function getIconClass($icon) {
|
||||
|
||||
$mappings = array(
|
||||
"sign-out" => "sign-out-alt",
|
||||
"bank" => "university",
|
||||
"line-chart" => "chart-line",
|
||||
"circle-right" => "arrow-alt-circle-right",
|
||||
"refresh" => "sync"
|
||||
);
|
||||
|
||||
if(isset($mappings[$icon]))
|
||||
$icon = $mappings[$icon];
|
||||
|
||||
if($icon === "spinner")
|
||||
$icon .= " fa-spin";
|
||||
|
||||
return "fas fa-$icon";
|
||||
}
|
||||
|
||||
protected function createBootstrapTable($data) {
|
||||
$code = "<div class=\"container\">";
|
||||
foreach($data as $row) {
|
||||
$code .= "<div class=\"row margin-top-xs margin-bottom-xs\">";
|
||||
$columnCount = count($row);
|
||||
if($columnCount > 0) {
|
||||
$remainingSize = 12;
|
||||
$columnSize = 12 / $columnCount;
|
||||
foreach($row as $col) {
|
||||
$size = ($columnSize <= $remainingSize ? $columnSize : $remainingSize);
|
||||
$content = $col;
|
||||
$class = "";
|
||||
$code .= "<div";
|
||||
|
||||
if(is_array($col)) {
|
||||
foreach($col as $key => $val) {
|
||||
if(strcmp($key, "content") === 0) {
|
||||
$content = $val;
|
||||
} else if(strcmp($key, "class") === 0) {
|
||||
$class = " " . $col["class"];
|
||||
} else if(strcmp($key, "cols") === 0 && is_numeric($val)) {
|
||||
$size = intval($val);
|
||||
} else {
|
||||
$code .= " $key=\"$val\"";
|
||||
}
|
||||
}
|
||||
|
||||
$content = (isset($col["content"]) ? $col["content"] : "");
|
||||
if(isset($col["class"])) $class = " " . $col["class"];
|
||||
}
|
||||
|
||||
if($size <= 6) $class .= " col-md-" . intval($size * 2);
|
||||
$code .= " class=\"col-lg-$size$class\">$content</div>";
|
||||
$remainingSize -= $size;
|
||||
}
|
||||
}
|
||||
$code .= "</div>";
|
||||
}
|
||||
|
||||
$code .= "</div>";
|
||||
return $code;
|
||||
}
|
||||
|
||||
protected function createBash($command, $output="", $prefix="") {
|
||||
$command = htmlspecialchars($command);
|
||||
$output = htmlspecialchars($output);
|
||||
$output = str_replace("\n", "<br>", $output);
|
||||
return "<div class=\"bash\">
|
||||
<span>$prefix$</span>
|
||||
<span>$command</span><br>
|
||||
<span>$output</span>
|
||||
</div>";
|
||||
}
|
||||
|
||||
protected function createErrorText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("danger", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createWarningText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("warning", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createSuccessText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("success", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createSecondaryText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("secondary", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createInfoText($text, $id="", $hidden=false) {
|
||||
return $this->createStatusText("info", $text, $id, $hidden);
|
||||
}
|
||||
|
||||
protected function createStatusText($type, $text, $id="", $hidden=false) {
|
||||
if(strlen($id) > 0) $id = " id=\"$id\"";
|
||||
$hidden = ($hidden?" hidden" : "");
|
||||
return "<div class=\"alert alert-$type$hidden\" role=\"alert\"$id>$text</div>";
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
6
core/constants.php
Normal file
6
core/constants.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
const USER_GROUP_DEFAULT = 1;
|
||||
const USER_GROUP_ADMIN = 2;
|
||||
|
||||
?>
|
||||
137
core/core.php
Normal file
137
core/core.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
function clamp($val, $min, $max) {
|
||||
if($val < $min) return $min;
|
||||
if($val > $max) return $max;
|
||||
return $val;
|
||||
}
|
||||
|
||||
function downloadFile($url) {
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
$data = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $data;
|
||||
}
|
||||
|
||||
function getSubclassesOf($parent) {
|
||||
$result = array();
|
||||
foreach (get_declared_classes() as $class) {
|
||||
if (is_subclass_of($class, $parent))
|
||||
$result[] = $class;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
function includeDir($dir, $aIgnore = array(), $recursive = false) {
|
||||
$aIgnore[] = '.';
|
||||
$aIgnore[] = '..';
|
||||
$aFiles = array_diff(scandir($dir), $aIgnore);
|
||||
|
||||
foreach($aFiles as $file) {
|
||||
$file = $dir . '/' . $file;
|
||||
if(is_dir($file)) {
|
||||
if($recursive) {
|
||||
includeDir($file, $aIgnore, true);
|
||||
}
|
||||
} else {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateRandomString($length) {
|
||||
$randomString = '';
|
||||
if($length > 0) {
|
||||
$numCharacters = 26 + 26 + 10; // a-z + A-Z + 0-9
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$num = random_int(0, $numCharacters - 1);
|
||||
if($num < 26) $randomString .= chr(ord('a') + $num);
|
||||
else if($num - 26 < 26) $randomString .= chr(ord('A') + $num - 26);
|
||||
else $randomString .= chr(ord('0') + $num - 26 - 26);
|
||||
}
|
||||
}
|
||||
|
||||
return $randomString;
|
||||
}
|
||||
|
||||
function cleanPath($path) {
|
||||
if($path === '')
|
||||
return $path;
|
||||
|
||||
$path = str_replace('\\', '/', $path);
|
||||
$path = str_replace('/./', '/', $path);
|
||||
|
||||
if($path[0] !== '/')
|
||||
$path = '/' . $path;
|
||||
|
||||
$path = str_replace('/../', '/', $path);
|
||||
return $path;
|
||||
}
|
||||
|
||||
function startsWith($haystack, $needle) {
|
||||
$length = strlen($needle);
|
||||
return (substr($haystack, 0, $length) === $needle);
|
||||
}
|
||||
|
||||
function endsWith($haystack, $needle) {
|
||||
$length = strlen($needle);
|
||||
if ($length == 0)
|
||||
return true;
|
||||
|
||||
return (substr($haystack, -$length) === $needle);
|
||||
}
|
||||
|
||||
function isCalledDirectly($file) {
|
||||
return $_SERVER['SCRIPT_FILENAME'] === $file;
|
||||
}
|
||||
|
||||
function anonymzeEmail($mail) {
|
||||
if(($pos = strpos($mail, '@')) !== -1) {
|
||||
$name = substr($mail, 0, $pos);
|
||||
$host = substr($mail, $pos + 1);
|
||||
if(strlen($name) > 2) $mail = substr($name, 0, 2) . str_repeat('*', strlen($name) - 2) . "@$host";
|
||||
else $mail = $mail = str_repeat('*', strlen($name)) . "@$host";
|
||||
}
|
||||
|
||||
return $mail;
|
||||
}
|
||||
|
||||
function intendCode($code, $escape=true) {
|
||||
$newCode = "";
|
||||
$first = true;
|
||||
$brackets = array();
|
||||
$intend = 0;
|
||||
|
||||
foreach(explode("\n", $code) as $line) {
|
||||
if(!$first) $newCode .= "\n";
|
||||
if($escape) $line = htmlspecialchars($line);
|
||||
$line = trim($line);
|
||||
|
||||
if(count($brackets) > 0 && startsWith($line, current($brackets))) {
|
||||
$intend = max(0, $intend - 2);
|
||||
array_pop($brackets);
|
||||
}
|
||||
|
||||
$newCode .= str_repeat(" ", $intend);
|
||||
$newCode .= $line;
|
||||
$first = false;
|
||||
|
||||
if(endsWith($line, "{")) {
|
||||
$intend += 2;
|
||||
array_push($brackets, "}");
|
||||
} else if(endsWith($line, "(")) {
|
||||
$intend += 2;
|
||||
array_push($brackets, ")");
|
||||
}
|
||||
}
|
||||
|
||||
return $newCode;
|
||||
}
|
||||
|
||||
function replaceCssSelector($sel) {
|
||||
return preg_replace("~[.#<>]~", "_", preg_replace("~[:\-]~", "", $sel));
|
||||
}
|
||||
?>
|
||||
121
core/datetime.php
Normal file
121
core/datetime.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
function getFirstWeekDayOfMonth($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
$dt = new DateTime($d);
|
||||
$dt->modify('first day of this month');
|
||||
return intval($dt->format('N'));
|
||||
}
|
||||
|
||||
function getDayCount($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
$dt = new DateTime($d);
|
||||
$dt->modify('last day of this month');
|
||||
return intval($dt->format('j'));
|
||||
}
|
||||
|
||||
function prevMonth($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
$dt = new DateTime($d);
|
||||
$dt->modify('previous month');
|
||||
return $dt->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function prevDay($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
$dt = new DateTime($d);
|
||||
$dt->modify('previous day');
|
||||
return $dt->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function nextDay($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
$dt = new DateTime($d);
|
||||
$dt->modify('next day');
|
||||
return $dt->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function nextMonth($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
$dt = new DateTime($d);
|
||||
$dt->modify('next month');
|
||||
return $dt->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
function formatPeriod($d1, $d2) {
|
||||
$timeStr = dateFunction('d.m.Y H:i', $d1);
|
||||
if($timeStr == dateFunction('d.m.Y H:i', $d2)) {
|
||||
if(dateFunction('H:i', $d1) === '00:00') {
|
||||
return dateFunction('d.m.Y', $d1);
|
||||
}
|
||||
} else if(dateFunction('d.m.Y', $d1) !== dateFunction('d.m.Y', $d2)) {
|
||||
$timeStr .= " - " . dateFunction('d.m.Y H:i', $d2);
|
||||
} elseif(dateFunction('H:i', $d1) !== dateFunction('H:i', $d2)) {
|
||||
$timeStr .= " - " . dateFunction('H:i', $d2);
|
||||
}
|
||||
return $timeStr;
|
||||
}
|
||||
|
||||
function now() { return new DateTime(); }
|
||||
function getTime($d = NULL) { return dateFunction('H:i', $d); }
|
||||
function getHour($d = NULL){ return dateFunction('H', $d); }
|
||||
function getMinute($d = NULL){ return dateFunction('i', $d); }
|
||||
function getYear($d = NULL) { return intval(dateFunction('Y', $d)); }
|
||||
function getMonth($d = NULL) { return intval(dateFunction('n', $d)); }
|
||||
function getDay($d = NULL) { return intval(dateFunction('d', $d)); }
|
||||
function getDayOfWeek($d = NULL) { return intval(dateFunction('N', $d)); }
|
||||
function getDayNumberOfWeek($d = NULL) { return intval(dateFunction('N', $d)); }
|
||||
function getDateTime($d = NULL) { return dateFunction('Y-m-d H:i:s', $d); }
|
||||
function getFirstDay($d = NULL) { return dateFunction('Y-m-01', $d); }
|
||||
function getLastDay($d = NULL) { return dateFunction('t', $d); }
|
||||
function getPrevMonth($d = NULL) { return dateFunction("-1 month", $d); }
|
||||
function getLocalizedDateTime($d = NULL) { return dateFunction(L('Y/m/d H:i'), $d); }
|
||||
|
||||
function getJavascriptDate($d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
if(!is_a($d, "DateTime")) $d = new DateTime($d);
|
||||
$year = getYear($d);
|
||||
$month = getMonth($d) - 1;
|
||||
$day = getDay($d);
|
||||
$hour = getHour($d);
|
||||
$minute = getMinute($d);
|
||||
|
||||
return "new Date($year, $month, $day, $hour, $minute)";
|
||||
}
|
||||
|
||||
function getWeekDayName($day) {
|
||||
$aWeekDays = array('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday');
|
||||
return L($aWeekDays[$day - 1]);
|
||||
}
|
||||
|
||||
function getMonthName($month) {
|
||||
$aMonthNames = array("January", "February", "March", "April", "May", "Juni", "July", "August", "September", "October", "November", "December");
|
||||
return L($aMonthNames[$month - 1]);
|
||||
}
|
||||
|
||||
function isInPast($d) {
|
||||
$now = date('Y-m-d H:i:s');
|
||||
if(is_a($d, "DateTime")) $d = $d->format('Y-m-d H:i:s');
|
||||
return (strtotime($d) < strtotime($now));
|
||||
}
|
||||
|
||||
function datetimeDiff($d1, $d2) {
|
||||
if(!($d1 instanceof DateTime)) $d1 = new DateTime($d1);
|
||||
if(!($d2 instanceof DateTime)) $d2 = new DateTime($d2);
|
||||
return $d2->getTimestamp() - $d1->getTimestamp();
|
||||
}
|
||||
|
||||
function durationIn($d1, $d2, $str) {
|
||||
if(!($d1 instanceof DateTime)) $d1 = new DateTime($d1);
|
||||
if(!($d2 instanceof DateTime)) $d2 = new DateTime($d2);
|
||||
$interval = $d1->diff($d2);
|
||||
return intval($interval->format($str));
|
||||
}
|
||||
|
||||
function dateFunction($str, $d = NULL) {
|
||||
if(is_null($d)) $d = date('Y-m-d H:i:s');
|
||||
if(!is_a($d, "DateTime")) $d = new DateTime($d);
|
||||
return $d->format($str);
|
||||
}
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user