1KA_F2F/admin/survey/classes/class.SurveyCheck.php
MAY 79fc5b7b02 Prilagoditev za F2F, ostalo:
Dopolnjena opomba k nastavitvi kodne tabele za SQL.

De-1KAizacija:
    Ukinjenih nekaj info@1ka.si emailov, odstranjenih nekaj testnih petrovih nastavitev.

    Tudi lastna instalacija ima pravico do obvestil o grdem početju (phishing ipd).
    GDPR na 1KA pošljemo samo, če NI lastna instalacija.

Dopolnitve za fieldwork delo:
    - 1ka data izvoz
    - grupa glede na kodo in ne le kuki
        Tako lahko anketar nadaljuje z anketiranjem istega respondenta z vnosom
        iste kode. Prej se je grupa nastavljala le glede na kuki, kar je bilo neuporabno
        za fieldwork.
    - skok na isto, ne naslednjo stran na koncu
        PREJ: izpolnil si 1, 2, 3 in zaprl na 3. strani. 3. stran se ni shranila,
              ker nisi dal NEXT. NAslednjič ko si odprl isti link, ki nadaljeval
              na *naslednji* strani (4.)

              Tako si imel podatke za 1.; 2.; 4.,... stran.
        ZDAJ: izpolniš 1, 2, 3, zapreš. 3. stran se seveda ni shranila, ker si zaprl.
              Ko ponovno odpreš anketo, te vrže na ISTO ZADNJO stran - torej tretjo.

    - možen lokalni dump podatkov iz crontaba (zaščiteno s kodo)
    - settings.php ima dodano nastavitev kode za dump podatkov. Tega ni smiselno
      dati v nastavitve, ker se mora poklicati iz cron joba na SERVERJU, tako da
      mora itak štaufat admin, ki pripravljal laptop.

    Skripte za terensko združevanje so ločen modul in jih bi porinil v ločenem
    patchu.

    POZOR, preveriti je treba še BodyController (ali je bil ugly hack za narobe
    nastavljeno anketo, ali je bilo kaj drugega). Avtomatsko je namreč disablalo
    popravljanje ankete anketarjem!
2022-11-11 14:41:51 +01:00

352 lines
12 KiB
PHP

