diff --git a/src/structure/components/com_sportsmanager/tools.php b/src/structure/components/com_sportsmanager/tools.php
index e951e7f..5126a71 100644
--- a/src/structure/components/com_sportsmanager/tools.php
+++ b/src/structure/components/com_sportsmanager/tools.php
@@ -1,723 +1,723 @@
-createFunc("ROUND", 'round', 1);
- $this->createFunc("VERTEILUNG", 'mathParserVerteilung', 4);
- $this->createFunc("VERTEILUNGR", 'mathParserVerteilungR', 4);
- } catch (Exception $e) {
- Log::add('an error occurred: ' . $e->getMessage(), Log::ERROR, 'com_sportsmanager');
- throw new RuntimeException('An error occurred.', 500);
- }
- }
-}
-
-#[NoReturn] function keinZugriff($login = FALSE): void
-{
- if (isJson()) {
- abortWithError(401 . ' Unauthorized');
- }
- if (!$login || Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id) {
- Log::add('Unauthorized user with id ' . Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id, Log::WARNING, 'com_sportsmanager');
- throw new RuntimeException('Not authorized!', 401);
- }
- $version = new Version();
- $joomla = $version->getShortVersion();
- $u = Uri::getInstance();
- $redirectUrl = urlencode(base64_encode($u->toString()));
- $redirectUrl = '&return=' . $redirectUrl;
- $joomlaLoginUrl = 'index.php?option=' . (!str_starts_with($joomla, '1.5') ? 'com_users' : 'com_user') . '&view=login';
- $finalUrl = $joomlaLoginUrl . $redirectUrl;
- $app = Factory::getContainer()->get(SiteApplication::class);
- $app->redirect(Route::_($finalUrl));
- jexit();
-}
-
-function bereinigterDateiname($dateiname): array|string
-{
- $_convertTable = array(
- '&' => 'and', '@' => 'at', '©' => 'c', '®' => 'r', 'À' => 'a',
- 'Á' => 'a', 'Â' => 'a', 'Ä' => 'a', 'Å' => 'a', 'Æ' => 'ae', 'Ç' => 'c',
- 'È' => 'e', 'É' => 'e', 'Ë' => 'e', 'Ì' => 'i', 'Í' => 'i', 'Î' => 'i',
- 'Ï' => 'i', 'Ò' => 'o', 'Ó' => 'o', 'Ô' => 'o', 'Õ' => 'o', 'Ö' => 'o',
- 'Ø' => 'o', 'Ù' => 'u', 'Ú' => 'u', 'Û' => 'u', 'Ü' => 'u', 'Ý' => 'y',
- 'ß' => 'ss', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ä' => 'a', 'å' => 'a',
- 'æ' => 'ae', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
- 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ò' => 'o', 'ó' => 'o',
- 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u',
- 'û' => 'u', 'ü' => 'u', 'ý' => 'y', 'þ' => 'p', 'ÿ' => 'y', 'Ā' => 'a',
- 'ā' => 'a', 'Ă' => 'a', 'ă' => 'a', 'Ą' => 'a', 'ą' => 'a', 'Ć' => 'c',
- 'ć' => 'c', 'Ĉ' => 'c', 'ĉ' => 'c', 'Ċ' => 'c', 'ċ' => 'c', 'Č' => 'c',
- 'č' => 'c', 'Ď' => 'd', 'ď' => 'd', 'Đ' => 'd', 'đ' => 'd', 'Ē' => 'e',
- 'ē' => 'e', 'Ĕ' => 'e', 'ĕ' => 'e', 'Ė' => 'e', 'ė' => 'e', 'Ę' => 'e',
- 'ę' => 'e', 'Ě' => 'e', 'ě' => 'e', 'Ĝ' => 'g', 'ĝ' => 'g', 'Ğ' => 'g',
- 'ğ' => 'g', 'Ġ' => 'g', 'ġ' => 'g', 'Ģ' => 'g', 'ģ' => 'g', 'Ĥ' => 'h',
- 'ĥ' => 'h', 'Ħ' => 'h', 'ħ' => 'h', 'Ĩ' => 'i', 'ĩ' => 'i', 'Ī' => 'i',
- 'ī' => 'i', 'Ĭ' => 'i', 'ĭ' => 'i', 'Į' => 'i', 'į' => 'i', 'İ' => 'i',
- 'ı' => 'i', 'IJ' => 'ij', 'ij' => 'ij', 'Ĵ' => 'j', 'ĵ' => 'j', 'Ķ' => 'k',
- 'ķ' => 'k', 'ĸ' => 'k', 'Ĺ' => 'l', 'ĺ' => 'l', 'Ļ' => 'l', 'ļ' => 'l',
- 'Ľ' => 'l', 'ľ' => 'l', 'Ŀ' => 'l', 'ŀ' => 'l', 'Ł' => 'l', 'ł' => 'l',
- 'Ń' => 'n', 'ń' => 'n', 'Ņ' => 'n', 'ņ' => 'n', 'Ň' => 'n', 'ň' => 'n',
- 'ʼn' => 'n', 'Ŋ' => 'n', 'ŋ' => 'n', 'Ō' => 'o', 'ō' => 'o', 'Ŏ' => 'o',
- 'ŏ' => 'o', 'Ő' => 'o', 'ő' => 'o', 'Œ' => 'oe', 'œ' => 'oe', 'Ŕ' => 'r',
- 'ŕ' => 'r', 'Ŗ' => 'r', 'ŗ' => 'r', 'Ř' => 'r', 'ř' => 'r', 'Ś' => 's',
- 'ś' => 's', 'Ŝ' => 's', 'ŝ' => 's', 'Ş' => 's', 'ş' => 's', 'Š' => 's',
- 'š' => 's', 'Ţ' => 't', 'ţ' => 't', 'Ť' => 't', 'ť' => 't', 'Ŧ' => 't',
- 'ŧ' => 't', 'Ũ' => 'u', 'ũ' => 'u', 'Ū' => 'u', 'ū' => 'u', 'Ŭ' => 'u',
- 'ŭ' => 'u', 'Ů' => 'u', 'ů' => 'u', 'Ű' => 'u', 'ű' => 'u', 'Ų' => 'u',
- 'ų' => 'u', 'Ŵ' => 'w', 'ŵ' => 'w', 'Ŷ' => 'y', 'ŷ' => 'y', 'Ÿ' => 'y',
- 'Ź' => 'z', 'ź' => 'z', 'Ż' => 'z', 'ż' => 'z', 'Ž' => 'z', 'ž' => 'z',
- 'ſ' => 'z', 'Ə' => 'e', 'ƒ' => 'f', 'Ơ' => 'o', 'ơ' => 'o', 'Ư' => 'u',
- 'ư' => 'u', 'Ǎ' => 'a', 'ǎ' => 'a', 'Ǐ' => 'i', 'ǐ' => 'i', 'Ǒ' => 'o',
- 'ǒ' => 'o', 'Ǔ' => 'u', 'ǔ' => 'u', 'Ǖ' => 'u', 'ǖ' => 'u', 'Ǘ' => 'u',
- 'ǘ' => 'u', 'Ǚ' => 'u', 'ǚ' => 'u', 'Ǜ' => 'u', 'ǜ' => 'u', 'Ǻ' => 'a',
- 'ǻ' => 'a', 'Ǽ' => 'ae', 'ǽ' => 'ae', 'Ǿ' => 'o', 'ǿ' => 'o', 'ə' => 'e',
- 'Ё' => 'jo', 'Є' => 'e', 'І' => 'i', 'Ї' => 'i', 'А' => 'a', 'Б' => 'b',
- 'В' => 'v', 'Г' => 'g', 'Д' => 'd', 'Е' => 'e', 'Ж' => 'zh', 'З' => 'z',
- 'И' => 'i', 'Й' => 'j', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n',
- 'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u',
- 'Ф' => 'f', 'Х' => 'h', 'Ц' => 'c', 'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'sch',
- 'Ъ' => '-', 'Ы' => 'y', 'Ь' => '-', 'Э' => 'je', 'Ю' => 'ju', 'Я' => 'ja',
- 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e',
- 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l',
- 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's',
- 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch',
- 'ш' => 'sh', 'щ' => 'sch', 'ъ' => '-', 'ы' => 'y', 'ь' => '-', 'э' => 'je',
- 'ю' => 'ju', 'я' => 'ja', 'ё' => 'jo', 'є' => 'e', 'і' => 'i', 'ї' => 'i',
- 'Ґ' => 'g', 'ґ' => 'g', 'א' => 'a', 'ב' => 'b', 'ג' => 'g', 'ד' => 'd',
- 'ה' => 'h', 'ו' => 'v', 'ז' => 'z', 'ח' => 'h', 'ט' => 't', 'י' => 'i',
- 'ך' => 'k', 'כ' => 'k', 'ל' => 'l', 'ם' => 'm', 'מ' => 'm', 'ן' => 'n',
- 'נ' => 'n', 'ס' => 's', 'ע' => 'e', 'ף' => 'p', 'פ' => 'p', 'ץ' => 'C',
- 'צ' => 'c', 'ק' => 'q', 'ר' => 'r', 'ש' => 'w', 'ת' => 't', '™' => 'tm',
- );
- $bad = array_merge(
- array_map('chr', range(0, 31)),
- array("<", ">", ":", '"', "/", "\\", "|", "?", "*"));
-
- return str_replace($bad, "", strtr($dateiname, $_convertTable));
-}
-
-function setMinMemoryLimit($memDestSize): void
-{
- if (getBytes(ini_get('memory_limit')) < getBytes($memDestSize))
- ini_set('memory_limit', $memDestSize);
-}
-
-function getBytes($val): int|string
-{
- $val = trim($val);
- $numeric = substr($val, 0, strlen($val) - 1);
- $last = strtolower($val[strlen($val) - 1]);
- switch ($last) {
- // The 'G' modifier is available since PHP 5.1.0
- case 'm':
- case 'g':
- case 'k':
- $numeric *= 1024;
- break;
- }
- return $numeric;
-}
-
-function encrypt($str, $key): string
-{
- $result = "";
- for ($i = 0; $i < strlen($str); $i++) {
- $char = substr($str, $i, 1);
- $keychar = substr($key, ($i % strlen($key)) - 1, 1);
- $char = chr(ord($char) + ord($keychar));
- $result .= $char;
- }
- return base64_encode($result);
-}
-
-function decrypt($str, $key): string
-{
- $str = base64_decode($str);
- $result = "";
- for ($i = 0; $i < strlen($str); $i++) {
- $char = substr($str, $i, 1);
- $keychar = substr($key, ($i % strlen($key)) - 1, 1);
- $char = chr(ord($char) - ord($keychar));
- $result .= $char;
- }
- return $result;
-}
-
-function individualwettbewerbFilter($prefix): string
-{
- $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
- return " " . $prefix . " (SELECT berechtigt_individualwettbewerb_id FROM #__sportsmanager_berechtigt_fuer_individualwettbewerb INNER JOIN #__sportsmanager_individualwettbewerb ON individualwettbewerb_id = berechtigt_individualwettbewerb_id WHERE berechtigt_user_id = $user_id) ";
-}
-
-function kategorieFilter($prefix, $suffix = ""): string
-{
- global $params;
-
- $kategorien = explode(",", $params->get('kategorien'));
- $result = [];
-
- foreach ($kategorien as $item) {
- $item = trim($item);
- if ($item === '') continue;
-
- // Prüfen, ob es ein Bereich ist
- if (strpos($item, '-') !== false) {
- $rangeParts = explode('-', $item);
-
- // genau 2 Teile für einen gültigen Bereich
- if (count($rangeParts) !== 2) continue;
-
- $start = intval(trim($rangeParts[0]));
- $end = intval(trim($rangeParts[1]));
-
- if ($start <= 0 || $end <= 0 || $start > $end) continue;
-
- for ($i = $start; $i <= $end; $i++) {
- $result[$i] = true; // Duplikate vermeiden
- }
- } else {
- $num = intval($item);
- if ($num > 0) {
- $result[$num] = true;
- }
- }
- }
-
- if (empty($result)) {
- return "";
- }
-
- $filter = array_keys($result);
- sort($filter, SORT_NUMERIC);
-
- return " $prefix (" . implode(", ", $filter) . ") $suffix";
-}
-
-function idListeParameterFilter(string $parameterName, string $prefix, string $suffix = ""): string
-{
- $jInput = Factory::getContainer()->get(SiteApplication::class)->input;
- $werte = $jInput->get($parameterName, '', 'STRING');
-
- $result = [];
- foreach (explode(",", $werte) as $item) {
- $item = trim($item);
- if ($item === '') continue;
-
- $num = intval($item);
- if ($num > 0) {
- $result[$num] = true; // Duplikate vermeiden
- }
- }
-
- if (empty($result)) {
- return "";
- }
-
- $filter = array_keys($result);
- sort($filter, SORT_NUMERIC);
-
- return " $prefix (" . implode(", ", $filter) . ") $suffix";
-}
-
-function halloffameIdFilter($prefix): string
-{
- // Keine Bereichssuche bei der Halloffame-Id, nur einzelne Werte
- return idListeParameterFilter('halloffame_id', $prefix);
-}
-
-function halloffameJahrFilter($prefix): string
-{
- $minJahr = 1900;
- $maxJahr = (int) date('Y') + 5;
-
- $jInput = Factory::getContainer()->get(SiteApplication::class)->input;
- $werte = $jInput->get('jahr', '', 'STRING');
-
- $result = [];
- foreach (explode(",", $werte) as $item) {
- $item = trim($item);
- if ($item === '') continue;
-
- // Prüfen, ob es ein Bereich ist
- if (strpos($item, '-') !== false) {
- $rangeParts = explode('-', $item);
-
- // genau 2 Teile für einen gültigen Bereich
- if (count($rangeParts) !== 2) continue;
-
- $start = intval(trim($rangeParts[0]));
- $end = intval(trim($rangeParts[1]));
-
- if ($start <= 0 || $end <= 0) continue;
-
- // Werte vertauschen, falls der 2. Wert kleiner als der 1. ist
- if ($end < $start) {
- [$start, $end] = [$end, $start];
- }
-
- // Bereich auf 1900 .. aktuelles Jahr+5 begrenzen
- $start = max($start, $minJahr);
- $end = min($end, $maxJahr);
-
- if ($start > $end) continue;
-
- for ($i = $start; $i <= $end; $i++) {
- $result[$i] = true; // Duplikate vermeiden
- }
- } else {
- $num = intval($item);
- if ($num <= 0) continue;
-
- // Einzelwert auf 1900 .. aktuelles Jahr+5 begrenzen
- $num = max($minJahr, min($maxJahr, $num));
- $result[$num] = true;
- }
- }
-
- if (empty($result)) {
- return "";
- }
-
- $filter = array_keys($result);
- sort($filter, SORT_NUMERIC);
-
- return " $prefix (" . implode(", ", $filter) . ")";
-}
-
-function halloffameAlleTeams($db): array
-{
- return loadObjectList($db, "SELECT team_id, teamname FROM #__sportsmanager_team ORDER BY team_id DESC");
-}
-
-function halloffameTeamIdFuerTeamname(array $alleTeams, ?string $teamname)
-{
- if (empty($teamname))
- return null;
- foreach ($alleTeams as $team) {
- if (str_starts_with($team->teamname, $teamname))
- return $team->team_id;
- }
- return null;
-}
-
-function halloffameAlleSpielerInfo($db): array
-{
- // "Aktiv" = hat einen aktuellen Verein; ohne aktuellen Verein liefert spieler_details ohnehin keine Daten
- $rows = loadObjectList($db, "SELECT spieler_id, geschlecht, aktueller_verein_id FROM #__sportsmanager_spieler");
- $result = [];
- foreach ($rows as $row) {
- $result[$row->spieler_id] = (object) [
- 'geschlecht' => $row->geschlecht,
- 'aktiv' => !empty($row->aktueller_verein_id),
- ];
- }
- return $result;
-}
-
-function halloffameSpielerAktiv(array $alleSpielerInfo, $spieler_id): bool
-{
- return empty($spieler_id) || !isset($alleSpielerInfo[$spieler_id]) || $alleSpielerInfo[$spieler_id]->aktiv;
-}
-
-function halloffameSpielerBildId(array $alleSpielerInfo, $spieler_id)
-{
- return halloffameSpielerAktiv($alleSpielerInfo, $spieler_id) ? $spieler_id : '';
-}
-
-function halloffameSpielerBildAlternativ(array $alleSpielerInfo, $spieler_id, string $geschaetztesGeschlecht = ''): string
-{
- if (!empty($spieler_id) && isset($alleSpielerInfo[$spieler_id]))
- return $alleSpielerInfo[$spieler_id]->geschlecht == 'M' ? 'm' : 'w';
- if ($geschaetztesGeschlecht === 'M')
- return 'm';
- if ($geschaetztesGeschlecht === 'W')
- return 'w';
- return 'n';
-}
-
-function halloffameGeschlechtZaehlen(object $ziel, array $alleSpielerInfo, $spieler1_id, $spieler2_id): void
-{
- foreach ([$spieler1_id, $spieler2_id] as $id) {
- if (empty($id) || !isset($alleSpielerInfo[$id]))
- continue;
- if ($alleSpielerInfo[$id]->geschlecht == 'M')
- $ziel->anzahl_m++;
- else
- $ziel->anzahl_w++;
- }
-}
-
-function halloffameGeschaetztesGeschlecht($anzahl_m, $anzahl_w): string
-{
- if ($anzahl_m > $anzahl_w)
- return 'M';
- if ($anzahl_w > $anzahl_m)
- return 'W';
- return '';
-}
-
-function halloffameAlleVereineInfo($db): array
-{
- $rows = loadObjectList($db, "SELECT verein_id, ausgetreten FROM #__sportsmanager_verein");
- $result = [];
- foreach ($rows as $row) {
- $result[$row->verein_id] = (object) [
- 'aktiv' => empty($row->ausgetreten),
- ];
- }
- return $result;
-}
-
-function halloffameVereinAktiv(array $alleVereineInfo, $verein_id): bool
-{
- return empty($verein_id) || !isset($alleVereineInfo[$verein_id]) || $alleVereineInfo[$verein_id]->aktiv;
-}
-
-function halloffameNameLink(string $bild_type, $id, array $alleSpielerInfo, array $alleVereineInfo, string $nameHtml): string
-{
- if (empty($id))
- return $nameHtml;
- if ($bild_type === 'spieler' && !halloffameSpielerAktiv($alleSpielerInfo, $id))
- return $nameHtml;
- if ($bild_type === 'vereine' && !halloffameVereinAktiv($alleVereineInfo, $id))
- return $nameHtml;
-
- $tasks = ['spieler' => 'spieler_details', 'vereine' => 'verein_details', 'mannschaften' => 'team_details'];
- if (!isset($tasks[$bild_type]))
- return $nameHtml;
-
- return '' . $nameHtml . '';
-}
-
-function halloffameTitel(): string
-{
- global $params;
-
- $titel = trim((string) $params->get('titel', ''));
- if ($titel !== '')
- return $titel;
-
- $menu = Factory::getContainer()->get(SiteApplication::class)->getMenu()->getActive();
- if ($menu !== null && trim((string) $menu->title) !== '')
- return $menu->title;
-
- return '';
-}
-
-function turnierFilter($prefix): string
-{
- $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
- return " " . $prefix . " (SELECT berechtigt_turnier_id FROM #__sportsmanager_berechtigt_fuer_turnier WHERE berechtigt_user_id = $user_id AND DATEDIFF(letzter_tag, NOW()) >= -21) ";
-}
-
-function vereinFilter($prefix): string
-{
- $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
- return " " . $prefix . " (SELECT berechtigt_verein_id FROM #__sportsmanager_berechtigt_fuer_verein INNER JOIN #__sportsmanager_verein ON berechtigt_verein_id = verein_id WHERE berechtigt_user_id = $user_id AND NOT ausgetreten) ";
-}
-
-function veranstalterFilter($prefix): string
-{
- $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
- return " " . $prefix . " (SELECT berechtigt_veranstalter_id FROM #__sportsmanager_berechtigt_fuer_veranstalter WHERE berechtigt_user_id = $user_id) ";
-}
-
-function veranstaltungFilter($prefix): string
-{
- $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
- return " " . $prefix . " (SELECT berechtigt_veranstaltung_id FROM #__sportsmanager_berechtigt_fuer_veranstaltung INNER JOIN #__sportsmanager_veranstaltung ON veranstaltung_id = berechtigt_veranstaltung_id WHERE berechtigt_user_id = $user_id AND DATEDIFF(letzter_tag, NOW()) >= -21) ";
-}
-
-// Berechnet Datum zum Montag der ersten Kalenderwoche eines Jahres
-function firstkw($jahr): bool|int
-{
- $erster = mktime(0, 0, 0, 1, 1, $jahr);
- $wtag = date('w', $erster);
- if ($wtag <= 4) {
- /**
- * Donnerstag oder kleiner: auf den Montag zurückrechnen.
- */
- $montag = mktime(0, 0, 0, 1, 1 - ($wtag - 1), $jahr);
- } else {
- /**
- * auf den Montag nach vorne rechnen.
- */
- $montag = mktime(0, 0, 0, 1, 1 + (7 - $wtag + 1), $jahr);
- }
- return $montag;
-}
-
-// Berechnet Wochentag über Kalenderwoche, Jahr und Wochentag (0 = Montag, ..., 6 = Sonntag)
-function mondaykw($kw, $jahr, $weekday): bool|int
-{
- $firstmonday = firstkw($jahr);
- $mon_monat = date('m', $firstmonday);
- $mon_jahr = date('Y', $firstmonday);
- $mon_tage = (int)date('d', $firstmonday);
- $tage = ($kw - 1) * 7;
- return mktime(0, 0, 0, $mon_monat, $mon_tage + $tage + $weekday, $mon_jahr);
-}
-
-// Berechnet Termin am Wochentag (0 = Montag, ..., 6 = Sonntag) in Kalenderwoche zum Datum
-function geaenderterWochentag($datum, $wochentag): bool|int
-{
- $wtag = date('w', $datum);
- if ($wtag == 0) // Sonntag
- $wtag = 7;
- $mon_monat = date('m', $datum);
- $mon_jahr = date('Y', $datum);
- $mon_tage = (int)date('d', $datum);
- return mktime(0, 0, 0, $mon_monat, $mon_tage + 1 - $wtag + $wochentag, $mon_jahr);
-}
-
-function normalisiertesDatum($datum): ?string
-{
- if ($datum == NULL)
- return NULL;
-
- if (str_contains($datum, "-"))
- $trennzeichen = "-";
- else
- $trennzeichen = ".";
-
- $t = explode($trennzeichen, $datum);
- $n = count($t);
- if ($n == 1) {
- $s = $t[0];
- if (strlen($s) < 8)
- return NULL;
- $jahr = intval(substr($s, 0, 4));
- $monat = intval(substr($s, 4, 2));
- $tag = intval(substr($s, 6, 2));
- } else if ($n == 3) {
- if ($trennzeichen != ".") {
- $jahr = intval($t[0]);
- if (strlen($t[0]) <= 2)
- $jahr += 1900;
- $monat = intval($t[1]);
- $tag = intval($t[2]);
- } else {
- $tag = intval($t[0]);
- $monat = intval($t[1]);
- $jahr = intval($t[2]);
- if (strlen($t[2]) <= 2)
- $jahr += 1900;
- }
- } else
- return NULL;
-
- if (!checkdate($monat, $tag, $jahr))
- return NULL;
-
- return sprintf("%04d-%02d-%02d", $jahr, $monat, $tag);
-}
-
-function normalisierteUhrzeit($uhrzeit): ?string
-{
- if ($uhrzeit == NULL)
- return NULL;
-
- if (str_contains($uhrzeit, "-"))
- $trennzeichen = "-";
- else
- $trennzeichen = ":";
-
- $t = explode($trennzeichen, $uhrzeit);
- $n = count($t);
- if ($n == 1) {
- $s = $t[0];
- $len = strlen($s);
- if ($len != 4 && $len != 6)
- return NULL;
- $stunden = intval(substr($s, 0, 2));
- $minuten = intval(substr($s, 2, 2));
- $sekunden = $len != 6 ? 0 : intval(substr($s, 4, 2));
- } else if ($n == 2 || $n == 3) {
- $stunden = intval($t[0]);
- $minuten = intval($t[1]);
- $sekunden = $n != 3 ? 0 : intval($t[2]);
- } else
- return NULL;
-
- if ($stunden < 0 || $stunden > 23 || $minuten < 0 || $minuten > 59 || $sekunden < 0 || $sekunden > 59)
- return NULL;
-
- return sprintf("%02d:%02d:%02d", $stunden, $minuten, $sekunden);
-}
-
-function runden_detailliert_invers($runden): ?string
-{
- if ($runden == null)
- return null;
- $runden_invers = "";
- $saetze = explode(" ", $runden);
- foreach ($saetze as $satz) {
- $punkte = explode(":", $satz);
- if (!empty($runden_invers))
- $runden_invers .= " ";
- $runden_invers .= $punkte[1] . ":" . $punkte[0];
- }
- return $runden_invers;
-}
-
-function runden_detailliert_auswertung($runden): array
-{
- $ergebnis = 0;
- $heim_saetze = 0;
- $unentschieden_saetze = 0;
- $gast_saetze = 0;
- $heim_punkte = 0;
- $gast_punkte = 0;
- if ($runden != null) {
- $saetze = explode(" ", $runden);
- foreach ($saetze as $satz) {
- $punkte = explode(":", $satz);
- $heim_punkte += (int)$punkte[0];
- $gast_punkte += (int)$punkte[1];
- if ($punkte[0] > $punkte[1])
- $heim_saetze++;
- else if ($punkte[0] < $punkte[1])
- $gast_saetze++;
- else
- $unentschieden_saetze++;
- }
- if ($heim_saetze > $gast_saetze)
- $ergebnis = 1;
- else if ($heim_saetze < $gast_saetze)
- $ergebnis = 2;
- }
- return array($ergebnis, $heim_saetze, $unentschieden_saetze, $gast_saetze, $heim_punkte, $gast_punkte);
-}
-
-function spielpunkteFuerSpiel($wertung, $heim_punkte, $gast_punkte, $ergebnis_detailliert = null): array
-{
- if ($wertung == 2)
- return array($heim_punkte, $gast_punkte);
- $je_satz = $wertung >= 10;
- $grund = $wertung % 10;
- $sieg = $grund == 0 ? 2 : ($grund == 1 ? 3 : 1);
- $remis = $grund == 3 ? 0 : 1;
- if ($je_satz) {
- if (empty($ergebnis_detailliert))
- return array($sieg * (int)$heim_punkte, $sieg * (int)$gast_punkte);
- $auswertung = runden_detailliert_auswertung($ergebnis_detailliert);
- return array($sieg * $auswertung[1] + $remis * $auswertung[2],
- $sieg * $auswertung[3] + $remis * $auswertung[2]);
- }
- if ($heim_punkte > $gast_punkte)
- return array($sieg, 0);
- if ($heim_punkte < $gast_punkte)
- return array(0, $sieg);
- if ($heim_punkte == 0 && $gast_punkte == 0)
- return array(0, 0);
- return array($remis, $remis);
-}
-
-function toreFuerSpiel($punktetyp, $satzergebnisse, $heim_punkte, $gast_punkte, $ergebnis_detailliert): array
-{
- if ($punktetyp == 0)
- return array((int)$heim_punkte, (int)$gast_punkte);
- if (!empty($satzergebnisse) && !empty($ergebnis_detailliert)) {
- $auswertung = runden_detailliert_auswertung($ergebnis_detailliert);
- return array($auswertung[4], $auswertung[5]);
- }
- return array(null, null);
-}
-
-function jeSatzWertung($wertung_einzel, $wertung_doppel): bool
-{
- return $wertung_einzel >= 10 || $wertung_doppel >= 10;
-}
-
-function ausgetragenBedingung($je_satz, $alias): string
-{
- return "($alias.heim_punkte != 0 OR $alias.gast_punkte != 0"
- . ($je_satz ? " OR NOT ISNULL($alias.heim_tore)" : "") . ")";
-}
-
-function ergebnisVorhanden($je_satz, $heim_punkte, $gast_punkte, $heim_tore): bool
-{
- return $heim_punkte != null || $gast_punkte != null || ($je_satz && $heim_tore !== null);
-}
-
-function saetzeRemisFuerSpiel($punktetyp, $satzergebnisse, $ergebnis_detailliert): ?int
-{
- if ($punktetyp == 0 || empty($satzergebnisse) || empty($ergebnis_detailliert))
- return null;
- $auswertung = runden_detailliert_auswertung($ergebnis_detailliert);
- return $auswertung[2];
-}
-
-// pass two file names
-// returns TRUE if files are the same, FALSE otherwise
-function files_identical($fn1, $fn2): bool
-{
- if (!is_file($fn1) || !is_file($fn2))
- return FALSE;
-
- if (filesize($fn1) !== filesize($fn2))
- return FALSE;
-
- if (!$fp1 = fopen($fn1, 'rb'))
- return FALSE;
-
- if (!$fp2 = fopen($fn2, 'rb')) {
- fclose($fp1);
- return FALSE;
- }
-
- $same = TRUE;
- while (!feof($fp1) and !feof($fp2))
- if (fread($fp1, 4096) !== fread($fp2, 4096)) {
- $same = FALSE;
- break;
- }
-
- if (feof($fp1) !== feof($fp2))
- $same = FALSE;
-
- fclose($fp1);
- fclose($fp2);
-
- return $same;
-}
-
+createFunc("ROUND", 'round', 1);
+ $this->createFunc("VERTEILUNG", 'mathParserVerteilung', 4);
+ $this->createFunc("VERTEILUNGR", 'mathParserVerteilungR', 4);
+ } catch (Exception $e) {
+ Log::add('an error occurred: ' . $e->getMessage(), Log::ERROR, 'com_sportsmanager');
+ throw new RuntimeException('An error occurred.', 500);
+ }
+ }
+}
+
+#[NoReturn] function keinZugriff($login = FALSE): void
+{
+ if (isJson()) {
+ abortWithError(401 . ' Unauthorized');
+ }
+ if (!$login || Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id) {
+ Log::add('Unauthorized user with id ' . Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id, Log::WARNING, 'com_sportsmanager');
+ throw new RuntimeException('Not authorized!', 401);
+ }
+ $version = new Version();
+ $joomla = $version->getShortVersion();
+ $u = Uri::getInstance();
+ $redirectUrl = urlencode(base64_encode($u->toString()));
+ $redirectUrl = '&return=' . $redirectUrl;
+ $joomlaLoginUrl = 'index.php?option=' . (!str_starts_with($joomla, '1.5') ? 'com_users' : 'com_user') . '&view=login';
+ $finalUrl = $joomlaLoginUrl . $redirectUrl;
+ $app = Factory::getContainer()->get(SiteApplication::class);
+ $app->redirect(Route::_($finalUrl));
+ jexit();
+}
+
+function bereinigterDateiname($dateiname): array|string
+{
+ $_convertTable = array(
+ '&' => 'and', '@' => 'at', '©' => 'c', '®' => 'r', 'À' => 'a',
+ 'Á' => 'a', 'Â' => 'a', 'Ä' => 'a', 'Å' => 'a', 'Æ' => 'ae', 'Ç' => 'c',
+ 'È' => 'e', 'É' => 'e', 'Ë' => 'e', 'Ì' => 'i', 'Í' => 'i', 'Î' => 'i',
+ 'Ï' => 'i', 'Ò' => 'o', 'Ó' => 'o', 'Ô' => 'o', 'Õ' => 'o', 'Ö' => 'o',
+ 'Ø' => 'o', 'Ù' => 'u', 'Ú' => 'u', 'Û' => 'u', 'Ü' => 'u', 'Ý' => 'y',
+ 'ß' => 'ss', 'à' => 'a', 'á' => 'a', 'â' => 'a', 'ä' => 'a', 'å' => 'a',
+ 'æ' => 'ae', 'ç' => 'c', 'è' => 'e', 'é' => 'e', 'ê' => 'e', 'ë' => 'e',
+ 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ò' => 'o', 'ó' => 'o',
+ 'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u',
+ 'û' => 'u', 'ü' => 'u', 'ý' => 'y', 'þ' => 'p', 'ÿ' => 'y', 'Ā' => 'a',
+ 'ā' => 'a', 'Ă' => 'a', 'ă' => 'a', 'Ą' => 'a', 'ą' => 'a', 'Ć' => 'c',
+ 'ć' => 'c', 'Ĉ' => 'c', 'ĉ' => 'c', 'Ċ' => 'c', 'ċ' => 'c', 'Č' => 'c',
+ 'č' => 'c', 'Ď' => 'd', 'ď' => 'd', 'Đ' => 'd', 'đ' => 'd', 'Ē' => 'e',
+ 'ē' => 'e', 'Ĕ' => 'e', 'ĕ' => 'e', 'Ė' => 'e', 'ė' => 'e', 'Ę' => 'e',
+ 'ę' => 'e', 'Ě' => 'e', 'ě' => 'e', 'Ĝ' => 'g', 'ĝ' => 'g', 'Ğ' => 'g',
+ 'ğ' => 'g', 'Ġ' => 'g', 'ġ' => 'g', 'Ģ' => 'g', 'ģ' => 'g', 'Ĥ' => 'h',
+ 'ĥ' => 'h', 'Ħ' => 'h', 'ħ' => 'h', 'Ĩ' => 'i', 'ĩ' => 'i', 'Ī' => 'i',
+ 'ī' => 'i', 'Ĭ' => 'i', 'ĭ' => 'i', 'Į' => 'i', 'į' => 'i', 'İ' => 'i',
+ 'ı' => 'i', 'IJ' => 'ij', 'ij' => 'ij', 'Ĵ' => 'j', 'ĵ' => 'j', 'Ķ' => 'k',
+ 'ķ' => 'k', 'ĸ' => 'k', 'Ĺ' => 'l', 'ĺ' => 'l', 'Ļ' => 'l', 'ļ' => 'l',
+ 'Ľ' => 'l', 'ľ' => 'l', 'Ŀ' => 'l', 'ŀ' => 'l', 'Ł' => 'l', 'ł' => 'l',
+ 'Ń' => 'n', 'ń' => 'n', 'Ņ' => 'n', 'ņ' => 'n', 'Ň' => 'n', 'ň' => 'n',
+ 'ʼn' => 'n', 'Ŋ' => 'n', 'ŋ' => 'n', 'Ō' => 'o', 'ō' => 'o', 'Ŏ' => 'o',
+ 'ŏ' => 'o', 'Ő' => 'o', 'ő' => 'o', 'Œ' => 'oe', 'œ' => 'oe', 'Ŕ' => 'r',
+ 'ŕ' => 'r', 'Ŗ' => 'r', 'ŗ' => 'r', 'Ř' => 'r', 'ř' => 'r', 'Ś' => 's',
+ 'ś' => 's', 'Ŝ' => 's', 'ŝ' => 's', 'Ş' => 's', 'ş' => 's', 'Š' => 's',
+ 'š' => 's', 'Ţ' => 't', 'ţ' => 't', 'Ť' => 't', 'ť' => 't', 'Ŧ' => 't',
+ 'ŧ' => 't', 'Ũ' => 'u', 'ũ' => 'u', 'Ū' => 'u', 'ū' => 'u', 'Ŭ' => 'u',
+ 'ŭ' => 'u', 'Ů' => 'u', 'ů' => 'u', 'Ű' => 'u', 'ű' => 'u', 'Ų' => 'u',
+ 'ų' => 'u', 'Ŵ' => 'w', 'ŵ' => 'w', 'Ŷ' => 'y', 'ŷ' => 'y', 'Ÿ' => 'y',
+ 'Ź' => 'z', 'ź' => 'z', 'Ż' => 'z', 'ż' => 'z', 'Ž' => 'z', 'ž' => 'z',
+ 'ſ' => 'z', 'Ə' => 'e', 'ƒ' => 'f', 'Ơ' => 'o', 'ơ' => 'o', 'Ư' => 'u',
+ 'ư' => 'u', 'Ǎ' => 'a', 'ǎ' => 'a', 'Ǐ' => 'i', 'ǐ' => 'i', 'Ǒ' => 'o',
+ 'ǒ' => 'o', 'Ǔ' => 'u', 'ǔ' => 'u', 'Ǖ' => 'u', 'ǖ' => 'u', 'Ǘ' => 'u',
+ 'ǘ' => 'u', 'Ǚ' => 'u', 'ǚ' => 'u', 'Ǜ' => 'u', 'ǜ' => 'u', 'Ǻ' => 'a',
+ 'ǻ' => 'a', 'Ǽ' => 'ae', 'ǽ' => 'ae', 'Ǿ' => 'o', 'ǿ' => 'o', 'ə' => 'e',
+ 'Ё' => 'jo', 'Є' => 'e', 'І' => 'i', 'Ї' => 'i', 'А' => 'a', 'Б' => 'b',
+ 'В' => 'v', 'Г' => 'g', 'Д' => 'd', 'Е' => 'e', 'Ж' => 'zh', 'З' => 'z',
+ 'И' => 'i', 'Й' => 'j', 'К' => 'k', 'Л' => 'l', 'М' => 'm', 'Н' => 'n',
+ 'О' => 'o', 'П' => 'p', 'Р' => 'r', 'С' => 's', 'Т' => 't', 'У' => 'u',
+ 'Ф' => 'f', 'Х' => 'h', 'Ц' => 'c', 'Ч' => 'ch', 'Ш' => 'sh', 'Щ' => 'sch',
+ 'Ъ' => '-', 'Ы' => 'y', 'Ь' => '-', 'Э' => 'je', 'Ю' => 'ju', 'Я' => 'ja',
+ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e',
+ 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'j', 'к' => 'k', 'л' => 'l',
+ 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's',
+ 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'c', 'ч' => 'ch',
+ 'ш' => 'sh', 'щ' => 'sch', 'ъ' => '-', 'ы' => 'y', 'ь' => '-', 'э' => 'je',
+ 'ю' => 'ju', 'я' => 'ja', 'ё' => 'jo', 'є' => 'e', 'і' => 'i', 'ї' => 'i',
+ 'Ґ' => 'g', 'ґ' => 'g', 'א' => 'a', 'ב' => 'b', 'ג' => 'g', 'ד' => 'd',
+ 'ה' => 'h', 'ו' => 'v', 'ז' => 'z', 'ח' => 'h', 'ט' => 't', 'י' => 'i',
+ 'ך' => 'k', 'כ' => 'k', 'ל' => 'l', 'ם' => 'm', 'מ' => 'm', 'ן' => 'n',
+ 'נ' => 'n', 'ס' => 's', 'ע' => 'e', 'ף' => 'p', 'פ' => 'p', 'ץ' => 'C',
+ 'צ' => 'c', 'ק' => 'q', 'ר' => 'r', 'ש' => 'w', 'ת' => 't', '™' => 'tm',
+ );
+ $bad = array_merge(
+ array_map('chr', range(0, 31)),
+ array("<", ">", ":", '"', "/", "\\", "|", "?", "*"));
+
+ return str_replace($bad, "", strtr($dateiname, $_convertTable));
+}
+
+function setMinMemoryLimit($memDestSize): void
+{
+ if (getBytes(ini_get('memory_limit')) < getBytes($memDestSize))
+ ini_set('memory_limit', $memDestSize);
+}
+
+function getBytes($val): int|string
+{
+ $val = trim($val);
+ $numeric = substr($val, 0, strlen($val) - 1);
+ $last = strtolower($val[strlen($val) - 1]);
+ switch ($last) {
+ // The 'G' modifier is available since PHP 5.1.0
+ case 'm':
+ case 'g':
+ case 'k':
+ $numeric *= 1024;
+ break;
+ }
+ return $numeric;
+}
+
+function encrypt($str, $key): string
+{
+ $result = "";
+ for ($i = 0; $i < strlen($str); $i++) {
+ $char = substr($str, $i, 1);
+ $keychar = substr($key, ($i % strlen($key)) - 1, 1);
+ $char = chr(ord($char) + ord($keychar));
+ $result .= $char;
+ }
+ return base64_encode($result);
+}
+
+function decrypt($str, $key): string
+{
+ $str = base64_decode($str);
+ $result = "";
+ for ($i = 0; $i < strlen($str); $i++) {
+ $char = substr($str, $i, 1);
+ $keychar = substr($key, ($i % strlen($key)) - 1, 1);
+ $char = chr(ord($char) - ord($keychar));
+ $result .= $char;
+ }
+ return $result;
+}
+
+function individualwettbewerbFilter($prefix): string
+{
+ $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
+ return " " . $prefix . " (SELECT berechtigt_individualwettbewerb_id FROM #__sportsmanager_berechtigt_fuer_individualwettbewerb INNER JOIN #__sportsmanager_individualwettbewerb ON individualwettbewerb_id = berechtigt_individualwettbewerb_id WHERE berechtigt_user_id = $user_id) ";
+}
+
+function kategorieFilter($prefix, $suffix = ""): string
+{
+ global $params;
+
+ $kategorien = explode(",", $params->get('kategorien'));
+ $result = [];
+
+ foreach ($kategorien as $item) {
+ $item = trim($item);
+ if ($item === '') continue;
+
+ // Prüfen, ob es ein Bereich ist
+ if (strpos($item, '-') !== false) {
+ $rangeParts = explode('-', $item);
+
+ // genau 2 Teile für einen gültigen Bereich
+ if (count($rangeParts) !== 2) continue;
+
+ $start = intval(trim($rangeParts[0]));
+ $end = intval(trim($rangeParts[1]));
+
+ if ($start <= 0 || $end <= 0 || $start > $end) continue;
+
+ for ($i = $start; $i <= $end; $i++) {
+ $result[$i] = true; // Duplikate vermeiden
+ }
+ } else {
+ $num = intval($item);
+ if ($num > 0) {
+ $result[$num] = true;
+ }
+ }
+ }
+
+ if (empty($result)) {
+ return "";
+ }
+
+ $filter = array_keys($result);
+ sort($filter, SORT_NUMERIC);
+
+ return " $prefix (" . implode(", ", $filter) . ") $suffix";
+}
+
+function idListeParameterFilter(string $parameterName, string $prefix, string $suffix = ""): string
+{
+ $jInput = Factory::getContainer()->get(SiteApplication::class)->input;
+ $werte = $jInput->get($parameterName, '', 'STRING');
+
+ $result = [];
+ foreach (explode(",", $werte) as $item) {
+ $item = trim($item);
+ if ($item === '') continue;
+
+ $num = intval($item);
+ if ($num > 0) {
+ $result[$num] = true; // Duplikate vermeiden
+ }
+ }
+
+ if (empty($result)) {
+ return "";
+ }
+
+ $filter = array_keys($result);
+ sort($filter, SORT_NUMERIC);
+
+ return " $prefix (" . implode(", ", $filter) . ") $suffix";
+}
+
+function halloffameIdFilter($prefix): string
+{
+ // Keine Bereichssuche bei der Halloffame-Id, nur einzelne Werte
+ return idListeParameterFilter('halloffame_id', $prefix);
+}
+
+function halloffameJahrFilter($prefix): string
+{
+ $minJahr = 1900;
+ $maxJahr = (int) date('Y') + 5;
+
+ $jInput = Factory::getContainer()->get(SiteApplication::class)->input;
+ $werte = $jInput->get('jahr', '', 'STRING');
+
+ $result = [];
+ foreach (explode(",", $werte) as $item) {
+ $item = trim($item);
+ if ($item === '') continue;
+
+ // Prüfen, ob es ein Bereich ist
+ if (strpos($item, '-') !== false) {
+ $rangeParts = explode('-', $item);
+
+ // genau 2 Teile für einen gültigen Bereich
+ if (count($rangeParts) !== 2) continue;
+
+ $start = intval(trim($rangeParts[0]));
+ $end = intval(trim($rangeParts[1]));
+
+ if ($start <= 0 || $end <= 0) continue;
+
+ // Werte vertauschen, falls der 2. Wert kleiner als der 1. ist
+ if ($end < $start) {
+ [$start, $end] = [$end, $start];
+ }
+
+ // Bereich auf 1900 .. aktuelles Jahr+5 begrenzen
+ $start = max($start, $minJahr);
+ $end = min($end, $maxJahr);
+
+ if ($start > $end) continue;
+
+ for ($i = $start; $i <= $end; $i++) {
+ $result[$i] = true; // Duplikate vermeiden
+ }
+ } else {
+ $num = intval($item);
+ if ($num <= 0) continue;
+
+ // Einzelwert auf 1900 .. aktuelles Jahr+5 begrenzen
+ $num = max($minJahr, min($maxJahr, $num));
+ $result[$num] = true;
+ }
+ }
+
+ if (empty($result)) {
+ return "";
+ }
+
+ $filter = array_keys($result);
+ sort($filter, SORT_NUMERIC);
+
+ return " $prefix (" . implode(", ", $filter) . ")";
+}
+
+function halloffameAlleTeams($db): array
+{
+ return loadObjectList($db, "SELECT team_id, teamname FROM #__sportsmanager_team ORDER BY team_id DESC");
+}
+
+function halloffameTeamIdFuerTeamname(array $alleTeams, ?string $teamname)
+{
+ if (empty($teamname))
+ return null;
+ foreach ($alleTeams as $team) {
+ if (str_starts_with($team->teamname, $teamname))
+ return $team->team_id;
+ }
+ return null;
+}
+
+function halloffameAlleSpielerInfo($db): array
+{
+ // "Aktiv" = hat einen aktuellen Verein; ohne aktuellen Verein liefert spieler_details ohnehin keine Daten
+ $rows = loadObjectList($db, "SELECT spieler_id, geschlecht, aktueller_verein_id FROM #__sportsmanager_spieler");
+ $result = [];
+ foreach ($rows as $row) {
+ $result[$row->spieler_id] = (object) [
+ 'geschlecht' => $row->geschlecht,
+ 'aktiv' => !empty($row->aktueller_verein_id),
+ ];
+ }
+ return $result;
+}
+
+function halloffameSpielerAktiv(array $alleSpielerInfo, $spieler_id): bool
+{
+ return empty($spieler_id) || !isset($alleSpielerInfo[$spieler_id]) || $alleSpielerInfo[$spieler_id]->aktiv;
+}
+
+function halloffameSpielerBildId(array $alleSpielerInfo, $spieler_id)
+{
+ return halloffameSpielerAktiv($alleSpielerInfo, $spieler_id) ? $spieler_id : '';
+}
+
+function halloffameSpielerBildAlternativ(array $alleSpielerInfo, $spieler_id, string $geschaetztesGeschlecht = ''): string
+{
+ if (!empty($spieler_id) && isset($alleSpielerInfo[$spieler_id]))
+ return $alleSpielerInfo[$spieler_id]->geschlecht == 'M' ? 'm' : 'w';
+ if ($geschaetztesGeschlecht === 'M')
+ return 'm';
+ if ($geschaetztesGeschlecht === 'W')
+ return 'w';
+ return 'n';
+}
+
+function halloffameGeschlechtZaehlen(object $ziel, array $alleSpielerInfo, $spieler1_id, $spieler2_id): void
+{
+ foreach ([$spieler1_id, $spieler2_id] as $id) {
+ if (empty($id) || !isset($alleSpielerInfo[$id]))
+ continue;
+ if ($alleSpielerInfo[$id]->geschlecht == 'M')
+ $ziel->anzahl_m++;
+ else
+ $ziel->anzahl_w++;
+ }
+}
+
+function halloffameGeschaetztesGeschlecht($anzahl_m, $anzahl_w): string
+{
+ if ($anzahl_m > $anzahl_w)
+ return 'M';
+ if ($anzahl_w > $anzahl_m)
+ return 'W';
+ return '';
+}
+
+function halloffameAlleVereineInfo($db): array
+{
+ $rows = loadObjectList($db, "SELECT verein_id, ausgetreten FROM #__sportsmanager_verein");
+ $result = [];
+ foreach ($rows as $row) {
+ $result[$row->verein_id] = (object) [
+ 'aktiv' => empty($row->ausgetreten),
+ ];
+ }
+ return $result;
+}
+
+function halloffameVereinAktiv(array $alleVereineInfo, $verein_id): bool
+{
+ return empty($verein_id) || !isset($alleVereineInfo[$verein_id]) || $alleVereineInfo[$verein_id]->aktiv;
+}
+
+function halloffameNameLink(string $bild_type, $id, array $alleSpielerInfo, array $alleVereineInfo, string $nameHtml): string
+{
+ if (empty($id))
+ return $nameHtml;
+ if ($bild_type === 'spieler' && !halloffameSpielerAktiv($alleSpielerInfo, $id))
+ return $nameHtml;
+ if ($bild_type === 'vereine' && !halloffameVereinAktiv($alleVereineInfo, $id))
+ return $nameHtml;
+
+ $tasks = ['spieler' => 'spieler_details', 'vereine' => 'verein_details', 'mannschaften' => 'team_details'];
+ if (!isset($tasks[$bild_type]))
+ return $nameHtml;
+
+ return '' . $nameHtml . '';
+}
+
+function halloffameTitel(): string
+{
+ global $params;
+
+ $titel = trim((string) $params->get('titel', ''));
+ if ($titel !== '')
+ return $titel;
+
+ $menu = Factory::getContainer()->get(SiteApplication::class)->getMenu()->getActive();
+ if ($menu !== null && trim((string) $menu->title) !== '')
+ return $menu->title;
+
+ return '';
+}
+
+function turnierFilter($prefix): string
+{
+ $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
+ return " " . $prefix . " (SELECT berechtigt_turnier_id FROM #__sportsmanager_berechtigt_fuer_turnier WHERE berechtigt_user_id = $user_id AND DATEDIFF(letzter_tag, NOW()) >= -21) ";
+}
+
+function vereinFilter($prefix): string
+{
+ $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
+ return " " . $prefix . " (SELECT berechtigt_verein_id FROM #__sportsmanager_berechtigt_fuer_verein INNER JOIN #__sportsmanager_verein ON berechtigt_verein_id = verein_id WHERE berechtigt_user_id = $user_id AND NOT ausgetreten) ";
+}
+
+function veranstalterFilter($prefix): string
+{
+ $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
+ return " " . $prefix . " (SELECT berechtigt_veranstalter_id FROM #__sportsmanager_berechtigt_fuer_veranstalter WHERE berechtigt_user_id = $user_id) ";
+}
+
+function veranstaltungFilter($prefix): string
+{
+ $user_id = isExternalDatabase() ? 0 : Factory::getContainer()->get(SiteApplication::class)->getIdentity()->id;
+ return " " . $prefix . " (SELECT berechtigt_veranstaltung_id FROM #__sportsmanager_berechtigt_fuer_veranstaltung INNER JOIN #__sportsmanager_veranstaltung ON veranstaltung_id = berechtigt_veranstaltung_id WHERE berechtigt_user_id = $user_id AND DATEDIFF(letzter_tag, NOW()) >= -21) ";
+}
+
+// Berechnet Datum zum Montag der ersten Kalenderwoche eines Jahres
+function firstkw($jahr): bool|int
+{
+ $erster = mktime(0, 0, 0, 1, 1, $jahr);
+ $wtag = date('w', $erster);
+ if ($wtag <= 4) {
+ /**
+ * Donnerstag oder kleiner: auf den Montag zurückrechnen.
+ */
+ $montag = mktime(0, 0, 0, 1, 1 - ($wtag - 1), $jahr);
+ } else {
+ /**
+ * auf den Montag nach vorne rechnen.
+ */
+ $montag = mktime(0, 0, 0, 1, 1 + (7 - $wtag + 1), $jahr);
+ }
+ return $montag;
+}
+
+// Berechnet Wochentag über Kalenderwoche, Jahr und Wochentag (0 = Montag, ..., 6 = Sonntag)
+function mondaykw($kw, $jahr, $weekday): bool|int
+{
+ $firstmonday = firstkw($jahr);
+ $mon_monat = date('m', $firstmonday);
+ $mon_jahr = date('Y', $firstmonday);
+ $mon_tage = (int)date('d', $firstmonday);
+ $tage = ($kw - 1) * 7;
+ return mktime(0, 0, 0, $mon_monat, $mon_tage + $tage + $weekday, $mon_jahr);
+}
+
+// Berechnet Termin am Wochentag (0 = Montag, ..., 6 = Sonntag) in Kalenderwoche zum Datum
+function geaenderterWochentag($datum, $wochentag): bool|int
+{
+ $wtag = date('w', $datum);
+ if ($wtag == 0) // Sonntag
+ $wtag = 7;
+ $mon_monat = date('m', $datum);
+ $mon_jahr = date('Y', $datum);
+ $mon_tage = (int)date('d', $datum);
+ return mktime(0, 0, 0, $mon_monat, $mon_tage + 1 - $wtag + $wochentag, $mon_jahr);
+}
+
+function normalisiertesDatum($datum): ?string
+{
+ if ($datum == NULL)
+ return NULL;
+
+ if (str_contains($datum, "-"))
+ $trennzeichen = "-";
+ else
+ $trennzeichen = ".";
+
+ $t = explode($trennzeichen, $datum);
+ $n = count($t);
+ if ($n == 1) {
+ $s = $t[0];
+ if (strlen($s) < 8)
+ return NULL;
+ $jahr = intval(substr($s, 0, 4));
+ $monat = intval(substr($s, 4, 2));
+ $tag = intval(substr($s, 6, 2));
+ } else if ($n == 3) {
+ if ($trennzeichen != ".") {
+ $jahr = intval($t[0]);
+ if (strlen($t[0]) <= 2)
+ $jahr += 1900;
+ $monat = intval($t[1]);
+ $tag = intval($t[2]);
+ } else {
+ $tag = intval($t[0]);
+ $monat = intval($t[1]);
+ $jahr = intval($t[2]);
+ if (strlen($t[2]) <= 2)
+ $jahr += 1900;
+ }
+ } else
+ return NULL;
+
+ if (!checkdate($monat, $tag, $jahr))
+ return NULL;
+
+ return sprintf("%04d-%02d-%02d", $jahr, $monat, $tag);
+}
+
+function normalisierteUhrzeit($uhrzeit): ?string
+{
+ if ($uhrzeit == NULL)
+ return NULL;
+
+ if (str_contains($uhrzeit, "-"))
+ $trennzeichen = "-";
+ else
+ $trennzeichen = ":";
+
+ $t = explode($trennzeichen, $uhrzeit);
+ $n = count($t);
+ if ($n == 1) {
+ $s = $t[0];
+ $len = strlen($s);
+ if ($len != 4 && $len != 6)
+ return NULL;
+ $stunden = intval(substr($s, 0, 2));
+ $minuten = intval(substr($s, 2, 2));
+ $sekunden = $len != 6 ? 0 : intval(substr($s, 4, 2));
+ } else if ($n == 2 || $n == 3) {
+ $stunden = intval($t[0]);
+ $minuten = intval($t[1]);
+ $sekunden = $n != 3 ? 0 : intval($t[2]);
+ } else
+ return NULL;
+
+ if ($stunden < 0 || $stunden > 23 || $minuten < 0 || $minuten > 59 || $sekunden < 0 || $sekunden > 59)
+ return NULL;
+
+ return sprintf("%02d:%02d:%02d", $stunden, $minuten, $sekunden);
+}
+
+function runden_detailliert_invers($runden): ?string
+{
+ if ($runden == null)
+ return null;
+ $runden_invers = "";
+ $saetze = explode(" ", $runden);
+ foreach ($saetze as $satz) {
+ $punkte = explode(":", $satz);
+ if (!empty($runden_invers))
+ $runden_invers .= " ";
+ $runden_invers .= $punkte[1] . ":" . $punkte[0];
+ }
+ return $runden_invers;
+}
+
+function runden_detailliert_auswertung($runden): array
+{
+ $ergebnis = 0;
+ $heim_saetze = 0;
+ $unentschieden_saetze = 0;
+ $gast_saetze = 0;
+ $heim_punkte = 0;
+ $gast_punkte = 0;
+ if ($runden != null) {
+ $saetze = explode(" ", $runden);
+ foreach ($saetze as $satz) {
+ $punkte = explode(":", $satz);
+ $heim_punkte += (int)$punkte[0];
+ $gast_punkte += (int)$punkte[1];
+ if ($punkte[0] > $punkte[1])
+ $heim_saetze++;
+ else if ($punkte[0] < $punkte[1])
+ $gast_saetze++;
+ else
+ $unentschieden_saetze++;
+ }
+ if ($heim_saetze > $gast_saetze)
+ $ergebnis = 1;
+ else if ($heim_saetze < $gast_saetze)
+ $ergebnis = 2;
+ }
+ return array($ergebnis, $heim_saetze, $unentschieden_saetze, $gast_saetze, $heim_punkte, $gast_punkte);
+}
+
+function spielpunkteFuerSpiel($wertung, $heim_punkte, $gast_punkte, $ergebnis_detailliert = null): array
+{
+ if ($wertung == 2)
+ return array($heim_punkte, $gast_punkte);
+ $je_satz = $wertung >= 10;
+ $grund = $wertung % 10;
+ $sieg = $grund == 0 ? 2 : ($grund == 1 ? 3 : 1);
+ $remis = $grund == 3 ? 0 : 1;
+ if ($je_satz) {
+ if (empty($ergebnis_detailliert))
+ return array($sieg * (int)$heim_punkte, $sieg * (int)$gast_punkte);
+ $auswertung = runden_detailliert_auswertung($ergebnis_detailliert);
+ return array($sieg * $auswertung[1] + $remis * $auswertung[2],
+ $sieg * $auswertung[3] + $remis * $auswertung[2]);
+ }
+ if ($heim_punkte > $gast_punkte)
+ return array($sieg, 0);
+ if ($heim_punkte < $gast_punkte)
+ return array(0, $sieg);
+ if ($heim_punkte == 0 && $gast_punkte == 0)
+ return array(0, 0);
+ return array($remis, $remis);
+}
+
+function toreFuerSpiel($punktetyp, $satzergebnisse, $heim_punkte, $gast_punkte, $ergebnis_detailliert): array
+{
+ if ($punktetyp == 0)
+ return array((int)$heim_punkte, (int)$gast_punkte);
+ if (!empty($satzergebnisse) && !empty($ergebnis_detailliert)) {
+ $auswertung = runden_detailliert_auswertung($ergebnis_detailliert);
+ return array($auswertung[4], $auswertung[5]);
+ }
+ return array(null, null);
+}
+
+function jeSatzWertung($wertung_einzel, $wertung_doppel): bool
+{
+ return $wertung_einzel >= 10 || $wertung_doppel >= 10;
+}
+
+function ausgetragenBedingung($je_satz, $alias): string
+{
+ return "($alias.heim_punkte != 0 OR $alias.gast_punkte != 0"
+ . ($je_satz ? " OR NOT ISNULL($alias.heim_tore)" : "") . ")";
+}
+
+function ergebnisVorhanden($je_satz, $heim_punkte, $gast_punkte, $heim_tore): bool
+{
+ return $heim_punkte != null || $gast_punkte != null || ($je_satz && $heim_tore !== null);
+}
+
+function saetzeRemisFuerSpiel($punktetyp, $satzergebnisse, $ergebnis_detailliert): ?int
+{
+ if ($punktetyp == 0 || empty($satzergebnisse) || empty($ergebnis_detailliert))
+ return null;
+ $auswertung = runden_detailliert_auswertung($ergebnis_detailliert);
+ return $auswertung[2];
+}
+
+// pass two file names
+// returns TRUE if files are the same, FALSE otherwise
+function files_identical($fn1, $fn2): bool
+{
+ if (!is_file($fn1) || !is_file($fn2))
+ return FALSE;
+
+ if (filesize($fn1) !== filesize($fn2))
+ return FALSE;
+
+ if (!$fp1 = fopen($fn1, 'rb'))
+ return FALSE;
+
+ if (!$fp2 = fopen($fn2, 'rb')) {
+ fclose($fp1);
+ return FALSE;
+ }
+
+ $same = TRUE;
+ while (!feof($fp1) and !feof($fp2))
+ if (fread($fp1, 4096) !== fread($fp2, 4096)) {
+ $same = FALSE;
+ break;
+ }
+
+ if (feof($fp1) !== feof($fp2))
+ $same = FALSE;
+
+ fclose($fp1);
+ fclose($fp2);
+
+ return $same;
+}
+