From c822bd5fc8e03fa9763eca489d539402557de445 Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Jan 2024 20:58:24 +0100 Subject: [PATCH 1/8] Hardening input validation and code stability --- cron/tag.php | 2 +- www/actions/comment_gotolastunread.php | 11 +- www/actions/events.php | 60 +++-- www/actions/hz_turn.php | 60 ++--- www/actions/profil.php | 4 +- www/actions/stockbroker.php | 18 +- www/bugtracker.php | 2 +- www/chess_test.php | 10 +- www/controller/layout.controller.php | 4 +- www/gallery.php | 231 +++++++++++------ www/includes/activities.inc.php | 6 +- www/includes/comments.fnc.php | 2 +- www/includes/config.inc.php | 8 +- www/includes/errlog.inc.php | 63 +++-- www/includes/error.inc.php | 11 +- www/includes/gallery.readpic.php | 52 ++-- www/includes/geo2ip.inc.php | 6 +- www/includes/go_game.inc.php | 3 +- www/includes/googleapis.inc.php | 2 +- www/includes/mysql.inc.php | 70 +++--- www/includes/notifications.inc.php | 10 +- www/includes/setistats.inc.php | 330 ++++++++++++++----------- www/includes/stl.inc.php | 112 +++++---- www/includes/telegrambot.inc.php | 47 ++-- www/includes/util.inc.php | 26 +- www/kurse.xml | 43 ---- www/models/gallery.php | 3 +- www/peter.php | 12 +- www/profil.php | 183 ++++++++------ www/scripts/rezepte.php | 10 +- www/scripts/stockbroker.php | 20 +- www/seti_example.php | 6 +- www/templates/layout/sidebar.tpl | 4 +- www/wetten.php | 21 +- 34 files changed, 792 insertions(+), 660 deletions(-) delete mode 100644 www/kurse.xml diff --git a/cron/tag.php b/cron/tag.php index 4db270d..c302a1c 100644 --- a/cron/tag.php +++ b/cron/tag.php @@ -25,7 +25,7 @@ error_log(sprintf('[%s] [NOTICE] <%s> Try including files...', date('d.m.Y H:i:s',time()), __FILE__)); define('SITE_ROOT', $wwwroot); // Define own SITE_ROOT before loading general zConfigs - require_once( SITE_ROOT.'/includes/config.inc.php'); + (!require_once( SITE_ROOT.'/includes/config.inc.php')) ?? error_log(sprintf('[%s] [ERROR] <%s> Including %s failed', date('d.m.Y H:i:s',time()), __FILE__, SITE_ROOT.'/includes/config.inc.php')); include_once( INCLUDES_DIR.'addle.inc.php'); include_once( INCLUDES_DIR.'hz_game.inc.php'); include_once( INCLUDES_DIR.'peter.inc.php'); diff --git a/www/actions/comment_gotolastunread.php b/www/actions/comment_gotolastunread.php index ec44692..eb8c9da 100644 --- a/www/actions/comment_gotolastunread.php +++ b/www/actions/comment_gotolastunread.php @@ -1,10 +1,11 @@ id) > 0) { +if(Forum::getNumunreadposts($user->id) > 0) { header("Location: ".Forum::getUnreadLink()); - die(); + exit(); } else { - header("Location: ../index.php?".session_name()."=".session_id()); - die(); + header("Location: /index.php"); + exit(); } diff --git a/www/actions/events.php b/www/actions/events.php index f53571b..b61388e 100644 --- a/www/actions/events.php +++ b/www/actions/events.php @@ -8,11 +8,9 @@ /** * File includes * @include config.inc.php - * @include main.inc.php Includes the Main Zorg Configs and Methods * @include events.inc.php Includes the Event Class and Methods */ require_once __DIR__.'/../includes/config.inc.php'; -require_once INCLUDES_DIR.'/../includes/main.inc.php'; require_once INCLUDES_DIR.'events.inc.php'; /** Validate $_GET & $_POST variables */ @@ -25,28 +23,51 @@ if ( isset($_POST['id']) && is_numeric($_POST['id']) && $_POST['id'] >= 0) $eventId = $_POST['id']; if ( isset($_POST['name']) && !empty($_POST['name'])) $eventName = sanitize_userinput($_POST['name']); if ( !empty($_POST['location'])) $eventLocation = sanitize_userinput($_POST['location']); -if ( !empty($_POST['link'])) $eventLink = (filter_var($_POST['link'], FILTER_VALIDATE_URL)===false?(filter_var(SITE_PROTOCOL.$_POST['link'], FILTER_VALIDATE_URL)!==false?SITE_PROTOCOL.$_POST['link']:$error='Ungültiger Event-Link'):$_POST['link']); -if ( !empty($_POST['review_url'])) $eventReviewlink = (filter_var($_POST['review_url'], FILTER_VALIDATE_URL)===false?(filter_var(SITE_PROTOCOL.$_POST['review_url'], FILTER_VALIDATE_URL)!==false?SITE_PROTOCOL.$_POST['review_url']:$error='Ungültige Review-URL'):$_POST['review_url']); +if ( !empty($_POST['link'])) $eventLink = (filter_input(INPUT_POST, 'link', FILTER_VALIDATE_URL)===false?(filter_var(SITE_PROTOCOL.$_POST['link'], FILTER_VALIDATE_URL)!==false?SITE_PROTOCOL.$_POST['link']:$error='Ungültiger Event-Link'):$_POST['link']); +if ( !empty($_POST['review_url'])) $eventReviewlink = (filter_input(INPUT_POST, 'review_url', FILTER_VALIDATE_URL)===false?(filter_var(SITE_PROTOCOL.$_POST['review_url'], FILTER_VALIDATE_URL)!==false?SITE_PROTOCOL.$_POST['review_url']:$error='Ungültige Review-URL'):$_POST['review_url']); if ( !empty($_POST['description'])) $eventDescription = htmlspecialchars_decode($_POST['description'], ENT_COMPAT | ENT_SUBSTITUTE); if ( isset($_POST['gallery_id']) && is_numeric($_POST['gallery_id']) && $_POST['gallery_id'] >= 0) $eventGallery = $_POST['gallery_id']; if ( isset($_GET['join']) && is_numeric($_GET['join']) && $_GET['join'] >= 0) $eventJoinId = $_GET['join']; if ( isset($_GET['unjoin']) && is_numeric($_GET['unjoin']) && $_GET['unjoin'] >= 0) $eventUnjoinId = $_GET['unjoin']; - - +if ( isset($_POST['fromDate']) && !empty($_POST['fromDate']) && isset($_POST['fromTime']) && !empty($_POST['fromTime']) ) { + $fromDate = explode('-', $_POST['fromDate']); + $fromTime = explode(':', $_POST['fromTime']); +} +if (isset($_POST['toDate']) && !empty($_POST['toDate']) && isset($_POST['toTime']) && !empty($_POST['toTime']) ) { + $toDate = explode('-', $_POST['toDate']); + $toTime = explode(':', $_POST['toTime']); +} switch (true) { /** Validation Error */ case (!empty($error)): /** If $error break switch() instantly */ - zorgDebugger::me()->warn('Validation Error: %s%s', [$error]); + zorgDebugger::log()->warn('Validation Error: %s%s', [$error]); break; - /** Add new Event */ - case ((isset($_POST['action']) && $_POST['action'] === 'new')): - zorgDebugger::me()->debug('Adding new Event: %s', [$eventName]); - $startdate = sprintf('%s-%s-%s %s:00', $_POST['startYear'], $_POST['startMonth'], $_POST['startDay'], $_POST['startHour']); - $enddate = sprintf('%s-%s-%s %s:00', $_POST['endYear'], $_POST['endMonth'], $_POST['endDay'], $_POST['endHour']); + case (isset($_POST['action']) && $_POST['action'] === 'new'): + if (isset($fromDate) && isset($fromTime)) { + $startdate = timestamp(true, [ + 'year' => intval($fromDate[0]) + ,'month' => intval($fromDate[1]) + ,'day' => intval($fromDate[2]) + ,'hour' => intval($fromTime[0]) + ,'minute' => intval($fromTime[1]) + ]); + } + if (isset($toDate) && isset($toTime)) { + $enddate = timestamp(true, [ + 'year' => intval($toDate[0]) + ,'month' => intval($toDate[1]) + ,'day' => intval($toDate[2]) + ,'hour' => intval($toTime[0]) + ,'minute' => intval($toTime[1]) + ]); + } + /** Backwards-compatibility to old individual Date fields */ + if (empty($startdate)) $startdate = sprintf('%s-%s-%s %s:00', $_POST['startYear'], $_POST['startMonth'], $_POST['startDay'], $_POST['startHour']); + if (empty($enddate)) $enddate = sprintf('%s-%s-%s %s:00', $_POST['endYear'], $_POST['endMonth'], $_POST['endDay'], $_POST['endHour']); $values = [ 'name' => $eventName, 'location' => $eventLocation, @@ -59,6 +80,7 @@ 'reportedon_date' => timestamp(true), 'review_url' => $eventReviewlink ]; + zorgDebugger::log()->debug('Adding new Event: %s dateFrom %s to %s', [$eventName, $startdate, $enddate]); $idNewEvent = $db->insert('events', $values, __FILE__, __LINE__, 'INSERT INTO events'); /** Error */ @@ -77,8 +99,8 @@ /** Save updated Event details */ - case ((isset($_POST['action']) && $_POST['action'] === 'edit')): - zorgDebugger::me()->debug('Update existing Event: %d «%s»', [$eventId, $eventName]); + case (isset($_POST['action']) && $_POST['action'] === 'edit'): + zorgDebugger::log()->debug('Update existing Event: %d «%s»', [$eventId, $eventName]); $newStartdate = sprintf('%s-%s-%s %s:00', $_POST['startYear'], $_POST['startMonth'], $_POST['startDay'], $_POST['startHour']); $newEnddate = sprintf('%s-%s-%s %s:00', $_POST['endYear'], $_POST['endMonth'], $_POST['endDay'], $_POST['endHour']); @@ -103,7 +125,7 @@ /** Join User to Event */ case (isset($eventJoinId) && is_numeric($eventJoinId)): - zorgDebugger::me()->debug('User joins Event: %d', [$eventJoinId]); + zorgDebugger::log()->debug('User joins Event: %d', [$eventJoinId]); $redirect_url .= '&event_id='.$eventJoinId; $insertValues = ['user_id' => $user->id, 'event_id' => $eventJoinId]; @@ -118,7 +140,7 @@ /** Unjoin User from Event */ case (isset($eventUnjoinId) && is_numeric($eventUnjoinId)): - zorgDebugger::me()->debug('User unjoins Event: %d', [$eventUnjoinId]); + zorgDebugger::log()->debug('User unjoins Event: %d', [$eventUnjoinId]); $redirect_url .= '&event_id='.$eventUnjoinId; $sql = 'DELETE FROM events_to_user WHERE user_id=? AND event_id=?'; @@ -128,8 +150,8 @@ /** Post Event to Twitter */ - case ((isset($_POST['action']) && $_POST['action'] === 'tweet')): - zorgDebugger::me()->debug('Tweet Event: %s', [$redirect_url]); + case (isset($_POST['action']) && $_POST['action'] === 'tweet'): + zorgDebugger::log()->debug('Tweet Event: %s', [$redirect_url]); /** * Load Twitter Class & Grab the Twitter API Keys @@ -192,6 +214,6 @@ /** Redirect request */ $goToUrl = $redirect_url . ( !empty($error) ? '&error='.rawurlencode($error) : ''); -zorgDebugger::me()->debug('Redirecting to %s', [$goToUrl]); +zorgDebugger::log()->debug('Redirecting to %s', [$goToUrl]); header('Location: ' . $goToUrl ); exit; diff --git a/www/actions/hz_turn.php b/www/actions/hz_turn.php index d38d1dc..0927b5a 100644 --- a/www/actions/hz_turn.php +++ b/www/actions/hz_turn.php @@ -1,49 +1,39 @@ $_GET-Params: %s', __FILE__, __LINE__, print_r($_GET,true))); -$gameId = (isset($_GET['game']) && is_numeric($_GET['game']) && $_GET['game']>0 ? (int)strip_tags(filter_var(trim($_GET['game']), FILTER_SANITIZE_NUMBER_INT)) : null); -$ticketType = (isset($_GET['ticket']) && !is_numeric($_GET['ticket']) && !is_bool($_GET['ticket']) ? (string)strip_tags(filter_var(trim($_GET['ticket']), FILTER_SANITIZE_STRING)) : null); -$moveToStationNum = (isset($_GET['move']) && is_numeric($_GET['move']) && $_GET['move']>0 ? (int)strip_tags(filter_var(trim($_GET['move']), FILTER_SANITIZE_NUMBER_INT)) : null); -if (isset($_GET['do']) && !is_numeric($_GET['do']) && !is_bool($_GET['do'])) $doAction = (string)strip_tags(filter_var(trim($_GET['do']), FILTER_SANITIZE_STRING)); -if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Sanitized-Params (%s): $gameId => %d | $ticketType => %s | $stationNum => %d', __FILE__, __LINE__, (isset($doAction) ? $doAction : 'mobe'), $gameId, $ticketType, $moveToStationNum)); +zorgDebugger::log()->debug('$_GET-Params: %s', [print_r($_GET,true)]); +$gameId = filter_input(INPUT_GET, 'game', FILTER_SANITIZE_NUMBER_INT) ?? null; +$ticketType = filter_input(INPUT_GET, 'ticket', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null;; +$moveToStationNum = filter_input(INPUT_GET, 'move', FILTER_SANITIZE_NUMBER_INT) ?? null; +$doAction = filter_input(INPUT_GET, 'do', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; +zorgDebugger::log()->debug('do => %s: $gameId => %d | $ticketType => %s | $stationNum => %d', [(!empty($doAction) ? $doAction : $moveToStationNum), $gameId, $ticketType, $moveToStationNum]); /** hz actions */ if (!empty($gameId) && $user->is_loggedin()) { if (turn_allowed($gameId, $user->id)) { -// $e = $db->query('SELECT g.*, me.station mystation FROM hz_games g -// JOIN hz_players me ON me.game = g.id -// WHERE g.id='.$gameId.' AND me.user='.$user->id, -// __FILE__, __LINE__, 'SELECT mystation'); -// $game = $db->fetch($e); -// -// if (!$game) -// { - /** move */ - if (!empty($ticketType) && !empty($moveToStationNum)) - { - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> turn_move(): %d, %s, %s', __FILE__, __LINE__, $gameId, $ticketType, $moveToStationNum)); - turn_move($gameId, $ticketType, $moveToStationNum); - } + /** move */ + if (!empty($ticketType) && !empty($moveToStationNum)) + { + zorgDebugger::log()->debug('turn_move(): %d, %s, %s', [$gameId, $ticketType, $moveToStationNum]); + turn_move($gameId, $ticketType, $moveToStationNum); // TODO add 4th Param: $user->id + } - /** sentinel */ - elseif (isset($doAction) && $doAction === 'sentinel') - { - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> turn_sentinel(): %d', __FILE__, __LINE__, $gameId)); - turn_sentinel($gameId); - } + /** sentinel */ + elseif ($doAction === 'sentinel') + { + zorgDebugger::log()->debug('turn_sentinel(): %d', [$gameId]); + turn_sentinel($gameId); + } - /** stay */ - elseif (isset($doAction) && $doAction === 'stay') - { - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> turn_stay(): %d', __FILE__, __LINE__, $gameId)); - turn_stay($gameId, $user->id); - } - // } + /** stay */ + elseif ($doAction === 'stay') + { + zorgDebugger::log()->debug('turn_stay(): %d', [$gameId]); + turn_stay($gameId, $user->id); + } } header('Location: /tpl/103?game='.$gameId); exit; diff --git a/www/actions/profil.php b/www/actions/profil.php index 4bd1e90..462b701 100644 --- a/www/actions/profil.php +++ b/www/actions/profil.php @@ -8,8 +8,8 @@ * @include mysql.inc.php required * @include usersystem.inc.php required */ -require_once dirname(__FILE__).'/../includes/mysql.inc.php'; -require_once dirname(__FILE__).'/../includes/usersystem.inc.php'; +require_once __DIR__.'/../includes/mysql.inc.php'; +require_once __DIR__.'/../includes/usersystem.inc.php'; if($_GET['do'] == 'aussperren') { diff --git a/www/actions/stockbroker.php b/www/actions/stockbroker.php index a8020d7..1123e0b 100644 --- a/www/actions/stockbroker.php +++ b/www/actions/stockbroker.php @@ -5,10 +5,16 @@ require_once INCLUDES_DIR.'/includes/main.inc.php'; require_once INCLUDES_DIR.'/includes/stockbroker.inc.php'; +$doAction = filter_input(INPUT_POST, 'do', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['do'] +$symbol = filter_input(INPUT_POST, 'symbol', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['symbol'] +$compareOperator = filter_input(INPUT_POST, 'compare', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['comparison'] +$kursWert = filter_input(INPUT_POST, 'kurs', FILTER_VALIDATE_FLOAT) ?? null; // $_POST['kurs'] +$anzahlMenge = filter_input(INPUT_POST, 'menge', FILTER_VALIDATE_INT) ?? 0; // $_POST['comparison'] +$useMaximum = filter_input(INPUT_POST, 'max', FILTER_VALIDATE_BOOLEAN) ?? false; // $_POST['max'] // Warning ändern ------------------------------------------------------------- -if($_POST['do'] == 'changewarning') { - if(Stockbroker::changeWarning($user->id, $_POST['symbol'], $_POST['comparison'], $_POST['kurs'])) { +if($doAction === 'changewarning') { + if($stockbroker->changeWarning($user->id, $symbol, $compareOperator, $kursWert)) { header("Location: /?tpl=164"); } exit; @@ -16,8 +22,8 @@ // Kaufen --------------------------------------------------------------------- -if($_POST['action'] == 'buy') { - if(Stockbroker::buyStock($user->id, $_POST['symbol'], $_POST['menge'], $_POST['max'])) { +if($doAction === 'buy') { + if($stockbroker->buyStock($user->id, $symbol, $anzahlMenge, $useMaximum)) { header("Location: /?tpl=164"); } exit; @@ -25,8 +31,8 @@ // Verkaufen ------------------------------------------------------------------ -if($_POST['action'] == 'sell') { - if(Stockbroker::sellStock($user->id, $_POST['symbol'], $_POST['menge'], $_POST['max'])) { +if($doAction === 'sell') { + if($stockbroker->sellStock($user->id, $symbol, $anzahlMenge, $useMaximum)) { header("Location: /?tpl=164"); } exit; diff --git a/www/bugtracker.php b/www/bugtracker.php index 0e17d36..97c9daa 100644 --- a/www/bugtracker.php +++ b/www/bugtracker.php @@ -22,7 +22,7 @@ /** * Validate GET-Parameters */ -$bug_id = (isset($_GET['bug_id']) ? (int)$_GET['bug_id'] : null); +$bug_id = (isset($getBugId) ? $getBugId : (filter_input(INPUT_GET, 'bug_id', FILTER_VALIDATE_INT) ?? null)); $show = (isset($_GET['show']) && !empty($_GET['show']) ? (array)$_GET['show'] : []); $order = isset($_GET['order'])?$_GET['order']:''; diff --git a/www/chess_test.php b/www/chess_test.php index b6deb46..85553a4 100644 --- a/www/chess_test.php +++ b/www/chess_test.php @@ -4,11 +4,15 @@ * * @package zorg\Games\Chess */ + /** * File includes */ -require_once dirname(__FILE__).'/includes/main.inc.php'; -include_once INCLUDES_DIR.'usersystem.inc.php'; +require_once __DIR__.'/includes/config.inc.php'; include_once INCLUDES_DIR.'chess.inc.php'; -$board = Chess::get_board(1); +/** Validate parameters */ +$gameId = (isset($_GET['game']) ? filter_input(INPUT_GET, 'game', FILTER_VALIDATE_INT) : 1); // Default: Game #1 + +/** Load Chess Board */ +$board = $chess->get_board($gameId); diff --git a/www/controller/layout.controller.php b/www/controller/layout.controller.php index dd9bd73..f0ae351 100644 --- a/www/controller/layout.controller.php +++ b/www/controller/layout.controller.php @@ -63,7 +63,7 @@ class Layout extends \MVC\Controller public function __construct() { /** Position vom user bestimmen */ - \zorgDebugger::me()->debug('New \Utils\IP2Geolocation()'); + \zorgDebugger::log()->debug('New \Utils\IP2Geolocation()'); $userLocationData = new \Utils\User\IP2Geolocation(); /** Assign user location vars */ @@ -147,7 +147,7 @@ private function setCountryFlagicon($countryCode='CHE') */ private function setColors() { - \zorgDebugger::me()->debug('Color Layout: %s', [$this->layouttype]); + \zorgDebugger::log()->debug('Color Layout: %s', [$this->layouttype]); /** Background colors */ if (!defined('BACKGROUNDCOLOR')) define('BACKGROUNDCOLOR', ($this->layouttype === 'day' ? '#F2F2F2' : '#141414')); diff --git a/www/gallery.php b/www/gallery.php index a46f015..2c2f98f 100644 --- a/www/gallery.php +++ b/www/gallery.php @@ -31,15 +31,15 @@ $model = new MVC\Gallery(); /** Pic-ID zu Album-ID auflösen */ -$getAlbId = isset( $_GET['albID'] ) ? (int) $_GET['albID'] : null; -$getPicId = isset( $_GET['picID'] ) ? (int) $_GET['picID'] : null; +$getAlbId = filter_input(INPUT_GET, 'albID', FILTER_VALIDATE_INT) ?? null; +$getPicId = filter_input(INPUT_GET, 'picID', FILTER_VALIDATE_INT) ?? null; $album_id = $model->setAlbumId($getAlbId, $getPicId); /** * [Bug #708] Gallery nur für eingeloggte User anzeigen. Ausnahme: APOD Gallery * @link https://zorg.ch/bugtracker.php?bug_id=708 */ -if (!$user->is_loggedin() && (int)$album_id !== APOD_GALLERY_ID) +if ($album_id !== APOD_GALLERY_ID && !$user->is_loggedin()) { $model->showOverview($smarty); $smarty->assign('error', ['type' => 'warn', 'title' => t('error-not-logged-in', 'gallery', [ SITE_URL ]), 'dismissable' => 'false']); @@ -51,7 +51,7 @@ * User & Vereinsmitglieder-Check: nur Vereinsmitglieder dürfen Pics sehen (Ausnahme: APOD Gallery & Pics) * @link https://github.com/zorgch/zorg-verein-docs/blob/master/GV/GV%202018/2018-12-23%20zorg%20GV%202018%20Protokoll.md */ -elseif ((int)$album_id !== APOD_GALLERY_ID && (empty($user->vereinsmitglied) || $user->vereinsmitglied === '0')) +elseif ($album_id !== APOD_GALLERY_ID && empty($user->vereinsmitglied)) { $model->showOverview($smarty); $smarty->assign('error', ['type' => 'warn', 'title' => t('error-no-member', 'gallery'), 'dismissable' => 'false']); @@ -61,103 +61,180 @@ /** Gallery / Pics anzeigen */ else { - if (!empty($_GET['do'])) + /** Sanitize User Inputs */ + $doAction = filter_input(INPUT_GET, 'do', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['do'] + $show = filter_input(INPUT_GET, 'show', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['show'] + $showPage = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT) ?? 0; // $_GET['page'] Default page: 0 + + /** User muss mindestens eingeloggt sein, um DO Actions zu machen */ + if (!empty($doAction) && $user->is_loggedin()) { - $doAction = (string)$_GET['do']; - /** Das Benoten (und mypic markieren) können nebst Schönen auch die registrierten User, deshalb müssen wirs vorziehen... */ - if ($user->is_loggedin() && ($doAction === 'benoten' || $doAction === 'mypic') && isset($_POST['picID']) && !empty($_POST['picID']) && $_POST['picID'] > 0) + switch ($doAction) { - switch ($doAction) - { - case 'benoten': - if (isset($_POST['score']) && !empty($_POST['score']) && $_POST['score'] > 0) { - doBenoten($_POST['picID'], $_POST['score']); - } - break; + case 'benoten': + $picIDfromPOST = filter_input(INPUT_POST, 'picID', FILTER_VALIDATE_INT) ?? null; // $_POST['picID'] + $benotenScore = filter_input(INPUT_POST, 'score', FILTER_VALIDATE_INT) ?? null; // $_POST['score'] + if ($user->typ >= USER_USER && $benotenScore > 0) { // Dürfen alle eingeloggten + doBenoten($picIDfromPOST, $benotenScore); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; - case 'mypic': - // Ein übergibt die X & Y Positionen via "inputName_x" & "inputName_y" - if (isset($_POST['mypic_x']) && isset($_POST['mypic_y']) && $_POST['mypic_x'] > 0 && $_POST['mypic_y'] > 0) { - doMyPic($_POST['picID'], $_POST['mypic_x'], $_POST['mypic_y']); + case 'mypic': + if ($user->typ >= USER_USER) { // Dürfen alle eingeloggten + $picIDfromPOST = filter_input(INPUT_POST, 'picID', FILTER_VALIDATE_INT) ?? null; // $_POST['picID'] + + /** Ein übergibt die X & Y Positionen via "inputName_x" & "inputName_y" */ + $mypic_xcoord = filter_input(INPUT_POST, 'mypic_x', FILTER_VALIDATE_INT) ?? null; // $_POST['mypic_x'] + $mypic_ycoord = filter_input(INPUT_POST, 'mypic_y', FILTER_VALIDATE_INT) ?? null; // $_POST['mypic_y'] + if ($mypic_xcoord > 0 && $mypic_ycoord > 0) { + doMyPic($picIDfromPOST, $mypic_xcoord, $mypic_ycoord); } - break; - } - } elseif (!$user->is_loggedin() && !empty($doAction)) { - $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); - } + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; - /** Ab hier kommt nur noch Zeugs dass Member & Schöne machen dürfen */ - if ($user->typ >= USER_MEMBER && (!empty($doAction) && $doAction != 'benoten' && $doAction != 'mypic')) - { - switch ($doAction) - { - case 'editAlbum': - $res = doEditAlbum($album_id, $_POST['frm']); + case 'editAlbum': + if ($user->typ >= USER_MEMBER) { // Dürfen nur Member+Schöne + $frm = filter_input(INPUT_POST, 'frm', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY); + $res = doEditAlbum($album_id, $frm); if (!$album_id) $album_id = $res['id']; - break; - // case 'editAlbumFromEvent': NOT IMPLEMENTED - // $res = doEditAlbumFromEvent($album_id, $_POST['event']); - // if (!$album_id) $album_id = $res['id']; - // break; - case 'delAlbum': + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + case 'zensur': + if ($user->typ >= USER_MEMBER && $getPicId > 0) { // Dürfen nur Member+Schöne + doZensur($getPicId); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + + case 'upload': + $frm = filter_input(INPUT_POST, 'frm', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY); + if ($user->typ >= USER_MEMBER & !empty($frm)) { // Dürfen nur Member+Schöne + $res = doUpload($album_id, $frm); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + + case 'mkUploadDir': + $frm = filter_input(INPUT_POST, 'frm', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY); + if ($user->typ >= USER_MEMBER && !empty($frm)) { // Dürfen nur Member+Schöne + $res = doMkUploadDir($frm); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + case 'editFotoTitle': + $frm = filter_input(INPUT_POST, 'frm', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY); + if ($user->typ >= USER_MEMBER && !empty($frm)) { // Dürfen nur Member+Schöne + $res = doEditFotoTitle($getPicId, $frm); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + case 'doRotatePic': + $rotateLeftOrRight = filter_input(INPUT_POST, 'rotatedir', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['rotatedir'] + if ($user->typ >= USER_MEMBER && !empty($rotateLeftOrRight)) { // Dürfen nur Member+Schöne + $res = doRotatePic($getPicId, $rotateLeftOrRight); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + case 'delAlbum': + if ($user->typ >= USER_SPECIAL) { // Dürfen nur Schöne+Admins $res = doDelAlbum($album_id, $_POST['del']); $_GET['show'] = $res['show']; - break; - case 'zensur': - doZensur($getPicId); - break; - case 'delPic': - $res = doDelPic($_POST['picID']); - break; - case 'upload': - $res = doUpload($album_id, $_POST['frm']); - break; - case 'delUploadDir': - $res = doDelUploadDir($_POST['frm']['folder']); - break; - case 'mkUploadDir': - $res = doMkUploadDir($_POST['frm']); - break; - case 'editFotoTitle': - $res = doEditFotoTitle($getPicId, $_POST['frm']); - break; - case 'doRotatePic': - $res = doRotatePic($getPicId, $_POST['rotatedir']); - break; - /*case 'markieren': - doMark($getPicId); - break;*/ - } - } elseif ($user->typ < USER_MEMBER && !empty($doAction)) { - $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); - } + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + case 'delPic': + $deleteThisPicID = filter_input(INPUT_POST, 'del', FILTER_VALIDATE_INT) ?? null; // $_POST['del'] + if ($user->typ >= USER_SPECIAL && $deleteThisPicID > 0) { // Dürfen nur Schöne+Admins + $res = doDelPic($deleteThisPicID); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; + + case 'delUploadDir': + $frm = filter_input(INPUT_POST, 'frm', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY); + if ($user->typ >= USER_SPECIAL && !empty($frm['folder'])) { // Dürfen nur Schöne+Admins + $res = doDelUploadDir($frm['folder']); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$doAction])]); + } + break; - unset($_GET['do']); - $doAction = null; + // case 'markieren': DISABLED + // doMark($getPicId); + // break; + + // case 'editAlbumFromEvent': NOT IMPLEMENTED + // $res = doEditAlbumFromEvent($album_id, $_POST['event']); + // if (!$album_id) $album_id = $res['id']; + // break; + } } else { $res = array( 'state' => '', 'error' => '' ); } - $show = (isset($_GET['show']) ? $_GET['show'] : null); - $showPage = (isset($_GET['page']) && is_numeric($_GET['page']) ? (int)$_GET['page'] : 0); // Default page: 0 + unset($_GET['do']); + $doAction = null; + switch ($show) { case 'editAlbum': $model->showAlbumedit($smarty, $album_id); + if ($user->typ >= USER_MEMBER && !empty($rotateLeftOrRight)) { // Dürfen nur Member+Schöne + editAlbum($album_id, $doAction, (isset($res['state']) ? $res['state'] : ''), (isset($res['error']) ? $res['error'] : ''), (isset($res['frm']) ? $res['frm'] : '')); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$show])]); + } $smarty->display('file:layout/head.tpl'); - editAlbum($album_id, $doAction, (isset($res['state']) ? $res['state'] : ''), (isset($res['error']) ? $res['error'] : ''), (isset($res['frm']) ? $res['frm'] : '')); break; + case 'editAlbumV2': - header('Location: /gallery_maker.php'.($getAlbId > 0 ? '?album_id='.$getAlbId : '')); + if ($user->typ >= USER_USER && !empty($user->vereinsmitglied) || $user->typ >= USER_SPECIAL) { // Dürfen nur Vereinsmitglieder, Schöne+Admins + header('Location: /gallery_maker.php'.($getAlbId > 0 ? '?album_id='.$getAlbId : '')); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$show])]); + } exit; + case 'albumThumbs': - $model->showAlbum($smarty, $album_id); - albumThumbs($album_id, $showPage); + if ($album_id === APOD_GALLERY_ID || + ($user->typ >= USER_USER && !empty($user->vereinsmitglied))) { // Dürfen nur eingeloggte + Vereinsmitglieder + $model->showAlbum($smarty, $album_id); + albumThumbs($album_id, $showPage); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$show])]); + } break; + case 'pic': - $model->showPic($smarty, $user, $getPicId, $album_id); - $smarty->display('file:layout/head.tpl'); - pic($getPicId); + if ($album_id === APOD_GALLERY_ID || + ($user->typ >= USER_USER && !empty($user->vereinsmitglied))) { // Dürfen nur eingeloggte + Vereinsmitglieder + $model->showPic($smarty, $user, $getPicId, $album_id); + $smarty->display('file:layout/head.tpl'); + pic($getPicId); + } else { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('permissions-insufficient', 'gallery', [$show])]); + } break; + default: $model->showOverview($smarty); galleryOverview($res['state'], $res['error']); diff --git a/www/includes/activities.inc.php b/www/includes/activities.inc.php index 6e3559c..98c950e 100644 --- a/www/includes/activities.inc.php +++ b/www/includes/activities.inc.php @@ -147,7 +147,7 @@ static public function addActivity ($fromUser, $forUser, $activity, $activityAre /** Telegram Notification auslösen */ return self::notify($fromUser, $activity, $activityArea); } else { - zorgDebugger::me()->debug('SQL INSERT result: %s', [strval($result)]); + zorgDebugger::log()->debug('SQL INSERT result: %s', [strval($result)]); return false; } } else { @@ -504,9 +504,9 @@ static public function notify ($fromUser, $activityText, $activityArea=NULL) } /** For all other Activites */ else { - zorgDebugger::me()->debug('Attempting to send Telegram Notification'); + zorgDebugger::log()->debug('Attempting to send Telegram Notification'); $success = $telegram->send->message('group', t('telegram-notification', 'activity', [ $user->id2user($fromUser, TRUE), $activityText ]), ['disable_notification' => 'true']); - zorgDebugger::me()->debug('Telegram Notification %s', [($success !== false ? 'SENT!' : 'NOT SENT')], ($success !== false ? 'DEBUG' : 'ERROR')); + zorgDebugger::log()->debug('Telegram Notification %s', [($success !== false ? 'SENT!' : 'NOT SENT')], ($success !== false ? 'DEBUG' : 'ERROR')); return $success; } return false; diff --git a/www/includes/comments.fnc.php b/www/includes/comments.fnc.php index ef7bd63..5d5b5fa 100644 --- a/www/includes/comments.fnc.php +++ b/www/includes/comments.fnc.php @@ -9,7 +9,7 @@ * @include forum.inc.php required * @include usersystem.inc.php required */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; require_once INCLUDES_DIR.'smarty.inc.php'; require_once INCLUDES_DIR.'forum.inc.php'; require_once INCLUDES_DIR.'usersystem.inc.php'; diff --git a/www/includes/config.inc.php b/www/includes/config.inc.php index 9f58535..e4af839 100644 --- a/www/includes/config.inc.php +++ b/www/includes/config.inc.php @@ -347,18 +347,18 @@ * @const ERRORLOG_FILETYPE sets the file extension used for the error log file * @const ERRORLOG_DIR sets the directory for logging the custom user_errors * @const ERRORLOG_FILEPATH sets the directory & file path for logging the custom user_errors to - * @const ERRORLOG_LEVELS sets the verbosity of logging errors, warnings, and notices caused by the application + * @const ERRORLOG_LEVEL sets the verbosity of logging errors, warnings, and notices caused by the application. See: https://stackoverflow.com/q/3758418 * @const ERRORLOG_DEBUG_SCOPE (Optional) sets a focused scope for DEBUG log entries * @include errlog.inc.php Errorlogging Class: Load the zorg Error and Debug Handling */ if (!defined('ERRORLOG_FILETYPE')) define('ERRORLOG_FILETYPE', (isset($_ENV['ERRORLOG_FILETYPE']) ? $_ENV['ERRORLOG_FILETYPE'] : '.log')); if (!defined('ERRORLOG_DIR')) define('ERRORLOG_DIR', (isset($_ENV['ERRORLOG_DIR']) ? $_ENV['ERRORLOG_DIR'] : null)); if (!defined('ERRORLOG_FILE')) define('ERRORLOG_FILE', ERRORLOG_DIR.date('Y-m-d').ERRORLOG_FILETYPE); -if (!defined('ERRORLOG_LEVELS')) define('ERRORLOG_LEVELS', (isset($_ENV['ERROR_REPORTING_LEVELS']) ? $_ENV['ERROR_REPORTING_LEVELS'] : E_ERROR)); +if (!defined('ERRORLOG_LEVEL')) define('ERRORLOG_LEVEL', (isset($_ENV['ERROR_REPORTING_LEVELS']) && is_numeric($_ENV['ERROR_REPORTING_LEVELS']) ? $_ENV['ERROR_REPORTING_LEVELS'] : E_ERROR)); if (!defined('ERRORLOG_DEBUG_SCOPE')) { - define('ERRORLOG_DEBUG_SCOPE', isset($_ENV['DEBUG_SCOPE']) ? explode(',', $_ENV['DEBUG_SCOPE']) : []); + define('ERRORLOG_DEBUG_SCOPE', isset($_ENV['DEBUG_SCOPE']) && !empty($_ENV['DEBUG_SCOPE']) ? explode(',', $_ENV['DEBUG_SCOPE']) : []); } -error_reporting(ERRORLOG_LEVELS); +error_reporting(ERRORLOG_LEVEL); require_once INCLUDES_DIR.'errlog.inc.php'; //set_error_handler('zorgErrorHandler'); diff --git a/www/includes/errlog.inc.php b/www/includes/errlog.inc.php index 1b6f9e9..582b059 100644 --- a/www/includes/errlog.inc.php +++ b/www/includes/errlog.inc.php @@ -71,8 +71,8 @@ function zorgErrorHandler ($errno, $errstr, $errfile, $errline) * currently are being worked on (and not distract with tons of * other messages in the log). * - * @example zorgDebugger::me()->debug('Required SQL-Query update: <%s> in %s:%d', [$funktion, $file, $line], 'DEPRECATED'); - * @example zorgDebugger::me()->error('The provided ID "%d" is invalid!', [$tplID]); + * @example zorgDebugger::log()->debug('Required SQL-Query update: <%s> in %s:%d', [$funktion, $file, $line], 'DEPRECATED'); + * @example zorgDebugger::log()->error('The provided ID "%d" is invalid!', [$tplID]); * * @version 1.0 * @since 1.0 `26.12.2024` `IneX` Class added @@ -80,10 +80,11 @@ function zorgErrorHandler ($errno, $errstr, $errfile, $errline) class zorgDebugger { /** - * @var bool Indicates if the current environment is a development environment. + * @var bool $isDevelopmentEnvironment Indicates if the current environment is a development environment. + * @var object $instance Stores a Singleton instance of this Class */ + public $isDevelopmentEnvironment; private static $instance = null; - private $isDevelopmentEnvironment; /** * Constructor for Errorlog. @@ -100,12 +101,12 @@ public function __construct() /** * Gets a Singleton instance of the zorgDebugger class. * - * This allows to call zorgDebugger::me()->... WITHOUT instantiating the Class manually, + * This allows to call zorgDebugger::log()->... WITHOUT instantiating the Class manually, * and WITHOUT including it or using something like "global $errlog;". * * @return zorgDebugger The singleton instance of the Errorlog class. */ - public static function me(): zorgDebugger + public static function log(): zorgDebugger { if (self::$instance === null) { self::$instance = new zorgDebugger(); @@ -129,11 +130,11 @@ public function debug($message, $params = [], $customLoglevel='DEBUG') if ($this->isDevelopmentEnvironment) { $origin = $this->getOrigin(); - if (is_null(ERRORLOG_DEBUG_SCOPE) || - in_array($origin['function'], ERRORLOG_DEBUG_SCOPE) || - in_array(basename($origin['file']), ERRORLOG_DEBUG_SCOPE)) + if (empty(ERRORLOG_DEBUG_SCOPE) || + (in_array($origin['function'], ERRORLOG_DEBUG_SCOPE) || + in_array(basename($origin['file']), ERRORLOG_DEBUG_SCOPE))) { - $this->log($customLoglevel, $message, $params, $origin); + $this->write($customLoglevel, $message, $params, $origin); } } } @@ -146,7 +147,7 @@ public function debug($message, $params = [], $customLoglevel='DEBUG') */ public function info($message, $params = []) { - $this->log('INFO', $message, $params, $this->getOrigin()); + $this->write('INFO', $message, $params, $this->getOrigin()); } /** @@ -157,7 +158,7 @@ public function info($message, $params = []) */ public function error($message, $params = []) { - $this->log('ERROR', $message, $params, $this->getOrigin()); + $this->write('ERROR', $message, $params, $this->getOrigin()); } /** @@ -168,7 +169,7 @@ public function error($message, $params = []) */ public function warn($message, $params = []) { - $this->log('WARNING', $message, $params, $this->getOrigin()); + $this->write('WARNING', $message, $params, $this->getOrigin()); } /** @@ -180,7 +181,7 @@ public function warn($message, $params = []) * @param array $params The parameters to be inserted into the message format string. * @param array $origina (Optional) Origin details from where a log message was triggered from. */ - private function log($level, $message, $params, $origin = []) + private function write($level, $message, $params, $origin = []) { $logOrigin = (!empty($origin['function']) ? $origin['function'] : (!empty($origin['file']) ? $origin['file'] : '')); $logLine = (!empty($origin['line']) ? ':'.$origin['line'] : ''); @@ -197,24 +198,42 @@ private function log($level, $message, $params, $origin = []) private function getOrigin() { $backtrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); + // 1=self::getOrigin() | 2=self::debug()/self::warn()/... | 3=self::__construct() $origin = [ 'function' => '', 'file' => '', 'line' => 0 ]; - - if (isset($backtrace[2])) { - if (isset($backtrace[2]['function'])) { - $origin['function'] = $backtrace[2]['function']; + $debuggerMethods = ['debug', 'info', 'warn', 'write']; + + if (isset($backtrace[1])) { + if (isset($backtrace[1]['function'])) { + /** Only log the Function name, if it's not from this Debugger Class */ + if (isset($backtrace[1]['function']) && !in_array($backtrace[1]['function'], $debuggerMethods)) { + $origin['function'] = $backtrace[1]['function']; + } + /** When the Function is a Class Constructor, then log its Class Name instead */ + elseif ($backtrace[1]['function'] === '__construct' && isset($backtrace[1]['class']) ) { + /** However, when it's the Debugger's Class Name, then fall back to use the Origin File reference */ + if ($backtrace[1]['class'] !== __CLASS__) { + $origin['function'] = $backtrace[1]['class']; + } else { + $origin['function'] = basename($backtrace[1]['file']); + } + } + } + elseif (isset($backtrace[1]['file'])) { + $origin['function'] = basename($backtrace[1]['file']); } - if (isset($backtrace[2]['file'])) { - $origin['file'] = basename($backtrace[2]['file']); + if (isset($backtrace[1]['file'])) { + $origin['file'] = basename($backtrace[1]['file']); } - if (isset($backtrace[2]['line'])) { - $origin['line'] = $backtrace[2]['line']; + if (isset($backtrace[1]['line'])) { + $origin['line'] = $backtrace[1]['line']; } } + return $origin; } } diff --git a/www/includes/error.inc.php b/www/includes/error.inc.php index 2155c30..dd0240e 100644 --- a/www/includes/error.inc.php +++ b/www/includes/error.inc.php @@ -1,9 +1,10 @@ fetch($db->query('SELECT count(*) as num_errors FROM sql_error WHERE status = 1', __FILE__, __LINE__, 'SELECT num_errors')); -$num_errors = $sql['num_errors']; +$sql = $db->fetch($db->query('SELECT COUNT(*) as num_errors FROM sql_error WHERE status=1', __FILE__, __LINE__, 'SELECT num_errors')); +$num_errors = (isset($sql['num_errors']) ? (int)$sql['num_errors'] : 0); /** * Get all SQL-Error Entries from the database @@ -23,7 +24,7 @@ function get_sql_errors($num=23,$order=3,$oby=0) if (isset($_GET['tpl'])) $tpl_id = (int)strip_tags(filter_var(trim($_GET['tpl']), FILTER_SANITIZE_NUMBER_INT)); if (isset($_GET['query'])) $query = (string)strip_tags(filter_var(trim($_GET['query']), FILTER_SANITIZE_STRING)); - if(isset($num_errors) && $num_errors > 0) + if($num_errors > 0) { if(!isset($_SESSION['error_order'])) { $_SESSION['error_num'] = $num; @@ -74,7 +75,7 @@ function get_sql_errors($num=23,$order=3,$oby=0) LIMIT '.$_SESSION['error_num'].') s LEFT JOIN user u ON u.id = s.s_user_id WHERE 1 = 1'; - $result = $db->query($sql,__FILE__,__LINE__); + $result = $db->query($sql,__FILE__,__LINE__,__FUNCTION__); $html = ''; if(isset($error_id) && $error_id>0) { diff --git a/www/includes/gallery.readpic.php b/www/includes/gallery.readpic.php index 7d9aaf5..7d4db53 100644 --- a/www/includes/gallery.readpic.php +++ b/www/includes/gallery.readpic.php @@ -5,15 +5,17 @@ * This script reads a gallery-pic (they aren't in a public directory). * It uses the standard session of the User. * - * @author [z]biko - * @author IneX * @package zorg\Gallery - * @version 3.0 - * @since 1.0 file & functions added initially - * @since 2.0 added check for valid GET-Parameters, refactored Caching & HTTP-Headers, added Movie-File output variations + * + * @version 3.5 + * @since 1.0 `[z]biko` File & functions added initially + * @since 2.0 `IneX` Added check for valid GET-Parameters, refactored Caching & HTTP-Headers, added Movie-File output variations * @since 3.0 `14.11.2019` `IneX` GV Beschluss 2018: added check if User is logged-in & Vereinsmitglied + * @since 3.5 `03.01.2024` `IneX` Code hardening and optimizations * * @param integer $_GET['id'] Passed integer > 0 of an existing Gallery Pic ID + * @param string $_GET['token'] Passed token to validate for allowed anonymous access (required for Telegram Bot) + * @param string $_GET['type'] Passed type value, to request either Full Pic or Thumbnail of the Pic * @return resource Media resource with correct MIME-Type and HTTP Headers */ @@ -22,25 +24,26 @@ * @include config.inc.php Include required global site configurations * @include mysql.inc.php MySQL-DB Connection and Functions * @include usersystem.inc.php Usersystem Functions and User definitions - * @include util.inc.php Various Helper Functions */ require_once dirname(__FILE__).'/config.inc.php'; require_once INCLUDES_DIR.'mysql.inc.php'; include_once INCLUDES_DIR.'usersystem.inc.php'; -include_once INCLUDES_DIR.'util.inc.php'; /** Check if passed $_GET['id'] is valid / integer & not empty */ -if (empty($_GET['id']) || !is_numeric($_GET['id']) || $_GET['id'] <= 0) { - /** @TODO instead of just exit(), output a default image showing "broken" or alike? */ +$media_id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?? 0; // $_GET['id'] +if ($media_id <= 0) { + // TODO instead of just exit(), output a default image showing "broken" or alike? */ header('HTTP/1.1 400 Bad Request'); - exit( error_log(sprintf('<%s:%d> Invalid Media-ID was requested: %s', __FILE__, __LINE__, $_GET['id'])) ); -} else { - $media_id = $_GET['id']; + exit( error_log(sprintf('<%s:%d> Invalid Media-ID was requested: %s', __FILE__, __LINE__, $media_id)) ); } /** Query image metadata from database */ -$query = $db->query('SELECT * FROM gallery_pics WHERE id='.$media_id, __FILE__, __LINE__, 'SELECT * FROM gallery_pics'); +$query = $db->query('SELECT * FROM gallery_pics WHERE id=?', __FILE__, __LINE__, 'SELECT FROM gallery_pics', [$media_id]); $media_data = $db->fetch($query); +if (!$media_data) { + header('HTTP/1.1 400 Bad Request'); + exit( error_log(sprintf('<%s:%d> No Media data could be obtained', __FILE__, __LINE__)) ); +} /** * User & Vereinsmitglieder-Check: nur Vereinsmitglieder dürfen Pics sehen @@ -48,12 +51,15 @@ * - Ausnahme #2: Telegram-Bot (Daily Pic) * @link https://github.com/zorgch/zorg-verein-docs/blob/master/GV/GV%202018/2018-12-23%20zorg%20GV%202018%20Protokoll.md */ -$auth_granted = (isset($_GET['token']) && md5(TELEGRAM_API_URI) === $_GET['token'] ? true : null); // Validate Telegram-Bot Auth-Token -if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Auth-Token: %s', __FILE__, __LINE__, ($auth_granted ? $_GET['token'] : 'false'))); -if ((int)$media_data['album'] === APOD_GALLERY_ID || $user->is_loggedin() && (!empty($user->vereinsmitglied) && $user->vereinsmitglied !== '0') || $auth_granted === true) +$token = filter_input(INPUT_GET, 'token', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['token'] +$token_validation = md5($_ENV['TELEGRAM_BOT_API']); +$auth_granted = (!empty($token) && $token === $token_validation ? true : null); // Validate Telegram-Bot Auth-Token +zorgDebugger::log()->debug('Auth-Token Validation: %s (required: %s)', [($auth_granted ? $_GET['token'] : 'false'), (!empty($_GET['token']) ? 'yes' : 'no')]); +if ((int)$media_data['album'] === APOD_GALLERY_ID || $auth_granted === true || ($user->is_loggedin() && !empty($user->vereinsmitglied) && $user->vereinsmitglied !== '0')) { /** Check if passed $_GET['type'] is set to "tn" and valid - in all other cases fallback to "_pic" (default) */ - $media_type = (!isset($_GET['type']) || empty($_GET['type']) || is_numeric($_GET['type']) || (!empty($_GET['type']) && $_GET['type'] != 'tn') ? 'pic_' : 'tn_' ); + $type = filter_input(INPUT_GET, 'type', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['type'] + $media_type = (empty($type) || $type != 'tn' ? 'pic_' : 'tn_' ); /** Zensur-Check: zensurierte Pics können nur Members sehen */ if (!$media_data['zensur'] || ($media_data['zensur'] && $user->typ == USER_MEMBER)) @@ -71,11 +77,11 @@ if ($media_data['extension'] === 'youtube' || $media_data['extension'] === 'vimeo') { $media_mime = 'image/jpeg'; $media_extension = '.jpg'; $media_download = false; } if ($media_data['extension'] === 'website') { $media_mime = 'image/png'; $media_extension = '.png'; $media_download = false; } if (empty($media_extension)) { exit( error_log(sprintf('<%s:%d> Unknown Media Extension: %s', __FILE__, __LINE__, $media_data['extension'])) ); } - + /** Build path to the Media Item */ $mediafile_name = $media_type.$media_data['id'].$media_extension; $mediafile = GALLERY_DIR . $media_data['album'] . DIRECTORY_SEPARATOR . $mediafile_name; - + /** * Last file modification date HTTP-Headers, must be valid HTTP-Date (in GMT) * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag @@ -85,7 +91,7 @@ $mediafile_hash = fileHash($mediafile, true); header('ETag: "'.$mediafile_hash.'"'); header('Last-Modified: ' . $mediafile_lastmodified_gmt); - + /** * Caching directives HTTP-Headers * Falls die Last_Modified & ETag Werte vom Client mit dem vom Server übereinstimmen @@ -108,14 +114,14 @@ header('Pragma: no-cache'); header('Cache-Control: no-store, no-cache, max-age=0, must-revalidate'); */ - + /** If not cached or changed: Media content HTTP-Headers */ header('Content-Type: '.$media_mime); header('Content-Length: ' . filesize($mediafile)); ; - + /** Tell browser whether to display file (e.g. images) or download it (e.g. ZIP) */ header('Content-Disposition: ' . ($media_download ? 'attachment; filename="'.basename($mediafile).'"' : 'inline' ) ); - + /** If not cached or changed: return $mediafile */ readfile($mediafile); diff --git a/www/includes/geo2ip.inc.php b/www/includes/geo2ip.inc.php index 63de351..6622d21 100644 --- a/www/includes/geo2ip.inc.php +++ b/www/includes/geo2ip.inc.php @@ -80,7 +80,7 @@ public function __construct() $this->storeUserIPToSession($this->UserIPaddress); $this->setMaxmindIPDetails(); } else { - \zorgDebugger::me()->debug('getDataFromSession(%s): SESSION CACHE HIT!', [$this->UserIPaddress]); + \zorgDebugger::log()->debug('getDataFromSession(%s): SESSION CACHE HIT!', [$this->UserIPaddress]); } } @@ -120,7 +120,7 @@ private function getRealIPaddress() foreach(explode(',', $_SERVER[$ServerVar]) as $ip_address) { /** Validate IP-Address from $_SERVER var */ - \zorgDebugger::me()->debug('%s => %s', [$ServerVar, $ip_address]); + \zorgDebugger::log()->debug('%s => %s', [$ServerVar, $ip_address]); $checked_IPaddress = $this->validateIPaddress((string)$ip_address); if (!empty($checked_IPaddress) && false !== $checked_IPaddress) @@ -129,7 +129,7 @@ private function getRealIPaddress() return $checked_IPaddress; } } - \zorgDebugger::me()->debug('%s => %s', [$ip_address, (empty($checked_IPaddress) ? 'empty' : ($checked_IPaddress === false ? 'false' : $checked_IPaddress))]); + \zorgDebugger::log()->debug('%s => %s', [$ip_address, (empty($checked_IPaddress) ? 'empty' : ($checked_IPaddress === false ? 'false' : $checked_IPaddress))]); } } diff --git a/www/includes/go_game.inc.php b/www/includes/go_game.inc.php index 465a85a..40244d6 100644 --- a/www/includes/go_game.inc.php +++ b/www/includes/go_game.inc.php @@ -790,8 +790,7 @@ function writeGame($game) $notification_text = t('message-your-turn', 'go', [ SITE_URL, $game['id'] ]); $notification_status = $notification->send($game['nextturn'], 'games', ['from_user_id'=>$user->id, 'subject'=>t('message-subject', 'go'), 'text'=>$notification_text, 'message'=>$notification_text]); if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $notification_status "%s" for user=%d to user=%d', __FUNCTION__, __LINE__, ($notification_status===true?'true':'false'), $game['nextturn'], $user->id)); - /** @deprecated - Messagesystem::sendMessage( + /** @deprecated Messagesystem::sendMessage( $user->id ,$game['nextturn'] ,t('message-subject', 'go') diff --git a/www/includes/googleapis.inc.php b/www/includes/googleapis.inc.php index 5e16641..81b9364 100644 --- a/www/includes/googleapis.inc.php +++ b/www/includes/googleapis.inc.php @@ -15,7 +15,7 @@ */ require_once __DIR__.'/config.inc.php'; if (!defined('GOOGLE_API_KEY') && isset($_ENV['GOOGLE_MAPS_API_KEY'])) define('GOOGLE_API_KEY', $_ENV['GOOGLE_MAPS_API_KEY']); -zorgDebugger::me()->debug('GOOGLE_API_KEY: %s', [(!empty(GOOGLE_API_KEY) ? 'found' : 'MISSING')]); +zorgDebugger::log()->debug('GOOGLE_API_KEY: %s', [(!empty(GOOGLE_API_KEY) ? 'found' : 'MISSING')]); /** * Google Maps API Class diff --git a/www/includes/mysql.inc.php b/www/includes/mysql.inc.php index be0b43a..0e434d4 100644 --- a/www/includes/mysql.inc.php +++ b/www/includes/mysql.inc.php @@ -12,7 +12,6 @@ /** * File includes * @include config.inc.php REQUIRED for $_ENV vars to be available - * @include mysql_login.inc.local.php Include MySQL Database login information file */ require_once __DIR__.'/config.inc.php'; @@ -78,11 +77,11 @@ public function __construct() { * @since 2.1 `07.08.2019` `IneX` changed return mysql_insert_id() & mysql_affected_rows() to return row-id or true * @since 3.0 `02.06.2023` `IneX` added support for mysqli prepared statements, helps mitigating SQL Injection risks (CWE-89) * - * @param $sql string SQL-Query. Als Prepared Statement wird auch $params benötigt! - * @param $file string (Optional) Dateiname in welcher SQL-Query abgesetzt wurde - * @param $line int (Optional) Linenumber in der Datei welche SQL-Query abgesetzt hat - * @param $funktion string (Optional) Name der Funktion aus welcher SQL-Query abgesetzt wurde - * @param $params array (Optional) Parameter für Prepared SQL Statement + * @param string $sql SQL-Query. Als Prepared Statement wird auch $params benötigt! + * @param string $file (Optional) Dateiname in welcher SQL-Query abgesetzt wurde + * @param int $line (Optional) Linenumber in der Datei welche SQL-Query abgesetzt hat + * @param string $funktion (Optional) Name der Funktion aus welcher SQL-Query abgesetzt wurde + * @param array $params (Optional) Parameter für Prepared SQL Statement * @global object $user Globales Class-Object mit den User-Methoden & Variablen * @return object|integer Query-Result-Resource or Primary-Key of INSERT */ @@ -111,7 +110,7 @@ function query($sql, $file='', $line=0, $funktion='', $params=[]) { if (empty($params)) { $result = mysqli_query($this->conn, $sql); /* Log SQL-Queries not upgraded to Prepared Statements */ - zorgDebugger::me()->debug('<%s> is no SQL prepared statement, in %s:%d', [$funktion, $file, $line]); + zorgDebugger::log()->debug('<%s:%d> may required update to SQL prepared statement, in %s', [$funktion, $line, $file]); } else { $stmt = mysqli_prepare($this->conn, $sql); if ($stmt === false) throw new mysqli_sql_exception(mysqli_error($this->conn)); @@ -161,16 +160,20 @@ function query($sql, $file='', $line=0, $funktion='', $params=[]) { $result = mysqli_stmt_get_result($stmt); } - /** If the query failed or no rows were returned, display MySQL-Error with some context */ - if ($result === false && mysqli_num_rows($result) === 0 && mysqli_affected_rows($this->conn) === 0) - { - if ($this->display_error === 1) { - throw new mysqli_sql_exception($this->msg($sql, $file, $line, $funktion)); - } else { - $this->msg($sql, $file, $line, $funktion); - throw new mysqli_sql_exception('SQL query error in '.$file.' at line '.$line); - } - } else { + /** + * If the query failed or no rows were returned, display MySQL-Error with some context + * //FIXME I don't know why, but when this is changed, it will break a lot of things (e.g. Smarty->compile(comment:xxxx)) + * // INFO 08.07.2024/IneX: disabled this check - doesn't add value & there seems no save way to check for WRONG queries only (no returned rows is no error...) + */ + // if ($result === false && mysqli_num_rows($result) === 0 && mysqli_affected_rows($this->conn) === 0) + // { + // if (!$this->display_error) { + // throw new mysqli_sql_exception($this->msg($sql, $file, $line, $funktion)); + // } else { + // $this->msg($sql, $file, $line, $funktion); + // throw new mysqli_sql_exception('SQL query error in '.$file.' at line '.$line); + // } + // } else { /** Retrieve and return a more valuable information, depending on the SQL-query type */ switch (strtolower(substr($sql, 0, 6))) { @@ -182,13 +185,15 @@ function query($sql, $file='', $line=0, $funktion='', $params=[]) { return $result; default: /** mysqli_affected_rows() returns the number of affected rows as an integer, or -1 on failure */ - $sql_affected_rows = (int)mysqli_affected_rows($this->conn); + $sql_affected_rows = intval(mysqli_affected_rows($this->conn)); return ($sql_affected_rows !== -1 ? $sql_affected_rows : false); } - } + // } } catch (mysqli_sql_exception $e) { - zorgDebugger::me()->debug('%s', [$e->getMessage()]); - die($e->getMessage()); + zorgDebugger::log()->debug('%s', [$e->getMessage()]); + $this->msg($sql, $file, $line, $funktion); + + die(($this->display_error ? $e->getMessage() : '')); } } @@ -242,12 +247,10 @@ function saveerror($msg, $sql, $file='', $line=0, $funktion='') $ip = (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''); $page = (isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''); $referer = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ''); - - $insertSql = 'INSERT INTO sql_error (user_id, ip, page, query, msg, date, file, line, referer, status, function) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)'; + // FIXME crasht wenn von :193 -> :222 aufgerufen, prepared statement scheint falsch zu sein *shrug* + $insertSql = 'INSERT INTO sql_error (user_id, ip, page, query, msg, date, file, line, referer, status, function) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)'; $stmt = mysqli_prepare($this->conn, $insertSql); - mysqli_stmt_bind_param($stmt, 'isssssiss', - $user_id, $ip, $page, $sql, $msg, timestamp(true), $file, $line, $referer, $funktion); + mysqli_stmt_bind_param($stmt, 'isssssiss', $user_id, $ip, $page, $sql, $msg, timestamp(true), $file, $line, $referer, $funktion); mysqli_stmt_execute($stmt); } @@ -348,7 +351,7 @@ function insert($table, $values, $file='', $line=0, $funktion=null) $insertKeys = '(`'.implode('`,`', array_keys($values)).'`)'; $insertValues = implode(',', array_fill(0, count($values), '?')); $sql = sprintf('INSERT INTO `%s` %s VALUES (%s)', $table, $insertKeys, $insertValues); - zorgDebugger::me()->debug('$db->insert() SQL: %s%s', [$sql, print_r($values,true)]); + zorgDebugger::log()->debug('$db->insert() SQL: %s%s', [$sql, print_r($values,true)]); foreach ($values as $key => $val) { if (strtolower($val) === 'now()') { $values[$key] = timestamp(true); // Fix "NOW()" => NOW() without quotes @@ -374,8 +377,8 @@ function insert($table, $values, $file='', $line=0, $funktion=null) * @since 3.0 `05.11.2018` `IneX` fixed iteration for $id (WHERE x=y) building, depending if array or integer is provided * @since 3.0 `02.06.2023` `IneX` added compatibility with mysqli prepared statements * - * @FIXME array($id) soll nicht key,value-Pairs parsen, sondern direkt der Vergleich (z.B. "id>2"), aktuell kann nur auf 1 name & mehrere exakte values geprüft werden: "a=b OR a=c" - * @TODO change all usages of $db->update to pass associative array elements, like 'name'=>'Barbara Harris'. + * // FIXME array($id) soll nicht key,value-Pairs parsen, sondern direkt der Vergleich (z.B. "id>2"), aktuell kann nur auf 1 name & mehrere exakte values geprüft werden: "a=b OR a=c" + * // TODO change all usages of $db->update to pass associative array elements, like 'name'=>'Barbara Harris'. * * @param string $table Name der Tabelle, in der geändert werden soll * @param array|int $id Array: $id[0]: Name des Primärschlüsselfeldes + $id[1+] Rows, die geändert werden sollen | bei Integer: Row, die geändert werden soll, nimmt Primärschlüsselfeld als 'id' an @@ -384,9 +387,13 @@ function insert($table, $values, $file='', $line=0, $funktion=null) * @param int $line (optional) Zeile des Aufrufes, für Fehlermeldung * @param string $funktion (optional) Funktion wo der Aufruf stattfand, für Fehlermeldung * @return integer|boolean Anzahl der geänderten Table-Rows des Update Queries - oder FALSE bei Fehler - */ + */ function update($table, $id, $values, $file='', $line='', $funktion='') { + if (!is_string($table)) { + error_log(sprintf('Invalid "table" for db->update(): %s', $table)); + return false; + } if (empty($values) || !is_array($values)) { error_log(sprintf('Wrong Parameter type "values" in db->update(): %s', print_r($values,true))); return false; @@ -436,9 +443,8 @@ function update($table, $id, $values, $file='', $line='', $funktion='') if ($field !== key($conditions)) $sql .= ' OR '; // Add Separator if not last Array-Iteration } } - zorgDebugger::me()->debug('$db->update() SQL: %s', [$sql]); + zorgDebugger::log()->debug('$db->update() SQL: %s', [$sql]); return $this->query($sql, $file, $line, $funktion, $params); - //return mysql_affected_rows(); } } diff --git a/www/includes/notifications.inc.php b/www/includes/notifications.inc.php index bf393aa..7f3390f 100644 --- a/www/includes/notifications.inc.php +++ b/www/includes/notifications.inc.php @@ -19,7 +19,7 @@ * File includes * @include messagesystem.inc.php Required Messagesystem Class */ -require_once INCLUDES_DIR.'messagesystem.inc.php' ; +require_once __DIR__.'/messagesystem.inc.php' ; /** * Class for Notification handling @@ -171,7 +171,7 @@ private function get($user_id) if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $user_id VALID', __METHOD__, __LINE__)); } - $query = $db->query('SELECT notifications FROM user WHERE id='.$user_id.' LIMIT 1', __FILE__, __LINE__, __METHOD__); + $query = $db->query('SELECT notifications FROM user WHERE id=? LIMIT 1', __FILE__, __LINE__, __METHOD__, [$user_id]); $result = $db->fetch($query); if (!$result || empty($result)) { @@ -180,7 +180,7 @@ private function get($user_id) $userEnabledNotifications = json_decode( $user->default_notifications, true ); // JSON-DECODE to Array } else { if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Use $userEnabledNotifications for $user_id %d: %s', __METHOD__, __LINE__, $user_id, $result['notifications'])); - $userEnabledNotifications = json_decode( $result['notifications'], true); // JSON-Decode to Array + $userEnabledNotifications = json_decode( stripslashes($result['notifications']), true); // JSON-Decode to Array } return $userEnabledNotifications; @@ -211,14 +211,14 @@ private function check($notification_source, $notification_type, $user_id) if (is_numeric($notification_type) || is_array($notification_type)) return false; if (!is_numeric($user_id) || $user_id <= 0 || is_array($user_id)) return false; - $query = $db->query('SELECT notifications FROM user WHERE id='.$user_id.' LIMIT 1', __FILE__, __LINE__, __METHOD__); + $query = $db->query('SELECT notifications FROM user WHERE id=? LIMIT 1', __FILE__, __LINE__, __METHOD__, [$user_id]); $result = $db->fetch($query); if (!$result || empty($result)) { /** No query result / empty "notifications"-field */ return false; } else { - $userEnabledNotifications = json_decode( $result['notifications'], true); // JSON-Decode to Array + $userEnabledNotifications = json_decode( stripslashes($result['notifications']), true); // JSON-Decode to Array } /** Check if $notification_type is enabled */ diff --git a/www/includes/setistats.inc.php b/www/includes/setistats.inc.php index 2d534dd..1ed706c 100644 --- a/www/includes/setistats.inc.php +++ b/www/includes/setistats.inc.php @@ -1,155 +1,185 @@ "URL)\n\n\n(.*)\n\n\n\n\nResults", - "Workunits" => "\n\nResults Received\n\n\n(.*)\n\n\n\nTotal CPU Time", - "TotalCPUTime" => "\n\nTotal CPU Time\n\n\n(.*)\n\n\n\n\nAverage CPU Time per work unit", - "AverageCPUTime" => "\n\nAverage CPU Time per work unit\n\n\n(.*)\n\n\n\n\nAverage results received per day", - "LastResult" => "Last result returned:(.*)\nRegistered on:", - "RegisteredOn" => "Registered on:(.*)\n  "SETI@home user for:(.*)\nYour group info", - "GroupName" => ".html\">(.*)\n\n\n "\n\nYou belong to the group named:\n\n\n", - "TotalUsers" => "\nYour rank out of (.*) total users is:\n", - "Rank" => "\n(.*)", - "TotalUsersWithThisRank" => "The number of users who have this rank:\n\n(.*)\n\n\nYou have completed more work units than", - "MoreWorkUnitsThan" => "work units than\n\n(.*) of our", - "AverageResultsPerDay" => "Average results received per day\n\n\n(.*)\n\n\nLast", - "RegistrationClass" => "\n View Registration Class\nSETI@home user for" - ); - - var $errors = array( - "SiteDown" => "Seti@Home Server unreachable", - "ParseError" => "Parse Error", - "Error" => "Error" - ); - - - - function setEmail($user_email) - { - $this->email = $user_email; - $this->server1 = "http://setiathome.ssl.berkeley.edu/fcgi-bin/fcgi?email=". $this->email. "&cmd=user_stats_new"; - $this->server2 = "http:///setiathome2.ssl.berkeley.edu/fcgi-bin/fcgi?email=". $this->email. "&cmd=user_stats_new"; - return true; - } - - function Init() - { - $this->raw = @implode("", @file($this->server1)); - - if (!$this->raw){ - $this->raw = @implode("", @file($this->server2)); - } - - } - - function viewStats($what) - { - - if (!$this->raw) { - $this->$what = $this->errors["SiteDown"]; - } - else - { - if (@eregi($this->exp[$what], $this->raw, $output)) - { - $this->$what = $output[1]; - } - else - { - $this->$what = $this->errors["ParseError"]; - } - } - if (!$this->$what) - { - $this->$what = $this->errors["Error"]; - } - return $this->$what; - - } - - function Group() - { - if (@eregi("You do not currently belong to a group", $this->raw)) - { - $this->Groupname = "none"; - $this->Groupurl = ""; - } - else - { - $this->Groupname = $this->viewStats('GroupName'); - $this->Groupurl = $this->viewStats('GroupURL'); - } - - $this->Groupstuff = array ( - "name" => $this->Groupname, - "url" => $this->Groupurl - ); - - return $this->Groupstuff; - } - - function ResultInt() - { - list ($this->null, $this->tmp_month, $this->tmp_null, $this->tmp_day, $this->tmp_time, $this->tmp_year, $this->null) = split ('[ ]', $this->viewStats('RegisteredOn')); - list ($this->tmp_hour, $this->tmp_min, $this->tmp_sec) = split ('[:]', $this->tmp_time); - - switch ($this->tmp_month) - { - case 'Jan'; $this->tmp_month = 1; break; - case 'Feb'; $this->tmp_month = 2; break; - case 'Mar'; $this->tmp_month = 3; break; - case 'Apr'; $this->tmp_month = 4; break; - case 'May'; $this->tmp_month = 5; break; - case 'Jun'; $this->tmp_month = 6; break; - case 'Jul'; $this->tmp_month = 7; break; - case 'Aug'; $this->tmp_month = 8; break; - case 'Sep'; $this->tmp_month = 9; break; - case 'Oct'; $this->tmp_month = 10; break; - case 'Nov'; $this->tmp_month = 11; break; - case 'Dec'; $this->tmp_month = 12; break; - } - - $this->RegDate = mktime($this->tmp_hour, $this->tmp_min, $this->tmp_sec, $this->tmp_month, $this->tmp_day, $this->tmp_year); - $this->ActDate = time(); - $this->DiffDate = ($this->ActDate-$this->RegDate); - $this->ResInt = ($this->DiffDate/$this->viewStats('Workunits')); - - $this->days = floor($this->ResInt / 24 / 60 / 60 ); - - $this->ResInt = $this->ResInt - ($this->days*24*60*60); - $this->hours = floor($this->ResInt / 60 / 60); - - $this->ResInt = ($this->ResInt - ($this->hours*60*60)); - $this->minutes = floor($this->ResInt / 60); - - $this->ResInt = $this->ResInt - ($this->minutes*60); - $this->seconds = floor($this->ResInt); - - $this->ResultInterval = array ( - "days" => $this->days, - "hours" => $this->hours, - "minutes" => $this->minutes, - "seconds" => $this->seconds - ); - return $this->ResultInterval; - - } - - function AverageResultsPerWeek() - { - return $this->viewStats('AverageResultsPerDay')*7; - } - - function AverageResultsPerMonth() - { - return $this->viewStats('AverageResultsPerDay')*30; - } + public $exp = [ + "UserName" => "URL)\n\n\n(.*)\n\n\n\n\nResults", + "Workunits" => "\n\nResults Received\n\n\n(.*)\n\n\n\nTotal CPU Time", + "TotalCPUTime" => "\n\nTotal CPU Time\n\n\n(.*)\n\n\n\n\nAverage CPU Time per work unit", + "AverageCPUTime" => "\n\nAverage CPU Time per work unit\n\n\n(.*)\n\n\n\n\nAverage results received per day", + "LastResult" => "Last result returned:(.*)\nRegistered on:", + "RegisteredOn" => "Registered on:(.*)\n  "SETI@home user for:(.*)\nYour group info", + "GroupName" => ".html\">(.*)\n\n\n "\n\nYou belong to the group named:\n\n\n", + "TotalUsers" => "\nYour rank out of (.*) total users is:\n", + "Rank" => "\n(.*)", + "TotalUsersWithThisRank" => "The number of users who have this rank:\n\n(.*)\n\n\nYou have completed more work units than", + "MoreWorkUnitsThan" => "work units than\n\n(.*) of our", + "AverageResultsPerDay" => "Average results received per day\n\n\n(.*)\n\n\nLast", + "RegistrationClass" => "\n View Registration Class\nSETI@home user for" + ]; + public $errors = [ + "SiteDown" => "Seti@Home Server unreachable", + "ParseError" => "Parse Error", + "Error" => "Error" + ]; + public $what; + private $email; + private $server1; + private $server2; + private $server3; + private $raw; + private $Groupname; + private $Groupurl; + private $Groupstuff; + private $null; + private $tmp_month; + private $tmp_null; + private $tmp_day; + private $tmp_time; + private $tmp_year; + private $tmp_hour; + private $tmp_min; + private $tmp_sec; + private $RegDate; + private $ActDate; + private $DiffDate; + private $ResInt; + private $days; + private $hours; + private $minutes; + private $seconds; + private $ResultInterval; + + + function __construct($user_email) + { + self::setEmail($user_email); + self::setServer(); + $this->raw = @implode("", @file($this->server1)); + + if (!$this->raw){ + $this->raw = @implode("", @file($this->server2)); + } + } + + function setEmail($user_email) + { + $this->email = $user_email; + return true; + } + + function setServer() + { + $this->server1 = "https://www.boincstats.com/stats/search/?search=". $this->email; + $this->server2 = "https://stats.free-dc.org/stats.php?page=search&proj=&team=&name=". $this->email. "&exact=Y&cross=N"; + $this->server3 = "http:///setiathome2.ssl.berkeley.edu/fcgi-bin/fcgi?email=". $this->email. "&cmd=user_stats_new"; + return true; + } + + function viewStats($what) + { + + if (!$this->raw) { + $this->$what = $this->errors["SiteDown"]; + } + else + { + if (@preg_match('/' . $this->exp[$what] . '/i', $this->raw, $output)) + { + $this->$what = $output[1]; + } + else + { + $this->$what = $this->errors["ParseError"]; + } + } + if (!$this->$what) + { + $this->$what = $this->errors["Error"]; + } + return $this->$what; + + } + + function Group() + { + if (@preg_match("/You do not currently belong to a group/i", $this->raw)) + { + $this->Groupname = "none"; + $this->Groupurl = ""; + } + else + { + $this->Groupname = $this->viewStats('GroupName'); + $this->Groupurl = $this->viewStats('GroupURL'); + } + + $this->Groupstuff = array ( + "name" => $this->Groupname, + "url" => $this->Groupurl + ); + + return $this->Groupstuff; + } + + function ResultInt() + { + list($this->null, $this->tmp_month, $this->tmp_null, $this->tmp_day, $this->tmp_time, $this->tmp_year, $this->null) = explode(' ', $this->viewStats('RegisteredOn')); + list($this->tmp_hour, $this->tmp_min, $this->tmp_sec) = explode(':', $this->tmp_time); + + switch ($this->tmp_month) + { + case 'Jan'; $this->tmp_month = 1; break; + case 'Feb'; $this->tmp_month = 2; break; + case 'Mar'; $this->tmp_month = 3; break; + case 'Apr'; $this->tmp_month = 4; break; + case 'May'; $this->tmp_month = 5; break; + case 'Jun'; $this->tmp_month = 6; break; + case 'Jul'; $this->tmp_month = 7; break; + case 'Aug'; $this->tmp_month = 8; break; + case 'Sep'; $this->tmp_month = 9; break; + case 'Oct'; $this->tmp_month = 10; break; + case 'Nov'; $this->tmp_month = 11; break; + case 'Dec'; $this->tmp_month = 12; break; + } + + $this->RegDate = mktime($this->tmp_hour, $this->tmp_min, $this->tmp_sec, $this->tmp_month, $this->tmp_day, $this->tmp_year); + $this->ActDate = time(); + $this->DiffDate = ($this->ActDate-$this->RegDate); + $this->ResInt = ($this->DiffDate/$this->viewStats('Workunits')); + + $this->days = floor($this->ResInt / 24 / 60 / 60 ); + + $this->ResInt = $this->ResInt - ($this->days*24*60*60); + $this->hours = floor($this->ResInt / 60 / 60); + + $this->ResInt = ($this->ResInt - ($this->hours*60*60)); + $this->minutes = floor($this->ResInt / 60); + + $this->ResInt = $this->ResInt - ($this->minutes*60); + $this->seconds = floor($this->ResInt); + + $this->ResultInterval = array ( + "days" => $this->days, + "hours" => $this->hours, + "minutes" => $this->minutes, + "seconds" => $this->seconds + ); + return $this->ResultInterval; + } + + function AverageResultsPerWeek() + { + return $this->viewStats('AverageResultsPerDay')*7; + } + + function AverageResultsPerMonth() + { + return $this->viewStats('AverageResultsPerDay')*30; + } } - - -?> \ No newline at end of file diff --git a/www/includes/stl.inc.php b/www/includes/stl.inc.php index 1fe5cdf..ac8b683 100644 --- a/www/includes/stl.inc.php +++ b/www/includes/stl.inc.php @@ -4,62 +4,66 @@ * * Shoot The Lamber ist ein Schiffchen-Versenken-Klon auf Zorg * mySQL Tables: - - Haupttable: - stl: - game_id (primary key) - spiel nummer - game_size (max. 23, min. 5) - spielfeld grösse Anzahl x Anzahl - status int - 0 = wurde erstellt, spieler werden gesucht - 1 = läuft - 2 = beendet - winner_team int - 0 = team red - 1 = team blue - creater_id - userID des spielerstellers (spiel-admin) - num_players (min. 6, max. 24) - anzahl spieler - game_title - spielname - - Spieler Table: - stl_players: - user_id - user ID aus der user table - team_id - team id bei dem der spieler mitglied ist. - game_id - spiel nummer - last_shoot - datum an dem der spieler zuletzt geschossen hat. - - Schiffs- und treffer positionen - stl_positions: - pos_id (primary key) - positions id - game_id - spiel nummer - grid_x - x koordinate - grid_y - y koordinate - hit_user_id - spieler id von dem hier ein torpedo gekommen ist, 0 bedeut kein schuss bis jetzt - hit_team_id - team_id vom topedo ;-) - ship_user_id - spieler id vom besitzer des schiffs, 0 bedeutet kein schiff - ship_team_id - team_id vom besitzer des schiffs - shoot_date - datum an dem der spieler das torpedo geschossen hat. * - * @author [z]milamber + * Haupttable: + * stl: + * game_id (primary key) + * spiel nummer + * game_size (max. 23, min. 5) + * spielfeld grösse Anzahl x Anzahl + * status int + * 0 = wurde erstellt, spieler werden gesucht + * 1 = läuft + * 2 = beendet + * winner_team int + * 0 = team red + * 1 = team blue + * creater_id + * userID des spielerstellers (spiel-admin) + * num_players (min. 6, max. 24) + * anzahl spieler + * game_title + * spielname + * + * Spieler Table: + * stl_players: + * user_id + * user ID aus der user table + * team_id + * team id bei dem der spieler mitglied ist. + * game_id + * spiel nummer + * last_shoot + * datum an dem der spieler zuletzt geschossen hat. + * + * Schiffs- und treffer positionen + * stl_positions: + * pos_id (primary key) + * positions id + * game_id + * spiel nummer + * grid_x + * x koordinate + * grid_y + * y koordinate + * hit_user_id + * spieler id von dem hier ein torpedo gekommen ist, 0 bedeut kein schuss bis jetzt + * hit_team_id + * team_id vom topedo ;-) + * ship_user_id + * spieler id vom besitzer des schiffs, 0 bedeutet kein schiff + * ship_team_id + * team_id vom besitzer des schiffs + * shoot_date + * datum an dem der spieler das torpedo geschossen hat. + * + * @version 2.0 + * @since 1.0 `[z]milamber` File added + * @since 2.0 `IneX` Code refactorings and Query optimizations + * * @package zorg\Games\STL */ + /** * File includes * @include config.inc.php @@ -67,7 +71,7 @@ * @include usersystem.inc.php * @include util.inc.php */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; require_once INCLUDES_DIR.'mysql.inc.php'; require_once INCLUDES_DIR.'usersystem.inc.php'; include_once INCLUDES_DIR.'util.inc.php'; diff --git a/www/includes/telegrambot.inc.php b/www/includes/telegrambot.inc.php index 5886bc8..0be04cc 100644 --- a/www/includes/telegrambot.inc.php +++ b/www/includes/telegrambot.inc.php @@ -52,6 +52,7 @@ class Telegram const PARSE_MODE = 'html'; // TODO Replace with $_ENV['TELEGRAM_PARSE_MODE'] const DISABLE_WEB_PAGE_PREVIEW = 'false'; // TODO Replace with $_ENV['TELEGRAM_DISABLE_WEBPAGE_PREVIEW'] const DISABLE_NOTIFICATION = 'false'; // TODO Replace with $_ENV['TELEGRAM_DISABLE_NOTIFICATION'] + public $send = null; /** * Send a Message via Telegram Messenger @@ -79,7 +80,7 @@ public function send($userScope, $messageType, $content) /** Parse $_ENV vars into $botconfigs */ if (empty($_ENV['TELEGRAM_BOT_API_KEY']) || empty($_ENV['TELEGRAM_BOT'])) { - zorgDebugger::me()->warn('Missing Telegram Bot Configs! TELEGRAM_BOT_API_KEY=%s | TELEGRAM_BOT=%s', [$_ENV['TELEGRAM_BOT_API_KEY'],$_ENV['TELEGRAM_BOT']]); + zorgDebugger::log()->warn('Missing Telegram Bot Configs! TELEGRAM_BOT_API_KEY=%s | TELEGRAM_BOT=%s', [$_ENV['TELEGRAM_BOT_API_KEY'],$_ENV['TELEGRAM_BOT']]); return false; } else { $botconfigs = [ 'api_key' => $_ENV['TELEGRAM_BOT_API_KEY'] @@ -104,13 +105,13 @@ public function send($userScope, $messageType, $content) { /** USER: If $userScope = User-ID: get the Telegram Chat-ID */ case is_numeric($userScope) && $userScope > 0: - zorgDebugger::me()->debug('Checking for User Telegram Chat-ID...'); + zorgDebugger::log()->debug('Checking for User Telegram Chat-ID...'); $telegramChatId = $user->userHasTelegram($userScope); break; /** GROUP: If $userScope = 'group': get the Telegram Groupchat-ID */ case 'group': - zorgDebugger::me()->debug('Checking for Group Telegram Chat-ID...'); + zorgDebugger::log()->debug('Checking for Group Telegram Chat-ID...'); $telegramChatId = $botconfigs['TELEGRAM_GROUPCHAT_ID']; break; @@ -128,7 +129,7 @@ public function send($userScope, $messageType, $content) /** Build API Call */ $parameters = array_merge( $content, [ 'chat_id' => $telegramChatId ] ); - zorgDebugger::me()->debug('Telegram Message $parameters Array: %s', [print_r($parameters, true)]); + zorgDebugger::log()->debug('Telegram Message $parameters Array: %s', [print_r($parameters, true)]); if (is_array($parameters) && !empty($parameters)) { /** Validate & compose the Parameter-Query for the API Call */ @@ -139,8 +140,8 @@ public function send($userScope, $messageType, $content) /** * Sending the Telegram message */ - zorgDebugger::me()->debug('Using "%s" to Chat "%s"', [$messageType, strval($telegramChatId)]); - zorgDebugger::me()->debug('API call: %s', [$telegramAPIcall]); + zorgDebugger::log()->debug('Using "%s" to Chat "%s"', [$messageType, strval($telegramChatId)]); + zorgDebugger::log()->debug('API call: %s', [$telegramAPIcall]); if (!empty($messageType)) { /** Create a stream_context for the file_get_contents HTTP request */ @@ -156,11 +157,11 @@ public function send($userScope, $messageType, $content) */ if (is_array($http_response_header)) { - zorgDebugger::me()->debug('file_get_contents() $http_response_header: %s | $httpResponseBody: %s', [print_r($http_response_header, true), $httpResponseBody]); + zorgDebugger::log()->debug('file_get_contents() $http_response_header: %s | $httpResponseBody: %s', [print_r($http_response_header, true), $httpResponseBody]); preg_match('{HTTP\/\S*\s(\d{3})}', $http_response_header[0], $match); if ($match[1] !== '200') { - zorgDebugger::me()->error('Telegram %s failed with HTTP status code %s and response: %s', [$messageType, $match[0], $httpResponseBody]); + zorgDebugger::log()->error('Telegram %s failed with HTTP status code %s and response: %s', [$messageType, strval($match[1]), (false !== $httpResponseBody ? $httpResponseBody : 'false')]); return false; } else { return true; @@ -170,12 +171,12 @@ public function send($userScope, $messageType, $content) } } } else { - zorgDebugger::me()->warn('«%s» did not pass validation!', [$messageType]); + zorgDebugger::log()->warn('«%s» did not pass validation!', [$messageType]); return false; } } } else { - zorgDebugger::me()->warn(t('invalid-telegram-chatid', 'messagesystem')); + zorgDebugger::log()->warn(t('invalid-telegram-chatid', 'messagesystem')); return false; } } @@ -219,13 +220,13 @@ public function mentionUser($userid) LIMIT 1'; $telegramUserIds = $db->fetch($db->query($sql, __FILE__, __LINE__, __METHOD__)); $telegramUserId = $telegramUserIds['tui']; - zorgDebugger::me()->debug('Found Telegram User ID «%d»', [$telegramUserId]); + zorgDebugger::log()->debug('Found Telegram User ID «%d»', [$telegramUserId]); if (!empty($telegramUserId)) { $username = $user->id2user($telegramUserId); $link = sprintf('%s', $telegramUserId, $username); - zorgDebugger::me()->debug('Returns HTML-link:', [$link]); + zorgDebugger::log()->debug('Returns HTML-link:', [$link]); return $telegramUserIds['tui']; } else { return false; @@ -256,7 +257,7 @@ public function mentionUser($userid) */ public function formatText($notificationText) { - zorgDebugger::me()->debug('Passed raw string: %s', [$notificationText]); + zorgDebugger::log()->debug('Passed raw string: %s', [$notificationText]); /** * Strip away all HTML-tags & unix line breaks @@ -302,7 +303,7 @@ public function formatText($notificationText) * Decode HTML-Entities */ $notificationText = html_entity_decode($notificationText); - zorgDebugger::me()->debug('Processed string: %s', [$notificationText]); + zorgDebugger::log()->debug('Processed string: %s', [$notificationText]); return ( !empty($notificationText) ? $notificationText : false ); } @@ -412,7 +413,7 @@ private function validateData($messageType, array $parameters) } /** Check if $messageType matches any available $_telegramMessageModels */ - zorgDebugger::me()->debug('Checking array_key_exists in $_telegramMessageModels for "%s"', [$messageType]); + zorgDebugger::log()->debug('Checking array_key_exists in $_telegramMessageModels for "%s"', [$messageType]); if (isset($_telegramMessageModels[$messageType])) { if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> SUCCESS: $messageType "%s" found and is OK', __METHOD__, __LINE__, $messageType)); @@ -425,14 +426,14 @@ private function validateData($messageType, array $parameters) * if ( !array_key_exists($parameters, $value) ) error_log(sprintf('[WARN] '.__METHOD__.': Value %s is required but was not passed!', $key+1)); * } */ - zorgDebugger::me()->debug('Checking $parameters for presence of required parameter "%s"', [$_telegramMessageModels[$messageType]['required'][0]]); + zorgDebugger::log()->debug('Checking $parameters for presence of required parameter "%s"', [$_telegramMessageModels[$messageType]['required'][0]]); if ( !isset($parameters[$_telegramMessageModels[$messageType]['required'][0]]) ) { error_log(sprintf('[WARN] <%s:%d> Value %s is required but was not passed!', __METHOD__, __LINE__, $_telegramMessageModels[$messageType]['required'][0])); return false; } else { if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> SUCCESS: required parameter "%s" found and is OK', __METHOD__, __LINE__, $_telegramMessageModels[$messageType]['required'][0])); - zorgDebugger::me()->debug('SUCCESS: required parameter "%s" found and is OK', [$_telegramMessageModels[$messageType]['required'][0]]); + zorgDebugger::log()->debug('SUCCESS: required parameter "%s" found and is OK', [$_telegramMessageModels[$messageType]['required'][0]]); /** * Build the Data-Array with key:value pairs assigned @@ -445,7 +446,7 @@ private function validateData($messageType, array $parameters) * ]; */ $data = []; - zorgDebugger::me()->debug('Building $data Array for Function return'); + zorgDebugger::log()->debug('Building $data Array for Function return'); /** Assign key=>value pairs for Global Parameters */ @@ -465,7 +466,7 @@ private function validateData($messageType, array $parameters) /** Assign key=>value pairs for $messageType Required Parameters */ foreach ((array) $_telegramMessageModels[$messageType]['required'] as $requiredParameter) { - zorgDebugger::me()->debug('array_push to $data Array for key=>value pair "%s"', [$requiredParameter]); + zorgDebugger::log()->debug('array_push to $data Array for key=>value pair "%s"', [$requiredParameter]); $data[$requiredParameter] = $this->formatText($parameters[$requiredParameter]); } @@ -474,18 +475,18 @@ private function validateData($messageType, array $parameters) { foreach ((array) $_telegramMessageModels[$messageType]['optional'] as $optionalParameter) { - zorgDebugger::me()->debug('array_push to $data Array for key=>value pair "%s"', [$optionalParameter]); + zorgDebugger::log()->debug('array_push to $data Array for key=>value pair "%s"', [$optionalParameter]); if (!empty($parameters[$optionalParameter])) $data[$optionalParameter] = $parameters[$optionalParameter]; } } /** Return Data-Array with key:value pairs assigned */ - zorgDebugger::me()->debug('Complete $data Array: %s', [print_r($data, true)]); + zorgDebugger::log()->debug('Complete $data Array: %s', [print_r($data, true)]); return $data; } } else { - zorgDebugger::me()->warn('Telegram Message Type "%s" is invalid!', [$messageType]); + zorgDebugger::log()->warn('Telegram Message Type "%s" is invalid!', [$messageType]); return false; } } @@ -579,5 +580,5 @@ public function poll($scope, $question, $options, $is_anonymous=true, $type='reg * Instantiating new Telegram Class-Object * @TODO Fix this "dirty hack" with instantiated "$telegram->send"-object... */ -//$telegram = new Telegram(); +$telegram = new Telegram(); $telegram->send = new send(); diff --git a/www/includes/util.inc.php b/www/includes/util.inc.php index 26560d5..8b38ad5 100644 --- a/www/includes/util.inc.php +++ b/www/includes/util.inc.php @@ -8,7 +8,7 @@ * File includes * @include config.inc.php */ -require_once dirname(__FILE__).'/config.inc.php'; +require_once __DIR__.'/config.inc.php'; /** * Funktion um ein UNIX_TIMESTAMP schön darzustellen. @@ -59,10 +59,10 @@ function timename($timestamp) $currTime = time(); /** Vergangen oder in der Zukunft? */ - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Comparing timestamps %s vs %s', __FUNCTION__, __LINE__, $timestamp, $currTime)); + zorgDebugger::log()->debug('Comparing %s : %s', [$timestamp, $currTime]); $prefix = ($timestamp >= $currTime ? 'in ' : 'vor '); $timeDiff = ($timestamp >= $currTime ? $timestamp - $currTime : $currTime - $timestamp); - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> Timestamps time difference: %s %d', __FUNCTION__, __LINE__, $prefix, $timeDiff)); + zorgDebugger::log()->debug('Time difference %s -> %d', [$prefix, $timeDiff]); /** Zeitperioden */ $timeLengths = array('s' => 1, 'm' => 60, 'h' => 3600, 'd' => 86400, 'w' => 604800, 'mt' => 2592000, 'y' => 31536000); @@ -330,25 +330,24 @@ function changeQueryString($querystring, $changes) } } $str = ltrim($str, '&'); - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> new query-string: %s', __FUNCTION__, __LINE__, $str)); + zorgDebugger::log()->debug('new query-string: %s', [$str]); return $str; } /** * Return all URL $_GET-Parameters in a String, usable to add to an URL as Query-Parameters * - * @author [z]biko - * @version 1.0 - * @since 1.0 function added + * @version 1.1 + * @since 1.0 `[z]biko` function added + * @since 1.1 `03.01.2024` `IneX` Addresses potential XSS through unsanitized input from an HTTP parameter * - * @param array $parsed An Array created using parse_url (splitting string parts into array elements) - * @return string Fully glued URL including Path & Query-Parameters, and Hash-Value + * @return string Combined string of all URL $_GET-Parameters */ function url_params() { $ret = ''; foreach ($_GET as $key => $val) { - $ret .= $key.'='.$val.'&'; + $ret .= htmlspecialchars($key, ENT_QUOTES, 'UTF-8') . '=' . htmlspecialchars($val, ENT_QUOTES, 'UTF-8') . '&'; } return substr($ret, 0, -1); } @@ -356,9 +355,8 @@ function url_params() /** * Combine Array parts of an URL back to an URL-String * - * @author [z]biko * @version 1.0 - * @since 1.0 function added + * @since 1.0 `[z]biko` function added * * @param array $parsed An Array created using parse_url (splitting string parts into array elements) * @return string Fully glued URL including Path & Query-Parameters, and Hash-Value @@ -411,7 +409,9 @@ function base64url_encode($data) */ function base64url_decode($data) { - return base64_decode(strtr($data, '-_', '+/') . str_repeat('=', 3-(3+strlen($data)) % 4 )); + $url_safe_data = strtr($data, '-_', '+/'); + $padded_data = str_pad($url_safe_data, strlen($url_safe_data) % 4, '=', STR_PAD_RIGHT); + return base64_decode($padded_data); } /** diff --git a/www/kurse.xml b/www/kurse.xml deleted file mode 100644 index 0393c17..0000000 --- a/www/kurse.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - Reference rates - - European Central Bank - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/www/models/gallery.php b/www/models/gallery.php index de21dd9..77e7660 100644 --- a/www/models/gallery.php +++ b/www/models/gallery.php @@ -33,12 +33,13 @@ public function __construct() * * @param integer $album_id Eine gültige Album-ID * @param integer $pic_id Einge gültige Pic-ID + * @return integer */ public function setAlbumId($album_id=null, $pic_id=null) { if(!empty($album_id)) $album_id = $album_id; if((!empty($pic_id) && $pic_id > 0) && empty($album_id)) $album_id = pic2album($pic_id); - return $album_id; + return intval($album_id); } /** diff --git a/www/peter.php b/www/peter.php index b33bc00..87a9989 100644 --- a/www/peter.php +++ b/www/peter.php @@ -12,7 +12,7 @@ ob_start(); /** File includes */ -require_once dirname(__FILE__).'/includes/main.inc.php'; +require_once __DIR__.'/includes/main.inc.php'; require_once MODELS_DIR.'core.model.php'; /** @@ -61,16 +61,6 @@ if ($peterGameId > 0) { /** Infos über das game holen */ - /* - $sql = 'SELECT - * - FROM peter_games pg - LEFT JOIN user u - ON pg.next_player = u.id - WHERE pg.game_id = '.$peterGameId; - $result = $db->query($sql,__FILE__,__LINE__,__FUNCTION__); - $rsg = $db->fetch($result); - */ $rsg = $model->getGamedata($peterGameId); /** Wenn dem Spiel noch beigetreten werden kann */ diff --git a/www/profil.php b/www/profil.php index 95247b1..7775cf7 100644 --- a/www/profil.php +++ b/www/profil.php @@ -10,18 +10,19 @@ * @include main.inc.php required * @include core.model.php required */ -require_once dirname(__FILE__).'/includes/main.inc.php'; +require_once __DIR__.'/includes/config.inc.php'; require_once MODELS_DIR.'core.model.php'; /** * Validate GET-Parameters */ -$doAction = null; -$user_id = null; -$userRegcode = null; -if (!empty($_GET['do']) && !is_numeric($_GET['do'])) $doAction = sanitize_userinput($_GET['do']); -if (!empty($_GET['regcode'])) $userRegcode = sanitize_userinput($_GET['regcode']); -if (!empty($_GET['user_id']) && is_numeric($_GET['user_id']) && (int)$_GET['user_id'] > 0) $user_id = sanitize_userinput((int)$_GET['user_id']); +$doAction = (isset($doAction) ? $doAction : (filter_input(INPUT_GET, 'do', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null)); // $_GET['do'] +$postDoAction = filter_input(INPUT_POST, 'do', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['do'] +$userRegcode = filter_input(INPUT_GET, 'regcode', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['regcode'] +$user_id = (isset($getUserId) ? intval($getUserId) : (filter_input(INPUT_GET, 'user_id', FILTER_VALIDATE_INT) ?? null)); // $_GET['user_id'] +$view_as_user = filter_input(INPUT_GET, 'viewas', FILTER_VALIDATE_INT) ?? null; // $_GET['viewas'] +$messageToUsers = filter_input(INPUT_GET, 'msgusers', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? null; // $_GET['msgusers'] +$messageSubject = filter_input(INPUT_GET, 'msgsubject', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? null; // $_GET['msgsubject'] //============================================================================= // Layout & code @@ -54,7 +55,7 @@ /** * Profil als anderen User anzeigen (DEV only!) */ - if (DEVELOPMENT === true && isset($_GET['viewas']) && (int)$_GET['viewas'] > 0) + if (zorgDebugger::log()->isDevelopmentEnvironment && $view_as_user > 0) { $model->showOtherprofile($smarty, $user, $_GET['viewas']); $smarty->assign('error', ['type' => 'info', 'dismissable' => 'false', 'title' => 'Userprofil wird angezeigt als '.$user->id2user((int)$_GET['viewas'], TRUE).'']); @@ -81,55 +82,58 @@ $model->showProfileupdate($smarty); /** Update Userprofile infos & settings */ - if (isset($_POST['do'])) + if (!empty($postDoAction)) { - if(isset($user->id) && $_POST['do'] === 'update' && $_FILES['image']['error'] === 4) + if ($user->id > 0) { - /** Validate $_POST-request */ - if (DEVELOPMENT) error_log(sprintf('[DEBUG] <%s:%d> $_POST: %s', __FILE__, __LINE__, print_r($_POST,true))); - if (count($_POST) > 1) + if($postDoAction === 'update' && $_FILES['image']['error'] === 4) { - $changeprofile_result = $user->exec_changeprofile($user->id, $_POST); + /** Validate $_POST-request */ + zorgDebugger::log()->debug('$_POST: %s', [print_r($_POST,true)]); + if (count($_POST) > 1) + { + $changeprofile_result = $user->exec_changeprofile($user->id, $_POST); + } + } + /** Upload and change new Userpic */ + if($postDoAction === 'update' && $_FILES['image']['error'] === 0) + { + $uploadimage_result = $user->exec_uploadimage($user->id, $_FILES); + } + /** Change User Password */ + if($postDoAction === 'change_password') + { + $newpassword_result = $user->exec_newpassword($user->id, $_POST['old_pass'], $_POST['new_pass'], $_POST['new_pass2']); } - } - /** Upload and change new Userpic */ - if(isset($user->id) && $_POST['do'] === 'update' && $_FILES['image']['error'] === 0) - { - $uploadimage_result = $user->exec_uploadimage($user->id, $_FILES); - } - /** Change User Password */ - if(isset($user->id) && $_POST['do'] === 'change_password') - { - $newpassword_result = $user->exec_newpassword($user->id, $_POST['old_pass'], $_POST['new_pass'], $_POST['new_pass2']); } /** * Error or Success message handling - */ - /* Userprofile change */ - if (isset($changeprofile_result[0])) { - if ($changeprofile_result[0] === TRUE) { - $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'true', 'title' => $changeprofile_result[1]]); - } else { - $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => t('userprofile-change-ok', 'user')]); - } + */ + /* Userprofile change */ + if (isset($changeprofile_result[0])) { + if ($changeprofile_result[0] === TRUE) { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'true', 'title' => $changeprofile_result[1]]); + } else { + $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => t('userprofile-change-ok', 'user')]); } - /** Userpic change */ - if (isset($uploadimage_result[0])) { - if ($uploadimage_result[0] === TRUE) { - $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'true', 'title' => $uploadimage_result[1]]); - } else { - $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => t('userpic-change-ok', 'user')]); - } + } + /** Userpic change */ + if (isset($uploadimage_result[0])) { + if ($uploadimage_result[0] === TRUE) { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'true', 'title' => $uploadimage_result[1]]); + } else { + $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => t('userpic-change-ok', 'user')]); } - /** New Password */ - if (isset($newpassword_result[0])) { - if ($newpassword_result[0] === TRUE) { - $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'true', 'title' => $newpassword_result[1]]); - } else { - $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => t('new-userpw-confirmation', 'user')]); - } + } + /** New Password */ + if (isset($newpassword_result[0])) { + if ($newpassword_result[0] === TRUE) { + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'true', 'title' => $newpassword_result[1]]); + } else { + $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => t('new-userpw-confirmation', 'user')]); } + } /** Instantiate a new, updated $user-Object (because new data...) */ $user = new usersystem(); @@ -147,13 +151,14 @@ /** * Userprofil anzeigen */ -if (!empty($user_id)) +if (!empty($user_id) && is_numeric($user_id) && $user_id>0) { $htmlOutput = null; $sidebarHtml = null; + $username = $user->id2user($user_id, true); - /** Validate required $_GET parameters */ - if (!is_numeric($user_id) || $user_id <= 0 || is_array($user_id) || $user->id2user($user_id) === false) + /** Check for invalid User ID */ + if ($username === false) { http_response_code(404); // Set response code 404 (not found) $model->showUnknownuser($smarty, $user_id); @@ -163,35 +168,34 @@ exit; } - $sql = 'SELECT * FROM user WHERE id = '.$user_id; - $result = $db->query($sql, __FILE__, __LINE__, 'Userprofil anzeigen'); - $rs = $db->fetch($result); - if (isset($_geaechtet[$user_id])) $smarty->assign('error', ['type' => 'info', 'dismissable' => 'true', 'title' => t('user-wird-geaechtet', 'user', $user->id2user($user_id, true))]); + // $sql = 'SELECT * FROM user WHERE id=?'; + // $result = $db->query($sql, __FILE__, __LINE__, 'Userprofil anzeigen', [$user_id]); + // $rs = $db->fetch($result); + if (isset($_geaechtet[$user_id])) $smarty->assign('error', ['type' => 'info', 'dismissable' => 'true', 'title' => t('user-wird-geaechtet', 'user', $username)]); - $htmlOutput .= '

