From 4695506d9ea6d0dce90e16f12ae0bb215ce1a01b Mon Sep 17 00:00:00 2001
From: Jan-Hendrik Willms <tleilax+studip@gmail.com>
Date: Mon, 17 Oct 2022 14:50:20 +0000
Subject: [PATCH] fix php8 warnings, fixes #1679

Closes #1679

Merge request studip/studip!1084
---
 app/controllers/calendar/calendar.php         | 12 ++---
 app/controllers/calendar/schedule.php         |  1 +
 app/controllers/contact.php                   |  3 +-
 app/controllers/course/details.php            |  6 +--
 app/controllers/course/members.php            |  1 +
 app/controllers/elearning.php                 | 12 +++--
 app/controllers/news.php                      |  4 +-
 app/controllers/profilemodules.php            | 12 ++---
 app/controllers/search/archive.php            |  1 +
 app/controllers/settings/statusgruppen.php    |  2 +-
 app/views/api/authorizations/index.php        |  4 +-
 app/views/calendar/schedule/index.php         |  2 +-
 app/views/course/details/index.php            |  8 ++--
 app/views/course/feedback/index_for.php       |  4 +-
 app/views/course/members/autor_list.php       |  4 +-
 app/views/course/plus/index.php               |  4 +-
 .../course/wizard/steps/studyareas/_node.php  |  2 +-
 app/views/files/_fileref_tr.php               |  4 +-
 app/views/files/_files_thead.php              | 18 +++----
 app/views/files/_overview.php                 |  2 +-
 app/views/files/index.php                     |  4 +-
 .../files_dashboard/_input-group-search.php   |  4 +-
 app/views/score/index.php                     | 12 ++---
 app/views/settings/studies/index.php          |  4 +-
 lib/calendar/CalendarColumn.class.php         |  2 +-
 lib/classes/ForumHelpers.php                  |  2 +-
 lib/classes/I18NString.php                    |  2 +-
 lib/classes/LinkButton.class.php              | 17 ++++---
 lib/classes/ModulesNotification.class.php     | 13 +++--
 lib/classes/MultiPersonSearch.class.php       | 26 +++++-----
 lib/classes/SemBrowse.class.php               |  2 +-
 lib/classes/SemClass.class.php                |  3 +-
 lib/classes/SmileyFormat.php                  |  2 +-
 lib/classes/WikiFormat.php                    |  2 +-
 .../calendar/CalendarScheduleModel.php        |  2 +-
 .../HTMLPurifier_Injector_TransformLinks.php  |  2 +-
 lib/filesystem/FileManager.php                | 10 ++--
 lib/functions.php                             |  8 ++--
 lib/meine_seminare_func.inc.php               | 19 ++++++--
 lib/models/BlubberThread.php                  |  3 ++
 lib/models/DataField.class.php                |  2 +-
 lib/models/DatafieldEntryModel.class.php      |  4 +-
 lib/models/StudipNews.class.php               | 46 +++++++++---------
 lib/models/User.class.php                     |  2 +-
 lib/models/resources/Resource.class.php       |  2 +-
 lib/user_visible.inc.php                      |  2 +-
 lib/visual.inc.php                            |  4 +-
 templates/dates/seminar_html_location.php     | 27 ++++++-----
 templates/header.php                          |  2 +-
 templates/layouts/base.php                    |  2 +-
 templates/shared/pagechooser.php              |  4 +-
 .../sidebar/room-search-criteria-seats.php    |  2 +-
 tests/unit/lib/classes/LinkButtonTest.php     | 48 ++++++++++++-------
 53 files changed, 223 insertions(+), 169 deletions(-)

diff --git a/app/controllers/calendar/calendar.php b/app/controllers/calendar/calendar.php
index 65dafa20cbc..5ad138fc79e 100644
--- a/app/controllers/calendar/calendar.php
+++ b/app/controllers/calendar/calendar.php
@@ -109,12 +109,12 @@ class Calendar_CalendarController extends AuthenticatedController
             $tmpl->action_url = $this->url_for('calendar/group/switch');
             $tmpl->view = $this->action;
             $filters->addElement(new WidgetElement($tmpl->render()));
-            $filters->addCheckbox(_('Abgelehnte Termine anzeigen'),
-                    $this->settings['show_declined'],
-                    $this->url_for($this->base . 'show_declined',
-                            ['show_declined' => 1]),
-                    $this->url_for($this->base . 'show_declined',
-                            ['show_declined' => 0]));
+            $filters->addCheckbox(
+                _('Abgelehnte Termine anzeigen'),
+                $this->settings['show_declined'] ?? false,
+                $this->url_for($this->base . 'show_declined', ['show_declined' => 1]),
+                $this->url_for($this->base . 'show_declined', ['show_declined' => 0])
+            );
         }
         Sidebar::get()->addWidget($filters);
     }