<?php
/*
* Preverjanje ankete - limiti velikosti, vabil, preverjanmje phishinga...
*
* Zaenkrat samo preverjamo in posljemo mail adminu
*
*/
class SurveyCheck {
var $anketa;
public function __construct($anketa){
if($anketa == null || $anketa <= 0)
return 'ID ankete ne obstaja!';
$this->anketa = $anketa;
}
// Preverimo stevilo vprasanj v anketi
public function checkLimitSpremenljivke(){
// Ce limit ni nastavljen ignoriramo
if(!AppSettings::getInstance()->getSetting('app_limits-question_count_limit'))
return true;
// Dobimo stevilo vprasanj v anketi
$stevilo_vprasanj = SurveyInfo::getInstance()->getSurveyQuestionCount();
// Obvestilo (mail adminu) posljemo pri dosezeni stevilki
if($stevilo_vprasanj == AppSettings::getInstance()->getSetting('app_limits-question_count_limit')){
$this->sendAlert($alert_type='limit_spremenljivke', $stevilo_vprasanj);
}
// Ce je v anketi ze vec vprasanj kot je limit
if($stevilo_vprasanj > AppSettings::getInstance()->getSetting('app_limits-question_count_limit')){
return true;
}
else{
return false;
}
}
// Preverimo stevilo poslanih vabil
public function checkLimitVabila(){
// Ce limit ni nastavljen ignoriramo
if(!AppSettings::getInstance()->getSetting('app_limits-invitation_count_limit'))
return true;
// Prestejemo poslana vabila
$sql = sisplet_query("SELECT count(id) AS stevilo_vabil
FROM srv_invitations_recipients
WHERE ank_id='".$this->anketa."' AND sent='1'
");
$row = mysqli_fetch_array($sql);
$stevilo_vabil = $row['stevilo_vabil'];
// Obvestilo (mail adminu) posljemo pri dosezeni stevilki
if($stevilo_vabil == AppSettings::getInstance()->getSetting('app_limits-invitation_count_limit')){
$this->sendAlert($alert_type='limit_vabila', $stevilo_vabil);
}
// Ce je poslanih ze vec vabil kot je limit
if($stevilo_vabil > AppSettings::getInstance()->getSetting('app_limits-invitation_count_limit')){
return true;
}
else{
return false;
}
}
// Preverimo stevilo responsov na anketo
public function checkLimitResponses(){
// Ce limit ni nastavljen ignoriramo
if(!AppSettings::getInstance()->getSetting('app_limits-response_count_limit'))
return true;
// Dobimo stevilo odgovorov na anketo
$stevilo_odgovorov = SurveyInfo::getInstance()->getSurveyAnswersCount();
$stevilo_odgovorov_limit = AppSettings::getInstance()->getSetting('app_limits-response_count_limit');
// Obvestilo (mail adminu) posljemo pri dosezeni stevilki
if($stevilo_odgovorov > 0 && $stevilo_odgovorov % $stevilo_odgovorov_limit === 0){
$this->sendAlert($alert_type='limit_responses', $stevilo_odgovorov);
// Deaktiviramo anketo, ce je aktivna ?
}
// Ce je na anketo ze vec responsov kot je limit
if($stevilo_odgovorov > AppSettings::getInstance()->getSetting('app_limits-response_count_limit')){
return true;
}
else{
return false;
}
}
// Preverimo ce je anketa potencialno phishing
public function checkPhishing(){
global $global_user_id;
// Dobimo stevilo vprasanj v anketi
$stevilo_vprasanj = SurveyInfo::getInstance()->getSurveyQuestionCount();
// Ce imamo v anketi 0 ali vec kot 5 vprasanj je vse ok
if($stevilo_vprasanj >= 5 || $stevilo_vprasanj == 0){
return false;
}
// Dobimo stevilo anket uporabnika
$sqlA = sisplet_query("SELECT count(id) AS count_surveys FROM srv_anketa WHERE insert_uid='".$global_user_id."'");
$rowA = mysqli_fetch_array($sqlA);
// Ce ima uporabnik ze vec anket je vse ok
if($rowA['count_surveys'] > 1){
return false;
}
// Prestejemo vprasanja po tipu
$sql = sisplet_query("SELECT count(s.id) AS count_questions
FROM srv_spremenljivka s, srv_grupa g
WHERE g.ank_id='".$this->anketa."' AND g.id=s.gru_id
AND (tip='21' OR tip='5')
");
$row = mysqli_fetch_array($sql);
// Ce imamo v anketi manj kot 5 vprasanj in so vsa tipa nagovor ali text je potencialen phishing
if($row['count_questions'] == $stevilo_vprasanj){
// Posljemo mail adminu
$this->sendAlert($alert_type='phishing');
return true;
}
else{
return false;
}
}
// Pri izpolnjevanju ankete preverimo stevilo klikov na minuto - ce jih je prevec, respondenta zavrnemo, drugace se lahko sql zafila in streznik ni vec odziven
public function checkClicksPerMinute(){
// Ce maximum na minuto ni nastavljen ignoriramo limit
if(!AppSettings::getInstance()->getSetting('app_limits-clicks_per_minute_limit'))
return true;
// Preverimo ce gre za izpolnjevanje ankete
if($_SERVER["SCRIPT_NAME"] != '/main/survey/index.php')
return true;
// Preverimo ce gre za prvi prihod na doloceno stran ankete in ne na prvo stran
if(isset($_GET['grupa']))
return true;
// Preverimo ce je id ankete ustrezno nastavljen
if(!isset($this->anketa) || $this->anketa <= 0)
return true;
$click_time = time();
$sql = sisplet_query("SELECT click_count, click_time FROM srv_clicks WHERE ank_id='".$this->anketa."'");
if (mysqli_num_rows($sql) > 0) {
list($click_count, $first_click_time) = mysqli_fetch_array($sql);
// Ce nismo znotraj minute vse resetiramo in pustimo naprej
if($click_time - $first_click_time > 60){
$sqlI = sisplet_query("UPDATE srv_clicks SET click_count='1', click_time='".$click_time."' WHERE ank_id='".$this->anketa."'");
return true;
}
// Click count je ok - pustimo naprej
if($click_count <= AppSettings::getInstance()->getSetting('app_limits-clicks_per_minute_limit')){
$sqlI = sisplet_query("UPDATE srv_clicks SET click_count=click_count+1 WHERE ank_id='".$this->anketa."'");
// Dosegli smo limit - posljemo mail adminu
if($click_count == AppSettings::getInstance()->getSetting('app_limits-clicks_per_minute_limit')){
// TODO - da se poslje samo 1x, drugace konstantno letijo maili:D
// Includamo vse da lahko posljemo mail
//include_once('../../vendor/autoload.php');
// Posljemo mail adminu
//$this->sendAlert($alert_type='limit_clicks', $click_count);
}
return true;
}
// Click count je previsok - ZAVRNEMO
else{
// Prikazemo error stran ki jo refreshamo na 5 sekund
$this->displayClicksPerMinuteError();
return false;
}
}
else{
$sqlI = sisplet_query("INSERT INTO srv_clicks (ank_id, click_count, click_time) VALUES ('".$this->anketa."', '1', '".$click_time."')");
}
return true;
}
// Posljemo obvestilo adminu o prebitem limitu, phishing anketi...
private function sendAlert($alert_type, $count=0){
global $site_url;
// Dobimo hash ankete
$anketa_hash = SurveyInfo::getInstance()->getSurveyColumn('hash');
switch($alert_type){
case 'limit_spremenljivke':
$title = 'Opozorilo - dosežena omejitev vprašanj';
$content = '<a href="'.$site_url.'admin/survey/index.php?anketa='.$this->anketa.'">Anketa '.$this->anketa.'</a> ima doseženo omejitev števila vprašanj ('.$count.')!';
break;
case 'limit_responses':
$title = 'Opozorilo - dosežena omejitev odgovorov';
$content = '<a href="'.$site_url.'admin/survey/index.php?anketa='.$this->anketa.'">Anketa '.$this->anketa.'</a> ima doseženo omejitev števila odgovorov ('.$count.')!';
break;
case 'limit_vabila':
$title = 'Opozorilo - dosežena omejitev vabil';
$content = '<a href="'.$site_url.'admin/survey/index.php?anketa='.$this->anketa.'">Anketa '.$this->anketa.'</a> ima doseženo omejitev poslanih vabil ('.$count.')!';
break;
case 'phishing':
$title = 'Opozorilo - potencialna phishing anketa';
$content = '<a href="'.$site_url.'admin/survey/index.php?anketa='.$this->anketa.'">Anketa '.$this->anketa.'</a> - potencialen phishing!';
break;
case 'limit_clicks':
$title = 'Opozorilo - dosežena omejitev klikov na minuto';
$content = '<a href="'.$site_url.'admin/survey/index.php?anketa='.$this->anketa.'">Anketa '.$this->anketa.'</a> ima doseženo omejitev klikov na minuto ('.$count.')!';
break;
}
// Dodamo se link do predogleda
$content .= '<br><br>Predogled ankete: <a href="'.$site_url.'a/'.$anketa_hash.'&preview=on">'.$site_url.'a/'.$anketa_hash.'&preview=on</a>';
if (!isLastnaInstalacija()) {
$prejemnik_obvestila = 'info@1ka.si';
}
elseif(AppSettings::getInstance()->getSetting('gdpr_admin_email') !== false){
$prejemnik_obvestila = AppSettings::getInstance()->getSetting('gdpr_admin_email');
}
else {
return;
}
try {
$MA = new MailAdapter($anketa=null, $type='admin');
$MA->addRecipients($prejemnik_obvestila);
$resultX = $MA->sendMail($content, $title);
}
catch (Exception $e){
}
// Zalogiramo opozorilo
$SL = new SurveyLog();
$SL->addMessage(SurveyLog::ERROR, $title.' - anketa '.$this->anketa);
$SL->write();
}
// Prikazemo stran z errorjem za presezeno stevilo klikov na minuto
private function displayClicksPerMinuteError(){
global $site_url;
$refresh_every = 5;
echo '<!DOCTYPE html>';
echo '<html>';
echo '<head>';
echo ' <title>Server Limit Reached</title>';
echo ' <meta http-equiv="refresh" content="'.$refresh_every.'" />';
echo ' <meta name="viewport" content="width=device-width, initial-scale=1.0" />';
echo ' <style>
body{
display: flex;
align-content: center;
height: 90vh;
flex-wrap: wrap;
align-content: center;
}
.main{
max-width: 1200px;
margin: 50px auto;
padding: 0 20px;
font-family: Montserrat, Arial, Sans-Serif !important;
color: #505050;
}
h1{
color: #1e88e5;
text-align: center;
margin: 30px 0;
}
hr{
margin: 50px 0;
border: 0;
border-top: 1px solid #ddeffd;
}
.loading{
margin: 50px 0;
text-align: center;
}
img{
width: 80px;
height: 80px;
}
</style>';
echo '</head>';
echo '<body><div class="main">';
echo ' <div class="loading"><img src="'.$site_url.'/public/img/icons/spinner.gif" /></div>';
echo ' <h1>Dosežena omejitev strežnika</h1>';
echo ' <h3>Prosimo, počakajte nekaj trenutkov. Trenutno je doseženo maksimalno število vnosov ankete na minuto.</h3>';
echo ' <hr>';
echo ' <h1>Server Limit Reached</h1>';
echo ' <h3>Please wait a few moments. Currently, the maximum number of survey entries per minute has been reached.</h3>';
echo '</div></body>';
echo '</html>';
die();
}
}
?>