1
0
mirror of https://github.com/devcode-it/openstamanager.git synced 2024-12-22 13:26:38 +01:00

Miglioramento della struttura delle classi

This commit is contained in:
Thomas Zilio 2017-09-04 16:04:45 +02:00
parent 90e7a23852
commit a688230c0d
6 changed files with 111 additions and 93 deletions

View File

@ -90,7 +90,7 @@ In particolare, ogni modulo può specificare una determinata serie di operazioni
Di seguito lo schema attraverso cui l'API individua la presenza delle possibili richieste supportate dai moduli (cartelle **api/** e **custom/api/**):
- `POST` - File `create.php`.
- `GET` - File `eetrieve.php`.
- `GET` - File `retrieve.php`.
- `PUT` - File `update.php`.
- `DELETE` - File `delete.php`.

View File

@ -43,9 +43,7 @@ class API extends \Util\Singleton
*/
public function __construct()
{
$user = Auth::user();
if (!self::isAPIRequest() || (empty($user) && self::getRequest()['resource'] != 'login')) {
if (!self::isAPIRequest() || (!Auth::check() && self::getRequest()['resource'] != 'login')) {
throw new InvalidArgumentException();
}
}
@ -62,81 +60,70 @@ class API extends \Util\Singleton
$user = Auth::user();
$table = '';
$select = '*';
// Selezione personalizzata
$display = $request['display'];
$select = !empty($display) ? explode(',', substr($display, 1, -1)) : $select;
$where = [];
$order = [];
// Selezione personalizzata
$select = !empty($request['display']) ? explode(',', substr($request['display'], 1, -1)) : $select;
// Ricerca personalizzata
$filter = (array) $request['filter'];
foreach ($filter as $key => $value) {
foreach ((array) $request['filter'] as $key => $value) {
// Rimozione delle parentesi
$value = substr($value, 1, -1);
$result = [];
if (str_contains($value, ',')) {
$or = [];
$temp = explode(',', $value);
foreach ($temp as $value) {
$or[] = [$key => $value];
}
$result[] = ['OR' => $or];
} else {
$result[$key] = $value;
}
$where[] = $result;
// Individuazione della tipologia (array o string)
$where[$key] = str_contains($value, ',') ? explode(',', $value) : $value;
}
$order = [];
// Ordinamento personalizzato
$order_request = (array) $request['order'];
foreach ($order_request as $value) {
foreach ((array) $request['order'] as $value) {
$pieces = explode('|', $value);
$order[] = empty($pieces[1]) ? $pieces[0] : [$pieces[0] => $pieces[1]];
}
// Date di interesse
$updated = $request['upd'];
$created = $request['crd'];
// Paginazione dell'API
// Paginazione automatica dell'API
$page = (int) $request['page'] ?: 0;
$length = Settings::get('Lunghezza pagine per API');
$database = Database::getConnection();
$dbo = $database;
$kind = 'retrieve';
$resources = self::getResources()[$kind];
$resource = $request['resource'];
if (!in_array($resource, array_keys($resources))) {
$excluded = explode(',', Settings::get('Tabelle escluse per la sincronizzazione API automatica'));
if (!in_array($resource, $excluded)) {
$table = $resource;
if (in_array($resource, array_keys($resources))) {
$dbo = $database;
if (empty($order)) {
$order[] = $dbo->fetchArray('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '.prepare($table)." AND EXTRA LIKE '%AUTO_INCREMENT%' AND TABLE_SCHEMA = ".prepare($dbo->getDatabaseName()))[0]['COLUMN_NAME'];
}
}
} else {
// Esecuzione delle operazioni personalizzate
$filename = DOCROOT.'/modules/'.$resources[$resource].'/api/'.$kind.'.php';
include $filename;
} elseif (!in_array($resource, explode(',', Settings::get('Tabelle escluse per la sincronizzazione API automatica')))) {
$table = $resource;
// Individuazione della colonna AUTO_INCREMENT per l'ordinamento automatico
if (empty($order)) {
$order[] = $database->fetchArray('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '.prepare($table)." AND EXTRA LIKE '%AUTO_INCREMENT%' AND TABLE_SCHEMA = ".prepare($database->getDatabaseName()))[0]['COLUMN_NAME'];
}
}
// Generazione automatica delle query
if (empty($results) && !empty($table)) {
try {
// Date di interesse
if (!empty($request['upd'])) {
$where['#updated_at'] = 'updated_at >= '.prepare($request['upd']);
}
if (!empty($request['crd'])) {
$where['#created_at'] = 'created_at >= '.prepare($request['crd']);
}
// Query per ottenere le informazioni
$results = $dbo->select($table, $select, $where, $order, [$page * $length, $length]);
$results = $database->select($table, $select, $where, $order, [$page * $length, $length]);
// Informazioni aggiuntive
$query = $dbo->select($table, $select, $where, $order, [], true);
$cont = $dbo->fetchArray('SELECT COUNT(*) as `records`, CEIL(COUNT(*) / '.$length.') as `pages` FROM ('.$query.') AS `count`');
$query = $database->select($table, $select, $where, $order, [], true);
$cont = $database->fetchArray('SELECT COUNT(*) as `records`, CEIL(COUNT(*) / '.$length.') as `pages` FROM ('.$query.') AS `count`');
if (!empty($cont)) {
$results['records'] = $cont[0]['records'];
$results['pages'] = $cont[0]['pages'];
@ -207,12 +194,13 @@ class API extends \Util\Singleton
$database = Database::getConnection();
$dbo = $database;
$dbo->query('START TRANSACTION');
$database->query('START TRANSACTION');
// Esecuzione delle operazioni
$filename = DOCROOT.'/modules/'.$resources[$resource].'/api/'.$kind.'.php';
include $filename;
$dbo->query('COMMIT');
$database->query('COMMIT');
return self::response($results);
}
@ -249,29 +237,32 @@ class API extends \Util\Singleton
$resources = [];
$operations = glob(DOCROOT.'/modules/*/api/{retrieve,create,update,delete}.php', GLOB_BRACE);
if (!empty($operations)) {
foreach ($operations as $operation) {
$module = basename(dirname(dirname($operation)));
$kind = basename($operation, '.php');
foreach ($operations as $operation) {
// Individua la tipologia e il modulo delle operazioni
$module = basename(dirname(dirname($operation)));
$kind = basename($operation, '.php');
$resources[$kind] = (array) $resources[$kind];
$resources[$kind] = (array) $resources[$kind];
$temp = str_replace('/api/', '/custom/api/', $operation);
$operation = file_exists($temp) ? $temp : $operation;
// Controllo sulla presenza di eventuali personalizzazioni
$temp = str_replace('/api/', '/custom/api/', $operation);
$operation = file_exists($temp) ? $temp : $operation;
$api = include $operation;
$api = is_array($api) ? array_unique($api) : [];
// Individuazione delle operazioni
$api = include $operation;
$api = is_array($api) ? array_unique($api) : [];
$keys = array_keys($resources[$kind]);
$keys = array_keys($resources[$kind]);
$results = [];
foreach ($api as $value) {
$value .= in_array($value, $keys) ? $module : '';
$results[$value] = $module;
}
$resources[$kind] = array_merge($resources[$kind], $results);
// Registrazione delle operazioni individuate
$results = [];
foreach ($api as $value) {
$value .= in_array($value, $keys) ? $module : '';
$results[$value] = $module;
}
// Salvataggio delle operazioni
$resources[$kind] = array_merge($resources[$kind], $results);
}
self::$resources = $resources;
@ -289,16 +280,19 @@ class API extends \Util\Singleton
*/
public static function response($array)
{
// Controllo sulla compatibilità dell'API
if (!self::isCompatible()) {
$array = [
'status' => self::$status['incompatible']['code'],
];
}
// Agiunta dello status di default
if (empty($array['status'])) {
$array['status'] = self::$status['ok']['code'];
}
// Aggiunta del messaggio in base allo status
if (empty($array['message'])) {
$codes = array_column(self::$status, 'code');
$messages = array_column(self::$status, 'message');
@ -307,6 +301,7 @@ class API extends \Util\Singleton
}
$flags = JSON_FORCE_OBJECT;
// Beautify forzato dei risultati
if (get('beautify') !== null) {
$flags |= JSON_PRETTY_PRINT;
}
@ -339,10 +334,15 @@ class API extends \Util\Singleton
*/
public static function getRequest()
{
$request = (array) json_decode(file_get_contents('php://input'), true);
$request = [];
if ($_SERVER['REQUEST_METHOD'] == 'GET' && empty($request)) {
$request = Filter::getGET();
if (self::isAPIRequest()) {
$request = (array) json_decode(file_get_contents('php://input'), true);
// Fallback nel caso la richiesta sia effettuata da browser
if ($_SERVER['REQUEST_METHOD'] == 'GET' && empty($request)) {
$request = Filter::getGET();
}
}
return $request;

View File

@ -51,6 +51,7 @@ class Auth extends \Util\Singleton
$database = Database::getConnection();
if ($database->isInstalled()) {
// Controllo dell'accesso da API
if (API::isAPIRequest()) {
$token = API::getRequest()['token'];
@ -81,6 +82,7 @@ class Auth extends \Util\Singleton
{
session_regenerate_id();
// Controllo sulla disponibilità dell'accesso (brute-forcing non in corso)
if (self::isBrute()) {
return false;
}
@ -105,15 +107,18 @@ class Auth extends \Util\Singleton
$this->password_check($password, $user['password'], $user['id_utente']) &&
!empty($module)
) {
// Accesso completato
$log['id_utente'] = $this->infos['id_utente'];
$log['stato'] = self::$status['success']['code'];
// Salvataggio nella sessione
$this->saveToSession();
} else {
if (empty($module)) {
$log['stato'] = self::$status['unauthorized']['code'];
}
// Logout automatico
$this->destory();
}
} else {
@ -121,6 +126,7 @@ class Auth extends \Util\Singleton
}
}
// Salvataggio dello stato nella sessione
if ($log['stato'] != self::$status['success']['code']) {
foreach (self::$status as $key => $value) {
if ($log['stato'] == $value['code']) {
@ -130,6 +136,7 @@ class Auth extends \Util\Singleton
}
}
// Salvataggio del tentativo nel database
$database->insert('zz_logs', $log);
return $this->isAuthenticated();

View File

@ -472,7 +472,7 @@ class Database extends Util\Singleton
{
if (
!is_string($table) ||
(!empty($order) && !is_string($order) && !is_array($limit)) ||
(!empty($order) && !is_string($order) && !is_array($order)) ||
(!empty($limit) && !is_string($limit) && !is_array($limit))
) {
throw new UnexpectedValueException();
@ -541,7 +541,7 @@ class Database extends Util\Singleton
$sync = array_unique((array) current($list));
if (!empty($field)) {
$results = array_column($this->fetchArray('SELECT '.$this->quote($field).' FROM '.$this->quote($table).' WHERE '.$this->whereStatement($conditions)), $field);
$results = array_column($this->select($table, $field, $conditions), $field);
$detachs = array_unique(array_diff($results, $sync));
$this->detach($table, $conditions, [$field => $detachs]);
@ -573,7 +573,7 @@ class Database extends Util\Singleton
$sync = array_unique((array) current($list));
if (!empty($field)) {
$results = array_column($this->fetchArray('SELECT '.$this->quote($field).' FROM '.$this->quote($table).' WHERE '.$this->whereStatement($conditions)), $field);
$results = array_column($this->select($table, $field, $conditions), $field);
$inserts = array_unique(array_diff($sync, $results));
foreach ($inserts as $insert) {
@ -605,14 +605,9 @@ class Database extends Util\Singleton
$sync = array_unique((array) current($list));
if (!empty($field) && !empty($sync)) {
$where = $this->whereStatement($conditions);
$conditions[$field] = $sync;
$in = [];
foreach ($sync as $value) {
$in[] = $this->prepare($value);
}
$this->query('DELETE FROM '.$this->quote($table).' WHERE '.$where.(!empty($where) ? ' AND ' : '').$this->quote($field).' IN ('.implode(', ', $in).')');
$this->query('DELETE FROM '.$this->quote($table).' WHERE '.$this->whereStatement($conditions));
}
}
@ -653,26 +648,40 @@ class Database extends Util\Singleton
{
$result = [];
if (is_array($where)) {
foreach ($where as $key => $value) {
if (is_array($value)) {
$key = strtoupper($key);
$key = (in_array($key, ['AND', 'OR'])) ? $key : 'AND';
foreach ($where as $key => $value) {
// Query personalizzata
if (starts_with($key, '#')) {
$result[] = $this->prepareValue($key, $value);
} else {
// Ulteriori livelli di complessità
if (is_array($value) && in_array(strtoupper($key), ['AND', 'OR'])) {
$result[] = '('.$this->whereStatement($value, $key == 'AND').')';
} elseif (starts_with($value, '#') && ends_with($value, '#')) {
$result[] = substr($value, 1, -1);
} elseif (starts_with($value, '%') || ends_with($value, '%')) {
}
// Condizione IN
elseif (is_array($value)) {
if (!empty($value)) {
$in = [];
foreach ($value as $v) {
$in[] = $this->prepareValue($key, $v);
}
$result[] = $this->quote($key).' IN ('.implode(',', $in).')';
}
}
// Condizione LIKE
elseif (str_contains($value, '%') || str_contains($value, '_')) {
$result[] = $this->quote($key).' LIKE '.$this->prepareValue($key, $value);
} elseif (str_contains($value, '|')) {
}
// Condizione BETWEEN
elseif (str_contains($value, '|')) {
$pieces = explode('|', $value);
$result[] = $this->quote($key).' BETWEEN '.$this->prepareValue($key, $pieces[0]).' AND '.$this->prepareValue($key, $pieces[1]);
} else {
}
// Condizione di uguaglianza
else {
$result[] = $this->quote($key).' = '.$this->prepareValue($key, $value);
}
}
} else {
$result[] = $where;
}
$cond = !empty($and) ? 'AND' : 'OR';

View File

@ -10,6 +10,7 @@ switch ($resource) {
$tokens = $database->fetchArray('SELECT `token` FROM `zz_tokens` WHERE `enabled` = 1 AND `id_utente` = '.prepare($user['id_utente']));
if (empty($tokens)) {
$token = secure_random_string();
$database->insert('zz_tokens', [
'id_utente' => $user['id_utente'],
'token' => $token,
@ -38,6 +39,7 @@ switch ($resource) {
// Operazione di logout
case 'logout':
if (!empty($request['token']) && !empty($user)) {
// Cancellazione della chiave
$database->query('DELETE FROM `zz_tokens` WHERE `token` = '.prepare($request['token']).' AND `id_utente` = '.prepare($user['id_utente']));
} else {
$results = [

View File

@ -680,7 +680,7 @@ ALTER TABLE `zz_semaphores` ADD FOREIGN KEY (`id_utente`) REFERENCES `zz_users`(
CREATE TABLE IF NOT EXISTS `zz_tokens` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_utente` int(11) NOT NULL,
`token` varchar(255) NOT NULL UNIQUE,
`token` varchar(255) NOT NULL,
`descrizione` varchar(255),
`enabled` boolean NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),