diff --git a/app/controllers/calendar/schedule.php b/app/controllers/calendar/schedule.php
index c20fbea88c8..9b106bd40f4 100644
--- a/app/controllers/calendar/schedule.php
+++ b/app/controllers/calendar/schedule.php
@@ -63,6 +63,7 @@ class Calendar_ScheduleController extends AuthenticatedController
     {
         $schedule_settings = CalendarScheduleModel::getScheduleSettings();
         $inst_mode = false;
+        $institute_id = null;
         if ($GLOBALS['perm']->have_perm('admin')) {
             $inst_mode = true;
         }
diff --git a/app/controllers/contact.php b/app/controllers/contact.php
index 35b693c565e..0225149222c 100644
--- a/app/controllers/contact.php
+++ b/app/controllers/contact.php
@@ -76,6 +76,7 @@ class ContactController extends AuthenticatedController
             $selected = $this->group;
             $contacts = SimpleCollection::createFromArray(User::findMany($selected->members->pluck('user_id')));
         } else {
+            $selected = false;
             $contacts = User::findCurrent()->contacts;
         }
         $contacts = $contacts->filter(function($u) {
@@ -206,7 +207,7 @@ class ContactController extends AuthenticatedController
         $letterlist = new SidebarWidget();
         $html       = '';
         foreach (range('A', 'Z') as $letter) {
-            if ($this->contacts[$letter]) {
+            if (!empty($this->contacts[$letter])) {
                 $html .= "<a href=\"#letter_{$letter}\">{$letter}</a>";
             } else {
                 $html .= "<span>{$letter}</span>";
diff --git a/app/controllers/course/details.php b/app/controllers/course/details.php
index 5eaedf763d6..a956f07de5b 100644
--- a/app/controllers/course/details.php
+++ b/app/controllers/course/details.php
@@ -24,7 +24,7 @@ class Course_DetailsController extends AuthenticatedController
     {
         parent::before_filter($action, $args);
 
-        $course_id = Request::option('sem_id', $args[0]);
+        $course_id = Request::option('sem_id', $args[0] ?? null);
         if (empty($course_id)) {
             checkObject(); //wirft Exception, wenn Context::get() leer ist
             $course_id = $GLOBALS['SessionSeminar'];
@@ -217,7 +217,7 @@ class Course_DetailsController extends AuthenticatedController
                 Icon::create('print'),
                 ['class' => 'print_action', 'target' => '_blank']
             );
-            if ($enrolment_info['enrolment_allowed'] && $sidebarlink) {
+            if (isset($enrolment_info) && $enrolment_info['enrolment_allowed'] && $sidebarlink) {
                 if (in_array($enrolment_info['cause'], ['member', 'root', 'courseadmin'])) {
                     $abo_msg = _('direkt zur Veranstaltung');
                 } else {
@@ -291,7 +291,7 @@ class Course_DetailsController extends AuthenticatedController
             );
             $sidebar->addWidget($share);
 
-            if ($enrolment_info['description']) {
+            if (isset($enrolment_info) && $enrolment_info['description']) {
                 PageLayout::postInfo($enrolment_info['description']);
             }
         }
diff --git a/app/controllers/course/members.php b/app/controllers/course/members.php
index 1fe9f57e70a..c0c5075dd85 100644
--- a/app/controllers/course/members.php
+++ b/app/controllers/course/members.php
@@ -145,6 +145,7 @@ class Course_MembersController extends AuthenticatedController
         $this->studipticket = Seminar_Session::get_ticket();
         $this->subject = $this->getSubject();
         $this->groups = $this->status_groups;
+        $this->semAdmissionEnabled = false;
         // Check Seminar
         $this->waitingTitle = _('Warteliste (nicht aktiv)');
         $this->waiting_type = 'awaiting';
diff --git a/app/controllers/elearning.php b/app/controllers/elearning.php
index 082a210da41..97b1b9058e0 100644
--- a/app/controllers/elearning.php
+++ b/app/controllers/elearning.php
@@ -40,7 +40,7 @@ class ElearningController extends AuthenticatedController
         $this->cms_select = Request::quoted('cms_select');
         $GLOBALS['cms_select'] = $this->cms_select;
         $this->cms_list = [];
-        if ($_SESSION['elearning_open_close']["type"] != "user") {
+        if (isset($_SESSION['elearning_open_close']) && $_SESSION['elearning_open_close']["type"] != "user") {
             unset($_SESSION['elearning_open_close']);
         }
         $_SESSION['elearning_open_close']["type"] = "user";
@@ -140,6 +140,7 @@ class ElearningController extends AuthenticatedController
         $sidebar = Sidebar::get();
         $widget = new ActionsWidget();
 
+        $link_count = 0;
         if ($GLOBALS['perm']->have_perm('autor') AND count($this->cms_list)) {
             foreach($this->cms_list as $cms_key => $cms_data) {
                 if ($connected_cms[$cms_key]->user->isConnected()) {
@@ -153,13 +154,16 @@ class ElearningController extends AuthenticatedController
                 }
             }
         }
-        if ($link_count)
+        if ($link_count) {
             $sidebar->addWidget($widget);
+        }
 
         // terminate objects
-        if (is_array($connected_cms))
-            foreach($connected_cms as $system)
+        if (is_array($connected_cms)) {
+            foreach ($connected_cms as $system) {
                 $system->terminate();
+            }
+        }
 
        if (is_array($messages)) {
            foreach ($messages as $mtype => $mtext) {
diff --git a/app/controllers/news.php b/app/controllers/news.php
index d41ee6398c2..2048ec7e599 100644
--- a/app/controllers/news.php
+++ b/app/controllers/news.php
@@ -435,7 +435,7 @@ class NewsController extends StudipController
         } else {
             $this->news_startdate = time();
         }
-        if (is_array($this->area_structure[$area_type])) {
+        if (isset($this->area_structure[$area_type]) && is_array($this->area_structure[$area_type])) {
             $this->area_type = $area_type;
         }
         PageLayout::setTitle(_('Meine Ankündigungen'));
@@ -523,7 +523,7 @@ class NewsController extends StudipController
         $counter = 0;
         // check for delete-buttons and news limit
         foreach ($this->area_structure as $type => $area_data) {
-            if (is_array($this->news_items[$type])) {
+            if (isset($this->news_items[$type]) && is_array($this->news_items[$type])) {
                 foreach($this->news_items[$type] as $key => $news) {
                     // has trash icon been clicked?
                     if (Request::submitted('news_remove_' . $news['object']->news_id . '_' . $news['range_id']) && Request::isPost()) {
diff --git a/app/controllers/profilemodules.php b/app/controllers/profilemodules.php
index 3c0a354681c..607a798009e 100644
--- a/app/controllers/profilemodules.php
+++ b/app/controllers/profilemodules.php
@@ -282,24 +282,24 @@ class ProfileModulesController extends AuthenticatedController
             if ($config['displaystyle'] !== 'category'){
                 $cat = 'Funktionen von A-Z';
             } else {
-                $cat = $metadata['category'] ?: 'Sonstiges';
+                $cat = !empty($metadata['category']) ? $metadata['category'] : 'Sonstiges';
             }
 
-            $icon = $metadata['icon'];
+            $icon = $metadata['icon'] ?? false;
             if ($icon && !$icon instanceof Icon) {
                 $icon = Icon::create("{$plugin->getPluginURL()}/{$metadata['icon']}");
             }
 
             $item = [
                 'id'          => $plugin->getPluginId(),
-                'name'        => $metadata['displayname'] ?: $plugin->getPluginname(),
+                'name'        => !empty($metadata['displayname']) ? $metadata['displayname'] : $plugin->getPluginname(),
                 'url'         => $plugin->getPluginURL(),
                 'activated'   => $manager->isPluginActivatedForUser($plugin->getPluginId(), $this->user->id),
                 'icon'        => $icon,
-                'abstract'    => str_replace('\n', ' ', $metadata['descriptionshort'] ?? $metadata['summary']),
-                'description' => str_replace('\n', ' ', $metadata['descriptionlong'] ?? $metadata['description']),
+                'abstract'    => str_replace('\n', ' ', $metadata['descriptionshort'] ?? $metadata['summary'] ?? ''),
+                'description' => str_replace('\n', ' ', $metadata['descriptionlong'] ?? $metadata['description'] ?? ''),
                 'screenshots' => [],
-                'keywords'    => $metadata['keywords'] ? explode(';', $metadata['keywords']) : [],
+                'keywords'    => isset($metadata['keywords']) ? explode(';', $metadata['keywords']) : [],
                 'homepage'    => $metadata['homepage'] ?? '',
                 'helplink'    => $metadata['helplink'] ?? '',
             ];
diff --git a/app/controllers/search/archive.php b/app/controllers/search/archive.php
index 624baeb7801..927650810e9 100644
--- a/app/controllers/search/archive.php
+++ b/app/controllers/search/archive.php
@@ -39,6 +39,7 @@ class Search_ArchiveController extends AuthenticatedController
         $this->teacher   = trim(Request::get('teacher'));
         $this->semester  = Request::get('semester');
         $this->institute = Request::get('institute');
+        $this->courses   = [];
 
         // the optional parameter my_courses_only says that only the courses of
         // the current user shall be searched with the search criteria
diff --git a/app/controllers/settings/statusgruppen.php b/app/controllers/settings/statusgruppen.php
index fd7d91c1f55..789d0ca8032 100644
--- a/app/controllers/settings/statusgruppen.php
+++ b/app/controllers/settings/statusgruppen.php
@@ -45,6 +45,7 @@ class Settings_StatusgruppenController extends Settings_SettingsController
     public function index_action($verify_action = null, $verify_id = null)
     {
         $all_rights = false;
+        $admin_insts = [];
         if ($this->user->username != $GLOBALS['user']->username) {
             $query = "SELECT Institut_id
                       FROM Institute
@@ -79,7 +80,6 @@ class Settings_StatusgruppenController extends Settings_SettingsController
             $statement->execute($parameters);
             $institutes = $statement->fetchAll(PDO::FETCH_ASSOC);
 
-            $admin_insts = [];
             foreach ($institutes as $institute) {
                 $institute['groups'] = GetAllStatusgruppen($institute['Institut_id'], $this->user->id) ?: [];
 
diff --git a/app/views/api/authorizations/index.php b/app/views/api/authorizations/index.php
index 1b07dad7c1b..95645f46220 100644
--- a/app/views/api/authorizations/index.php
+++ b/app/views/api/authorizations/index.php
@@ -22,8 +22,8 @@
                 <? else: ?>
                     <?= htmlReady($consumer->title) ?>
                 <? endif; ?>
-                <? if ($type = $types[$consumer->type]): ?>
-                    <small>(<?= htmlReady($type) ?>)</small>
+                <? if (isset($types[$consumer->type])): ?>
+                    <small>(<?= htmlReady($types[$consumer->type]) ?>)</small>
                 <? endif; ?>
                 </h3>
             <? if ($consumer->description): ?>
diff --git a/app/views/calendar/schedule/index.php b/app/views/calendar/schedule/index.php
index 31339f5e6bb..45a4c328b66 100644
--- a/app/views/calendar/schedule/index.php
+++ b/app/views/calendar/schedule/index.php
@@ -72,7 +72,7 @@ $sidebar->addWidget($options, 'calendar/schedule/options');
     <?= htmlReady($current_semester['name']) ?>
 </div>
 
-<? if ($show_entry) : ?>
+<? if (!empty($show_entry)) : ?>
     <div class="ui-widget-overlay" style="width: 100%; height: 100%; z-index: 1001;"></div>
     <?= $this->render_partial('calendar/schedule/_dialog', [
         'content_for_layout' => $this->render_partial('calendar/schedule/entry', [
diff --git a/app/views/course/details/index.php b/app/views/course/details/index.php
index 7621519f5b5..0e8249405b7 100644
--- a/app/views/course/details/index.php
+++ b/app/views/course/details/index.php
@@ -138,7 +138,7 @@
             <? endif ?>
             </td>
         </tr>
-    <? elseif ($children) : ?>
+    <? elseif (!empty($children)) : ?>
         <tr>
             <td><strong><?= _('Unterveranstaltungen') ?></strong></td>
             <td>
@@ -343,7 +343,7 @@
     </article>
 <? endif ?>
 
-<? if ($studyAreaTree && $studyAreaTree->required_children) : ?>
+<? if (isset($studyAreaTree) && $studyAreaTree->required_children) : ?>
     <article class="studip">
         <header>
             <h1><?= _('Studienbereiche') ?></h1>
@@ -384,7 +384,7 @@
 
 <?
 // Ausgabe der Modulzuordnung MVV
-if ($mvv_tree) : ?>
+if (!empty($mvv_tree)) : ?>
     <article class="studip">
         <header>
             <h1><?= _('Modulzuordnungen') ?></h1>
@@ -400,7 +400,7 @@ if ($mvv_tree) : ?>
     </article>
 <? endif; ?>
 
-<? if ($mvv_pathes) : ?>
+<? if (!empty($mvv_pathes)) : ?>
     <article class="studip">
         <header>
             <h1><?= _('Modulzuordnungen') ?></h1>
diff --git a/app/views/course/feedback/index_for.php b/app/views/course/feedback/index_for.php
index 7e27bfd9222..d2e82e6b778 100644
--- a/app/views/course/feedback/index_for.php
+++ b/app/views/course/feedback/index_for.php
@@ -8,7 +8,7 @@
         <? if($create_perm) : ?>
         <nav>
             <a href="<?= $controller->link_for('course/feedback/create_form/' . $range_id . '/' . $range_type) ?>"
-                title="<?= _('Neues Feedback-Element') ?>" class="feedback-add" data-id="<?= $feedback->id ?>"
+                title="<?= _('Neues Feedback-Element') ?>" class="feedback-add" data-id="<?= $feedback ? $feedback->id : '' ?>"
                 data-dialog="">
                 <?= Icon::create('add'); ?>
             </a>
@@ -19,4 +19,4 @@
         <?= $this->render_partial('course/feedback/_feedback_stream.php' , ['feedback' => $feedback]) ?>
     <? endforeach; ?>
 </article>
-<? endif; ?>
\ No newline at end of file
+<? endif; ?>
diff --git a/app/views/course/members/autor_list.php b/app/views/course/members/autor_list.php
index e40a4547e46..5c2ca173ad7 100644
--- a/app/views/course/members/autor_list.php
+++ b/app/views/course/members/autor_list.php
@@ -81,7 +81,7 @@
             </tr>
         </thead>
         <tbody>
-        <? $nr = $autor_nr?>
+        <? $nr = $autor_nr ?? 0; ?>
         <? foreach ($autoren as $autor) : ?>
             <? $fullname = $autor['fullname']?>
             <tr>
@@ -175,7 +175,7 @@
                 </td>
             </tr>
         <? endforeach ?>
-        <? if ($invisibles > 0) : ?>
+        <? if (!empty($invisibles)) : ?>
             <tr>
                 <td colspan="<?= $cols ?>" class="blank"></td>
             </tr>
diff --git a/app/views/course/plus/index.php b/app/views/course/plus/index.php
index f3a348fcc5a..a034f5790f7 100644
--- a/app/views/course/plus/index.php
+++ b/app/views/course/plus/index.php
@@ -25,7 +25,7 @@ use Studip\Button;
                 if ($_SESSION['plus']['displaystyle'] != 'category' && $category != 'Funktionen von A-Z') {
                     $visibility = 'invisible';
                 }
-                if (isset($_SESSION['plus']) && !$_SESSION['plus']['Kategorie'][$category] && $category != 'Funktionen von A-Z') {
+                if (isset($_SESSION['plus']) && empty($_SESSION['plus']['Kategorie'][$category]) && $category != 'Funktionen von A-Z') {
                     $visibility = 'invisible';
                 }
                 ?>
@@ -61,7 +61,7 @@ use Studip\Button;
                                        id="<?= $key ?>"
                                        name="<?= $key ?>"
                                        data-moduleclass="<?= htmlReady($val['moduleclass']) ?>"
-                                       data-key="<?= htmlReady($val['modulkey']) ?>"
+                                       data-key="<?= htmlReady($val['modulkey'] ?? '') ?>"
                                        value="TRUE" <?= $cb_disabled ?> <?= $cb_checked ?>
                                        onClick="STUDIP.Plus.setModule.call(this);">
                                 <div class="element_header">
diff --git a/app/views/course/wizard/steps/studyareas/_node.php b/app/views/course/wizard/steps/studyareas/_node.php
index 75e37c250ab..00238a436ea 100644
--- a/app/views/course/wizard/steps/studyareas/_node.php
+++ b/app/views/course/wizard/steps/studyareas/_node.php
@@ -1,4 +1,4 @@
-<?php if (!$search_result || in_array($node->id, $search_result)) : ?>
+<?php if (empty($search_result) || in_array($node->id, $search_result)) : ?>
 <li class="sem-tree-<?= htmlReady($node->id) ?> keep-node" data-id="<?= $node->id ?>">
     <?php if ($node->isAssignable()) : ?>
     <?= Icon::create('arr_2left', 'sort')->asInput(["name" => 'assign['.$node->id.']', "onclick" => "return STUDIP.CourseWizard.assignNode('".$node->id."')", "class" => in_array($node->id,$values['studyareas']?:[])?'hidden-no-js':'', "style" => in_array($node->id,$values['studyareas']?:[])?'display:none':false]) ?>
diff --git a/app/views/files/_fileref_tr.php b/app/views/files/_fileref_tr.php
index 2bf7fe2db36..7ab64a7f8f4 100644
--- a/app/views/files/_fileref_tr.php
+++ b/app/views/files/_fileref_tr.php
@@ -17,7 +17,7 @@ if ($file->isDownloadable($GLOBALS['user']->id)) {
                 <input type="checkbox"
                        name="ids[]"
                        value="<?= htmlReady($file->getId()) ?>"
-                       <?= in_array($file->getId(), (array) $marked_element_ids) ? 'checked' : '' ?>>
+                       <?= in_array($file->getId(), (array) ($marked_element_ids ?? [])) ? 'checked' : '' ?>>
             <? endif ?>
         </td>
     <? endif ?>
@@ -40,7 +40,7 @@ if ($file->isDownloadable($GLOBALS['user']->id)) {
         <? endif ?>
 
         <?php $terms = $file->getTermsOfUse() ?>
-        <? if ($terms && !$terms->isDownloadable($topFolder->range_id, $topFolder->range_type, false)) : ?>
+        <? if ($terms && !empty($topFolder) && !$terms->isDownloadable($topFolder->range_id, $topFolder->range_type, false)) : ?>
             <?= Icon::create('lock-locked', Icon::ROLE_INFO)->asImg(['title' => _('Das Herunterladen dieser Datei ist nur eingeschränkt möglich.')]) ?>
         <? endif ?>
     </td>
diff --git a/app/views/files/_files_thead.php b/app/views/files/_files_thead.php
index 4bad9f793b0..a6024e97dc8 100644
--- a/app/views/files/_files_thead.php
+++ b/app/views/files/_files_thead.php
@@ -1,11 +1,11 @@
 <colgroup>
-    <? if ($show_bulk_checkboxes) : ?>
+    <? if (!empty($show_bulk_checkboxes)) : ?>
         <col width="30px" data-filter-ignore>
     <? endif ?>
         <col width="20px" data-filter-ignore>
         <col>
         <col width="100px" class="responsive-hidden" data-filter-ignore>
-    <? if ($show_downloads) : ?>
+    <? if (!empty($show_downloads)) : ?>
         <col width="100px" class="responsive-hidden" data-filter-ignore>
     <? endif; ?>
         <col width="150px" class="responsive-hidden">
@@ -17,11 +17,11 @@
             <? if ($show_bulk_checkboxes) : ?>
                 <th data-sort="false">
                     <input type="checkbox"
-                           <?= $table_id
+                           <?= !empty($table_id)
                              ? 'data-proxyfor="table.documents[data-table_id=\'' . htmlReady($table_id) . '\'] tbody :checkbox"'
                              : 'data-proxyfor="table.documents tbody :checkbox"'
                            ?>
-                           <?= $table_id
+                           <?= !empty($table_id)
                              ? 'data-activates="table.documents[data-table_id=\'' . htmlReady($table_id) . '\'] tfoot .multibuttons .button"'
                              : 'data-activates="table.documents tfoot .multibuttons .button"'
                            ?>
@@ -36,11 +36,11 @@
         <? endif ?>
             <th data-sort="text" class="responsive-hidden"><?= _('Autor/-in') ?></th>
             <th data-sort="htmldata" class="responsive-hidden"><?= _('Datum') ?></th>
-            <? if ($topFolder) : ?>
-                <? foreach ($topFolder->getAdditionalColumns() as $index => $column_name) : ?>
-                    <th data-sort="htmldata" class="responsive-hidden"><?=htmlReady($column_name) ?></th>
-                <? endforeach ?>
-            <? endif ?>
+        <? if (isset($topFolder) && $topFolder instanceof FolderType) : ?>
+            <? foreach ($topFolder->getAdditionalColumns() as $column_name) : ?>
+                <th data-sort="htmldata" class="responsive-hidden"><?=htmlReady($column_name) ?></th>
+            <? endforeach ?>
+        <? endif ?>
             <th data-sort="false"><?= _('Aktionen') ?></th>
         </tr>
     </thead>
diff --git a/app/views/files/_overview.php b/app/views/files/_overview.php
index 6fd203f5612..90278226daa 100644
--- a/app/views/files/_overview.php
+++ b/app/views/files/_overview.php
@@ -102,6 +102,6 @@
     </div>
 <? endif ?>
 
-<? if ($no_files) : ?>
+<? if (!empty($no_files)) : ?>
     <?= MessageBox::info(_('Es sind keine Dateien vorhanden, die für Sie zugänglich sind!')) ?>
 <? endif ?>
diff --git a/app/views/files/index.php b/app/views/files/index.php
index a0fc2bcbfdd..94ae3f4defb 100644
--- a/app/views/files/index.php
+++ b/app/views/files/index.php
@@ -1,6 +1,6 @@
 <? if ($topFolder): ?>
     <?php
-    if (!$controllerpath) {
+    if (empty($controllerpath)) {
         $controllerpath = 'files/index';
         if ($topFolder->range_type !== 'user') {
             $controllerpath = $topFolder->range_type . '/' . $controllerpath;
@@ -81,7 +81,7 @@
     }
     ?>
 
-    <? if ($show_file_search) : ?>
+    <? if (!empty($show_file_search)) : ?>
         <form class="default" method="get" action="<?= $controller->link_for('files_dashboard/search') ?>">
             <?= $this->render_partial('files_dashboard/_input-group-search') ?>
         </form>
diff --git a/app/views/files_dashboard/_input-group-search.php b/app/views/files_dashboard/_input-group-search.php
index 0606b6876c4..258f83b1f00 100644
--- a/app/views/files_dashboard/_input-group-search.php
+++ b/app/views/files_dashboard/_input-group-search.php
@@ -1,7 +1,7 @@
 <div class="input-group files-search">
     <input
         name="q"
-        value="<?= htmlReady($query) ?>"
+        value="<?= htmlReady($query ?? '') ?>"
         placeholder="<?= _('Was suchen Sie?') ?>"
         aria-label="<?= _('Was suchen Sie?') ?>"
         minlength="4"
@@ -13,7 +13,7 @@
             <?= Icon::create('search')->asImg(['title' => _("Suche starten")]) ?>
         </button>
 
-        <? if ($query != '') : ?>
+        <? if (!empty($query)) : ?>
             <?= \Studip\LinkButton::createReset(_('Zurücksetzen'), $controller->url_for('files_dashboard/search')) ?>
         <? endif ?>
     </span>
diff --git a/app/views/score/index.php b/app/views/score/index.php
index d20802615c0..3e9a4a037fa 100644
--- a/app/views/score/index.php
+++ b/app/views/score/index.php
@@ -63,8 +63,8 @@
             $content = Assets::img('blank.gif', ['width' => 16]) . ' ';
 
             // News
-            if ($news = $person['newscount']) {
-                $tmp = sprintf(ngettext('Eine persönliche Ankündigung', '%s persönliche Ankündigungen', $news), $news);
+            if (!empty($person['newscount'])) {
+                $tmp = sprintf(ngettext('Eine persönliche Ankündigung', '%s persönliche Ankündigungen', $person['newscount']), $person['newscount']);
                 $content .= sprintf(
                     '<a href="%s">%s</a> ',
                     URLHelper::getLink('dispatch.php/profile?username=' . $person['username']),
@@ -75,8 +75,8 @@
             }
 
             // Votes
-            if ($vote = $person['votecount']) {
-                $tmp = sprintf(ngettext('Eine Umfrage', '%s Umfragen', $vote), $vote);
+            if (!empty($person['votecount'])) {
+                $tmp = sprintf(ngettext('Eine Umfrage', '%s Umfragen', $person['votecount']), $person['votecount']);
                 $content .= sprintf(
                     '<a href="%s">%s</a> ',
                     URLHelper::getLink('dispatch.php/profile?username=' . $person['username'] . '#questionnaire_area'),
@@ -87,8 +87,8 @@
             }
 
             // Termine
-            if ($termin = $person['eventcount']) {
-                $tmp = sprintf(ngettext('Ein Termin', '%s Termine', $termin), $termin);
+            if (!empty($person['eventcount'])) {
+                $tmp = sprintf(ngettext('Ein Termin', '%s Termine', $person['eventcount']), $person['eventcount']);
                 $content .= sprintf(
                     '<a href="%s">%s</a> ',
                     URLHelper::getLink('dispatch.php/profile?username=' . $person['username'] . '#a'),
diff --git a/app/views/settings/studies/index.php b/app/views/settings/studies/index.php
index 420114fba24..2c6cac927d8 100644
--- a/app/views/settings/studies/index.php
+++ b/app/views/settings/studies/index.php
@@ -1,2 +1,2 @@
-<?= $this->render_partial('settings/studies/studiengang', compact(words('allow_change about'))) ?>
-<?= $this->render_partial('settings/studies/institute', compact(words('allow_change about'))) ?>
+<?= $this->render_partial('settings/studies/studiengang', compact('allow_change')) ?>
+<?= $this->render_partial('settings/studies/institute', compact('allow_change')) ?>
diff --git a/lib/calendar/CalendarColumn.class.php b/lib/calendar/CalendarColumn.class.php
index cbaffec052c..9292d0cf485 100644
--- a/lib/calendar/CalendarColumn.class.php
+++ b/lib/calendar/CalendarColumn.class.php
@@ -324,7 +324,7 @@ class CalendarColumn
         $group_matrix = [];
         foreach ($this->getGroupedEntries() as $groups) {
             foreach ($groups as $group) {
-                if (is_array($group[0])) {
+                if (isset($group[0]) && is_array($group[0])) {
                     $data = $group[0];
                 } else {
                     $data = $group;
diff --git a/lib/classes/ForumHelpers.php b/lib/classes/ForumHelpers.php
index ed478adb383..3054dbc8ea4 100644
--- a/lib/classes/ForumHelpers.php
+++ b/lib/classes/ForumHelpers.php
@@ -194,7 +194,7 @@ class ForumHelpers {
             }
         }
 
-        return $online_status[$user_id] ?: 'offline';
+        return $online_status[$user_id] ?? 'offline';
     }
 
     /**
diff --git a/lib/classes/I18NString.php b/lib/classes/I18NString.php
index aebe1c8d42c..b8d666bc5e1 100644
--- a/lib/classes/I18NString.php
+++ b/lib/classes/I18NString.php
@@ -332,7 +332,7 @@ class I18NString implements JsonSerializable
         $data = [];
         foreach (array_keys(Config::get()->CONTENT_LANGUAGES) as $lang) {
             if ($lang != self::getDefaultLanguage()) {
-                $data[$lang] = mb_strlen($values[$lang]) ? $values[$lang] : null;
+                $data[$lang] = $values[$lang] ?? null;
             }
         }
         return $data;
diff --git a/lib/classes/LinkButton.class.php b/lib/classes/LinkButton.class.php
index 6d60da83b82..f203841ebe2 100644
--- a/lib/classes/LinkButton.class.php
+++ b/lib/classes/LinkButton.class.php
@@ -36,17 +36,16 @@ class LinkButton extends Interactable
     public function __toString()
     {
         // add "button" to attribute @class
-        $this->attributes['class'] .= ' button';
-
-        $attributes = [];
-        ksort($this->attributes);
-        foreach ($this->attributes as $k => $v) {
-            $attributes[] = sprintf(' %s="%s"', $k, htmlReady($v));
+        if (!isset($this->attributes['class'])) {
+            $this->attributes['class'] = '';
         }
+        $this->attributes['class'] .= ' button';
 
         // TODO: URLHelper...?!
-        return sprintf('<a%s>%s</a>',
-                       join('', $attributes),
-                       htmlReady($this->label));
+        return sprintf(
+            '<a %s>%s</a>',
+            arrayToHtmlAttributes($this->attributes),
+            htmlReady($this->label)
+        );
     }
 }
diff --git a/lib/classes/ModulesNotification.class.php b/lib/classes/ModulesNotification.class.php
index ae86645f1c6..888052ab865 100644
--- a/lib/classes/ModulesNotification.class.php
+++ b/lib/classes/ModulesNotification.class.php
@@ -41,13 +41,18 @@ class ModulesNotification
     public $registered_notification_modules = [];
     public $subject;
 
-    function __construct ()
+    public function __construct ()
     {
         foreach (MyRealmModel::getDefaultModules() as $id => $module) {
-            if (!is_object($module)) continue;
+            if (!is_object($module)) {
+                continue;
+            }
+
+            $metadata = $module->getMetadata();
+
             $this->registered_notification_modules[$id] = [
-                'icon' => $module->getMetadata()['icon'],
-                'name' => $module->getMetadata()['displayname'] ?: $module->getPluginName()
+                'icon' => $metadata['icon'],
+                'name' => !empty($metadata['displayname'])  ? $metadata['displayname'] : $module->getPluginName(),
             ];
             if ($module instanceof CoreOverview) {
                 $this->registered_notification_modules[$id]['name'] = _("Ankündigungen");
diff --git a/lib/classes/MultiPersonSearch.class.php b/lib/classes/MultiPersonSearch.class.php
index 1b37cb0701f..eafcdbb529a 100644
--- a/lib/classes/MultiPersonSearch.class.php
+++ b/lib/classes/MultiPersonSearch.class.php
@@ -83,7 +83,7 @@ class MultiPersonSearch {
      * @return array containing all new persons
      */
     public function getAddedUsers() {
-        return $_SESSION['multipersonsearch'][$this->name]['added'] ? : [];
+        return $_SESSION['multipersonsearch'][$this->name]['added'] ?? [];
     }
 
     /**
@@ -490,17 +490,19 @@ class MultiPersonSearch {
      * restores the internal data from a session.
      */
     public function restoreFromSession() {
-        $this->title = $_SESSION['multipersonsearch'][$this->name]['title'];
-        $this->description = $_SESSION['multipersonsearch'][$this->name]['description'];
-        $this->quickfilterIds = $_SESSION['multipersonsearch'][$this->name]['quickfilterIds'];
-        $this->additionalHMTL = $_SESSION['multipersonsearch'][$this->name]['additionalHMTL'];
-        $this->executeURL = html_entity_decode($_SESSION['multipersonsearch'][$this->name]['executeURL']);
-        $this->jsFunction = $_SESSION['multipersonsearch'][$this->name]['jsFunction'];
-        $this->defaultSelectableUsersIDs = $_SESSION['multipersonsearch'][$this->name]['defaultSelectableUsersIDs'];
-        $this->defaultSelectedUsersIDs = $_SESSION['multipersonsearch'][$this->name]['defaultSelectedUsersIDs'];
-        $this->searchObject = unserialize($_SESSION['multipersonsearch'][$this->name]['searchObject']);
-        $this->navigationItem = $_SESSION['multipersonsearch'][$this->name]['navigationItem'];
-        $this->dataDialogStatus = $_SESSION['multipersonsearch'][$this->name]['dataDialogStatus'];
+        if (isset($_SESSION['multipersonsearch'][$this->name])) {
+            $this->title = $_SESSION['multipersonsearch'][$this->name]['title'];
+            $this->description = $_SESSION['multipersonsearch'][$this->name]['description'];
+            $this->quickfilterIds = $_SESSION['multipersonsearch'][$this->name]['quickfilterIds'];
+            $this->additionalHMTL = $_SESSION['multipersonsearch'][$this->name]['additionalHMTL'];
+            $this->executeURL = html_entity_decode($_SESSION['multipersonsearch'][$this->name]['executeURL']);
+            $this->jsFunction = $_SESSION['multipersonsearch'][$this->name]['jsFunction'];
+            $this->defaultSelectableUsersIDs = $_SESSION['multipersonsearch'][$this->name]['defaultSelectableUsersIDs'];
+            $this->defaultSelectedUsersIDs = $_SESSION['multipersonsearch'][$this->name]['defaultSelectedUsersIDs'];
+            $this->searchObject = unserialize($_SESSION['multipersonsearch'][$this->name]['searchObject']);
+            $this->navigationItem = $_SESSION['multipersonsearch'][$this->name]['navigationItem'];
+            $this->dataDialogStatus = $_SESSION['multipersonsearch'][$this->name]['dataDialogStatus'];
+        }
     }
 
     /**
diff --git a/lib/classes/SemBrowse.class.php b/lib/classes/SemBrowse.class.php
index 12de227fff1..f9eed7f01be 100644
--- a/lib/classes/SemBrowse.class.php
+++ b/lib/classes/SemBrowse.class.php
@@ -1298,7 +1298,7 @@ class SemBrowse {
         }
 
         // set default values
-        if (!$_SESSION['sem_browse_data']['default_sem']) {
+        if (empty($_SESSION['sem_browse_data']['default_sem'])) {
             $_SESSION['sem_browse_data']['default_sem'] =
                 Semester::getIndexById(self::getDefaultSemester(), true, true)
                         ?: 'all';
diff --git a/lib/classes/SemClass.class.php b/lib/classes/SemClass.class.php
index dbbbcd7fa35..b6ccb82e990 100644
--- a/lib/classes/SemClass.class.php
+++ b/lib/classes/SemClass.class.php
@@ -328,7 +328,8 @@ class SemClass implements ArrayAccess
      */
     public function isModuleMandatory($module)
     {
-        return $this->data['modules'][$module]['sticky']
+        return isset($this->data['modules'][$module])
+            && $this->data['modules'][$module]['sticky']
             && $this->data['modules'][$module]['activated'];
     }
 
diff --git a/lib/classes/SmileyFormat.php b/lib/classes/SmileyFormat.php
index 5b52df8e08b..e0a9034461b 100644
--- a/lib/classes/SmileyFormat.php
+++ b/lib/classes/SmileyFormat.php
@@ -51,7 +51,7 @@ class SmileyFormat extends TextFormat
         $smileys = Smiley::getShort();
         $name    = $smileys[$matches[2]] ?? '';
         return $name
-            ? $matches[1] . Smiley::getByName($name)->getImageTag() . $matches[3]
+            ? $matches[1] . Smiley::getByName($name)->getImageTag() . ($matches[3] ?? '')
             : $matches[0];
     }
 }
diff --git a/lib/classes/WikiFormat.php b/lib/classes/WikiFormat.php
index 262ab65cc93..0614010b1de 100644
--- a/lib/classes/WikiFormat.php
+++ b/lib/classes/WikiFormat.php
@@ -99,7 +99,7 @@ class WikiFormat extends StudipFormat
                 $rule['start'],
                 $rule['end'],
                 $rule['callback'],
-                $rule['before'] ?: null
+                $rule['before'] ?? null
             );
         }
     }
diff --git a/lib/classes/calendar/CalendarScheduleModel.php b/lib/classes/calendar/CalendarScheduleModel.php
index 47b65c418a7..feb79d20aa5 100644
--- a/lib/classes/calendar/CalendarScheduleModel.php
+++ b/lib/classes/calendar/CalendarScheduleModel.php
@@ -227,7 +227,7 @@ class CalendarScheduleModel
                         'title' => _("Dies ist eine vorgemerkte Veranstaltung")
                     ];
                 } else {
-                    $entry['color'] = $details['color'] ?: ($member->gruppe % 9 + 1);
+                    $entry['color'] = $details ? $details['color'] : ($member->gruppe % 9 + 1);
                 }
                 $entry['visible'] = $details ? $details['visible'] : 1;
 
diff --git a/lib/classes/htmlpurifier/HTMLPurifier_Injector_TransformLinks.php b/lib/classes/htmlpurifier/HTMLPurifier_Injector_TransformLinks.php
index 73e648bba33..59dccba30a2 100644
--- a/lib/classes/htmlpurifier/HTMLPurifier_Injector_TransformLinks.php
+++ b/lib/classes/htmlpurifier/HTMLPurifier_Injector_TransformLinks.php
@@ -10,7 +10,7 @@ class HTMLPurifier_Injector_TransformLinks extends HTMLPurifier_Injector
 
     public function handleElement(&$token)
     {
-        if ($token->name === 'a' && $token->attr['class'] === 'link-intern') {
+        if ($token->name === 'a' && isset($token->attr['class']) && $token->attr['class'] === 'link-intern') {
             $token->attr['href'] = TransformInternalLinks($token->attr['href']);
         }
     }
diff --git a/lib/filesystem/FileManager.php b/lib/filesystem/FileManager.php
index b5b85a46dbe..f5b3391b05a 100644
--- a/lib/filesystem/FileManager.php
+++ b/lib/filesystem/FileManager.php
@@ -1518,7 +1518,7 @@ class FileManager
             $documentpath .= '?' . $url_parts['query'];
         }
         $host = $url_parts['host'];
-        $port = $url_parts['port'];
+        $port = $url_parts['port'] ?? null;
         $scheme = mb_strtolower($url_parts['scheme']);
         if (!in_array($scheme, ['http', 'https']) || !$host) {
             return ['response' => 'HTTP/1.0 400 Bad Request', 'response_code' => 400];
@@ -1564,7 +1564,7 @@ class FileManager
         }
 
         $urlString = "GET {$documentpath} HTTP/1.0\r\nHost: {$host}\r\n";
-        if ($url_parts['user'] && $url_parts['pass']) {
+        if (isset($url_parts['user'], $url_parts['pass'])) {
             $pass = $url_parts['pass'];
             $user = $url_parts['user'];
             $urlString .= "Authorization: Basic " . base64_encode("{$user}:{$pass}") . "\r\n";
@@ -1606,7 +1606,7 @@ class FileManager
         }
 
         // Anderer Dateiname?
-        $disposition_header = $header['Content-Disposition'] ?: $header['content-disposition'];
+        $disposition_header = $header['Content-Disposition'] ?? $header['content-disposition'] ?? null;
         if ($disposition_header) {
             $header_parts = explode(';', $disposition_header);
             foreach ($header_parts as $part) {
@@ -1621,7 +1621,7 @@ class FileManager
         }
 
         // Weg über einen Locationheader:
-        $location_header = $header['Location'] ?: $header['location'];
+        $location_header = $header['Location'] ?? $header['location'] ?? null;
         if (in_array($header['response_code'], [300, 301, 302, 303, 305, 307]) && $location_header) {
             if (mb_strpos($location_header, 'http') !== 0) {
                 $location_header = $url_parts['scheme'] . '://' . $url_parts['host'] . '/' . $location_header;
@@ -1909,7 +1909,7 @@ class FileManager
             $range_ids[] = $course->id;
         }
         foreach ($institutes as $institute) {
-            $range_ids[] = $institute->id;
+            $range_ids[] = $institute['Institut_id'];
         }
 
         if ($with_personal_file_area) {
diff --git a/lib/functions.php b/lib/functions.php
index a86a9c4b9d5..baa77962ab3 100644
--- a/lib/functions.php
+++ b/lib/functions.php
@@ -88,11 +88,13 @@ function get_object_name($range_id, $object_type)
         $statement->execute([$range_id]);
         $row = $statement->fetch(PDO::FETCH_ASSOC);
 
-        $type = $INST_TYPE[$row['type']]['name'];
-        if (!$type) {
+        if (!$row) {
+            $name = _('Unbekannt');
             $type = _('Einrichtung');
+        } else {
+            $name = $row['Name'];
+            $type = $INST_TYPE[$row['type']]['name'] ?? _('Einrichtung');
         }
-        $name = $row['Name'];
     }
 
     return compact('name', 'type');
diff --git a/lib/meine_seminare_func.inc.php b/lib/meine_seminare_func.inc.php
index a743417239f..f2b49d7da53 100644
--- a/lib/meine_seminare_func.inc.php
+++ b/lib/meine_seminare_func.inc.php
@@ -195,17 +195,26 @@ function add_sem_name(&$my_obj)
 
 /**
  *
- * @param unknown_type $groups
- * @param unknown_type $group_key
- * @param unknown_type $group_entry
+ * @param array $groups
+ * @param string $group_key
+ * @param array $group_entry
  */
 function fill_groups(&$groups, $group_key, $group_entry)
 {
     if (is_null($group_key)){
         $group_key = 'not_grouped';
     }
-    $group_entry['name'] = str_replace(["ä","ö","ü"], ["ae","oe","ue"], mb_strtolower($group_entry['name']));
-    if (!is_array($groups[$group_key]) || (is_array($groups[$group_key]) && !in_array($group_entry, $groups[$group_key]))){
+
+    if (!isset($groups[$group_key]) || !is_array($groups[$group_key])) {
+        $groups[$group_key] = [];
+    }
+
+    $group_entry['name'] = str_replace(
+        ["ä","ö","ü"],
+        ["ae","oe","ue"],
+        mb_strtolower($group_entry['name'])
+    );
+    if (!in_array($group_entry, $groups[$group_key])) {
         $groups[$group_key][$group_entry['seminar_id']] = $group_entry;
         return true;
     } else {
diff --git a/lib/models/BlubberThread.php b/lib/models/BlubberThread.php
index 4fd36395936..70d99e25fab 100644
--- a/lib/models/BlubberThread.php
+++ b/lib/models/BlubberThread.php
@@ -961,6 +961,9 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
             }
 
             foreach ($matches[1] as $tag) {
+                if (!isset($hashtags[mb_strtolower($tag)])) {
+                    $hashtags[mb_strtolower($tag)] = 0;
+                }
                 $hashtags[mb_strtolower($tag)] += 1;
             }
         }
diff --git a/lib/models/DataField.class.php b/lib/models/DataField.class.php
index b0b5c963ba2..441db450662 100644
--- a/lib/models/DataField.class.php
+++ b/lib/models/DataField.class.php
@@ -142,7 +142,7 @@ class DataField extends SimpleORMap implements PrivacyObject
      */
     public static function permMask($perm)
     {
-        return self::$permission_masks[$perm];
+        return self::$permission_masks[$perm] ?? 0;
     }
 
     /**
diff --git a/lib/models/DatafieldEntryModel.class.php b/lib/models/DatafieldEntryModel.class.php
index 6bc851d77eb..0ae03c4a17f 100644
--- a/lib/models/DatafieldEntryModel.class.php
+++ b/lib/models/DatafieldEntryModel.class.php
@@ -115,6 +115,8 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject
         }
         if ($datafield_id !== null) {
             $one_datafield = ' AND a.datafield_id = ' . DBManager::get()->quote($datafield_id);
+        } else {
+            $one_datafield = '';
         }
 
         $query = "SELECT a.*, b.*,a.datafield_id,b.datafield_id as isset_content ";
@@ -142,7 +144,7 @@ class DatafieldEntryModel extends SimpleORMap implements PrivacyObject
             $query .= "AND ((object_class & :object_class) OR object_class IS NULL) $one_datafield ORDER BY priority";
             $params = array_merge($params, [
                 ':range_id' => (string) $range_id,
-                ':sec_range_id' => (string) $sec_range_id,
+                ':sec_range_id' => (string) ($sec_range_id ?? ''),
                 ':object_type' => $object_type,
                 ':object_class' => (int) $object_class]);
         }
diff --git a/lib/models/StudipNews.class.php b/lib/models/StudipNews.class.php
index 0c8c6f7e82d..bae4cd9618a 100644
--- a/lib/models/StudipNews.class.php
+++ b/lib/models/StudipNews.class.php
@@ -285,32 +285,33 @@ class StudipNews extends SimpleORMap implements PrivacyObject
         $query_vars[]   = $limit;
         $statement      = DBManager::get()->prepare($query);
         $statement->execute($query_vars);
-        $news_result    = $statement->fetchGrouped(PDO::FETCH_ASSOC);
-        if (is_array($news_result)) {
-            foreach($news_result as $id => $result) {
-                $objects[$area][$id]['range_id']    = $result['range_id'];
-                $objects[$area][$id]['title']       = $result['title'];
-                if ($area == 'sem') {
-                    $objects[$area][$id]['semester'] .= sprintf('(%s%s)',
-                        $result['startsem'],
-                        $result['startsem'] != $result['endsem'] ? ' - ' . $result['endsem'] : '');
-                } elseif ($area == 'user') {
-                    if ($GLOBALS['user']->id == $result['userid']) {
-                        $objects[$area][$id]['title'] = _('Ankündigungen auf Ihrer Profilseite');
-                    }
-                    else {
-                        $objects[$area][$id]['title'] = sprintf(_('Ankündigungen auf der Profilseite von %s'), get_fullname($result['userid']));
-                    }
-                } elseif ($area == 'global') {
-                    $objects[$area][$id]['title'] = _('Ankündigungen auf der Stud.IP Startseite');
+        $news_result    = $statement->fetchGrouped();
+
+        $objects = [$area => []];
+        foreach($news_result as $id => $result) {
+            $objects[$area][$id] = [
+                'range_id' => $result['range_id'],
+                'title'    => $result['title'],
+            ];
+            if ($area == 'sem') {
+                $objects[$area][$id]['semester'] .= sprintf('(%s%s)',
+                    $result['startsem'],
+                    $result['startsem'] != $result['endsem'] ? ' - ' . $result['endsem'] : '');
+            } elseif ($area == 'user') {
+                if ($GLOBALS['user']->id == $result['userid']) {
+                    $objects[$area][$id]['title'] = _('Ankündigungen auf Ihrer Profilseite');
                 }
-                if ($as_objects) {
-                    $objects[$area][$id]['object'] = new self();
-                    $objects[$area][$id]['object']->setData($result, true);
-                    $objects[$area][$id]['object']->setNew(false);
+                else {
+                    $objects[$area][$id]['title'] = sprintf(_('Ankündigungen auf der Profilseite von %s'), get_fullname($result['userid']));
                 }
+            } elseif ($area == 'global') {
+                $objects[$area][$id]['title'] = _('Ankündigungen auf der Stud.IP Startseite');
+            }
+            if ($as_objects) {
+                $objects[$area][$id]['object'] = self::build($result, false);
             }
         }
+
         return $objects;
     }
 
@@ -597,6 +598,7 @@ class StudipNews extends SimpleORMap implements PrivacyObject
         } else {
             $range_operation = $operation;
         }
+        $permission_ranges = 0;
         foreach ($this->getRanges() as $range_id) {
             if (static::haveRangePermission($range_operation, $range_id, $user_id)) {
                 if ($operation === 'view' || $operation === 'edit' || $operation === 'copy') {
diff --git a/lib/models/User.class.php b/lib/models/User.class.php
index 70b44766f2f..825df46e6d0 100644
--- a/lib/models/User.class.php
+++ b/lib/models/User.class.php
@@ -513,7 +513,7 @@ class User extends AuthUserMd5 implements Range, PrivacyObject
             $format = 'full';
         }
 
-        $sql = $GLOBALS['_fullname_sql'][$format];
+        $sql = $GLOBALS['_fullname_sql'][$format] ?? null;
         if (!$sql || $format == 'no_title') {
             return $this->vorname . ' ' . $this->nachname;
         }
diff --git a/lib/models/resources/Resource.class.php b/lib/models/resources/Resource.class.php
index e66598dd89a..999b34a9979 100644
--- a/lib/models/resources/Resource.class.php
+++ b/lib/models/resources/Resource.class.php
@@ -2340,7 +2340,7 @@ class Resource extends SimpleORMap implements StudipItem
         } else {
             //No temporary permission exist or has been retrieved.
             //Check for a "normal" permission.
-            $cached_perms = self::$permission_cache[$this->id][$user->id];
+            $cached_perms = self::$permission_cache[$this->id][$user->id] ?? null;
             if ($cached_perms === null) {
                 //The permission of the specified user is not in the
                 //permission cache. Load it from the database and store
diff --git a/lib/user_visible.inc.php b/lib/user_visible.inc.php
index cc13047bd2a..c47640efd72 100644
--- a/lib/user_visible.inc.php
+++ b/lib/user_visible.inc.php
@@ -303,7 +303,7 @@ function get_local_visibility_by_id($user_id, $context, $return_user_perm=false)
         }
     }
 
-    if ($data[$context] === null) {
+    if (!isset($data[$context])) {
         $data[$context] = Config::get()->getValue(mb_strtoupper($context) . '_VISIBILITY_DEFAULT');
     }
 
diff --git a/lib/visual.inc.php b/lib/visual.inc.php
index 9cf78c3f42b..99d80b002c3 100644
--- a/lib/visual.inc.php
+++ b/lib/visual.inc.php
@@ -132,13 +132,13 @@ function formatLinks($text, $nl2br = true) {
     $markup->addMarkup(
         'links',
         $link_markup_rule['start'],
-        $link_markup_rule['end'],
+        $link_markup_rule['end'] ?? '',
         $link_markup_rule['callback']
     );
     $markup->addMarkup(
         'emails',
         $email_markup_rule['start'],
-        $email_markup_rule['end'],
+        $email_markup_rule['end'] ?? '',
         $email_markup_rule['callback']
     );
     return $markup->format(htmlReady($text, true, $nl2br));
diff --git a/templates/dates/seminar_html_location.php b/templates/dates/seminar_html_location.php
index 53cdfad2624..976edbf7dfd 100644
--- a/templates/dates/seminar_html_location.php
+++ b/templates/dates/seminar_html_location.php
@@ -1,6 +1,9 @@
 <?
 if (!isset($link)) $link = true;
 
+$output = [];
+$output_dates = [];
+
 // condense regular dates by room
 if (is_array($dates['regular']['turnus_data'])) foreach ($dates['regular']['turnus_data'] as $cycle) :
     $first_date   = sprintf(_("ab %s"), strftime('%x', $cycle['first_date']['date']));
@@ -41,18 +44,20 @@ endforeach;
 
 
 // condense irregular dates by room
-if (is_array($dates['irregular'])) foreach ($dates['irregular'] as $date) :
-    if (isset($date['resource_id'])) :
-        $output_dates[$date['resource_id']][] = $date;
-    elseif (!empty($date['raum'])) :
-        $output_dates[$date['raum']][] = $date;
-    else :
-        $output_dates[_('k.A.')][]  = $date['tostring'];
-    endif;
-endforeach;
+if (isset($dates['irregular']) && is_array($dates['irregular'])) {
+    foreach ($dates['irregular'] as $date) :
+        if (isset($date['resource_id'])) :
+            $output_dates[$date['resource_id']][] = $date;
+        elseif (!empty($date['raum'])) :
+            $output_dates[$date['raum']][] = $date;
+        else :
+            $output_dates[_('k.A.')][]  = $date['tostring'];
+        endif;
+    endforeach;
+}
 
 // now shrink the dates for each room/freetext and add them to the output
-if (is_array($output_dates)) foreach ($output_dates as $dates) :
+foreach ($output_dates as $dates) :
     if (isset($dates[0]['resource_id'])) :
         $room_obj = Room::find($dates[0]['resource_id']);
         if ($link) {
@@ -72,7 +77,7 @@ endforeach;
 ?>
 
 
-<? if (!is_array($output) || count($output) === 0) : ?>
+<? if (count($output) === 0) : ?>
     <?= htmlReady($ort) ?: _("nicht angegeben") ?>
 <? else: ?>
     <table class="default">
diff --git a/templates/header.php b/templates/header.php
index 2f58da978d6..63602b2fd0e 100644
--- a/templates/header.php
+++ b/templates/header.php
@@ -35,7 +35,7 @@ if (isset($_COOKIE['navigation-length'])) {
         <? if (Navigation::hasItem('/links')): ?>
             <? foreach (Navigation::getItem('/links') as $nav): ?>
                 <? if ($nav->isVisible()) : ?>
-                    <li class="<? if ($nav->isActive()) echo 'active'; ?> <?= htmlReady($nav->getLinkAttributes()['class']) ?>">
+                    <li class="<? if ($nav->isActive()) echo 'active'; ?> <?= htmlReady($nav->getLinkAttributes()['class'] ?? '') ?>">
                         <a
                             <? if (is_internal_url($url = $nav->getURL())) : ?>
                                 href="<?= URLHelper::getLink($url) ?>"
diff --git a/templates/layouts/base.php b/templates/layouts/base.php
index e30d7fcdc48..527049c8a79 100644
--- a/templates/layouts/base.php
+++ b/templates/layouts/base.php
@@ -163,7 +163,7 @@ $lang_attr = str_replace('_', '-', $_SESSION['_language']);
             {
                 // indicate to the template that this course is publicly visible
                 // need to handle institutes separately (always visible)
-                if ($GLOBALS['SessSemName']['class'] == 'inst') {
+                if (isset($GLOBALS['SessSemName']['class']) && $GLOBALS['SessSemName']['class'] === 'inst') {
                     $header_template->public_hint = _('öffentliche Einrichtung');
                 } else if (Course::findCurrent()->lesezugriff == 0) {
                     $header_template->public_hint = _('öffentliche Veranstaltung');
diff --git a/templates/shared/pagechooser.php b/templates/shared/pagechooser.php
index af8d01d891e..bf8726db28c 100644
--- a/templates/shared/pagechooser.php
+++ b/templates/shared/pagechooser.php
@@ -33,7 +33,7 @@
     <li class="divider" data-skipped="<?= $last_page + 1 ?>-<?= $item - 1 ?>">&hellip;</li>
 <? endif; ?>
     <li <? if ($item == $cur_page) echo 'class="current"'; ?>>
-        <a class="pagination--link" href="<?= URLHelper::getLink(sprintf($pagelink, $item), $pageparams) ?>" <?= $dialog ?: ''?>>
+        <a class="pagination--link" href="<?= URLHelper::getLink(sprintf($pagelink, $item), $pageparams) ?>" <?= $dialog ?? ''?>>
             <span class="audible"><?= _('Seite') ?></span>
             <?= $item ?>
         </a>
@@ -44,7 +44,7 @@
 ?>
 <? if ($cur_page < $num_pages): ?>
     <li class="next">
-        <a class="pagination--link" href="<?= URLHelper::getLink(sprintf($pagelink, $cur_page + 1), $pageparams) ?>" rel="next" <?= $dialog ?: ''?>>
+        <a class="pagination--link" href="<?= URLHelper::getLink(sprintf($pagelink, $cur_page + 1), $pageparams) ?>" rel="next" <?= $dialog ?? ''?>>
             <span class="audible"><?= _('Eine Seite') ?></span>
             <?= _('weiter') ?>
         </a>
diff --git a/templates/sidebar/room-search-criteria-seats.php b/templates/sidebar/room-search-criteria-seats.php
index a947bb11366..095a0197435 100644
--- a/templates/sidebar/room-search-criteria-seats.php
+++ b/templates/sidebar/room-search-criteria-seats.php
@@ -17,7 +17,7 @@
         <input type="checkbox" class="special-item-switch" value="1"
                title="<?= _('Kriterium ausgewählt'); ?>"
                name="<?= htmlReady($criteria['name'] . '_enabled')?>"
-               <?= $criteria['enabled'] ? 'checked' : ''?>>
+               <?= !empty($criteria['enabled']) ? 'checked' : ''?>>
         <?= htmlReady($criteria['title']) ?>
     </label>
     <div class="hgroup special-item-content">
diff --git a/tests/unit/lib/classes/LinkButtonTest.php b/tests/unit/lib/classes/LinkButtonTest.php
index c83669bd1f4..697ce443124 100644
--- a/tests/unit/lib/classes/LinkButtonTest.php
+++ b/tests/unit/lib/classes/LinkButtonTest.php
@@ -20,49 +20,65 @@ class LinkButtonTestCase extends \Codeception\Test\Unit
 
     function testCreateWithLabel()
     {
-        $this->assertEquals('<a class="button" href="?">yes</a>',
-                            '' . LinkButton::create('yes'));
+        $this->assertXmlStringEqualsXmlString(
+            '<a class="button" href="?">yes</a>',
+            (string) LinkButton::create('yes')
+        );
     }
 
     function testCreateWithLabelAndUrl()
     {
-        $this->assertEquals('<a class="button" href="http://example.net">yes</a>',
-                            '' . LinkButton::create('yes', 'http://example.net'));
+        $this->assertXmlStringEqualsXmlString(
+            '<a class="button" href="http://example.net">yes</a>',
+            (string) LinkButton::create('yes', 'http://example.net')
+        );
     }
 
     function testCreateWithLabelAndArray()
     {
-        $this->assertEquals('<a a="1" b="2" class="button" href="?">yes</a>',
-                            '' . LinkButton::create('yes', ['a' => 1, 'b' => 2]));
+        $this->assertXmlStringEqualsXmlString(
+            '<a a="1" b="2" class="button" href="?">yes</a>',
+            (string) LinkButton::create('yes', ['a' => 1, 'b' => 2])
+        );
     }
 
     function testCreateWithLabelUrlAndArray()
     {
-        $this->assertEquals('<a a="1" b="2" class="button" href="http://example.net">yes</a>',
-                            '' . LinkButton::create('yes', 'http://example.net', ['a' => 1, 'b' => 2]));
+        $this->assertXmlStringEqualsXmlString(
+            '<a a="1" b="2" class="button" href="http://example.net">yes</a>',
+            (string) LinkButton::create('yes', 'http://example.net', ['a' => 1, 'b' => 2])
+        );
     }
 
     function testCreateAccept()
     {
-        $this->assertEquals('<a class="accept button" href="?" name="accept">Ãœbernehmen</a>',
-                            '' . LinkButton::createAccept());
+        $this->assertXmlStringEqualsXmlString(
+            '<a class="accept button" href="?" name="accept">Ãœbernehmen</a>',
+            (string) LinkButton::createAccept()
+        );
     }
 
     function testCreateCancel()
     {
-        $this->assertEquals('<a class="cancel button" href="?" name="cancel">Abbrechen</a>',
-                            '' . LinkButton::createCancel());
+        $this->assertXmlStringEqualsXmlString(
+            '<a class="cancel button" href="?" name="cancel">Abbrechen</a>',
+            (string) LinkButton::createCancel()
+        );
     }
 
     function testCreatePreOrder()
     {
-        $this->assertEquals('<a class="pre-order button" href="?" name="pre-order">ok</a>',
-                            '' . LinkButton::createPreOrder());
+        $this->assertXmlStringEqualsXmlString(
+            '<a class="pre-order button" href="?" name="pre-order">ok</a>',
+            (string) LinkButton::createPreOrder()
+        );
     }
 
     function testCreateWithInsaneArguments()
     {
-        $this->assertEquals('<a class="button" href="http://example.net?m=&amp;m=" mad="&lt;S&gt;tu&quot;ff">&gt;ok&lt;</a>',
-                            '' . LinkButton::create('>ok<', 'http://example.net?m=&m=', ['mad' => '<S>tu"ff']));
+        $this->assertXmlStringEqualsXmlString(
+            '<a class="button" href="http://example.net?m=&amp;m=" mad="&lt;S&gt;tu&quot;ff">&gt;ok&lt;</a>',
+            (string) LinkButton::create('>ok<', 'http://example.net?m=&m=', ['mad' => '<S>tu"ff'])
+        );
     }
 }
-- 
GitLab