'.(isset($rs['clan_tag']) && !empty($rs['clan_tag']) ? html_entity_decode($rs['clan_tag']) : '').html_entity_decode($rs['username']).'

'; - $htmlOutput .= ''; + $htmlOutput .= '

'.html_entity_decode($username).'

'; + $htmlOutput .= '';//style="width: 100%;max-width: 100%;" - /** User Addle */ - if (isset($user->id) && $user->id > 0 && $user_id != $user->id && $rs['addle']) + /** User Addle (nur wenn Viewer selber eingeloggt ist) */ + if ($user->is_loggedin() && $user_id !== $user->id && $user->userPlays('addle', $user_id)) { $sidebarHtml .= '

Addle

- +
'; } - /** User Messaging */ if($user->is_loggedin()) { - /** Der User das bin ich */ - if($user_id == $user->id) + /** User Messaging: der User das bin ich */ + if($user_id === $user->id) { /** User will eine neue Message senden */ - if(isset($_GET['newmsg'])) + if($doAction === 'newmsg') { - if(isset($_GET['msgusers']) && isset($_GET['msgsubject'])) { - $htmlOutput .= Messagesystem::getFormSend($_GET['msgusers'],$_GET['msgsubject'],''); + if(!empty($messageToUsers) && !empty($messageSubject)) { + $htmlOutput .= Messagesystem::getFormSend($messageToUsers, $messageSubject,''); } else { $htmlOutput .= Messagesystem::getFormSend(0,'',''); } @@ -201,17 +205,17 @@ $page = isset( $_GET['page'] ) ? $_GET['page'] : null; $sort = isset( $_GET['sort'] ) ? $_GET['sort'] : null; $order = isset( $_GET['order'] ) ? $_GET['order'] : null; - $htmlOutput .= Messagesystem::getInboxHTML($box, 11,$page, $sort, $order); + $htmlOutput .= Messagesystem::getInboxHTML($box, 11, $page, $sort, $order); } /** Der User ist jemand anderes */ } else { $htmlOutput .= Messagesystem::getFormSend(array($user_id), '', ''); } - } - /** User markierte Gallery-Pics */ - if ($user->is_loggedin()) $htmlOutput .= getUserPics($user_id, 0); + /** User markierte Gallery-Pics */ + if ($user->is_loggedin()) $htmlOutput .= getUserPics($user_id, 0); + } /** User Events */ $sidebarHtml .= $smarty->fetch('tpl:211'); @@ -231,6 +235,15 @@ exit; // make sure only Userprofile page is processed / displayed } +/** Malformatted User ID */ +else { + http_response_code(404); // Set response code 404 (not found) + $model->showUnknownuser($smarty, $user_id); + $smarty->assign('error', ['type' => 'warn', 'dismissable' => 'false', 'title' => t('invalid-id', 'user')]); + $smarty->display('file:layout/head.tpl'); + $smarty->display('file:layout/footer.tpl'); + exit; +} /** * Registrationsformular / User activation @@ -258,6 +271,7 @@ require_once INCLUDES_DIR.'g-recaptcha-src/autoload.php'; $reCaptchaApiKeys = ['key' => $_ENV['GOOGLE_RECAPTCHA_KEY'],'secret' => $_ENV['GOOGLE_RECAPTCHA_SECRET']]; $reCaptchaLang = $_ENV['GOOGLE_RECAPTCHA_LOCALE']; + $reCaptchaVerification = filter_input(INPUT_POST, 'g-recaptcha-response', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['g-recaptcha-response'] try { $reCaptcha = new \ReCaptcha\ReCaptcha($reCaptchaApiKeys['secret']); } catch(Exception $e) { @@ -266,26 +280,31 @@ } /** reCaptcha validieren */ - if (isset($_POST['g-recaptcha-response'])) + if (!empty($reCaptchaVerification)) { //$reCaptcha = new \ReCaptcha\ReCaptcha($reCaptchaApiKeys['secret']); - $resp = $reCaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']); + $resp = $reCaptcha->verify($reCaptchaVerification, $_SERVER['REMOTE_ADDR']); /** reCaptcha VALID */ if ($resp->isSuccess()) { - if (empty($_POST['new_username'])) $registerError = t('invalid-username', 'user'); - if (empty($_POST['new_email'])) $registerError = t('invalid-email', 'user'); - if (empty($_POST['new_password']) || empty($_POST['new_password2'])) $registerError = t('invalid-userpw-missing', 'user'); - if ($_POST['new_password'] != $_POST['new_password2']) $registerError = t('invalid-userpw-match', 'user'); - if (!check_email($_POST['new_email'])) $registerError = t('invalid-email', 'user'); + $registerError = null; + $newUsername = htmlentities(sanitize_userinput(filter_input(INPUT_POST, 'new_username', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR))) ?? null; // $_POST['new_username'] + $newEmail = filter_input(INPUT_POST, 'new_email', FILTER_VALIDATE_EMAIL) ?? null; // $_POST['new_email'] + $newPassword = $user->crypt_pw($_POST['new_password2']); + $comparePassword = password_verify($_POST['new_password'], $newPassword); + if (empty($newUsername)) $registerError = t('invalid-username', 'user'); + if (empty($newEmail)) $registerError = t('invalid-email', 'user'); + if (!check_email($newEmail)) $registerError = t('invalid-email', 'user'); + if (empty($newPassword)) $registerError = t('invalid-userpw-missing', 'user'); + if (!$comparePassword) $registerError = t('invalid-userpw-match', 'user'); /** Userregistrierung schaut gut aus - User anlegen probieren */ - if (!isset($registerError) || empty($registerError)) + if (empty($registerError)) { - $createUserResult = $user->create_newuser(htmlentities($_POST['new_username']), $_POST['new_password'], $_POST['new_password2'], $_POST['new_email']); - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> create_newuser() Result: %s', __FILE__, __LINE__, (is_bool($createUserResult)?'true':$createUserResult))); - if (is_bool($createUserResult) && $createUserResult===true) { + $createUserResult = $user->create_newuser($newUsername, $newPassword, $newEmail); + zorgDebugger::log()->debug('Result: %s', [(is_bool($createUserResult)?'true':$createUserResult)]); + if ($createUserResult===true) { $error = t('account-confirmation', 'user'); $smarty->assign('error', ['type' => 'success', 'dismissable' => 'true', 'title' => $error]); } else { @@ -359,9 +378,9 @@ /** * Passwort vergessen Formular */ - if (!empty($_POST['email'])) + $email2check = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) ?? null; // $_POST['email'] + if (!empty($email2check)) { - $email2check = sanitize_userinput($_POST['email']); $checkEmail = (!empty($email2check) ? check_email($email2check) : null); if ($checkEmail === false) { @@ -396,7 +415,7 @@ */ elseif (!empty($userRegcode)) { - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> $userRegcode: %s', __FILE__, __LINE__, $userRegcode)); + zorgDebugger::log()->debug('$userRegcode: %s', [$userRegcode]); $user_activation_result = $user->activate_user($userRegcode); $model->showActivation($smarty, $user->error_message); if ($user_activation_result === true) $smarty->assign('error', ['type' => 'success', 'dismissable' => 'false', 'title' => t('account-activated', 'user'), 'message' => t('account-activated-text', 'user')]); diff --git a/www/scripts/rezepte.php b/www/scripts/rezepte.php index 3f64877..1bf142d 100644 --- a/www/scripts/rezepte.php +++ b/www/scripts/rezepte.php @@ -5,12 +5,8 @@ */ global $db, $user, $smarty; +/** Fetch all Rezepte by Title */ +// FIXME move this to rezepte.inc.php $f = $db->query('SELECT * FROM rezepte ORDER by title ASC', __FILE__, __LINE__, 'SELECT FROM rezepte'); -$list = array(); -while ($f = $db->fetch($g)) -{ - array_push($list, $g); -} - -$smarty->assign('rezepte', $list); +$smarty->assign('rezepte', $db->fetch($f)); diff --git a/www/scripts/stockbroker.php b/www/scripts/stockbroker.php index 799a1de..19118b3 100644 --- a/www/scripts/stockbroker.php +++ b/www/scripts/stockbroker.php @@ -5,18 +5,18 @@ */ /** File includes */ -require_once dirname(__FILE__).'/../includes/stockbroker.inc.php'; +require_once __DIR__.'/../includes/stockbroker.inc.php'; require_once INCLUDES_DIR.'usersystem.inc.php'; -global $smarty, $user; +global $smarty, $user; //$smarty->assign("kurse_aktuell", Stockbroker::getKurseNeuste(10)); -$smarty->assign("kurse_tagesgewinner", Stockbroker::getTodaysWinners()); -$smarty->assign("kurse_tagesverlierer", Stockbroker::getTodaysLosers()); +$smarty->assign("kurse_tagesgewinner", $stockbroker->getTodaysWinners()); +$smarty->assign("kurse_tagesverlierer", $stockbroker->getTodaysLosers()); -$smarty->assign("mosttraded", Stockbroker::getYesterdaysMosttraded()); -$smarty->assign("bargeld", Stockbroker::getBargeld($user->id)); -$smarty->assign("currentproperty", Stockbroker::getStocksOwned($user->id)); -$smarty->assign("highscore", Stockbroker::getHighscore()); -$smarty->assign("mytrades", Stockbroker::getTrades($user->id)); -$smarty->assign("stock_warnings", Stockbroker::getWarnings($user->id)); +$smarty->assign("mosttraded", $stockbroker->getYesterdaysMosttraded()); +if ($user->is_loggedin()) $smarty->assign("bargeld", $stockbroker->getBargeld($user->id)); +if ($user->is_loggedin()) $smarty->assign("currentproperty", $stockbroker->getStocksOwned($user->id)); +$smarty->assign("highscore", $stockbroker->getHighscore()); +if ($user->is_loggedin()) $smarty->assign("mytrades", $stockbroker->getTrades($user->id)); +if ($user->is_loggedin()) $smarty->assign("stock_warnings", $stockbroker->getWarnings($user->id)); diff --git a/www/seti_example.php b/www/seti_example.php index b124742..85ca068 100644 --- a/www/seti_example.php +++ b/www/seti_example.php @@ -26,9 +26,9 @@ /** * Initialise SETI Stats Class-Object */ - $seti = new SetiStats(); - $seti->setEmail($_ENV['SETI_EMAIL']); - $seti->Init(); + $seti = new SetiStats($_ENV['SETI_EMAIL']); + // $seti->setEmail(); + // $seti->Init(); REPLACED WITH __construct($user_email) print '' .'' diff --git a/www/templates/layout/sidebar.tpl b/www/templates/layout/sidebar.tpl index 9071b31..8e8f1e1 100644 --- a/www/templates/layout/sidebar.tpl +++ b/www/templates/layout/sidebar.tpl @@ -1,4 +1,4 @@ -{if $tplroot.sidebar_tpl neq '' || $sidebarHtml neq ''} +{if $tplroot.sidebar_tpl neq '' || isset($sidebarHtml) && $sidebarHtml neq ''} {else} -{/if} \ No newline at end of file +{/if} diff --git a/www/wetten.php b/www/wetten.php index 668d0b6..ccff7de 100644 --- a/www/wetten.php +++ b/www/wetten.php @@ -9,7 +9,7 @@ /** * File includes */ -require_once dirname(__FILE__).'/includes/main.inc.php'; +require_once __DIR__.'/includes/main.inc.php'; require_once INCLUDES_DIR.'wetten.inc.php'; require_once MODELS_DIR.'core.model.php'; @@ -19,16 +19,16 @@ $model = new MVC\Wetten(); /** - * Validate GET-Parameters + * Input validation & sanitization */ -if (!empty($_GET['id'])) $wette = (int)$_GET['id']; -if (!empty($_GET['eintrag'])) $getEintrag = (string)$_GET['eintrag']; +$wette = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?? 0; // $_GET['id'] +$getEintrag = filter_input(INPUT_GET, 'eintrag', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['eintrag'] /** Post actions ausführen/entgegennehmen */ wetten::exec(); /** Wettbüro Übersicht */ -if (empty($wette) || $wette <= 0) +if ($wette <= 0) { $model->showOverview($smarty); if (isset($getEintrag) && $getEintrag == true) @@ -46,13 +46,16 @@ echo '

zorg Wettbüro

'; /** offene wetten auflisten */ - wetten::listopen(); + //wetten::listopen(); + wetten::listwetten(); /** laufende wetten auflisten */ - wetten::listlaufende(); - + //wetten::listlaufende(); + wetten::listwetten('laeuft'); + /** geschlossene wetten auflisten */ - wetten::listclosed(); + //wetten::listclosed(); + wetten::listwetten('geschlossen'); } /** Wette anzeigen */ From 05c04c0436f186b80f0fc28c725f410064b4d5cd Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 10 Jan 2024 21:06:33 +0100 Subject: [PATCH 2/8] Mitigates SQL injects through Prepared Statements --- www/actions/chess.php | 154 +++-- www/actions/commenting.php | 42 +- www/actions/error_action.php | 51 +- www/actions/poll_edit.php | 4 +- www/actions/poll_state.php | 20 +- www/actions/poll_unvote.php | 13 +- www/actions/poll_vote.php | 19 +- www/actions/tpleditor.php | 53 +- www/addle.php | 40 +- www/aklick.php | 83 +-- www/books.php | 361 +++++----- www/forum.php | 40 +- www/frets_upload.php | 62 +- www/includes/anficker.inc.php | 153 ++--- www/includes/chess.inc.php | 122 ++-- www/includes/comments.res.php | 93 ++- www/includes/events.inc.php | 86 +-- www/includes/forum.inc.php | 544 +++++++--------- www/includes/gallery.inc.php | 50 +- www/includes/hz_game.inc.php | 328 ++++------ www/includes/messagesystem.inc.php | 183 ++---- www/includes/peter.inc.php | 614 ++++++------------ www/includes/poll.inc.php | 81 ++- www/includes/schach.inc.php | 90 +-- www/includes/setiathome.inc.php | 77 +-- www/includes/smarty.fnc.php | 33 +- www/includes/smarty.inc.php | 149 +++-- www/includes/spaceweather.inc.php | 18 +- www/includes/stockbroker.inc.php | 470 ++++---------- www/includes/strings.array.php | 17 + www/includes/tpleditor.inc.php | 10 +- www/includes/usersystem.inc.php | 227 ++++--- www/includes/wetten.inc.php | 591 +++++++++-------- www/index.php | 108 +-- www/scripts/chatlog_bak.php | 16 +- www/scripts/file_manager.php | 132 ++-- www/scripts/tpleditor.php | 12 +- www/seti_xml.php | 73 +-- www/stl2.php | 583 ++++------------- .../partials/messages/messages_list.tpl | 2 +- 40 files changed, 2438 insertions(+), 3366 deletions(-) diff --git a/www/actions/chess.php b/www/actions/chess.php index 56250ef..60f213f 100644 --- a/www/actions/chess.php +++ b/www/actions/chess.php @@ -1,102 +1,114 @@ 0 && isset($_GET['from']) && isset($_GET['to'])) +/** Input validation and sanitization */ +$doAction = filter_input(INPUT_GET, 'do', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['do'] +$gameId = filter_input(INPUT_GET, 'game', FILTER_VALIDATE_INT) ?? 0; // $_GET['game'] +$fromField = filter_input(INPUT_GET, 'from', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['from'] +$toField = filter_input(INPUT_GET, 'to', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['to'] +$viewForm = filter_input(INPUT_POST, 'formid', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['formid'] +$userId = filter_input(INPUT_POST, 'user', FILTER_VALIDATE_INT) ?? null; // $_POST['user'] + +if (isset($gameId) && $gameId > 0) { - $e = $db->query('SELECT *, IF(white=next_turn, "w", "b") player - FROM chess_games - WHERE id='.$_GET['game'].' AND next_turn='.$user->id, - __FILE__, __LINE__, 'move'); - $d = $db->fetch($e); + /** move */ + if (!empty($fromField) && !empty($toField)) + { + $e = $db->query('SELECT *, IF(white=next_turn, "w", "b") player FROM chess_games WHERE id=? AND next_turn=?', + __FILE__, __LINE__, 'move', [$gameId, $user->id]); + $d = $db->fetch($e); - - if ($d && Chess::is_valid_position($_GET['from']) && Chess::is_valid_position($_GET['to']) - && Chess::do_move($d['id'], $d['player'], $_GET['from'], $_GET['to']) - ) { - unset($_GET['from']); - unset($_GET['to']); - header('Location: /?'.url_params()); - }else{ - echo "Invalid chess move:
game = ".$_GET['game']."
from = ".$_GET['from']."
to = ".$_GET['to']; + + if ($d && $chess->is_valid_position($fromField) && $chess->is_valid_position($toField) + && $chess->do_move($d['id'], $d['player'], $fromField, $toField) + ) { + unset($_GET['from']); + unset($_GET['to']); + header('Location: /?'.url_params()); + }else{ + echo "Invalid chess move:
game = ".$gameId."
from = ".$fromField."
to = ".$toField; + } exit; } -} -/** offer remis */ -if (isset($_GET['game']) && $_GET['game'] > 0 && isset($_GET['do']) && $_GET['do'] == 'offer_remis') -{ - $e = $db->query('SELECT * FROM chess_games WHERE id='.$_GET['game'].' AND next_turn='.$user->id, __FILE__, __LINE__, 'offer remis'); - $d = $db->fetch($e); - if ($d) { - Chess::do_offer_remis($_GET['game']); - unset($_GET['do']); - header("Location: /?".url_params()); - }else{ - echo "'offer remis' is not allowed."; + /** offer remis */ + if ($doAction === 'offer_remis') + { + $e = $db->query('SELECT * FROM chess_games WHERE id=? AND next_turn=?', __FILE__, __LINE__, 'offer remis', [$gameId, $user->id]); + $d = $db->fetch($e); + if ($d) { + $chess->do_offer_remis($gameId); + + unset($_GET['do']); + header("Location: /?".url_params()); + }else{ + echo "'offer remis' is not allowed."; + } exit; } -} -/** accept remis */ -if (isset($_GET['game']) && $_GET['game'] > 0 && isset($_GET['do']) && $_GET['do'] == 'accept_remis') -{ - $e = $db->query('SELECT * - FROM chess_games - WHERE id='.$_GET['game'].' AND (white='.$user->id.' OR black='.$user->id.') AND next_turn!='.$user->id.' AND offering_remis="1"', - __FILE__, __LINE__, 'accept remis'); - $d = $db->fetch($e); - if ($d) { - Chess::do_remis($_GET['game']); - unset($_GET['do']); - header("Location: /?".url_params()); - }else{ - echo "'accept remis' is not allowed."; + /** accept remis */ + if ($doAction === 'accept_remis') + { + $e = $db->query('SELECT * FROM chess_games WHERE id=? AND (white=? OR black=?) AND next_turn!=? AND offering_remis="1"', + __FILE__, __LINE__, 'accept remis', [$gameId, $user->id, $user->id, $user->id]); + $d = $db->fetch($e); + if ($d) { + $chess->do_remis($gameId); + + unset($_GET['do']); + header("Location: /?".url_params()); + }else{ + echo "'accept remis' is not allowed."; + } exit; } -} -/** deny remis */ -if (isset($_GET['game']) && $_GET['game'] > 0 && isset($_GET['do']) && $_GET['do'] == 'deny_remis') -{ - $e = $db->query('SELECT * - FROM chess_games - WHERE id='.$_GET['game'].' AND (white='.$user->id.' OR black='.$user->id.') AND next_turn!='.$user->id.' AND offering_remis="1"', - __FILE__, __LINE__, 'deny remis'); - $d = $db->fetch($e); - if ($d) { - Chess::deny_remis($_GET['game']); - header("Location: /?".url_params()); - }else{ - echo "'deny remis' is not allowed"; + /** deny remis */ + if ($doAction === 'deny_remis') + { + $e = $db->query('SELECT * FROM chess_games WHERE id=? AND (white=? OR black=?) AND next_turn!=? AND offering_remis="1"', + __FILE__, __LINE__, 'deny remis', [$gameId, $user->id, $user->id, $user->id]); + $d = $db->fetch($e); + if ($d) { + $chess->deny_remis($gameId); + + unset($_GET['do']); + header("Location: /?".url_params()); + }else{ + echo "'deny remis' is not allowed"; + } + exit; + } + + /** aufgeben */ + if ($doAction === 'aufgeben') + { + $chess->aufgabe($gameId); + + unset($_GET['do']); + header("Location: /tpl/141?".url_params()); exit; } } /** start new game */ -if (isset($_POST['formid']) && $_POST['formid'] == 'chess_start') +elseif ($viewForm === 'chess_start') { - if (Chess::new_game($_POST['user'])) { + if ($chess->new_game($userId)) { header("Location: /?tpl=139"); }else{ - echo "invalid chess_start:
user = ".$_POST['user']; - exit; + echo "invalid chess_start:
user = ".$userId; } -} - -/** aufgeben */ -if (isset($_GET['game']) && $_GET['game'] > 0 && isset($_GET['do']) && $_GET['do'] == 'aufgeben') -{ - Chess::aufgabe($_GET['game']); - - unset($_GET['do']); - header("Location: /tpl/141?".url_params()); + exit; } diff --git a/www/actions/commenting.php b/www/actions/commenting.php index 50f3551..416ecd9 100644 --- a/www/actions/commenting.php +++ b/www/actions/commenting.php @@ -1,33 +1,45 @@ is_loggedin()) { + http_response_code(403); // Set response code 403 (Access denied) + user_error('Access denied', E_USER_ERROR); +} +if(empty($comment) || $comment <= 0) { + http_response_code(404); // Set response code 404 (Not found) + user_error('Invalid comment: '.$comment, E_USER_ERROR); +} + /** Subscribe */ -if(isset($_GET['do']) && $_GET['do'] == 'subscribe') +if($doAction === 'subscribe') { - $sql = 'INSERT INTO comments_subscriptions (board, comment_id, user_id) - VALUES("'.$_GET['board'].'", '.$_GET['comment_id'].', '.$user->id.')'; - $db->query($sql, __FILE__, __LINE__, 'Commenting subscribe'); - - header("Location: ".base64url_decode($_GET['url'])); - exit; + $sql = 'INSERT INTO comments_subscriptions (board, comment_id, user_id) VALUES(?, ?, ?)'; + $db->query($sql, __FILE__, __LINE__, 'Commenting subscribe', [$board, $comment, $user->id]); } /** Unsubscribe */ -if(isset($_GET['do']) && $_GET['do'] == 'unsubscribe') +elseif($doAction === 'unsubscribe' && $user->is_loggedin()) { - $sql = 'DELETE FROM comments_subscriptions - WHERE board = "'.$_GET['board'].'" AND comment_id = '.$_GET['comment_id'].' AND user_id = '.$user->id; - $db->query($sql, __FILE__, __LINE__, 'Commenting unsubscribe'); - - header("Location: ".base64url_decode($_GET['url'])); - exit; + $sql = 'DELETE FROM comments_subscriptions WHERE board=? AND comment_id=? AND user_id=?'; + $db->query($sql, __FILE__, __LINE__, 'Commenting unsubscribe', [$board, $comment, $user->id]); } + +header("Location: ".$redirect); +exit; diff --git a/www/actions/error_action.php b/www/actions/error_action.php index 226f5e3..a5298cf 100644 --- a/www/actions/error_action.php +++ b/www/actions/error_action.php @@ -1,39 +1,52 @@ 0) +if($user->is_loggedin() && count($_POST) > 0) { + /** Input validation & sanitization */ + $errorId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) ?? null; // $_GET['id'] + $tplId = filter_input(INPUT_GET, 'tpl', FILTER_VALIDATE_INT) ?? null; // $_GET['tpl'] + $doDelete = filter_input(INPUT_POST, 'del', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_POST['del'] + $showQuery = filter_input(INPUT_POST, 'query', FILTER_SANITIZE_FULL_SPECIAL_CHARS) ?? 0; // $_POST['query'] + $del_ids = filter_input(INPUT_POST, 'to_del', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY) ?? []; // $_POST['to_del'] + $showNum = filter_input(INPUT_POST, 'num', FILTER_VALIDATE_INT) ?? 0; // $_POST['num'] + $urlParams = ''; + /** Delete SQL-Error */ - if($_POST['del'] && !empty($_GET['id'])) + if($doDelete === 'delete' && $errorId>0) { - $sql_del = 'DELETE FROM sql_error WHERE id='.$_GET['id']; - $db->query($sql_del, __FILE__, __LINE__, 'Delete SQL-Error'); - header('Location: /tpl/'.$_GET['tpl']); - die(); + $sql_del = 'DELETE FROM sql_error WHERE id=?'; + $db->query($sql_del, __FILE__, __LINE__, 'Delete SQL-Error', [$errorId]); } /** Show Query details */ - if($_POST['query']) + if(!empty($showQuery)) { - header('Location: /tpl/'.$_GET['tpl'].'&id='.$_GET['id'].'&query='.base64url_encode($_POST['query'])); - die(); + $urlParams = '?id='.$errorId.'&query='.base64url_encode($showQuery); } /** Delete multiple SQL-Errors */ - if(count($_POST['to_del']) > 0) + if(count($del_ids) > 0 && $user->type >= USER_MEMBER) { - $del_ids = implode(',', $_POST['to_del']); - $sql = 'DELETE FROM sql_error WHERE id IN ('.$del_ids.')'; - $db->query($sql, __FILE__, __LINE__, 'Delete multiple SQL-Errors'); - header('Location: /tpl/'.$_GET['tpl']); - die(); + $placeholders = implode(',', array_fill(0, count($del_ids), '?')); + $sql = 'DELETE FROM sql_error WHERE id IN (' . $placeholders . ')'; + $params = array_map('intval', $del_ids); // $del_ids must be integers + $db->query($sql, __FILE__, __LINE__, 'Delete multiple SQL-Errors', $params); } /** Change displayed number of SQL-Error */ - if($_POST['num']) + if($showNum > 0) { $_SESSION['error_num'] = $_POST['num']; - header('Location: /tpl/'.$_GET['tpl'].'?error_num='.$_POST['num']); - die(); + $urlParams = '?error_num='.$showNum; } + + header('Location: /tpl/'.$tplId.$urlParams); + exit; +} +else { + http_response_code(403); // Set response code 403 (Access denied) + user_error('Access denied', E_USER_ERROR); } diff --git a/www/actions/poll_edit.php b/www/actions/poll_edit.php index a97c80b..a027bc3 100644 --- a/www/actions/poll_edit.php +++ b/www/actions/poll_edit.php @@ -8,9 +8,9 @@ */ /** * File includes. - * @include main.inc.php + * @include poll.inc.php */ -require_once dirname(__FILE__).'/../includes/main.inc.php'; +require_once __DIR__.'/../includes/poll.inc.php'; /** User not logged in? Error in his face! */ if (!$user->is_loggedin()) { diff --git a/www/actions/poll_state.php b/www/actions/poll_state.php index 3f336e0..b06b60b 100644 --- a/www/actions/poll_state.php +++ b/www/actions/poll_state.php @@ -3,32 +3,36 @@ * Poll State change (close/open). * @package zorg\Polls */ -require_once dirname(__FILE__).'/../includes/poll.inc.php'; +require_once __DIR__.'/../includes/poll.inc.php'; + +/** Input validation and sanitization */ +$pollId = filter_input(INPUT_GET, 'poll', FILTER_VALIDATE_INT) ?? null; // $_GET['poll'] +$pollState = filter_input(INPUT_GET, 'state', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR) ?? null; // $_GET['state'] if (!$user->is_loggedin()) { http_response_code(403); // Set response code 403 (Access denied) user_error('Access denied', E_USER_ERROR); } -if (!in_array($_GET['state'], array('open', 'closed'))) { +if (!in_array($pollState, array('open', 'closed'))) { http_response_code(400); // Set response code 400 (Bad request) - user_error('Invalid state "'.$_GET['state'].'"', E_USER_ERROR); + user_error('Invalid state "'.$pollState.'"', E_USER_ERROR); } -if(!isset($_GET['poll']) || !is_numeric($_GET['poll']) || (int)$_GET['poll'] <= 0) { +if(empty($pollId) || $pollId <= 0) { http_response_code(404); // Set response code 404 (Not found) - user_error('Invalid poll-id: '.$_GET['poll'], E_USER_ERROR); + user_error('Invalid poll-id: '.$pollId, E_USER_ERROR); } $polls = new Polls(); -$e = $db->query('SELECT * FROM polls WHERE user='.$user->id.' AND id='.$_GET['poll'], __FILE__, __LINE__, 'SELECT'); +$e = $db->query('SELECT * FROM polls WHERE user=? AND id=?', __FILE__, __LINE__, 'SELECT', [$user->id, $pollId]); $d = $db->fetch($e); if ($d && $polls->user_has_vote_permission($d['type'])) { - $db->query('UPDATE polls SET state="'.$_GET['state'].'" WHERE id='.$_GET['poll'], __FILE__, __LINE__, 'UPDATE'); + $db->query('UPDATE polls SET state=? WHERE id=?', __FILE__, __LINE__, 'UPDATE', [$pollState, $pollId]); // @TODO Stop Telegram-Poll on close via chat_id using https://core.telegram.org/bots/api#stoppoll }else{ - user_error('Invalid poll_change_state (poll='.$_GET['poll'].' & state='.$_GET['state'].')', E_USER_ERROR); + user_error('Invalid poll_change_state (poll='.$pollId.' & state='.$pollState.')', E_USER_ERROR); } unset($_GET['poll']); diff --git a/www/actions/poll_unvote.php b/www/actions/poll_unvote.php index 3c41f4a..d9479d8 100644 --- a/www/actions/poll_unvote.php +++ b/www/actions/poll_unvote.php @@ -5,24 +5,27 @@ */ require_once dirname(__FILE__).'/../includes/poll.inc.php'; +/** Input validation and sanitization */ +$pollId = filter_input(INPUT_GET, 'poll', FILTER_VALIDATE_INT) ?? null; // $_GET['poll'] + if(!$user->is_loggedin()) { http_response_code(403); // Set response code 403 (Access denied) user_error('Du bist nicht eingeloggt', E_USER_ERROR); } -if(!isset($_GET['poll']) || !is_numeric($_GET['poll']) || (int)$_GET['poll'] <= 0) { +if(empty($pollId) || $pollId <= 0) { http_response_code(404); // Set response code 404 (Not found) - user_error('Invalid poll-id: '.$_GET['poll'], E_USER_ERROR); + user_error('Invalid poll-id: '.$pollId, E_USER_ERROR); } $polls = new Polls(); -$e = $db->query('SELECT * FROM polls WHERE id='.$_GET['poll'], __FILE__, __LINE__, 'SELECT'); +$e = $db->query('SELECT * FROM polls WHERE id=?', __FILE__, __LINE__, 'SELECT', [$pollId]); $d = $db->fetch($e); if ($d['state'] === 'closed' || !$polls->user_has_vote_permission($d['type'])) { - user_error('Poll "'.$_GET['poll'].'" is closed', E_USER_ERROR); + user_error('Poll "'.$pollId.'" is closed', E_USER_ERROR); } else { - $db->query('DELETE FROM poll_votes WHERE poll='.$_GET['poll'].' AND user='.$user->id, __FILE__, __LINE__, 'DELETE'); + $db->query('DELETE FROM poll_votes WHERE poll=? AND user=?', __FILE__, __LINE__, 'DELETE', [$pollId, $user->id]); unset($_GET['poll']); } diff --git a/www/actions/poll_vote.php b/www/actions/poll_vote.php index 7213624..13da307 100644 --- a/www/actions/poll_vote.php +++ b/www/actions/poll_vote.php @@ -3,34 +3,37 @@ * Poll Voting. * @packages zorg\Polls */ -require_once dirname(__FILE__).'/../includes/poll.inc.php'; +require_once __DIR__.'/../includes/poll.inc.php'; + +/** Input validation and sanitization */ +$poll = (filter_input(INPUT_POST, 'poll', FILTER_VALIDATE_INT) ?? (filter_input(INPUT_GET, 'poll', FILTER_VALIDATE_INT) ?? null)); // $_POST['poll'] / $_GET['poll'] +$vote = (filter_input(INPUT_POST, 'vote', FILTER_VALIDATE_INT) ?? (filter_input(INPUT_GET, 'vote', FILTER_VALIDATE_INT) ?? null)); // $_POST['vote'] / $_GET['vote'] +$redirect = base64url_decode(filter_input(INPUT_GET, 'redirect', FILTER_DEFAULT, FILTER_REQUIRE_SCALAR)) ?? null; // $_GET['redirect'] if (!$user->is_loggedin()) { http_response_code(403); // Set response code 403 (Access denied) user_error('Access denied', E_USER_ERROR); } -if ((!isset($_POST['poll']) || !isset($_POST['vote'])) && (!isset($_GET['poll']) || !isset($_GET['vote']))) { +if (empty($poll) || $poll <= 0 || empty($vote) || $vote <= 0) { http_response_code(403); // Set response code 403 (Access denied) user_error('Nice try', E_USER_ERROR); } -$poll = (!empty($_POST['poll']) ? $_POST['poll'] : (!empty($_GET['poll']) ? $_GET['poll'] : null)); -$vote = (!empty($_POST['vote']) ? $_POST['vote'] : (!empty($_GET['vote']) ? $_GET['vote'] : null)); - if ($poll !== null && $vote !== null) { $polls = new Polls(); - $e = $db->query('SELECT p.* FROM polls p, poll_answers a WHERE a.poll=p.id AND p.id='.$poll.' AND a.id='.$vote, __FILE__, __LINE__, __FILE__); + $e = $db->query('SELECT p.* FROM polls p, poll_answers a WHERE a.poll=p.id AND p.id=? AND a.id=?', __FILE__, __LINE__, __FILE__, [$poll, $vote]); $d = $db->fetch($e); if ($d && $d['state']=='open' && $polls->user_has_vote_permission($d['type'])) { - $db->query('REPLACE INTO poll_votes (poll, user, answer) VALUES ('.$poll.', '.$user->id.', '.$vote.')', __FILE__, __LINE__, 'REPLACE INTO poll_votes'); + $db->query('REPLACE INTO poll_votes (poll, user, answer) VALUES (?, ?, ?)', + __FILE__, __LINE__, 'REPLACE INTO poll_votes', [$poll, $user->id, $vote]); }else{ user_error('Invalid Poll/Vote "'.$poll.' / '.$vote.'"', E_USER_ERROR); } - header('Location: '.base64url_decode($_GET['redirect'])); + header('Location: '.$redirect); exit; } else { diff --git a/www/actions/tpleditor.php b/www/actions/tpleditor.php index 7d0c4a1..e7c3bdc 100644 --- a/www/actions/tpleditor.php +++ b/www/actions/tpleditor.php @@ -8,9 +8,10 @@ /** * File includes */ -require_once dirname(__FILE__).'/../includes/tpleditor.inc.php'; +require_once __DIR__.'/../includes/tpleditor.inc.php'; /** Initialize Vars */ +global $notification; $error = null; $state = null; $access_error = null; @@ -89,7 +90,7 @@ $updated_tplid = $frm['id']; $return_url = '/?tpl='.$updated_tplid; - $return_url .= '&created'; + $return_url .= '&created=1'; $smarty->assign('tplupdnew', 1); $state = t('created', 'tpl', $frm['id']); @@ -119,7 +120,7 @@ ,'sidebar_tpl' => $frm['sidebar_tpl'] ,'allow_comments' => $frm['allow_comments'] ,'error' => null - ,'owner' => $user->id + //,'owner' => $user->id // ähhh nei, Owner söll nöd change?! ,'update_user' => $user->id ,'last_update' => timestamp(true) ]; @@ -136,28 +137,36 @@ $db->query('DELETE FROM tpl_menus WHERE tpl_id=?', __FILE__, __LINE__, 'DELETE FROM tpl_menus', [$frm['id']]); if (!empty($_POST['frm']['menus'])) { - $tplmenusInsertData = null; + $tplmenusInsertData = []; + $params = []; foreach ($_POST['frm']['menus'] as $menu_id) { - /** Note: only works when getting Array directly from $_POST, not via $frm. - Don't know why, cost me like 2 hours to figure this out WTF */ - if (!empty($menu_id)) $tplmenusInsertData[] = sprintf('(%d, %d)', $frm['id'], $menu_id); + if ($menu_id > 0) { + $tplmenusInsertData[] = '(?, ?)'; + $params[] = $frm['id']; + $params[] = $menu_id; + } } - $db->query('INSERT INTO tpl_menus (tpl_id, menu_id) VALUES '.implode(',',$tplmenusInsertData), __FILE__, __LINE__, 'Link Template to selected Menus'); // add new - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Template ID #%d linked to Menus: %s', __FILE__, __LINE__, $frm['id'], print_r($tplmenusInsertData, true))); + $sql = 'INSERT INTO tpl_menus (tpl_id, menu_id) VALUES '.implode(',', $tplmenusInsertData); + zorgDebugger::log()->debug('Template ID #%d linked to Menus: %s%s', [$frm['id'], $sql, print_r($params, true)]); + $db->query($sql, __FILE__, __LINE__, 'Link Template to selected Menus', $params); } /** Packages: remove all links between Template & Packages, relink selected Packages */ $db->query('DELETE FROM tpl_packages WHERE tpl_id=?', __FILE__, __LINE__, 'DELETE FROM tpl_packages', [$frm['id']]); if (!empty($_POST['frm']['packages'])) { - $tplpackagesInsertData = null; + $tplpackagesInsertData = []; + $params = []; foreach ($_POST['frm']['packages'] as $package_id) { - /** Note: only works when getting Array directly from $_POST, not via $frm. - Don't know why, cost me like 2 hours to figure this out WTF */ - if (!empty($package_id)) $tplpackagesInsertData[] = sprintf('(%d, %d)', $frm['id'], $package_id); + if (!empty($package_id)) { + $tplpackagesInsertData[] = '(?, ?)'; + $params[] = $frm['id']; + $params[] = $package_id; + } } - $db->query('INSERT INTO tpl_packages (tpl_id, package_id) VALUES '.implode(',',$tplpackagesInsertData), __FILE__, __LINE__, 'Link Template to selected Packages'); // add new - if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> Template ID #%d linked to Packages: %s', __FILE__, __LINE__, $frm['id'], print_r($tplpackagesInsertData, true))); + $sql = 'INSERT INTO tpl_packages (tpl_id, package_id) VALUES ' . implode(',', $tplpackagesInsertData); + zorgDebugger::log()->debug('Template ID #%d linked to Packages: %s%s', [$frm['id'], $sql, print_r($params, true)]); + $db->query($sql, __FILE__, __LINE__, 'Link Template to selected Packages', $params); } } } @@ -208,7 +217,7 @@ /** If compile-error, write it to the template in the DB */ if (!empty($error)) { - $db->query('UPDATE templates SET error="'.addslashes($error).'" WHERE id='.$frm['id'], __FILE__, __LINE__, 'UPDATE templates (tplid)'); + $db->query('UPDATE templates SET error=? WHERE id=?', __FILE__, __LINE__, 'UPDATE templates (tplid)', [$error, $frm['id']]); } } @@ -218,11 +227,21 @@ /** Unlock Template for editing - only if no $error occurred */ tpleditor_unlock($updated_tplid); if (!isset($return_url) || empty($return_url)) $return_url = '/?tpl='.$updated_tplid; - $return_url .= '&updated'; + $return_url .= '&updated=1'; $updated_tplid = null; $enable_tpleditor = null; + /** Notify Template-Owner about change - if done by other User */ + $notifyOtherTplOwner = tpl_get_associated_user($frm['id']); + zorgDebugger::log()->debug('Notify Template-Owner: owner %d <-- edit by %d', [$notifyOtherTplOwner, $user->id]); + if ($notifyOtherTplOwner !== $user->id) + { + $notification_text = t('change-notification-owner', 'tpl', [ $user->id2user($user->id), $frm['id'], $frm['title'] ]); + $notification_status = $notification->send($notifyOtherTplOwner, 'messagesystem', ['from_user_id'=>$user->id, 'subject'=>t('change-notification-owner-subject', 'tpl'), 'text'=>$notification_text, 'message'=>$notification_text]); + zorgDebugger::log()->debug('$_TPLROOT[owner] Notification: %s', [$notification_status ? 'true' : 'false']); + } + if (DEVELOPMENT === true) error_log(sprintf('[DEBUG] <%s:%d> header(Location): %s', __FILE__, __LINE__, $return_url)); header('Location: '.$return_url); exit(); diff --git a/www/addle.php b/www/addle.php index 449feee..95d6f91 100644 --- a/www/addle.php +++ b/www/addle.php @@ -177,8 +177,9 @@ function newgame($player) { $row = mt_rand(0,7); // db-entry - $gameid = $db->query('INSERT INTO addle (date, player1, player2, data, nextrow) VALUES (UNIX_TIMESTAMP(NOW()), '.$player.', '.$user->id.', "'.$board.'", '.$row.')', __FILE__, __LINE__, __FUNCTION__); - $db->query('UPDATE user SET addle="1" WHERE id='.$user->id, __FILE__, __LINE__, __FUNCTION__); + $gameid = $db->query('INSERT INTO addle (date, player1, player2, data, nextrow) VALUES (UNIX_TIMESTAMP(?), ?, ?, ?, ?)', + __FILE__, __LINE__, __FUNCTION__, [timestamp(true), $player, $user->id, $board, $row]); + $db->query('UPDATE user SET addle="1" WHERE id=?', __FILE__, __LINE__, __FUNCTION__, [$user->id]); /*======================================== Addle KI - start ========================================*/ @@ -226,7 +227,8 @@ function games() /** Eingeloggte User */ if ($user->is_loggedin()) { - $e = $db->query('SELECT * FROM addle WHERE ((player1='.$user->id.' AND nextturn=1) OR (player2='.$user->id.' AND nextturn=2)) AND finish=0', __FILE__, __LINE__, __FUNCTION__); + $e = $db->query('SELECT * FROM addle WHERE ((player1=? AND nextturn=1) OR (player2=? AND nextturn=2)) AND finish=0', + __FILE__, __LINE__, __FUNCTION__, [$user->id, $user->id]); $num = $db->num($e); if (!empty($num) && $num !== false && $num > 0) { @@ -242,7 +244,8 @@ function games() } /** Meine Laufenden Spiele */ - $s = $db->query('SELECT * FROM addle WHERE ((player1='.$user->id.' AND nextturn=2) OR (player2='.$user->id.' AND nextturn=1)) AND finish=0', __FILE__, __LINE__, __FUNCTION__); + $s = $db->query('SELECT * FROM addle WHERE ((player1=? AND nextturn=2) OR (player2=? AND nextturn=1)) AND finish=0', + __FILE__, __LINE__, __FUNCTION__, [$user->id, $user->id]); $num = $db->num($s); if (!empty($num) || $num > 0) { @@ -303,8 +306,8 @@ function overview() {