Commit iniziale (r1662)

Migrazione da SourceForge, partendo dal commit 1662 della carrtella trunk/openstamanager.
This commit is contained in:
Thomas Zilio 2017-08-04 16:28:16 +02:00
parent 662fcbd7b9
commit 1c9e7b1634
383 changed files with 55144 additions and 0 deletions

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
# editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

87
.gitignore vendored Normal file
View File

@ -0,0 +1,87 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
*.pyo
*.pyc
# Packages #
############
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip
# Logs and databases #
######################
*.log
*.sql
*.sqlite
# OS generated files #
######################
*~
._*
.cache
.DS_Store
.DS_Store?
.idea
.project
.settings
.tmproj
*.esproj
*.sublime-project
*.sublime-workspace
nbproject
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
$RECYCLE.BIN
desktop.ini
Desktop.ini
.Spotlight-V100
.Trashes
.fuse_hidden*
.directory
.Trash-*
.nfs*
*.cab
*.msi
*.msm
*.msp
*.lnk
# Visual Studio Code #
######################
.vscode/*
# Npm and Yarn, Bower, Composer #
######################
bower_components/
node_modules/
vendor/
# Project #
######################
*.phar
*.lock
*.new
*.old
assets/dist
backup/*
!backup/.htaccess
files/*
!files/.htaccess
!files/my_impianti/
files/my_impianti/*
!files/my_impianti/componente.ini
config.inc.php
REVISION

88
.htaccess Normal file
View File

@ -0,0 +1,88 @@
# Remove autoindex
IndexIgnore *
## Options -Indexes
# Try to set PHP settings
php_value upload_max_filesize 20M
php_value post_max_size 20M
# Deny access to files starting with dot
<FilesMatch "^\.">
Order allow,deny
Deny from all
</FilesMatch>
# Deny access to log, sql, htaccess ecc..
<FilesMatch "\.(ini|psd|log|sh|sql|md|lock|phar)$">
Order allow,deny
Deny from all
</FilesMatch>
# Deny access to VERSION, REVISION and config file
<Files ~ "(VERSION$|REVISION$|LICENSE|(config.inc|config.example).php|(composer|package).json|gulpfile.js)">
Order allow,deny
Deny from all
</Files>
# Disable OSM indexing of php, html, htm, pdf files
<IfModule mod_headers.c>
<FilesMatch "\.(php|html|htm|pdf|log)$">
Header set X-Robots-Tag: "noindex"
</FilesMatch>
</IfModule>
<IfModule mod_rewrite.c>
RewriteEngine On
# Tell PHP that the mod_rewrite module is ENABLED.
SetEnv HTTP_MOD_REWRITE On
# Deny access to protected folders
RewriteRule ^backup/?$ - [F,L]
RewriteRule ^docs/?$ - [F,L]
RewriteRule ^include/?$ - [F,L]
RewriteRule ^locale/?$ - [F,L]
RewriteRule ^logs/?$ - [F,L]
RewriteRule ^update/?$ - [F,L]
# Deny access to svn, node_modules and vendor folders
RewriteRule ^.svn/?$ - [F,L]
RewriteRule ^node_modules/?$ - [F,L]
RewriteRule ^vendor/?$ - [F,L]
# Prevent hacks
# proc/self/environ? no way!
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
# Block out any script trying to set a mosConfig value through the URL
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
# Block out any script trying to base64_encode crap to send via URL
RewriteCond %{QUERY_STRING} base64_encode.*(.*) [OR]
# Block out any script that includes a <script> tag in URL
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
# Block out any script trying to set a PHP GLOBALS variable via URL
RewriteCond %{QUERY_STRING} GLOBALS(=|[|\%[0-9A-Z]{0,2}) [OR]
# Block out any script trying to modify a _REQUEST variable via URL
RewriteCond %{QUERY_STRING} _REQUEST(=|[|\%[0-9A-Z]{0,2})
# Block visitors referred from indicated domains
SetEnvIfNoCase ^User-Agent$ .*(craftbot|download|extract|stripper|sucker|ninja|clshttp|webspider|leacher|collector|grabber|webpictures) HTTP_SAFE_BADBOT
SetEnvIfNoCase ^User-Agent$ .*(libwww-perl|aesop_com_spiderman) HTTP_SAFE_BADBOT
Deny from env=HTTP_SAFE_BADBOT
</ifModule>
# Compress text, html, javascript, css, ecc...
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>

202
CHANGELOG.md Normal file
View File

@ -0,0 +1,202 @@
# Changelog
Tutti i maggiori cambiamenti di questo progetto saranno documentati in questo file. Per informazioni più dettagliate, consultare il log SVN della repository su SourceForge.
Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://keepachangelog.com/), e il progetto segue il [Semantic Versioning](http://semver.org/) per definire le versioni delle release.
## Tabella dei contenuti
<!-- TOC depthFrom:2 depthTo:2 orderedList:false updateOnSave:true withLinks:true -->
- [Tabella dei contenuti](#tabella-dei-contenuti)
- [2.3 (In sviluppo)](#23-in-sviluppo)
- [2.2 (2016-11-10)](#22-2016-11-10)
- [2.1 (2015-04-02)](#21-2015-04-02)
<!-- /TOC -->
## 2.3 (In sviluppo)
### Aggiunto (Added)
- Creazione della documentazione ufficiale per sviluppatori (disponibile nel Wiki e in `docs/`)
- Creazione di un sistema API ufficiale
- Creazione di un sistema per controllare gli accessi degli utenti
- Nuovi moduli _Viste_, _Utenti e permessi_, _Opzioni_, con ulteriori moduli per la gestione di tabelle secondarie (_IVA_, _Pagamenti_, ...)
- Nuova struttura per permettere il richiamo via AJAX delle procedure per la creazione di nuovi elementi all'esterno del modulo specifico (tramite il file `add.php`)
- Possibilità di vedere se ci sono altri utenti che stanno visualizzando lo stesso record (opzione "Sessione avanzata" nel modulo _Opzioni_)
- Nuove funzioni PHP (con commenti) in `lib/functions.php`
- getRevision
- str\_replace\_once
- filter
- post
- get
- readSQLFile
- array\_pluck
- starts_with
- ends_with
- slashes
- prepare
- tr (con aggiunta della funzione di gettext nel caso questi non sia abilitato - `_`)
- safe\_truncate (in sostituzione a cut\_text)
- secure\_random\_string
- random\_string
- safe\_truncate
- force\_download
- isHTTPS
- Nuovi oggetti per la gestione delle operazioni di base (posizionati in `lib/classes/`)
- Auth
- Database
- Filter (in sostituzione a HTMLHelper, ora deprecato ma ancora presente)
- HTMLBuilder
- Modules
- Options
- Permissions
- Translator (per la futura internazionalizzazione e traduzione del progetto, inoltre disponibile in `locale/it/`)
- Update
- Widgtes (modificati per lavorare secondo una metodologia statica)
- Nuova gestione delle operazioni di debugging e logging
- Nuovo file `lib/init.js` per permettere una rapida inizializzazione dei componenti JS
- Creazione di cartelle di default per i backup (`backup/`) e i log (`logs/`)
- Nuovo pulsante per resettare i filtri di ricerca (nella sezione generica dei moduli)
- Nuovo modulo per gestire i file `.ini` dei componenti degli impianti
- Nuovi plugins e widgets
- Nuova gestione generalizzata degli upload
- Nuove funzioni relative ai diversi moduli
- Possibilità di inserire in fattura un range di serial number
- Possibilità di individuare i componenti dell'impianto su cui l'intervento viene effettuato
- Possibilità di gestire le ritenute d'acconto
- Firma degli interventi
- Selezione della tipologia di attività per ogni sessione di lavoro
- Tabella riepilogativa più completa dei costi
- Sconto incondizionato in _Interventi_
### Modificato (Changed)
- Gestione delle librerie e dipendenze PHP tramite _Composer_
- Gestione degli assets tramite Yarn e Gulp
- Miglioramenti grafici
- Miglioramento della procedura di installazione
- Miglioramenti delle informazioni disponibili sul progetto e della procedura di segnalazione dei bug
- Impianti ora identificati tramite numerazione univoca (non più tramite matricola)
- Sostituzione di Chosen con Select2
- Miglioramento dell'interpretazione del template per la generazione degli input (`lib/htmlbuilder.php`), ora inoltre disponibile ovunque all'interno del progetto
- Miglioramento generale sull'identificazione del modulo attualmente in uso e sull'inclusione dei file necessari per il funzionamento
- Miglioramento della gestione dei permessi
- Gestione della connessione al database tramite Medoo (possibile futuro ampliamento dei DMBS supportati)
- Gestione delle tabelle ora completamente basata su Datatables
- Ottimizzazione della schermata per aggiunta dell'intervento
- Miglioramento dei riquadri delle spese aggiuntive e degli articoli
- La prima anagrafica di tipo Azienda caricata viene impostata come Azienda predefinita
- Passaggio completo all'estensione `.php` per tutti i file dei moduli
- Miglioramento dei permessi di visione per il modulo _MyImpianti_, per cui ora ogni cliente vede solo i propri impianti
- Miglioramento della procedura di aggiornamento del gestionale
- Aggiunto sistema di ripresa dell'aggiornamento (se questi è stato bloccato in una fase intermedia tra i singoli aggiornamenti)
- Aggiunto sistema di bloccaggio dell'aggiornamento, per evitare problemi nel caso molteplici richieste di update
- Semplificazione della procedura manuale, che ora non richiede nessuna modifica dei file VERSION da parte dell'utente (la versione dell'aggiornamento viene memorizzata nel file VERSION.new)
- Modificata la struttura della tabella `updates`
### Deprecato (Deprecated)
- Classe HTMLHelper, a favore della nuova classe Filter
- Funzioni PHP
- readDateTime
- readDateTimePrint
- get\_permessi
- saveDateTime
- saveDate
- fix\_str
- clean
- makeid
- read
- readTime
- readDate
- build\_html\_element
### Rimosso (Removed)
- Funzioni PHP non utilizzate (`lib/functions.php`)
- is\_id\_ok
- write\_error
- write\_ok
- getAvailableModules
- read\_file
- dateadd
- show\_info\_messages
- show\_error\_messages
- get\_module\_name
- mytruncate
- get\_user\_browser
- RemoveNonASCIICharacters
- full\_html\_entity\_decode
- data\_italiana
- gestione\_sessioni
- get\_text\_around
- coolDate
- get\_module\_name\_by\_id
- cut\_text
- getLastPathSegment
- cut\_text
- Funzioni JS non utilizzate (`lib/functionsjs.php`)
- Cartelle non più utilizzate (`lib/jscripts/`, `lib/html2pdf/`, `widgets`, `share`, ...)
- File non più utilizzati (`lib/dbo.class.php`, `lib/widgets.class.php`, ...)
### Fixed
- Risoluzione di numerosi bug e malfunzionamenti
### Sicurezza (Security)
- Aggiunta protezione contro l'XSS
- Aggiunta base per contrastare l'SQL Injection
- Passaggio della codifica della password con algoritmo di hashing BCrypt
## 2.2 (2016-11-10)
### Aggiunto (Added)
- Aggiunto ordinamento righe in fattura e stampa con ordine impostato
- Creazione automatica del conto cliente e fornitore nel piano dei conti
- Aggiunte stampe dei mastrini nel piano dei conti
- Aumentata performance caricamento record sulle viste principali dei moduli
- Aggiunta funzionalità di rinnovo contratto con collegamento a contratti precedenti
- Migliorata gestione dei backup (1 backup al giorno)
- Aggiunta tipologia di attività di default nel cliente per pre-caricarla durante la creazione attività
- Aggiunta funzionalità di firma rapportino e stampa del rapportino con firma inserita
- Modifica raggruppamento voci di menu, principalmente "Vendite" e "Acquisti"
- Aggiunta funzionalità di duplicazione fattura
- Migliorata la procedura di installazione
- Aggiunta richiesta di salvataggio prima di uscire da una schermata
- Aggiunta possibilità di collegare più agenti ad un cliente, e specificarne uno principale
- Aggiunta schermata di visualizzazione accessi
- Aggiunte rivalsa inps e ritenuta d'acconto nelle singole righe in fattura
- Aggiunti widget "Valore magazzino" e "Articoli in magazzino"
- Aggiunta stampa viste principali da browser con buona grafica minimale
- Aggiunta gestione componenti
- Aggiunta possibilità di generare lotti e serial number dalla fattura e ddt di acquisto
- Aggiunta possibilità di impostare dei costi unitari per ogni tipo di attività collegata al contratto, per utilizzare prezzi concordati nel contratto durante le attività
### Fixed
- Bugfix vari sui permessi
- Bugfix minori
## 2.1 (2015-04-02)
### Aggiunto (Added)
- Aggiunto stato “Parzialmente pagato” sulle fatture
- Aggiunta stampa scadenzario
- Aggiunta possibilità di includere più ddt in fattura
- Aggiunto blocco sulla modifica campi di testo per gli utenti in sola lettura
- Aggiunta scelta rivalsa inps e ritenuta dacconto per ogni riga della fattura
### Modificato (Changed)
- Allargate le cifre decimali a 4 sugli importi
### Fixed
- Alcune migliorie su vari moduli
- Aumentata performance schermate

133
README.md Normal file
View File

@ -0,0 +1,133 @@
# OpenSTAManager
OpenSTAManager ("Gestore Aperto del Servizio Tecnico di Assistenza") è un software open source, web based, modulare e semplice da usare, ideato e sviluppato da Fabio Lovato per gestire ed archiviare il servizio di assistenza tecnica e la fatturazione.
Funzioni principali:
- dashboard con Interventi e Appuntamenti;
- gestione Anagrafiche;
- gestione Contabilità;
- gestione Contratti;
- gestione Magazzino;
- gestione Impianti.
## Tabella dei contenuti
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Tabella dei contenuti](#tabella-dei-contenuti)
- [Requisiti](#requisiti)
- [Installazione](#installazione)
- [Versioni](#versioni)
- [SourceForge](#sourceforge)
- [Perché software open source](#perché-software-open-source)
- [Componenti esterni](#componenti-esterni)
- [Community](#community)
- [Contribuire](#contribuire)
- [Sviluppatori](#sviluppatori)
- [Licenza](#licenza)
<!-- /TOC -->
## Requisiti
Prima di iniziare l'installazione, è necessario procedere al download di una versione del progetto da [SourceForge](https://sourceforge.net/p/openstamanager/). Si consiglia inoltre di controllare che i prerequisiti del software, elencati di seguito, siano soddisfatti.
L'installazione del gestionale richiede la presenza di un server web con abilitato il [DBMS (Database Management System)](https://it.wikipedia.org/wiki/Database_management_system) MySQL e il linguaggio di programmazione [PHP](http://php.net/).
- PHP >= 5.4 (si consiglia come minimo la versione 5.6 per poter usufruire di tutte le funzionalità del progetto)
- MySQL >= 5.0
Per ulteriori informazioni sui pacchetti che forniscono questi elementi di default, visitare la sezione [Informazioni](https://sourceforge.net/p/openstamanager/wiki/Installazione/) della documentazione.
## Installazione
Per procedere all'installazione è necessario seguire i seguenti punti:
1. Creare una cartella (ad esempio `openstamanager`) nella root del sever web installato ed estrarvi il contenuto della release scaricata. Il percorso della cartella root del server varia in base al software in utilizzo:
- LAMP (`/var/www/html`);
- XAMPP (`C:/xampp/htdocs` per Windows, `/opt/lampp/htdocs/` per Linux, `/Applications/XAMPP/htdocs/` per MAC);
- WAMP (`C:\wamp\www`);
- MAMP (`C:\MAMP\htdocs` per Windows, `/Applications/MAMP/htdocs` per MAC).
2. Creare un database vuoto (tramite [PHPMyAdmin](http://localhost/phpmyadmin/) o riga di comando).
3. Accedere a <http://localhost/openstamanager> dal vostro browser.
4. Inserire i dati per collegarsi al database e cliccare su **Installa** per completare l'installazione.
**Attenzione**: è possibile che l'installazione richieda del tempo. Si consiglia pertanto di attendere almeno qualche minuto senza alcun cambiamento nella pagina di installazione (in particolare, della progress bar presente) prima di cercare una possibile soluzione nelle discussioni del forum o nella sezione dedicata.
### Versioni
Per mantenere un elevato grado di trasparenza riguardo al ciclo delle release, seguiamo le linee guida [Semantic Versioning (SemVer)](http://semver.org/) per definire le versioni del progetto. Per vedere tutte le versioni disponibili al download, visitare la [pagina relativa](https://sourceforge.net/projects/openstamanager/files/) su SourceForge.
### SourceForge
Nel caso si stia utilizzando la versione direttamente ottenuta dalla repository di SourceForge, è necessario eseguire i seguenti comandi da linea di comando per completare le dipendenze PHP (tramite [Composer](https://getcomposer.org/)) e gli asssets (tramite [Yarn](https://yarnpkg.com/)) del progetto.
```bash
php composer.phar install
php composer.phar update
yarn global add gulp
yarn install
gulp
```
In alternativa alla sequenza di comandi precedente, è possibile utilizzare il seguente comando (richiede l'installazione di GIT e Yarn, oltre che l'inserimento dell'archivio `composer.phar` nella cartella principale del progetto):
```bash
yarn run develop-OSM
```
Per ulteriori informazioni, visitare le sezioni [Assets](https://sourceforge.net/p/openstamanager/wiki/Assets/) e [Framework](https://sourceforge.net/p/openstamanager/wiki/Framework/) della documentazione.
## Perché software open source
Il progetto è un software open source perché permette agli utilizzatori di studiarne il funzionamento ed adattarlo alle proprie esigenze; inoltre, in ambito commerciale, non obbliga l'utilizzatore ad essere legato allo stesso fornitore di assistenza.
In questo modo è possibile ottenere un'ulteriore garanzia sul funzionamento del software, poiché chiunque ne abbia le capacità può verificarlo, escludendo mancanze in relazione alla sicurezza e alla privacy dei dati (caratteristica che il software proprietario non può offrire).
Nel caso utilizziate il programma per uso commerciale, si consiglia di non utilizzare le versioni ottenibili direttamente dalla repository su SourceForge (SVN) ma di scaricare le release ufficiali disponibili nel nostro sito ufficiale <http://www.openstamanager.com>; se siete inoltre interessati a supporto e assistenza professionali, li potete richiedere nella [sezione dedicata](http://www.openstamanager.com/per-le-aziende/).
## Componenti esterni
OpenSTAManager è stato progettato utilizzando altro software open source, tra cui principalmente:
- [PHP](https://secure.php.net/) - A popular general-purpose scripting language especially suited to web development
- [MySQL](https://www.mysql.com/) - The world's most popular open source database
- [JQuery](https://jquery.com/) - New Wave JavaScript
- [Bootstrap](http://getbootstrap.com/) - The world's most popular mobile-first and responsive front-end framework
- [FontAwesome](http://fontawesome.io/) - The iconic font and CSS toolkit
- [HTML2PDF](http://html2pdf.fr/en/default) - HTML to PDF converter written in PHP
## Community
La community è una componente importante in un progetto open source, perché mette in contatto utenti e programmatori tra di loro e permette pertanto l'individuazione di soluzioni innovative e migliori.
Il forum ufficiale è disponibile all'indirizzo <http://www.openstamanager.com/forum/>, e potete segnalare i vostri problemi e soddisfare le vostre curiosità nelle sezioni più adeguate:
- [Idee, suggerimenti e consigli](http://www.openstamanager.com/forum/viewforum.php?f=1)
- [Problemi con la prima installazione](http://www.openstamanager.com/forum/viewforum.php?f=2)
- [Sicurezza](http://www.openstamanager.com/forum/viewforum.php?f=3)
- [Altro tipo di assistenza](http://www.openstamanager.com/forum/viewforum.php?f=4)
- [Tutorial](http://www.openstamanager.com/forum/viewforum.php?f=5)
**Attenzione**: vi ricordiamo che non vi è nessuna garanzia che qualcuno risponda in tempo alle vostre richieste o problemi.
Siamo inoltre presenti su [Facebook](https://www.facebook.com/openstamanager) e su SourceForge con una [mailing-list](https://sourceforge.net/p/openstamanager/mailman/).
## Contribuire
Per poter contribuire, si consiglia di seguire le indicazioni descritte all'interno della [documentazione ufficiale](https://sourceforge.net/p/openstamanager/wiki/Contribuire/); in particolare, prestare attenzione al codice di condotta e allo stile del codice.
## Sviluppatori
- **Fabio Lovato**, fondatore e sviluppatore ([loviuz](https://sourceforge.net/u/loviuz/profile/))
- **Fabio Piovan**, sviluppatore ([magreba](https://sourceforge.net/u/magreba/profile/))
- **Luca Salvà**, sviluppatore ([lucasalva](https://sourceforge.net/u/lucasalva/profile/))
Per la lista completa delle persone che hanno partecipato al progetto, consultare la [pagina principale della documentazione](https://sourceforge.net/p/openstamanager/wiki/Home/) su SourceForge.
## Licenza
Questo progetto è tutelato dalla licenza **GPL 3** (vedere [LICENSE](https://sourceforge.net/p/openstamanager/code/HEAD/tree/trunk/openstamanager/LICENSE) per ulteriori dettagli).

1
VERSION Normal file
View File

@ -0,0 +1 @@
2.3

249
actions.php Normal file
View File

@ -0,0 +1,249 @@
<?php
include_once __DIR__.'/core.php';
// Lettura parametri iniziali
if (!empty($id_plugin)) {
$info = Plugins::getPlugin($id_plugin);
$directory = '/plugins/'.$info['directory'];
$permesso = $info['idmodule_to'];
} else {
$info = Modules::getModule($id_module);
$directory = '/modules/'.$info['directory'];
$permesso = $id_module;
}
$dbo->query('START TRANSACTION');
// GESTIONE UPLOAD
if (filter('op') == 'link_file' || filter('op') == 'unlink_file') {
$upload_dir = $docroot.'/files/'.basename($directory);
// Controllo sui permessi di scrittura per il modulo
if (Modules::getPermission($id_module) != 'rw') {
$_SESSION['errors'][] = str_replace('_MODULE_', '"'.Modules::getModule($id_module)['name'].'"', _('Non hai permessi di scrittura per il modulo _MODULE_'));
}
// Controllo sui permessi di scrittura per il file system
elseif ((!is_dir($upload_dir) && !mkdir($upload_dir)) || (is_dir($upload_dir) && !is_writable($upload_dir))) {
$_SESSION['errors'][] = str_replace('_DIR_', '"files"', _('Non hai i permessi di scrittura nella cartella _DIR_!'));
}
// Gestione delle operazioni
else {
// UPLOAD
if (filter('op') == 'link_file' && !empty($_FILES) && !empty($_FILES['blob']['name'])) {
$nome = filter('nome_allegato');
$src = $_FILES['blob']['tmp_name'];
$f = pathinfo($_FILES['blob']['name']);
/*
$allowed = [
// Image formats
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'bmp' => 'image/bmp',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'ico' => 'image/x-icon',
// Video formats
'asx' => 'video/asf',
'asf' => 'video/asf',
'wax' => 'video/asf',
'wmv' => 'video/asf',
'wmx' => 'video/asf',
'avi' => 'video/avi',
'divx' => 'video/divx',
'flv' => 'video/x-flv',
'mov' => 'video/quicktime',
'qt' => 'video/quicktime',
'mpg' => 'video/mpeg',
'mpeg' => 'video/mpeg',
'mpe' => 'video/mpeg',
'mp4' => 'video/mp4',
'm4v' => 'video/mp4',
'ogv' => 'video/ogg',
'mkv' => 'video/x-matroska',
// Text formats
'txt' => 'text/plain',
'csv' => 'text/csv',
'tsv' => 'text/tab-separated-values',
'ics' => 'text/calendar',
'rtx' => 'text/richtext',
'css' => 'text/css',
'htm' => 'text/html',
'html' => 'text/html',
// Audio formats
'mp3' => 'audio/mpeg',
'm4a' => 'audio/mpeg',
'm4b' => 'audio/mpeg',
'mp' => 'audio/mpeg',
'm4b' => 'audio/mpeg',
'ra' => 'audio/x-realaudio',
'ram' => 'audio/x-realaudio',
'wav' => 'audio/wav',
'ogg' => 'audio/ogg',
'oga' => 'audio/ogg',
'mid' => 'audio/midi',
'midi' => 'audio/midi',
'wma' => 'audio/wma',
'mka' => 'audio/x-matroska',
// Misc application formats
'rtf' => 'application/rtf',
'js' => 'application/javascript',
'pdf' => 'application/pdf',
'swf' => 'application/x-shockwave-flash',
'class' => 'application/java',
'tar' => 'application/x-tar',
'zip' => 'application/zip',
'gz' => 'application/x-gzip',
'gzip' => 'application/x-gzip',
'rar' => 'application/rar',
'7z' => 'application/x-7z-compressed',
// MS Office formats
'doc' => 'application/msword',
'pot' => 'application/vnd.ms-powerpoint',
'pps' => 'application/vnd.ms-powerpoint',
'ppt' => 'application/vnd.ms-powerpoint',
'wri' => 'application/vnd.ms-write',
'xla' => 'application/vnd.ms-excel',
'xls' => 'application/vnd.ms-excel',
'xlt' => 'application/vnd.ms-excel',
'xlw' => 'application/vnd.ms-excel',
'mdb' => 'application/vnd.ms-access',
'mpp' => 'application/vnd.ms-project',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
'onetoc' => 'application/onenote',
'onetoc2' => 'application/onenote',
'onetmp' => 'application/onenote',
'onepkg' => 'application/onenote',
// OpenOffice formats
'odt' => 'application/vnd.oasis.opendocument.text',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odg' => 'application/vnd.oasis.opendocument.graphics',
'odc' => 'application/vnd.oasis.opendocument.chart',
'odb' => 'application/vnd.oasis.opendocument.database',
'odf' => 'application/vnd.oasis.opendocument.formula',
// WordPerfect formats
'wp' => 'application/wordperfect',
'wpd' => 'application/wordperfect',
];
if (in_array($f['extension'], array_keys($allowed))) {
*/
do {
$filename = random_string().'.'.$f['extension'];
} while (file_exists($upload_dir.'/'.$filename));
// Creazione file fisico
if (move_uploaded_file($src, $upload_dir.'/'.$filename)) {
$dbo->query('INSERT INTO `zz_files`(nome, filename, id_module, id_record) VALUES('.prepare($nome).', '.prepare($filename).', '.prepare($id_module).', '.prepare($id_record).')');
$_SESSION['infos'][] = _('File caricato correttamente!');
} else {
$_SESSION['errors'][] = _('Errore durante il caricamento del file!');
}
/*
} else {
$_SESSION['errors'][] = _('Tipologia di file non permessa!');
}
*/
}
// DELETE
elseif (filter('op') == 'unlink_file' && filter('filename') !== null) {
$filename = filter('filename');
$rs = $dbo->fetchArray('SELECT * FROM zz_files WHERE id_module='.prepare($id_module).' AND id='.prepare(filter('id')).' AND filename='.prepare($filename));
if (unlink($upload_dir.'/'.$filename)) {
$query = 'DELETE FROM zz_files WHERE id_module='.prepare($id_module).' AND id='.prepare(filter('id')).' AND filename='.prepare($filename);
if ($dbo->query($query)) {
$_SESSION['infos'][] = str_replace('_FILE_', '"'.$rs[0]['nome'].'"', _('File _FILE_ eliminato!'));
}
} else {
$_SESSION['errors'][] = str_replace(['_FILE_', '_DIR_'], ['"'.$filename.'"', '"files/'.$module_dir.'/"'], _("Errore durante l'eliminazione del file _FILE_ in _DIR_!"));
}
}
redirect(ROOTDIR.'/editor.php?id_module='.$id_module.'&id_record='.$id_record);
}
}
if (Modules::getPermission($permesso) == 'rw') {
if (!empty($info['script'])) {
// Inclusione di eventuale plugin personalizzato
if (file_exists($docroot.'/modules/'.$info['module_dir'].'/plugins/custom/'.$info['script'])) {
include $docroot.'/modules/'.$info['module_dir'].'/plugins/custom/'.$info['script'];
} elseif (file_exists($docroot.'/modules/'.$info['module_dir'].'/plugins/'.$info['script'])) {
include $docroot.'/modules/'.$info['module_dir'].'/plugins/'.$info['script'];
}
return;
}
// Caricamento helper modulo (verifico se ci sono helper personalizzati)
if (file_exists($docroot.$directory.'/custom/modutil.php')) {
include_once $docroot.$directory.'/custom/modutil.php';
} elseif (file_exists($docroot.$directory.'/modutil.php')) {
include_once $docroot.$directory.'/modutil.php';
}
// Lettura risultato query del modulo
if (file_exists($docroot.$directory.'/custom/init.php')) {
include $docroot.$directory.'/custom/init.php';
} elseif (file_exists($docroot.$directory.'/init.php')) {
include $docroot.$directory.'/init.php';
}
// Esecuzione delle operazioni di gruppo
$id_records = post('id_records');
$id_records = is_array($id_records) ? $id_records : explode(',', $id_records);
$bulk = null;
if (file_exists($docroot.$directory.'/custom/bulk.php')) {
$bulk = include $docroot.$directory.'/custom/bulk.php';
} elseif (file_exists($docroot.$directory.'/bulk.php')) {
$bulk = include $docroot.$directory.'/bulk.php';
}
$bulk = (array) $bulk;
if (in_array(post('op'), $bulk)) {
redirect(ROOTDIR.'/controller.php?id_module='.$id_module, 'js');
} else {
// Esecuzione delle operazioni del modulo
if (file_exists($docroot.$directory.'/custom/actions.php')) {
include $docroot.$directory.'/custom/actions.php';
} elseif (file_exists($docroot.$directory.'/actions.php')) {
include $docroot.$directory.'/actions.php';
}
}
}
$dbo->query('COMMIT');

94
add.php Normal file
View File

@ -0,0 +1,94 @@
<?php
include_once __DIR__.'/core.php';
if (!empty($id_plugin)) {
$info = Plugins::getPlugin($id_plugin);
$directory = '/plugins/'.$info['directory'];
} else {
Permissions::check('rw');
$module = Modules::getModule($id_module);
$directory = '/modules/'.$module['directory'];
}
$module_dir = $module['directory'];
echo '
<div id="form_'.$id_module.'-'.$id_plugin.'">
';
// Caricamento template popup
if (file_exists($docroot.$directory.'/custom/add.php')) {
include $docroot.$directory.'/custom/add.php';
} elseif (file_exists($docroot.$directory.'/custom/add.html')) {
include $docroot.$directory.'/custom/add.html';
} elseif (file_exists($docroot.$directory.'/add.php')) {
include $docroot.$directory.'/add.php';
} elseif (file_exists($docroot.$directory.'/add.html')) {
include $docroot.$directory.'/add.html';
}
echo '
</div>';
if (isAjaxRequest()) {
echo '
<script>
$(document).ready(function(){
$("#form_'.$id_module.'-'.$id_plugin.'").find("form").on("submit", function(){
if($(this).parsley().validate()){
var form_data = new FormData();';
foreach ($get as $key => $value) {
echo '
form_data.append("'.$key.'", "'.$value.'");';
}
echo '
$(this).find("input, textarea, select").each(function(){
var name = $(this).attr("name");
var data = $(this).val();
data = (typeof data == "string") ? [data] : data;
data.forEach(function(item){
form_data.append(name, item);
});
});
$.ajax({
url: "'.$rootdir.$directory.'/actions.php",
cache: false,
type: "post",
processData: false,
contentType: false,
dataType : "html",
data: form_data,
success: function(data) {
data = data.trim();
if(data && !$("#'.$get['select'].'").val()) {
result = JSON.parse(data);
$("#'.$get['select'].'").append(\'<option value="\' + result.id +\'">\' + result.text + \'</option>\').val(result.id).trigger("change");
}
$("#bs-popup2").modal("hide");
},
error: function() {
alert("'._('Errore').': " + form_data);
}
});
}
return false;
});
});
</script>';
}
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';

49
ajax.php Normal file
View File

@ -0,0 +1,49 @@
<?php
include_once __DIR__.'/core.php';
switch (get('op')) {
// Imposta un valore ad un array di $_SESSION
// esempio: push di un valore in $_SESSION['dashboard']['idtecnici']
// iversed: specifica se rimuovere dall'array il valore trovato e applicare quindi una deselezione (valori 0 o 1, default 1)
case 'session_set_array':
$array = explode(',', get('session'));
$value = "'".get('value')."'";
$inversed = get('inversed');
$found = false;
// Ricerca valore nell'array
foreach ($_SESSION[$array[0]][$array[1]] as $idx => $val) {
// Se il valore esiste lo tolgo
if ($val == $value) {
$found = true;
if ((int) $inversed == 1) {
unset($_SESSION[$array[0]][$array[1]][$idx]);
}
}
}
if (!$found) {
array_push($_SESSION[$array[0]][$array[1]], $value);
}
// print_r($_SESSION[$array[0]][$array[1]]);
break;
// Imposta un valore ad una sessione
case 'session_set':
$array = explode(',', get('session'));
$value = get('value');
$clear = get('clear');
if ($clear == 1 || $value == '') {
unset($_SESSION[$array[0]][$array[1]]);
} else {
$_SESSION[$array[0]][$array[1]] = $value;
}
break;
}

1196
ajax_autocomplete.php Normal file

File diff suppressed because it is too large Load Diff

219
ajax_dataload.php Normal file
View File

@ -0,0 +1,219 @@
<?php
include_once __DIR__.'/core.php';
// Informazioni fondamentali
$start = filter('start');
$length = filter('length');
$columns = filter('columns');
$order = filter('order')[0];
$order['column'] = $order['column'] - 1;
array_shift($columns);
// Lettura parametri iniziali
if (!empty($id_plugin)) {
$total = Plugins::getQuery($id_plugin);
$total['query'] = Modules::replacePlaceholder($total['query'], $id_parent);
} else {
$total = Modules::getQuery($id_module);
}
// Lettura parametri modulo
$module_query = $total['query'];
$module_query = str_replace('|period_start|', $_SESSION['period_start'], $module_query);
$module_query = str_replace('|period_end|', $_SESSION['period_end'], $module_query);
$module_query = str_replace('|select|', $total['select'], $module_query);
// Predisposizione dela risposta
$results = [];
$results['data'] = [];
$results['recordsTotal'] = 0;
$results['recordsFiltered'] = 0;
$results['summable'] = [];
if (!empty($module_query) && $module_query != 'menu' && $module_query != 'custom') {
// Conteggio totale
$query = 'SELECT COUNT(*) as `tot` FROM ('.$module_query.') AS `count`';
$cont = $dbo->fetchArray($query);
if (!empty($cont)) {
$results['recordsTotal'] = $cont[0]['tot'];
}
// Filtri di ricerica
$search_filters = [];
for ($i = 0; $i < count($columns); ++$i) {
if (!empty($columns[$i]['search']['value'])) {
if (strpos($total['search_inside'][$i], '|search|') !== false) {
$pieces = explode(',', $columns[$i]['search']['value']);
foreach ($pieces as $piece) {
$piece = trim($piece);
$search_filters[] = str_replace('|search|', prepare('%'.$piece.'%'), $total['search_inside'][$i]);
}
} else {
$search_filters[] = '`'.$total['search_inside'][$i].'` LIKE '.prepare('%'.trim($columns[$i]['search']['value'].'%'));
}
}
}
if (!empty($search_filters)) {
$module_query = str_replace('2=2', '2=2 AND ('.implode(' AND ', $search_filters).') ', $module_query);
}
// Filtri derivanti dai permessi (eventuali)
$module_query = Modules::replaceAdditionals($id_module, $module_query);
// Ordinamento dei risultati
if (isset($order['dir']) && isset($order['column'])) {
$pieces = explode('ORDER', $module_query);
$cont = count($pieces);
if ($cont > 1) {
unset($pieces[$cont - 1]);
}
$module_query = implode('ORDER', $pieces).' ORDER BY `'.$total['order_by'][$order['column']].'` '.$order['dir'];
}
// Calcolo di eventuali somme
if (!empty($total['summable'])) {
$query = str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $module_query).') AS `z`';
$sums = $dbo->fetchArray($query)[0];
if (!empty($sums)) {
$r = [];
foreach ($sums as $key => $sum) {
if (strpos($key, 'sum_') !== false) {
$r[str_replace('sum_', '', $key)] = Translator::numberToLocale($sum);
}
}
$results['summable'] = $r;
}
}
// Paginazione
if ($length > 0) {
$module_query .= ' LIMIT '.$start.', '.$length;
}
// Query effettiva
$query = str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $module_query);
$rs = $dbo->fetchArray($query);
// Conteggio dei record filtrati
$cont = $dbo->fetchArray('SELECT FOUND_ROWS()');
if (!empty($cont)) {
$results['recordsFiltered'] = $cont[0]['FOUND_ROWS()'];
}
// Creazione della tabella
$align = [];
foreach ($rs as $i => $r) {
if ($i == 0) {
foreach ($total['fields'] as $field) {
$value = trim($r[$field]);
// Allineamento a destra se il valore della prima riga risulta numerica
if (Translator::getEnglishFormatter()->isNumber($value) || Translator::getEnglishFormatter()->isNumber($value)) {
$align[$field] = 'text-right';
}
// Allineamento al centro se il valore della prima riga risulta relativo a date o icone
elseif ((Translator::getEnglishFormatter()->isDate($value) || Translator::getEnglishFormatter()->isDate($value)) || preg_match('/^icon_(.+?)$/', $field)) {
$align[$field] = 'text-center';
}
}
}
$result = [];
$result[] = '<span class="hide" data-id="'.$r['id'].'"></span>';
foreach ($total['fields'] as $pos => $field) {
$column = [];
if (!empty($r['_bg_'])) {
$column['data-background'] = $r['_bg_'];
}
// Allineamento
if (!empty($align[$field])) {
$column['class'] = $align[$field];
}
$value = trim($r[$field]);
// Formattazione automatica
if (!empty($total['format'][$pos]) && !empty($value) && !empty(Translator::getEnglishFormatter())) {
if (Translator::getEnglishFormatter()->isNumber($value)) {
$value = Translator::numberToLocale($value);
} elseif (Translator::getEnglishFormatter()->isTimestamp($value)) {
$value = Translator::timestampToLocale($value);
} elseif (Translator::getEnglishFormatter()->isDate($value)) {
$value = Translator::dateToLocale($value);
} elseif (Translator::getEnglishFormatter()->isTime($value)) {
$value = Translator::timeToLocale($value);
}
}
// Icona
if (preg_match('/^color_(.+?)$/', $field, $m)) {
$value = $r['color_title_'.$m[1]] ?: '';
$column['class'] = 'text-center small';
$column['data-background'] = $r[$field];
}
// Icona di stampa
elseif ($field == '_print_') {
$print_url = $r['_print_'];
preg_match_all('/\$(.+?)\$/', $print_url, $matches);
for ($m = 0; $m < sizeof($matches[0]); ++$m) {
$print_url = str_replace($matches[0][$m], $r[$matches[1][$m]], $print_url);
}
$value = '<a href="'.$rootdir.'/'.$print_url.'" target="_blank"><i class="fa fa-2x fa-print"></i></a>';
}
// Icona
elseif (preg_match('/^icon_(.+?)$/', trim($field), $m)) {
$value = '<i class="'.$r[$field].'"></i> <small>'.$r['icon_title_'.$m[1]].'</small>';
}
// Colore del testo
if (!empty($column['data-background'])) {
$column['data-color'] = $column['data-color'] ?: color_inverse($column['data-background']);
}
// Link della colonna
if ($field != '_print_') {
$id_record = $r['id'];
$hash = '';
if (!empty($r['_link_record_'])) {
$id_module = $r['_link_module_'];
$id_record = $r['_link_record_'];
$hash = !empty($r['_link_hash_']) ? '#'.$r['_link_hash_'] : '';
unset($id_plugin);
}
$column['data-link'] = $rootdir.'/'.(empty($id_plugin) ? '' : 'plugin_').'editor.php?id_module='.$id_module.'&id_record='.$id_record.(empty($id_plugin) ? '' : '&id_plugin='.$id_plugin.'&id_parent='.$id_parent).$hash;
if (!empty($id_plugin)) {
$column['data-type'] = 'dialog';
}
}
$attributes = [];
foreach ($column as $key => $val) {
$val = is_array($val) ? implode(' ', $val) : $val;
$attributes[] = $key.'="'.$val.'"';
}
$result[] = str_replace('|attr|', implode(' ', $attributes), '<div |attr|>'.$value.'</div>');
}
$results['data'][] = $result;
}
}
echo json_encode($results);

563
ajax_select.php Normal file
View File

@ -0,0 +1,563 @@
<?php
include_once __DIR__.'/core.php';
$op = empty($op) ? filter('op') : $op;
$search = filter('q');
if (!isset($elements)) {
$elements = [];
}
$elements = (!is_array($elements)) ? explode(',', $elements) : $elements;
$superselect = !empty($_SESSION['superselect']) ? $_SESSION['superselect'] : [];
$where = [];
$filter = [];
$search_fields = [];
$custom = [
'id' => 'id',
'text' => 'descrizione',
];
if (!function_exists('completeResults')) {
function completeResults($query, $where, $filter = [], $search = [], $custom = [])
{
$dbo = Database::getConnection();
if (strpos($query, '|filter|') !== false) {
$query = str_replace('|filter|', !empty($filter) ? 'WHERE '.implode(' OR ', $filter) : '', $query);
} elseif (!empty($filter)) {
$where[] = '('.implode(' OR ', $filter).')';
}
if (!empty($search)) {
$where[] = '('.implode(' OR ', $search).')';
}
$query = str_replace('|where|', !empty($where) ? 'WHERE '.implode(' AND ', $where) : '', $query);
$rs = $dbo->fetchArray($query);
$results = [];
foreach ($rs as $r) {
$result = [];
foreach ($custom as $key => $value) {
$result[$key] = $r[$value];
}
$results[] = $result;
}
return $results;
}
}
switch ($op) {
case 'clienti':
if (Modules::getModule('Anagrafiche')['permessi'] != '-') {
$query = "SELECT an_anagrafiche.idanagrafica AS id, CONCAT(ragione_sociale, IF(citta IS NULL OR citta = '', '', CONCAT(' (', citta, ')'))) AS descrizione, idtipointervento_default FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY ragione_sociale";
foreach ($elements as $element) {
$filter[] = 'an_anagrafiche.idanagrafica='.prepare($element);
}
if (empty($filter)) {
$where[] = "descrizione='Cliente'";
$where[] = 'deleted=0';
}
if (!empty($search)) {
$search_fields[] = 'ragione_sociale LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'citta LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
$custom['idtipointervento'] = 'idtipointervento_default';
}
break;
case 'fornitori':
if (Modules::getModule('Anagrafiche')['permessi'] != '-') {
$query = "SELECT an_anagrafiche.idanagrafica AS id, CONCAT(ragione_sociale, IF(citta IS NULL OR citta = '', '', CONCAT(' (', citta, ')'))) AS descrizione, idtipointervento_default FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY ragione_sociale";
foreach ($elements as $element) {
$filter[] = 'an_anagrafiche.idanagrafica='.prepare($element);
}
if (empty($filter)) {
$where[] = "descrizione='Fornitore'";
$where[] = 'deleted=0';
}
if (!empty($search)) {
$search_fields[] = 'ragione_sociale LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'citta LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
$custom['idtipointervento'] = 'idtipointervento_default';
}
break;
case 'agenti':
if (Modules::getModule('Anagrafiche')['permessi'] != '-') {
$query = "SELECT an_anagrafiche.idanagrafica AS id, CONCAT(ragione_sociale, IF(citta IS NULL OR citta = '', '', CONCAT(' (', citta, ')'))) AS descrizione, idtipointervento_default FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY ragione_sociale";
foreach ($elements as $element) {
$filter[] = 'an_anagrafiche.idanagrafica='.prepare($element);
}
if (empty($filter)) {
$where[] = "descrizione='Agente'";
$where[] = 'deleted=0';
}
if (!empty($search)) {
$search_fields[] = 'ragione_sociale LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'citta LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
$results = completeResults($query, $where, $filter, $search, $custom);
// Evidenzia l'agente di default
if ($superselect['idanagrafica']) {
$rsa = $dbo->fetchArray('SELECT idagente FROM an_anagrafiche WHERE idanagrafica='.prepare($superselect['idanagrafica']));
$idagente_default = $rsa[0]['idagente'];
} else {
$idagente_default = 0;
}
$ids = array_column($results, $id);
$pos = array_search($idagente_default, $ids);
if ($pos !== false) {
$results[$pos]['_bgcolor_'] = '#ff0';
}
}
break;
case 'tecnici':
if (Modules::getModule('Anagrafiche')['permessi'] != '-') {
$query = "SELECT an_anagrafiche.idanagrafica AS id, CONCAT(ragione_sociale, IF(citta IS NULL OR citta = '', '', CONCAT(' (', citta, ')'))) AS descrizione, idtipointervento_default FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY ragione_sociale";
foreach ($elements as $element) {
$filter[] = 'an_anagrafiche.idanagrafica='.prepare($element);
}
if (empty($filter)) {
$where[] = "descrizione='Tecnico'";
$where[] = 'deleted=0';
}
if (!empty($search)) {
$search_fields[] = 'ragione_sociale LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'citta LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
// $custom['idtipointervento'] = 'idtipointervento_default';
}
break;
// Nota Bene: nel campo id viene specificato idtipoanagrafica-idanagrafica -> modulo Utenti e permessi, creazione nuovo utente
case 'anagrafiche':
if (Modules::getModule('Anagrafiche')['permessi'] != '-') {
$query = "SELECT CONCAT(an_tipianagrafiche.idtipoanagrafica, '-', an_anagrafiche.idanagrafica) AS id, CONCAT_WS('', ragione_sociale, ' (', citta, ' ', provincia, ')') AS descrizione idtipointervento_default FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica |where| ORDER BY ragione_sociale";
foreach ($elements as $element) {
$filter[] = 'an_anagrafiche.idanagrafica='.prepare($element);
}
if (empty($filter)) {
$where[] = 'deleted=0';
}
if (!empty($search)) {
$search_fields[] = 'ragione_sociale LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'citta LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
// $custom['idtipointervento'] = 'idtipointervento_default';
}
break;
case 'sedi':
if (Modules::getModule('Anagrafiche')['permessi'] != '-' && isset($superselect['idanagrafica'])) {
$query = "SELECT * FROM (SELECT 0 AS id, 'Sede legale' AS descrizione UNION SELECT id, CONCAT_WS(' - ', nomesede, citta) FROM an_sedi |where|) AS tab |filter| ORDER BY id";
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'idanagrafica='.prepare($superselect['idanagrafica']);
if (!empty($search)) {
$search_fields[] = 'nomesede LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'citta LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'referenti':
if (Modules::getModule('Anagrafiche')['permessi'] != '-' && isset($superselect['idanagrafica'])) {
$query = 'SELECT id, nome AS descrizione FROM an_referenti |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'idanagrafica='.prepare($superselect['idanagrafica']);
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'articoli':
$query = 'SELECT * FROM mg_articoli |where| ORDER BY id_categoria ASC, id_sottocategoria ASC';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'attivo=1';
if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') {
$where[] = 'qta>0';
}
if (!empty($search)) {
$search_fields[] = 'descrizione LIKE '.prepare('%'.$search.'%');
}
$wh = '';
if (!empty($search_fields)) {
$where[] = '('.implode(' OR ', $search_fields).')';
}
if (count($where) != 0) {
$wh = 'WHERE '.implode(' AND ', $where);
}
$query = str_replace('|where|', $wh, $query);
$prev = -1;
$rs = $dbo->fetchArray($query);
foreach ($rs as $r) {
if ($prev != $r['id_sottocategoria']) {
$prev = $r['id_sottocategoria'];
$results[] = ['text' => $dbo->fetchArray('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_categoria']))[0]['nome'], 'children' => []];
}
$results[count($results) - 1]['children'][] = [
'id' => $r['id'],
'text' => $r['codice'].' - '.$r['descrizione'],
'descrizione' => $r['descrizione'],
'um' => $r['um'],
'prezzo_acquisto' => Translator::numberToLocale($r['prezzo_acquisto']),
'prezzo_vendita' => Translator::numberToLocale($r['prezzo_vendita']),
];
}
break;
case 'conti':
if (Modules::getModule('Piano dei conti')['permessi'] != '-') {
$query = 'SELECT * FROM co_pianodeiconti2';
$rs = $dbo->fetchArray($query);
foreach ($rs as $r) {
$results[] = ['text' => $r['numero'].' '.$r['descrizione'], 'children' => []];
$subquery = 'SELECT * FROM co_pianodeiconti3 |where|';
$where = [];
$filter = [];
$search_fields = [];
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
if (!empty($filter)) {
$where[] = '('.implode(' OR ', $filter).')';
}
$where[] = 'idpianodeiconti2='.prepare($r['id']);
if (!empty($search)) {
$search_fields[] = 'descrizione LIKE '.prepare('%'.$search.'%');
}
if (!empty($search_fields)) {
$where[] = '('.implode(' OR ', $search_fields).')';
}
$wh = '';
if (count($where) != 0) {
$wh = 'WHERE '.implode(' AND ', $where);
}
$subquery = str_replace('|where|', $wh, $subquery);
$rs2 = $dbo->fetchArray($subquery);
foreach ($rs2 as $r2) {
$results[count($results) - 1]['children'][] = ['id' => $r2['id'], 'text' => $r2['descrizione']];
}
}
}
break;
case 'conti-vendite':
if (Modules::getModule('Piano dei conti')['permessi'] != '-') {
$query = "SELECT co_pianodeiconti3.id, CONCAT_WS( ' ', co_pianodeiconti3.numero, co_pianodeiconti3.descrizione ) AS descrizione FROM co_pianodeiconti3 INNER JOIN (co_pianodeiconti2 INNER JOIN co_pianodeiconti1 ON co_pianodeiconti2.idpianodeiconti1=co_pianodeiconti1.id) ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id |where| ORDER BY co_pianodeiconti3.numero ASC";
foreach ($elements as $element) {
$filter[] = 'co_pianodeiconti3.id='.prepare($element);
}
$where[] = "co_pianodeiconti1.descrizione='Economico'";
$where[] = "co_pianodeiconti3.dir='entrata'";
if (!empty($search)) {
$search_fields[] = 'descrizione LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'conti-acquisti':
if (Modules::getModule('Piano dei conti')['permessi'] != '-') {
$query = "SELECT co_pianodeiconti3.id, CONCAT_WS( ' ', co_pianodeiconti3.numero, co_pianodeiconti3.descrizione ) AS descrizione FROM co_pianodeiconti3 INNER JOIN (co_pianodeiconti2 INNER JOIN co_pianodeiconti1 ON co_pianodeiconti2.idpianodeiconti1=co_pianodeiconti1.id) ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id |where| ORDER BY co_pianodeiconti3.numero ASC";
foreach ($elements as $element) {
$filter[] = 'co_pianodeiconti3.id='.prepare($element);
}
$where[] = "co_pianodeiconti1.descrizione='Economico'";
$where[] = "co_pianodeiconti3.dir='uscita'";
if (!empty($search)) {
$search_fields[] = 'descrizione LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'impianti':
if (Modules::getModule('MyImpianti')['permessi'] != '-' && isset($superselect['idanagrafica'])) {
$query = 'SELECT id, CONCAT(matricola, " - ", nome) AS descrizione FROM my_impianti |where| ORDER BY idsede';
foreach ($elements as $element) {
$filter[] = 'idsede='.prepare($element);
}
$where[] = 'idanagrafica='.prepare($superselect['idanagrafica']);
$where[] = 'idsede='.prepare($superselect['idsede']);
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'matricola LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'componenti':
if (Modules::getModule('Gestione componenti')['permessi'] != '-' && isset($superselect['marticola'])) {
$query = 'SELECT id, nome AS descrizione, contenuto FROM my_impianto_componenti |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'idimpianto='.prepare($element);
}
$temp = [];
$impianti = explode(',', $superselect['marticola']);
foreach ($impianti as $key => $idimpianto) {
$temp[] = 'idimpianto='.prepare($idimpianto);
}
$where[] = '('.implode(' OR ', $temp).')';
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
$custom['contenuto'] = 'contenuto';
$results = completeResults($query, $where, $filter, $search, $custom);
foreach ($results as $key => $value) {
$matricola = \Util\Ini::getValue($r['contenuto'], 'Matricola');
$results[$key]['text'] = (empty($matricola) ? '' : $matricola.' - ').$results[$key]['text'];
unset($results[$key]['content']);
}
}
break;
case 'categorie':
if (Modules::getModule('Magazzino')['permessi'] != '-') {
$query = 'SELECT id, nome AS descrizione FROM mg_categorie |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = '`parent` IS NULL';
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'sottocategorie':
if (Modules::getModule('Magazzino')['permessi'] != '-' && isset($superselect['id_categoria'])) {
$query = 'SELECT id, nome AS descrizione FROM mg_categorie |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = '`parent`='.prepare($superselect['id_categoria']);
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'preventivi':
if (Modules::getModule('Preventivi')['permessi'] != '-' && isset($superselect['idanagrafica'])) {
$query = 'SELECT co_preventivi.id AS id, an_anagrafiche.idanagrafica, CONCAT(numero, " ", nome) AS descrizione, co_preventivi.idtipointervento, (SELECT descrizione descrizione FROM in_tipiintervento WHERE in_tipiintervento.idtipointervento = co_preventivi.idtipointervento) AS idtipointervento_descrizione FROM co_preventivi INNER JOIN an_anagrafiche ON co_preventivi.idanagrafica=an_anagrafiche.idanagrafica |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']);
$where[] = "idstato NOT IN (SELECT `id` FROM co_statipreventivi WHERE descrizione='Bozza' OR descrizione='Rifiutato' OR descrizione='Pagato')";
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
$custom['idtipointervento'] = 'idtipointervento';
$custom['idtipointervento_descrizione'] = 'idtipointervento_descrizione';
}
break;
case 'preventivi_aperti':
if (Modules::getModule('Preventivi')['permessi'] != '-') {
$query = 'SELECT co_preventivi.id AS id, CONCAT(numero, " ", nome, " (", ragione_sociale, ")") AS descrizione FROM co_preventivi INNER JOIN an_anagrafiche ON co_preventivi.idanagrafica=an_anagrafiche.idanagrafica |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'idpreventivo='.prepare($element);
}
$where[] = 'idstato IN (1)';
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'contratti':
if (Modules::getModule('Contratti')['permessi'] != '-') {
$query = 'SELECT co_contratti.id AS id, CONCAT(numero, " ", nome) AS descrizione FROM co_contratti INNER JOIN an_anagrafiche ON co_contratti.idanagrafica=an_anagrafiche.idanagrafica |where| ORDER BY id';
foreach ($elements as $element) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']);
$where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE pianificabile = 1)';
if (!empty($search)) {
$search_fields[] = 'nome LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'tipiintervento':
if (Modules::getModule('Interventi')['permessi'] != '-') {
$query = 'SELECT idtipointervento AS id, descrizione FROM in_tipiintervento |where| ORDER BY idtipointervento';
foreach ($elements as $element) {
$filter[] = 'idtipointervento='.prepare($element);
}
if (!empty($search)) {
$search_fields[] = 'descrizione LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'misure':
if (Modules::getModule('Magazzino')['permessi'] != '-') {
$query = 'SELECT valore AS id, valore AS descrizione FROM mg_unitamisura |where| ORDER BY valore';
foreach ($elements as $element) {
$filter[] = 'valore='.prepare($element).'';
}
if (!empty($search)) {
$search_fields[] = 'valore LIKE '.prepare('%'.$search.'%');
}
}
break;
case 'prodotti_lotti':
if (Modules::getModule('Magazzino')['permessi'] != '-') {
$query = 'SELECT DISTINCT lotto AS descrizione FROM mg_prodotti |where|';
$where[] = 'idarticolo='.prepare($superselect['idarticolo']);
foreach ($elements as $element) {
$filter[] = 'lotto='.prepare($element).'';
}
if (!empty($search)) {
$search_fields[] = 'lotto LIKE '.prepare('%'.$search.'%');
}
$custom['id'] = 'descrizione';
}
break;
case 'prodotti_serial':
if (Modules::getModule('Magazzino')['permessi'] != '-') {
$query = 'SELECT DISTINCT serial AS descrizione FROM mg_prodotti |where|';
$where[] = 'idarticolo='.prepare($superselect['idarticolo']);
$where[] = 'lotto='.prepare($superselect['lotto']);
foreach ($elements as $element) {
$filter[] = 'serial='.prepare($element).'';
}
if (!empty($search)) {
$search_fields[] = 'serial LIKE '.prepare('%'.$search.'%');
}
$custom['id'] = 'descrizione';
}
break;
case 'prodotti_altro':
if (Modules::getModule('Magazzino')['permessi'] != '-') {
$query = 'SELECT DISTINCT altro AS descrizione FROM mg_prodotti |where|';
$where[] = 'idarticolo='.prepare($superselect['idarticolo']);
$where[] = 'lotto='.prepare($superselect['lotto']);
$where[] = 'serial='.prepare($superselect['serial']);
foreach ($elements as $element) {
$filter[] = 'altro='.prepare($element).'';
}
if (!empty($search)) {
$search_fields[] = 'altro LIKE '.prepare('%'.$search.'%');
}
$custom['id'] = 'descrizione';
}
break;
}
if (!isset($results) && !empty($query)) {
$results = completeResults($query, $where, $filter, $search_fields, $custom);
}
echo json_encode($results);

29
api/index.php Normal file
View File

@ -0,0 +1,29 @@
<?php
include_once __DIR__.'/../core.php';
// Disabilta la sessione per l'API
session_write_close();
// Permesso di accesso all'API da ogni dispositivo
header('Access-Control-Allow-Origin: *');
// Attenzione: al momento l'API permette la lettura di tutte le tabelle rpesenti nel database (non limitate a quelle del progetto).
// Controlli sulla chiave di accesso
try {
$api = new API(filter('token'));
$resource = filter('resource');
if (!empty($resource)) {
$result = $api->retrieve($resource);
} else {
$result = API::response(API::getResources()['retrieve']);
}
} catch (InvalidArgumentException $e) {
$result = API::error('unauthorized');
} catch (Exception $e) {
$result = API::error('serverError');
}
echo $result;

View File

@ -0,0 +1,221 @@
/*!
* DataTables + Font Awesome integration
* License: MIT - http://datatables.net/license
*/
/*
* Sort styling
*/
table.dataTable thead th {
position: relative;
background-image: none !important;
/* Remove the DataTables bootstrap integration styling */
}
table.dataTable thead th.sorting:after,
table.dataTable thead th.sorting_asc:after,
table.dataTable thead th.sorting_desc:after {
position: absolute;
top: 12px;
right: 8px;
display: block;
font-family: FontAwesome;
}
table.dataTable thead th.sorting:after {
content: "\f0dc";
color: #ddd;
font-size: 0.8em;
padding-top: 0.12em;
}
table.dataTable thead th.sorting_asc:after {
content: "\f0de";
}
table.dataTable thead th.sorting_desc:after {
content: "\f0dd";
}
div.dataTables_scrollBody table.dataTable thead th.sorting:after,
div.dataTables_scrollBody table.dataTable thead th.sorting_asc:after,
div.dataTables_scrollBody table.dataTable thead th.sorting_desc:after {
content: "";
}
/* In Bootstrap and Foundation the padding top is a little different from the DataTables stylesheet */
table.table thead th.sorting:after,
table.table thead th.sorting_asc:after,
table.table thead th.sorting_desc:after {
top: 8px;
}
/*
* DataTables style pagination controls
*/
div.dataTables_paginate a.paginate_button.first,
div.dataTables_paginate a.paginate_button.previous {
position: relative;
padding-left: 24px;
}
div.dataTables_paginate a.paginate_button.next,
div.dataTables_paginate a.paginate_button.last {
position: relative;
padding-right: 24px;
}
div.dataTables_paginate a.first:before,
div.dataTables_paginate a.previous:before {
position: absolute;
top: 8px;
left: 10px;
display: block;
font-family: FontAwesome;
}
div.dataTables_paginate a.next:after,
div.dataTables_paginate a.last:after {
position: absolute;
top: 8px;
right: 10px;
display: block;
font-family: FontAwesome;
}
div.dataTables_paginate a.first:before {
content: "\f100";
}
div.dataTables_paginate a.previous:before {
content: "\f104";
}
div.dataTables_paginate a.next:after {
content: "\f105";
}
div.dataTables_paginate a.last:after {
content: "\f101";
}
/*
* Bootstrap and foundation style pagination controls
*/
div.dataTables_paginate li.first>a,
div.dataTables_paginate li.previous>a {
position: relative;
padding-left: 24px;
}
div.dataTables_paginate li.next>a,
div.dataTables_paginate li.last>a {
position: relative;
padding-right: 24px;
}
div.dataTables_paginate li.first a:before,
div.dataTables_paginate li.previous a:before {
position: absolute;
top: 6px;
left: 10px;
display: block;
font-family: FontAwesome;
}
div.dataTables_paginate li.next a:after,
div.dataTables_paginate li.last a:after {
position: absolute;
top: 6px;
right: 10px;
display: block;
font-family: FontAwesome;
}
div.dataTables_paginate li.first a:before {
content: "\f100";
}
div.dataTables_paginate li.previous a:before {
content: "\f104";
}
div.dataTables_paginate li.next a:after {
content: "\f105";
}
div.dataTables_paginate li.last a:after {
content: "\f101";
}
/* In Foundation we don't want the padding like in bootstrap */
div.columns div.dataTables_paginate li.first a:before,
div.columns div.dataTables_paginate li.previous a:before,
div.columns div.dataTables_paginate li.next a:after,
div.columns div.dataTables_paginate li.last a:after {
top: 0;
}
/* Fix for Scroller plugin */
div.DTS {
display: block !important;
}
div.DTS tbody th,
div.DTS tbody td {
white-space: nowrap;
}
div.DTS div.DTS_Loading {
z-index: 1;
}
div.DTS div.dataTables_scrollBody {
background: none;
}
div.DTS div.dataTables_scrollBody table {
z-index: 2;
}
div.DTS div.dataTables_paginate,
div.DTS div.dataTables_length {
display: none;
}
/* Custom */
div.dataTables_wrapper {
min-height: 150px;
}
.dataTables_filter input {
display: inline-block;
border-radius: 0px !important;
box-shadow: none;
height: 34px;
padding: 6px 12px;
font-size: 14px;
line-height: 1.42857;
vertical-align: middle;
background-color: #FFF;
background-image: none;
border: 1px solid #CCC;
transition: border-color 0.15s ease-in-out 0s, box-shadow 0.15s ease-in-out 0s;
}
.dataTables_info .select-info{
display: none;
}

View File

@ -0,0 +1,67 @@
input,
button,
.btn,
header,
.main-sidebar,
.main-footer,
#widget-controller_top,
#widget-controller_right,
.daterangepicker,
.datepicker,
#main-records_filter,
.extra-info,
.deleteicon,
.fa.deleteicon::after,
.fa.deleteicon::before,
.hide,
#back-to-top {
display: none;
}
td {
border: 1px solid #ccc;
}
th {
background: #333;
color: #fff;
text-align: left;
padding: 4px;
}
ul.nav {
float: left;
}
ul {
margin: 0;
padding: 0;
}
li.header i {
display: none;
}
li.header {
list-style: none;
margin: 10px 0;
padding: 0;
}
li.header > a {
font-size: 30px;
text-decoration: none;
font-weight: bold;
color: #333;
text-align: left;
float: left;
}
.table {
width: 100%;
}
.text-right {
text-align: right;
}
.pull-left {
float: left;
text-align: left;
}
#totali_colonne td {
background: #eee;
}
#totali_colonne td big {
font-size: 22px;
}

561
assets/src/css/style.css Normal file
View File

@ -0,0 +1,561 @@
*:focus {
outline: none;
}
@font-face {
font-family: 'OpenSansRegular';
src: url('../fonts/opensans-regular-webfont.eot');
src: url('../fonts/opensans-regular-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/opensans-regular-webfont.woff') format('woff'), url('../fonts/opensans-regular-webfont.ttf') format('truetype'), url('../fonts/opensans-regular-webfont.svg#OpenSansRegular') format('svg');
font-weight: normal;
font-style: normal;
}
html,
body {
font-family: 'Open Sans', sans-serif;
}
html {
height: 100%;
}
textarea {
resize: vertical;
}
a.disabled {
pointer-events: none;
cursor: default;
opacity: 0.6;
}
.btn-calendar>.btn {
color: inherit !important;
background: transparent;
font-size: 20px;
margin-top: 2px;
}
#progress {
width: 400px;
margin: auto;
position: relative;
display: none;
}
#progress .progress-bar {
background-image: url(../img/progress.gif);
}
#progress .progress-bar span {
position: absolute;
top: 2px;
left: 47%;
color: #a20;
font-weight: bold;
}
#datetime {
font-size: 11px;
font-weight: normal;
color: #aaa;
margin: 8px 0 0 0;
}
#right-menu {
padding: 10px;
}
#right-menu .fa-info {
padding: 0px 5px
}
.ui-menu {
position: fixed !important;
}
.ui-autocomplete {
min-width: 160px;
padding: 10px;
margin: 2px;
list-style: none;
border-style: solid;
border-width: 1px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.ui-autocomplete-category {
font-size: 150%;
}
.ui-autocomplete-scrollable {
max-height: 80vh;
width: 600px;
overflow-y: auto;
overflow-x: hidden;
}
.ui-autocomplete a {
color: inherit;
}
.square {
width: 24px;
height: 24px;
margin: auto;
}
.content {
padding: 20px 15px;
}
.navbar a:hover,
.logo:hover {
text-decoration: none
}
.no-padding {
padding: 0 0px;
}
.box-center {
width: 600px;
margin: 7% auto
}
.box-center-large {
width: 850px;
margin: 7% auto
}
.box-center .box-body,
.box-center-large .box-body {
padding: 20px;
border-top: 0
}
@media ( max-width:768px) {
.box-center,
.box-center-large {
width: 90%;
margin-top: 20px
}
}
.li-widget a:hover {
text-decoration: none;
}
.clickable {
cursor: pointer;
}
#main_loading {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #555;
z-index: 9999;
text-align: center;
opacity: 0.9;
-moz-opacity: 0.9;
filter: alpha(opacity=90);
}
#main_loading>div {
position: relative;
top: 50%;
color: #333;
}
#main_loading>div>i {
font-size: 300px;
margin-top: -150px;
color: #e24e1e;
}
#mini-loader {
position: fixed;
top: 0;
left: 0;
z-index: 9000;
width: 100%;
height: 100%;
background: rgba( 0, 0, 0, 0.15);
}
#mini-loader>div {
position: absolute;
bottom: 50%;
left: 50%;
width: 100px;
height: 100px;
margin-top: -50px;
margin-left: -50px;
background: transparent url(../img/ajax-loader.gif) top left no-repeat;
}
body .header .logo {
font-family: inherit;
}
.btn-github {
color: #ffffff;
background-color: #444444;
border-color: rgba(0, 0, 0, 0.2);
}
.btn-github:hover,
.btn-github:focus,
.btn-github:active,
.btn-github.active,
.open .dropdown-toggle.btn-github {
color: #ffffff;
background-color: #303030;
border-color: rgba(0, 0, 0, 0.2);
}
.btn-github:active,
.btn-github.active,
.open .dropdown-toggle.btn-github {
background-image: none;
}
.btn-github.disabled,
.btn-github[disabled],
fieldset[disabled] .btn-github,
.btn-github.disabled:hover,
.btn-github[disabled]:hover,
fieldset[disabled] .btn-github:hover,
.btn-github.disabled:focus,
.btn-github[disabled]:focus,
fieldset[disabled] .btn-github:focus,
.btn-github.disabled:active,
.btn-github[disabled]:active,
fieldset[disabled] .btn-github:active,
.btn-github.disabled.active,
.btn-github[disabled].active,
fieldset[disabled] .btn-github.active {
background-color: #444444;
border-color: rgba(0, 0, 0, 0.2);
}
.btn-github .badge {
color: #444444;
background-color: #ffffff;
}
span.form-control {
background: transparent;
border: none;
}
.panel-heading.mini {
padding: 5px 8px;
}
.dropdown.col-md-3>.dropdown-menu {
width: 91.5%;
left: 15px;
padding: 5px;
}
.input-group-addon {
padding: 0px 12px;
}
.colorpicker {
margin-top: 0px !important;
}
@media ( max-width: 992px) {
.table-bordered>thead>tr>th,
.table-bordered>tbody>tr>th,
.table-bordered>tfoot>tr>th,
.table-bordered>thead>tr>td,
.table-bordered>tbody>tr>td,
.table-bordered>tfoot>tr>td {
word-break: break-all;
}
}
/* Aggiustamenti per i widget */
.widget li {
margin-left: 0 !important;
list-style-type: none;
}
.widget {
padding: 0;
margin-bottom: 0;
}
.widget.bordered {
border: 6px dashed #aaa;
margin: 10px;
min-height: 200px;
padding: 4px;
}
.close {
padding-right: 5px;
position: relative;
z-index: 1;
opacity: 0.1;
}
/* Tooltip dark */
.ui-tooltip {
background: #222 !important;
color: white !important;
border: 0px;
font-size: 11px !important;
}
.nav-tabs-custom>.nav-tabs.pull-right>li>a.back-btn {
font-size: 12px;
color: #3C8DBC;
}
.nav-tabs-custom>.nav-tabs.pull-right>li>a.back-btn:hover {
cursor: pointer;
color: #72AFD2;
}
@media ( max-width: 480px) {
#main_loading>div>i {
font-size: 160px;
margin-top: -80px;
}
}
#back-to-top {
display: inline-block;
height: 60px;
width: 60px;
position: fixed;
bottom: 60px;
right: 10px;
z-index: 10;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.05);
/* image replacement properties */
color: #fff;
overflow: hidden;
white-space: nowrap;
background: rgba(255, 78, 0, 0.8);
visibility: hidden;
opacity: 0;
-webkit-transition: opacity .3s 0s, visibility 0s .3s;
-moz-transition: opacity .3s 0s, visibility 0s .3s;
transition: opacity .3s 0s, visibility 0s .3s;
}
#back-to-top>span {
position: absolute;
top: 50%;
left: 50%;
width: 30px;
height: 30px;
text-align: center;
margin-left: -15px;
margin-top: -15px;
}
#back-to-top.cd-is-visible {
visibility: visible;
opacity: 0.8;
z-index: 900;
}
#back-to-top.cd-is-visible:hover {
visibility: visible;
opacity: 1;
z-index: 900;
}
#back-to-top.cd-fade-out {
opacity: 0.5;
}
.input-searching {
background: #FFBF91;
}
.deleteicon:hover {
color: black;
}
.deleteicon {
color: gray;
width: 30px;
height: 30px;
position: absolute;
margin-left: -30px;
bottom: 7px;
right: 17px;
float: right;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.input-group-addon {
min-width: 40px;
}
.info-box-icon i {
color: #fff;
}
.progress-description,
.info-box-text {
white-space: normal;
overflow: auto;
}
.colorpicker,
.colorpicker * {
z-index: 9999
}
.signature-pad {
width: 100%;
height: 100%;
font-size: 10px;
border: 1px solid #e8e8e8;
background-color: #fff;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset;
border-radius: 4px;
}
.signature-pad:before,
.signature-pad:after {
content: "";
width: 40%;
height: 10px;
left: 20px;
bottom: 10px;
background: transparent;
-webkit-transform: skew(-3deg) rotate(-3deg);
-moz-transform: skew(-3deg) rotate(-3deg);
-ms-transform: skew(-3deg) rotate(-3deg);
-o-transform: skew(-3deg) rotate(-3deg);
transform: skew(-3deg) rotate(-3deg);
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.4);
}
.signature-pad:after {
left: auto;
right: 20px;
-webkit-transform: skew(3deg) rotate(3deg);
-moz-transform: skew(3deg) rotate(3deg);
-ms-transform: skew(3deg) rotate(3deg);
-o-transform: skew(3deg) rotate(3deg);
transform: skew(3deg) rotate(3deg);
}
@media screen and (max-width: 1024px) {
.signature-pad {
top: 0;
left: 0;
right: 0;
bottom: 0;
width: auto;
height: auto;
min-width: 250px;
min-height: 140px;
margin: 5%;
}
}
@media screen and (min-device-width: 768px) and (max-device-width: 1024px) {
.signature-pad {
margin: 10%;
}
}
#canvas {
width: 100%;
height: 100%;
min-height: 202px;
border-radius: 4px;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.02) inset;
}
.sidebar-menu li>a>.pull-right-container {
position: absolute;
padding: 12px;
right: 10px;
top: 50%;
margin-top: -19px;
}
.sidebar-form {
border-radius: 3px;
border-color: 1px;
margin: 10px 10px;
}
.sidebar-form input[type="text"],
.sidebar-form .btn {
border: 1px;
height: 35px;
-webkit-transition: all 0.3s ease-in-out;
-o-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
.sidebar-form input[type="text"] {
border-top-left-radius: 2px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: 2px;
}
.sidebar-form .btn {
border-top-left-radius: 0;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0;
}
.swal2-buttonswrapper .btn {
margin: 5px;
}
/* Personalizzazione del plugin Select2 */
.select2-search,
.select2-search__field {
width: 100%!important
}
.select2-results__option[aria-selected=true] {
display: none
}
.select2-container--bootstrap .select2-selection--multiple .select2-selection__choice {
margin: 2px 0 0 2px;
}
.select2-container--bootstrap .select2-selection--single .select2-selection__rendered {
padding: 4px;
}
.input-group-addon.no-padding {
border: 0px;
}
.input-group-addon.no-padding>* {
border-radius: 0px;
}

View File

@ -0,0 +1,214 @@
.skin-default .wrapper,
.skin-default .main-sidebar,
.skin-default .left-side {
background: #333;
}
.skin-default.login-page .wrapper {
background: #d2d6de;
}
.skin-default .content-wrapper,
.skin-default .content {
background: #f6f6f6;
}
.skin-default #supersearch {
color: #eee;
}
.skin-default #supersearch:focus {
color: #222;
}
.skin-default .inner {
color: #eee;
}
.skin-default .nav-tabs-custom .nav-tabs li a {
color: #3c8dbc;
}
.skin-default .nav-tabs-custom .nav-tabs li.active a {
color: inherit;
}
.skin-default .nav-tabs-custom .nav-tabs.pull-right li a.back-btn {
color: #3C8DBC;
}
.skin-default .nav-tabs-custom .nav-tabs.pull-right li a.back-btn:hover {
color: #72AFD2;
}
.skin-default .main-header .navbar {
color: #eee;
background: #222;
border: none;
}
.skin-default .main-header .navbar .nav li a
.skin-default .main-header .navbar .nav li a:hover,
.skin-default .main-header .navbar .nav li a:active,
.skin-default .main-header .navbar .nav li a:focus,
.skin-default .main-header .navbar .nav .open a,
.skin-default .main-header .navbar .nav .open a:hover,
.skin-default .main-header .navbar .nav .open a:focus,
.skin-default .main-header .navbar .nav .active a,
.skin-default .main-header .navbar .nav .actual a {
background: rgba(0, 0, 0, 0.2);
color: #f6f6f6;
}
.skin-default .main-header .navbar .sidebar-toggle,
.skin-default .main-header .navbar .sidebar-toggle .icon-bar {
color: #f6f6f6;
}
.skin-default .main-header .navbar .sidebar-toggle:hover {
color: #f6f6f6;
background: rgba(0, 0, 0, 0.2);
}
.skin-default .main-header .navbar .sidebar-toggle {
color: #f6f6f6;
}
.skin-default .main-header .navbar .sidebar-toggle:hover {
background: #222;
}
@media (max-width: 767px) {
.skin-default .main-header .navbar .dropdown-menu li.divider {
background: rgba(255, 255, 255, 0.1);
}
.skin-default .main-header .navbar .dropdown-menu li a {
color: #f6f6f6;
}
.skin-default .main-header .navbar .dropdown-menu li a:hover {
background: #222;
}
}
.skin-default .main-header .navbar .sidebar-toggle .icon-bar {
background: #f6f6f6;
}
.skin-default .main-header .logo {
background: #222;
color: #f6f6f6;
border-bottom: 0 solid transparent;
}
.skin-default .main-header .logo:hover {
background: #222;
}
.skin-default .main-header li.user-header {
background: #222;
}
.skin-default .main-header a {
text-decoration: none;
}
.skin-default .content-header {
background: transparent;
}
.skin-default .user-panel .info,
.skin-default .user-panel .info a {
color: #f6f6f6;
}
.skin-default .sidebar-menu li.header {
color: #4b646f;
background: #222;
}
.skin-default .sidebar-menu li a {
border-left: 3px solid transparent;
}
.skin-default .sidebar-menu li:hover a,
.skin-default .sidebar-menu li.active a,
.skin-default .sidebar-menu li.actual a {
background: #222;
border-left-color: #222;
}
.skin-default .sidebar-menu li:hover>a,
.skin-default .sidebar-menu li.actual>a {
color: #f6f6f6;
}
.skin-default .sidebar-menu li .treeview-menu {
margin: 0 1px;
background: #222;
}
.skin-default .sidebar a {
color: #f6f6f6;
}
.skin-default .sidebar a:hover {
text-decoration: none;
}
.skin-default .treeview-menu li a {
color: #f6f6f6;
}
.skin-default .sidebar-form {
border-color: #222;
}
.skin-default .sidebar-form input[type="text"],
.skin-default .sidebar-form .btn {
box-shadow: none;
background: #222;
border-color: transparent;
}
.skin-default .sidebar-form input[type="text"] {
color: #666;
}
.skin-default .sidebar-form input[type="text"]:focus,
.skin-default .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
background: #f6f6f6;
color: #666;
}
.skin-default .sidebar-form input[type="text"]:focus+.input-group-btn .btn {
border-left-color: #f6f6f6;
}
.skin-default .sidebar-form .btn {
color: #999;
}
.skin-default .main-sidebar li,
.skin-default .main-sidebar li a {
color: #ccc;
}
.skin-default .panel-primary .panel-heading {
border-bottom: 2px solid #57a;
}
.skin-default .ui-autocomplete {
background: #f6f6f6;
border-color: #ccc;
border-color: rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
}
.skin-default .parsley-errors-list{
color: red;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
assets/src/img/help.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
assets/src/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
assets/src/img/progress.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

41
assets/src/js/custom.js Normal file
View File

@ -0,0 +1,41 @@
$(document).ready(function () {
var animationSpeed = 500;
$(document).off('click', '.sidebar li a')
.on('click', '.sidebar li a', function (e) {
//Get the clicked link and the next element
var $this = $(this);
var checkElement = $this.next();
//Check if the next element is a menu and is visible
if ((checkElement.is('.treeview-menu')) && (checkElement.is(':visible')) && (!$('body').hasClass('sidebar-collapse'))) {
//Close the menu
checkElement.slideUp(animationSpeed, function () {
checkElement.removeClass('menu-open');
});
checkElement.parent("li").removeClass("active");
}
//If the menu is not visible
else if ((checkElement.is('.treeview-menu')) && (!checkElement.is(':visible'))) {
//Get the parent menu
var parent = $this.parents('ul').first();
//Close all open menus within the parent
var ul = parent.find('ul:visible').slideUp(animationSpeed);
//Remove the menu-open class from the parent
ul.removeClass('menu-open');
//Get the parent li
var parent_li = $this.parent("li");
//Open the target menu and add the menu-open class
checkElement.slideDown(animationSpeed, function () {
//Add the class active to the parent li
checkElement.addClass('menu-open');
parent.find('li.active').removeClass('active');
parent_li.addClass('active');
});
}
//if this isn't a link, prevent the page from being redirected
if (checkElement.is('.treeview-menu') && $(event.target).is('.pull-right-container')) {
e.preventDefault();
}
});
});

View File

@ -0,0 +1,23 @@
{
"sEmptyTable": "Nessun dato presente nella tabella",
"sInfo": "Vista da _START_ a _END_ di _TOTAL_ elementi",
"sInfoEmpty": "Vista da 0 a 0 di 0 elementi",
"sInfoFiltered": "(filtrati da _MAX_ elementi totali)",
"sInfoPostFix": "",
"sInfoThousands": ".",
"sLengthMenu": "Visualizza _MENU_ elementi",
"sLoadingRecords": "Caricamento...",
"sProcessing": "Elaborazione...",
"sSearch": "Cerca:",
"sZeroRecords": "La ricerca non ha portato alcun risultato.",
"oPaginate": {
"sFirst": "Inizio",
"sPrevious": "Precedente",
"sNext": "Successivo",
"sLast": "Fine"
},
"oAria": {
"sSortAscending": ": attiva per ordinare la colonna in ordine crescente",
"sSortDescending": ": attiva per ordinare la colonna in ordine decrescente"
}
}

1
backup/.htaccess Normal file
View File

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

275
bug.php Normal file
View File

@ -0,0 +1,275 @@
<?php
include_once __DIR__.'/core.php';
$pageTitle = 'Bug';
$jscript_modules[] = $js.'/ckeditor.js';
if (filter('op') == 'send') {
$dati = $post;
// Parametri e-mail
$replace = [
'Server SMTP' => 'email_host',
'Username SMTP' => 'email_username',
'Porta SMTP' => 'email_porta',
'Sicurezza SMTP' => 'email_secure',
'Password SMTP' => 'email_password',
];
$rs = $dbo->fetchArray("SELECT * FROM zz_settings WHERE sezione = 'Email'");
foreach ($rs as $r) {
if (!empty($replace[$r['nome']])) {
$dati[$replace[$r['nome']]] = $r['valore'];
}
}
// Preparazione email
$mail = new PHPMailer();
// Se non specificato l'host uso le impostazioni di invio mail di default del server
if (!empty($dati['email_host'])) {
$mail->IsSMTP();
$mail->IsHTML();
$mail->SMTPDebug = 2;
$mail->Host = $dati['email_host'];
$mail->Port = $dati['email_porta'];
// Controllo se è necessaria l'autenticazione per il server di posta
if (!empty($dati['email_username'])) {
$mail->SMTPAuth = true;
$mail->Username = $dati['email_username'];
$mail->Password = $dati['email_password'];
}
if (in_array(strtolower($dati['email_secure']), ['ssl', 'tls'])) {
$mail->SMTPSecure = strtolower($dati['email_secure']);
}
}
$mail->WordWrap = 50;
// Mittente
$mail->From = $dati['email_from'];
$mail->FromName = $_SESSION['username'];
$mail->AddReplyTo($dati['email_from']);
// Destinatario
$mail->AddAddress($dati['email_to']);
// Copia
if (!empty($dati['email_cc'])) {
$mail->AddCC($dati['email_cc']);
}
// Copia nascosta
if (!empty($dati['email_bcc'])) {
$mail->AddBCC($dati['email_bcc']);
}
$mail->Subject = 'Segnalazione bug OSM '.$version.' ('.(!empty($revision) ? 'R'.$revision : _('In sviluppo')).')';
$mail->AltBody = _('Questa email arriva dal modulo bug di segnalazione bug di OSM');
$body = $dati['body'].'<hr><br>'._('IP').': '.get_client_ip()."<br>\n";
// Se ho scelto di inoltrare i file di log, allego
if (!empty($post['log']) && file_exists($docroot.'/logs/error.log')) {
$mail->AddAttachment($docroot.'/logs/error.log');
}
// Se ho scelto di inoltrare copia del db
if (!empty($post['sql'])) {
$dump = "SET foreign_key_checks = 0;\n";
$dump .= backup_tables();
$dump .= "SET foreign_key_checks = 1;\n";
$backup_file = 'Backup OSM '.date('Y-m-d').' '.date('H_i_s').'.sql';
if (file_put_contents($docroot.'/'.$backup_file, $dump)) {
$mail->AddAttachment($docroot.'/'.$backup_file);
$_SESSION['infos'][] = _('Backup del database eseguito ed allegato correttamente!');
} else {
$_SESSION['errors'][] = _('Errore durante la creazione del file di backup!');
}
}
// Se ho scelto di inoltrare le INFO del mio sistema
if (!empty($post['info'])) {
$body .= $_SERVER['HTTP_USER_AGENT'].' - '.getOS();
}
$mail->Body = $body;
// Invio mail
if (!$mail->send()) {
$_SESSION['errors'][] = _("Errore durante l'invio della segnalazione").': '.$mail->ErrorInfo;
} else {
$_SESSION['infos'][] = _('Email inviata correttamente!');
}
$mail->SmtpClose();
if (!empty($post['sql'])) {
unlink($docroot.'/'.$backup_file);
}
redirect($rootdir.'/bug.php');
exit();
}
if (file_exists($docroot.'/include/custom/top.php')) {
include $docroot.'/include/custom/top.php';
} else {
include $docroot.'/include/top.php';
}
$email_to = '';
$email_from = '';
$rs = $dbo->fetchArray("SELECT * FROM zz_settings WHERE sezione = 'Email'");
foreach ($rs as $r) {
if (($r['nome'] == 'Server SMTP' || $r['nome'] == 'Indirizzo per le email in uscita' || $r['nome'] == 'Destinatario') && $r['valore'] == '') {
$alert = true;
}
if ($r['nome'] == 'Destinatario') {
$email_to = $r['valore'];
} elseif ($r['nome'] == 'Indirizzo per le email in uscita') {
$email_from = $r['valore'];
}
}
if (!empty($alert)) {
echo '
<div class="alert alert-warning">
<i class="fa fa-warning"></i>
<b>'._('Attenzione!').'</b> '._('Per utilizzare correttamente il modulo di segnalazione bug devi configurare alcuni parametri email nella scheda impostazioni').'.
'.Modules::link('Opzioni', $dbo->fetchArray("SELECT `idimpostazione` FROM `zz_settings` WHERE sezione='Email'")[0]['idimpostazione'], _('Correggi'), null, 'class="btn btn-warning pull-right"').'
<div class="clearfix"></div>
</div>';
}
echo '
<div class="box">
<div class="box-header">
<h3 class="box-title"><i class="fa fa-bug"></i>'._('Segnalazione bug').'</h3></h3>
</div>
<div class="box-body">
<form method="post" action="'.$rootdir.'/bug.php?op=send">
<table class="table table-bordered table-condensed table-striped table-hover">
<tr>
<th width="150" class="text-right">'._('Da').':</th>
<td>
{[ "type": "email", "placeholder": "'._('Mittente').'", "name": "email_from", "value": "'.$email_from.'", "required": 1 ]}
</td>
</tr>
<!-- A -->
<tr>
<th class="text-right">'._('A').':</th>
<td>
{[ "type": "email", "placeholder": "'._('Destinatario').'", "name": "email_to", "value": "'.$email_to.'", "required": 1 ]}
</td>
</tr>
<!-- Cc -->
<tr>
<th class="text-right">'._('Cc').':</th>
<td>
{[ "type": "email", "placeholder": "'._('Copia a').'...", "name": "email_cc" ]}
</td>
</tr>
<!-- Bcc -->
<tr>
<th class="text-right">'._('Bcc').':</th>
<td>
{[ "type": "email", "placeholder": "'._('Copia nascosta a').'...", "name": "email_bcc" ]}
</td>
</tr>
<!-- Versione -->
<tr>
<th class="text-right">'._('Versione OSM').':</th>
<td>
{[ "type": "span", "placeholder": "'._('Versione OSM').'", "value": "'.$version.' ('.(!empty($revision) ? 'R'.$revision : _('In sviluppo')).')" ]}
</td>
</tr>
</table>
<div class="row">
<div class="col-xs-12 col-md-4">
{[ "type": "checkbox", "placeholder": "'._('Allega file di log').'", "name": "log", "value": "1" ]}
</div>
<div class="col-xs-12 col-md-4">
{[ "type": "checkbox", "placeholder": "'._('Allega copia del database').'", "name": "sql", "value": "0" ]}
</div>
<div class="col-xs-12 col-md-4">
{[ "type": "checkbox", "placeholder": "'._('Allega informazioni sul PC').'", "name": "info", "value": "1" ]}
</div>
</div>
<div class="clearfix"></div>
<br>
{[ "type": "textarea", "label": "'._('Descrizione del bug').'", "name": "body" ]}
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary" id="send" disabled><i class="fa fa-envelope"></i> '._('Invia segnalazione').'</button>
</div>
</div>
</form>
</div>
</div>
<script>
$(document).ready(function(){
var html = "<p>'._('Se hai riscontrato un bug ricordati di specificare').':</p>" +
"<ul>" +
"<li>'._('Modulo esatto (o pagina relativa) in cui questi si è verificato').';</li>" +
"<li>'._('Dopo quali specifiche operazioni hai notato il malfunzionameto').'.</li>" +
"</ul>" +
"<p>'._('Assicurati inoltre di controllare che il checkbox relativo ai file di log sia contrassegnato, oppure riporta qui l\'errore visualizzato').'.</p>" +
"<p>'._('Ti ringraziamo per il tuo contributo').',<br>" +
"'._('Lo staff di OSM').'</p>";
var firstFocus = 1;
CKEDITOR.replace("body", {
toolbar: [
{ name: "document", items: [ "NewPage", "Preview", "-", "Templates" ] }, // Defines toolbar group with name (used to create voice label) and items in 3 subgroups
["Bold","Italic","Underline","Superscript","-","NumberedList","BulletedList","Outdent","Indent","Blockquote","-","Format",], // Defines toolbar group without name
]
});
CKEDITOR.instances.body.on("key", function() {
setTimeout(function(){
if(CKEDITOR.instances.body.getData() == ""){
$("#send").prop("disabled", true);
}
else $("#send").prop("disabled", false);
}, 10);
});
CKEDITOR.instances.body.setData( html, function() {});
CKEDITOR.instances.body.on("focus", function() {
if(firstFocus){
CKEDITOR.instances.body.setData("", function() {
CKEDITOR.instances.body.focus();
});
firstFocus = 0;
}
});
});
</script>';
if (file_exists($docroot.'/include/custom/bottom.php')) {
include $docroot.'/include/custom/bottom.php';
} else {
include $docroot.'/include/bottom.php';
}

24
call.php Normal file
View File

@ -0,0 +1,24 @@
<?php
include_once __DIR__.'/core.php';
$id_module = filter('id_module');
$id_record = filter('id_record');
$posizione = $id_module;
if (isset($id_record)) {
$posizione .= ', '.$id_record;
}
$dbo->query('UPDATE zz_semaphores SET updated_at = NOW() WHERE id_utente = '.prepare($_SESSION['idutente']).' AND posizione = '.prepare($posizione));
$dbo->query('DELETE FROM zz_semaphores WHERE DATE_ADD(updated_at, INTERVAL '.(get_var('Timeout notifica di presenza (minuti)') * 2).' SECOND) <= NOW()');
$datas = $dbo->fetchArray('SELECT DISTINCT * FROM zz_semaphores INNER JOIN zz_users ON zz_semaphores.id_utente=zz_users.idutente WHERE id_utente != '.prepare($_SESSION['idutente']).' AND posizione = '.prepare($posizione));
$result = [];
if ($datas != null) {
foreach ($datas as $data) {
array_push($result, ['username' => $data['username']]);
}
}
echo json_encode($result);

57
composer.json Normal file
View File

@ -0,0 +1,57 @@
{
"name": "openstamanager/openstamanager",
"description": "Gestionale open source per assistenza tecnica e fatturazione",
"version": "2.3.0",
"license": "GPL-3.0",
"keywords": [
"open source",
"gestionale",
"assistenza tecnica",
"fatturazione"
],
"homepage": "http://openstamanager.com/",
"authors": [{
"name": "Fabio Lovato",
"email": "info@openstamanager.com"
}, {
"name": "Fabio Piovan",
"email": "info@openstamanager.com"
}, {
"name": "Luca Salvà",
"email": "info@openstamanager.com"
}],
"type": "project",
"require": {
"php": ">=5.4",
"ezyang/htmlpurifier": "^4.8",
"filp/whoops": "^2.1",
"intervention/image": "^2.3",
"ircmaxell/password-compat": "^1.0",
"maximebf/debugbar": "^1.13",
"monolog/monolog": "^1.22",
"paragonie/random_compat": "^2.0",
"phpmailer/phpmailer": "^5.2",
"spipu/html2pdf": "^4.6",
"symfony/translation": "^3.2"
},
"autoload": {
"psr-4": {
"": "lib/classes/",
"Module\\": "modules/"
},
"files": [
"lib/functions.php",
"lib/util.php",
"lib/deprecated.php"
]
},
"scripts": {
"post-create-project-cmd": "yarn run release-OSM"
},
"config": {
"sort-packages": true,
"optimize-autoloader": true,
"apcu-autoloader": true,
"prefer-stable": true
}
}

22
config.example.php Normal file
View File

@ -0,0 +1,22 @@
<?php
$db_host = '|host|';
$db_username = '|username|';
$db_password = '|password|';
$db_name = '|database|';
$backup_dir = __DIR__.'/backup/';
$theme = 'default';
$redirectHTTPS = false;
$debug = false;
$strict = false;
$HTMLWrapper = null;
$HTMLHandlers = [];
$HTMLManagers = [];
$lang = 'it';
$formatter = [];

101
controller.php Normal file
View File

@ -0,0 +1,101 @@
<?php
include_once __DIR__.'/core.php';
if (file_exists($docroot.'/include/custom/top.php')) {
include $docroot.'/include/custom/top.php';
} else {
include $docroot.'/include/top.php';
}
// Lettura parametri iniziali del modulo
$module = Modules::getModule($id_module);
if (empty($module) || empty($module['enabled'])) {
die(_('Accesso negato'));
}
$module_dir = $module['directory'];
include $docroot.'/actions.php';
/*
* Widget top
*/
echo Widgets::addModuleWidgets($id_module, 'controller_top');
// Lettura eventuali plugins modulo da inserire come tab
echo '
<div class="nav-tabs-custom">
<ul class="nav nav-tabs pull-right" role="tablist">
<li class="pull-left active header">';
// Verifico se ho impostato un nome modulo personalizzato
$name = $module['title'];
echo '
<a data-toggle="tab" href="#tab_0">
<i class="'.$module['icon'].'"></i> '.$name;
// Pulsante "Aggiungi" solo se il modulo è di tipo "table" e se esiste il template per la popup
if (file_exists($docroot.'/modules/'.$module_dir.'/add.php') && $module['permessi'] == 'rw') {
echo '
<button type="button" class="btn btn-primary" data-toggle="modal" data-title="'._('Aggiungi').'..." data-target="#bs-popup" data-href="add.php?id_module='.$id_module.'"><i class="fa fa-plus"></i></button>';
}
echo '
</a>
</li>';
$plugins = $dbo->fetchArray('SELECT id, title FROM zz_plugins WHERE idmodule_to='.prepare($id_module)." AND position='tab_main' AND enabled = 1");
foreach ($plugins as $plugin) {
echo '
<li>
<a data-toggle="tab" href="#tab_'.$plugin['id'].'" id="link-tab_'.$plugin['id'].'">'.$plugin['title'].'</a>
</li>';
}
echo '
</ul>
<div class="tab-content">
<div id="tab_0" class="tab-pane active">';
include $docroot.'/include/manager.php';
echo '
</div>';
// Inclusione contenuti varie tab dei plugin
foreach ($plugins as $plugin) {
echo '
<div id="tab_'.$plugin['id'].'" class="tab-pane">';
$id_plugin = $plugin['id'];
include $docroot.'/include/manager.php';
echo '
</div>';
}
echo '
</div>
</div>
</div>';
/**
* Widget laterali.
*/
// Controllo se ho widget per il lato destro dello schermo, altrimenti non creo la colonna di destra
$result_widgets = $dbo->fetchArray('SELECT `id`, `location`, `class` FROM `zz_widgets` WHERE `id_module`='.prepare($id_module)." AND `location`='controller_right' AND `enabled`=1 ORDER BY `order` ASC");
if (count($result_widgets) > 0) {
echo '
<div class="col-md-12">';
echo Widgets::addModuleWidgets($id_module, 'controller_right');
echo '
</div>';
}
if (file_exists($docroot.'/include/custom/bottom.php')) {
include $docroot.'/include/custom/bottom.php';
} else {
include $docroot.'/include/bottom.php';
}

264
core.php Normal file
View File

@ -0,0 +1,264 @@
<?php
// Impostazioni per la corretta interpretazione di UTF-8
header('Content-Type: text/html; charset=UTF-8');
$handler = null;
if (extension_loaded('mbstring')) {
mb_internal_encoding('UTF-8');
mb_http_output('UTF-8');
mb_http_input('UTF-8');
mb_language('uni');
mb_regex_encoding('UTF-8');
$handler = 'mb_output_handler';
}
ob_start($handler);
// Impostazioni di configurazione PHP
date_default_timezone_set('Europe/Rome');
// Caricamento delle impostazioni personalizzabili
if (file_exists(__DIR__.'/config.inc.php')) {
include_once __DIR__.'/config.inc.php';
}
// Individuazione dei percorsi di base
$docroot = __DIR__;
$rootdir = substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
if (strrpos($rootdir, '/'.basename($docroot).'/') !== false) {
$rootdir = substr($rootdir, 0, strrpos($rootdir, '/'.basename($docroot).'/')).'/'.basename($docroot);
}
$rootdir = str_replace('%2F', '/', rawurlencode($rootdir));
// Aggiunta delle variabili globali
define('DOCROOT', $docroot);
define('ROOTDIR', $rootdir);
// Caricamento delle dipendenze e delle librerie del progetto
require_once __DIR__.'/vendor/autoload.php';
// Forzamento del debug
// $debug = true;
/*
// Controllo CSRF
if(!CSRF::getInstance()->validate()){
die(_('Constrollo CSRF fallito!'));
}*/
// Logger per la segnalazione degli errori
$logger = new Monolog\Logger(_('OpenSTAManager'));
$logger->pushProcessor(new Monolog\Processor\UidProcessor());
$logger->pushProcessor(new Monolog\Processor\WebProcessor());
use Monolog\Handler\StreamHandler;
use Monolog\Handler\RotatingFileHandler;
$handlers = [];
// File di log di base (logs/all.log)
$handlers[] = new StreamHandler(__DIR__.'/logs/error.log', Monolog\Logger::ERROR);
$handlers[] = new StreamHandler(__DIR__.'/logs/setup.log', Monolog\Logger::EMERGENCY);
// Impostazioni di debug
if (!empty($debug)) {
if (empty($strict)) {
// Ignoramento degli avvertimenti e delle informazioni relative alla deprecazione di componenti
error_reporting(E_ALL & ~E_NOTICE & ~E_USER_DEPRECATED);
}
// File di log ordinato in base alla data
$handlers[] = new RotatingFileHandler(__DIR__.'/logs/error.log', 0, Monolog\Logger::ERROR);
$handlers[] = new RotatingFileHandler(__DIR__.'/logs/setup.log', 0, Monolog\Logger::EMERGENCY);
if (version_compare(PHP_VERSION, '5.5.9') >= 0) {
$prettyPageHandler = new Whoops\Handler\PrettyPageHandler();
// Imposta Whoops come gestore delle eccezioni di default
$whoops = new Whoops\Run();
$whoops->pushHandler($prettyPageHandler);
// Abilita la gestione degli errori nel caso la richiesta sia di tipo AJAX
if (\Whoops\Util\Misc::isAjaxRequest()) {
$whoops->pushHandler(new Whoops\Handler\JsonResponseHandler());
}
$whoops->register();
}
// Istanziamento della barra di debug
$debugbar = new DebugBar\StandardDebugBar();
$debugbar->addCollector(new DebugBar\Bridge\MonologCollector($logger));
} else {
// Disabilita la segnalazione degli errori
error_reporting(0);
}
// Imposta il formato di salvataggio dei log
$monologFormatter = new Monolog\Formatter\LineFormatter('[%datetime%] %channel%.%level_name%: %message% %extra%'.PHP_EOL);
foreach ($handlers as $handler) {
$logger->pushHandler($handler->setFormatter($monologFormatter));
}
// Imposta Monolog come gestore degli errori (si sovrappone a Whoops)
Monolog\ErrorHandler::register($logger);
// Istanziamento della gestione di date e numeri
$formatter = !empty($formatter) ? $formatter : [];
Translator::setLocaleFormatter($formatter);
// Aggiunta del wrapper personalizzato per la generazione degli input
if (!empty($HTMLWrapper)) {
HTMLBuilder\HTMLBuilder::setWrapper($HTMLWrapper);
}
// Aggiunta dei gestori personalizzati per la generazione degli input
foreach ((array) $HTMLHandlers as $key => $value) {
HTMLBuilder\HTMLBuilder::setHandler($key, $value);
}
// Aggiunta dei gestori per componenti personalizzate
foreach ((array) $HTMLManagers as $key => $value) {
HTMLBuilder\HTMLBuilder::setManager($key, $value);
}
// Registrazione globale del template per gli input HTML
register_shutdown_function('translateTemplate');
// Redirect al percorso HTTPS se impostato nella configurazione
if (!empty($redirectHTTPS) && !isHTTPS(true)) {
header('HTTP/1.1 301 Moved Permanently');
header('Location: https://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
exit();
}
session_set_cookie_params(0, $rootdir);
session_start();
// Impostazione della sessione di base
$_SESSION['infos'] = isset($_SESSION['infos']) ? $_SESSION['infos'] : [];
$_SESSION['warnings'] = isset($_SESSION['warnings']) ? $_SESSION['warnings'] : [];
$_SESSION['errors'] = (array) $_SESSION['errors'];
// Imposto il periodo di visualizzazione dei record dal 01-01-yyy al 31-12-yyyy
if (!empty($_GET['period_start'])) {
$_SESSION['period_start'] = $_GET['period_start'];
$_SESSION['period_end'] = $_GET['period_end'];
} elseif (!isset($_SESSION['period_start'])) {
$_SESSION['period_start'] = date('Y').'-01-01';
$_SESSION['period_end'] = date('Y').'-12-31';
}
// Impostazione del tema grafico di default
$theme = !empty($theme) ? $theme : 'default';
// Istanziamento del gestore delle traduzioni del progetto
$lang = !empty($lang) ? $lang : 'it';
$translator = new Translator($lang);
$translator->addLocalePath($docroot.'/locale');
$translator->addLocalePath($docroot.'/modules/*/locale');
// Istanziamento del gestore degli utenti
if (!Update::isUpdateAvailable()) {
$auth = new Auth();
}
$version = Update::getVersion();
$revision = Update::getRevision();
$assets = $rootdir.'/assets/dist';
$css = $assets.'/css';
$js = $assets.'/js';
$img = $assets.'/img';
// CSS di base del progetto
$css_modules = [];
$css_modules[] = $css.'/app.min.css';
$css_modules[] = $css.'/style.min.css';
$css_modules[] = $css.'/themes.min.css';
$css_modules[] = [
'href' => $css.'/print.min.css',
'media' => 'print',
];
// JS di base del progetto
$jscript_modules = [];
$jscript_modules[] = $js.'/app.min.js';
$jscript_modules[] = $js.'/custom.min.js';
$jscript_modules[] = $js.'/i18n/parsleyjs/'.$lang.'.min.js';
$jscript_modules[] = $js.'/i18n/select2/'.$lang.'.min.js';
$jscript_modules[] = $js.'/i18n/moment/'.$lang.'.min.js';
$jscript_modules[] = $js.'/i18n/fullcalendar/'.$lang.'.min.js';
if (Auth::check()) {
$jscript_modules[] = $rootdir.'/lib/functions.js';
$jscript_modules[] = $rootdir.'/lib/init.js';
}
$dbo = Database::getConnection();
// Controllo sull'esistenza delle informazioni necessarie prima di effettuare la connessione al database
if ($dbo->isConnected() && $dbo->isInstalled() && (Auth::check() || API::isAPIRequest()) && !Update::isUpdateAvailable()) {
if (!empty($debugbar)) {
$debugbar->addCollector(new DebugBar\DataCollector\PDO\PDOCollector($dbo->getPDO()));
}
$id_module = filter('id_module');
$id_record = filter('id_record');
$id_plugin = filter('id_plugin');
$id_parent = filter('id_parent');
/*
* Creazione array con l'elenco dei moduli
* es. $modules['Anagrafiche']['nome_campo'];
*/
$rs = $dbo->fetchArray('SELECT * FROM `zz_modules` LEFT JOIN (SELECT `idmodule`, `permessi` FROM `zz_permissions` WHERE `idgruppo`=(SELECT `idgruppo` FROM `zz_users` WHERE `idutente`='.prepare($_SESSION['idutente']).')) AS `zz_permissions` ON `zz_modules`.`id`=`zz_permissions`.`idmodule` LEFT JOIN (SELECT `idmodule`, `clause` FROM `zz_group_module` WHERE `idgruppo`=(SELECT `idgruppo` FROM `zz_users` WHERE `idutente`='.prepare($_SESSION['idutente']).')) AS `zz_group_module` ON `zz_modules`.`id`=`zz_group_module`.`idmodule`');
$modules_info = [];
for ($i = 0; $i < count($rs); ++$i) {
foreach ($rs[$i] as $name => $value) {
if ($name == 'permessi' && (Auth::isAdmin() || $value == null)) {
if (Auth::isAdmin()) {
$value = 'rw';
} else {
$value = '-';
}
}
if ($name != 'idmodule' && $name != 'updated_at' && $name != 'created_at' && $name != 'clause') {
$modules_info[$rs[$i]['name']][$name] = $value;
} elseif ($name == 'clause') {
$additional_where[$rs[$i]['name']] = !empty($value) ? ' AND '.$value : $value;
}
}
$modules_info[$rs[$i]['id']]['name'] = $rs[$i]['name'];
}
$user = Auth::getUser();
$user_idanagrafica = $user['idanagrafica'];
if (!empty($id_module)) {
$module = Modules::getModule($id_module);
$pageTitle = $module['title'];
Permissions::addModule($id_module);
}
if (!empty($skip_permissions)) {
Permissions::skip();
}
Permissions::check();
} elseif (slashes($_SERVER['SCRIPT_FILENAME']) != slashes(DOCROOT.'/index.php')) {
redirect(ROOTDIR.'/index.php?op=logout');
exit();
}
// Istanziamento di HTMLHelper
$html = new HTMLHelper();
// Variabili GET e POST
$post = Filter::getPOST();
$get = Filter::getGET();

47
couscous.yml Normal file
View File

@ -0,0 +1,47 @@
template:
url: https://github.com/pnowy/CouscousNativeTemplate
include:
- docs
# Base URL of the published website (no "/" at the end!)
baseUrl: /osm/website
title: OpenSTAManager
subTitle: Il gestionale open source per l'assistenza tecnica e la fatturazione
fontAwesomeIcon: fa fa-cog
# The left menu bar
menu:
sections:
main:
name: Documentazione di base
items:
home:
text: Home page
relativeUrl: index.html
installazione:
text: Installazione
relativeUrl: installazione.html
framework:
text: Framework
relativeUrl: framework.html
assets:
text: Assets
relativeUrl: assets.html
moduli:
text: Moduli
relativeUrl: moduli.html
other:
name: Approfondimenti
items:
api:
text: API
relativeUrl: api.html
docs:
text: Documentazione completa
relativeUrl: docs/
osm:
text: Sito ufficiale
absoluteUrl: http://www.openstamanager.com/

1
docs/.htaccess Normal file
View File

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

110
docs/API.md Normal file
View File

@ -0,0 +1,110 @@
---
currentMenu: api
---
# API
> Con application programming interface (in acronimo API, in italiano interfaccia di programmazione di un'applicazione), in informatica, si indica ogni insieme di procedure disponibili al programmatore, di solito raggruppate a formare un set di strumenti specifici per l'espletamento di un determinato compito all'interno di un certo programma.
>
> \-- <cite>[Wikipedia](https://it.wikipedia.org/wiki/Application_programming_interface)</cite>
L'API del progetto è attualmente ancora in sviluppo, e pertanto le funzioni disponibili potrebbero essere piuttosto ridotte. Di seguito sono elencate le basi per connettersi al sistema e ottenere i dati a cui si è interessati.
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Accesso](#accesso)
- [Output](#output)
- [Messaggi](#messaggi)
- [Formato dei componenti](#formato-dei-componenti)
- [Richieste di lettura](#richieste-di-lettura)
- [Interventi](#interventi)
- [Anagrafiche](#anagrafiche)
- [Richieste disabilitate](#richieste-disabilitate)
- [Modifiche](#modifiche)
- [Eliminazioni](#eliminazioni)
<!-- /TOC -->
## Accesso
L'accesso all'API viene effettuato concatenendo la chiave dell'utenza all'URL del sito su cui è ospitato il progetto.
http://<url_osm>/api/?token=<token>
La chiave di accesso è ottenibile eseguendo la seguente query all'interno del database del progetto:
```sql
SELECT `token` FROM `zz_tokens` WHERE `id_utente` = <id_utente>
```
## Output
L'API del progetto permette di ottenere le informazioni attraverso un array in formato JSON.
Per poter interpretare correttamente i dati, si devono ignorare gli indici numerici di primo livello (non rilevanti all'interno del formato) e sfruttare in particolare i seguenti campi generici:
- `records`, rappresentante il numero totale dei record richiesti;
- `pages`, indicante il numero totale della pagine disponibili.
Si ricorda che l'API prevede la restituzione di un insieme di dati limitato rispetto alla richiesta effettuatua: per ottenere l'intero insieme di informazioni è necessario eseguire molteplici richieste consecutive basate sul campo `page`.
## Messaggi
Ogni richiesta effettuata all'API viene accompagnata da un messaggio predefinito che permette di interpretare in modo più preciso la risposta.
In particolare, sono presenti i seguenti _status_:
- `200: OK` - La richiesta è andata a buon fine.
- `400: Errore interno dell'API` - La richiesta effettuata risulta invalida per l'API.
- `401: Non autorizzato` - Accesso non autorizzato.
- `404: Non trovato` - La risorsa richiesta non risulta disponibile.
- `500: Errore del server` - Il gestionale non è in grado di completare la richiesta.
## Formato dei componenti
I seguenti componenti delle richieste devono seguire una rigida struttura:
- `page` (intero).
- `upd` (yyyy-MM-dd hh:mm:ss).
## Richieste di lettura
### Interventi
Tutto il contenuto della tabella in_interventi:
http://<url_osm>/api/?token=<token>&resource=in_interventi
Singolo intervento (riga della tabella):
http://<url_osm>/api/?token=<token>&resource=in_interventi&filter[id]=[1]
### Anagrafiche
Tutto il contenuto della tabella an_anagrafiche:
http://<url_osm>/api/?token=<token>&resource=an_anagrafiche
Singolo intervento (riga della tabella):
http://<url_osm>/api/?token=<token>&resource=an_anagrafiche&filter[idanagrafica]=[1]
Ricerca per ragione sociale:
http://<url_osm>/api/?token=<token>&resource=an_anagrafiche&filter[ragione_sociale]=[%<stringa_ragione_sociale>%]
### Richieste disabilitate
#### Modifiche
Tutti i contenuti di tutte le tabelle:
http://<url_osm>/api/?token=<token>&resource=updates
Tutti i contenuti di tutte le tabelle, aggiornati a partire da una data precisa:
http://<url_osm>/api/?token=<token>&resource=updates&upd=2016-01-31%2010:44:31
#### Eliminazioni
Tutte le eliminazioni di tutte le tabelle:
http://<url_osm>/api/?token=<token>&resource=deleted

107
docs/Assets.md Normal file
View File

@ -0,0 +1,107 @@
---
currentMenu: assets
---
# Assets
> Web assets are things like CSS, JavaScript and image files that make the frontend of your site look and work great.
>
> \-- <cite>[Symfony](http://symfony.com/doc/current/best_practices/web-assets.html)</cite>
Gli assets sono, allinterno dei moderni ambienti di sviluppo web, il cuore pulsante del software in relazione al layout e al livello di accessibilità; in particolare,il termine assets fa solitamente riferimento ai componenti di natura grafica di un software, quali immagini, fonts e icone, linguaggi di scripting client-side (JavaScript) e fogli di stile a cascata (_Cascading Style Sheets_).
Il progetto utilizza [Yarn](https://yarnpkg.com/) per gestire l'installazione e l'aggiornamento degli assets e [Gulp](http://gulpjs.com/) per compilarli e associarli con le personalizzazioni. Viene inoltre richiesta la presenza di [Git](https://git-scm.com/) asll'interno del sistema operativo.
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Struttura](#struttura)
- [Personalizzazione](#personalizzazione)
- [Tema grafico](#tema-grafico)
- [Aggiornamento e installazione pacchetti](#aggiornamento-e-installazione-pacchetti)
- [Compilazione](#compilazione)
- [Assets predefiniti](#assets-predefiniti)
<!-- /TOC -->
## Struttura
Yarn salva automaticamente gli assets da lui gestiti all'interno della cartella `node_modules`, non presente nella repository e nelle release del progetto per la sua natura estremamente variabile e facilmente riproducibile (tramite l'utilizzo dello strumento, come si vedrà in [Personalizzazione](#personalizzazione)).
Gli assets personalizzati del progetto sono al contrario contenuti all'interno della cartella `assets/src`; parallelamente, gli assets utilizzati direttamente dal progetto sono infine contenuti all'interno della cartella `assets/dist`, generata in automatico tramite l'utilizzo di [Gulp](http://gulpjs.com/).
## Personalizzazione
L'introduzione di una gestione automatizzata rende, di fatto, maggiromente semplificata la gestione delle dipendeze grafiche del progetto, portando però al tempo stesso alla necessità di utilizzare una specifica procedura per aggiornare e personalizzare gli assets.
Si ricorda che è altamente sconsigliato modificare i contenuti delle cartelle `node_modules` o `assets/dist` in modo manuale, poiché tali modifiche andrebbero perse a seguito di ogni aggiornamento.
### Tema grafico
La personalizzazione dello stile del gestionale può essere effettuata a partire dal foglio di stile `assets/src/css/themes/default.css`, contentente le principali impoistazioni grafiche del progetto.
L'aggiunta di un nuovo tema richieda la creazione di un file indipendente nella stessa cartella, rinominando la classe CSS generica con il nome della skin inserita (da `.skin-default` a `.skin-nome`).
Una volta eseguita la task automatica di compilazione, il nuovo file varrà aggiunto in `themes.min.css` di `assets/css`.
Per modificare lo stile utilizzato dal gestionale, vedere la variabile `$theme` in `config.inc.php`.
### Aggiornamento e installazione pacchetti
Nel caso si rivelasse necessario installare o aggiornare i pacchetti predisposti dal gestionale, è necessario procedere all'esecuzione dei comdani caratteristici di Yarn e successivamente eseguire una compliazione degli assets.
L'installazione di nuovi pacchetti viene eseguita attraverso il seguente comando:
```bash
yarn add <package>
```
L'aggiornamento degli assets gestiti è effettuabile tramite il seguente comando:
```bash
yarn upgrade
```
Per ulteriori informazioni, consultare la [documentazione ufficiale di Yarn](https://yarnpkg.com/en/docs).
### Compilazione
Per compilare gli assets, sia quelli gestiti da Yarn che quelli personalizzati, è necessario eseguire il seguente comando:
```bash
yarn run build-OSM
```
**Attenzione**: la compilazione è fondamentale a seguito di ogni modifica degli assets, poiché altrimenti i file utilizzati dal progetto non saranno aggiornati.
## Assets predefiniti
- admin-lte
- autosize
- bootstrap
- bootstrap-colorpicker
- bootstrap-daterangepicker
- bootstrap-switch
- ckeditor
- components-jqueryui
- datatables.net-bs
- datatables.net-scroller-bs
- eonasdan-bootstrap-datetimepicker
- font-awesome
- fullcalendar
- html5shiv
- inputmask
- jquery
- jquery-form
- jquery-slimscroll
- jquery-ui-touch-punch
- moment
- parsleyjs
- respond.js
- select2
- select2-bootstrap-theme
- signature_pad
- smartwizard
- sweetalert2
- tooltipster
_I nomi sono indicati secondo la notazione tipica dei pacchetti NPM._

10
docs/Contribuire.md Normal file
View File

@ -0,0 +1,10 @@
---
currentMenu: contribuire
---
# Contribuire
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
<!-- /TOC -->

36
docs/File.md Normal file
View File

@ -0,0 +1,36 @@
---
currentMenu: file
---
# File
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [MyImpianti](#myimpianti)
<!-- /TOC -->
## MyImpianti
La cartella _files_ contiene file di vari tipologie, raggruppati in base al modulo di cui fanno parte:
- Impostazione (`.ini`), utilizzate dai moduli abilitati in tal senso per ampliare l'offerta naturale degli stessi.
- File di cui viene effettuato l'upload all'interno dei vari moduli (riconosciuti dal gestionale tramite le funzioni interne al file `lib/modulebuilder.php`).
I file \*.ini devono seguire il seguente standard. {} = facoltativo
```ini
[Nome]
tipo = tag_HTML
valore ={ "Valore di default"}
{opzioni = "Opzione 1", "Opzione 2", "Opzione 3"}
[Nome]
tipo = tag_HTML
valore ={ "Valore di default"}
{opzioni = "Opzione 1", "Opzione 2", "Opzione 3"}
```
Per tag_HTML si intendono tutti i tag HTML, con preferenza rivolata verso quelli di input (input, select, textarea, date, ...) sebbene il sistema accetti anche gli altri (span, p, ...).
Attualmente questi file vengono utilizzati esclusivamente dal modulo **MyImpianti** per la gestione delle varie tipologie di _Componenti_. Il file `my_impianti/componente.ini` è un esempio di base di questa funzionalità, e un'ulteriore personalizzazione può essere trovata [nel forum](http://www.openstamanager.com/forum/viewtopic.php?f=5&t=93).

67
docs/Framework.md Normal file
View File

@ -0,0 +1,67 @@
---
currentMenu: framework
---
# Framework
> Un framework, termine della lingua inglese che può essere tradotto come intelaiatura o struttura, in informatica e specificatamente nello sviluppo software, è un'architettura logica di supporto (spesso un'implementazione logica di un particolare design pattern) su cui un software può essere progettato e realizzato, spesso facilitandone lo sviluppo da parte del programmatore.
>
> \-- <cite>[Wikipedia](https://it.wikipedia.org/wiki/Framework)</cite>
Il progetto utilizza [Composer](https://getcomposer.org/) per gestire le librerie PHP in modo completamente gratuito e open source. Questo permette di completare l'installazione e l'aggiornamento dei diversi framework in modo facile ed intuitivo, senza doversi preoccupare in modo eccessivo delle dipendenze delle diverse librerie.
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Struttura](#struttura)
- [Personalizzazione](#personalizzazione)
- [Aggiornamento](#aggiornamento)
- [Installazione di nuovi pacchetti](#installazione-di-nuovi-pacchetti)
- [Framework predefiniti](#framework-predefiniti)
<!-- /TOC -->
## Struttura
I framework vengono automaticamente scaricati da Composer all'interno della cartella _vendor_ nella root del progetto, dove vengono memorizzati secondo un percorso derivante dall'origine del pacchetto (per maggiori informazioni, consultare la [documentazione ufficiale di Composer](https://getcomposer.org/doc/)).
La modifica dei contenuti di `vendor` è altamente sconsigliata, poichè qualunque aggiornamento potrebbe sovrascrivere ed annullare le modifiche effettuate.
## Personalizzazione
Nel caso si rivelasse necessario aggiornare i framework presenti o installare nuove librerie, è necessario avere disponibile una corretta e funzionante [installazione locale di Composer](https://getcomposer.org/download/).
Una volta completata l'installazione di Composer è possibile, partendo dalla cartella del gestionale, iniziare l'aggiornamento e la personalizzazione tramite le seguenti operazioni.
### Aggiornamento
L'aggiornamento dei framework è effettuabile tramite il seguente comando:
```bash
php composer.phar update
```
Per ulteriori informazioni, consultare la [documentazione ufficiale di Composer](https://getcomposer.org/doc/).
### Installazione di nuovi pacchetti
Per installare nuovi framework e/o librerie è utilizzabile il seguente comando:
```bash
php composer.phar require <package>
```
Per ulteriori informazioni, consultare la [documentazione ufficiale di Composer](https://getcomposer.org/doc/).
## Framework predefiniti
- ezyang/htmlpurifier
- filp/whoops
- intervention/image
- ircmaxell/password-compat
- maximebf/debugbar
- monolog/monolog
- phpmailer/phpmailer
- spipu/html2pdf
- symfony/translation
_I nomi sono indicati secondo la notazione tipica dei progetti pubblici su Github._

150
docs/Installazione.md Normal file
View File

@ -0,0 +1,150 @@
---
currentMenu: installazione
---
# Installazione
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Tabella dei contenuti](#tabella-dei-contenuti)
- [Requisiti](#requisiti)
- [Installazione](#installazione)
- [Versioni](#versioni)
- [SourceForge](#sourceforge)
- [Strumenti utili](#strumenti-utili)
- [Windows](#windows)
- [Linux](#linux)
- [MAC](#mac)
- [Problemi comuni](#problemi-comuni)
- [Schermata bianca iniziale](#schermata-bianca-iniziale)
- [Blocco dell'installazione allo 0%](#blocco-dellinstallazione-allo-0%25)
<!-- /TOC -->
## Requisiti
Prima di iniziare l'installazione, è necessario procedere al download di una versione del progetto da [SourceForge](https://sourceforge.net/p/openstamanager/). Si consiglia inoltre di controllare che i prerequisiti del software, elencati di seguito, siano soddisfatti.
L'installazione del gestionale richiede la presenza di un server web con abilitato il [DBMS (Database Management System)](https://it.wikipedia.org/wiki/Database_management_system) MySQL e il linguaggio di programmazione [PHP](http://php.net/).
- PHP >= 5.4 (si consiglia come minimo la versione 5.6 per poter usufruire di tutte le funzionalità del progetto)
- MySQL >= 5.0
## Installazione
Per procedere all'installazione è necessario seguire i seguenti punti:
1. Creare una cartella (ad esempio `openstamanager`) nella root del sever web installato ed estrarvi il contenuto della release scaricata. Il percorso della cartella root del server varia in base al software in utilizzo:
- LAMP (`/var/www/html`);
- XAMPP (`C:/xampp/htdocs` per Windows, `/opt/lampp/htdocs/` per Linux, `/Applications/XAMPP/htdocs/` per MAC);
- WAMP (`C:\wamp\www`);
- MAMP (`C:\MAMP\htdocs` per Windows, `/Applications/MAMP/htdocs` per MAC).
2. Creare un database vuoto (tramite [PHPMyAdmin](http://localhost/phpmyadmin/) o riga di comando).
3. Accedere a <http://localhost/openstamanager> dal vostro browser.
4. Inserire i dati per collegarsi al database e cliccare su **Installa** per completare l'installazione.
**Attenzione**: è possibile che l'installazione richieda del tempo. Si consiglia pertanto di attendere almeno qualche minuto senza alcun cambiamento nella pagina di installazione (in particolare, della progress bar presente) prima di cercare una possibile soluzione nelle discussioni del forum o nella sezione dedicata.
### Versioni
Per mantenere un elevato grado di trasparenza riguardo al ciclo delle release, seguiamo le linee guida [Semantic Versioning (SemVer)](http://semver.org/) per definire le versioni del progetto. Per vedere tutte le versioni disponibili al download, visitare la [pagina relativa](https://sourceforge.net/projects/openstamanager/files/) su SourceForge.
### SourceForge
Nel caso si stia utilizzando la versione direttamente ottenuta dalla repository di SourceForge, è necessario eseguire i seguenti comandi da linea di comando per completare le dipendenze PHP (tramite [Composer](https://getcomposer.org/)) e gli asssets (tramite [Yarn](https://yarnpkg.com/)) del progetto.
```bash
php composer.phar install
php composer.phar update
yarn global add gulp
yarn install
gulp
```
In alternativa alla sequenza di comandi precedente, è possibile utilizzare il seguente comando (richiede l'installazione di GIT e Yarn, oltre che l'inserimento dell'archivio `composer.phar` nella cartella principale del progetto):
```bash
yarn run develop-OSM
```
Per ulteriori informazioni, visitare le sezioni [Assets](https://sourceforge.net/p/openstamanager/wiki/Assets/) e [Framework](https://sourceforge.net/p/openstamanager/wiki/Framework/) della documentazione.
## Strumenti utili
### Windows
Per installare il server web si consiglia di scaricare [WAMP dal sito ufficiale](http://www.wampserver.com/en/#download-wrapper), seguendo l'installazione guidata senza particolari personalizzazioni.
Una volta terminata linstallazione è necessario creare una cartella per il gestionale in `C:\wamp\www\`, copiando al suo interno il contenuto della release scaricata.
### Linux
Per installare il web server è necessario installare i pacchetti `apache2`, `php5` e `mysql-server`.
```bash
sudo apt-get install apache2 php5 mysql-server
```
Una volta completata linstallazione è necessario creare una cartella per il gestionale, copiandobi al suo interno il contenuto della release scaricata, nel web server di Apache2:
- nella versione <= 2.3, la cartella si trova in `/var/www/`;
- nella versione >= 2.4, la cartella si trova in `/var/www/html/`;
E' inoltre necessario assicurarsi di concedere i permessi di scrittura sulla cartella creata:
```bash
sudo chmod 777 -R /var/www/
```
Si consiglia l'installazione del pacchetto `phpmyadmin`, per poter gestire graficamente il database MySQL:
```bash
sudo apt-get install phpmyadmin
```
### MAC
La piattaforma Apple non è stata oggetto di molti test: pertanto si consiglia di individuare in prima persona un server web funzionante e con caratteristiche corrispondenti ai requisiti indicati.
Il gestionale è stato testato con successo su Mac OS X con [MAMP](http://www.mamp.info/en/) e XAMPP.
## Problemi comuni
### Schermata bianca iniziale
**Attenzione**: a partire dalla versione 2.3 questa problema non è più presente.
Nel caso si verifichi il problema di schermata bianca iniziale è necessario controllare i valori delle variabili `$rootdir` e `$docroot` nelle prime righe di _core.php_. Una possibile soluzione, implementata dalla versione 2.3, potrebbe essere:
```php
$docroot = __DIR__;
$rootdir = substr($_SERVER['SCRIPT_NAME'], 0, strrpos($_SERVER['SCRIPT_NAME'], '/'));
if (strrpos($rootdir, '/'.basename($docroot).'/') !== false) {
$rootdir = substr($rootdir, 0, strrpos($rootdir, '/'.basename($docroot).'/')).'/'.basename($docroot);
}
$rootdir = str_replace('%2F', '/', rawurlencode($rootdir));
```
Si ricorda comunque che:
- `$docroot` deve corrispondere al percorso reale nel file system per raggiungere la cartella principale del gestionale.
- `$rootdir` deve corrispondere al percorso URL del browser per raggiungere il gestionale nel server web.
### Blocco dell'installazione allo 0%
**Attenzione**: a partire dalla versione 2.3 questa problema non è più presente.
Nel caso l'installazione iniziale del database si blocchi allo 0% è probabilmente necessario effettuare una modifica nel file di impostazione del DBMS (`my.ini` nel caso di MySQL).
```ini
#sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
```
La riga preceduta da `#` è quella originale, mentre quella seguente è l'opzione che permette il corretto funzionamento dell'installazione.
Discussioni originale:
- [\[RISOLTO\] Tabelle Mancanti](http://www.openstamanager.com/forum/viewtopic.php?f=2&t=86981)
- [MySQL running in Strict Mode and giving me problems. How to fix this?](http://stackoverflow.com/questions/21667601/mysql-running-in-strict-mode-and-giving-me-problems-how-to-fix-this)

271
docs/Moduli.md Normal file
View File

@ -0,0 +1,271 @@
---
currentMenu: moduli
---
# Moduli
> Un modulo (software) è un componente software autonomo e ben identificato, e quindi facilmente riusabile.
>
> \-- <cite>[Wikipedia](https://it.wikipedia.org/wiki/Modulo#Informatica)</cite>
All'interno del progetto, i moduli vengono genericamente definiti quali sistemi di gestione delle funzionalità del gestionale; proprio per questo, la loro struttura e composizione risulta spesso variabile e differenziata, presentando componenti uniche e talvolta complesse.
Ogni modulo è composto da diverse sezioni, generalmente suddivise in:
- Nucleo;
- [Stampe](Stampe.md);
- [Widget](Widget.md);
- [Plugin](Plugin.md).
Inoltre, OpenSTAManager presenta una struttura nativamente preposta alla personalizzazione delle proprie funzioni, che rende il progetto ancora più complicato da comprendere a prima vista.
Segue un'analisi della struttura fisica e logica del nucleo dei moduli supportati dal gestionale; per ulteriori informazioni e approfondimenti, si consiglia di osservare l'effettiva composizione dei moduli implementati in modo ufficiale.
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Struttura](#struttura)
- [actions.php](#actionsphp)
- [add.php e edit.php](#addphp-e-editphp)
- [init.php](#initphp)
- [controller_after.php e controller_before.php](#controller_afterphp-e-controller_beforephp)
- [modutil.php](#modutilphp)
- [Database](#database)
- [zz_modules](#zz_modules)
- [zz_permissions e zz_group_module](#zz_permissions-e-zz_group_module)
- [zz_views e zz_group_view](#zz_views-e-zz_group_view)
- [zz_plugins e zz_widgets](#zz_plugins-e-zz_widgets)
- [Consigli per lo sviluppo](#consigli-per-lo-sviluppo)
- [Progettazione](#progettazione)
- [Sviluppo](#sviluppo)
- [Test](#test)
- [Installazione](#installazione)
- [Archivio ZIP](#archivio-zip)
- [update/VERSIONE.sql](#updateversionesql)
- [update/unistall.php (INCLUDE)](#updateunistallphp-include)
- [MODULE](#module)
- [Moduli di base](#moduli-di-base)
<!-- /TOC -->
## Struttura
La sezione fondamentale di un qualsiasi modulo all'interno di OpenSTAManager risulta presenta all'interno della cartella `modules`, che contiene tutti i file su cui si basano tutti i moduli per funzionare correttamente.
In questo contensto, ogni modulo possiede una cartella univoca per gestire i propri contenuti in modo indipendente ma comunque sottoposto alla seguente struttura di base.
.
└── modulo
   ├── actions.php
   ├── add.php
   ├── controller_after.php
   ├── controller_before.php
   ├── edit.php
   ├── init.php
   └── modutil.php
Il gestionale supporta in modo nativo questa struttura, che può essere ampliata e personalizzata a necessità dagli sviluppatori: si consiglia pertanto di analizzare la struttuta dei moduli **Iva**, **Dashboard** e **Contratti** per esempi di diversa complessità e funzione.
**Attenzione**: la presenza dei file sopra indicati non è strettamente necessaria per il funzionamento di un modulo (si veda **Movimenti**, presente esclusivamente a livello di database).
### actions.php
Il file `actions.php` gestisce tutte le operazioni supportate dal modulo.
In generale, le diverse operazioni vengono gestite attraverso attraverso una logica programmativa basata su casi (solitamente, il parametro `op` permette di identificare quale azione viene richiesta); il funzionamento a livello di programmazione può essere comunque sottoposto a scelte personali.
L'unico requisito effettivo risulta relativo alle operazioni di creazione dei nuovi record, per cui deve essere definito all'interno della variabile `$id_record` l'identificativo del nuovo elemento.
Per osservare questo sistema, si consiglia di analizzare il relativo file del modulo **Iva**.
### add.php e edit.php
Il file `add.php` contiene il template HTML dedicato all'inserimento di nuovi elementi per il modulo, mentre `edit.php` contiene il template HTML dedicato alla modifica degli stessi.
In base alla configurazione del modulo nel database, il file `edit.php` può assumere il ruolo di gestore della sezione principale dell'interno modulo, permettendo così la personalizzazione dei contenuti come si può notare per i moduli **Dashboard** e **Gestione componenti**.
**Attenzione**: il progetto individua in automatico la presenza di questo file e agisce di conseguenza per permettere o meno l'inserimento di nuovi valori.
### init.php
Il file `init.php` si occupa di individuare le informazioni principali utili all'identificazione e alla modifica dei singoli elementi del modulo.
In particolare, questi file sono solitamente composti da una query dedicata ad ottenere tutti i dati dell'elemento nella variabile `$records`, successivamente utilizzata dal gestore dei template per completare le informazioni degli input.
### controller_after.php e controller_before.php
Il file `controller_after.php` contiene le funzioni javaScript aggiuntive specifiche del modulo.
### modutil.php
Il file `modutil.php` viene utilizzato per definire le funzioni PHP specifiche per il modulo, e permettere in questo modo uan gestione semplificata delle operazioni più comuni.
Si noti che un modulo non è necessariamente limitato all'utilizzo del proprio file `modutil.php`: come avviene per esempio in **Fatture** e **Interventi**, risulta possibile richiamare file di questa tipologia da altri moduli (in questo caso, da **Articoli** per la gestione delle movimentazioni di magazzino).
## Database
All'interno del database del progetto, le tabelle con il suffisso `zz` sono generalmente dedicate alla gestione delle funzioni di base del gestionale, finalizzate in particolare all'utilizzo dei moduli installati.
La gestione dei moduli avviene in questo senso grazie alle seguenti tabelle:
- `zz_modules`;
- `zz_permissions`;
- `zz_views`;
- `zz_plugins`;
- `zz_widgets`.
### zz_modules
La tabella `zz_modules` contiene tutte le informazioni dei diversi moduli installati nel gestionale in uso, con particolare riferimento a:
- Nome (utilizzato a livello di programmazione) [`name`]
- Titolo (visibile e personalizzabile) [`title`]
- Percorso nel file system (partendo da `modules/`) [`directory`]
- Icona [`icon`]
- Posizione nella sidebar [`order`]
- Compatibilità [`compatibility`]
- Query di default [`options`]
- Query personalizzata [`options2`]
Gli ultimi due attributi si rivelano di fondamentale importanza per garantire il corretto funzionamento del modulo, poiché descrivono il comportamento dello stesso per la generazione della schermata principale nativa di OpenSTAManager.
Sono permessi i seguenti valori:
- custom [Modulo con schermata principale personalizzata e definita nel file `edit.php`]
- {VUOTO} [Menu non navigabile]
- menu [Menu non navigabile]
- Oggetto JSON
```json
{ "main_query": [ { "type": "table", "fields": "Nome, Descrizione", "query": "SELECT `id`, `nome` AS `Nome`, `descrizione` AS `Descrizione` FROM `tabella` HAVING 1=1 ORDER BY `nome`"} ]}
```
- Query SQL \[vedasi la tabella [zz_views](#zz_views-e-zz_group_view)]
```sql
SELECT |select| FROM `tabella` HAVING 1=1
```
### zz_permissions e zz_group_module
La tabella `zz_permissions` contiene i permessi di accesso dei vari gruppi ai diversi moduli, mentre la tabella `zz_group_module` contiene le clausole DQL per permettere questo accesso.
### zz_views e zz_group_view
Le tabelle `zz_views` e `zz_group_view` vengono utilizzate dal gestionale per la visualizzazione delle informazioni secondo i permessi accordati, oltre che dal modulo **Viste** per la gestione dinamica delle query.
### zz_plugins e zz_widgets
La tabella `zz_plugins` contiene l'elenco di plugins relativi ai diversi moduli, mentre la tabella `zz_group_module` contiene l'elenco di widgets dei vari moduli.
## Consigli per lo sviluppo
### Progettazione
Alla base dello sviluppo di ogni modulo vi è una fase di analisi indirizzata all'individuazione dettagliata delle funzionalità dello stesso e della struttura interna al database atta a sostenere queste funzioni. Siete dunque pregati di identificare chiaramente tutte le caratteristiche del Vostro nuovo modulo o delle Vostre modifiche prima di iniziare lo sviluppo vero e proprio (comunemente identificato con la scrittura del codice).
> E' bene trascurare le fasi di analisi e di progetto e precipitarsi all'implementazione allo scopo di guadagnare il tempo necessario per rimediare agli errori commessi per aver trascurato la fase di analisi e di progetto.
>
> \-- <cite>Legge di Mayers</cite>
### Sviluppo
Lo sviluppo del codice deve seguire alcune direttive generali per la corretta interpretazione del codice all'interno del gestionale: ciò comporta una struttura di base fondata sui file precedentemente indicati nella sezione [Cartella `modules`](#Cartella_modules) ma ampliabile liberamente.
### Test
Prima di pubblicare un modulo si consiglia di effettuare svariati test in varie installazioni. Siete inoltre pregati di indicare i bug noti.
> Se cè una remota possibilità che qualcosa vada male, sicuramente ciò accadrà e produrrà il massimo danno.
>
> \-- <cite>Legge di Murphy</cite>
## Installazione
L'installazione di un modulo è completabile in modo automatico seguendo la seguente procedura:
- Scaricare l'archivio `.zip` del modulo da installare;
- Accedere al proprio gestionale con un account abilita all'accesso del modulo **Aggiornamenti**;
- Selezionare l'archivio scaricato nella selezione file della sezione "Carica un nuovo modulo";
- Cliccare il pulsante "Carica".
Si ricorda che per effettuare l'installazione è necessaria la presenza dell'estensione `php_zip` (per ulteriori informazioni guardare [qui](http://php.net/manual/it/zip.installation.php)).
**Attenzione**: la procedura può essere completata anche a livello manuale, ma si consiglia di evitare tale sistema a meno che non si conosca approfonditamente il funzionamento complessivo e specifico del database del progetto.
### Archivio ZIP
L'archivio scaricato deve contenere direttamente al proprio interno i contenuti del modulo da installare, organizzati secondo la seguente struttura:
modulo.zip
├── update
| ├── VERSIONE.sql
| └── unistall.php
├── ... - File contententi il codice del modulo
└── MODULE
#### update/VERSIONE.sql
Il file `VERSIONE.sql` (dove VERSIONE sta per la versione del modulo con `_`[underscore] al posto di `.`[punto]) contiene le operazioni di installazione del modulo a livello del database, comprendenti la creazione delle tabelle di base del modulo e l'inserimento di ulteriori dati nelle altre tabelle.
#### update/unistall.php (INCLUDE)
Il file `unistall.php` contiene le operazioni di disinstallazione del modulo a livello del database, comprendenti l'eliminazione delle tabelle non più necessarie e dei dati inutilizzati.
```php
<?php
include_once __DIR__.'/../../core.php';
$dbo->query("DROP TABLE `tabella`");
?>
```
#### MODULE
Il file `MODULE` è infine il diretto responsabile dell'installazione del modulo poiché definisce tutti i valori caratteristici dello stesso; in caso di sua assenza la cartella compressa viene considerata non corretta.
```ini
module_name = Nome del modulo
module_version = Versione del modulo
module_dir = Cartella di installazione del modulo
module_options = Operazione da eseguire all'apertura del modulo
module_icon = Icona del modulo (Font-Awesome)
module_compatibility = Compatibilità del modulo
module_parent = "Genitore" del modulo
```
## Moduli di base
Nella versione base del gestionale sono presenti, all'interno della cartella `modules`, i seguenti moduli.
.
├── aggiornamenti
├── anagrafiche
├── articoli
├── automezzi
├── backup
├── beni
├── categorie
├── causali
├── contratti
├── dashboard
├── ddt
├── fatture
├── gestione_componenti
├── interventi
├── impostazioni
├── iva
├── listini
├── misure
├── my_impianti
├── ordini
├── pagamenti
├── partitario
├── porti
├── preventivi
├── primanota
├── scadenzario
├── stati_intervento
├── tecnici_tariffe
├── tipi_anagrafiche
├── tipi_intervento
├── utenti
├── viste
├── voci_servizio
└── zone

253
docs/Nucleo.md Normal file
View File

@ -0,0 +1,253 @@
---
currentMenu: nucleo
---
# Nucleo
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Root](#root)
- [add.php](#addphp)
- [ajax_autocomplete.php](#ajax_autocompletephp)
- [ajax_dataload.php](#ajax_dataloadphp)
- [ajax_select.php](#ajax_selectphp)
- [bug.php](#bugphp)
- [core.php](#corephp)
- [config.inc.php](#configincphp)
- [controller.php](#controllerphp)
- [editor.php](#editorphp)
- [index.php](#indexphp)
- [info.php](#infophp)
- [log.php](#logphp)
- [composer.json, gulpfile.js, package.json](#composerjson-gulpfilejs-packagejson)
- [Cartella api](#cartella-api)
- [Cartella assets](#cartella-assets)
- [Cartella backup](#cartella-backup)
- [Cartella docs](#cartella-docs)
- [Cartella files](#cartella-files)
- [Cartella include](#cartella-include)
- [bottom.php (CUSTOMIZABLE)](#bottomphp-customizable)
- [top.php (CUSTOMIZABLE)](#topphp-customizable)
- [Cartella lib](#cartella-lib)
- [deprecated.php](#deprecatedphp)
- [functions.php](#functionsphp)
- [functionsjs.php (HTML)](#functionsjsphp-html)
- [init.js (HTML)](#initjs-html)
- [modulebuilder.php](#modulebuilderphp)
- [permissions_check.php](#permissions_checkphp)
- [user_check.php](#user_checkphp)
- [classes/Database.php](#classesdatabasephp)
- [classes/HTMLBuilder.php](#classeshtmlbuilderphp)
- [Cartella locale](#cartella-locale)
- [Cartella modules](#cartella-modules)
- [Cartella templates](#cartella-templates)
- [Cartella update](#cartella-update)
- [create_updates.sql](#create_updatessql)
- [update_VERSIONE.sql (OPEN)](#update_versionesql-open)
- [update_VERSIONE.php](#update_versionephp)
- [Cartella vendor](#cartella-vendor)
<!-- /TOC -->
Scaricando la versione SVN del progetto dovreste trovare una struttura di base molto simile a quella seguente.
.
├── api
├── assets
├── backup
├── doc
├── files
├── include
├── lib
├── locale
├── modules
├── src
├── templates
├── update
└── vendor
Analizzeremo ora in dettaglio la funzione delle diverse cartelle e dei relativi contenuti.
Si avverte che il gestionale è fortemente basato sulla correttezza contemporanea di molti file: siete pertanto pregati di astenervi da modifiche o, se queste dovessero rivelarsi necessarie, procedere alla creazione di un relativo file custom nella cartella del file. E' comunque consigliabile richiedere l'assistenza ufficiale.
Per maggiori informazioni riguardanti il procedimento di personalizzazione, rivolgersi alla sezione [Personalizzazione].
## Root
I contenuti della cartella _root_, indicata nella struttura precedente dal punto inziale, sono estremamente importante per il progetto, in quanto sono generalmente dedicati a garantire il funzionamento dell'intero gestionale.
Questa centralizzazione permette al software di essere estremamente scalabile e personalizzabile, soprattutto in relazione ai moduli.
Per maggiori informazioni riguardanti lo sviluppo di un modulo, consultare la sezione [Moduli].
### add.php
Il file `add.php` è dedicato alla gestione dei form di creazione nuovi elementi all'interno dei vari moduli.
In particolare si occupa parallelamente della funzionalità di aggiunta al volo, visibile in azione nei modulo **Attività**, **Articoli** e in alcuni altri punti del software.
### ajax_autocomplete.php
Il file `ajax_dataload.php` gestisce il caricamento dinamico dei dati in varie sezioni del sito, relativamente alle operazioni di auto-completamento dei form.
**Attenzione**: questo sistema è ormai quasi deprecato e, tranne in rari casi, completamente sostituito dall'utilizzo del file `ajax_select.php` e dal plugin [Select2](https://select2.github.io/).
### ajax_dataload.php
Il file `ajax_dataload.php` gestisce il caricamento dinamico dei dati nelle tabelle fornite nella vista generale dei moduli (`controller.php`), filtrando i risultati in base alle richieste dell'utente.
### ajax_select.php
Il file `ajax_select.php` gestisce il caricamento dinamico dei dati nei diversi select abilitati, garantendo l'accesso a tutti i record senza provocare rallentamenti (persino per numeri più elevati).
### bug.php
Il file `bug.php` si occupa della segnalazione dei bug, fornendo un sistema integrato di invio email dopo la configurazione di pochi parametri iniziali.
Le opzioni relative alle informazioni da allegare sono:
- Allegare il file di log (fondamentale nel caso si stia effettuando una segnalazione)
- Allegare una copia del database
- Allegare le informazioni relative al PC utilizzato
### core.php
Il _core_, come si può discernere dal nome, è il nucleo dell'intero gestionale: si occupa delle operazioni di inizializzazione fondamentali, compresa l'inclusione del file di configurazione `config.inc.php` e la creazione dell'elenco degli assets da includere.
Si occupa inoltre del controllo dei permessi, tramite l'inclusione di `lib/permissions.php`, e dell'individuazione delle informazioni di base relative al modulo aperto.
### config.inc.php
Il file `config.inc.php` contiene tutte le informazioni per accedere correttamente al database e per determinare il tema utilizzato dal gestionale.
**Attenzione**: questo file non è presente di default poiché obbligatoriamente da personalizzare tramite la procedura di installazione.
### controller.php
Il file `controller.php` si occupa di gestire l'accesso generico ai moduli, caricando le informazioni e i widget del modulo in oggetto. Permette inoltre la visualizzazione, in base ai permessi accordati all'utente, del pulsante di creazione nuovi elementi.
### editor.php
Il file `editor.php` si occupa di gestire l'accesso specifico ai dati di un singolo elemento di un modulo, caricando al tempo stesso l'insieme di plugin (e, in casi più rari, di widget) legati alla visualizzazione dell'elemento in oggetto. Permette inoltre, in base ai permessi accordati all'utente, la modifica dei dati inseriti e l'interazione con altri moduli.
### index.php
Il file `index.php` si occupa delle operazioni di autenticazione (login e logout), oltre che effettuare un controllo sulla disponibilità di aggiornamenti (tramite l'inclusione di `update/update_checker.php`) e a garantire il redirect iniziale al primo modulo su cui l'utente possiede i permessi di accesso.
### info.php
Il file `info.php` contiene la sezione informativa relativa al progetto, indicante la community, la modalità di supporto e le offerte a pagamento.
### log.php
Il file `log.php` permette di visualizzare le informazioni relative agli ultimi 100 accessi, comprendenti eventuali tentativi falliti ed errori.
**Attenzione**: nel caso in cui l'utente sia un amministratore, le informazioni accessibili sono relative a _tutti_ i tentativi di accesso (al contrario, un utente normale può visualizzare esclusivamente i propri tentativi).
### composer.json, gulpfile.js, package.json
Per maggiori informazioni questi file, consultare le sezioni [Framework] e [Assets].
## Cartella api
Per maggiori informazioni riguardanti la cartella `api` e i suoi contenuti, rivolgersi alla sezione [API].
## Cartella assets
Per maggiori informazioni riguardanti la cartella `assets` e i suoi contenuti, rivolgersi alla sezione [Assets (CSS, JS e immagini)].
## Cartella backup
La cartella _backup_ è quella di default utilizzata dall'operazione omonima del progetto.
## Cartella docs
La cartella `docs`, come si può intuire, contiene la documentazione di sviluppo del progetto.
## Cartella files
Per maggiori informazioni riguardanti la cartella `files` e i suoi contenuti, rivolgersi alla sezione [Moduli].
## Cartella include
### bottom.php (CUSTOMIZABLE)
Il file `bottom.php` si occupa delle operazioni di chiusura della pagina HTML, garantendo inoltre l'eliminazione dei log temporanei della sessione.
### top.php (CUSTOMIZABLE)
Il file `top.php` gestisce la creazione del layout di base del gestionale, comprendente la barra di navigazione e la sidebar.
## Cartella lib
La cartella `lib` contiene le librerie personalizzate e le funzioni utilizzate dall'intero gestionale nei diversi moduli.
**Attenzione**: sono qui presenti solo i metodi generali e comunemente riutilizzati. Per maggiori informazioni riguardanti la locazione delle funzioni specifiche di un modulo, visitare la sezione [Moduli].
### deprecated.php
Il file `deprecated.php` contiente l'insieme di funzioni deprecate nella versione corrente del gestionale, che verranno successivamente rimosse nella futura release.
### functions.php
Il file `functions.php` contiene tutte le funzioni comunemente utilizzate nel progetto.
### functionsjs.php (HTML)
Il file `functionsjs.php` contiene tutte le funzioni JavaScript comunemente utilizzate nel progetto.
### init.js (HTML)
Il file `init.js` contiene le funzioni JavaScript comunemente richiamate al caricamento di parti indipendenti del progetto.
### modulebuilder.php
Il file `modulebuilder.php` contiene le funzioni (e le sezioni HTML) atte all'upload di file e all'individuazione degli stessi, oltre che alla loro gestione, nei vari moduli.
### permissions_check.php
Il file `permissions_check.php` si occupa dei controlli relativi ai permessi di accesso di un utente ad un determinato modulo.
**Attenzione**: questo file è ora sostituito dalla classe Permissions.
### user_check.php
Il file `user_check.php` si occupa di controllare se è stato effettuato l'accesso.
**Attenzione**: questo file è ora sostituito dalla classe Permissions.
### classes/Database.php
La classe Database gestisce la connessione con il database, rendendo disponibile un insieme di funzioni utili ad elaborare i risulti delle diverse query.
### classes/HTMLBuilder.php
La classe HTMLBuilder contiene i metodi responsabili della creazione di contenuto HTML partendo dal template interno del progetto.
Per maggiori informazioni le caratteristiche del template utilizzato dal gestionale, rivolgersi alla sezione [Template].
## Cartella locale
La cartella `locale` contiene tutte le traduzioni del progetto, nei formati tipici di Gettext (`.po` e `.mo`).
## Cartella modules
Per maggiori informazioni riguardanti la cartella `modules` e i suoi contenuti, rivolgersi alla sezione [Moduli].
Si ricorda che per tutti i contenuti del modulo è possibile creare una personalizzazione nella cartella `custom`.
## Cartella templates
La cartella `templates` contiene tutti i file relativi alla visualizzazione in PDF dei dati dei vari moduli.
Per maggiori informazioni riguardanti la cartella `templates` e i suoi contenuti, rivolgersi alla sezione [Stampe].
## Cartella update
### create_updates.sql
Il file `create_updates.sql` contiene la query SQL per la creazione della tabella di gestione degli aggiornamenti e delle installazioni del gestionale.
### update_VERSIONE.sql (OPEN)
I file `VERSIONE.sql` contengono l'insieme di query SQL necessarie per l'aggiornamento del gestionale alla versione _VERSIONE_.
### update_VERSIONE.php
I file `VERSIONE.php` contengono l'insieme di operazioni PHP (e, talvolta, SQL) necessarie per l'aggiornamento del gestionale alla versione _VERSIONE_.
## Cartella vendor
Per maggiori informazioni riguardanti la cartella `vendor` e i suoi contenuti, rivolgersi alla sezione [Framework].

10
docs/Plugin.md Normal file
View File

@ -0,0 +1,10 @@
---
currentMenu: plugin
---
# Plugin
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
<!-- /TOC -->

51
docs/README.md Normal file
View File

@ -0,0 +1,51 @@
---
currentMenu: home
---
# OpenSTAManager - Documentazione
Benvenuti nella wiki di OpenSTAManager!
> Al giorno d'oggi, per le aziende coinvolte nel settore dell'assistenza tecnica la necessità di un software dedicato, flessibile, completo e funzionale in molteplici categorie di dispositivi risulta di fondamentale importanza per permettere un'efficiente gestione dell'attività lavorativa.
> Per rispondere a queste esigenze nasce il gestionale per il servizio di assistenza tecnica OpenSTAManager, che rende disponibile un supporto informatico per la gestione di questa tipologia di pratiche in un contesto talvolta povero di alternative.
La documentazione del progetto presenta informazioni valide a partire dalla versione 2.3 dello stesso.
Si avverte pertanto che questa documentazione non è utilizzabile con efficacia per le versioni precedenti del progetto, con particolare riguardo verso le strutture relative ad assets e framework, oltre che alle procedure di sviluppo di moduli.
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Presentazione](#presentazione)
- [Storia](#storia)
- [Membri](#membri)
<!-- /TOC -->
## Presentazione
Il gestionale OpenSTAManager è un software open-source e web based, sviluppato dall'azienda informatica DevCode di Este per gestire ed archiviare il servizio di assistenza tecnica e la relativa fatturazione.
Il nome del progetto deriva dalla parziale traduzione in inglese degli elementi principali che lo compongono: la natura open source e il suo obiettivo quale Gestore del Servizio Tecnico di Assistenza.
Un software gestionale, identificato nell'insieme degli applicativi che automatizzano i processi di gestione all'interno delle aziende, appartiene solitamente a una specifica categoria del settore, specializzata negli ambiti di:
- Gestione della contabilità;
- Gestione del magazzino;
- Gestione e ausilio della produzione;
- Gestione e previsione dei budget aziendali;
- Gestione ed analisi finanziaria.
Secondo questa definizione, OpenSTAManager riesce a generalizzare al proprio interno le funzionalità caratteristiche della contabilità e della gestione del magazzino, presentando inoltre moduli piuttosto avanzati e destinati a complementare l'attività aziendale in relazione agli interventi di assistenza della realtà lavorativa in oggetto.
Proprio grazie alla vasta gamma di funzionalità che lo caratterizzano, questo gestionale riesce a mantenere una posizione rilevante all'interno del mercato, garantita dalla natura open source del progetto e amplificata dall'ampio grado di personalizzazione che contraddistingue questo particolare software.
## Storia
OpenSTAManager viene inizialmente ideato da Nicoletta Marampon e sviluppato da **Fabio Lovato** al fine di gestire esclusivamente le anagrafiche e gli interventi aziendali per piccole realtà lavorative.
La prima release (0.2RC2 dell'agosto 2008) viene successivamente ampliata con numerosi e innovativi componenti, quali il calendario delle attività, e ottimizzata in relazione al sistema di installazione e di aggiornamento; parallelamente, tra il 2011 e 2012, viene introdotto il sistema di gestione della contabilità e vengono migliorati numerosi moduli, soprattutto a livello grafico.
Fondamentale in questo senso risulta essere la collaborazione dei nuovi colleghi **Luca Salvà** e **Fabio Piovan**, che ha permesso il continuo adeguamento del progetto a un mondo informatico in continua evoluzione e a richieste sempre più complesse da parte dei clienti.
L'insieme di cambiamenti introdotti nel periodo compreso tra giugno 2016 e giugno 2017 hanno infine portato alla generazione di un ramo di sviluppo parallelo (_branch_) per la versione 2.3, destinata a cambiare e migliorare in modo fondamentale numerose sezioni _front-end_ e _back-end_ del progetto.
## Membri
[[members]]

37
docs/Stampe.md Normal file
View File

@ -0,0 +1,37 @@
---
currentMenu: stampe
---
# Stampe
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
- [Struttura](#struttura)
- [pdfgen.php](#pdfgenphp)
- [pdfgen_variables.php (INCLUDE)](#pdfgen_variablesphp-include)
- [Struttura interna](#struttura-interna)
<!-- /TOC -->
### Struttura
La cartella _templates_ contiene tutti i template per la creazione dei PDF, raggruppati in base al nome del modulo. QUesti vengono utilizzati da `pdfgen.php` e da `pdfgen_variables.php` per la generazione vera e propria del PDF tramite il framework [HTML2PDF](https://github.com/spipu/html2pdf).
#### pdfgen.php
Il file `pdfgen.php` si occupa della formattazione dei contenuti dei template per la visualizzazione vera e propria del PDF, inizializzando l'oggetto relativo ed eseguendone l'output.
#### pdfgen_variables.php (INCLUDE)
Il file `pdfgen_variables.php` si occupa della sostituzione delle variabili comuni a tutti i template, e viene richiamata dal file `pdfgen.MODULO.php` descritto di seguito.
#### Struttura interna
La cartella _templates_ contiene tutti i template per la creazione dei PDF relativi al modulo specifico, in una struttura interna simile alla seguente (modulo **Contratti** utilizzato come esempio).
.
└── contratti
   ├── contratto_body.html (OPEN) - Struttura di base del PDF
   ├── contratto.html (OPEN) - Contenitore personalizzato della struttura del PDF
   ├── logo_azienda.jpg (HTML) - Logo dell'azienda specifico per il PDF
   └── pdfgen.contratti.php (INCLUDE) - Individuazione delle informazioni da visualizzare e generazione della loro struttura

10
docs/Widget.md Normal file
View File

@ -0,0 +1,10 @@
---
currentMenu: widget
---
# Widget
<!-- TOC depthFrom:2 depthTo:6 orderedList:false updateOnSave:true withLinks:true -->
<!-- /TOC -->

212
editor.php Normal file
View File

@ -0,0 +1,212 @@
<?php
include_once __DIR__.'/core.php';
if (empty($id_record) && !empty($id_module)) {
redirect(ROOTDIR.'/controller.php?id_module='.$id_module);
} elseif (empty($id_record) && empty($id_module)) {
redirect(ROOTDIR.'/index.php');
}
if (file_exists($docroot.'/include/custom/top.php')) {
include $docroot.'/include/custom/top.php';
} else {
include $docroot.'/include/top.php';
}
// Lettura parametri iniziali del modulo
$module = Modules::getModule($id_module);
if (empty($module) || empty($module['enabled'])) {
die(_('Accesso negato'));
}
$module_dir = $module['directory'];
// Inclusione elementi fondamentali del modulo
include $docroot.'/actions.php';
$advanced_sessions = get_var('Attiva notifica di presenza utenti sul record');
if ($advanced_sessions) {
$dbo->query('DELETE FROM zz_semaphores WHERE id_utente='.prepare($_SESSION['idutente']).' AND posizione='.prepare($id_module.', '.$id_record));
$dbo->query('INSERT INTO zz_semaphores (id_utente, posizione) VALUES ('.prepare($_SESSION['idutente']).', '.prepare($id_module.', '.$id_record).')');
echo '
<div class="box box-warning box-solid text-center info-active hide">
<div class="box-header with-border">
<h3 class="box-title"><i class="fa fa-warning"></i> '._('Attenzione!').'</h3>
</div>
<div class="box-body">
<p>'._('I seguenti utenti stanno visualizzando questa pagina').':</p>
<ul class="list">
</ul>
<p>'._('Prestare attenzione prima di effettuare modifiche, poichè queste potrebbero essere perse a causa di multipli salvataggi contemporanei').'.</p>
</div>
</div>';
}
if (empty($records)) {
echo '
<p>'._('Record non trovato').'.</p>';
} else {
/*
* Lettura eventuali plugins modulo da inserire come tab
*/
echo '
<div class="nav-tabs-custom">
<ul class="nav nav-tabs pull-right" role="tablist">
<li class="pull-left active header">';
// Verifico se ho impostato un nome modulo personalizzato
$name = $module['title'];
echo '
<a data-toggle="tab" href="#tab_0"><i class="'.$module['icon'].'"></i> '.$name.'</a>
<a class="back-btn" href="controller.php?id_module='.$id_module.'"><i class="fa fa-chevron-left"></i> '._("Torna all'elenco").'</a>
</li>';
$plugins = $dbo->fetchArray('SELECT id, title FROM zz_plugins WHERE idmodule_to='.prepare($id_module)." AND position='tab' AND enabled = 1");
foreach ($plugins as $plugin) {
echo '
<li>
<a data-toggle="tab" href="#tab_'.$plugin['id'].'" id="link-tab_'.$plugin['id'].'">'.$plugin['title'].'</a>
</li>';
}
echo '
</ul>
<div class="tab-content">
<div id="tab_0" class="tab-pane active">';
// Lettura template modulo (verifico se ci sono template personalizzati, altrimenti uso quello base)
if (file_exists($docroot.'/modules/'.$module_dir.'/custom/edit.php')) {
include $docroot.'/modules/'.$module_dir.'/custom/edit.php';
} elseif (file_exists($docroot.'/modules/'.$module_dir.'/custom/edit.html')) {
include $docroot.'/modules/'.$module_dir.'/custom/edit.html';
} elseif (file_exists($docroot.'/modules/'.$module_dir.'/edit.php')) {
include $docroot.'/modules/'.$module_dir.'/edit.php';
} elseif (file_exists($docroot.'/modules/'.$module_dir.'/edit.html')) {
include $docroot.'/modules/'.$module_dir.'/edit.html';
}
echo '
</div>';
foreach ($plugins as $plugin) {
echo '
<div id="tab_'.$plugin['id'].'" class="tab-pane">';
$id_plugin = $plugin['id'];
include $docroot.'/include/manager.php';
echo '
</div>';
}
echo '
</div>
</div>';
}
$backto = filter('backto');
// Scelta del redirect dopo un submit
if (!empty($backto)) {
$hash = filter('hash');
if ($backto == 'record-edit') {
redirect(ROOTDIR.'/editor.php?id_module='.$id_module.'&id_record='.$id_record.$hash);
exit();
} elseif ($backto == 'record-list') {
redirect(ROOTDIR.'/controller.php?id_module='.$id_module.$hash);
exit();
}
}
echo '
<hr>
<a href="controller.php?id_module='.$id_module.'"><i class="fa fa-chevron-left"></i> '._('Indietro').'</a>';
/*
* Widget laterali
*/
echo '
</div>
<div class="col-xs-12 col-md-12">';
echo Widgets::addModuleWidgets($id_module, 'editor_right');
echo '
</div>';
?>
<script>
<?php
// Se l'utente ha i permessi in sola lettura per il modulo, converto tutti i campi di testo in span
if ($module['permessi'] == 'r') {
?>
$(document).ready( function(){
$('input, textarea, select', 'section.content').attr('readonly', 'true');
$('select, input[type="checkbox"]').prop('disabled', true);
$('a.btn, button, input[type=button], input[type=submit]', 'section.content').hide();
$('a.btn-info, button.btn-info, input[type=button].btn-info', 'section.content').show();
});
<?php
} ?>
var content_was_modified = false;
//controllo se digito qualche valore o cambio qualche select
$("input, textarea, select").bind("change paste keyup", function(event) {
if( event.keyCode >= 32 ){
content_was_modified = true;
}
});
//tolgo il controllo se sto salvando
$(".btn-success, button[type=submit]").bind("click", function() {
content_was_modified = false;
});
// questo controllo blocca il modulo vendita al banco, dopo la lettura con barcode, appare il messaggio di conferma
window.onbeforeunload = function(){
if(content_was_modified) {
return 'Uscire senza salvare?';
}
};
<?php
if ($advanced_sessions) {
?>
function getActiveUsers(){
$.getJSON('<?php echo ROOTDIR; ?>/call.php', {
id_module: <?php echo $id_module; ?>,
id_record: <?php echo $id_record; ?>
},
function(data) {
if (data.length != 0) {
$(".info-active").removeClass("hide");
$(".info-active .list").html("");
$.each( data, function( key, val ) {
$(".info-active .list").append("<li>"+val.username+"</li>");
});
}
else $(".info-active").addClass("hide");
});
}
getActiveUsers();
setInterval(getActiveUsers, <?php echo get_var('Timeout notifica di presenza (minuti)') * 1000; ?>);
<?php
}
?>
</script>
<?php
if (file_exists($docroot.'/include/custom/bottom.php')) {
include $docroot.'/include/custom/bottom.php';
} else {
include $docroot.'/include/bottom.php';
}

5
files/.htaccess Normal file
View File

@ -0,0 +1,5 @@
# Disable PHP rendering
php_flag engine off
## Options -ExecCGI
AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi

View File

@ -0,0 +1,20 @@
[Nome]
tipo = span
valore = "Componente di esempio"
[Marca]
tipo = input
valore =
[Tipo]
tipo = select
valore =
opzioni = "Tipo 1", "Tipo 2"
[Data di installazione]
tipo = date
valore =
[Note]
tipo = textarea
valore =

300
gulpfile.js Normal file
View File

@ -0,0 +1,300 @@
// Librerie NPM richieste per l'esecuzione
var gulp = require('gulp');
var del = require('del');
var debug = require('gulp-debug');
var util = require('gulp-util');
var shell = require('shelljs');
var mainBowerFiles = require('main-bower-files');
var gulpIf = require('gulp-if');
// Minificatori
var minifyJS = require('gulp-uglify');
var minifyCSS = require('gulp-clean-css');
var minifyJSON = require('gulp-json-minify');
// Interpretatori CSS
var sass = require('gulp-sass');
var less = require('gulp-less');
var stylus = require('gulp-stylus');
var autoprefixer = require('gulp-autoprefixer');
// Concatenatore
var concat = require('gulp-concat');
// Altro
var flatten = require('gulp-flatten');
var rename = require('gulp-rename');
// Configurazione
var config = {
production: 'assets/dist', // Cartella di destinazione
development: 'assets/src', // Cartella dei file di personalizzazione
debug: false,
main: {
bowerDirectory: './node_modules',
bowerJson: './package.json',
},
paths: {
js: 'js',
css: 'css',
images: 'img',
fonts: 'fonts'
}
};
// Elaborazione e minificazione di JS
gulp.task('JS', function () {
gulp.src(mainBowerFiles('**/*.js', {
paths: config.main,
debugging: config.debug,
}))
.pipe(concat('app.min.js'))
.pipe(minifyJS())
.pipe(gulp.dest(config.production + '/' + config.paths.js));
gulp.start('srcJS');
});
// Elaborazione e minificazione di JS personalizzati
gulp.task('srcJS', function () {
gulp.src([
config.development + '/' + config.paths.js + '/*.js',
])
.pipe(concat('custom.min.js'))
.pipe(minifyJS())
.pipe(gulp.dest(config.production + '/' + config.paths.js));
});
// Elaborazione e minificazione di CSS
gulp.task('CSS', function () {
gulp.src(mainBowerFiles('**/*.{css,scss,less,styl}', {
paths: config.main,
debugging: config.debug,
}))
.pipe(gulpIf('*.scss', sass(), gulpIf('*.less', less(), gulpIf('*.styl', stylus()))))
.pipe(autoprefixer({
browsers: 'last 2 version',
}))
.pipe(minifyCSS({
rebase: false,
}))
.pipe(concat('app.min.css'))
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.css));
gulp.start('srcCSS');
});
// Elaborazione e minificazione di CSS personalizzati
gulp.task('srcCSS', function () {
gulp.src([
config.development + '/' + config.paths.css + '/*.{css,scss,less,styl}',
])
.pipe(gulpIf('*.scss', sass(), gulpIf('*.less', less(), gulpIf('*.styl', stylus()))))
.pipe(autoprefixer({
browsers: 'last 2 version',
}))
.pipe(minifyCSS({
rebase: false,
}))
.pipe(concat('style.min.css'))
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.css));
gulp.src([
config.development + '/' + config.paths.css + '/print/*.{css,scss,less,styl}',
config.bowerDirectory + '/fullcalendar/fullcalendar.print.css',
])
.pipe(gulpIf('*.scss', sass(), gulpIf('*.less', less(), gulpIf('*.styl', stylus()))))
.pipe(autoprefixer({
browsers: 'last 2 version',
}))
.pipe(minifyCSS({
rebase: false,
}))
.pipe(concat('print.min.css'))
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.css));
gulp.src([
config.development + '/' + config.paths.css + '/themes/*.{css,scss,less,styl}',
config.main.bowerDirectory + '/adminlte/dist/css/skins/_all-skins.css',
])
.pipe(gulpIf('*.scss', sass(), gulpIf('*.less', less(), gulpIf('*.styl', stylus()))))
.pipe(autoprefixer({
browsers: 'last 2 version',
}))
.pipe(minifyCSS({
rebase: false,
}))
.pipe(concat('themes.min.css'))
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.css));
});
// Elaborazione delle immagini
gulp.task('images', function () {
gulp.src(mainBowerFiles('**/*.{jpg,png,jpeg,gif}', {
paths: config.main,
debugging: config.debug,
}))
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.images));
gulp.start('srcImages');
});
// Elaborazione delle immagini personalizzate
gulp.task('srcImages', function () {
gulp.src([
config.development + '/' + config.paths.images + '/**/*.{jpg,png,jpeg,gif}',
])
.pipe(gulp.dest(config.production + '/' + config.paths.images));
});
// Elaborazione dei fonts
gulp.task('fonts', function () {
gulp.src(mainBowerFiles('**/*.{otf,eot,svg,ttf,woff,woff2}', {
paths: config.main,
debugging: config.debug,
}))
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.fonts));
gulp.start('srcFonts');
});
// Elaborazione dei fonts personalizzati
gulp.task('srcFonts', function () {
gulp.src([
config.development + '/' + config.paths.fonts + '/**/*.{otf,eot,svg,ttf,woff,woff2}',
])
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.fonts));
});
gulp.task('ckeditor', function () {
gulp.src([
config.main.bowerDirectory + '/ckeditor/{adapters,lang,skins}/**/*',
])
.pipe(gulp.dest(config.production + '/' + config.paths.js));
gulp.src([
config.main.bowerDirectory + '/ckeditor/{ckeditor,styles}.js',
])
.pipe(gulp.dest(config.production + '/' + config.paths.js));
});
gulp.task('colorpicker', function () {
gulp.src([
config.main.bowerDirectory + '/bootstrap-colorpicker/dist/**/*.{jpg,png,jpeg}',
])
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.images + '/bootstrap-colorpicker'));
});
// Elaborazione e minificazione delle informazioni sull'internazionalizzazione
gulp.task('i18n', function () {
gulp.src([
config.main.bowerDirectory + '/**/{i18n,lang,locale,locales}/*.{js,json}',
config.development + '/' + config.paths.js + '/i18n/**/*.{js,json}',
'!' + config.main.bowerDirectory + '/**/{src,plugins}/**',
'!' + config.main.bowerDirectory + '/ckeditor/**',
'!' + config.main.bowerDirectory + '/jquery-ui/**',
])
.pipe(gulpIf('*.js', minifyJS(), gulpIf('*.json', minifyJSON())))
.pipe(gulpIf('!*.min.*', rename({
suffix: '.min'
})))
.pipe(flatten({
includeParents: 1
}))
.pipe(gulp.dest(config.production + '/' + config.paths.js + '/i18n'));
});
// PHP DebugBar assets
gulp.task('php-debugbar', function () {
gulp.src([
'./vendor/maximebf/debugbar/src/DebugBar/Resources/**/*',
])
.pipe(gulpIf('*.css', minifyCSS(), gulpIf('*.js', minifyJS())))
.pipe(gulp.dest(config.production + '/php-debugbar'));
});
// Operazioni per la release
gulp.task('release', function () {
var archiver = require('archiver');
var fs = require('fs');
shell.exec('svn info --show-item=revision . > REVISION');
del([
'./vendor/tecnickcom/tcpdf/fonts/*',
'!./vendor/tecnickcom/tcpdf/fonts/*helvetica*',
]);
var output = fs.createWriteStream('./release.zip');
var archive = archiver('zip');
output.on('close', function() {
console.log('done!');
});
archive.on('error', function(err) {
throw err;
});
archive.pipe(output);
archive.glob('**/*', {
dot: true,
ignore: [
'.svn/**',
'node_modules/**',
'backup/**',
'files/**',
'config.inc.php',
'*.lock',
'*.phar',
'**/*.log',
'**/*.zip',
'**/*.bak',
'**/~*',
]
});
archive.file('backup/.htaccess');
archive.file('files/.htaccess');
archive.file('files/my_impianti/componente.ini');
archive.finalize();
});
// Pulizia
gulp.task('clean', function () {
return del([config.production]);
});
// Operazioni di default per la generazione degli assets
gulp.task('bower', ['clean'], function () {
gulp.start('JS');
gulp.start('CSS');
gulp.start('images');
gulp.start('fonts');
gulp.start('other');
});
// Operazioni particolari per la generazione degli assets
gulp.task('other', ['clean'], function () {
gulp.start('ckeditor');
gulp.start('colorpicker');
gulp.start('i18n');
gulp.start('php-debugbar');
});
gulp.task('default', ['clean', 'bower']);

1
include/.htaccess Normal file
View File

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

54
include/bottom.php Normal file
View File

@ -0,0 +1,54 @@
<?php
include_once __DIR__.'/../core.php';
if (Auth::check()) {
echo '
</div><!-- /.row -->
</section><!-- /.content -->
</aside><!-- /.content-wrapper -->
<footer class="main-footer">
<span class="pull-right hidden-xs">
<strong>'._('Versione').' '.$version.'</strong>
<small class="text-muted">('.(!empty($revision) ? 'R'.$revision : _('In sviluppo')).')</small>
</span>
'._('OpenSTAManager').'
</footer>
<div class="modal fade" id="bs-popup" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false"></div>
<div class="modal fade" id="bs-popup2" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false"></div>
<a href="#" id="back-to-top">
<span><i class="fa fa-2x fa-chevron-up"></i></span>
</a>';
}
echo '
</div><!-- ./wrapper -->';
if (Auth::check()) {
if (!empty($_SESSION['keep_alive'])) {
echo '
<script> setInterval("session_keep_alive()", 5*60*1000); </script>';
}
if (get_var('CSS Personalizzato') != '') {
echo '
<style>'.get_var('CSS Personalizzato').'</style>';
}
if (!empty($debugbarRenderer)) {
echo $debugbarRenderer->render();
}
}
echo '
<script>
// Rimozione del messaggio automatico riguardante la modifica di valori nella pagina
window.onbeforeunload = null;
</script>
</body>
</html>';
unset($_SESSION['infos']);
unset($_SESSION['errors']);
unset($_SESSION['warnings']);

450
include/configuration.php Normal file
View File

@ -0,0 +1,450 @@
<?php
include_once __DIR__.'/../core.php';
$valid_config = isset($db_host) && isset($db_name) && isset($db_username) && isset($db_password);
// Gestione del file di configurazione
if (file_exists('config.inc.php') && $valid_config && $dbo->isConnected()) {
return;
}
$pageTitle = _('Configurazione');
if (file_exists($docroot.'/include/custom/top.php')) {
include_once $docroot.'/include/custom/top.php';
} else {
include_once $docroot.'/include/top.php';
}
// Controllo sull'esistenza di nuovi parametri di configurazione
if (post('db_host') !== null) {
$db_host = post('db_host');
$db_name = post('db_name');
$db_username = post('db_username');
$db_password = post('db_password');
$_SESSION['osm_password'] = post('osm_password');
$_SESSION['osm_email'] = post('osm_email');
$valid_config = isset($db_host) && isset($db_name) && isset($db_username) && isset($db_password);
// Generazione di una nuova connessione al database
$dbo = Database::getConnection(true);
if ($dbo->isConnected()) {
// Impostazioni di configurazione strettamente necessarie al funzionamento del progetto
$backup_config = '<?php
$backup_dir = __DIR__.\'/backup/\';
$db_host = \'|host|\';
$db_username = \'|username|\';
$db_password = \'|password|\';
$db_name = \'|database|\';
';
$new_config = (file_exists($docroot.'/config.example.php')) ? file_get_contents($docroot.'/config.example.php') : $backup_config;
$values = [
'|host|' => $db_host,
'|username|' => $db_username,
'|password|' => $db_password,
'|database|' => $db_name,
];
$new_config = str_replace(array_keys($values), $values, $new_config);
// Controlla che la scrittura del file di configurazione sia andata a buon fine
$creation = file_put_contents('config.inc.php', $new_config);
if (!$creation) {
echo '
<div class="box box-center box-danger box-solid text-center">
<div class="box-header with-border">
<h3 class="box-title">'._('Permessi di scrittura mancanti').'</h3>
</div>
<div class="box-body">
<p>'.str_replace('_FILE_', '<b>config.inc.php</b>', _('Sembra che non ci siano i permessi di scrittura sul file _FILE_')).'</p>
<form action="'.$rootdir.'/index.php?action=updateconfig&firstuse=true" method="post">
<div class="hide">
<input type="hidden" name="db_name" value="'.$db_name.'">
<input type="hidden" name="db_password" value="'.$db_password.'">
<input type="hidden" name="db_username" value="'.$db_username.'">;
<input type="hidden" name="db_host" value="'.$db_host.'">
</div>
<a class="btn btn-warning" href="'.$rootdir.'/index.php"><i class="fa fa-arrow-left"></i> '._('Torna indietro').'</a>
<button class="btn btn-info"><i class="fa fa-repeat"></i> '._('Riprova').'</button>
</form>
<hr>
<div class="box box-default collapsed-box">
<div class="box-header with-border">
<h4 class="box-title"><a class="clickable" data-widget="collapse">'._('Creazione manuale').'...</a></h4>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="box-body">
<p>'.str_replace('_FILE_', '<b>config.inc.php</b>', _('Inserire il seguente testo nel file _FILE_')).'</p>
<pre class="text-left">'.htmlentities($new_config).'</pre>
</div>
</div>
</div>
</div>';
}
// Continua con l'esecuzione delle operazioni previste
else {
redirect(ROOTDIR.'/index.php');
exit();
}
}
}
// Controlla che i parametri di configurazione permettano l'accesso al database
if ((file_exists('config.inc.php') || $valid_config) && !$dbo->isConnected()) {
echo '
<div class="box box-center box-danger box-solid text-center">
<div class="box-header with-border">
<h3 class="box-title">'._('Impossibile connettersi al database').'</h3>
</div>
<div class="box-body">
<p>'._("Si è verificato un'errore durante la connessione al database").'.</p>
<p>'._('Controllare di aver inserito correttamente i dati di accesso, e che il database atto ad ospitare i dati del gestionale sia esistente').'.</p>
<a class="btn btn-info" href="'.$rootdir.'/index.php"><i class="fa fa-repeat"></i> '._('Riprova').'</a>
</div>
</div>';
}
// Visualizzazione dell'interfaccia di impostazione iniziale, nel caso il file di configurazione sia mancante oppure i paramentri non siano sufficienti
if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) {
if (file_exists('config.inc.php')) {
echo '
<div class="box box-center box-danger box-solid text-center">
<div class="box-header with-border">
<h3 class="box-title">'._('Parametri non sufficienti!').'</h3>
</div>
<div class="box-body">
<p>'._("L'avvio del software è fallito a causa dell'assenza di alcuni paramentri nella configurazione di base").'.</p>
<p>'.str_replace('_CONFIG_', '<b>config.inc.php</b>', _("Si prega di controllare che il file _CONFIG_ contenga tutti i dati inseriti durante la configurazione iniziale (con l'eccezione di password e indirizzo email amministrativi)")).'.</p>
<p>'._("Nel caso il problema persista, rivolgersi all'assistenza ufficiale").'.</p>
<a class="btn btn-info" href="'.$rootdir.'/index.php"><i class="fa fa-repeat"></i> '._('Riprova').'</a>
</div>
</div>';
}
// Controlli per essere sicuro che l'utente abbia letto la licenza
echo '
<script>
$(document).ready(function(){
$("#smartwizard").smartWizard({
useURLhash: false,
showStepURLhash: false,
theme: "default",
transitionEffect: "slideLeft",
lang : {
next: "'._('Successivo').'",
previous: "'._('Precedente').'",
}
});
$("#smartwizard").on("leaveStep", function(e, anchorObject, stepNumber, stepDirection) {
result = true;
if(stepDirection == "forward" && $("#step-" + (stepNumber + 1) + " form").length){
result = $("#step-" + (stepNumber + 1) + " form").parsley().validate();
}
if(!result){
swal("'._('Impossibile procedere').'", "'._('Prima di proseguire devi completare i campi obbligatori!').'", "error");
}
$("html, body").animate({ scrollTop: $("#steps").offset().top }, 500);
return result;
});
});
</script>';
echo '
<div class="box box-center-large box-warning">
<div class="box-header with-border text-center">
<img src="'.$img.'/logo.png" alt="'._('OSM Logo').'">
<h3 class="box-title">'._('OpenSTAManager').'</h3>
</div>
<div class="box-body" id="smartwizard">';
// REQUISITI PER IL CORRETTO FUNZIONAMENTO
echo '
<ul>
<li><a href="#step-1">
<h3>'._('Requisiti').'</h3>
</a></li>
<li><a href="#step-2">
<h3>'._('Licenza').'</h3>
</a></li>
<li><a href="#step-3">
<h3>'._('Configurazione').'</h3>
</a></li>
</ul>
<div id="steps">
<div id="step-1">
<p>'._('Un benvenuto da OpenSTAManager!').'</p>
<p>'._("Prima di procedere alla configurazione e all'installazione del software, sono necessari alcuni accorgimenti per garantire il corretto funzionamento del gestionale").'.</p>
<hr>';
// Estensioni di PHP
echo '
<div class="row">
<div class="col-xs-12 col-md-6">
<p>'.str_replace('_FILE_', '<i>php.ini</i>', _('Le seguenti estensioni PHP devono essere abilitate dal file di configurazione _FILE_')).':</p>
<div class="list-group">';
$extensions = [
'zip' => _("Necessario per l'utilizzo delle funzioni di aggiornamento automatico e backup, oltre che per eventuali moduli aggiuntivi"),
'pdo_mysql' => _('Necessario per la connessione al database'),
'openssl' => _('Utile per la generazione di chiavi complesse (non obbligatorio)'),
];
foreach ($extensions as $key => $value) {
$check = extension_loaded($key);
echo '
<div class="list-group-item">
<h4 class="list-group-item-heading">
'.$key;
if ($check) {
echo '
<span class="label label-success pull-right">
<i class="fa fa-check"></i>
</span>';
} else {
echo '
<span class="label label-danger pull-right">
<i class="fa fa-times"></i>
</span>';
}
echo '
</h4>
<p class="list-group-item-text">'.$value.'</p>
</div>';
}
echo '
</div>
<hr>
</div>';
// Impostazione di valore per PHP
echo '
<div class="col-xs-12 col-md-6">
<p>'.str_replace('_FILE_', '<i>php.ini</i>', _('Le seguenti impostazioni PHP devono essere modificate nel file di configurazione _FILE_')).':</p>
<div class="list-group">';
$values = [
'display_errors' => true,
'upload_max_filesize' => '>16M',
'post_max_size' => '>16M',
];
foreach ($values as $key => $value) {
$ini = str_replace(['k', 'M'], ['000', '000000'], ini_get($key));
$real = str_replace(['k', 'M'], ['000', '000000'], $value);
if (starts_with($real, '>')) {
$check = $ini >= substr($real, 1);
} elseif (starts_with($real, '<')) {
$check = $ini <= substr($real, 1);
} else {
$check = ($real == $ini);
}
if (is_bool($value)) {
$value = !empty($value) ? 'On' : 'Off';
} else {
$value = str_replace(['>', '<'], '', $value);
}
echo '
<div class="list-group-item">
<h4 class="list-group-item-heading">
'.$key;
if ($check) {
echo '
<span class="label label-success pull-right">
<i class="fa fa-check"></i>
</span>';
} else {
echo '
<span class="label label-danger pull-right">
<i class="fa fa-times"></i>
</span>';
}
echo '
</h4>
<p class="list-group-item-text">'._('Valore consigliato').': '.$value.'</p>
</div>';
}
echo '
</div>
<hr>
</div>
</div>';
// Percorsi necessari
echo '
<div class="row">
<div class="col-xs-12">
<p>'._('Le seguenti cartelle devono risultare scrivibili da parte del gestionale').':</p>
<div class="list-group">';
$dirs = [
'backup' => _('Necessario per il salvataggio dei backup'),
'files' => _('Necessario per il salvataggio di file inseriti dagli utenti'),
'logs' => _('Necessario per la gestione dei file di log'),
];
foreach ($dirs as $key => $value) {
$check = is_writable($docroot.DIRECTORY_SEPARATOR.$key);
echo '
<div class="list-group-item">
<h4 class="list-group-item-heading">
'.$key;
if ($check) {
echo '
<span class="label label-success pull-right">
<i class="fa fa-check"></i>
</span>';
} else {
echo '
<span class="label label-danger pull-right">
<i class="fa fa-times"></i>
</span>';
}
echo '
</h4>
<p class="list-group-item-text">'.$value.'</p>
</div>';
}
echo '
</div>
<hr>
</div>
</div>
</div>';
// LICENZA
echo '
<div id="step-2">
<p>'.str_replace('_LICENSE_', 'GPL 3.0', _('OpenSTAManager è tutelato dalla licenza _LICENSE_!')).'</p>
<div class="row">
<div class="col-xs-12 col-md-8">
<span class="pull-left" title='._('Visiona e accetta la licenza per proseguire').' >'._('Accetti la licenza GPLv3 di OpenSTAManager?').'*</span>
</div>
<form class="col-xs-12 col-md-4">
<input type="checkbox" id="agree" name="agree" data-parsley-required="true">
<label for="agree">'._('Ho visionato e accetto').'.</label>
</form>
</div>
<hr>
<textarea class="form-control autosize" rows="15" readonly>'.file_get_contents('LICENSE').'</textarea><br>
<a class="pull-left" href="https://www.gnu.org/licenses/translations.en.html#GPL" target="_blank">[ '._('Versioni tradotte').' ]</a><br><br>
</div>';
$host = !empty($db_host) ? $db_host : '';
$username = !empty($db_username) ? $db_username : '';
$password = !empty($db_password) ? $db_password : '';
$name = !empty($db_name) ? $db_name : '';
$osm_password = !empty($_SESSION['osm_password']) ? $_SESSION['osm_password'] : '';
$osm_email = !empty($_SESSION['osm_email']) ? $_SESSION['osm_email'] : '';
// PARAMETRI
echo '
<div id="step-3">
<a href="http://www.openstamanager.com/contattaci/?subject=Assistenza%20installazione%20OSM" target="_blank" ><img class="pull-right" width="32" src="'.$img.'/help.png" alt="'._('Aiuto').'" title="'._('Contatta il nostro help-desk').'"/></a>
<p>'._('Non hai ancora configurato OpenSTAManager').'.</p>
<p><small class="help-block">'.str_replace('_CONFIG_', '<b>config.inc.php</b>', _('Configura correttamente il software con i seguenti parametri (modificabili successivamente dal file _CONFIG_)')).'</small></p>';
// Form dei parametri
echo '
<form action="?action=updateconfig&firstuse=true" method="post" id="config_form">
<div class="row">';
// db_host
echo '
<div class="col-xs-12">
{[ "type": "text", "label": "'._('Host del database').'", "name": "db_host", "placeholder": "'._("Indirizzo dell'host del database").'", "value": "'.$host.'", "help": "'._('Esempio').': <i>localhost</i>", "show-help": 1, "required": 1 ]}
</div>
</div>
<div class="row">';
// db_username
echo '
<div class="col-xs-12 col-md-4">
{[ "type": "text", "label": "'._("Username dell'utente MySQL").'", "name": "db_username", "placeholder": "'._("Username dell'utente MySQL").'", "value": "'.$username.'", "help": "'._('Esempio').': <i>root</i>", "show-help": 1, "required": 1 ]}
</div>';
// db_password
echo '
<div class="col-xs-12 col-md-4">
{[ "type": "password", "label": "'._("Password dell'utente MySQL").'", "name": "db_password", "placeholder": "'._("Password dell'utente MySQL").'", "value": "'.$password.'", "help": "'._('Esempio').': <i>mysql</i>", "show-help": 1 ]}
</div>';
// db_name
echo '
<div class="col-xs-12 col-md-4">
{[ "type": "text", "label": "'._('Nome del database').'", "name": "db_name", "placeholder": "'._('Nome del database').'", "value": "'.$name.'", "help": "'._('Esempio').': <i>openstamanager</i>", "show-help": 1, "required": 1 ]}
</div>
</div>
<div class="row">';
// Password utente admin
echo '
<div class="col-xs-12 col-md-6">
{[ "type": "password", "label": "'._("Password dell'amministratore").'", "name": "osm_password", "placeholder": "'._('Scegli la password di amministratore').'", "value": "'.$osm_password.'", "help": "'._('Valore di default').': <i>admin</i>", "show-help": 1 ]}
</div>';
// Email utente admin
echo '
<div class="col-xs-12 col-md-6">
{[ "type": "email", "label": "'._("Email dell'amministratore").'", "name": "osm_email", "placeholder": "'._("Digita l'indirizzo email dell'amministratore").'", "value": "'.$osm_email.'" ]}
</div>
</div>';
echo '
';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-4">
<span>*<small><small>'._('Campi obbligatori').'</small></small></span>
</div>
<div class="col-md-8 text-right">
<button type="submit" class="btn btn-success btn-block">
<i class="fa fa-check"></i> '._('Prosegui').'
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>';
}
if (file_exists($docroot.'/include/custom/bottom.php')) {
include_once $docroot.'/include/custom/bottom.php';
} else {
include_once $docroot.'/include/bottom.php';
}
exit();

193
include/manager.php Normal file
View File

@ -0,0 +1,193 @@
<?php
include_once __DIR__.'/../core.php';
// Lettura parametri iniziali del modulo
if (!empty($id_plugin)) {
$info = Plugins::getPlugin($id_plugin);
if (!empty($info['script'])) {
// Inclusione di eventuale plugin personalizzato
if (file_exists($docroot.'/modules/'.$info['module_dir'].'/plugins/custom/'.$info['script'])) {
include $docroot.'/modules/'.$info['module_dir'].'/plugins/custom/'.$info['script'];
} elseif (file_exists($docroot.'/modules/'.$info['module_dir'].'/plugins/'.$info['script'])) {
include $docroot.'/modules/'.$info['module_dir'].'/plugins/'.$info['script'];
}
return;
}
echo '
<h4>
'.$info['name'];
if (file_exists($docroot.'/plugins/'.$info['directory'].'/add.php')) {
echo '
<button type="button" class="btn btn-primary" data-toggle="modal" data-title="'._('Aggiungi').'..." data-target="#bs-popup" data-href="add.php?id_module='.$id_module.'&id_plugin='.$id_plugin.'&id_parent='.$id_record.'"><i class="fa fa-plus"></i></button>';
}
echo '
</h4>';
$total = Plugins::getQuery($id_plugin);
$directory = '/plugins/'.$info['directory'];
} else {
$info = Modules::getModule($id_module);
$total = Modules::getQuery($id_module);
$directory = '/modules/'.$info['directory'];
}
$module_options = (!empty($info['options2'])) ? $info['options2'] : $info['options'];
// Caricamento file aggiuntivo su elenco record
if (file_exists($docroot.$directory.'/custom/controller_before.php')) {
include $docroot.$directory.'/custom/controller_before.php';
} elseif (file_exists($docroot.$directory.'/controller_before.php')) {
include $docroot.$directory.'/controller_before.php';
}
/*
* Datatables con record
*/
if (!empty($module_options) && $module_options != 'menu' && $module_options != 'custom') {
$table_id = 'main_'.rand(0, 99);
echo '
<table data-idmodule="'.$id_module.'" data-idplugin="'.$id_plugin.'" data-idparent="'.$id_record.'" id="'.$table_id.'" width="100%" class="main-records table table-condensed table-bordered">
<thead>
<tr>
<th id="th_selector"></th>';
foreach ($total['fields'] as $key => $field) {
$attr_td = '';
$name = trim($field);
// Check per tipologie di campi particolari
if (preg_match('/^color_/', $field)) {
$attr_td .= " width='140'";
$field = str_replace('color_', '', $field);
}
// Data (larghezza fissa)
elseif (preg_match('/^Data/', $field)) {
$attr_td .= " width='100'";
}
// Icona di stampa
elseif (trim($field) == '_print_') {
$attr_td .= " width='30'";
$field = str_replace('_print_', '', $field);
} elseif (preg_match('/^icon_/', $field)) {
$attr_td .= " width='30'";
$name = str_replace('icon_', 'icon_title_', $name);
$field = str_replace('icon_', '', $field);
}
echo '
<th'.$attr_td.' id="th_'.str_replace([' ', '.'], ['-', ''], $name).'"';
if ($total['search'][$key] == 1) {
echo ' class="search"';
} else {
echo ' class="no-search"';
}
if ($total['slow'][$key] == 1) {
echo ' data-slow="1"';
}
echo '>'.$field.'</th>';
}
echo '
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>';
foreach ($total['fields'] as $key => $field) {
echo '
<td></td>';
}
echo '
</tr>
</tfoot>
</table>';
$bulk = null;
if (file_exists($docroot.$directory.'/custom/bulk.php')) {
$bulk = include $docroot.$directory.'/custom/bulk.php';
} elseif (file_exists($docroot.$directory.'/bulk.php')) {
$bulk = include $docroot.$directory.'/bulk.php';
}
$bulk = (array) $bulk;
$tr = [
'delete' => _('Elimina selezione'),
];
echo '
<div class="row" data-target="'.$table_id.'">
<div class="col-xs-12 col-md-5">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-select-all">'._('Seleziona tutto').'</button>
<button type="button" class="btn btn-default btn-select-none">'._('Deseleziona tutto').'</button>
</div>
</div>
<div class="col-xs-12 col-md-2 dropdown">';
if (!empty($bulk)) {
echo '
<button class="btn btn-primary btn-block dropdown-toggle bulk-container disabled" type="button" data-toggle="dropdown" disabled>'._('Azioni di gruppo').' <span class="caret"></span></button>
<ul class="dropdown-menu" data-target="'.$table_id.'" role="menu">';
foreach ($bulk as $key => $value) {
echo '
<li role="presentation"><a class="bulk-action" data-op="'.$value.'">'.$tr[$key].'</a></li>';
}
echo '
</ul>';
}
echo '
</div>
<div class="col-xs-12 col-md-5 text-right">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary btn-csv disabled" disabled>'._('Esporta').'</button>
<button type="button" class="btn btn-default btn-copy disabled" disabled>'._('Copia').'</button>
<button type="button" class="btn btn-default btn-print disabled" disabled>'._('Stampa').'</button>
</div>
</div>
</div>';
}
/*
* Inclusione modulo personalizzato
*/
elseif ($module_options == 'custom') {
// Inclusione elementi fondamentali del modulo
include $docroot.'/actions.php';
// Lettura template modulo (verifico se ci sono template personalizzati, altrimenti uso quello base)
if (file_exists($docroot.$directory.'/custom/edit.php')) {
include $docroot.$directory.'/custom/edit.php';
} elseif (file_exists($docroot.$directory.'/custom/edit.html')) {
include $docroot.$directory.'/custom/edit.html';
} elseif (file_exists($docroot.$directory.'/edit.php')) {
include $docroot.$directory.'/edit.php';
} elseif (file_exists($docroot.$directory.'/edit.html')) {
include $docroot.$directory.'/edit.html';
}
}
// Caricamento file aggiuntivo su elenco record
if (file_exists($docroot.$directory.'/custom/controller_after.php')) {
include $docroot.$directory.'/custom/controller_after.php';
} elseif (file_exists($docroot.$directory.'/controller_after.php')) {
include $docroot.$directory.'/controller_after.php';
}

275
include/top.php Normal file
View File

@ -0,0 +1,275 @@
<?php
include_once __DIR__.'/../core.php';
if (!empty($debugbar)) {
$debugbarRenderer = $debugbar->getJavascriptRenderer();
$debugbarRenderer->setIncludeVendors(false);
$debugbarRenderer->setBaseUrl($assets.'/php-debugbar');
}
echo '
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>'.$pageTitle.' - '._('OpenSTAManager').'</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOW5ykAAAAAFYfm/xZ/5a4AAAAAGHDkWgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGe55cTluf8AAAAABWH5v8Wf+W2AAAAABhw5P8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD67o/wAAAAAOda0KE5bn/xSP5v8Vh+b/Fn/l/xd35f8YcOT/Aw0dARRHqxIcWOPWAAAAAAAAAAAAAAAAAAAAAA+u6LwQpuj/Ep7n/xOW5/8Uj+b/FYfm/xZ/5f8Xd+X/GHDk/xpo5P8bX+P/FUKqKQAAAAAAAAAAAAAAAAVEVwILga4cEKbo/xKe5/8Tluf/FI/m/xWH5v4Wf+X+F3fl/xhw5P8aaOT/G1/j/wAAAAASMo41AAAAAA2+6aoOtuj/D6/o/xCm6P8Snuf/E5bn9w9rrQEAAAAAAAAAABRnyAMYcOT7Gmjk/xtf4/8cWOP/HVDj/xMujWwUMVr/FDFa/xQxWv8UU5j/FFOY/xQ0YP8UPnP/FFOY/xRTmP8UMl3/FEqG/xQxWv8UMFn/E0mF/xQxWv8UMVr/FDFa/xQxWv8TU5b/FDFa/xQxWv8TXKf/FDFa/xQxWv8UMVr/E3fY/xJ53P8ShO3/Ennd/xJ74P8UMVr/FDFa/xQxWv8UMVr/E1OW/xQxWv8UMVr/E1yn/xNvyv8UMVr/FDFa/xQxWv8SeNv/FDJb/xQxWv8ShvP/FDFa/xQxWv8UMVrzFDFa8xQ3Yf8UN2L/FDdi/xQxWvMUMVrzFDJc8xQyXPMUMVrzFDJb8xQ0Yf8UM2H/FTVj/xQxWvMUMVrzDb3pRw626P0Pr+j/EKbo/xKe5/8Tluf9AAAAAAAAAAAAAAAAAAAAABhv5P8aaOT/G1/j/xxY4/8dUOP/Ey6NYwAAAAAOtuicD63oehCm6P8Snuf/E5bn/xSP5v8Vh+b9Fn/l/Rd35f8YcOT/Gmjk/xtf4/8VQqoYFjyqSxMvjQIAAAAAAAAAAAIWHQ8Qpuj/Ep7n/xOW5/8Uj+b/FYfm/xZ/5f8Xd+X/GHDk/xpo5P8bX+P/BAscCwAAAAAAAAAAAAAAAAAAAAAPr+j3DH2uSxKe55wTluf/FI/m/xWH5v8Wf+X/F3fl/xhw5P8UTqskG1/kWBxY4/YAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASnOcQE5bn/xJ8yRQVh+b/Fn/l8xRnyBMYcOT/EUKPIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC2KQAxOW59cAAAAAFYfm/xZ/5a4AAAAAGHDkvwAAAAAAAAAAAAAAAAAAAAAAAAAA/n8AAPJfAADYGwAAwAcAAOAHAAADwQAAAAAAAAAAAAAAAAAAAAAAAIPBAACgBwAA4AcAANAbAAD6XwAA+l8AAA==" rel="icon" type="image/x-icon" />';
foreach ($css_modules as $style) {
$style = (is_array($style)) ? $style : ['href' => $style, 'media' => 'all'];
echo '
<link rel="stylesheet" type="text/css" media="'.$style['media'].'" href="'.$style['href'].'"/>';
}
if (Auth::check()) {
echo '
<script>
search = []';
$array = [];
foreach ($_SESSION as $idx1 => $arr2) {
if ($idx1 == 'module_'.$id_module) {
foreach ($arr2 as $field => $value) {
if ($value != '') {
$field_name = str_replace('search_', '', $field);
echo '
search.push("search_'.$field_name.'");
search["search_'.$field_name.'"] = "'.$value.'";';
}
}
}
}
echo '
translations = {';
$translations = [
'day' => _('Giorno'),
'week' => _('Settimana'),
'month' => _('Mese'),
'today' => _('Oggi'),
'yesterday' => _('Ieri'),
'last7Days' => _('Ultimi 7 giorni'),
'last30Days' => _('Ultimi 30 giorni'),
'thisMonth' => _('Questo mese'),
'lastMonth' => _('Mese scorso'),
'thisYear' => _("Quest'anno"),
'lastYear' => _('Anno scorso'),
'apply' => _('Applica'),
'cancel' => _('Annulla'),
'from' => _('Da'),
'to' => _('A'),
'custom' => _('Personalizzato'),
'delete' => _('Elimina'),
'deleteTitle' => _('Sei sicuro?'),
'deleteMessage' => _('Eliminare questo elemento?'),
'close' => _('Chiudi'),
'filter' => _('Filtra'),
'long' => _('La ricerca potrebbe richiedere del tempo'),
'details' => _('Dettagli'),
'csv' => _('Esporta'),
'print' => _('Stampa'),
'copy' => _('Copia'),
'waiting' => _('Impossibile procedere'),
'waiting_msg' => _('Prima di proseguire devi selezionare alcuni elementi!'),
];
foreach ($translations as $key => $value) {
echo '
'.$key.': \''.addslashes($value).'\',';
}
echo '
};
globals = {
rootdir: \''.$rootdir.'\', js: \''.$js.'\', css: \''.$css.'\', img: \''.$img.'\',
id_module: \''.$id_module.'\',
id_record: \''.$id_record.'\',
aggiornamenti_id: \''.($dbo->isInstalled() ? Modules::getModule('Aggiornamenti')['id'] : '').'\',
cifre_decimali: '.get_var('Cifre decimali per importi').',
decimals: "'.Translator::getLocaleFormatter()->getNumberSeparators()['decimals'].'", thousands: "'.Translator::getLocaleFormatter()->getNumberSeparators()['thousands'].'",
search: search,
translations: translations,
start_date: \''.Translator::dateToLocale($_SESSION['period_start']).'\',
end_date: \''.Translator::dateToLocale($_SESSION['period_end']).'\',
locale: \''.$lang.'\',
};
</script>';
}
foreach ($jscript_modules as $js) {
echo '
<script type="text/javascript" charset="utf-8" src="'.$js.'"></script>';
}
// Impostazioni di default per gli alert
echo '
<script>
swal.setDefaults({
buttonsStyling: false,
confirmButtonClass: "btn btn-lg btn-primary",
cancelButtonClass: "btn btn-lg",
cancelButtonText: "'._('Annulla').'",
});
</script>';
if (!empty($debugbarRenderer) && Auth::check()) {
echo $debugbarRenderer->renderHead();
}
echo '
</head>
<body class="skin-'.$theme.' fixed'.(!empty(get_var('Nascondere la barra sinistra di default')) ? ' sidebar-collapse' : '').(!Auth::check() ? ' hold-transition login-page' : '').'">
<div class="wrapper">';
if (Auth::check()) {
$calendar = ($_SESSION['period_start'] != date('Y').'-01-01' || $_SESSION['period_end'] != date('Y').'-12-31') ? 'red' : 'white';
echo '
<!-- Loader principale -->
<div id="main_loading">
<div>
<i class="fa fa-cog fa-spin text-danger"></i>
</div>
</div>
<!-- Loader secondario -->
<div id="mini-loader" style="display:none;">
<div></div>
</div>
<header class="main-header">
<a href="http://www.openstamanager.com" class="logo" target="_blank">
<!-- mini logo for sidebar mini 50x50 pixels -->
<span class="logo-mini">'._('OSM').'</span>
<!-- logo for regular state and mobile devices -->
<span class="logo-lg">'._('OpenSTAManager').'</span>
</a>
<!-- Header Navbar: style can be found in header.less -->
<nav class="navbar navbar-static-top" role="navigation">
<!-- Sidebar toggle button-->
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button">
<span class="sr-only">'._('Mostra/nascondi menu').'</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<div class="input-group btn-calendar pull-left">
<button id="daterange" class="btn"><i class="fa fa-calendar" style="color:'.$calendar.'"></i> <i class="fa fa-caret-down"></i></button>
</div>
<div id="right-menu" class="pull-right">
<button onclick="window.print()" class="btn btn-sm btn-info tip" title="'._('Stampa').'">
<i class="fa fa-print"></i>
</button>
<a href="'.$rootdir.'/bug.php" class="btn btn-sm btn-github tip" title="'._('Segnalazione bug').'">
<i class="fa fa-bug"></i>
</a>
<a href="'.$rootdir.'/log.php" class="btn btn-sm btn-github tip" title="'._('Log accessi').'">
<i class="fa fa-book"></i>
</a>
<a href="'.$rootdir.'/info.php" class="btn btn-sm btn-github tip" title="'._('Informazioni').'">
<i class="fa fa-info"></i>
</a>
<a href="'.$rootdir.'/index.php?op=logout" class="btn btn-sm btn-danger tip" title="'._('Esci').'">
<i class="fa fa-power-off"></i>
</a>
</div>
</nav>
</header>
<aside class="main-sidebar">
<section class="sidebar">
<!-- Sidebar user panel -->
<div class="user-panel text-center info">
<div class="info">
<p>'.$_SESSION['username'].'</p>
<p id="datetime"></p>
</div>
<div class="image">
<img src="'.$img.'/logo.png" class="img-circle img-responsive" alt="'._('OpenSTAManager').'" />
</div>
</div>
<!-- search form -->
<div class="sidebar-form">
<div class="input-group">
<input type="text" name="q" class="form-control" id="supersearch" placeholder="'._('Cerca').'..."/>
<span class="input-group-btn">
<button class="btn btn-flat" id="search-btn" name="search" type="submit" ><i class="fa fa-search"></i>
</button>
</span>
</div>
</div>
<!-- /.search form -->
<ul class="sidebar-menu">';
echo Modules::getMainMenu();
echo '
</ul>
</section>
<!-- /.sidebar -->
</aside>
<!-- Right side column. Contains the navbar and content of the page -->
<aside class="content-wrapper">
<!-- Main content -->
<section class="content">
<div class="row">';
if (strpos($_SERVER['SCRIPT_FILENAME'], 'editor.php') !== false) {
$location = 'editor_right';
} elseif (strpos($_SERVER['SCRIPT_FILENAME'], 'controller.php') !== false) {
$location = 'controller_right';
}
echo '
<div class="col-md-12">';
} elseif (!empty($_SESSION['infos']) || !empty($_SESSION['warnings']) || !empty($_SESSION['errors'])) {
echo '
<div class="box box-warning box-center">
<div class="box-header with-border text-center">
<h3 class="box-title">'._('Informazioni').'</h3>
</div>
<div class="box-body">';
}
// Infomazioni
foreach ($_SESSION['infos'] as $value) {
echo '
<div class="alert alert-success push">
<i class="fa fa-check"></i> '.$value.'
</div>';
}
// Errori
foreach ($_SESSION['errors'] as $value) {
echo '
<div class="alert alert-danger push">
<i class="fa fa-times"></i> '.$value.'
</div>';
}
// Avvisi
foreach ($_SESSION['warnings'] as $value) {
echo '
<div class="alert alert-warning push">
<i class="fa fa-warning"></i>
'.$value.'
</div>';
}
if (!Auth::check() && (!empty($_SESSION['infos']) || !empty($_SESSION['warnings']) || !empty($_SESSION['errors']))) {
echo '
</div>
</div>';
}

256
include/update.php Normal file
View File

@ -0,0 +1,256 @@
<?php
include_once __DIR__.'/../core.php';
$updateRate = 20;
$scriptValue = $updateRate * 3;
/*
* Aggiornamento tramite AJAX
*/
if (filter('action') == 'do_update') {
// Aggiornamento in progresso
if (Update::isUpdateAvailable()) {
$update = Update::getUpdate();
$result = Update::doUpdate($updateRate);
if (!empty($result)) {
// Aggiunta del messaggio generico riguardante l'aggiornamento
echo '
<script>
addVersion("'.$update['version'].'");
</script>';
if (is_array($result)) {
// Aggiunta del messaggio riguardante la conclusione dell'aggiornamento del database
if (!empty($update['sql']) && $result[1] == $result[2]) {
echo '
<script>
$("#progress .info").html($("#progress .info").html() + "<p>&nbsp;&nbsp;&nbsp;&nbsp;<i class=\"fa fa-check\"></i> '.str_replace('_FILENAME_', '<i>'.$update['filename'].'.sql</i>', _('Aggiornamento del database (_FILENAME_)')).'</p>");
</script>';
}
$rate = $result[1] - $result[0];
} elseif (!empty($update['script'])) {
// Aggiunta del messaggio riguardante la conclusione dello script
echo '
<script>
$("#progress .info").html($("#progress .info").html() + "<p>&nbsp;&nbsp;&nbsp;&nbsp;<i class=\"fa fa-check\"></i> '.str_replace('_FILENAME_', '<i>'.$update['filename'].'.php</i>', _('Esecuzione dello script di aggiornamento (_FILENAME_)')).'</p>");
</script>';
$rate = $scriptValue;
}
// Aumento della percentuale di completameno totale
if (!empty($rate)) {
echo '
<script>
addProgress('.$rate.');
</script>';
}
echo '
<script>
$("#result").load("index.php?action=do_update&firstuse='.$_GET['firstuse'].'");
</script>';
} else {
// Fallimento
echo '
<div class="alert alert-danger">
<i class="fa fa-times"></i> '.str_replace('_VERSION_', $update['version'], _("Errore durante l'esecuzione dell'aggiornamento alla versione _VERSION_")).'
</div>';
}
}
// Aggiornamento completato
elseif (Update::isUpdateCompleted()) {
Update::updateCleanup();
echo '
<p><strong>'._('Aggiornamento completato!!!').'</strong> <i class="fa fa-smile-o"></i></p>';
// Rimostro la finestra di login
echo '
<script>
$(".login-box").fadeIn();
</script>';
// Istruzioni per la prima installazione
if ($_GET['firstuse'] == 'true') {
if (!empty($_SESSION['osm_password'])) {
$password = $_SESSION['osm_password'];
} else {
$password = 'admin';
}
echo '
<p>'._('Puoi procedere al login con i seguenti dati').':</p>
<p>'._('Username').': <i>admin</i></p>
<p>'._('Password').': <i> '.$password.'</i></p>
<p class="text-danger">'.str_replace('_FILE_', '<b>config.inc.php</b>', _("E' fortemente consigliato rimuovere i permessi di scrittura dal file _FILE_")).'.</p>';
// Imposto la password di admin che l'utente ha selezionato all'inizio
if (isset($_SESSION['osm_password'])) {
$dbo->query('UPDATE `zz_users` SET `password`='.prepare(Auth::hashPassword($password))." WHERE `username`='admin'");
unset($_SESSION['osm_password']);
}
if (isset($_SESSION['osm_email'])) {
if (!empty($_SESSION['osm_email'])) {
$dbo->query('UPDATE `zz_users` SET `email`='.preare($_SESSION['osm_email'])." WHERE `username`='admin' ");
}
unset($_SESSION['osm_email']);
}
}
}
exit();
} elseif (Update::isUpdateAvailable()) {
// Controllo se l'aggiornamento è in esecuzione
if (Update::isUpdateLocked() && filter('force') === null) {
$pageTitle = _('Aggiornamento in corso!');
if (file_exists($docroot.'/include/custom/top.php')) {
include_once $docroot.'/include/custom/top.php';
} else {
include_once $docroot.'/include/top.php';
}
echo '
<div class="box box-center box-danger box-solid text-center">
<div class="box-header with-border">
<h3 class="box-title">'._('Aggiornamento in corso!').'</h3>
</div>
<div class="box-body">
<p>'._("E' attualmente in corso la procedura di aggiornamento del software, e pertanto siete pregati di attendere fino alla sua conclusione").'.</p>
<p>'._("Nel caso il problema persista, rivolgersi all'amministratore o all'assistenza ufficiale").'.</p>
<a class="btn btn-info" href="'.$rootdir.'/index.php"><i class="fa fa-repeat"></i> '._('Riprova').'</a>
</div>
</div>';
if (file_exists($docroot.'/include/custom/bottom.php')) {
include_once $docroot.'/include/custom/bottom.php';
} else {
include_once $docroot.'/include/bottom.php';
}
exit();
}
$firstuse = !$dbo->isInstalled() ? 'true' : 'false';
$button = !$dbo->isInstalled() ? _('Installa!') : _('Aggiorna!');
$pageTitle = !$dbo->isInstalled() ? _('Installazione') : _('Aggiornamento');
if (file_exists($docroot.'/include/custom/top.php')) {
include_once $docroot.'/include/custom/top.php';
} else {
include_once $docroot.'/include/top.php';
}
echo '
<div class="box box-center-large box-warning text-center">
<div class="box-header with-border">
<h3 class="box-title">'.(!$dbo->isInstalled() ? _('Installazione') : _('Aggiornamento')).'</h3>
</div>
<div class="box-body">';
if (!$dbo->isInstalled()) {
echo '
<p><strong>'._("E' la prima volta che avvii OpenSTAManager e non hai ancora installato il database").'.</strong></p>';
} else {
echo '
<p>'._("E' necessario aggiornare il database a una nuova versione").'.</p>';
}
echo '
<p>'.str_replace('_BUTTON_', '<b>"'.$button.'"</b>', _("Premi il tasto _BUTTON_ per procedere con l'aggiornamento!")).'</p>
<input type="button" class="btn btn-primary" value="'.$button.'" onclick="continue_update()" id="contine_button">
<script>
function continue_update(){
swal({
title: "'._('Sei sicuro?').'",
text: "'._("Continuare con l'aggiornamento?").'",
type: "warning",
showCancelButton: true,
confirmButtonClass: "btn btn-lg btn-success",
confirmButtonText: "'._('Procedi').'",
}).then(
function(){
$("#progress").show();
$("#result").load("index.php?action=do_update&firstuse='.$firstuse.'");
$("#contine_button").remove();
}, function(){});
}
</script>
<div id="progress">
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width:0%">
<span>0%</span>
</div>
</div>
<hr>
<div class="box box-info text-center collapsed-box">
<div class="box-header with-border">
<h3 class="box-title"><a class="clickable" data-widget="collapse">'._('Log').'</a></h3>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i></button>
</div>
</div>
<div class="box-body info text-left"></div>
</div>
</div>
<div id="result"></div>';
$total = 0;
$updates = Update::getTodos();
foreach ($updates as $update) {
if ($update['sql'] && $update['done'] !== 0) {
$queries = readSQLFile(DOCROOT.$update['directory'].$update['filename'].'.sql', ';');
$total += count($queries);
}
if ($update['script']) {
$total += $scriptValue;
}
if ($update['done'] > 1) {
$total -= $update['done'] - 2;
}
}
echo '
<script>
$(document).ready(function(){
$(".login-box").fadeOut();
count = '.count($updates).';
current = 0;
versions = [];
progress = 0;
total = '.$total.';
});
function addProgress(rate){
progress += rate;
percent = progress / total * 100;
percent = Math.round(percent);
$("#progress .progress-bar").width(percent + "%");
$("#progress .progress-bar span").text(percent + "%");
}
function addVersion(version){
if(versions.indexOf(version) === -1){
versions.push(version);
current += 1;
$("#progress .info").html($("#progress .info").html() + "<p><strong>'.str_replace(['_DONE_', '_TODO_', '_VERSION_'], ['" + current + "', '" + count + "', '" + version + "'], _('Aggiornamento _DONE_ di _TODO_ (_VERSION_)')).'</strong></p>");
}
}
</script>
</div>
</div>';
}

164
index.php Normal file
View File

@ -0,0 +1,164 @@
<?php
$skip_permissions = true;
include_once __DIR__.'/core.php';
$op = filter('op');
// LOGIN
switch ($op) {
case 'login':
$username = filter('username');
$password = filter('password');
if ($dbo->isConnected() && $dbo->isInstalled() && $auth->attempt($username, $password)) {
$_SESSION['keep_alive'] = (filter('keep_alive') != null);
// Auto backup del database giornaliero
if (get_var('Backup automatico')) {
$folders = glob($backup_dir.'*');
$regexp = '/'.date('Y\-m\-d').'/';
// Controllo se esiste già un backup zip o folder creato per oggi
if (!empty($folders)) {
$found = false;
foreach ($folders as $folder) {
if (preg_match($regexp, $folder, $matches)) {
$found = true;
}
}
}
if ($found) {
$_SESSION['infos'][] = _('Backup saltato perché già esistente!');
} elseif (do_backup()) {
$_SESSION['infos'][] = _('Backup automatico eseguito correttamente!');
} elseif (empty($backup_dir)) {
$_SESSION['errors'][] = _('Non è possibile eseguire i backup poichè la cartella di backup non esiste!!!');
} elseif (!file_exists($backup_dir)) {
if (mkdir($backup_dir)) {
$_SESSION['infos'][] = _('La cartella di backup è stata creata correttamente.');
if (do_backup()) {
$_SESSION['infos'][] = _('Backup automatico eseguito correttamente!');
}
} else {
$_SESSION['errors'][] = _('Non è stato possibile creare la cartella di backup!');
}
}
}
}
break;
case 'logout':
Auth::logout();
redirect(ROOTDIR.'/index.php');
exit();
break;
}
if (Auth::check() && isset($dbo) && $dbo->isConnected() && $dbo->isInstalled()) {
$module = $auth->getFirstModule();
if (!empty($module)) {
redirect(ROOTDIR.'/controller.php?id_module='.$module, 'js');
} else {
redirect(ROOTDIR.'/index.php?op=logout');
}
exit();
}
include_once $docroot.'/include/configuration.php';
include_once $docroot.'/include/update.php';
$pageTitle = _('Login');
if (file_exists($docroot.'/include/custom/top.php')) {
include_once $docroot.'/include/custom/top.php';
} else {
include_once $docroot.'/include/top.php';
}
// Controllo se è una beta e in caso mostro un warning
if (strpos($version, 'beta') !== false) {
echo '
<div class="alert alert-warning alert-dismissable pull-right fade in">
<i class="fa fa-warning"></i> <b>'._('Attenzione!').'</b> '._('Stai utilizzando una versione <b>non stabile</b> di OSM.').'
<button aria-hidden="true" data-dismiss="alert" class="close" type="button">×</button>
</div>';
}
if (!empty($_SESSION['errors'])) {
echo '
<script>
$(document).ready(function(){
$(".login-box").effect("shake");
});
</script>';
}
echo '
<form action="?op=login" method="post" class="login-box box">
<div class="box-header with-border text-center">
<img src="'.$img.'/logo.png" alt="'._('OSM Logo').'">
<h3 class="box-title">'._('OpenSTAManager').'</h3>
</div>
<!-- /.box-header -->
<div class="login-box-body box-body">
<div class="form-group input-group">
<span class="input-group-addon"><i class="fa fa-user"></i> </span>
<input type="text" name="username" autocomplete="off" class="form-control" placeholder="'._('Nome utente').'"';
if (isset($username)) {
echo ' value="'.$username.'"';
}
echo'>
</div>
<div class="form-group input-group">
<span class="input-group-addon"><i class="fa fa-lock"></i> </span>
<input type="password" name="password" autocomplete="off" class="form-control" placeholder="'._('Password').'">
</div>
<div class="form-group">
<input type="checkbox" name="keep_alive"';
if (filter('keep_alive') != null) {
echo ' checked';
}
echo '/> '._('Mantieni attiva la sessione').'
</div>
</div>
<!-- /.box-body -->
<div class="box-footer">
<button type="submit" id="login" class="btn btn-danger btn-block">'._('Accedi').'</button>
</div>
<!-- box-footer -->
</form>
<!-- /.box -->
<script>
$(document).ready( function(){
$("#login").click(function(){
$("#login").text("';
if ($dbo->isInstalled() && get_var('Backup automatico')) {
echo _('Backup automatico in corso');
} else {
echo _('Autenticazione');
}
echo '...");
});
if( $("input[name=username]").val() == ""){
$("input[name=username]").focus();
}
else{
$("input[name=password]").focus();
}
});
</script>';
if (file_exists($docroot.'/include/custom/bottom.php')) {
include_once $docroot.'/include/custom/bottom.php';
} else {
include_once $docroot.'/include/bottom.php';
}

157
info.php Normal file
View File

@ -0,0 +1,157 @@
<?php
include_once(__DIR__."/core.php");
$pageTitle = "Info";
if( file_exists($docroot."/include/custom/top.php") ){
include($docroot."/include/custom/top.php");
}
else{
include($docroot."/include/top.php");
}
?>
<div class="box">
<div class="box-header">
<img src="<?php echo $img ?>/logo.png" alt="<?php echo _("OSM Logo"); ?>">
<h3 class="box-title"><?php echo _("OpenSTAManager"); ?></h3>
<div class="pull-right">
<i class="fa fa-info"></i> <?php echo _("Informazioni") ?>
</div>
</div>
<div class="box-body">
<?php
if( file_exists("assistenza.php")) include("assistenza.php");
else{
?>
<div class="row">
<div class="col-xs-12 col-md-8">
<p><?php echo _('<b>OpenSTAManager</b> è un <b>software libero</b> ideato e sviluppato da <a href="mailto:info@openstamanager.com">Fabio Lovato</a>') ?>.</p>
<p><?php echo _('Il nome significa "Gestore di STA (<b>Servizio Tecnico Assistenza</b>) aperto" ed è stato creato per gestire e archiviare l\'assistenza tecnica fornita ai propri clienti') ?>.</p>
</div>
<div class="col-xs-12 col-md-4">
<p><b><?php echo _("Sito web") ?>:</b> <a href="http://www.openstamanager.com" target="_blank">http://www.openstamanager.com</a></p>
<p><b><?php echo _("Versione") ?>:</b> <?php echo $version.' <small class="text-muted">('.(!empty($revision) ? 'R'.$revision : _('In sviluppo')).')'; ?></small></p>
<p><b><?php echo _("Licenza") ?>:</b> <a href="http://www.gnu.org/licenses/gpl-3.0.txt" target="_blank" title="<?php echo _("Vai al sito per leggere la licenza")?>">GPLv3</a></p>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12 col-md-6">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title text-uppercase"><i class="fa fa-globe"></i> <?php echo _("Perchè software libero") ?></h3>
</div>
<div class="box-body">
<p><?php echo _("Il progetto è software libero perchè permette a tutti di conoscere come funziona avendo il codice sorgente del programma e fornisce così la possibilità di studiare come funziona, modificarlo, adattarlo alle proprie esigenze e, in ambito commerciale, non obbliga l'utilizzatore ad essere legato allo stesso fornitore di assistenza") ?>.</p>
<p><?php echo _("E' altrettanto importante sapere come funziona per conoscere come vengono trattati i VOSTRI dati, proteggendo così la vostra <b>privacy</b>") ?>.</p>
<p><?php echo _("OpenSTAManager è inoltre stato progettato utilizzando altro software libero, tra cui principalmente") ?>:</p>
<a href="http://www.php.net" target="_blank"><i class="fa fa-circle-o-notch"></i> PHP</a><br>
<a href="http://www.mysql.com" target="_blank"><i class="fa fa-circle-o-notch"></i> MySQL</a><br>
<a href="http://jquery.com" target="_blank"><i class="fa fa-circle-o-notch"></i> JQuery</a><br>
<a href="http://getbootstrap.com" target="_blank"><i class="fa fa-circle-o-notch"></i> Bootstrap</a><br>
<a href="http://fortawesome.github.io/Font-Awesome" target="_blank"><i class="fa fa-circle-o-notch"></i> FontAwesome</a><br>
<a href="http://html2pdf.fr/it/default" target="_blank"><i class="fa fa-circle-o-notch"></i> HTML2PDF</a>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="box box-danger">
<div class="box-header">
<h3 class="box-title text-uppercase"><i class="fa fa-group"></i> <?php echo _("Community") ?></h3>
</div>
<div class="box-body">
<p><?php echo _("La community è un componente importante in un progetto open source perchè mette in contatto le persone tra di loro, utenti e programmatori") ?>.</p>
<p><?php echo _("Con OpenSTAManager siamo presenti su") ?>:</p>
<div class="well">
<div class="row">
<div class="col-md-4 text-center">
<a href="http://www.openstamanager.com/forum/" target="_blank"><i class="fa fa-2x fa-edit"></i><br><?php echo _("Forum") ?></b></a>
</div>
<div class="col-md-4 text-center">
<a href="http://sourceforge.net/p/openstamanager/mailman/" target="_blank"><i class="fa fa-2x fa-envelope"></i><br><?php echo _("Mailing list") ?></a>
</div>
<div class="col-md-4 text-center">
<a href="https://www.facebook.com/openstamanager" target="_blank"><i class="fa fa-2x fa-facebook-square"></i><br><?php echo _("Pagina Facebook") ?></a>
</div>
</div>
</div>
</div>
</div>
<div class="box box-default">
<div class="box-header">
<h3 class="box-title text-uppercase"><i class="fa fa-download"></i> <?php echo _("Aggiornamenti e nuove versioni") ?></h3>
</div>
<div class="box-body">
<p><?php echo _("Tutti gli aggiornamenti e le nuove versioni sono disponibili all'indirizzo") ?>:</p>
<a href="http://www.openstamanager.com/downloads/" target="_blank"><i class="fa fa-external-link"></i> www.openstamanager.com/downloads/</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-md-6">
<div class="box box-warning">
<div class="box-header">
<h3 class="box-title text-uppercase"><i class="fa fa-money"></i> <?php echo _("Supporta il progetto") ?></h3>
</div>
<div class="box-body">
<p><?php echo _("OpenSTAManager è software libero ed è nato e cresciuto con il lavoro volontario di alcuni programmatori") ?>.</p>
<p><?php echo _("La filosofia del software libero fa sì che il progetto sia <b>accessibile a tutti</b> e nel nostro caso specifico lo è, anche dal punto di vista della gratuità") ?>.</p>
<p><?php echo _("Offriamo supporto a pagamento professionale a chi fosse interessato, ma a chi non interessa il supporto a pagamento e sta comunque utilizzando il software chiediamo una donazione per il lavoro svolto finora e per la possibilità di continuare questo progetto con lo stesso spirito con cui è nato. Con le donazioni non diventiamo ricchi, ma è un <b>grande
simbolo di apprezzamento</b>") ?>.</p>
<p>
<a href="http://sourceforge.net/donate/index.php?group_id=236538" class="btn btn-lg btn-success" target="_blank"><i class="fa fa-usd"></i> <?php echo _("Supporta questo progetto") ?></a>
<img src="http://images.sourceforge.net/images/project-support.jpg" border="0" alt="<?php echo _("Supporta questo progetto") ?>" class="pull-right"/>
</p>
</div>
</div>
</div>
<div class="col-xs-12 col-md-6">
<div class="box box-success">
<div class="box-header">
<h3 class="box-title text-uppercase"><i class="fa fa-euro"></i> <?php echo _("Servizi a pagamento") ?></h3>
</div>
<div class="box-body">
<p><?php echo _("Per le aziende che hanno necessità di essere seguite da <b>supporto professionale</b> è disponibile un servizio di assistenza e supporto a pagamento") ?>.</p>
<p><?php echo _("E' disponibile anche un <b>servizio cloud</b> su cui poter installare OpenSTAManager, in modo da non doverti più preoccupare di backup e gestione dei dati") ?>.</p>
<p><?php echo _("Tutte le informazioni su servizi e prezzi le potete trovare qui") ?>:</p>
<p><a href="http://www.openstamanager.com/per-le-aziende/" class="btn btn-lg btn-success" target="_blank"><i class="fa fa-thumbs-up"></i> <?php echo _("Ottieni supporto professionale") ?></a></p>
</div>
</div>
</div>
</div>
<?php
}
?>
</div>
</div>
<?php
if( file_exists($docroot."/include/custom/bottom.php") ){
include($docroot."/include/custom/bottom.php");
}
else{
include($docroot."/include/bottom.php");
}
?>

228
lib/classes/API.php Normal file
View File

@ -0,0 +1,228 @@
<?php
/**
* Classe per la gestione delle API del progetto.
*
* @since 2.3
*/
class API extends \Util\Singleton
{
protected static $resources;
protected static $status = [
'ok' => [
'code' => 200,
'message' => 'OK',
],
'internalError' => [
'code' => 400,
'message' => "Errore interno dell'API",
],
'unauthorized' => [
'code' => 401,
'message' => 'Non autorizzato',
],
'notFound' => [
'code' => 404,
'message' => 'Non trovato',
],
'serverError' => [
'code' => 500,
'message' => 'Errore del server',
],
];
public function __construct($token)
{
$user = Auth::getUser();
if (!self::isAPIRequest() || empty($user)) {
throw new InvalidArgumentException();
}
}
public function retrieve($resource)
{
$table = '';
$select = '*';
// Selezione personalizzata
$display = filter('display');
$select = !empty($display) ? explode(',', substr($display, 1, -1)) : $select;
$where = [];
// Ricerca personalizzata
$filter = (array) filter('filter');
foreach ($filter as $key => $value) {
$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;
}
$order = [];
// Ordinamento personalizzato
$order_request = (array) filter('order');
foreach ($order_request as $value) {
$pieces = explode('|', $value);
$order[] = empty($pieces[1]) ? $pieces[0] : [$pieces[0] => $pieces[1]];
}
// Date di interesse
$updated = filter('upd');
$created = filter('crd');
$dbo = Database::getConnection();
$kind = 'retrieve';
$resources = self::getResources()[$kind];
if (!in_array($resource, $resources)) {
$excluded = explode(',', Settings::get('Tabelle escluse per la sincronizzazione API automatica'));
if (!in_array($resource, $excluded)) {
$table = $resource;
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 {
$filename = DOCROOT.'/modules/'.$resources[$resource].'/api/'.$kind.'.php';
include $filename;
}
// Paginazione dell'API
$page = (int) filter('page') ?: 0;
$length = Settings::get('Lunghezza pagine per API');
// Generazione automatica delle query
if (empty($results) && !empty($table)) {
try {
// Query per ottenere le informazioni
$results = $dbo->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`');
if (!empty($cont)) {
$results['records'] = $cont[0]['records'];
$results['pages'] = $cont[0]['pages'];
}
} catch (PDOException $e) {
return self::error('internalError');
}
}
return self::response($results);
}
public function create($resource)
{
return $this->fileRequest($resource, 'create');
}
public function update($resource)
{
return $this->fileRequest($resource, 'generate');
}
public function delete($resource)
{
return $this->fileRequest($resource, 'delete');
}
protected function fileRequest($resource, $kind)
{
$resources = self::getResources()[$kind];
if (!in_array($resource, $resources)) {
return self::error('notFound');
}
$dbo = Database::getConnection();
$filename = DOCROOT.'/modules/'.$resources[$resource].'/api/'.$kind.'.php';
include $filename;
return self::response($results);
}
public static function error($error)
{
$keys = array_keys(self::$status);
$error = (in_array($error, $keys)) ? $error : end($keys);
return self::response([
'status' => self::$status[$error]['code'],
'message' => self::$status[$error]['message'],
]);
}
public static function getResources()
{
if (!is_array(self::$resources)) {
$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');
$temp = str_replace('/api/', '/custom/api/', $operation);
$operation = file_exists($temp) ? $temp : $operation;
$api = include $operation;
$api = array_unique($api);
$keys = array_keys($resources[$kind]);
$results = [];
foreach ($api as $value) {
$value .= in_array($value, $keys) ? $module : '';
$results[$value] = $module;
}
$resources[$kind] = array_merge((array) $resources[$kind], $results);
}
}
self::$resources = $resources;
}
return self::$resources;
}
public static function response($array)
{
if (empty($array['status'])) {
$array['status'] = self::$status['ok']['code'];
$array['message'] = self::$status['ok']['message'];
}
$flags = JSON_FORCE_OBJECT;
if (filter('beautify') !== null) {
$flags |= JSON_PRETTY_PRINT;
}
return json_encode($array, $flags);
}
public static function isAPIRequest()
{
return slashes($_SERVER['SCRIPT_FILENAME']) == slashes(DOCROOT.'/api/index.php');
}
}

234
lib/classes/Auth.php Normal file
View File

@ -0,0 +1,234 @@
<?php
/**
* Classe per la gestione delle utenze.
*
* @since 2.3
*/
class Auth
{
protected static $infos;
protected static $first_module = null;
public function __construct()
{
$database = Database::getConnection();
if (API::isAPIRequest()) {
$this->api(filter('token'));
}
// Controllo sulla sessione attiva
elseif (!empty($_SESSION['idutente']) && $database->isConnected() && $database->isInstalled()) {
$this->find();
}
}
public function attempt($username, $password)
{
session_regenerate_id();
$database = Database::getConnection();
$users = $database->fetchArray('SELECT idutente, username, password, enabled FROM zz_users WHERE username = '.prepare($username).' LIMIT 1');
$log = [];
$log['username'] = $username;
$log['ip'] = get_client_ip();
$log['stato'] = 0;
if (!empty($users)) {
$user = $users[0];
if (empty($user['enabled'])) {
$log['stato'] = 2;
} else {
$_SESSION['idutente'] = $user['idutente'];
$continue = $this->password_check($password, $user['password']) && $this->find();
if (!$continue || empty(self::$first_module)) {
if ($continue && empty(self::$first_module)) {
$log['stato'] = 3;
}
self::logout();
} else {
$log['idutente'] = self::$infos['idutente'];
$log['stato'] = 1;
}
}
}
$messages = [
0 => _('Autenticazione fallita!'),
2 => _('Utente non abilitato!'),
3 => _("L'utente non ha nessun permesso impostato!"),
];
if (!empty($messages[$log['stato']])) {
$_SESSION['errors'][] = $messages[$log['stato']];
}
foreach ($log as $key => $value) {
$log[$key] = prepare($value);
}
$database->query('INSERT INTO zz_logs('.implode(', ', array_keys($log)).') VALUES('.implode(', ', $log).')');
return self::check();
}
protected function password_check($password, $hash)
{
if ($hash == md5($password)) {
$database = Database::getConnection();
$database->query('UPDATE zz_users SET password='.prepare(self::hashPassword($password)).' WHERE idutente = '.prepare($_SESSION['idutente']));
return true;
}
if (password_verify($password, $hash)) {
return true;
}
return false;
}
/**
* Crea la l'hash della password per il successivo salvataggio all'interno del database.
*
* @since 2.3
*
* @return string
*/
public static function hashPassword($password)
{
return password_hash($password, PASSWORD_BCRYPT);
}
protected function find()
{
$database = Database::getConnection();
$user = self::userInfo($_SESSION['idutente']);
if (!empty($user)) {
foreach ($user as $key => $value) {
$_SESSION[$key] = $value;
}
self::$infos = $user;
$query = 'SELECT id FROM zz_modules WHERE enabled = 1';
if (!self::isAdmin()) {
$query .= ' AND id IN (SELECT idmodule FROM zz_permissions WHERE idgruppo = (SELECT id FROM zz_groups WHERE nome = '.prepare($_SESSION['gruppo']).") AND permessi IN ('r', 'rw'))";
}
$results = $database->fetchArray($query.' ORDER BY `order` ASC');
if (!empty($results)) {
$module = null;
$first = get_var('Prima pagina');
if (array_search($first, array_column($results, 'id')) === false) {
foreach ($results as $result) {
if (!empty($result['options']) && $result['options'] != 'menu') {
$module = $result['id'];
break;
}
}
} else {
$module = $first;
}
self::$first_module = $module;
}
$identifier = md5($_SESSION['idutente'].$_SERVER['HTTP_USER_AGENT']);
if ((empty($_SESSION['last_active']) || time() < $_SESSION['last_active'] + (60 * 60)) && (empty($_SESSION['identifier']) || $_SESSION['identifier'] == $identifier)) {
$_SESSION['last_active'] = time();
$_SESSION['identifier'] = $identifier;
return true;
}
}
self::logout();
return false;
}
protected static function userInfo($user_id)
{
$database = Database::getConnection();
$results = $database->fetchArray('SELECT *, (SELECT nome FROM zz_groups WHERE id=idgruppo) AS gruppo FROM zz_users WHERE idutente = '.prepare($user_id).' AND enabled = 1 LIMIT 1');
$infos = [];
if (!empty($results)) {
$infos['idutente'] = $results[0]['idutente'];
$infos['is_admin'] = ($results[0]['gruppo'] == 'Amministratori');
$infos['idanagrafica'] = $results[0]['idanagrafica'];
$infos['username'] = $results[0]['username'];
$infos['gruppo'] = $results[0]['gruppo'];
}
return $infos;
}
/**
* Controlla se la chiave di accesso per l'API abilita l'accesso di un utente.
*
* @param string $token Chiave
*
* @return array
*/
public function api($token)
{
$database = Database::getConnection();
$results = $database->fetchArray('SELECT `id_utente` FROM `zz_tokens` WHERE `token` = '.prepare($token));
if (!empty($results)) {
self::$infos = self::userInfo($results[0]['id_utente']);
}
return self::$infos;
}
public static function check()
{
return !empty(self::$infos);
}
public static function isAdmin()
{
return self::check() && !empty(self::$infos['is_admin']);
}
public static function logout()
{
if (self::check() || !empty($_SESSION['idutente'])) {
self::$infos = null;
self::$first_module = null;
session_unset();
session_destroy();
session_start();
session_regenerate_id();
$_SESSION['infos'] = [];
$_SESSION['warnings'] = [];
$_SESSION['errors'] = [];
}
}
public static function getFirstModule()
{
return self::$first_module;
}
public static function getUser()
{
return self::$infos;
}
}

309
lib/classes/CSRF.php Normal file
View File

@ -0,0 +1,309 @@
<?php
/**
* Sistema di protezione CSRF, basato sulla libreria Slim CSRF.
*
* @since 2.3
*/
class CSRF extends Util\Singleton
{
/**
* Prefix for CSRF parameters (omit trailing "_" underscore).
*
* @var string
*/
protected $prefix;
/**
* CSRF storage.
*
* Should be either an array or an object. If an object is used, then it must
* implement ArrayAccess and should implement Countable and Iterator (or
* IteratorAggregate) if storage limit enforcement is required.
*
* @var array|ArrayAccess
*/
protected $storage;
/**
* Number of elements to store in the storage array.
*
* @var int
*/
protected $storageLimit;
/**
* CSRF Strength.
*
* @var int
*/
protected $strength = 16;
/**
* Stores the latest key-pair generated by the class.
*
* @var array
*/
protected $keyPair = null;
/**
* Create new CSRF guard.
*
* @param string $prefix
* @param null|array|ArrayAccess $storage
* @param int $storageLimit
*/
protected function __construct($prefix = 'csrf', &$storage = null, $storageLimit = -1)
{
$this->prefix = rtrim($prefix, '_');
$this->storage = &$storage;
$this->validateStorage();
$this->storageLimit = $storageLimit;
}
/**
* @return string
*/
public function getToken()
{
if (!$this->keyPair && (!$this->isPersistent() || !$this->loadLastToken())) {
$this->generateToken();
}
return $this->keyPair;
}
/**
* Generates a new CSRF token.
*
* @return array
*/
protected function generateToken()
{
// Generate new CSRF token
$name = uniqid($this->prefix);
$value = $this->createToken();
$this->saveToStorage($name, $value);
$this->keyPair = [
$this->prefix.'_name' => $name,
$this->prefix.'_value' => $value,
];
return $this->keyPair;
}
public function validate()
{
$result = true;
$this->validateStorage();
if (in_array($_SERVER['REQUEST_METHOD'], ['POST'])) {
$name = isset($_POST[$this->prefix.'_name']) ? $_POST[$this->prefix.'_name'] : false;
$value = isset($_POST[$this->prefix.'_value']) ? $_POST[$this->prefix.'_value'] : false;
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$this->generateToken();
$result = false;
}
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $result;
}
/**
* @param $prefix
* @param $storage
*
* @return mixed
*/
protected function validateStorage()
{
if (is_array($this->storage)) {
return $this->storage;
}
if ($this->storage instanceof ArrayAccess) {
return $this->storage;
}
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!array_key_exists($this->prefix, $_SESSION)) {
$_SESSION[$this->prefix] = [];
}
$this->storage = &$_SESSION[$this->prefix];
return $this->storage;
}
/**
* Validate CSRF token from current request against token value stored in $_SESSION.
*
* @param string $name CSRF name
* @param string $value CSRF token value
*
* @return bool
*/
protected function validateToken($name, $value)
{
$token = $this->getFromStorage($name);
if (function_exists('hash_equals')) {
$result = ($token !== false && hash_equals($token, $value));
} else {
$result = ($token !== false && $token === $value);
}
// If we're not in persistent token mode, delete the token.
if (!$this->isPersistent() || !$result) {
$this->removeFromStorage($name);
}
return $result;
}
/**
* Create CSRF token value.
*
* @return string
*/
protected function createToken()
{
return bin2hex(random_bytes($this->strength));
}
/**
* Save token to storage.
*
* @param string $name CSRF token name
* @param string $value CSRF token value
*/
protected function saveToStorage($name, $value)
{
$this->storage[$name] = $value;
}
/**
* Get token from storage.
*
* @param string $name CSRF token name
*
* @return string|bool CSRF token value or `false` if not present
*/
protected function getFromStorage($name)
{
return isset($this->storage[$name]) ? $this->storage[$name] : false;
}
/**
* Get the most recent key pair from storage.
*
* @return string[]|null Array containing name and value if found, null otherwise
*/
protected function loadLastToken()
{
// Use count, since empty ArrayAccess objects can still return false for `empty`
if (count($this->storage) < 1) {
return null;
}
foreach ($this->storage as $name => $value) {
continue;
}
$keyPair = [
$this->prefix.'_name' => $name,
$this->prefix.'_value' => $value,
];
if ($keyPair) {
$this->keyPair = $keyPair;
return true;
}
return false;
}
/**
* Remove token from storage.
*
* @param string $name CSRF token name
*/
protected function removeFromStorage($name)
{
$this->storage[$name] = ' ';
unset($this->storage[$name]);
}
/**
* Remove the oldest tokens from the storage array so that there
* are never more than storageLimit tokens in the array.
*
* This is required as a token is generated every request and so
* most will never be used.
*/
protected function enforceStorageLimit()
{
if ($this->storageLimit < 1) {
return;
}
// $storage must be an array or implement Countable and Traversable
if (!is_array($this->storage)
&& !($this->storage instanceof Countable && $this->storage instanceof Traversable)
) {
return;
}
if (is_array($this->storage)) {
while (count($this->storage) > $this->storageLimit) {
array_shift($this->storage);
}
} else {
// array_shift() doesn't work for ArrayAccess, so we need an iterator in order to use rewind()
// and key(), so that we can then unset
$iterator = $this->storage;
if ($this->storage instanceof \IteratorAggregate) {
$iterator = $this->storage->getIterator();
}
while (count($this->storage) > $this->storageLimit) {
$iterator->rewind();
unset($this->storage[$iterator->key()]);
}
}
}
/**
* Setter for storageLimit.
*
* @param int $storageLimit Value to set
*
* @return $this
*/
public function setStorageLimit($storageLimit)
{
$this->storageLimit = (int) $storageLimit;
}
/**
* Getter for persistentTokenMode.
*
* @return bool
*/
public function isPersistent()
{
return $this->storageLimit < 0;
}
}

615
lib/classes/Database.php Normal file
View File

@ -0,0 +1,615 @@
<?php
/**
* Classe per gestire la connessione al database.
*
* @since 2.3
*/
class Database extends Util\Singleton
{
protected $host;
protected $port;
protected $username;
protected $password;
protected $database_name;
protected $charset;
protected $option = [];
protected static $connection;
protected $pdo;
protected $is_installed;
protected $mysql_version;
/**
* Costruisce la nuova connessione al database.
* Basato sul framework open source Medoo.
*
* @param string|array $server
* @param string $username
* @param string $password
* @param string $database_name
* @param string $charset
* @param array $option
*
* @since 2.3
*
* @return Database
*/
protected function __construct($server, $username, $password, $database_name, $charset = 'utf8mb4', $option = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION])
{
if (is_array($server)) {
$host = $server['host'];
$port = !empty($server['port']) ? $server['port'] : null;
} else {
$temp = explode(':', $server);
$host = $temp[0];
$port = !empty($temp[1]) ? $temp[1] : null;
}
$this->host = $host;
if (!empty($port) && is_int($port * 1)) {
$this->port = $port;
}
$this->username = $username;
$this->password = $password;
$this->database_name = $database_name;
$this->charset = $charset;
$this->option = $option;
if (!empty($this->host) && !empty($this->database_name)) {
try {
$this->pdo = new \DebugBar\DataCollector\PDO\TraceablePDO(new PDO(
'mysql:host='.$this->host.(!empty($this->port) ? ';port='.$this->port : '').';dbname='.$this->database_name,
$this->username,
$this->password,
$this->option
));
$this->query("SET NAMES '".$this->charset."'");
$this->query("SET sql_mode = ''");
} catch (PDOException $e) {
if ($e->getCode() == 1049 || $e->getCode() == 1044) {
$e = new PDOException(($e->getCode() == 1049) ? _('Database non esistente!') : _('Credenziali di accesso invalide!'));
}
$this->signal($e, _('Errore durante la connessione al database'), ['throw' => false, 'session' => false]);
}
}
}
/**
* Restituisce la connessione attiva al database, creandola nel caso non esista.
*
* @since 2.3
*
* @return Database
*/
public static function getConnection($new = false)
{
if (empty(parent::$instance) || !parent::$instance->isConnected() || $new) {
global $db_host;
global $db_username;
global $db_password;
global $db_name;
parent::$instance = new self($db_host, $db_username, $db_password, $db_name);
}
return parent::$instance;
}
public static function getInstance()
{
return self::getConnection();
}
/**
* Restituisce l'oggetto PDO artefice della connessione.
*
* @since 2.3
*
* @return \DebugBar\DataCollector\PDO\TraceablePDO
*/
public function getPDO()
{
return $this->pdo;
}
/**
* Controlla se la connessione è valida e andata a buon fine.
*
* @since 2.3
*
* @return bool
*/
public function isConnected()
{
return !empty($this->pdo);
}
/**
* Controlla se il database necessario al progetto esiste.
*
* @since 2.3
*
* @return bool
*/
public function isInstalled()
{
if (empty($this->is_installed)) {
$this->is_installed = $this->isConnected() && $this->fetchNum("SHOW TABLES LIKE 'zz_modules'");
}
return $this->is_installed;
}
/**
* Restituisce la versione del DBMS MySQL in utilizzo.
*
* @since 2.3
*
* @return int
*/
public function getMySQLVersion()
{
if (empty($this->mysql_version) && $this->isConnected()) {
$ver = $this->fetchArray('SELECT VERSION()');
if (!empty($ver[0]['VERSION()'])) {
$this->mysql_version = explode('-', $ver[0]['VERSION()'])[0];
}
}
return $this->mysql_version;
}
/**
* Restituisce il nome del database a cui si è connessi.
*
* @since 2.3
*
* @return string
*/
public function getDatabaseName()
{
return $this->database_name;
}
/**
* Esegue la query indicata, restituendo l'identificativo della nuova entità se si tratta di una query di inserimento.
*
* @since 2.0
*
* @param string $query Query da eseguire
*
* @return int
*/
public function query($query, $signal = null, $options = [])
{
try {
$this->pdo->query($query);
$id = $this->lastInsertedID();
if ($id == 0) {
return 1;
} else {
return $id;
}
} catch (PDOException $e) {
$signal = empty($signal) ? $query : $signal;
$this->signal($e, $signal, $options);
}
}
/**
* Restituisce un'array strutturato in base ai nomi degli attributi della selezione.
*
* @since 2.0
*
* @param string $query Query da eseguire
*
* @return array
*/
public function fetchArray($query, $numeric = false)
{
try {
$mode = empty($numeric) ? PDO::FETCH_ASSOC : PDO::FETCH_NUM;
$result = $this->pdo->query($query)->fetchAll($mode);
return $result;
} catch (PDOException $e) {
$this->signal($e, $query);
}
}
/**
* Restituisce un'array strutturato in base agli indici degli attributi della selezione.
*
* @since 2.0
* @deprecated 2.3
*
* @param string $query Query da eseguire
*
* @return array
*/
public function fetchRows($query)
{
return $this->fetchArray($query, true);
}
/**
* Restituisce il primo elemento della selezione, strutturato in base ai nomi degli attributi.
*
* @since 2.0
* @deprecated 2.3
*
* @param string $query Query da eseguire
*
* @return array
*/
public function fetchRow($query)
{
$result = $this->fetchArray($query);
if (is_array($result)) {
return $result[0];
}
return $result;
}
/**
* Restituisce il numero dei risultati della selezione.
*
* @since 2.0
*
* @param string $query Query da eseguire
*
* @return array
*/
public function fetchNum($query)
{
$result = $this->fetchArray($query);
if (is_array($result)) {
return count($result);
}
return $result;
}
/**
* Restituisce l'identificativo dell'ultimo elemento inserito.
*
* @since 2.0
* @deprecated 2.3
*
* @return int
*/
public function last_inserted_id()
{
return $this->lastInsertedID();
}
/**
* Restituisce l'identificativo dell'ultimo elemento inserito.
*
* @since 2.3
*
* @return int
*/
public function lastInsertedID()
{
try {
return $this->pdo->lastInsertId();
} catch (PDOException $e) {
$this->signal($e, _("Impossibile ottenere l'ultimo identificativo creato"));
}
}
/**
* Prepara il parametro inserito per l'inserimento in una query SQL.
* Attenzione: protezione di base contro SQL Injection.
*
* @param string $parameter
*
* @since 2.3
*
* @return string
*/
public function prepare($parameter)
{
return $this->pdo->quote($parameter);
}
/**
* Prepara il campo per l'inserimento in uno statement SQL.
*
* @since 2.3
*
* @param string $value
*
* @return string
*/
protected function quote($string)
{
return '`'.str_replace('`', '', $string).'`';
}
/**
* Costruisce la query per l'INSERT definito dagli argomenti.
*
* @since 2.3
*
* @param string $table
* @param array $array
* @param bool $return
*
* @return string|array
*/
public function insert($table, $array, $return = false)
{
if (!is_string($table) || !is_array($array)) {
throw new UnexpectedValueException();
}
if (!is_array($array[0])) {
$array = [$array];
}
$keys = [];
$temp = array_keys($array[0]);
foreach ($temp as $value) {
$keys[] = $this->quote($value);
}
$inserts = [];
foreach ($array as $values) {
foreach ($values as $key => $value) {
$values[$key] = $this->getValue($value);
}
$inserts[] = '('.implode(array_values($values), ', ').')';
}
$query = 'INSERT INTO '.$this->quote($table).' ('.implode(',', $keys).') VALUES '.implode($inserts, ', ');
if (!empty($return)) {
return $query;
} else {
return $this->query($query);
}
}
/**
* Costruisce la query per l'UPDATE definito dagli argomenti.
*
* @since 2.3
*
* @param string $table
* @param array $array
* @param array $conditions
* @param bool $return
*
* @return string|array
*/
public function update($table, $array, $conditions, $return = false)
{
if (!is_string($table) || !is_array($array) || !is_array($conditions)) {
throw new UnexpectedValueException();
}
$update = [];
foreach ($array as $key => $value) {
$update[] = $this->quote($key).' = '.$this->getValue($value);
}
$where = [];
foreach ($conditions as $key => $value) {
$where[] = $this->quote($key).' = '.$this->getValue($value);
}
$query = 'UPDATE '.$this->quote($table).' SET '.implode($update, ', ').' WHERE '.implode($where, ' AND ');
if (!empty($return)) {
return $query;
} else {
return $this->query($query);
}
}
/**
* Costruisce la query per il SELECT definito dagli argomenti.
*
* @since 2.3
*
* @param string $table
* @param array $array
* @param array $conditions
* @param array $order
* @param string|array $limit
* @param bool $return
*
* @return string|array
*/
public function select($table, $array = [], $conditions = [], $order = [], $limit = null, $return = false)
{
if (
!is_string($table) ||
(!empty($order) && !is_string($order) && !is_array($limit)) ||
(!empty($limit) && !is_string($limit) && !is_array($limit))
) {
throw new UnexpectedValueException();
}
$select = [];
foreach ((array) $array as $key => $value) {
$select[] = $value.(is_numeric($key) ? '' : 'AS '.$this->quote($key));
}
$select = !empty($select) ? $select : ['*'];
$query = 'SELECT '.implode(', ', $select).' FROM '.$this->quote($table);
$where = $this->whereStatement($conditions);
if (!empty($where)) {
$query .= ' WHERE '.$where;
}
if (!empty($order)) {
$list = [];
$allow = ['ASC', 'DESC'];
foreach ((array) $order as $key => $value) {
if (is_numeric($key)) {
$key = $value;
$value = $allow[0];
}
$value = in_array($value, $allow) ? $value : $allow[0];
$list[] = $this->quote($key).' '.$value;
}
$query .= ' ORDER BY '.implode(', ', $list);
}
if (!empty($limit)) {
$query .= ' LIMIT '.(is_array($limit) ? $limit[0].', '.$limit[1] : $limit);
}
if (!empty($return)) {
return $query;
} else {
return $this->fetchArray($query);
}
}
/**
* Predispone una variabile per il relativo inserimento all'interno di uno statement SQL.
*
* @since 2.3
*
* @param string $value
*
* @return string
*/
protected function getValue($value)
{
$value = (is_null($value)) ? 'NULL' : $value;
$value = is_bool($value) ? intval($value) : $value;
if (starts_with($value, '#') && ends_with($value, '#')) {
$value = substr($value, 1, -1);
} elseif ($value != 'NULL') {
$value = $this->prepare($value);
}
return $value;
}
/**
* Predispone il contenuto di un array come clausola WHERE.
*
* @since 2.3
*
* @param string|array $where
* @param bool $and
*
* @return string
*/
protected function whereStatement($where, $and = true)
{
$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';
$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, '%')) {
$result[] = $this->quote($key).' LIKE '.$this->getValue($value);
} elseif (str_contains($value, '|')) {
$pieces = explode('|', $value);
$result[] = $this->quote($key).' BETWEEN '.$this->getValue($pieces[0]).' AND '.$this->getValue($pieces[1]);
} else {
$result[] = $this->quote($key).' = '.$this->getValue($value);
}
}
} else {
$result[] = $where;
}
$cond = !empty($and) ? 'AND' : 'OR';
return implode(' '.$cond.' ', $result);
}
/**
* Esegue le query interne ad un file .sql.
*
* @since 2.0
*
* @param string $filename Percorso per raggiungere il file delle query
* @param string $delimiter Delimitatore delle query
*/
public function multiQuery($filename, $start = 0)
{
$queries = readSQLFile($filename, ';');
$end = count($queries);
for ($i = $start; $i < $end; ++$i) {
try {
$this->pdo->query($queries[$i]);
} catch (PDOException $e) {
$this->signal($e, _('Aggiornamento fallito').': '.$queries[$i], [
'level' => \Monolog\Logger::EMERGENCY,
'throw' => false,
]);
return $i;
}
}
return true;
}
/**
* Aggiunge informazioni alla struttura di base dell'erroe o dell'eccezione intercettata.
*
* @since 2.3
*/
protected function signal($e, $message, $options = [])
{
global $logger;
$options = array_merge([
'session' => true,
'level' => \Monolog\Logger::ERROR,
'throw' => true,
], $options);
if (!empty($options['session'])) {
$msg = _("Si è verificato un'errore").'.';
if (Auth::check()) {
$msg .= ' '._('Se il problema persiste siete pregati di chiedere assistenza tramite la sezione Bug').'. <a href="'.ROOTDIR.'/bug.php"><i class="fa fa-external-link"></i></a>';
}
$msg .= '<br><small>'.$e->getMessage().'</small>';
$_SESSION['errors'][] = $msg;
}
$error = $e->getMessage().' - '.$message;
if (!empty($options['throw'])) {
throw new PDOException($error);
} else {
$logger->addRecord($options['level'], $error);
}
}
}

148
lib/classes/Filter.php Normal file
View File

@ -0,0 +1,148 @@
<?php
/**
* Classe per gestire la sanitarizzazione degli input, basata sul framework open source HTMLPurifier.
*
* @since 2.3
*/
class Filter
{
/** @var HTMLPurifier */
protected static $purifier;
/** @var array Lista dei contenuti inviati via POST */
protected static $post;
/** @var array Lista dei contenuti inviati via GET */
protected static $get;
/**
* Restituisce il valore presente nei dati ottenuti dall'input dell'utente.
*
* @param string $property
* @param string $method
*
* @return string
*/
public static function getValue($property, $method = null)
{
$value = null;
if (empty($method)) {
$value = (self::post($property) !== null) ? self::post($property) : self::get($property);
} elseif (strtolower($method) == 'post') {
$value = self::post($property);
} elseif (strtolower($method) == 'get') {
$value = self::get($property);
}
return $value;
}
/**
* Restituisce i contenuti dalla sezione POST.
*
* @return array
*/
public static function getPOST()
{
if (empty(self::$post)) {
self::$post = self::sanitize($_POST);
}
return self::$post;
}
/**
* Restituisce il valore presente nei dati ottenuti dalla sezione POST.
*
* @param string $property
*
* @return string
*/
public static function post($property)
{
if (!empty(self::getPOST()) && isset(self::getPOST()[$property])) {
return self::getPOST()[$property];
}
}
/**
* Restituisce i contenuti dalla sezione GET.
*
* @return array
*/
public static function getGET()
{
if (empty(self::$get)) {
self::$get = self::sanitize($_GET);
}
return self::$get;
}
/**
* Restituisce il valore presente nei dati ottenuti dalla sezione GET.
*
* @param string $property
*
* @return string
*/
public static function get($property)
{
if (!empty(self::getGET()) && isset(self::getGET()[$property])) {
return self::getGET()[$property];
}
}
/**
* Sanitarizza il testo inserito.
*
* @param mixed $input Testo da sanitarizzare
*
* @return mixed
*/
public static function sanitize($input)
{
$output = null;
if (is_array($input)) {
foreach ($input as $key => $value) {
$output[$key] = self::sanitize($value);
}
} else {
$output = trim(self::getPurifier()->purify($input));
if (!empty($output) && !empty(Translator::getLocaleFormatter())) {
if (Translator::getLocaleFormatter()->isNumber($output)) {
$output = Translator::numberToEnglish($output);
} elseif (Translator::getLocaleFormatter()->isTimestamp($output)) {
$output = Translator::timestampToEnglish($output);
} elseif (Translator::getLocaleFormatter()->isDate($output)) {
$output = Translator::dateToEnglish($output);
} elseif (Translator::getLocaleFormatter()->isTime($output)) {
$output = Translator::timeToEnglish($output);
}
}
}
return $output;
}
/**
* Restituisce l'istanza di HTMLPurifier in utilizzo.
*
* @return \HTMLPurifier
*/
public static function getPurifier()
{
if (empty(self::$purifier)) {
$config = \HTMLPurifier_Config::createDefault();
$config->set('HTML.Allowed', 'a[href|target|title],img[class|src|border|alt|title|hspace|vspace|width|height|align|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|style],br,p[class]');
//$config->set('Cache.SerializerPath', realpath(__DIR__.'/cache/HTMLPurifier'));
$config->set('Cache.DefinitionImpl', null);
self::$purifier = new \HTMLPurifier($config);
}
return self::$purifier;
}
}

View File

@ -0,0 +1,312 @@
<?php
namespace HTMLBuilder;
/**
* Classe dedicata alla gestione della conversione di tag in codice HTML.
*
* Campo di input generico:
* {[ "type": "text", "required": 1, "value": "$idintervento$" ]}
*
* Campo di testo normale e non modificabile:
* {[ "type": "span", "value": "$testo$" ]}
*
* Campo select automatizzatp:
* {[ "type": "select", "required": 1, "values": "query=SELECT id, descrizione FROM co_contratti WHERE idanagrafica=$idanagrafica$", "value": "$idcontratto$" ]}
*
* La sostituzione dei parametri compresi tra $$ viene effettuata attraverso il parametro $records.
*
* @since 2.3
*/
class HTMLBuilder
{
/** @var array Codici di apertura dei tag personalizzati */
public static $open = [
'handler' => '{[',
'manager' => '{(',
];
/** @var array Codici di chiusura dei tag personalizzati */
public static $close = [
'handler' => ']}',
'manager' => ')}',
];
/** @var array Lista degli attributi inseriit nel formato che necessitano solo di essere presenti */
protected static $specifics = [
'multiple',
'checked',
'disabled',
'readonly',
'required',
];
/** @var array Lista dei gestori dei campi HTML */
protected static $handlers = [
'list' => [
'default' => 'HTMLBuilder\Handler\DefaultHandler',
'image' => 'HTMLBuilder\Handler\MediaHandler',
'select' => 'HTMLBuilder\Handler\SelectHandler',
'checkbox' => 'HTMLBuilder\Handler\ChoicesHandler',
'radio' => 'HTMLBuilder\Handler\ChoicesHandler',
'bootswitch' => 'HTMLBuilder\Handler\ChoicesHandler',
'timestamp' => 'HTMLBuilder\Handler\DateHandler',
'date' => 'HTMLBuilder\Handler\DateHandler',
'time' => 'HTMLBuilder\Handler\DateHandler',
],
'instances' => [],
];
/** @var array Generatore del contenitore per i campi HTML */
protected static $wrapper = [
'class' => 'HTMLBuilder\Wrapper\HTMLWrapper',
'istance' => null,
];
/** @var array Lista dei gestori delle strutture HTML */
protected static $managers = [
'list' => [
'filelist_and_upload' => 'HTMLBuilder\Manager\FileManager',
'csrf' => 'HTMLBuilder\Manager\CSRFManager',
],
'instances' => [],
];
public static function replace($html)
{
preg_match_all('/'.preg_quote(self::$open['manager']).'(.+?)'.preg_quote(self::$close['manager']).'/i', $html, $managers);
foreach ($managers[0] as $value) {
$json = self::decode($value, 'manager');
$class = self::getManager($json['name']);
$html = str_replace($value, !empty($class) ? $class->manage($json) : '', $html);
}
preg_match_all('/'.preg_quote(self::$open['handler']).'(.+?)'.preg_quote(self::$close['handler']).'/i', $html, $handlers);
foreach ($handlers[0] as $value) {
$json = self::decode($value, 'handler');
$html = str_replace($value, self::generate($json), $html);
}
return $html;
}
protected static function generate($json)
{
// Elaborazione del formato
list($values, $extras) = self::elaborate($json);
$result = null;
if (!empty($values)) {
// Generazione dell'elemento
$html = self::getHandler($values['type'])->handle($values, $extras);
// Generazione del parte iniziale del contenitore
$before = self::getWrapper()->before($values, $extras);
// Generazione del parte finale del contenitore
$after = self::getWrapper()->after($values, $extras);
$result = $before.$html.$after;
// Elaborazione del codice HTML
$result = self::process($result, $values, $extras);
}
return $result;
}
protected static function decode($string, $type)
{
$string = '{'.substr($string, strlen(self::$open[$type]), -strlen(self::$close[$type])).'}';
$json = (array) json_decode($string, true, 2);
return $json;
}
protected static function elaborate($json)
{
global $records;
$values = [];
$extras = [];
if (!empty($json)) {
// Conversione delle variabili con i campi di database ($records)
foreach ($json as $key => $value) {
if (empty($value) && !is_numeric($value)) {
unset($json[$key]);
}
// Sostituzione delle variabili $nome$ col relativo valore da database
elseif (preg_match_all('/\$([a-z0-9\_]+)\$/i', $json[$key], $m)) {
for ($i = 0; $i < count($m[0]); ++$i) {
$record = isset($records[0][$m[1][$i]]) ? $records[0][$m[1][$i]] : '';
$json[$key] = str_replace($m[0][$i], prepareToField($record), $json[$key]);
}
}
}
// Valori speciali che richiedono solo la propria presenza
foreach (self::$specifics as $specific) {
if (isset($json[$specific])) {
if (!empty($json[$specific])) {
$extras[] = trim($specific);
}
unset($json[$specific]);
}
}
// Campo personalizzato "extra"
if (isset($json['extra'])) {
if (!empty($json['extra'])) {
$extras[] = trim($json['extra']);
}
unset($json['extra']);
}
// Attributi normali
foreach ($json as $key => $value) {
$values[trim($key)] = trim($value);
}
// Valori particolari
$values['name'] = str_replace(' ', '_', $values['name']);
$values['id'] = empty($values['id']) ? $values['name'] : $values['id'];
$values['id'] = str_replace(['[', ']', ' '], ['', '', '_'], $values['id']);
$values['value'] = isset($values['value']) ? $values['value'] : '';
// Gestione delle classi CSS
$values['class'] = [];
$values['class'][] = 'form-control';
if (!empty($json['class'])) {
$classes = explode(' ', $json['class']);
foreach ($classes as $class) {
if (!empty($class)) {
$values['class'][] = trim($class);
}
}
}
// Gestione grafica dell'attributo required
if (in_array('required', $extras)) {
if (!empty($values['label'])) {
$values['label'] .= '*';
} elseif (!empty($values['placeholder'])) {
$values['placeholder'] .= '*';
}
}
}
return [$values, $extras];
}
protected static function process($result, $values, $extras)
{
unset($values['label']);
$values['class'] = array_unique($values['class']);
foreach ($values as $key => $value) {
// Fix per la presenza di apici doppi
$value = prepareToField(is_array($value) ? implode(' ', $value) : $value);
if (strpos($result, '|'.$key.'|') !== false) {
$result = str_replace('|'.$key.'|', $value, $result);
} elseif (!empty($value) || is_numeric($value)) {
$attributes[] = $key.'="'.$value.'"';
}
}
$attributes = array_unique(array_merge($attributes, $extras));
$result = str_replace('|attr|', implode(' ', $attributes), $result);
return $result;
}
public static function getHandlerName($input)
{
$result = empty(self::$handlers['list'][$input]) ? self::$handlers['list']['default'] : self::$handlers['list'][$input];
return $result;
}
public static function getHandler($input)
{
$class = self::getHandlerName($input);
if (empty(self::$handlers['instances'][$class])) {
self::$handlers['instances'][$class] = new $class();
}
return self::$handlers['instances'][$class];
}
public static function setHandler($input, $class)
{
$original = $class;
$class = is_object($class) ? $class : new $class();
if ($class instanceof Handler\HandlerInterface) {
self::$handlers['list'][$input] = $original;
self::$handlers['instances'][$original] = $class;
}
}
public static function getWrapper()
{
if (empty(self::$wrapper['instance'])) {
$class = self::$wrapper['class'];
self::$wrapper['instance'] = new $class();
}
return self::$wrapper['instance'];
}
public static function setWrapper($class)
{
$original = $class;
$class = is_object($class) ? $class : new $class();
if ($class instanceof Wrapper\WrapperInterface) {
self::$wrapper['class'] = $original;
self::$wrapper['instance'] = $class;
}
}
public static function getManager($input)
{
$result = null;
$class = self::$managers['list'][$input];
if (!empty($class)) {
if (empty(self::$managers['instances'][$class])) {
self::$managers['instances'][$class] = new $class();
}
$result = self::$managers['instances'][$class];
}
return $result;
}
public static function setManager($input, $class)
{
$original = $class;
$class = is_object($class) ? $class : new $class();
if ($class instanceof Handler\ManagerInterface) {
self::$managers['list'][$input] = $original;
self::$managers['instances'][$original] = $class;
}
}
}
function prepareToField($string)
{
return str_replace('"', '&quot;', $string);
}

View File

@ -0,0 +1,89 @@
<?php
namespace HTMLBuilder\Handler;
// Utilizzo della funzione prepareToField (PHP 5.6+)
// use function \HTMLBuilder\prepareToField;
/**
* @since 2.3
*/
class ChoicesHandler implements HandlerInterface
{
public function handle(&$values, &$extras)
{
$result = $this->{$values['type']}($values, $extras);
return $result;
}
protected function checkbox(&$values, &$extras)
{
unset($values['class'][0]);
$values['value'] = (empty($values['value']) || $values['value'] == 'off') ? false : true;
if (!empty($values['value']) && !in_array('checked', $extras)) {
$extras[] = 'checked';
}
if (in_array('readonly', $extras)) {
$extras[] = 'disabled';
}
$values['placeholder'] = (isset($values['placeholder'])) ? $values['placeholder'] : $values['label'];
$result .= '
<div class="input-group">
<span class="input-group-addon">
<input |attr| onchange="$(this).parent().find(\'[type=hidden]\').val( + this.checked)">
<input type="hidden" name="|name|" value="|value|">
</span>
<input type="text" class="form-control" placeholder="|placeholder|" disabled>
</div>';
return $result;
}
protected function bootswitch(&$values, &$extras)
{
unset($values['class'][0]);
$values['class'][] = 'bootstrap-switch';
$values['value'] = (empty($values['value']) || $values['value'] == 'off') ? false : true;
if (!empty($values['value']) && !in_array('checked', $extras)) {
$extras[] = 'checked';
}
return '
<div class="input-group">
<input type="checkbox" |attr|>
<input type="hidden" name="checkbox['.\HTMLBuilder\prepareToField($values['name']).']" value="'.\HTMLBuilder\prepareToField($values['value']).'">
</div>';
}
protected function radio(&$values, &$extras)
{
$result = '';
$originalExtras = $extras;
$radios = json_decode('{'.$values['values'].'}', true);
$values['value'] = !array_key_exists($values['value'], $radios) ? array_keys($radios)[0] : $values['value'];
foreach ($radios as $key => $value) {
$checked = false;
if ($key === $values['value']) {
$checked = true;
}
$result .= '
<input type="radio" class="bootstrap-switch" name="'.\HTMLBuilder\prepareToField($values['name']).'" id="'.\HTMLBuilder\prepareToField($values['id'].'_'.$key).'" value="'.\HTMLBuilder\prepareToField($key).'" data-label-text="'.\HTMLBuilder\prepareToField($value).'"'.($checked ? ' checked' : '').'>';
}
return $result;
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace HTMLBuilder\Handler;
/**
* @since 2.3
*/
class DateHandler implements HandlerInterface
{
public function handle(&$values, &$extras)
{
// Impostazione alla data corrente se il contenuto corrisponde a "now"
if ($values['value'] == '-now-') {
$values['value'] = date(\Translator::getEnglishFormatter()->getTimestampPattern());
}
if ($values['max-date'] == '-now-') {
$values['max-date'] = date(\Translator::getEnglishFormatter()->getTimestampPattern());
}
if ($values['min-date'] == '-now-') {
$values['min-date'] = date(\Translator::getEnglishFormatter()->getTimestampPattern());
}
if (\Translator::getEnglishFormatter()->isTimestamp($values['value']) && $values['type'] == 'timestamp') {
$values['value'] = \Translator::timestampToLocale($values['value']);
} elseif (\Translator::getEnglishFormatter()->isDate($values['value']) && $values['type'] == 'date') {
$values['value'] = \Translator::dateToLocale($values['value']);
} elseif (\Translator::getEnglishFormatter()->isTime($values['value']) && $values['type'] == 'time') {
$values['value'] = \Translator::timeToLocale($values['value']);
}
$resetValues = [
\Translator::timestampToLocale('0000-00-00 00:00:00'),
\Translator::dateToLocale('0000-00-00'),
\Translator::timeToLocale('00:00:00'),
];
$values['value'] = in_array($values['value'], $resetValues) ? '' : $values['value'];
$result = $this->{$values['type']}($values, $extras);
$values['type'] = 'text';
if (empty($result)) {
$result = '
<input |attr|>';
}
return $result;
}
protected function timestamp(&$values, &$extras)
{
$values['class'][] = 'text-center';
$values['class'][] = 'timestamp-picker';
$values['value'] = (\Translator::getLocaleFormatter()->isTimestamp($values['value'])) ? $values['value'] : '';
}
protected function date(&$values, &$extras)
{
$values['class'][] = 'text-center';
$values['class'][] = 'datepicker';
$values['class'][] = 'date-mask';
$values['value'] = (\Translator::getLocaleFormatter()->isDate($values['value'])) ? $values['value'] : '';
}
protected function time(&$values, &$extras)
{
$values['class'][] = 'text-center';
$values['class'][] = 'timepicker';
$values['value'] = (\Translator::getLocaleFormatter()->isTime($values['value'])) ? $values['value'] : '';
}
}

View File

@ -0,0 +1,98 @@
<?php
namespace HTMLBuilder\Handler;
/**
* @since 2.3
*/
class DefaultHandler implements HandlerInterface
{
public function handle(&$values, &$extras)
{
if (in_array($values['type'], get_class_methods($this))) {
$result = $this->{$values['type']}($values, $extras);
} else {
$result = $this->custom($values, $extras);
}
return $result;
}
protected function text(&$values, &$extras)
{
return '
<input |attr|>';
}
protected function file(&$values, &$extras)
{
return $this->text($values, $extras);
}
protected function password(&$values, &$extras)
{
return $this->text($values, $extras);
}
protected function hidden(&$values, &$extras)
{
$original = $values;
$values = [];
$values['type'] = $original['type'];
$values['value'] = $original['value'];
$values['name'] = $original['name'];
$values['class'] = [];
return $this->text($values, $extras);
}
protected function email(&$values, &$extras)
{
$values['class'][] = 'email-mask';
$values['type'] = 'text';
return $this->text($values, $extras);
}
protected function number(&$values, &$extras)
{
$values['class'][] = 'inputmask-decimal';
$values['value'] = !empty($values['value']) ? $values['value'] : 0;
$decimals = true;
if (isset($values['decimals'])) {
if (is_numeric($values['decimals'])) {
$decimals = $values['decimals'];
} elseif (starts_with($values['decimals'], 'qta')) {
$parts = explode('|', $values['decimals']);
$values['min-value'] = isset($parts[1]) ? $parts[1] : 1;
$decimals = \Settings::get('Cifre decimali per quantità');
$values['decimals'] = $decimals;
}
}
$values['value'] = (\Translator::getEnglishFormatter()->isNumber($values['value'])) ? \Translator::numberToLocale($values['value'], $decimals) : $values['value'];
$values['type'] = 'text';
return $this->text($values, $extras);
}
protected function custom(&$values, &$extras)
{
return '
<span |attr|>|value|</span>';
}
protected function textarea(&$values, &$extras)
{
$values['class'][] = 'autosize';
return '
<textarea |attr|>|value|</textarea>';
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace HTMLBuilder\Handler;
/**
*
* @since 2.3
*/
interface HandlerInterface
{
public function handle(&$values, &$extras);
}

View File

@ -0,0 +1,41 @@
<?php
namespace HTMLBuilder\Handler;
/**
* @since 2.3
*/
class MediaHandler implements HandlerInterface
{
/**
* @since 2.3
*
* @param array $values
* @param array $extras
*
* @return string
*/
public function handle(&$values, &$extras)
{
unset($values['class'][0]);
// Form upload
if (empty($values['value'])) {
$values['type'] = 'file';
return '
<input |attr|>';
} else {
// Visualizzazione dell'immagine e della relativa spunta per la cancellazione
$values['class'][] = 'img-thumbnail';
$values['class'][] = 'img-responsive';
return '
<img src="|value|" |attr|><br>
<label>
<input type="checkbox" name="delete_|name|" id="delete_|id|"> '._('Elimina').'
</label>
<input type="hidden" name="|name|" value="|value|" id="|id|">';
}
}
}

View File

@ -0,0 +1,202 @@
<?php
namespace HTMLBuilder\Handler;
// Utilizzo della funzione prepareToField (PHP 5.6+)
// use function \HTMLBuilder\prepareToField;
/**
* @since 2.3
*/
class SelectHandler implements HandlerInterface
{
public function handle(&$values, &$extras)
{
$values['class'][] = (!empty($values['ajax-source'])) ? 'superselectajax' : 'superselect';
$values['data-source'] = (!empty($values['ajax-source'])) ? $values['ajax-source'] : '';
$values['value'] = explode(',', $values['value']);
if (count($values['value']) === 1 && strlen($values['value'][0]) === 0) {
$values['value'] = [];
}
// Se il valore presente non è valido, carica l'eventuale valore predefinito
if (empty($values['value']) && !is_numeric($values['value']) && !empty($values['valore_predefinito'])) {
$values['value'] = get_var($values['valore_predefinito']);
}
$values['value'] = (array) $values['value'];
$result = '
<select |attr|>';
if (!empty($values['ajax-source'])) {
if (!empty($values['value']) || is_numeric($values['value'])) {
$result .= $this->select2($values['ajax-source'], $values['value']);
}
}
// Generazione <select> da query
elseif (preg_match_all('/^query=(.+?)$/', $values['values'], $matches)) {
$result .= '
<option></option>';
$result .= $this->selectQuery($matches[1][0], $values['value']);
}
// Generazione <select> da JSON
// esempio creazione select con opzioni: Maschio, Femmina, Unisex
// {[ "type": "select", "label": "Sesso", "name": "sesso", "values": "list=\"\": \"\", \"M\": \"Maschio\", \"F\": \"Femmina\", \"U\": \"Unisex\"", "value": "$sesso$" ]}
elseif (preg_match_all('/^list=(.+?)$/', $values['values'], $matches)) {
$result .= '
<option></option>';
$result .= $this->selectList(json_decode('{'.$matches[1][0].'}', true), $values);
} elseif (preg_match_all('/^json=(.+?)$/', $values['values'], $matches)) {
$result .= '
<option></option>';
$result .= $this->selectJSON(json_decode('[{'.$matches[1][0].'}]', true), $values['value']);
}
$values['placeholder'] = !empty($values['placeholder']) ? $values['placeholder'] : '- '._("Seleziona un'opzione").' -';
$values['data-placeholder'] = $values['placeholder'];
unset($values['values']);
$result .= '
</select>';
if (in_array('disabled', $extras) || in_array('readonly', $extras)) {
$result .= '
<script>$("#'.$values['id'].'").prop("disabled", true);</script>';
}
if (in_array('readonly', $extras) && empty($values['ajax-source'])) {
$result .= '
<select class="hide" name="'.\HTMLBuilder\prepareToField($values['name']).'"'.((in_array('multiple', $extras)) ? ' multiple' : '').'>';
foreach ($values['value'] as $value) {
$result .= '
<option value="'.\HTMLBuilder\prepareToField($value).'" selected></option>';
}
$result .= '
</select>';
}
return $result;
}
protected function select2($op, $elements)
{
// Richiamo alla pagina ajax_select.php per aggiungere il valore iniziale al select
ob_start();
$dbo = \Database::getConnection();
include DOCROOT.'/ajax_select.php';
$text = ob_get_clean();
$result = '';
$array = (array) json_decode($text, true);
foreach ($array as $element) {
$element = (array) $element;
if (isset($element['children'][0])) {
$element = (array) $element['children'][0];
}
$attributes = [];
if (in_array($element['id'], $elements)) {
$attributes[] = 'selected';
}
if (!empty($element['_bgcolor_'])) {
$attributes[] = 'style="background:'.$element['_bgcolor_'].'; color:'.color_inverse($element['_bgcolor_'].';"');
}
$exclude = ['id', 'text'];
// Leggo ulteriori campi oltre a id e descrizione per inserirli nell'option nella forma "data-nomecampo1", "data-nomecampo2", ecc
foreach ($element as $key => $value) {
if (!in_array($key, $exclude)) {
$attributes[] = 'data-'.$key.'="'.\HTMLBuilder\prepareToField($value).'"';
}
}
$result .= '
<option value="'.\HTMLBuilder\prepareToField($element['id']).'" '.implode(' ', $attributes).'>'.$element['text'].'</option>';
}
return $result;
}
protected function selectJSON($array, $values)
{
$prev = '';
foreach ($array as $element) {
if (!empty($element['optgroup'])) {
if ($prev != $element['optgroup']) {
$result .= '
<optgroup label="'.\HTMLBuilder\prepareToField($element['optgroup']).'"></optgroup>';
$prev = $element['optgroup'];
}
}
$element['text'] = empty($element['text']) ? $element['descrizione'] : $element['text'];
$attributes = [];
if (in_array($element['id'], $values)) {
$attributes[] = 'selected';
}
if (!empty($element['_bgcolor_'])) {
$attributes[] = 'style="background:'.$element['_bgcolor_'].'; color:'.color_inverse($element['_bgcolor_']).';"';
}
$exclude = ['optgroup'];
// Leggo ulteriori campi oltre a id e descrizione per inserirli nell'option nella forma "data-nomecampo1", "data-nomecampo2", ecc
foreach ($element as $key => $value) {
if (!in_array($key, $exclude)) {
$attributes[] = 'data-'.$key.'="'.\HTMLBuilder\prepareToField($value).'"';
}
}
$result .= '
<option value="'.\HTMLBuilder\prepareToField($element['id']).'" '.implode(' ', $attributes).'>'.$element['text'].'</option>';
}
return $result;
}
protected function selectQuery($query, $values)
{
$result = '';
$database = \Database::getConnection();
$array = $database->fetchArray($query);
return $this->selectJSON($array, $values);
}
protected function selectList($datas, &$values)
{
$result = '';
foreach ($datas as $key => $value) {
if (!empty($key)) {
$attributes = [];
if (in_array($key, $values['value'])) {
$attributes[] = 'selected';
}
$result .= '
<option value="'.\HTMLBuilder\prepareToField($key).'" '.implode(' ', $attributes).'>'.$value.'</option>';
} elseif (empty($values['placeholder'])) {
$values['placeholder'] = $value;
}
}
return $result;
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace HTMLBuilder\Manager;
/**
* @since 2.3
*/
class CSRFManager implements ManagerInterface
{
public function manage($options)
{
$token = \CSRF::getInstance()->getToken();
$keys = array_keys($token);
$values = array_values($token);
$result = '
{[ "type": "hidden", "name": "'.$keys[0].'", "value": "'.$values[0].'" ]}
{[ "type": "hidden", "name": "'.$keys[1].'", "value": "'.$values[1].'" ]}';
return $result;
}
}

View File

@ -0,0 +1,128 @@
<?php
namespace HTMLBuilder\Manager;
/**
* @since 2.3
*/
class FileManager implements ManagerInterface
{
public function manage($options)
{
$options['showpanel'] = isset($options['showpanel']) ? $options['showpanel'] : true;
$options['label'] = isset($options['label']) ? $options['label'] : 'Nuovo allegato:';
$dbo = \Database::getConnection();
$result .= '
<a name="attachments"></a>';
if (!empty($options['showpanel'])) {
$result .= '
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">'._('Allegati').'</h3>
</div>
<div class="panel-body">';
}
// Visualizzo l'elenco di file già caricati
$rs = $dbo->fetchArray('SELECT * FROM zz_files WHERE id_module='.prepare($options['id_module']).' AND id_record='.prepare($options['id_record']));
if (!empty($rs)) {
$result .= '
<table class="table table-condensed table-hover table-bordered">
<tr>
<th>'._('Nome').'</th>
<th>'._('Data').'</th>
<th style="width:5%;text-align:center;">#</th>
</tr>';
foreach ($rs as $r) {
$result .= '
<tr>
<td align="left">
<a href="'.ROOTDIR.'/files/'.\Modules::getModule($options['id_module'])['directory'].'/'.$r['filename'].'" target="_blank">
<i class="fa fa-external-link"></i> '.$r['nome'].'
</a>
</td>
<td>'.\Translator::timestampToLocale($r['created_at']).'</td>
<td>
<a class="btn btn-danger ask" data-backto="record-edit" data-msg="'._('Vuoi eliminare questo file?').'" data-op="unlink_file" data-id="'.$r['id'].'" data-filename="'.$r['filename'].'">
<i class="fa fa-trash"></i>
</a>
</td>
</tr>';
}
$result .= '
</table>
<div class="clearfix"></div>
<br>';
}
// Form per l'upload di un nuovo file
$result .= '
<b>'.$options['label'].'</b>
<div class="row">
<div class="col-lg-4">
{[ "type": "text", "placeholder": "'._('Nome').'", "name": "nome_allegato", "required": 1 ]}
</div>
<div class="col-lg-6">
{[ "type": "file", "placeholder": "'._('File').'", "name": "blob", "required": 1 ]}
</div>
<div class="col-lg-2 text-right">
<button type="button" class="btn btn-success" id="upload_button" onclick="SaveFile();">
<i class="fa fa-upload"></i> '._('Carica').'
</button>
</div>
</div>';
$result .= '
<script>
function SaveFile(){
if(!$("#blob").val()){
alert("Devi selezionare un file con il tasto Sfoglia...");
return false;
} else if(!$("input[name=nome_allegato]").val()){
alert("Devi inserire un nome per il file!");
return false;
}
var file_data = $("#blob").prop("files")[0];
var form_data = new FormData();
form_data.append("blob", file_data);
form_data.append("nome_allegato", $("input[name=nome_allegato]").val());
form_data.append("op","link_file");
form_data.append("id_record","'.$options['id_record'].'");
form_data.append("id_module", "'.$options['id_module'].'");
$.ajax({
url: "'.ROOTDIR.'/actions.php",
cache: false,
type: "post",
processData: false,
contentType: false,
dataType : "html",
data: form_data,
success: function(data) {
location.href = globals.rootdir + "/editor.php?id_module='.$options['id_module'].'&id_record='.$options['id_record'].'";
},
error: function(data) {
alert(data);
}
})
}
</script>';
if (!empty($options['showpanel'])) {
$result .= '
</div>
</div>';
}
return $result;
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace HTMLBuilder\Manager;
/**
*
* @since 2.3
*/
interface ManagerInterface
{
public function manage($options);
}

View File

@ -0,0 +1,146 @@
<?php
namespace HTMLBuilder\Wrapper;
// Utilizzo della funzione prepareToField (PHP 5.6+)
// use function \HTMLBuilder\prepareToField;
/**
* @since 2.3
*/
class HTMLWrapper implements WrapperInterface
{
public function before(&$values, &$extras)
{
$result = '';
// Valori particolari
$values['icon-before'] = $this->parser($values, $values['icon-before']);
$values['icon-after'] = $this->parser($values, $values['icon-after']);
// Generazione dell'etichetta
if (!empty($values['label'])) {
$result .= '
<div class="form-group">
<label for="'.\HTMLBuilder\prepareToField($values['id']).'">'.(empty($values['help']) ? $values['label'] : '<span class="tip" title="'.\HTMLBuilder\prepareToField($values['help']).'">'.$values['label'].'</span>').'</label>';
}
if (!empty($values['icon-before']) || !empty($values['icon-after'])) {
$result .= '
<div class="input-group">';
if (!empty($values['icon-before'])) {
$result .= '
<span class="input-group-addon'.(!empty($values['icon-custom']) ? ' '.$values['icon-custom'] : '').'">'.$values['icon-before'].'</span>';
}
}
return $result;
}
public function after(&$values, &$extras)
{
$result = '';
if (!empty($values['icon-before']) || !empty($values['icon-after'])) {
if (!empty($values['icon-after'])) {
$result .= '
<span class="input-group-addon'.(!empty($values['icon-custom']) ? ' '.$values['icon-custom'] : '').'">'.$values['icon-after'].'</span>';
}
$result .= '
</div>';
unset($values['icon-before']);
unset($values['icon-after']);
unset($values['icon-custom']);
}
if (!empty($values['help']) && !empty($values['show-help'])) {
$result .= '
<span class="help-block pull-left"><small>'.$values['help'].'</small></span>';
unset($values['help']);
unset($values['show-help']);
}
$values['data-parsley-errors-container'] = '#'.$values['id'].'-errors';
$result .= '
<div id="'.$values['id'].'-errors"></div>';
if (!empty($values['label'])) {
$result .= '
</div>';
unset($values['label']);
}
return $result;
}
protected function parser(&$values, $string)
{
$result = $string;
if (starts_with($string, 'add|')) {
$result = $this->add($values, $string);
$values['icon-custom'] = 'no-padding';
} elseif (starts_with($string, 'choice|')) {
$result = $this->choice($values, $string);
$values['icon-custom'] = 'no-padding';
}
return $result;
}
protected function add(&$values, $string)
{
$result = null;
$pieces = explode('|', $string);
$id_module = $pieces[1];
$extra = empty($pieces[2]) ? '' : '&'.$pieces[2];
$classes = empty($pieces[3]) ? '' : ' '.$pieces[3];
$module = \Modules::getModule($id_module);
if (in_array($module['permessi'], ['r', 'rw'])) {
$result = '
<button data-href="'.ROOTDIR.'/add.php?id_module='.$id_module.$extra.'&select='.$values['id'].'&ajax=yes" data-target="#bs-popup2" data-toggle="modal" data-title="'._('Aggiungi').'" type="button" class="btn'.$classes.'">
<i class="fa fa-plus"></i>
</button>';
}
return $result;
}
protected function choice(&$values, $string)
{
$result = null;
$choices = [
[
'id' => 'UNT',
'descrizione' => _('&euro;'),
],
[
'id' => 'PRC',
'descrizione' => '%',
],
];
$pieces = explode('|', $string);
$type = $pieces[1];
$value = (empty($pieces[2]) || !in_array($pieces[2], array_column($choices, 'id'))) ? 'UNT' : $pieces[2];
if ($type == 'untprc') {
$result = '{[ "type": "select", "name": "tipo_'.\HTMLBuilder\prepareToField($values['name']).'", "value": "'.\HTMLBuilder\prepareToField($value).'", "values": "json='.substr(str_replace('"', '\"', json_encode($choices)), 2, -2).'", "class": "no-search" ]}';
$result = \HTMLBuilder\HTMLBuilder::replace($result);
}
return $result;
}
}

View File

@ -0,0 +1,14 @@
<?php
namespace HTMLBuilder\Wrapper;
/**
*
* @since 2.3
*/
interface WrapperInterface
{
public function before(&$values, &$extras);
public function after(&$values, &$extras);
}

View File

@ -0,0 +1,52 @@
<?php
namespace Intl;
/**
* Classe dedicata al caricamento delle risorse per le traduzioni.
*
* @since 2.3
*/
class FileLoader extends \Symfony\Component\Translation\Loader\FileLoader
{
protected static $loaders = [];
protected $include_filename;
public function __construct($include_filename = false)
{
$this->include_filename = $include_filename;
}
protected function loadResource($resource)
{
$result = [];
$extension = strtolower(pathinfo($resource, PATHINFO_EXTENSION));
if (!empty($extension) && !empty($this->getLoader($extension))) {
$result = $this->getLoader($extension)->loadResource($resource);
if (!empty($this->include_filename)) {
$result = array_combine(
array_map(function ($k) use ($resource, $extension) {
return basename($resource, '.'.$extension).'.'.$k;
}, array_keys($result)),
$result
);
}
}
return $result;
}
protected function getLoader($name)
{
if (empty(self::$loaders[$name])) {
$class = '\Symfony\Component\Translation\Loader\\'.ucfirst($name).'FileLoader';
if (class_exists($class)) {
self::$loaders[$name] = new $class();
}
}
return !empty(self::$loaders[$name]) ? self::$loaders[$name] : null;
}
}

View File

@ -0,0 +1,470 @@
<?php
namespace Intl;
use DateTime;
use UnexpectedValueException;
use Exception;
/**
* Classe per gestire le conversione di date e numeri tra diversi formati.
*
* @since 2.3
*/
class Formatter
{
protected $numberSeparators;
protected $datePattern;
protected $timePattern;
protected $timestampPattern;
public function __construct($numberSeparators = [], $date = null, $time = null, $timestamp = null)
{
$this->setNumberSeparators($numberSeparators);
$this->setDatePattern($date);
$this->setTimePattern($time);
$this->setTimestampPattern($timestamp);
}
/**
* Imposta il formato dei numeri.
*
* @param string $values
*/
protected function setNumberSeparators($values)
{
$decimals = empty($values['decimals']) ? '.' : $values['decimals'];
$thousands = !isset($values['thousands']) ? '' : $values['thousands'];
if ($decimals == $thousands) {
throw new Exception('Bad separators');
}
$this->numberSeparators = [
'decimals' => $decimals,
'thousands' => $thousands,
];
}
/**
* Restituisce i separatori utilizzati per la formattazione.
*
* @return array
*/
public function getNumberSeparators()
{
return $this->numberSeparators;
}
/**
* Imposta il formato della data.
*
* @param string $value
*/
protected function setDatePattern($value)
{
$value = empty($value) ? 'Y-m-d' : $value;
if (is_array($value)) {
$pattern = implode($value['separator'], $value['order']);
$pattern = str_replace(['day', 'month', 'year'], ['d', 'm', 'Y'], $pattern);
} else {
$pattern = $value;
}
$this->datePattern = $pattern;
}
/**
* Restituisce il formato della data.
*
* @return string
*/
public function getDatePattern()
{
return $this->datePattern;
}
/**
* Imposta il formato dell'orario.
*
* @param string $value
*/
protected function setTimePattern($value)
{
$value = empty($value) ? 'H:i:s' : $value;
if (is_array($value)) {
$pattern = implode($value['separator'], $value['order']);
$pattern = str_replace(['hours', 'minutes', 'seconds'], ['H', 'i', 's'], $pattern);
} else {
$pattern = $value;
}
$this->timePattern = $pattern;
}
/**
* Restituisce il formato dell'orario.
*
* @return string
*/
public function getTimePattern()
{
return $this->timePattern;
}
/**
* Imposta il formato del timestamp.
*
* @param string $value
*/
protected function setTimestampPattern($value)
{
$value = empty($value) ? [
'order' => ['date', 'time'],
'separator' => ' ',
] : $value;
if (is_array($value)) {
$pattern = implode($value['separator'], $value['order']);
$pattern = str_replace(['date', 'time'], [$this->getDatePattern(), $this->getTimePattern()], $pattern);
} else {
$pattern = $value;
}
$this->timestampPattern = $pattern;
}
/**
* Restituisce il formato del timestamp.
*
* @return string
*/
public function getTimestampPattern()
{
return $this->timestampPattern;
}
/**
* Controlla se l'elemento indicato è un numero.
*
* @param string $value
*
* @return bool
*/
public function isNumber($value)
{
try {
$this->toNumberObject($value);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* Controlla se l'elemento indicato è un timestamp.
*
* @param string $value
*
* @return bool
*/
public function isTimestamp($value)
{
try {
$this->toTimestampObject($value);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* Controlla se l'elemento indicato è una data.
*
* @param string $value
*
* @return bool
*/
public function isDate($value)
{
try {
$this->toDateObject($value);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* Controlla se l'elemento indicato è un orario.
*
* @param string $value
*
* @return bool
*/
public function isTime($value)
{
try {
$this->toTimeObject($value);
} catch (Exception $e) {
return false;
}
return true;
}
/**
* Converte l'elemento in una rappresentazione numerica.
*
* @param string $value
*
* @return array
*/
public function toNumberObject($value)
{
$value = trim($value);
if (strlen($value) == 0) {
throw new UnexpectedValueException('Format not supported');
}
$sign = null;
if ($value[0] == '+' || $value[0] == '-') {
$sign = $value[0];
$value = trim(substr($value, 1));
} elseif (!is_numeric($value[0])) {
throw new UnexpectedValueException('Format not supported');
}
if (strlen($value) == 0) {
throw new UnexpectedValueException('Format not supported');
}
$pieces = explode($this->getNumberSeparators()['decimals'], $value);
if (count($pieces) > 2) {
throw new UnexpectedValueException('Format not supported');
}
$integer = $pieces[0];
$decimal = (isset($pieces[1])) ? $pieces[1] : null;
if (!empty($this->getNumberSeparators()['thousands'])) {
$error = true;
if (floor(strlen($integer) / 4) == substr_count($integer, $this->getNumberSeparators()['thousands'])) {
$values = str_split(strrev($integer), 4);
foreach ($values as $key => $value) {
if (strlen($value) == 4 && ends_with($value, '.')) {
$values[$key] = substr($value, 0, -1);
}
}
$integer = strrev(implode($values));
$error = substr_count($integer, $this->getNumberSeparators()['thousands']);
}
if (!empty($error)) {
throw new UnexpectedValueException('Format not supported');
}
}
if (!ctype_digit($integer) || (strlen($integer) != strlen((int) $integer)) || (isset($decimal) && !ctype_digit($decimal))) {
throw new UnexpectedValueException('Format not supported');
}
return [$sign, $integer, $decimal];
}
/**
* Converte l'elemento dal formato personalizzato a quello predefinito di PHP.
*
* @param string $value
*
* @return string
*/
public function toTimestampObject($value)
{
$value = trim($value);
$result = DateTime::createFromFormat($this->getTimestampPattern(), $value);
if (!is_object($result)) {
throw new UnexpectedValueException('Format not supported');
}
return $result;
}
/**
* Converte l'elemento dal formato personalizzato a quello predefinito di PHP.
*
* @param string $value
*
* @return string
*/
public function toDateObject($value)
{
$value = trim($value);
$result = DateTime::createFromFormat($this->getDatePattern(), $value);
$result = !is_object($result) ? $this->toTimestampObject($value) : $result;
if (!is_object($result)) {
throw new UnexpectedValueException('Format not supported');
}
return $result;
}
/**
* Converte l'elemento dal formato personalizzato a quello predefinito di PHP.
*
* @param string $value
*
* @return string
*/
public function toTimeObject($value)
{
$value = trim($value);
$result = DateTime::createFromFormat($this->getTimePattern(), $value);
$result = !is_object($result) ? $this->toTimestampObject($value) : $result;
if (!is_object($result)) {
throw new UnexpectedValueException('Format not supported');
}
return $result;
}
/**
* Converte un numero da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function convertNumberTo($formatter, $value)
{
$pieces = $this->toNumberObject($value);
$result = (!empty($pieces[0])) ? $pieces[0] : '';
$result .= number_format($pieces[1], 0, '', $formatter->getNumberSeparators()['thousands']);
if (isset($pieces[2])) {
$result .= $formatter->getNumberSeparators()['decimals'].$pieces[2];
}
return $result;
}
/**
* Converte un timestamp da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function convertTimestampTo($formatter, $value)
{
$result = $this->toTimestampObject($value);
return $result->format($formatter->getTimestampPattern());
}
/**
* Converte una data da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function convertDateTo($formatter, $value)
{
$result = $this->toDateObject($value);
return $result->format($formatter->getDatePattern());
}
/**
* Converte un orario da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function convertTimeTo($formatter, $value)
{
$result = $this->toTimeObject($value);
return $result->format($formatter->getTimePattern());
}
/**
* Converte un numero da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function getNumberFrom($formatter, $value)
{
return $formatter->convertNumberTo($this, $value);
}
/**
* Converte un timestamp da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function getTimestampFrom($formatter, $value)
{
return $formatter->convertTimestampTo($this, $value);
}
/**
* Converte una data da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function getDateFrom($formatter, $value)
{
return $formatter->convertDateTo($this, $value);
}
/**
* Converte un orario da una formattazione all'altra.
*
* @param Formatter $formatter
* @param string $value
*
* @return string
*/
public function getTimeFrom($formatter, $value)
{
return $formatter->convertTimeTo($this, $value);
}
}

466
lib/classes/Modules.php Normal file
View File

@ -0,0 +1,466 @@
<?php
/**
* Classe per la gestione delle informazioni relative ai moduli installati.
*
* @since 2.3
*/
class Modules
{
protected static $current_module;
protected static $current_element;
protected static $modules = [];
protected static $additionals = [];
protected static $queries = [];
protected static $hierarchy = [];
protected static $depth;
protected static $menu;
/**
* Restituisce tutte le informazioni di tutti i moduli installati.
*
* @return array
*/
public static function getModules()
{
if (empty(self::$modules)) {
$database = Database::getConnection();
$user = Auth::getUser();
$results = $database->fetchArray('SELECT * FROM `zz_modules` LEFT JOIN (SELECT `idmodule`, `permessi` FROM `zz_permissions` WHERE `idgruppo` = (SELECT `idgruppo` FROM `zz_users` WHERE `idutente` = '.prepare($user['idutente']).')) AS `zz_permissions` ON `zz_modules`.`id`=`zz_permissions`.`idmodule` LEFT JOIN (SELECT `idmodule`, `clause`, `position` FROM `zz_group_module` WHERE `idgruppo` = (SELECT `idgruppo` FROM `zz_users` WHERE `idutente` = '.prepare($user['idutente']).') AND `enabled` = 1) AS `zz_group_module` ON `zz_modules`.`id`=`zz_group_module`.`idmodule`');
$modules = [];
$additionals = [];
foreach ($results as $result) {
if (empty($additionals[$result['id']])) {
$additionals[$result['id']]['WHR'] = [];
$additionals[$result['id']]['HVN'] = [];
}
if (!empty($result['clause'])) {
$result['clause'] = self::replacePlaceholder($result['clause']);
$additionals[$result['id']][$result['position']][] = $result['clause'];
}
if (empty($modules[$result['id']])) {
if (empty($result['permessi'])) {
if (Auth::isAdmin()) {
$result['permessi'] = 'rw';
} else {
$result['permessi'] = '-';
}
}
unset($result['clause']);
unset($result['position']);
unset($result['idmodule']);
$modules[$result['id']] = $result;
$modules[$result['name']] = $result['id'];
}
}
self::$modules = $modules;
self::$additionals = $additionals;
}
return self::$modules;
}
/**
* Restituisce le informazioni relative a un singolo modulo specificato.
*
* @param string|int $module
*
* @return array
*/
public static function getModule($module)
{
if (!is_numeric($module) && !empty(self::getModules()[$module])) {
$module = self::getModules()[$module];
}
return self::getModules()[$module];
}
/**
* Restituisce i permessi accordati all'utente in relazione al modulo specificato.
*
* @param string|int $module
*
* @return string
*/
public static function getPermission($module)
{
return self::getModule($module)['permessi'];
}
/**
* Restituisce i filtri aggiuntivi dell'utente in relazione al modulo specificato.
*
* @param int $id
*
* @return string
*/
public static function getAdditionals($module)
{
return (array) self::$additionals[self::getModule($module)['id']];
}
/**
* Restituisce le condizioni SQL aggiuntive del modulo.
*
* @param string $name
*
* @return array
*/
public static function getAdditionalsQuery($module, $type = null)
{
$array = self::getAdditionals($module);
if (!empty($type) && isset($array[$type])) {
$result = $array[$type];
} else {
$result = array_merge($array['WHR'], $array['HVN']);
}
$result = implode(' AND ', $result);
$result = empty($result) ? $result : ' AND '.$result;
return $result;
}
public static function replaceAdditionals($id_module, $query)
{
$result = $query;
// Aggiunta delle condizione WHERE
$result = str_replace('1=1', '1=1'.self::getAdditionalsQuery($id_module, 'WHR'), $result);
// Aggiunta delle condizione HAVING
$result = str_replace('2=2', '2=2'.self::getAdditionalsQuery($id_module, 'HVN'), $result);
return $result;
}
/**
* Restituisce l'identificativo del modulo attualmente in utilizzo.
*
* @return int
*/
public static function getCurrentModule()
{
if (empty(self::$current_module)) {
self::$current_module = filter('id_module');
}
return self::getModule(self::$current_module);
}
/**
* Restituisce l'identificativo dell'elemento attualmente in utilizzo.
*
* @return int
*/
public static function getCurrentElement()
{
if (empty(self::$current_element)) {
self::$current_element = filter('id_record');
}
return self::$current_element;
}
/**
* Restituisce un'insieme di array comprendenti le informazioni per la costruzione della query del modulo indicato.
*
* @param int $id
*
* @return array
*/
public static function getQuery($id)
{
if (empty(self::$queries[$id])) {
$database = Database::getConnection();
$module = self::getModule($id);
$fields = [];
$summable = [];
$search_inside = [];
$search = [];
$slow = [];
$order_by = [];
$select = '*';
$options = !empty($module['options2']) ? $module['options2'] : $module['options'];
if (strpos($options, '|select|') !== false) {
$query = $options;
$user = Auth::getUser();
$datas = $database->fetchArray('SELECT * FROM `zz_views` WHERE `id_module`='.prepare($id).' AND `id` IN (SELECT `id_vista` FROM `zz_group_view` WHERE `id_gruppo`=(SELECT `idgruppo` FROM `zz_users` WHERE `idutente`='.prepare($user['idutente']).')) ORDER BY `order` ASC');
if (!empty($datas)) {
$select = '';
foreach ($datas as $data) {
$select .= $data['query'].(!empty($data['name']) ? " AS '".$data['name']."', " : '');
if ($data['enabled']) {
$fields[] = trim($data['name']);
$search_inside[] = !empty(trim($data['search_inside'])) ? trim($data['search_inside']) : trim($data['name']);
$order_by[] = !empty(trim($data['order_by'])) ? trim($data['order_by']) : trim($data['name']);
$search[] = $data['search'];
$slow[] = $data['slow'];
$format[] = $data['format'];
if ($data['summable']) {
$summable[] = 'SUM(`'.trim($data['name']."`) AS 'sum_".(count($fields) - 1)."'");
}
}
}
$select = substr($select, 0, strlen($select) - 2);
}
} else {
$options = self::readOldQuery($options);
$query = $options['query'];
$fields = explode(',', $options['fields']);
foreach ($fields as $key => $value) {
$fields[$key] = trim($value);
$search[] = 1;
$slow[] = 0;
$format[] = 0;
}
$search_inside = $fields;
$order_by = $fields;
}
$result = [];
$result['query'] = $query;
$result['select'] = $select;
$result['fields'] = $fields;
$result['search_inside'] = $search_inside;
$result['order_by'] = $order_by;
$result['search'] = $search;
$result['slow'] = $slow;
$result['format'] = $format;
$result['summable'] = $summable;
self::$queries[$id] = $result;
}
return self::$queries[$id];
}
public static function readOldQuery($options)
{
$options = str_replace(["\r", "\n", "\t"], ' ', $options);
$options = json_decode($options, true);
return $options['main_query'][0];
}
public static function replacePlaceholder($query, $custom = null)
{
$user = Auth::getUser();
$custom = empty($custom) ? $user['idanagrafica'] : $custom;
$result = str_replace(['|idagente|', '|idtecnico|', '|idanagrafica|'], prepare($custom), $query);
return $result;
}
/**
* Restituisce tutte le informazioni dei moduli installati in una scala gerarchica fino alla profondità indicata.
*
*
* @param int $depth
*
* @return array
*/
public static function getHierarchy($depth = 3)
{
if (empty(self::$hierarchy) || self::$depth != $depth) {
$database = Database::getConnection();
$depth = ($depth < 2) ? 2 : $depth;
$fields = [];
for ($i = 0; $i < $depth; ++$i) {
$fields[] = '`t'.$i."`.`id` AS 't".$i.".id'";
}
$query = 'SELECT '.implode(', ', $fields).' FROM `zz_modules` AS `t0`';
for ($i = 1; $i < $depth; ++$i) {
$query .= ' LEFT JOIN `zz_modules` AS `t'.$i.'` ON `t'.$i.'`.`parent` = `t'.($i - 1).'`.`id`';
}
$query .= ' WHERE `t0`.`parent` IS NULL ORDER BY `t0`.`order` ASC';
$modules = $database->fetchArray($query);
$hierarchy = [];
foreach ($modules as $module) {
$hierarchy = self::buildArray($module, $hierarchy);
}
self::$depth = $depth;
self::$hierarchy = $hierarchy;
}
return self::$hierarchy;
}
/**
* Restituisce l'elaborazione dell'array secondo una struttura ad albero (molteplici root).
*
* @param int $id
* @param array $data
* @param int $actual
*
* @return array
*/
protected static function buildArray($module, $data = [], $actual = 0)
{
if (!empty($module['t'.$actual.'.id'])) {
$pos = array_search($module['t'.$actual.'.id'], array_column($data, 'id'));
if ($pos === false && !empty($module['t'.$actual.'.id'])) {
$array = self::getModule($module['t'.$actual.'.id']);
$array['childrens'] = [];
$data[] = $array;
$pos = count($data) - 1;
}
if (!empty($module['t'.($actual + 1).'.id'])) {
$data[$pos]['childrens'] = self::buildArray($module, $data[$pos]['childrens'], $actual + 1);
}
}
return $data;
}
/**
* Restituisce il menu principale del progetto.
*
* @param int $depth Profondità del menu
*
* @return string
*/
public static function getMainMenu($depth = 3)
{
if (empty(self::$menu) || self::$depth != $depth) {
$menus = self::getHierarchy($depth);
$module_name = self::getCurrentModule()['name'];
$result = '';
foreach ($menus as $menu) {
$result .= self::sidebarMenu($menu, isset($module_name) ? $module_name : '')[0];
}
self::$menu = $result;
}
return self::$menu;
}
/**
* Restituisce l'insieme dei menu derivato da un'array strutturato ad albero.
*
* @param array $element
* @param int $actual
*
* @return string
*/
protected static function sidebarMenu($element, $actual = null)
{
global $rootdir;
$options = ($element['options2'] != '') ? $element['options2'] : $element['options'];
$link = ($options != '' && $options != 'menu') ? $rootdir.'/controller.php?id_module='.$element['id'] : 'javascript:;';
$title = $element['title'];
$target = ($element['new'] == 1) ? '_blank' : '_self';
$active = ($actual == $element['name']);
$show = (self::getPermission($element['id']) != '-' && !empty($element['enabled'])) ? true : false;
$submenus = $element['childrens'];
if (!empty($submenus)) {
$temp = '';
foreach ($submenus as $submenu) {
$r = self::sidebarMenu($submenu, $actual);
$active = $active || $r[1];
if (!$show && $r[2]) {
$link = 'javascript:;';
}
$show = $show || $r[2];
$temp .= $r[0];
}
}
$result = '';
if ($show) {
$result .= '<li class="treeview';
if ($active) {
$result .= ' active actual';
}
$result .= '" id="'.$element['id'].'">
<a href="'.$link.'" target="'.$target.'" >
<i class="'.$element['icon'].'"></i>
<span>'.$title.'</span>';
if (!empty($submenus) && !empty($temp)) {
$result .= '
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
'.$temp.'
</ul>';
} else {
$result .= '
</a>';
}
$result .= '
</li>';
}
return [$result, $active, $show];
}
/**
* Undocumented function.
*
* @param string|int $modulo
* @param int $id_record
* @param string $testo
* @param string $alternativo
* @param string $extra
*
* @return string
*/
public static function link($modulo, $id_record, $testo = null, $alternativo = true, $extra = null, $blank = true)
{
$testo = isset($testo) ? nl2br($testo) : _('Visualizza scheda').' <i class="fa fa-external-link"></i>';
$alternativo = is_bool($alternativo) && $alternativo ? $testo : $alternativo;
$module = self::getModule($modulo);
$extra .= !empty($blank) ? ' target="_blank"' : '';
if (!empty($module) && in_array($module['permessi'], ['r', 'rw'])) {
return '<a href="'.ROOTDIR.'/editor.php?id_module='.$module['id'].'&id_record='.$id_record.'" '.$extra.'>'.$testo.'</a>';
} else {
return $alternativo;
}
}
}

View File

@ -0,0 +1,89 @@
<?php
/**
* Classe per gestire i permessi di accesso alle diverse sezioni del progetto.
*
* @since 2.3
*/
class Permissions
{
protected static $permissions = [];
protected static $skip_permissions = false;
/**
* Aggiunge un modulo di cui eseguire il controllo dei permessi.
*
* @param string $id
*/
public static function addModule($module)
{
$id = Modules::getModule($module)['id'];
if (is_int($id) && !in_array($id, self::$permissions)) {
self::$permissions[] = $id;
}
}
/**
* Ignora il controllo dei permessi per la pagina corrente.
*/
public static function skip()
{
self::$skip_permissions = true;
}
/**
* Riabilita il controllo dei permessi per la pagina corrente.
*/
public static function execute()
{
self::$skip_permissions = false;
}
/**
* Restituisce la variabile per cui si effettua o meno il controllo dei permessi per la pagina corrente.
*
* @return bool
*/
public static function getSkip()
{
return self::$skip_permissions;
}
/**
* Esegue il controllo dei permessi.
*
* @return bool
*/
public static function check($permissions = [])
{
if (empty($permissions)) {
$permissions = ['r', 'rw'];
} elseif (!is_array($permissions)) {
$permissions = [$permissions];
}
$result = true;
if (!self::getSkip()) {
if (!Auth::check() && strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') === false) {
redirect(ROOTDIR.'/index.php');
exit();
$result = false;
} else {
if (!empty(self::$permissions)) {
foreach (self::$permissions as $module) {
if (!in_array(Modules::getPermission($module), $permissions)) {
$result = false;
}
}
}
if (!$result) {
die(_('Accesso negato!'));
}
}
}
return $result;
}
}

117
lib/classes/Plugins.php Normal file
View File

@ -0,0 +1,117 @@
<?php
/**
* Classe per la gestione delle informazioni relative ai moduli installati.
*
* @since 2.3
*/
class Plugins
{
protected static $plugins = [];
protected static $queries = [];
/**
* Restituisce tutte le informazioni di tutti i moduli installati.
*
* @return array
*/
public static function getPlugins()
{
if (empty(self::$plugins)) {
$database = Database::getConnection();
$results = $database->fetchArray('SELECT *, (SELECT directory FROM zz_modules WHERE id=idmodule_from) AS module_dir FROM zz_plugins');
$plugins = [];
foreach ($results as $result) {
$plugins[$result['id']] = $result;
$plugins[$result['name']] = $result['id'];
}
self::$plugins = $plugins;
}
return self::$plugins;
}
/**
* Restituisce le informazioni relative a un singolo modulo specificato.
*
* @param int $id
*
* @return array
*/
public static function getPlugin($id)
{
return self::getPlugins()[$id];
}
/**
* Restituisce le informazioni relative a un singolo modulo specificato, ricercato in base al nome.
*
* @param string $name
*
* @return array
*/
public static function getPluginByName($name)
{
if (!empty(self::getPlugins()[$name])) {
return self::getPlugin(self::getPlugins()[$name]);
}
}
/**
* Restituisce un'insieme di array comprendenti le informazioni per la costruzione della query del modulo indicato.
*
* @param int $id
*
* @return array
*/
public static function getQuery($id)
{
if (empty(self::$queries[$id])) {
$database = Database::getConnection();
$module = self::getPlugin($id);
$fields = [];
$summable = [];
$search_inside = [];
$search = [];
$slow = [];
$order_by = [];
$select = '*';
$options = !empty($module['options2']) ? $module['options2'] : $module['options'];
$options = Modules::readOldQuery($options);
$query = $options['query'];
$fields = explode(',', $options['fields']);
foreach ($fields as $key => $value) {
$fields[$key] = trim($value);
$search[] = 1;
$slow[] = 0;
$format[] = 0;
}
$search_inside = $fields;
$order_by = $fields;
$result = [];
$result['query'] = $query;
$result['select'] = $select;
$result['fields'] = $fields;
$result['search_inside'] = $search_inside;
$result['order_by'] = $order_by;
$result['search'] = $search;
$result['slow'] = $slow;
$result['format'] = $format;
$result['summable'] = $summable;
self::$queries[$id] = $result;
}
return self::$queries[$id];
}
}

60
lib/classes/Settings.php Normal file
View File

@ -0,0 +1,60 @@
<?php
/**
* Classe per la gestione dell impostazioni del progetto.
*
* @since 2.3
*/
class Settings
{
protected static $values = [];
/**
* Restituisce il valore corrente dell'impostazione ricercata.
* Se l'impostazione viene cercata più volte, il primo valore individuato viene salvato; per costringere a aggiornare i contenuto, usare l'opzione $again.
*
* @param string $nome
* @param string $sezione
* @param string $descrizione
* @param bool $again
*
* @return string
*/
public static function get($nome, $sezione = null, $descrizione = false, $again = false)
{
if (Update::isUpdateAvailable()) {
return null;
}
if (empty(self::$values[$sezione.'.'.$nome]) || !empty($again)) {
$database = Database::getConnection();
if (!$database->isInstalled()) {
return null;
}
$query = 'SELECT valore, tipo FROM zz_settings WHERE nome='.prepare($nome);
if (!empty($sezione)) {
$query .= ' AND sezione='.prepare($sezione);
}
$results = $database->fetchArray($query);
$value = null;
if (!empty($results)) {
$result = $results[0];
$value = $result['valore'];
if (!empty($descrizione) && strpos($result['tipo'], 'query=') !== false) {
$data = $database->fetchArray(str_replace('query=', '', $result['tipo']));
if (!empty($data)) {
$value = $data[0]['descrizione'];
}
}
}
self::$values[$sezione.'.'.$nome] = $value;
}
return self::$values[$sezione.'.'.$nome];
}
}

361
lib/classes/Translator.php Normal file
View File

@ -0,0 +1,361 @@
<?php
/**
* Classe per gestire le traduzioni del progetto.
*
* @since 2.3
*/
class Translator extends Util\Singleton
{
/** @var Intl\Formatter Oggetto per la conversione di date e numeri nella lingua selezionata */
protected static $localeFormatter;
/** @var Intl\Formatter Oggetto per la conversione di date e numeri nella formattazione originale */
protected static $englishFormatter;
/** @var Symfony\Component\Translation\Translator Oggetto dedicato alle traduzioni */
protected $translator;
/** @var array Lingue disponibili */
protected $locales = [];
/** @var string Lingua selezionata */
protected $locale;
public function __construct($default_locale = 'it', $fallback_locales = ['it'])
{
if (!empty($instance)) {
throw new Exception();
}
if (version_compare(PHP_VERSION, '5.5.9') >= 0) {
$translator = new Symfony\Component\Translation\Translator($default_locale);
$this->locale = $default_locale;
$translator->setFallbackLocales($fallback_locales);
// Imposta la classe per il caricamento
$translator->addLoader('default', new Intl\FileLoader());
$this->translator = $translator;
}
$instance = $this;
}
/**
* Ricerca e aggiunge le traduzioni presenti nei percorsi predefiniti (cartella locale sia nella root che nei diversi moduli).
*
* @param [type] $string
*/
public function addLocalePath($string)
{
$paths = glob($string);
foreach ($paths as $path) {
$this->addLocales($path);
}
}
/**
* Aggiunge i contenuti della cartella specificata alle traduzioni disponibili.
*
* @param string $path
*/
protected function addLocales($path)
{
if (!empty($this->$translator)) {
// Individua i linguaggi disponibili
$dirs = glob($path.DIRECTORY_SEPARATOR.'*', GLOB_ONLYDIR);
foreach ($dirs as $dir) {
$this->addLocale(basename($dir));
}
// Aggiunge le singole traduzioni
foreach ($this->locales as $lang) {
$done = [];
$files = glob($path.DIRECTORY_SEPARATOR.$lang.DIRECTORY_SEPARATOR.'*.*');
foreach ($files as $file) {
if (!in_array(basename($file), $done)) {
$this->translator->addResource('default', $file, $lang);
$done[] = basename($file);
}
}
}
}
}
/**
* Aggiunge il linguaggio indicato all'elenco di quelli disponibili.
*
* @param string $language
*/
protected function addLocale($language)
{
if (!$this->isLocaleAvailable($language)) {
$this->locales[] = $language;
}
}
/**
* Restituisce l'elenco dei linguaggi disponibili.
*
* @return array
*/
public function getAvailableLocales()
{
return $this->locales;
}
/**
* Controlla se il linguaggio indicato è disponibile.
*
* @param string $language
*
* @return bool
*/
public function isLocaleAvailable($language)
{
return in_array($language, $this->getAvailableLocales());
}
/**
* Imposta il linguaggio in utilizzo.
*
* @param string $locale
*/
public function setLocale($locale)
{
if (!empty($locale) && $this->isLocaleAvailable($locale)) {
if (!empty($this->translator)) {
self::$translator->setLocale($locale);
}
$this->locale = $locale;
}
}
/**
* Restituisce il linguaggio attualmente in utilizzo.
*
* @return string
*/
public function getCurrentLocale()
{
return $this->locale;
}
/**
* Restituisce l'oggetto responsabile della gestione delle traduzioni.
*
* @return Symfony\Component\Translation\Translator
*/
public function getTranslator()
{
return $this->translator;
}
/**
* Restituisce la traduzione richiesta.
*
* @param string $string
* @param string $parameters
* @param string $domain
* @param string $locale
*
* @return string
*/
public static function translate($string, $parameters = [], $domain = null, $locale = null)
{
$translator = self::getInstance();
if (!empty($translator)) {
return $translator->trans($string, $parameters, $domain, $locale);
} else {
return $string;
}
}
/**
* Genera l'oggetto dedicato alla gestione delle conversioni nella lingua locale.
*
* @param array $formatter
*/
public static function setLocaleFormatter($formatter = [])
{
self::$localeFormatter = new Intl\Formatter(
empty($formatter['numbers']) ? [
'decimals' => ',',
'thousands' => '.',
] : $formatter['numbers'],
empty($formatter['date']) ? 'd/m/Y' : $formatter['date'],
empty($formatter['time']) ? 'H:i' : $formatter['time'],
empty($formatter['timestamp']) ? null : $formatter['timestamp']);
}
/**
* Restituisce il formato locale della data.
*
* @return Intl\Formatter
*/
public static function getLocaleFormatter()
{
if (empty(self::$localeFormatter)) {
self::setLocaleFormatter();
}
return self::$localeFormatter;
}
/**
* Restituisce il formato locale della data.
*
* @return Intl\Formatter
*/
public static function getEnglishFormatter()
{
if (empty(self::$englishFormatter)) {
self::$englishFormatter = new Intl\Formatter();
}
return self::$englishFormatter;
}
/**
* Restituisce il formato locale della data.
*
* @return string
*/
public static function getLocaleDatePattern()
{
return self::getLocaleFormatter()->getDatePattern();
}
/**
* Converte il numero dalla formattazione locale a quella inglese.
*
* @param string $string
*
* @return string
*/
public static function numberToEnglish($string)
{
return self::getLocaleFormatter()->convertNumberTo(self::getEnglishFormatter(), $string);
}
/**
* Converte il numero dalla formattazione inglese a quella locale.
*
* @param string $string
* @param mixed $decimals
*
* @return string
*/
public static function numberToLocale($string, $decimals = true)
{
$string = !isset($string) ? 0 : $string;
if (isset($decimals) && (is_int($decimals) || !empty($decimals))) {
$decimals = is_numeric($decimals) ? $decimals : Settings::get('Cifre decimali per importi');
$string = number_format($string, $decimals, self::getEnglishFormatter()->getNumberSeparators()['decimals'], self::getEnglishFormatter()->getNumberSeparators()['thousands']);
}
return self::getEnglishFormatter()->convertNumberTo(self::getLocaleFormatter(), $string);
}
/**
* Converte la data dalla formattazione locale a quella inglese.
*
* @param string $string
*
* @return string
*/
public static function dateToEnglish($string)
{
return self::getLocaleFormatter()->convertDateTo(self::getEnglishFormatter(), $string);
}
/**
* Converte la data dalla formattazione inglese a quella locale.
*
* @param string $string
* @param string $fail
*
* @return string
*/
public static function dateToLocale($string, $fail = null)
{
if (!self::isValid($string)) {
return $fail;
}
return self::getEnglishFormatter()->convertDateTo(self::getLocaleFormatter(), $string);
}
/**
* Converte la data dalla formattazione locale a quella inglese.
*
* @param string $string
*
* @return string
*/
public static function timeToEnglish($string)
{
return self::getLocaleFormatter()->convertTimeTo(self::getEnglishFormatter(), $string);
}
/**
* Converte la data dalla formattazione inglese a quella locale.
*
* @param string $string
* @param string $fail
*
* @return string
*/
public static function timeToLocale($string, $fail = null)
{
if (!self::isValid($string)) {
return $fail;
}
return self::getEnglishFormatter()->convertTimeTo(self::getLocaleFormatter(), $string);
}
/**
* Converte un timestamp dalla formattazione locale a quella inglese.
*
* @param string $timestamp
*
* @return string
*/
public static function timestampToEnglish($string)
{
return self::getLocaleFormatter()->convertTimestampTo(self::getEnglishFormatter(), $string);
}
/**
* Converte un timestamp dalla formattazione inglese a quella locale.
*
* @param string $timestamp
* @param string $fail
*
* @return string
*/
public static function timestampToLocale($string, $fail = null)
{
if (!self::isValid($string)) {
return $fail;
}
return self::getEnglishFormatter()->convertTimestampTo(self::getLocaleFormatter(), $string);
}
/**
* Controlla se una data inserita nella formattazione inglese è valida.
*
* @param string $timestamp
*
* @return bool
*/
protected static function isValid($string)
{
return !in_array($string, ['0000-00-00 00:00:00', '0000-00-00', '00:00:00']);
}
}

306
lib/classes/Update.php Normal file
View File

@ -0,0 +1,306 @@
<?php
/**
* Classe dedicata alla gestione delle procedure di aggiornamento del database del progetto.
*
* @since 2.3
*/
class Update
{
/** @var array Lista degli aggiornamenti da completare */
protected static $updates;
protected static function prepareToUpdate()
{
$database = Database::getConnection();
$database_ready = $database->isConnected() && $database->fetchNum("SHOW TABLES LIKE 'updates'");
// Individuazione di tutti gli aggiornamenti fisicamente presenti
$results = [];
// Aggiornamenti del gestionale
$core = (array) glob(DOCROOT.'/update/*.{php,sql}', GLOB_BRACE);
foreach ($core as $value) {
$infos = pathinfo($value);
$value = str_replace('_', '.', $infos['filename']);
if (self::isVersion($value)) {
$results[] = $value;
}
}
// Aggiornamenti dei moduli
$modules = (array) glob(DOCROOT.'/modules/*/update/*.{php,sql}', GLOB_BRACE);
foreach ($modules as $value) {
$infos = pathinfo($value);
$module = end(explode('/', dirname($infos['dirname'])));
$value = str_replace('_', '.', $infos['filename']);
if (self::isVersion($value)) {
$results[] = $module.'_'.$value;
}
}
$results = array_unique($results);
asort($results);
// Individuazione di tutti gli aggiornamenti inseriti
$updates = ($database_ready) ? $database->fetchArray('SELECT * FROM `updates`') : [];
$versions = array_column($updates, 'version');
$reset = count(array_intersect($results, $versions)) != count($results);
if ($reset && $database->isConnected()) {
// Individua le versioni che sono state installate, anche solo parzialmente
$done = ($database_ready) ? $database->fetchArray('SELECT version, done FROM updates WHERE `done` IS NOT NULL') : [];
// Reimpostazione della tabella degli aggiornamenti
$create = DOCROOT.'/update/create_updates.sql';
if (file_exists($create)) {
$database->query('DROP TABLE IF EXISTS `updates`');
$database->multiQuery($create);
}
// Inserimento degli aggiornamenti individuati
foreach ($results as $result) {
// Individuazione di script e sql
$temp = explode('_', $result);
$file = DOCROOT.((strpos($result, '_') !== false) ? '/modules/'.implode('_', explode('_', $result, -1)) : '').'/update/'.str_replace('.', '_', end($temp));
$sql = file_exists($file.'.sql') ? 1 : 0;
$script = file_exists($file.'.php') ? 1 : 0;
// Reimpostazione degli stati per gli aggiornamenti precedentemente presenti
$pos = array_search($result, $versions);
$done = ($pos !== false) ? prepare($updates[$pos]['done']) : 'NULL';
$database->query('INSERT INTO `updates` (`version`, `sql`, `script`, `done`) VALUES ('.prepare($result).', '.prepare($sql).', '.prepare($script).', '.$done.')');
}
// Normalizzazione di charset e collation
self::normalizeDatabase($database->getDatabaseName());
}
}
public static function getTodos()
{
if (!is_array(self::$updates)) {
self::prepareToUpdate();
$database = Database::getConnection();
$updates = $database->isConnected() ? $database->fetchArray('SELECT * FROM `updates` WHERE `done` != 1 OR `done` IS NULL ORDER BY `done` DESC, `id` ASC') : [];
foreach ($updates as $key => $value) {
$updates[$key]['name'] = ucwords(str_replace('_', ' ', $value['version']));
$temp = explode('_', $value['version']);
$updates[$key]['filename'] = str_replace('.', '_', end($temp));
$updates[$key]['directory'] = ((strpos($value['version'], '_') !== false) ? '/modules/'.implode('_', explode('_', $value['version'], -1)) : '').'/update/';
}
self::$updates = $updates;
}
return self::$updates;
}
public static function getUpdate()
{
if (!empty(self::getTodos())) {
return self::getTodos()[0];
}
}
public static function isVersion($string)
{
return preg_match('/^\d+(?:\.\d+)+$/', $string);
}
public static function isUpdateAvailable()
{
return !empty(self::getTodos());
}
public static function isUpdateCompleted()
{
return !self::isUpdateAvailable();
}
public static function isUpdateLocked()
{
$todos = array_column(self::getTodos(), 'done');
foreach ($todos as $todo) {
if ($todo !== null && $todo !== 1) {
return true;
}
}
return false;
}
public static function getDatabaseVersion()
{
$database = Database::getConnection();
$results = $database->fetchArray("SELECT version FROM `updates` WHERE version NOT LIKE '%\_%' ORDER BY version DESC LIMIT 1");
return $results[0]['version'];
}
public static function getVersion()
{
return self::getFile('VERSION');
}
public static function getRevision()
{
return self::getFile('REVISION');
}
protected static function getFile($file)
{
$file = (strpos($file, DOCROOT.DIRECTORY_SEPARATOR) !== false) ? $file : DOCROOT.DIRECTORY_SEPARATOR.$file;
$result = '';
$filepath = realpath($file);
if (!empty($filepath)) {
$result = file_get_contents($filepath);
$result = str_replace(["\r\n", "\n"], '', $result);
}
return trim($result);
}
public static function updateCleanup()
{
if (self::isUpdateCompleted()) {
$database = Database::getConnection();
// Aggiornamento all'ultima release della versione e compatibilità moduli
$database->query('UPDATE `zz_modules` SET `compatibility`='.prepare(self::getVersion()).', `version`='.prepare(self::getVersion()).' WHERE `default` = 1');
// Normalizzazione di charset e collation
self::normalizeDatabase($database->getDatabaseName());
return true;
}
return false;
}
public static function doUpdate($rate = 20)
{
global $logger;
set_time_limit(0);
ignore_user_abort(true);
if (!self::isUpdateCompleted()) {
$update = self::getUpdate();
$file = DOCROOT.$update['directory'].$update['filename'];
$database = Database::getConnection();
try {
// Esecuzione query release
if (!empty($update['sql']) && (!empty($update['done']) || is_null($update['done'])) && file_exists($file.'.sql')) {
$queries = readSQLFile($file.'.sql', ';');
$count = count($queries);
$start = empty($update['done']) ? 0 : $update['done'] - 2;
$end = ($start + $rate + 1) > $count ? $count : $start + $rate + 1;
if ($start < $end) {
for ($i = $start; $i < $end; ++$i) {
$database->query($queries[$i], _('Aggiornamento fallito').': '.$queries[$i]);
$database->query('UPDATE `updates` SET `done` = '.prepare($i + 3).' WHERE id = '.prepare($update['id']));
}
return [
$start,
$end,
$count,
];
}
}
$database->query('UPDATE `updates` SET `done` = 0 WHERE id = '.prepare($update['id']));
// Esecuzione script release
if (!empty($update['script']) && file_exists($file.'.php')) {
self::executeScript($file.'.php');
}
$database->query('UPDATE `updates` SET `done` = 1 WHERE id = '.prepare($update['id']));
// Normalizzazione di charset e collation
self::normalizeDatabase($database->getDatabaseName());
return true;
} catch (\Exception $e) {
$logger->addRecord(\Monolog\Logger::EMERGENCY, $e->getMessage());
}
return false;
}
}
protected static function normalizeDatabase($database_name)
{
set_time_limit(0);
ignore_user_abort(true);
$database = Database::getConnection();
$mysql_ver = $database->getMySQLVersion();
if (version_compare($mysql_ver, '5.5.3') >= 0) {
$character_set = 'utf8mb4';
$collation = 'utf8mb4_general_ci';
} else {
$character_set = 'utf8';
$collation = 'utf8_general_ci';
}
// Normalizzazione del database (le nuove tabelle verranno automaticamente impostate secondo la codifica predefinita)
$default_collation = $database->fetchArray('SELECT DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = '.prepare($database_name).' LIMIT 1')[0]['DEFAULT_COLLATION_NAME'];
if ($default_collation != $collation) {
$database->query('ALTER DATABASE `'.$database_name.'` CHARACTER SET '.$character_set.' COLLATE '.$collation);
}
// Normalizzazione delle tabelle
$tables = $database->fetchArray('SHOW TABLE STATUS IN `'.$database_name.'` WHERE Collation != '.prepare($collation)." AND Name != 'updates'");
if (!empty($tables)) {
$database->query('SET foreign_key_checks = 0');
// Conversione delle tabelle
foreach ($tables as $table) {
$database->query('ALTER TABLE `'.$table['Name'].'` CONVERT TO CHARACTER SET '.$character_set.' COLLATE '.$collation);
}
$database->query('SET foreign_key_checks = 1');
}
}
protected static function executeScript($script)
{
include __DIR__.'/../../core.php';
$database = $dbo;
// Informazioni relative a MySQL
$mysql_ver = $database->getMySQLVersion();
include $script;
}
}

155
lib/classes/Util/Ini.php Normal file
View File

@ -0,0 +1,155 @@
<?php
namespace Util;
/**
* Classe dedicata alla gestione e all'interpretazione dei file INI.
*
* @since 2.3
*/
class Ini
{
/**
* Predispone la struttura per il salvataggio dei contenuti INI a partire da una struttura precedente.
*
* @param string $content
* @param array $values
*
* @return string
*/
public static function write($content, $values)
{
$result = '';
// Lettura info componente
if (!empty($content)) {
// Converto 'contenuto' di questo componente in un array
$array = self::read($content);
// Per ogni sezione dell'array estratto dal file ini
foreach ($array as $sezione => $valori) {
$sezione = str_replace(["\r", "\n"], '<br/>', $sezione);
$result .= '['.$sezione.']'.PHP_EOL;
if (array_key_exists('valore', $valori)) {
$valori = array_replace($valori, ['valore' => $valori['valore']], ['valore' => $values[str_replace(' ', '_', $sezione)]]);
}
foreach ($valori as $key => $value) {
$result .= $key.' = "'.addslashes($value).'"'.PHP_EOL;
}
}
}
return $result;
}
/**
* Interpreta i contentuti di una stringa in formato INI.
*
* @param string $string
*
* @return array
*/
public static function read($string)
{
return parse_ini_string($string, true);
}
/**
* Interpreta i contenuti di un file INI.
*
* @param string $filename
*
* @return array
*/
public static function readFile($filename)
{
$filename = (file_exists($filename)) ? $filename : DOCROOT.'/files/my_impianti/'.$filename;
return self::read(file_get_contents($filename));
}
/**
* Restituisce la lista di tutti i file INI presenti all'interno della cartella indicata.
*
* @param string $dir
* @param array $exclude
*/
public static function getList($dir, $exclude = [])
{
$results = [];
// Lettura dei files nella cartella indicata
$exclude = (!empty($exclude)) ? $exclude : [];
$exclude = (is_string($exclude)) ? explode(',', $list) : $exclude;
// Aggiungo tutti i componenti di possibile installazione
$files = (array) glob(realpath($dir).'/*.ini');
foreach ($files as $file) {
if (!in_array(basename($file), $exclude)) {
$results[] = [basename($file), self::getValue(self::readFile($file), 'Nome')];
}
}
return $results;
}
/**
* Ottiene il valore di un campo contenuto all'interno della struttura INI.
*
* @param string $content
* @param string $value
*
* @return mixed
*/
public static function getValue($content, $value)
{
$result = !empty($content) && isset($content[$value]['valore']) ? $content[$value]['valore'] : '';
return $result;
}
/**
* Predispone il form dedicato alla modifica dei contenuti della struttura INI.
*
* @param string $contenut
*
* @return array
*/
public static function getFields($contenut)
{
$result = [];
// Caricamento campi dell'eventuale componente selezionato
if (!empty($contenut)) {
$random = rand();
$array = self::read($contenut);
if (is_array($array)) {
$result[] = '
<h4>'.str_replace('_NAME_', $array['Nome']['valore'], _('Attributi per _NAME_')).'</h4>
<input type="hidden" name="Nome" value="'.$array['Nome']['valore'].'">';
foreach ($array as $sezione => $array_impostazioni) {
if ($sezione != 'Nome') {
$nome = $sezione;
$tipo = ($array[$sezione]['tipo'] == 'input') ? 'text' : $array[$sezione]['tipo'];
$valore = $array[$sezione]['valore'];
$opzioni = strpos($array[$sezione]['opzioni'], ',') ? explode(',', $array[$sezione]['opzioni']) : [];
$values = [];
foreach ($opzioni as $o) {
$values[] = '\"'.addslashes(addslashes($o)).'\": \"'.addslashes(addslashes($o)).'\"';
}
$result[] = '
{[ "type": "'.$tipo.'", "label": "'.$nome.':", "name": "'.$nome.'", "value": '.json_encode($valore).', "id": "'.$nome.'_'.$random.'" '.(!empty($values) ? ', "values": "list='.implode(', ', $values).'"' : '').' ]}';
}
}
}
}
return $result;
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Util;
/**
* @since 2.3
*/
class Singleton
{
/** @var \Util\Singleton Oggetto istanziato */
protected static $instance = null;
protected function __construct()
{
}
/**
* Restituisce l'istanza della classe in oggetto.
*
* @return Singleton
*/
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new static();
}
return self::$instance;
}
private function __clone()
{
}
private function __wakeup()
{
}
}

173
lib/classes/Widgets.php Normal file
View File

@ -0,0 +1,173 @@
<?php
/**
* Classe per la gestione dei widgets del progetto.
*
* @since 2.0
*/
class Widgets
{
public static $widgets = [];
/**
* Funzione addModuleWidgets
* $id_modulo: modulo in cui ci si trova
* $location: location all'interno del modulo, per esempio controller oppure inserimento/modifica
* Prende da database tutti i widget associati al modulo passato come parametro e li aggiunge con createWidget
* alla pagina.
*/
public static function addModuleWidgets($id_module, $location)
{
if (empty(self::$widgets[$id_module][$location])) {
$dbo = Database::getConnection();
// ottengo da db gli id dei widget associati al modulo
$results = $dbo->fetchArray('SELECT id, location, class FROM zz_widgets WHERE id_module='.prepare($id_module).' AND location='.prepare($location).' AND enabled=1 ORDER BY `order` ASC');
$result = '';
if (!empty($results)) {
$cont = count($results);
if ($cont > 4 || $cont < 2) {
$cont = 4;
}
// Aggiungo la riga per bootstrap
$result = '
<ul class="row widget" id="widget-'.$location.'" data-class="'.$results[0]['class'].'">';
// Aggiungo ad uno ad uno tutti i widget
foreach ($results as $widget) {
$result .= self::createWidget($widget['id'], $widget['class'], $cont);
}
$result .= '
</ul>
<script>
equalHeight("#widget-'.$location.' .li-widget .box");
</script>';
}
self::$widgets[$id_module][$location] = $result;
}
return self::$widgets[$id_module][$location];
}
/**
* Funzione createWidget
* $id_widget: l'id numerico del widget da creare ed inserire nella pagina
* Sa seconda del tipo di widget inserisce il codice HTML per la sua creazione nella pagina.
* Ottiene i dati per la creazione
* del widget da tabella, in maniera da crearli in maniera dinamica a seconda dei campi.
*/
protected static function createWidget($id_widget, $class, $totalNumber = 4)
{
global $rootdir;
$dbo = Database::getConnection();
// ottengo i dati del widget passato come parametro da database
$results = $dbo->fetchArray("SELECT *, (SELECT name FROM zz_modules WHERE id = zz_widgets.id_module) AS 'module_name' FROM zz_widgets WHERE id=".prepare($id_widget));
$module_name = $results[0]['module_name'];
$result = '';
// a seconda del tipo inserisco il widget in maniera differente
switch ($results[0]['type']) {
// widget di tipo statistiche
case 'print':
case 'stats':
$query = $results[0]['query'];
$additionals = Modules::getAdditionalsQuery($module_name);
if (!empty($additionals)) {
$query = str_replace('1=1', '1=1 '.$additionals, $query);
}
$query = str_replace('|period_start|', $_SESSION['period_start'], $query);
$query = str_replace('|period_end|', $_SESSION['period_end'], $query);
$dato = '';
if ($query != '') {
$dato = $dbo->fetchArray($query);
}
if (!empty($dato)) {
$dato = $dato[0]['dato'];
// inserisco il widget
$result .= '
<li class="col-xs-12 col-sm-6 col-md-4 col-lg-'.intval(12 / $totalNumber).' li-widget" id="widget_'.$results[0]['id'].'">
<button type="button" class="close" onclick="if(confirm(\'Disabilitare questo widget?\')) { $.post( \''.$rootdir.'/modules/aggiornamenti/actions.php?id_module='.$results[0]['id_module'].'\', { op: \'disable_widget\', id: \''.$results[0]['id'].'\' }, function(response){ location.href = \''.$rootdir.'/controller.php?id_module='.$results[0]['id_module'].'\'; }); };" ><span aria-hidden="true">&times;</span><span class="sr-only">'._('Chiudi').'</span></button>';
if (!empty($results[0]['more_link'])) {
$result .= '
<a class="clickable" ';
if ($results[0]['more_link_type'] == 'link') {
$result .= 'href="'.$results[0]['more_link'].'"';
} elseif ($results[0]['more_link_type'] == 'popup') {
$result .= 'data-href="'.$results[0]['more_link'].'" data-toggle="modal" data-title="'.$results[0]['text'].'" data-target="#bs-popup"';
} elseif ($results[0]['more_link_type'] == 'javascript') {
$link = $results[0]['more_link'];
$link = str_replace('|period_start|', $_SESSION['period_start'], $link);
$link = str_replace('|period_end|', $_SESSION['period_end'], $link);
$result .= 'onclick="'.$link.'"';
}
$result .= '>';
}
$result .= '
<div class="info-box">
<span class="info-box-icon" style="background-color:'.$results[0]['bgcolor'].'">
<i class="'.$results[0]['icon'].'"></i>
</span>
<div class="info-box-content">
<span class="info-box-text">'.$results[0]['text'].'</span>
<span class="info-box-number">'.$dato.'</span>
</div>
</div>';
if (!empty($results[0]['more_link'])) {
$result .= '
</a>';
}
$result .= '
</li>';
}
break;
// widget di tipo chart: importa la pagina php specificata nel campo php_include della tabella, non ha l'icona
case 'chart':
$result .= '
<li class="'.$class.'" id="'.$results[0]['id'].'">
<!-- small box -->
<div class="small-box bg-'.$results[0]['bgcolor'].'">
<div class="inner">';
include_once $results[0]['php_include'];
$result .= '
</div>
</div>
</li>';
break;
// widget custom con codice php e icona
case 'custom':
$result .= '
<li class="'.$class.'" id="'.$results[0]['id'].'">
<!-- small box -->
<div class="small-box bg-'.$results[0]['bgcolor'].'">
<div class="inner">';
include_once $results[0]['php_include'];
$result .= '
</div>
<div class="icon">
<i class="'.$results[0]['icon'].'"></i>
</div>
</div>
</li>';
break;
}
return $result;
}
}

1025
lib/deprecated.php Normal file

File diff suppressed because it is too large Load Diff

1255
lib/functions.js Normal file

File diff suppressed because it is too large Load Diff

842
lib/functions.php Normal file
View File

@ -0,0 +1,842 @@
<?php
/**
* Esegue il redirect.
*
* @param string $url
* @param string $type
*
* @return bool
*/
function redirect($url, $type = 'php')
{
switch ($type) {
case 'php':
header('Location: '.$url);
break;
case 'js':
echo '<script type="text/javascript">location.href="'.$url.'";</script>';
break;
}
}
/**
* Verifica e corregge il nome di un file.
*
* @param unknown $filename
*
* @return mixed
*/
function sanitizeFilename($filename)
{
$filename = str_replace(' ', '-', $filename);
$filename = preg_replace("/[^A-Za-z0-9_\-\.?!]/", '', $filename);
return $filename;
}
/**
* Rimuove ricorsivamente una directory.
*
* @param unknown $path
*
* @return bool
*/
function deltree($path)
{
$path = realpath($path);
if (is_dir($path)) {
$files = scandir($path);
if (empty($files)) {
$files = [];
}
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
deltree($path.DIRECTORY_SEPARATOR.$file);
}
}
return rmdir($path);
} elseif (file_exists($path)) {
return unlink($path);
}
}
/**
* Copy a file, or recursively copy a folder and its contents.
*
* @author Aidan Lister <aidan@php.net>
*
* @version 1.0.1
*
* @see http://aidanlister.com/repos/v/function.copyr.php
*
* @param string $source
* Source path
* @param string $dest
* Destination path
* @param string $exclude
* Path to exclude
*
* @return bool Returns TRUE on success, FALSE on failure
*/
function copyr($source, $dest, $exclude = [])
{
// Simple copy for a file
if (is_file($source) && !in_array(slashes(realpath($source)), $exclude) && !in_array($source, $exclude)) {
return copy($source, $dest);
}
// Make destination directory
if (!is_dir($dest)) {
mkdir($dest);
}
// If the source is a symlink
if (is_link($source)) {
$link_dest = readlink($source);
return symlink($link_dest, $dest);
}
// Loop through the folder
$dir = dir($source);
while (false !== $entry = $dir->read()) {
// Skip pointers
if ($entry == '.' || $entry == '..') {
continue;
}
// Deep copy directories
if ($dest !== $source.'/'.$entry && !in_array(slashes(realpath($source.'/'.$entry.'/')), $exclude) && !in_array(slashes(realpath($source.'/'.$entry.'/').'/'), $exclude) && !in_array($entry, $exclude)) {
copyr($source.'/'.$entry, $dest.'/'.$entry, $exclude);
}
}
// Clean up
$dir->close();
return true;
}
/**
* Crea un file zip comprimendo ricorsivamente tutte le sottocartelle a partire da una cartella specificata.
*
* @see http://stackoverflow.com/questions/1334613/how-to-recursively-zip-a-directory-in-php
*
* @param unknown $source
* @param unknown $destination
*/
function create_zip($source, $destination)
{
if (!extension_loaded('zip') || !file_exists($source)) {
$_SESSION['errors'][] = _('Estensione zip non supportata!');
return false;
}
$zip = new ZipArchive();
if ($zip->open($destination, ZIPARCHIVE::CREATE)) {
$source = slashes(realpath($source));
if (is_dir($source) === true) {
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), RecursiveIteratorIterator::SELF_FIRST);
foreach ($files as $file) {
$file = slashes(realpath($file));
$file = str_replace($source.DIRECTORY_SEPARATOR, '', $file);
if (is_dir($file) === true) {
$zip->addEmptyDir($file);
} elseif (is_file($file) === true) {
$zip->addFromString($file, file_get_contents($file));
}
}
} elseif (is_file($source) === true) {
$zip->addFromString(basename($source), file_get_contents($source));
}
$zip->close();
return true;
} else {
$_SESSION['errors'][] = _("Errore durante la creazione dell'archivio!");
return false;
}
}
/**
* Controllo dei file zip e gestione errori.
*
* @param unknown $zip_file
*
* @return string|bool
*/
function checkZip($zip_file)
{
$errno = zip_open($zip_file);
zip_close($errno);
if (!is_resource($errno)) {
// using constant name as a string to make this function PHP4 compatible
$errors = [
ZIPARCHIVE::ER_MULTIDISK => _('archivi multi-disco non supportati'),
ZIPARCHIVE::ER_RENAME => _('ridenominazione del file temporaneo fallita'),
ZIPARCHIVE::ER_CLOSE => _('impossibile chiudere il file zip'),
ZIPARCHIVE::ER_SEEK => _('errore durante la ricerca dei file'),
ZIPARCHIVE::ER_READ => _('errore di lettura'),
ZIPARCHIVE::ER_WRITE => _('errore di scrittura'),
ZIPARCHIVE::ER_CRC => _('errore CRC'),
ZIPARCHIVE::ER_ZIPCLOSED => _("l'archivio zip è stato chiuso"),
ZIPARCHIVE::ER_NOENT => _('file non trovato'),
ZIPARCHIVE::ER_EXISTS => _('il file esiste già'),
ZIPARCHIVE::ER_OPEN => _('impossibile aprire il file'),
ZIPARCHIVE::ER_TMPOPEN => _('impossibile creare il file temporaneo'),
ZIPARCHIVE::ER_ZLIB => _('errore nella libreria Zlib'),
ZIPARCHIVE::ER_MEMORY => _("fallimento nell'allocare memoria"),
ZIPARCHIVE::ER_CHANGED => _('voce modificata'),
ZIPARCHIVE::ER_COMPNOTSUPP => _('metodo di compressione non supportato'),
ZIPARCHIVE::ER_EOF => _('fine del file non prevista'),
ZIPARCHIVE::ER_INVAL => _('argomento non valido'),
ZIPARCHIVE::ER_NOZIP => _('file zip non valido'),
ZIPARCHIVE::ER_INTERNAL => _('errore interno'),
ZIPARCHIVE::ER_INCONS => _('archivio zip inconsistente'),
ZIPARCHIVE::ER_REMOVE => _('impossibile rimuovere la voce'),
ZIPARCHIVE::ER_DELETED => _('voce eliminata'),
];
if (isset($errors[$errno])) {
return _('Errore').': '.$errors[$errno];
}
return false;
} else {
return true;
}
}
/**
* Esegue il backup dell'intero progetto.
*
* @return bool
*/
function do_backup()
{
global $backup_dir;
set_time_limit(0);
if (extension_loaded('zip')) {
$tmp_backup_dir = '/tmp/';
} else {
$tmp_backup_dir = '/OSM backup '.date('Y-m-d').' '.date('H_i_s').'/';
}
// Creazione cartella temporanea
if (!file_exists($backup_dir.$tmp_backup_dir)) {
if (@mkdir($backup_dir.$tmp_backup_dir)) {
$do_backup = true;
} else {
$do_backup = false;
}
} else {
$do_backup = true;
}
if ($do_backup) {
$database_file = 'backup database.sql';
$backup_file = 'OSM backup '.date('Y-m-d').' '.date('H_i_s').'.zip';
// Dump database
$dump = "SET foreign_key_checks = 0;\n";
$dump .= backup_tables();
file_put_contents($backup_dir.$tmp_backup_dir.$database_file, $dump);
// Copia file di OSM (escludendo la cartella di backup)
copyr(DOCROOT, $backup_dir.$tmp_backup_dir, [slashes($backup_dir), '.svn', 'config.inc.php', 'node_modules']);
// Creazione zip
if (extension_loaded('zip')) {
if (create_zip($backup_dir.$tmp_backup_dir, $backup_dir.$backup_file)) {
$_SESSION['infos'][] = _('Nuovo backup creato!');
} else {
$_SESSION['errors'][] = _('Errore durante la creazione del backup!');
}
} else {
$_SESSION['infos'][] = _('Nuovo backup creato!');
}
// Rimozione cartella temporanea
if (extension_loaded('zip')) {
deltree($backup_dir.$tmp_backup_dir);
}
// Eliminazione vecchi backup se ce ne sono
$max_backups = intval(get_var('Numero di backup da mantenere'));
// Lettura file di backup
if ($handle = opendir($backup_dir)) {
$backups = [];
while (false !== ($file = readdir($handle))) {
// I nomi dei file di backup hanno questa forma:
// OSM backup yyyy-mm-dd HH_ii_ss.zip (oppure solo cartella senza zip)
if (preg_match('/^OSM backup ([0-9\-]{10}) ([0-9_]{8})/', $file, $m)) {
$backups[] = $file;
}
}
closedir($handle);
if (count($backups) > $max_backups) {
// Fondo e ordino i backup dal più recente al più vecchio
arsort($backups);
$cont = 1;
foreach ($backups as $backup) {
if ($cont > $max_backups) {
if (preg_match('/^OSM backup ([0-9\-]{10}) ([0-9_]{8})$/', $backup, $m)) {
deltree($backup_dir.'/'.$backup);
} elseif (preg_match('/^OSM backup ([0-9\-]{10}) ([0-9_]{8})\.zip$/', $backup, $m)) {
unlink($backup_dir.'/'.$backup);
}
}
++$cont;
}
}
}
}
return $do_backup;
}
/**
* Funzione per fare il dump del database.
*
* @see http://davidwalsh.name/backup-mysql-database-php
*
* @param string $tables
*
* @return string
*/
function backup_tables($tables = '*')
{
$dbo = Database::getConnection();
if ($tables == '*') {
$tables = [];
$result = $dbo->fetchArray('SHOW TABLES', true);
if ($result != null) {
foreach ($result as $res) {
$tables[] = $res[0];
}
}
} else {
$tables = is_array($tables) ? $tables : explode(',', $tables);
}
// Eliminazione di tutte le tabelle
foreach ($tables as $table) {
$return .= "DROP TABLE IF EXISTS `$table`;\n";
}
// Ricreazione della struttura di ogni tabella e ri-popolazione database
foreach ($tables as $table) {
$result = $dbo->fetchArray('SELECT * FROM '.$table, true);
$num_fields = count($result[0]);
$row2 = $dbo->fetchArray('SHOW CREATE TABLE '.$table);
$return .= "\n".$row2[1].";\n";
for ($i = 0; $i < $num_fields; ++$i) {
if ($result != false) {
foreach ($result as $row) {
$return .= 'INSERT INTO '.$table.' VALUES(';
for ($j = 0; $j < $num_fields; ++$j) {
$row[$j] = addslashes($row[$j]);
$row[$j] = str_replace("\r\n", '\\n', $row[$j]);
$row[$j] = str_replace("\n", '\\n', $row[$j]);
if (isset($row[$j])) {
$return .= '"'.$row[$j].'"';
} else {
$return .= '""';
}
if ($j < ($num_fields - 1)) {
$return .= ',';
}
}
$return .= ");\n";
}
}
}
$return .= "\n";
}
return $return;
// save file
// $handle = fopen('db-backup-'.time().'-'.(md5(implode(',',$tables))).'.sql','w+');
// fwrite($handle,$return);
// fclose($handle);
}
/**
* Individua la differenza tra le date indicate.
* $interval può essere:
* yyyy - Number of full years
* q - Number of full quarters
* m - Number of full months
* y - Difference between day numbers
* (eg 1st Jan 2004 is "1", the first day. 2nd Feb 2003 is "33". The datediff is "-32".)
* d - Number of full days
* w - Number of full weekdays
* ww - Number of full weeks
* h - Number of full hours
* n - Number of full minutes
* s - Number of full seconds (default).
*
* @param unknown $interval
* @param unknown $datefrom
* @param unknown $dateto
* @param string $using_timestamps
*/
function datediff($interval, $datefrom, $dateto, $using_timestamps = false)
{
if (!$using_timestamps) {
$datefrom = strtotime($datefrom, 0);
$dateto = strtotime($dateto, 0);
}
$difference = $dateto - $datefrom; // Difference in seconds
switch ($interval) {
case 'yyyy': // Number of full years
$years_difference = floor($difference / 31536000);
if (mktime(date('H', $datefrom), date('i', $datefrom), date('s', $datefrom), date('n', $datefrom), date('j', $datefrom), date('Y', $datefrom) + $years_difference) > $dateto) {
--$years_difference;
}
if (mktime(date('H', $dateto), date('i', $dateto), date('s', $dateto), date('n', $dateto), date('j', $dateto), date('Y', $dateto) - ($years_difference + 1)) > $datefrom) {
++$years_difference;
}
$datediff = $years_difference;
break;
case 'q': // Number of full quarters
$quarters_difference = floor($difference / 8035200);
while (mktime(date('H', $datefrom), date('i', $datefrom), date('s', $datefrom), date('n', $datefrom) + ($quarters_difference * 3), date('j', $dateto), date('Y', $datefrom)) < $dateto) {
++$months_difference;
}
--$quarters_difference;
$datediff = $quarters_difference;
break;
case 'm': // Number of full months
$months_difference = floor($difference / 2678400);
while (mktime(date('H', $datefrom), date('i', $datefrom), date('s', $datefrom), date('n', $datefrom) + ($months_difference), date('j', $dateto), date('Y', $datefrom)) < $dateto) {
++$months_difference;
}
--$months_difference;
$datediff = $months_difference;
break;
case 'y': // Difference between day numbers
$datediff = date('z', $dateto) - date('z', $datefrom);
break;
case 'd': // Number of full days
$datediff = floor($difference / 86400);
break;
case 'w': // Number of full weekdays
$days_difference = floor($difference / 86400);
$weeks_difference = floor($days_difference / 7); // Complete weeks
$first_day = date('w', $datefrom);
$days_remainder = floor($days_difference % 7);
$odd_days = $first_day + $days_remainder; // Do we have a Saturday or Sunday in the remainder?
if ($odd_days > 7) { // Sunday
--$days_remainder;
}
if ($odd_days > 6) { // Saturday
--$days_remainder;
}
$datediff = ($weeks_difference * 5) + $days_remainder;
break;
case 'ww': // Number of full weeks
$datediff = floor($difference / 604800);
break;
case 'h': // Number of full hours
$datediff = floor($difference / 3600);
break;
case 'n': // Number of full minutes
$datediff = floor($difference / 60);
break;
default: // Number of full seconds (default)
$datediff = $difference;
break;
}
return $datediff;
}
/**
* Recupera informazioni sistema operativo dell'utente.
*
* @return string
*/
function getOS()
{
$os = [
'Windows NT 6.1' => 'Windows 7',
'Windows NT 6.0' => 'Windows Vista',
'Windows NT 5.1' => 'Windows XP',
'Windows NT 5.0' => 'Windows 2000',
'Windows NT 4.90' => 'Windows ME',
'Win95' => 'Windows 95',
'Win98' => 'Windows 98',
'Windows NT 5.2' => 'Windows NET',
'WinNT4.0' => 'Windows NT',
'Mac' => 'Mac',
'PPC' => 'Mac',
'Linux' => 'Linux',
'FreeBSD' => 'FreeBSD',
'SunOS' => 'SunOS',
'Irix' => 'Irix',
'BeOS' => 'BeOS',
'OS/2' => 'OS/2',
'AIX' => 'AIX',
];
foreach ($os as $key => $value) {
if (strpos($_SERVER['HTTP_USER_AGENT'], $key)) {
return $value;
}
}
return _('Altro');
}
/**
* Legge una stringa presumibilmente codificata (tipo "8D001") e, se possibile, restituisce il codice successivo ("8D002").
*
* @param $str string
* Codice di partenza da incrementare
* @param $qty int
* Unità da aggiungere alla parte numerica del codice (di default incrementa di 1)
* @param $mask string
* Specifica i caratteri da sostituire con numeri nel caso di generazione di codici complessi (esempio: se un codice attuale fosse 56/D e volessi calcolare il successivo (57/D), dovrei usare una maschera. La maschera in questo caso potrebbe essere ##/D. In questo modo so che i caratteri ## vanno sostituiti da numeri e il totale di caratteri sarà 2. Quindi il primo codice non sarebbe 1/D, ma 01/D)
*/
function get_next_code($str, $qty = 1, $mask = '')
{
// Se è il primo codice che sto inserendo sostituisco gli zeri al carattere jolly #
if ($str == '') {
$str = str_replace('#', '0', $mask);
}
// Se non uso una maschera, estraggo l'ultima parte numerica a destra della stringa e la incremento
if ($mask == '') {
preg_match("/(.*?)([\d]*$)/", $str, $m);
$first_part = $m[1];
$numeric_part = $m[2];
// Se non c'è una parte numerica ritorno stringa vuota
if ($numeric_part == '') {
return '';
} else {
$pad_length = strlen($numeric_part);
$second_part = str_pad(intval($numeric_part) + $qty, $pad_length, '0', STR_PAD_LEFT);
return $first_part.$second_part;
}
}
// Utilizzo della maschera
else {
// Calcolo prima parte (se c'è)
$pos1 = strpos($mask, '#');
$first_part = substr($str, 0, $pos1);
// Calcolo terza parte (se c'è)
$pos2 = strlen($str) - strpos(strrev($mask), '#');
$third_part = substr($str, $pos2, strlen($mask));
// Calcolo parte numerica
$numeric_part = substr($str, $pos1, $pos2);
$pad_length = intval(strlen($numeric_part));
$first_part_length = intval(strlen($first_part));
$third_part_length = intval(strlen($third_part));
$numeric_part = str_pad(intval($numeric_part) + intval($qty), $pad_length, '0', STR_PAD_LEFT);
// $numeric_part = str_pad( intval($numeric_part)+intval($qty), ( $pad_length - $third_part_length ), "0", STR_PAD_LEFT );
return $first_part.$numeric_part.$third_part;
}
}
/**
* Verifica che il nome del file non sia già usato nella cartella inserita, nel qual caso aggiungo un suffisso.
*
* @param unknown $filename
* @param unknown $dir
*
* @return string
*/
function unique_filename($filename, $dir)
{
$f = pathinfo($filename);
$suffix = 1;
while (file_exists($dir.'/'.$filename)) {
$filename = $f['filename'].'_'.$suffix.'.'.$f['extension'];
++$suffix;
}
return $filename;
}
/**
* Crea le thumbnails di $filename da dentro $dir e le salva in $dir.
*
* @param unknown $tmp
* @param unknown $filename
* @param unknown $dir
*
* @return bool
*/
function create_thumbnails($tmp, $filename, $dir)
{
$infos = pathinfo($filename);
$name = $infos['filename'];
$extension = strtolower($infos['extension']);
if ((is_dir($dir) && !is_writable($dir)) || (!is_dir($dir) && !mkdir($dir))) {
return false;
}
$driver = extension_loaded('gd') ? 'gd' : 'imagick';
Intervention\Image\ImageManagerStatic::configure(['driver' => $driver]);
$img = Intervention\Image\ImageManagerStatic::make($tmp);
$img->resize(600, null, function ($constraint) {
$constraint->aspectRatio();
});
$img->save(slashes($dir.'/'.$name.'.'.$extension));
$img->resize(250, null, function ($constraint) {
$constraint->aspectRatio();
});
$img->save(slashes($dir.'/'.$name.'_thumb250.'.$extension));
$img->resize(100, null, function ($constraint) {
$constraint->aspectRatio();
});
$img->save(slashes($dir.'/'.$name.'_thumb100.'.$extension));
return true;
}
/**
* Ottiene l'indirizzo IP del client.
*
* @return string|unknown
*/
function get_client_ip()
{
$ipaddress = '';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ipaddress = $_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ipaddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) {
$ipaddress = $_SERVER['HTTP_X_FORWARDED'];
} elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
$ipaddress = $_SERVER['HTTP_FORWARDED_FOR'];
} elseif (!empty($_SERVER['HTTP_FORWARDED'])) {
$ipaddress = $_SERVER['HTTP_FORWARDED'];
} elseif (!empty($_SERVER['REMOTE_ADDR'])) {
$ipaddress = $_SERVER['REMOTE_ADDR'];
} else {
$ipaddress = 'UNKNOWN';
}
return $ipaddress;
}
/**
* Traduce il template semplificato in componenti HTML.
*
* @since 2.3
*/
function translateTemplate()
{
global $id_module;
global $id_record;
global $id_plugin;
$template = ob_get_clean();
$template = \HTMLBuilder\HTMLBuilder::replace($template);
$template = str_replace('$id_module$', $id_module, $template);
$template = str_replace('$id_plugin$', $id_plugin, $template);
$template = str_replace('$id_record$', $id_record, $template);
// Annullo le notifiche (AJAX)
if (isAjaxRequest()) {
unset($_SESSION['infos']);
}
echo $template;
}
/**
* Sostituisce la prima occorenza di una determinata stringa.
*
* @param string $str_pattern
* @param string $str_replacement
* @param string $string
*
* @since 2.3
*
* @return string
*/
function str_replace_once($str_pattern, $str_replacement, $string)
{
if (strpos($string, $str_pattern) !== false) {
$occurrence = strpos($string, $str_pattern);
return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern));
}
return $string;
}
/**
* Restituisce il percorso del filesystem in modo indipendete dal sistema operativo.
*
* @param string $string Percorso da correggere
*
* @since 2.3
*
* @return string
*/
function slashes($string)
{
return str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $string);
}
/**
* Prepara il parametro inserito per l'inserimento in una query SQL.
* Attenzione: protezione di base contro SQL Injection.
*
* @param string $parameter
*
* @since 2.3
*
* @return string
*/
function prepare($parameter)
{
return p($parameter);
}
/**
* Prepara il parametro inserito per l'inserimento in una query SQL.
* Attenzione: protezione di base contro SQL Injection.
*
* @param string $parameter
*
* @since 2.3
*
* @return string
*/
function p($parameter)
{
return Database::getConnection()->prepare($parameter);
}
/**
* Restituisce la traduzione del messaggio inserito.
*
* @param string $string
* @param array $parameters
* @param string $domain
* @param string $locale
*
* @since 2.3
*
* @return string
*/
function tr($string, $parameters = [], $domain = null, $locale = null)
{
return Translator::translate($string, $parameters, $domain, $locale);
}
if (!function_exists('_')) {
function _($string, $parameters = [], $domain = null, $locale = null)
{
return tr($string, $parameters, $domain, $locale);
}
}
/**
* Legge il valore di un'impostazione dalla tabella zz_settings.
* Se descrizione = 1 e il tipo è 'query=' mi restituisce il valore del campo descrizione della query.
*
* @param string $name
* @param string $sezione
* @param string $descrizione
*
* @return mixed
*/
function get_var($nome, $sezione = null, $descrizione = false, $again = false)
{
return Settings::get($nome, $sezione, $descrizione, $again);
}
/**
* Restitusice il contentuo sanitarizzato dell'input dell'utente.
*
* @param string $param Nome del paramentro
* @param string $rule Regola di filtraggio
* @param string $method Posizione del paramentro (post o get)
*
* @since 2.3
*
* @return string
*/
function filter($param, $rule = 'text', $method = null)
{
return Filter::getValue($param, $method = null);
}
/**
* Restitusice il contentuo sanitarizzato dell'input dell'utente.
*
* @param string $param Nome del paramentro
* @param string $rule Regola di filtraggio
*
* @since 2.3
*
* @return string
*/
function post($param, $rule = 'text')
{
return Filter::getValue($param, 'post');
}
/**
* Restitusice il contentuo sanitarizzato dell'input dell'utente.
*
* @param string $param Nome del paramentro
* @param string $rule Regola di filtraggio
*
* @since 2.3
*
* @return string
*/
function get($param, $rule = 'text')
{
return Filter::getValue($param, 'get');
}
function isAjaxRequest()
{
return \Whoops\Util\Misc::isAjaxRequest() && filter('ajax') !== null;
}
function sum($first, $second = null, $decimals = null)
{
$first = (array) $first;
$second = (array) $second;
$array = array_merge($first, $second);
$result = 0;
if (!is_numeric($decimals)) {
$decimals = is_numeric($decimals) ? $decimals : Settings::get('Cifre decimali per importi');
}
$bcadd = function_exists('bcadd');
foreach ($array as $value) {
if ($bcadd) {
$result = bcadd($result, $value, $decimals);
} else {
$result = round($result, $decimals) + round($value, $decimals);
}
}
return $result;
}

94
lib/init.js Normal file
View File

@ -0,0 +1,94 @@
$(document).ready(function () {
$('[data-href]').not('.ask, .bound').click(function () {
$(this).addClass('bound');
launch_modal($(this).data('title'), $(this).data('href'), 1, $(this).data('target'));
});
$('.tip').not('.tooltipstered').tooltipster({
animation: 'grow',
contentAsHTML: true,
hideOnClick: true,
onlyOne: true,
maxWidth: 350,
touchDevices: true,
trigger: 'hover',
position: 'top'
});
autosize($('.autosize'));
$(".bootstrap-switch").bootstrapSwitch();
if ($('form').length) {
$('form').not('.no-check').parsley();
}
window.Parsley.on('field:success', function () {
this.$element.removeClass('parsley-success');
});
var icons = {
time: 'fa fa-clock-o',
date: 'fa fa-calendar',
up: 'fa fa-chevron-up',
down: 'fa fa-chevron-down',
previous: 'fa fa-chevron-left',
next: 'fa fa-chevron-right',
today: 'fa fa-street-view',
clear: 'fa fa-trash-o',
close: 'fa fa-times'
}
$('.timestamp-picker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
minDate: $this.attr('min-date') ? $this.attr('min-date') : false,
maxDate: $this.attr('max-date') ? $this.attr('max-date') : false,
});
});
$('.datepicker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
format: 'L',
minDate: $this.attr('min-date') ? $this.attr('min-date') : false,
maxDate: $this.attr('max-date') ? $this.attr('max-date') : false,
});
});
$('.timepicker').each(function () {
$this = $(this);
$this.datetimepicker({
locale: globals.locale,
icons: icons,
useCurrent: false,
format: 'LT',
stepping: 5,
minDate: $this.attr('min-date') ? $this.attr('min-date') : false,
maxDate: $this.attr('max-date') ? $this.attr('max-date') : false,
});
});
$("form").submit(function() {
if ($(this).parsley().validate()) {
$(this).submit(function() {
return false;
});
$(this).find('[type=submit]').prop("disabled", true).addClass("disabled");
return true;
}
return false;
});
start_superselect();
start_inputmask();
});

61
lib/permissions_check.php Normal file
View File

@ -0,0 +1,61 @@
<?php
trigger_error(_('Procedura deprecata!'), E_USER_DEPRECATED);
/*
Controllo permessi modulo su utente (se non è is_admin)
*/
if( $module_name == '' ){
$rs = $dbo->fetchArray("SELECT name FROM zz_modules WHERE id='".$html->form('id_module')."'");
$module_name = $rs[0]['name'];
}
//Il modulo "Info" è visibile da tutti
if( $module_name == 'Info' ){
$permessi[$module_name] = 'r';
}
else{
$rs = $dbo->fetchArray("SELECT idanagrafica FROM zz_users WHERE idutente='".$_SESSION['idutente']."'");
$user_idanagrafica = $rs[0]['idanagrafica'];
$query = "SELECT *, (SELECT idanagrafica FROM zz_users WHERE idutente='".$_SESSION['idutente']."') AS idanagrafica FROM zz_permissions WHERE idgruppo=(SELECT idgruppo FROM zz_users WHERE idutente='".$_SESSION['idutente']."') AND idmodule=(SELECT id FROM zz_modules WHERE name='".$module_name."')";
$rs = $dbo->fetchArray($query);
if( sizeof($rs)<=0 ){
//Ultimo tentativo: se non ci sono i permessi ma sono l'amministratore posso comunque leggere il modulo
if( $_SESSION['is_admin']==1 ){
$permessi[$module_name] = 'rw';
}
else{
echo "<div style='clear:both;'></div><br/><br/><br/><br/><br/><p>Non hai i permessi per accedere a questo modulo.</p>\n";
$permessi[$module_name] = '-';
exit;
}
}
else{
if( $rs[0]['permessi']=='-' ){
echo "<div style='clear:both;'></div><br/><br/><br/><br/><br/><p>Non hai i permessi per accedere a questo modulo.</p>\n";
$permessi[$module_name] = '-';
exit;
}
else if( $rs[0]['permessi']=='r' ){
$permessi[$module_name] = 'r';
}
else if( $rs[0]['permessi']=='rw' ){
$permessi[$module_name] = 'rw';
}
}
//Carico i filtri dei WHERE in base al modulo e all'utente loggato
$qp = "SELECT *, (SELECT idanagrafica FROM zz_users WHERE idutente='".$_SESSION['idutente']."') AS idanagrafica, (SELECT name FROM zz_modules WHERE id=idmodule) AS nome_modulo FROM zz_group_module WHERE idgruppo=(SELECT idgruppo FROM zz_users WHERE idutente='".$_SESSION['idutente']."')";
$rsp = $dbo->fetchArray($qp);
for( $i=0; $i<sizeof($rsp); $i++ ){
$additional_where[ $rsp[$i]['nome_modulo'] ] = $rsp[$i]['clause'];
}
}
?>

17
lib/user_check.php Normal file
View File

@ -0,0 +1,17 @@
<?php
trigger_error(_('Procedura deprecata!'), E_USER_DEPRECATED);
if ( isset ($_GET['op']) )
$op = $_GET['op'];
else
$op = '';
if( $op == 'logout' )
$_SESSION['idutente']='';
if( $_SESSION['idutente'] == '' ){
redirect($rootdir."/index.php","php");
exit;
}
?>

416
lib/util.php Normal file
View File

@ -0,0 +1,416 @@
<?php
if (!function_exists('parse_ini_string')) {
/**
* Simulazione di "parse_ini_string".
*
* @param unknown $ini
* @param string $process_sections
* @param unknown $scanner_mode
*/
function parse_ini_string($ini, $process_sections = false, $scanner_mode = null)
{
// Generate a temporary file.
$tempname = tempnam('/tmp', 'ini');
$fp = fopen($tempname, 'w');
fwrite($fp, $ini);
$ini = parse_ini_file($tempname, !empty($process_sections));
fclose($fp);
@unlink($tempname);
return $ini;
}
}
if (!function_exists('array_column')) {
/**
* Pluck an array of values from an array.
*
* @param $array - data
* @param $key - value you want to pluck from array
*
* @since 2.3
*
* @return plucked array only with key data
*/
function array_column($array, $key)
{
return array_map(function ($v) use ($key) {
return is_object($v) ? $v->$key : $v[$key];
}, $array);
}
}
if (!function_exists('starts_with')) {
/**
* Check if a string starts with the given string.
*
* @param string $string
* @param string $starts_with
*
* @return bool
*/
function starts_with($string, $starts_with)
{
return strpos($string, $starts_with) === 0;
}
}
if (!function_exists('ends_with')) {
/**
* Check if a string ends with the given string.
*
* @param string $string
* @param string $ends_with
*
* @return bool
*/
function ends_with($string, $ends_with)
{
return substr($string, -strlen($ends_with)) === $ends_with;
}
}
if (!function_exists('str_contains')) {
/**
* Check if a string contains the given string.
*
* @param string $string
* @param string $contains
*
* @return bool
*/
function str_contains($string, $contains)
{
return strpos($string, $contains) !== false;
}
}
if (!function_exists('random_string')) {
/**
* Generates a string of random characters.
*
* @throws LengthException If $length is bigger than the available
* character pool and $no_duplicate_chars is
* enabled
*
* @param int $length The length of the string to
* generate
* @param bool $human_friendly Whether or not to make the
* string human friendly by
* removing characters that can be
* confused with other characters (
* O and 0, l and 1, etc)
* @param bool $include_symbols Whether or not to include
* symbols in the string. Can not
* be enabled if $human_friendly is
* true
* @param bool $no_duplicate_chars whether or not to only use
* characters once in the string
*
* @return string
*/
function random_string($length = 16, $human_friendly = true, $include_symbols = false, $no_duplicate_chars = false)
{
$nice_chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefhjkmnprstuvwxyz23456789';
$all_an = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
$symbols = '!@#$%^&*()~_-=+{}[]|:;<>,.?/"\'\\`';
$string = '';
// Determine the pool of available characters based on the given parameters
if ($human_friendly) {
$pool = $nice_chars;
} else {
$pool = $all_an;
if ($include_symbols) {
$pool .= $symbols;
}
}
if (!$no_duplicate_chars) {
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}
// Don't allow duplicate letters to be disabled if the length is
// longer than the available characters
if ($no_duplicate_chars && strlen($pool) < $length) {
throw new \LengthException('$length exceeds the size of the pool and $no_duplicate_chars is enabled');
}
// Convert the pool of characters into an array of characters and
// shuffle the array
$pool = str_split($pool);
$poolLength = count($pool);
$rand = mt_rand(0, $poolLength - 1);
// Generate our string
for ($i = 0; $i < $length; ++$i) {
$string .= $pool[$rand];
// Remove the character from the array to avoid duplicates
array_splice($pool, $rand, 1);
// Generate a new number
if (($poolLength - 2 - $i) > 0) {
$rand = mt_rand(0, $poolLength - 2 - $i);
} else {
$rand = 0;
}
}
return $string;
}
}
if (!function_exists('secure_random_string')) {
/**
* Generate secure random string of given length
* If 'openssl_random_pseudo_bytes' is not available
* then generate random string using default function.
*
* Part of the Laravel Project <https://github.com/laravel/laravel>
*
* @param int $length length of string
*
* @return bool
*/
function secure_random_string($length = 32)
{
if (function_exists('openssl_random_pseudo_bytes')) {
$bytes = openssl_random_pseudo_bytes($length * 2);
if ($bytes === false) {
throw new \LengthException('$length is not accurate, unable to generate random string');
}
return substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $length);
}
return random_string($length);
}
}
if (!function_exists('force_download')) {
/**
* Transmit headers that force a browser to display the download file
* dialog. Cross browser compatible. Only fires if headers have not
* already been sent.
*
* @param string $filename The name of the filename to display to
* browsers
* @param string $content The content to output for the download.
* If you don't specify this, just the
* headers will be sent
*
* @since 2.3
*
* @return bool
*/
function force_download($filename, $content = false)
{
if (!headers_sent()) {
// Required for some browsers
if (ini_get('zlib.output_compression')) {
@ini_set('zlib.output_compression', 'Off');
}
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
// Required for certain browsers
header('Cache-Control: private', false);
header('Content-Disposition: attachment; filename="'.basename(str_replace('"', '', $filename)).'";');
header('Content-Type: application/force-download');
header('Content-Transfer-Encoding: binary');
if ($content) {
header('Content-Length: '.strlen($content));
}
ob_clean();
flush();
if ($content) {
echo $content;
}
return true;
}
return false;
}
}
if (!function_exists('safe_truncate')) {
/**
* Truncate a string to a specified length without cutting a word off.
*
* @param string $string The string to truncate
* @param int $length The length to truncate the string to
* @param string $append Text to append to the string IF it gets
* truncated, defaults to '...'
*
* @since 2.3
*
* @return string
*/
function safe_truncate($string, $length, $append = '...')
{
$ret = substr($string, 0, $length);
$last_space = strrpos($ret, ' ');
if ($last_space !== false && $string != $ret) {
$ret = substr($ret, 0, $last_space);
}
if ($ret != $string) {
$ret .= $append;
}
return $ret;
}
}
/**
* Scurisce un determinato colore.
*
* @param unknown $color
* @param number $dif
*
* @return string
*/
function color_darken($color, $dif = 20)
{
$color = str_replace('#', '', $color);
if (strlen($color) != 6) {
return '000000';
}
$rgb = '';
for ($x = 0; $x < 3; ++$x) {
$c = hexdec(substr($color, (2 * $x), 2)) - $dif;
$c = ($c < 0) ? 0 : dechex($c);
$rgb .= (strlen($c) < 2) ? '0'.$c : $c;
}
return '#'.$rgb;
}
/**
* Inverte il colore inserito.
*
* @see http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php
*
* @param string $start_colour
*
* @return string
*/
function color_inverse($start_colour)
{
$R1 = hexdec(substr($start_colour, 1, 2));
$G1 = hexdec(substr($start_colour, 3, 2));
$B1 = hexdec(substr($start_colour, 5, 2));
$R2 = 255;
$G2 = 255;
$B2 = 255;
$L1 = 0.2126 * pow($R1 / 255, 2.2) + 0.7152 * pow($G1 / 255, 2.2) + 0.0722 * pow($B1 / 255, 2.2);
$L2 = 0.2126 * pow($R2 / 255, 2.2) + 0.7152 * pow($G2 / 255, 2.2) + 0.0722 * pow($B2 / 255, 2.2);
if ($L1 > $L2) {
$lum = ($L1 + 0.05) / ($L2 + 0.05);
} else {
$lum = ($L2 + 0.05) / ($L1 + 0.05);
}
if ($lum >= 2.5) {
return '#fff';
} else {
return '#000';
}
}
/**
* Restituisce l'insieme delle query presente nel file specificato.
*
* @param string $filename Percorso per il file
* @param string $delimiter Delimitatore delle query
*
* @since 2.3
*
* @return array
*/
function readSQLFile($filename, $delimiter = ';')
{
$inString = false;
$escChar = false;
$query = '';
$stringChar = '';
$queryLine = [];
$queryBlock = file_get_contents($filename);
$sqlRows = explode("\n", $queryBlock);
$delimiterLen = strlen($delimiter);
do {
$sqlRow = current($sqlRows)."\n";
$sqlRowLen = strlen($sqlRow);
for ($i = 0; $i < $sqlRowLen; ++$i) {
if ((substr(ltrim($sqlRow), $i, 2) === '--') && !$inString) {
break;
}
$znak = substr($sqlRow, $i, 1);
if ($znak === '\'' || $znak === '"') {
if ($inString) {
if (!$escChar && $znak === $stringChar) {
$inString = false;
}
} else {
$stringChar = $znak;
$inString = true;
}
}
if ($znak === '\\' && substr($sqlRow, $i - 1, 2) !== '\\\\') {
$escChar = !$escChar;
} else {
$escChar = false;
}
if (substr($sqlRow, $i, $delimiterLen) === $delimiter) {
if (!$inString) {
$query = trim($query);
$delimiterMatch = [];
if (preg_match('/^DELIMITER[[:space:]]*([^[:space:]]+)$/i', $query, $delimiterMatch)) {
$delimiter = $delimiterMatch[1];
$delimiterLen = strlen($delimiter);
} else {
$queryLine[] = $query;
}
$query = '';
continue;
}
}
$query .= $znak;
}
} while (next($sqlRows) !== false);
return $queryLine;
}
/**
* Checks to see if the page is being served over SSL or not.
*
* @since 2.3
*
* @return bool
*/
function isHTTPS($trust_proxy_headers = false)
{
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off') {
// Check the standard HTTPS headers
return true;
} elseif ($trust_proxy_headers && isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
// Check proxy headers if allowed
return true;
} elseif (!empty($_SERVER['HTTP_FRONT_END_HTTPS']) && strtolower($_SERVER['HTTP_FRONT_END_HTTPS']) !== 'off') {
return true;
}
return false;
}

1
locale/.htaccess Normal file
View File

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

BIN
locale/it/it.mo Normal file

Binary file not shown.

5462
locale/it/it.po Normal file

File diff suppressed because it is too large Load Diff

87
log.php Normal file
View File

@ -0,0 +1,87 @@
<?php
include_once __DIR__.'/core.php';
$pageTitle = 'Log';
if (file_exists($docroot.'/include/custom/top.php')) {
include $docroot.'/include/custom/top.php';
} else {
include $docroot.'/include/top.php';
}
echo '
<div class="box">
<div class="box-header">
<h3 class="box-title"><i class="fa fa-book"></i> '._('Ultimi 100 accessi').'</h3>
</div>
<!-- /.box-header -->
<div class="box-body table-responsive no-padding">
<table class="datatables table table-hover">
<thead>
<tr>
<th>'._('Username').'</th>
<th>'._('Data').'</th>
<th>'._('Stato').'</th>
<th>'._('Indirizzo IP').'</th>
</tr>
</thead>
<tbody>';
/*
LEGGO DALLA TABELLA ZZ_LOG
*/
if (Auth::isAdmin()) {
$q = 'SELECT * FROM `zz_logs` ORDER BY `created_at` DESC LIMIT 0, 100';
} else {
$q = 'SELECT * FROM `zz_logs` WHERE `idutente`='.prepare($_SESSION['idutente']).' ORDER BY `created_at` DESC LIMIT 0, 100';
}
$rs = $dbo->fetchArray($q);
$n = sizeof($rs);
for ($i = 0; $i < $n; ++$i) {
$id = $rs[$i]['id'];
$idutente = $rs[$i]['idutente'];
$username = $rs[$i]['username'];
$ip = $rs[$i]['ip'];
$timestamp = Translator::timestampToLocale($rs[$i]['created_at']);
if ($rs[$i]['stato'] == 1) {
$type = 'success';
$stato = _('Login riuscito!');
} elseif ($rs[$i]['stato'] == 2) {
$type = 'warning';
$stato = _('Utente non abilitato!');
} elseif ($rs[$i]['stato'] == 3) {
$type = 'warning';
$stato = _("L'utente non ha nessun permesso impostato!");
} else {
$type = 'danger';
$stato = _('Autenticazione fallita!');
}
echo '
<tr class="'.$type.'">
<td>'.$username.'</td>
<td>'.$timestamp.'</td>
<td><span class="label label-'.$type.'">'.$stato.'</span></td>
<td>'.$ip.'</td>
</tr>';
}
echo '
</tbody>
</table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->';
if (file_exists($docroot.'/include/custom/bottom.php')) {
include $docroot.'/include/custom/bottom.php';
} else {
include $docroot.'/include/bottom.php';
}

1
logs/.htaccess Normal file
View File

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

View File

@ -0,0 +1,127 @@
<?php
include_once __DIR__.'/../../core.php';
$id = post('id');
switch (post('op')) {
case 'upload':
include $docroot.'/modules/aggiornamenti/upload_modules.php';
break;
case 'uninstall':
if (!empty($id)) {
// Leggo l'id del modulo
$rs = $dbo->fetchArray('SELECT id, name, directory FROM zz_modules WHERE id='.prepare($id).' AND `default`=0');
$modulo = $rs[0]['name'];
$module_dir = $rs[0]['directory'];
if (count($rs) == 1) {
// Elimino il modulo dal menu
$dbo->query('DELETE FROM zz_modules WHERE id='.prepare($id).' OR parent='.prepare($id));
$uninstall_script = $docroot.'/modules/'.$module_dir.'/update/uninstall.php';
if (file_exists($uninstall_script)) {
include_once $uninstall_script;
}
deltree($docroot.'/modules/'.$module_dir.'/');
$_SESSION['infos'][] = str_replace('_MODULE_', '"'.$modulo.'"', _('Modulo _MODULE_ disinstallato!'));
}
}
break;
case 'disable':
$dbo->query('UPDATE zz_modules SET enabled=0 WHERE id='.prepare($id));
$rs = $dbo->fetchArray('SELECT id, name FROM zz_modules WHERE id='.prepare($id));
$modulo = $rs[0]['name'];
$_SESSION['infos'][] = str_replace('_MODULE_', '"'.$modulo.'"', _('Modulo _MODULE_ disabilitato!'));
break;
case 'enable':
$dbo->query('UPDATE zz_modules SET enabled=1 WHERE id='.prepare($id));
$rs = $dbo->fetchArray('SELECT id, name FROM zz_modules WHERE id='.prepare($id));
$modulo = $rs[0]['name'];
$_SESSION['infos'][] = str_replace('_MODULE_', '"'.$modulo.'"', _('Modulo _MODULE_ abilitato!'));
break;
case 'disable_widget':
if (Modules::getPermission($module_name) == 'rw') {
$dbo->query('UPDATE zz_widgets SET enabled=0 WHERE id='.prepare($id));
$rs = $dbo->fetchArray('SELECT id, name FROM zz_widgets WHERE id='.prepare($id));
$widget = $rs[0]['name'];
$_SESSION['infos'][] = str_replace('_WIDGET_', '"'.$widget.'"', _('Widget _WIDGET_ disabilitato!'));
}
break;
case 'enable_widget':
if (Modules::getPermission($module_name) == 'rw') {
$dbo->query('UPDATE zz_widgets SET enabled=1 WHERE id='.prepare($id));
$rs = $dbo->fetchArray('SELECT id, name FROM zz_widgets WHERE id='.prepare($id));
$widget = $rs[0]['name'];
$_SESSION['infos'][] = str_replace('_WIDGET_', '"'.$widget.'"', _('Widget _WIDGET_ abilitato!'));
}
break;
case 'change_position_widget_top':
if (Modules::getPermission($module_name) == 'rw') {
$dbo->query("UPDATE zz_widgets SET location='controller_top' WHERE id=".prepare($id));
$rs = $dbo->fetchArray('SELECT id, name FROM zz_widgets WHERE id='.prepare($id));
$widget = $rs[0]['name'];
$_SESSION['infos'][] = str_replace('_WIDGET_', '"'.$widget.'"', _('Posizione del widget _WIDGET_ aggiornata!'));
}
break;
case 'change_position_widget_right':
if (Modules::getPermission($module_name) == 'rw') {
$dbo->query("UPDATE zz_widgets SET location='controller_right' WHERE id=".prepare($id));
$rs = $dbo->fetchArray('SELECT id, name FROM zz_widgets WHERE id='.prepare($id));
$widget = $rs[0]['name'];
$_SESSION['infos'][] = str_replace('_WIDGET_', '"'.$widget.'"', _('Posizione del widget _WIDGET_ aggiornata!'));
}
break;
// Ordinamento moduli di primo livello
case 'sortmodules':
$ids = explode(',', post('ids'));
for ($i = 0; $i < count($ids); ++$i) {
$dbo->query('UPDATE zz_modules SET `order`='.prepare($i).' WHERE id='.prepare($ids[$i]));
}
break;
case 'sortwidget':
$id_module = post('id_module');
$location = post('location');
$class = post('class');
$ids = explode(',', post('ids'));
for ($i = 0; $i < count($ids); ++$i) {
$id = explode('_', $ids[$i]);
$dbo->query('UPDATE zz_widgets SET `order`='.prepare($i).", class=".prepare($class).' WHERE id='.prepare($id[1]).' AND location='.prepare($location).' AND id_module='.prepare($id_module));
}
break;
case 'updatewidget':
$class = post('class');
$id_module = post('id_module');
$location = post('location');
$id = explode('_', post('id'));
$dbo->query('UPDATE zz_widgets SET location='.prepare($location).', class='.prepare($class).' WHERE id='.prepare($id[1]).' AND id_module='.prepare($id_module));
break;
}

View File

@ -0,0 +1,64 @@
<?php
switch ($resource) {
case 'updates':
$custom_where = !empty($updated) ? ' WHERE updated_at >= '.prepare($updated) : '';
$excluded = explode(',', Settings::get('Tabelle escluse per la sincronizzazione API automatica'));
// Attenzione: query specifica per MySQL
$datas = $dbo->fetchArray("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA=".prepare($db_name));
if (!empty($datas)) {
foreach ($datas as $data) {
if (!in_array($data['TABLE_NAME'], $excluded)) {
$results[$data['TABLE_NAME']] = $dbo->fetchArray('SELECT * FROM '.$data['TABLE_NAME'].$custom_where);
}
}
}
break;
// Attualmente vengono considerate solo le tabelle che eseguono l'eliminazione fisica della riga
case 'deleted':
$excluded = explode(',', Settings::get('Tabelle escluse per la sincronizzazione API automatica'));
// Attenzione: query specifica per MySQL
$datas = $dbo->fetchArray("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_SCHEMA=".prepare($db_name));
if (!empty($datas)) {
foreach ($datas as $data) {
$table_name = $data['TABLE_NAME'];
// Ottiene il nome della colonna di tipo AUTO_INCREMENT della tabella
$column = $dbo->fetchArray('SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '.prepare($table_name)." AND EXTRA LIKE '%AUTO_INCREMENT%' AND TABLE_SCHEMA = ".prepare($db_name))[0]['COLUMN_NAME'];
if (!in_array($table_name, $excluded) && !empty($column)) {
// Ottiene il valore successivo della colonna di tipo AUTO_INCREMENT
$auto_inc = $dbo->fetchArray('SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '.prepare($table_name).' AND TABLE_SCHEMA = '.prepare($db_name))[0]['AUTO_INCREMENT'];
// Ottiene i vuoti all'interno della sequenza AUTO_INCREMENT
$steps = $dbo->fetchArray('SELECT (t1.'.$column.' + 1) as start, (SELECT MIN(t3.'.$column.') - 1 FROM '.$table_name.' t3 WHERE t3.'.$column.' > t1.'.$column.') as end FROM '.$table_name.' t1 WHERE NOT EXISTS (SELECT t2.'.$column.' FROM '.$table_name.' t2 WHERE t2.'.$column.' = t1.'.$column.' + 1) ORDER BY start');
$total = [];
foreach ($steps as $step) {
if ($step['end'] == null) {
$step['end'] = $auto_inc - 1;
}
if ($step['end'] >= $step['start']) {
$total = array_merge($total, range($step['start'], $step['end']));
}
}
$results[$table_name] = $total;
}
}
}
break;
}
/*
return [
'updates',
'deleted',
];
*/

View File

@ -0,0 +1,292 @@
<?php
include_once __DIR__.'/../../core.php';
if (get_var('Attiva aggiornamenti')) {
$alerts = [];
if (!extension_loaded('zip')) {
$alerts[_('Estensione ZIP')] = _('da abilitare');
}
$upload_max_filesize = ini_get('upload_max_filesize');
$upload_max_filesize = str_replace(['k', 'M'], ['000', '000000'], $upload_max_filesize);
// Dimensione minima: 16MB
if ($upload_max_filesize < 16000000) {
$alerts['upload_max_filesize'] = '16MB';
}
$post_max_size = ini_get('post_max_size');
$post_max_size = str_replace(['k', 'M'], ['000', '000000'], $post_max_size);
// Dimensione minima: 16MB
if ($post_max_size < 16000000) {
$alerts['post_max_size'] = '16MB';
}
if (!empty($alerts)) {
echo '
<div class="alert alert-warning">
<p>'.str_replace('_CONFIG_', '<b>php.ini</b>', _('Devi modificare il seguenti parametri del file di configurazione PHP (_CONFIG_) per poter caricare gli aggiornamenti')).':<ul>';
foreach ($alerts as $key => $value) {
echo '
<li><b>'.$key.'</b> = '.$value.'</li>';
}
echo '
</ul></p>
</div>';
}
echo '
<div class="row">';
// Aggiornamento
echo '
<div class="col-xs-12 col-md-6">
<div class="box box-success">
<div class="box-header with-border">
<h3 class="box-title">'._('Carica un aggiornamento').'</h3>
</div>
<div class="box-body">
<form action="'.$rootdir.'/controller.php?id_module='.$id_module.'" method="post" enctype="multipart/form-data" class="form-inline" id="update">
<input type="hidden" name="op" value="upload">
<input type="hidden" name="type" value="update">
<label><input type="file" name="blob"></label>
<button type="button" class="btn btn-primary" onclick="if( confirm(\''._('Avviare la procedura?').'\') ){ $(\'#update\').submit(); }">
<i class="fa fa-upload"></i> '._('Carica').'...
</button>
</form>
</div>
</div>
</div>';
// Nuovo modulo
echo '
<div class="col-xs-12 col-md-6">
<div class="box box-info">
<div class="box-header with-border">
<h3 class="box-title">'._('Carica un nuovo modulo').'</h3>
</div>
<div class="box-body">
<form action="'.$rootdir.'/controller.php?id_module='.$id_module.'" method="post" enctype="multipart/form-data" class="form-inline" id="module">
<input type="hidden" name="op" value="upload">
<input type="hidden" name="type" value="new">
<label><input type="file" name="blob"></label>
<button type="button" class="btn btn-primary" onclick="if( confirm(\''._('Avviare la procedura?').'\') ){ $(\'#module\').submit(); }">
<i class="fa fa-upload"></i> '._('Carica').'...
</button>
</form>
</div>
</div>
</div>';
echo '
</div>';
}
// Elenco moduli installati
echo '
<div class="row">
<div class="col-md-12 col-lg-6">
<h3>'._('Moduli installati').'</h3>
<table class="table table-hover table-bordered table-condensed">
<tr>
<th>'._('Nome').'</th>
<th width="50">'._('Versione').'</th>
<th width="30">'._('Stato').'</th>
<th width="30">'._('Compatibilità').'</th>
<th width="20"></th>
</tr>';
$modules = $dbo->fetchArray('SELECT * FROM zz_modules WHERE parent IS NULL ORDER BY `order` ASC');
$osm_version = Update::getVersion();
foreach ($modules as $module) {
// STATO
if (!empty($module['enabled'])) {
$text = _('Abilitato');
$text .= ($module['id'] != $id_module) ? '. '._('Clicca per disabilitarlo').'...' : '';
$stato = '<i class="fa fa-cog fa-spin text-success" data-toggle="tooltip" title="'.$text.'"></i>';
} else {
$stato = '<i class="fa fa-cog text-warning" data-toggle="tooltip" title="'._('Non abilitato').'"></i>';
$class = 'warning';
}
// Possibilità di disabilitare o abilitare i moduli tranne quello degli aggiornamenti
if ($module['id'] != $id_module) {
if ($module['enabled']) {
$stato = "<a href='javascript:;' onclick=\"if( confirm('"._('Disabilitare questo modulo?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'disable', id: '".$module['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\">".$stato."</a>\n";
} else {
$stato = "<a href='javascript:;' onclick=\"if( confirm('"._('Abilitare questo modulo?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'enable', id: '".$module['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\"\">".$stato."</a>\n";
}
}
// COMPATIBILITA'
$compatibilities = explode(',', $module['compatibility']);
// Controllo per ogni versione se la regexp combacia per dire che è compatibile o meno
$comp = false;
foreach ($compatibilities as $compatibility) {
$comp = (preg_match('/'.$compatibility.'/', $osm_version)) ? true : $comp;
}
if ($comp) {
$compatible = '<i class="fa fa-check-circle text-success" data-toggle="tooltip" title="'._('Compatibile').'"></i>';
$class = 'success';
} else {
$compatible = '<i class="fa fa-warning text-danger" data-toggle="tooltip" title="'._('Non compabitile!')._('Questo modulo è compatibile solo con le versioni').': '.$module['compatibility'].'"></i>';
$class = 'danger';
}
echo '
<tr class="'.$class.'">
<td>'.$module['name'].'</td>
<td align="right">'.$module['version'].'</td>
<td align="center">'.$stato.'</td>
<td align="center">'.$compatible.'</td>';
echo '
<td>';
// Possibilità di disinstallare solo se il modulo non è tra quelli predefiniti
if (empty($module['default'])) {
echo "
<a href=\"javascript:;\" data-toggle='tooltip' title=\""._('Disinstalla')."...\" onclick=\"if( confirm('"._('Vuoi disinstallare questo modulo?').' '._('Tutti i dati salvati andranno persi!')."') ){ if( confirm('"._('Sei veramente sicuro?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'uninstall', id: '".$module['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); } }\"><i class='fa fa-trash-o'></i></a>";
}
echo '
</td>
</tr>';
// Prima di cambiare modulo verifico se ci sono sottomoduli
$submodules = $dbo->fetchArray('SELECT * FROM zz_modules WHERE parent='.prepare($module['id']).' ORDER BY `order` ASC');
foreach ($submodules as $sub) {
// STATO
if (!empty($sub['enabled'])) {
$text = _('Abilitato');
$text .= ($sub['id'] != $id_module) ? '. '._('Clicca per disabilitarlo').'...' : '';
$stato = '<i class="fa fa-cog fa-spin text-success" data-toggle="tooltip" title="'.$text.'"></i>';
} else {
$stato = '<i class="fa fa-cog text-warning" data-toggle="tooltip" title="'._('Non abilitato').'"></i>';
$class = 'warning';
}
// Possibilità di disabilitare o abilitare i moduli tranne quello degli aggiornamenti
if ($sub['id'] != $id_module) {
if ($sub['enabled']) {
$stato = "<a href='javascript:;' onclick=\"if( confirm('"._('Disabilitare questo modulo?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'disable', id: '".$sub['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\">".$stato."</a>\n";
} else {
$stato = "<a href='javascript:;' onclick=\"if( confirm('"._('Abilitare questo modulo?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'enable', id: '".$sub['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\"\">".$stato."</a>\n";
}
}
// COMPATIBILITA'
$compatibilities = explode(',', $sub['compatibility']);
// Controllo per ogni versione se la regexp combacia per dire che è compatibile o meno
$comp = false;
foreach ($compatibilities as $compatibility) {
$comp = (preg_match('/'.$compatibility.'/', $osm_version)) ? true : $comp;
}
if ($comp) {
$compatible = '<i class="fa fa-check-circle text-success" data-toggle="tooltip" title="'._('Compatibile').'"></i>';
$class = 'success';
} else {
$compatible = '<i class="fa fa-warning text-danger" data-toggle="tooltip" title="'._('Non compabitile!')._('Questo modulo è compatibile solo con le versioni').': '.$sub['compatibility'].'"></i>';
$class = 'danger';
}
echo '
<tr class="'.$class.'">
<td><small>&nbsp;&nbsp;- '.$sub['name'].'</small></td>
<td align="right">'.$sub['version'].'</td>
<td align="center">'.$stato.'</td>
<td align="center">'.$compatible.'</td>';
echo '
<td>';
// Possibilità di disinstallare solo se il modulo non è tra quelli predefiniti
if (empty($sub['default'])) {
echo "
<a href=\"javascript:;\" data-toggle='tooltip' title=\""._('Disinstalla')."...\" onclick=\"if( confirm('"._('Vuoi disinstallare questo modulo?').' '._('Tutti i dati salvati andranno persi!')."') ){ if( confirm('"._('Sei veramente sicuro?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'uninstall', id: '".$sub['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); } }\"><i class='fa fa-trash-o'></i></a>";
}
echo '
</td>
</tr>';
}
}
echo '
</table>
</div>';
// Widgets
echo '
<div class="col-md-12 col-lg-6">
<h3>'._('Widgets').'</h3>
<table class="table table-hover table-bordered table-condensed">
<tr>
<th>'._('Nome').'</th>
<th width="200">'._('Posizione').'</th>
<th width="30">'._('Stato').'</th>
<th width="30">'._('Posizione').'</th>
</tr>';
$widgets = $dbo->fetchArray('SELECT zz_widgets.id, zz_widgets.name AS widget_name, zz_modules.name AS module_name, zz_widgets.enabled AS enabled, location FROM zz_widgets INNER JOIN zz_modules ON zz_widgets.id_module=zz_modules.id ORDER BY `id_module` ASC, `zz_widgets`.`order` ASC');
$previous = '';
foreach ($widgets as $widget) {
// Nome modulo come titolo sezione
if ($widget['module_name'] != $previous) {
echo '
<tr>
<th colspan="4">'.$widget['module_name'].'</th>
</tr>';
}
// STATO
if ($widget['enabled']) {
$stato = '<i class="fa fa-cog fa-spin text-success" data-toggle="tooltip" title="'._('Abilitato').'. '._('Clicca per disabilitarlo').'..."></i>';
$class = 'success';
} else {
$stato = '<i class="fa fa-cog text-warning" data-toggle="tooltip" title="'._('Non abilitato').'"></i>';
$class = 'warning';
}
// Possibilità di disabilitare o abilitare i moduli tranne quello degli aggiornamenti
if ($widget['enabled']) {
$stato = "<a href='javascript:;' onclick=\"if( confirm('"._('Disabilitare questo widget?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'disable_widget', id: '".$widget['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\">".$stato."</a>\n";
} else {
$stato = "<a href='javascript:;' onclick=\"if( confirm('"._('Abilitare questo widget?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'enable_widget', id: '".$widget['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\"\">".$stato."</a>\n";
}
// POSIZIONE
if ($widget['location'] == 'controller_top') {
$location = _('Schermata modulo in alto');
} elseif ($widget['location'] == 'controller_right') {
$location = _('Schermata modulo a destra');
}
if ($widget['location'] == 'controller_right') {
$posizione = "<i class='fa fa-arrow-up text-warning' data-toggle='tooltip' title=\""._('Clicca per cambiare la posizione...')."\"></i>&nbsp;<i class='fa fa-arrow-right text-success' data-toggle='tooltip' title=\"\"></i>";
$posizione = "<a href='javascript:;' onclick=\"if( confirm('"._('Cambiare la posizione di questo widget?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'change_position_widget_top', id: '".$widget['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\"\">".$posizione."</a>\n";
} elseif ($widget['location'] == 'controller_top') {
$posizione = "<i class='fa fa-arrow-up text-success' data-toggle='tooltip' title=\"\"></i>&nbsp;<i class='fa fa-arrow-right text-warning' data-toggle='tooltip' title=\""._('Clicca per cambiare la posizione...').'"></i></i>';
$posizione = "<a href='javascript:;' onclick=\"if( confirm('"._('Cambiare la posizione di questo widget?')."') ){ $.post( '".$rootdir.'/editor.php?id_module='.$id_module."', { op: 'change_position_widget_right', id: '".$widget['id']."' }, function(response){ location.href='".$rootdir.'/controller.php?id_module='.$id_module."'; }); }\"\">".$posizione."</a>\n";
}
echo '
<tr class="'.$class.'">
<td>'.$widget['widget_name'].'</td>
<td align="right"><small>'.$location.'</small></td>
<td align="center">'.$stato.'</td>
<td align="center">'.$posizione.'</td>
</tr>';
$previous = $widget['module_name'];
}
echo '
</table>
</div>
</div>';

Some files were not shown because too many files have changed in this diff Show More