diff --git a/api/src/Contacts.php b/api/src/Contacts.php
index 09acb061ad..2409357a24 100755
--- a/api/src/Contacts.php
+++ b/api/src/Contacts.php
@@ -483,7 +483,7 @@ class Contacts extends Contacts\Storage
 				'bday'     => (int)$contact['bday'] ? DateTime::to($contact['bday'], true) : $contact['bday'],
 			)));
 
-		while ($fileas[0] == ':' ||  $fileas[0] == ',')
+		while (!empty($fileas) && ($fileas[0] == ':' ||  $fileas[0] == ','))
 		{
 			$fileas = substr($fileas,2);
 		}
@@ -764,10 +764,10 @@ class Contacts extends Contacts\Storage
 				$data[$name] = DateTime::server2user($data[$name], $date_format);
 			}
 		}
-		$data['photo'] = $this->photo_src($data['id'],$data['jpegphoto'] || ($data['files'] & self::FILES_BIT_PHOTO), '', $data['etag']);
+		$data['photo'] = $this->photo_src($data['id'],!empty($data['jpegphoto']) || (($data['files']??0) & self::FILES_BIT_PHOTO), '', $data['etag'] ?? null);
 
 		// set freebusy_uri for accounts
-		if (!$data['freebusy_uri'] && !$data['owner'] && $data['account_id'] && !is_object($GLOBALS['egw_setup']))
+		if (empty($data['freebusy_uri']) && empty($data['owner']) && !empty($data['account_id']) && empty($GLOBALS['egw_setup']))
 		{
 			if ($fb_url || @is_dir(EGW_SERVER_ROOT.'/calendar/inc'))
 			{
@@ -1686,7 +1686,7 @@ class Contacts extends Contacts\Storage
 			{
 				$result[$contact['id']] = $this->link_title($contact+(array)$cfs[$contact['id']]);
 				// make sure to return a correctly quoted rfc822 address, if requested
-				if ($options['type'] === 'email')
+				if (isset($options['type']) && $options['type'] === 'email')
 				{
 					$args = explode('@', $contact['email']);
 					$args[] = $result[$contact['id']];
diff --git a/api/src/Etemplate/Widget.php b/api/src/Etemplate/Widget.php
index b5b02787a3..58e00ea8bc 100644
--- a/api/src/Etemplate/Widget.php
+++ b/api/src/Etemplate/Widget.php
@@ -114,7 +114,7 @@ class Widget
 		// Update content?
 		if(self::$cont == null)
 			self::$cont = is_array(self::$request->content) ? self::$request->content : array();
-		if($this->id && is_array(self::$cont[$this->id]))
+		if($this->id && is_array(self::$cont[$this->id] ?? null))
 		{
 			$old_cont = self::$cont;
 			self::$cont = self::$cont[$this->id];
@@ -147,7 +147,7 @@ class Widget
 		}
 
 		// Reset content as we leave
-		if($old_cont) {
+		if ($old_cont ?? null) {
 			self::$cont = $old_cont;
 		}
 	}
@@ -206,7 +206,7 @@ class Widget
 		$template = $this;
 		while($reader->moveToNextAttribute())
 		{
-			if ($reader->name != 'id' && $template->attr[$reader->name] !== $reader->value)
+			if ($reader->name != 'id' && isset($template->attr[$reader->name]) && $template->attr[$reader->name] !== $reader->value)
 			{
 				if (!$cloned)
 				{
@@ -218,7 +218,7 @@ class Widget
 				$template->attrs[$reader->name] = $value = $reader->value;
 
 				// expand attributes values, otherwise eg. validation can not use attrs referencing to content
-				if ($value[0] == '@' || strpos($value, '$cont') !== false)
+				if (!empty($value) && ($value[0] === '@' || strpos($value, '$cont') !== false))
 				{
 					$value = self::expand_name($value, null, null, null, null,
 						isset(self::$cont) ? self::$cont : self::$request->content);
@@ -237,7 +237,7 @@ class Widget
 		}
 
 		// Add in anything in the modification array
-		if(is_array(self::$request->modifications[$this->id]))
+		if (is_array(self::$request->modifications[$this->id] ?? null))
 		{
 			$this->attrs = array_merge($this->attrs,self::$request->modifications[$this->id]);
 		}
@@ -426,7 +426,7 @@ class Widget
 					 class_exists($class_name = $basetype.'_etemplate_widget'))))
 			{
 				// Try for base type, it's probably better than the root
-				if(self::$widget_registry[$basetype] && self::$widget_registry[$basetype] != $class_name)
+				if(isset(self::$widget_registry[$basetype]) && self::$widget_registry[$basetype] !== $class_name)
 				{
 					$class_name = self::$widget_registry[$basetype];
 				}
@@ -535,12 +535,12 @@ class Widget
 		// maintain $expand array name-expansion
 		$cname = $params[0];
 		$expand =& $params[1];
-		if ($expand['cname'] && $expand['cname'] !== $cname)
+		if (isset($expand['cname']) && $expand['cname'] !== $cname)
 		{
 			$expand['cont'] =& self::get_array(self::$request->content, $cname);
 			$expand['cname'] = $cname;
 		}
-		if ($respect_disabled && ($disabled = $this->attrs['disabled'] && self::check_disabled($this->attrs['disabled'], $expand)))
+		if ($respect_disabled && ($disabled = isset($this->attrs['disabled']) && self::check_disabled($this->attrs['disabled'], $expand)))
 		{
 			//error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'=".array2string($disabled).": NOT running");
 			return;
@@ -593,13 +593,13 @@ class Widget
 		foreach($attrs as $name => &$value)
 		{
 			if(!is_string($value)) continue;
-			$value = self::expand_name($value,$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
+			$value = self::expand_name($value, $expand['c'] ?? null, $expand['row'] ?? null, $expand['c_'] ?? null, $expand['row_'] ?? null, $expand['cont'] ?? []);
 		}
-		if($attrs['attributes'])
+		if (!empty($attrs['attributes']))
 		{
 			$attrs = array_merge($attrs, $attrs['attributes']);
 		}
-		if(strpos($child->attrs['type'], '@') !== false || strpos($child->attrs['type'], '$') !== false)
+		if (!empty($child->attrs['type']) && (strpos($child->attrs['type'], '@') !== false || strpos($child->attrs['type'], '$') !== false))
 		{
 			$type = self::expand_name($child->attrs['type'],$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
 			$id = self::expand_name($child->id,$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
@@ -677,7 +677,7 @@ class Widget
 	 */
 	protected static function expand_name($name,$c,$row,$c_=0,$row_=0,$cont=array())
 	{
-		$is_index_in_content = $name[0] == '@';
+		$is_index_in_content = !empty($name) && $name[0] == '@';
 		if (($pos_var=strpos($name,'$')) !== false)
 		{
 			if (!$cont)
@@ -687,8 +687,8 @@ class Widget
 			if (!is_numeric($c)) $c = self::chrs2num($c);
 			$col = self::num2chrs($c-1);	// $c-1 to get: 0:'@', 1:'A', ...
 			if (is_numeric($c_)) $col_ = self::num2chrs($c_-1);
-			$row_cont = $cont[$row];
-			$col_row_cont = $cont[$col.$row];
+			$row_cont = $cont[$row] ?? null;
+			$col_row_cont = $cont[$col.$row] ?? null;
 
 			try {
 				eval('$name = "' . str_replace('"', '\\"', $name) . '";');
@@ -726,9 +726,9 @@ class Widget
 	 */
 	static function chrs2num($chrs)
 	{
+		if (empty($chrs)) return 0;
 		$min = ord('A');
 		$max = ord('Z') - $min + 1;
-
 		$num = 1+ord($chrs[0])-$min;
 		if (strlen($chrs) > 1)
 		{
@@ -751,7 +751,7 @@ class Widget
 		if ($num >= $max)
 		{
 			$chrs = chr(($num / $max) + $min - 1);
-		}
+		} else $chrs = '';
 		$chrs .= chr(($num % $max) + $min);
 
 		return $chrs;
@@ -829,7 +829,7 @@ class Widget
 	{
 		if ($expand && !empty($name))
 		{
-			$name = self::expand_name($name, $expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
+			$name = self::expand_name($name, $expand['c'] ?? null, $expand['row'] ?? null, $expand['c_'] ?? null, $expand['row_'] ?? null, $expand['cont'] ?? []);
 		}
 		if (count($name_parts = explode('[', $name, 2)) > 1)
 		{
diff --git a/api/src/Etemplate/Widget/Nextmatch.php b/api/src/Etemplate/Widget/Nextmatch.php
index 34d87826d2..01acdc8625 100644
--- a/api/src/Etemplate/Widget/Nextmatch.php
+++ b/api/src/Etemplate/Widget/Nextmatch.php
@@ -186,21 +186,21 @@ class Nextmatch extends Etemplate\Widget
 		if (true) $value =& self::get_array(self::$request->content, $form_name, true);
 
 		// Add favorite here so app doesn't save it in the session
-		if($_GET['favorite'])
+		if (empty($_GET['favorite']))
 		{
 			$send_value['favorite'] = $safe_name;
 		}
 		if (true) $value = $send_value;
-		$value['total'] = $total;
+		$value['total'] = $total ?? null;
 
 		// Send categories
-		if(!$value['no_cat'] && !$value['cat_is_select'])
+		if(empty($value['no_cat']) && empty($value['cat_is_select']))
 		{
-			$cat_app = $value['cat_app'] ? $value['cat_app'] : $GLOBALS['egw_info']['flags']['current_app'];
-			$value['options-cat_id'] = self::$request->sel_options['cat_id'] ? self::$request->sel_options['cat_id'] : array();
+			$cat_app = $value['cat_app'] ?? $GLOBALS['egw_info']['flags']['current_app'] ?? '';
+			$value['options-cat_id'] = self::$request->sel_options['cat_id'] ?? [];
 
 			// Add 'All', if not already there
-			if(!$value['options-cat_id'][''] && !$value['options-cat_id'][0])
+			if(empty($value['options-cat_id']['']) && empty($value['options-cat_id'][0]))
 			{
 				$value['options-cat_id'][''] = lang('All categories');
 			}
@@ -220,7 +220,7 @@ class Nextmatch extends Etemplate\Widget
 			if(strpos($name, 'options-') !== false && $_value)
 			{
 				$select = substr($name, 8);
-				if(!self::$request->sel_options[$select])
+				if (empty(self::$request->sel_options[$select]))
 				{
 					self::$request->sel_options[$select] = array();
 				}
@@ -231,21 +231,21 @@ class Nextmatch extends Etemplate\Widget
 				//unset($value[$name]);
 			}
 		}
-		if($value['rows']['sel_options'])
+		if (!empty($value['rows']['sel_options']))
 		{
 			self::$request->sel_options = array_merge(self::$request->sel_options,$value['rows']['sel_options']);
 			unset($value['rows']['sel_options']);
 		}
 
 		// If column selection preference is forced, set a flag to turn off UI
-		$pref_name = 'nextmatch-' . (isset($value['columnselection_pref']) ? $value['columnselection_pref'] : $this->attrs['template']);
-		$value['no_columnselection'] = $value['no_columnselection'] || (
-			$GLOBALS['egw']->preferences->forced[$app][$pref_name] &&
+		$pref_name = 'nextmatch-' . ($value['columnselection_pref'] ?? $this->attrs['template'] ?? '');
+		$value['no_columnselection'] = !empty($value['no_columnselection']) || (
+			!empty($GLOBALS['egw']->preferences->forced[$app][$pref_name]) &&
 			// Need to check admin too, or it will be impossible to turn off
-			!$GLOBALS['egw_info']['user']['apps']['admin']
+			empty($GLOBALS['egw_info']['user']['apps']['admin'])
 		);
 		// Use this flag to indicate to the admin that columns are forced (and that's why they can't change)
-		$value['columns_forced'] = (boolean)$GLOBALS['egw']->preferences->forced[$app][$pref_name];
+		$value['columns_forced'] = !empty($GLOBALS['egw']->preferences->forced[$app][$pref_name]);
 
 		// todo: no need to store rows in request, it's enought to send them to client
 
@@ -256,7 +256,7 @@ class Nextmatch extends Etemplate\Widget
 		if (isset($value['actions']) && !isset($value['actions'][0]))
 		{
 			$value['action_links'] = array();
-			$template_name = isset($value['template']) ? $value['template'] : ($this->attrs['template'] ?: $this->attrs['options']);
+			$template_name = isset($value['template']) ? $value['template'] : ($this->attrs['template'] ?? $this->attrs['options'] ?? null);
 			if (!is_array($value['action_links'])) $value['action_links'] = array();
 			$value['actions'] = self::egw_actions($value['actions'], $template_name, '', $value['action_links']);
 		}
@@ -375,8 +375,8 @@ class Nextmatch extends Etemplate\Widget
 
 		$GLOBALS['egw']->session->commit_session();
 
-		$row_id = isset($value['row_id']) ? $value['row_id'] : 'id';
-		$row_modified = $value['row_modified'];
+		$row_id = $value['row_id'] ?? 'id';
+		$row_modified = $value['row_modified'] ?? null;
 
 		foreach($rows as $n => $row)
 		{
@@ -384,12 +384,12 @@ class Nextmatch extends Etemplate\Widget
 			if (is_int($n) && $row)
 			{
 				if (!isset($row[$row_id])) unset($row_id);	// unset default row_id of 'id', if not used
-				if (!isset($row[$row_modified])) unset($row_modified);
+				if (empty($row[$row_modified])) unset($row_modified);
 
 				$id = $row_id ? $row[$row_id] : $n;
 				$result['order'][] = $id;
 
-				$modified = $row[$row_modified];
+				$modified = $row[$row_modified] ?? null;
 				if (isset($modified) && !(is_int($modified) || is_string($modified) && is_numeric($modified)))
 				{
 					$modified = Api\DateTime::to(str_replace('Z', '', $modified), 'ts');
@@ -497,10 +497,10 @@ class Nextmatch extends Etemplate\Widget
 			{
 				continue;
 			}
-			if($value_in[$key] == $value[$key]) continue;
+			if (($value_in[$key]??null) == ($value[$key]??null)) continue;
 
 			// These keys we don't send row data back, as they cause a partial reload
-			if(in_array($key, array('template'))) $no_rows = true;
+			if (in_array($key, array('template'))) $no_rows = true;
 
 			// Actions still need extra handling
 			if($key == 'actions' && !isset($value['actions'][0]))
@@ -626,7 +626,7 @@ class Nextmatch extends Etemplate\Widget
 		), array(), true);	// true = no permission check
 
 		// if we have a nextmatch widget, find the repeating row
-		if ($widget && $widget->attrs['template'])
+		if ($widget && !empty($widget->attrs['template']))
 		{
 			$row_template = $widget->getElementById($widget->attrs['template']);
 			if(!$row_template)
@@ -642,12 +642,12 @@ class Nextmatch extends Etemplate\Widget
 				if($child->type == 'row') $repeating_row = $child;
 			}
 		}
-		// otherwise we might get stoped by max_excutiontime
+		// otherwise, we might get stopped by max_excutiontime
 		if ($total > 200) @set_time_limit(0);
 
-		$is_parent = $value['is_parent'];
-		$is_parent_value = $value['is_parent_value'];
-		$parent_id = $value['parent_id'];
+		$is_parent = $value['is_parent'] ?? null;
+		$is_parent_value = $value['is_parent_value'] ?? null;
+		$parent_id = $value['parent_id'] ?? null;
 
 		// remove empty rows required by old etemplate to compensate for header rows
 		$first = $total ? null : 0;
@@ -658,14 +658,14 @@ class Nextmatch extends Etemplate\Widget
 			{
 				if (is_null($first)) $first = $n;
 
-				if ($row[$is_parent])	// if app supports parent_id / hierarchy, set parent_id and is_parent
+				if (!empty($row[$is_parent]))	// if app supports parent_id / hierarchy, set parent_id and is_parent
 				{
 					$row['is_parent'] = isset($is_parent_value) ?
 						$row[$is_parent] == $is_parent_value : (boolean)$row[$is_parent];
-					$row['parent_id'] = $row[$parent_id];	// seems NOT used on client!
+					$row['parent_id'] = $row[$parent_id] ?? null;	// seems NOT used on client!
 				}
 				// run beforeSendToClient methods of widgets in row on row-data
-				if($repeating_row)
+				if (!empty($repeating_row))
 				{
 					// Change anything by widget for each row ($row set to 1)
 					$_row = array(1 => &$row);
@@ -894,7 +894,7 @@ class Nextmatch extends Etemplate\Widget
 			if ($default_attrs) $action += $default_attrs;
 
 			// Add 'Select All' after first group
-			if ($first_level && $group !== false && $action['group'] != $group && !$egw_actions[$prefix.'select_all'])
+			if ($first_level && $group !== false && $action['group'] != $group && empty($egw_actions[$prefix.'select_all']))
 			{
 
 				$egw_actions[$prefix.'select_all'] = array(
@@ -911,7 +911,7 @@ class Nextmatch extends Etemplate\Widget
 				);
 				$action_links[] = $prefix.'select_all';
 			}
-			$group = $action['group'];
+			$group = $action['group'] ?? 0;
 
 			if (!$first_level && $n == $max_length && count($actions) > $max_length)
 			{
@@ -941,29 +941,29 @@ class Nextmatch extends Etemplate\Widget
 			}
 
 			// add all first level popup actions plus ones with enabled = 'javaScript:...' to action_links
-			if ((!isset($action['type']) || in_array($action['type'],array('popup','drag','drop'))) &&	// popup is the default
-				($first_level || substr($action['enabled'],0,11) == 'javaScript:'))
+			if ((!isset($action['type']) || in_array($action['type'], array('popup','drag','drop'))) &&	// popup is the default
+				($first_level || isset($action['enabled']) && substr($action['enabled'],0,11) === 'javaScript:'))
 			{
 				$action_links[] = $prefix.$id;
 			}
 
-			// add sub-menues
-			if ($action['children'])
+			// add sub-menus
+			if (!empty($action['children']))
 			{
 				static $inherit_attrs = array('url','popup','nm_action','onExecute','type','egw_open','allowOnMultiple','confirm','confirm_multiple');
 				$inherit_keys = array_flip($inherit_attrs);
-				$action['children'] = self::egw_actions($action['children'], $template_name, $action['prefix'], $action_links, $max_length,
+				$action['children'] = self::egw_actions($action['children'], $template_name, $action['prefix'] ?? '', $action_links, $max_length,
 					array_intersect_key($action, $inherit_keys));
 
 				unset($action['prefix']);
 
 				// Allow default actions to keep their onExecute
-				if($action['default']) unset($inherit_keys['onExecute']);
+				if (!empty($action['default'])) unset($inherit_keys['onExecute']);
 				$action = array_diff_key($action, $inherit_keys);
 			}
 
 			// link or popup action
-			if ($action['url'])
+			if (!empty($action['url']))
 			{
 				$action['url'] = Api\Framework::link('/index.php',str_replace('$action',$id,$action['url']));
 				if ($action['popup'])
@@ -984,7 +984,7 @@ class Nextmatch extends Etemplate\Widget
 					}
 				}
 			}
-			if ($action['egw_open'])
+			if (!empty($action['egw_open']))
 			{
 				$action['data']['nm_action'] = 'egw_open';
 			}
@@ -997,10 +997,10 @@ class Nextmatch extends Etemplate\Widget
 		// Make sure select all is in a group by itself
 		foreach($egw_actions as $id => &$_action)
 		{
-			if($id == $prefix . 'select_all') continue;
-			if($_action['group'] >= $egw_actions[$prefix.'select_all']['group'] )
+			if ($id == $prefix . 'select_all') continue;
+			if (($_action['group'] ?? 0) >= (($egw_actions[$prefix.'select_all'] ?? [])['group'] ?? 0))
 			{
-				$egw_actions[$id]['group']+=1;
+				$egw_actions[$id]['group'] = ($egw_actions[$id]['group'] ?? 0) + 1;
 			}
 		}
 		//echo "egw_actions="; _debug_array($egw_actions);
@@ -1044,7 +1044,7 @@ class Nextmatch extends Etemplate\Widget
 					'no_lang' => true,
 				);
 				// add category icon
-				if (is_array($cat['data']) && $cat['data']['icon'] && file_exists(EGW_SERVER_ROOT.self::ICON_PATH.'/'.basename($cat['data']['icon'])))
+				if (is_array($cat['data']) && !empty($cat['data']['icon']) && file_exists(EGW_SERVER_ROOT.self::ICON_PATH.'/'.basename($cat['data']['icon'])))
 				{
 					$cat_actions[$cat['id']]['iconUrl'] = $GLOBALS['egw_info']['server']['webserver_url'].self::ICON_PATH.'/'.$cat['data']['icon'];
 				}
@@ -1083,7 +1083,7 @@ class Nextmatch extends Etemplate\Widget
 					'prefix' => $prefix,
 				);
 				// add category icon
-				if ($cat['data']['icon'] && file_exists(EGW_SERVER_ROOT.self::ICON_PATH.'/'.basename($cat['data']['icon'])))
+				if (!empty($cat['data']['icon']) && file_exists(EGW_SERVER_ROOT.self::ICON_PATH.'/'.basename($cat['data']['icon'])))
 				{
 					$cat_actions[$cat['id']]['iconUrl'] = $GLOBALS['egw_info']['server']['webserver_url'].self::ICON_PATH.'/'.$cat['data']['icon'];
 				}
@@ -1222,7 +1222,7 @@ class Nextmatch extends Etemplate\Widget
 			// Run on all the sub-templates
 			foreach(array('template', 'header_left', 'header_right', 'header_row') as $sub_template)
 			{
-				if($this->attrs[$sub_template])
+				if (!empty($this->attrs[$sub_template]))
 				{
 					$row_template = Template::instance($this->attrs[$sub_template]);
 					$row_template->run($method_name, $params, $respect_disabled);
@@ -1230,14 +1230,6 @@ class Nextmatch extends Etemplate\Widget
 			}
 		}
 		$params[0] = $old_param0;
-
-		// Prevent troublesome keys from breaking the nextmatch
-		// TODO: Figure out where these come from
-		foreach(array('$row','${row}', '$', '0','1','2') as $key)
-		{
-			if(is_array(self::$request->content[$cname])) unset(self::$request->content[$cname][$key]);
-			if(is_array(self::$request->preserve[$cname])) unset(self::$request->preserve[$cname][$key]);
-		}
 	}
 
 	/**
diff --git a/api/src/Preferences.php b/api/src/Preferences.php
index e50932cd0b..b8752e08a9 100644
--- a/api/src/Preferences.php
+++ b/api/src/Preferences.php
@@ -196,7 +196,7 @@ class Preferences
 		foreach((array)$ids as $id)
 		{
 			// if prefs are not returned, null or not an array, read them from db
-			if (!isset($prefs[$id]) && !is_array($prefs[$id])) $db_read[] = $id;
+			if (!isset($prefs[$id]) || !is_array($prefs[$id])) $db_read[] = $id;
 		}
 		if ($db_read)
 		{
@@ -237,7 +237,7 @@ class Preferences
 		$replace = $with = array();
 		foreach($vals as $key => $val)
 		{
-			if ($this->debug) error_log(__METHOD__." replacing \$\$$key\$\$ with $val  ");
+			if (!empty($this->debug)) error_log(__METHOD__." replacing \$\$$key\$\$ with $val  ");
 			$replace[] = '$$'.$key.'$$';
 			$with[]    = $val;
 		}
@@ -275,7 +275,7 @@ class Preferences
 	 */
 	function standard_substitutes()
 	{
-		if ($this->debug) error_log(__METHOD__." is called ");
+		if (!empty($this->debug)) error_log(__METHOD__." is called ");
 		if (!is_array(@$GLOBALS['egw_info']['user']['preferences']))
 		{
 			$GLOBALS['egw_info']['user']['preferences'] = $this->data;	// else no lang()
@@ -301,7 +301,7 @@ class Preferences
 			'email'     => lang('email-address of the user, eg. "%1"',$this->values['email']),
 			'date'      => lang('todays date, eg. "%1"',$this->values['date']),
 		);
-		if ($this->debug) error_log(__METHOD__.print_r($this->vars,true));
+		if (!empty($this->debug)) error_log(__METHOD__.print_r($this->vars,true));
 		// do the substituetion in the effective prefs (data)
 		//
 		foreach($this->data as $app => $data)
@@ -421,7 +421,7 @@ class Preferences
 				default:
 					foreach($values as $app => $vals)
 					{
-						$this->group[$app] = (array)$vals + (array)$this->group[$app];
+						$this->group[$app] = (array)$vals + ($this->group[$app] ?? []);
 					}
 					break;
 			}
@@ -474,7 +474,7 @@ class Preferences
 		}
 		// setup the standard substitutes and substitutes the data in $this->data
 		//
-		if ($GLOBALS['egw_info']['flags']['load_translations'] !== false)
+		if (!empty($GLOBALS['egw_info']['flags']['load_translations']))
 		{
 			$this->standard_substitutes();
 		}
diff --git a/api/src/Session.php b/api/src/Session.php
index 4e5be655bc..509f9409aa 100644
--- a/api/src/Session.php
+++ b/api/src/Session.php
@@ -1363,7 +1363,7 @@ class Session
 			return false;
 		}
 
-		if ($GLOBALS['egw_info']['server']['sessions_checkip'])
+		if (!empty($GLOBALS['egw_info']['server']['sessions_checkip']))
 		{
 			if (strtoupper(substr(PHP_OS,0,3)) != 'WIN' && (!$GLOBALS['egw_info']['user']['session_ip'] ||
 				$GLOBALS['egw_info']['user']['session_ip'] != $this->getuser_ip()))
@@ -1538,7 +1538,7 @@ class Session
 		}
 
 		// check if the url already contains a query and ensure that vars is an array and all strings are in extravars
-		list($ret_url,$othervars) = explode('?', $url, 2);
+		if (strpos($ret_url=$url, '?') !== false) list($ret_url,$othervars) = explode('?', $url, 2);
 		if ($extravars && is_array($extravars))
 		{
 			$vars += $extravars;
@@ -1720,7 +1720,7 @@ class Session
 	{
 		if (PHP_SAPI === "cli") return;	// gives warnings and has no benefit
 
-		if ($GLOBALS['egw_info']['server']['cookiedomain'])
+		if (!empty($GLOBALS['egw_info']['server']['cookiedomain']))
 		{
 			// Admin set domain, eg. .domain.com to allow egw.domain.com and www.domain.com
 			self::$cookie_domain = $GLOBALS['egw_info']['server']['cookiedomain'];
@@ -1741,7 +1741,7 @@ class Session
 			// setcookie dont likes domains without dots, leaving it empty, gets setcookie to fill the domain in
 			self::$cookie_domain = '';
 		}
-		if (!$GLOBALS['egw_info']['server']['cookiepath'] ||
+		if (empty($GLOBALS['egw_info']['server']['cookiepath']) ||
 			!(self::$cookie_path = parse_url($GLOBALS['egw_info']['server']['webserver_url'],PHP_URL_PATH)))
 		{
 			self::$cookie_path = '/';
@@ -1851,7 +1851,7 @@ class Session
 	private function update_dla($update_access_log=false)
 	{
 		// This way XML-RPC users aren't always listed as xmlrpc.php
-		if (isset($_GET['menuaction']))
+		if (isset($_GET['menuaction']) && strpos($_GET['menuaction'], '.ajax_exec.template.') !== false)
 		{
 			list(, $action) = explode('.ajax_exec.template.', $_GET['menuaction']);
 
diff --git a/api/src/Vfs.php b/api/src/Vfs.php
index f3ffcf49b5..cac0e74ae0 100644
--- a/api/src/Vfs.php
+++ b/api/src/Vfs.php
@@ -349,8 +349,8 @@ class Vfs extends Vfs\Base
 	{
 		//error_log(__METHOD__."(".print_r($base,true).",".print_r($options,true).",".print_r($exec,true).",".print_r($exec_params,true).")\n");
 
-		$type = $options['type'];	// 'd', 'f' or 'F'
-		$dirs_last = $options['depth'];	// put content of dirs before the dir itself
+		$type = $options['type'] ?? null;	// 'd', 'f' or 'F'
+		$dirs_last = !empty($options['depth']);	// put content of dirs before the dir itself
 		// show dirs on top by default, if no recursive listing (allways disabled if $type specified, as unnecessary)
 		$dirsontop = !$type && (isset($options['dirsontop']) ? (boolean)$options['dirsontop'] : isset($options['maxdepth'])&&$options['maxdepth']>0);
 		if ($dirsontop) $options['need_mime'] = true;	// otherwise dirsontop can NOT work
@@ -386,7 +386,7 @@ class Vfs extends Vfs\Base
 				$options['gid'] = 0;
 			}
 		}
-		if ($options['order'] == 'mime')
+		if (isset($options['order']) && $options['order'] === 'mime')
 		{
 			$options['need_mime'] = true;	// we need to return the mime colum
 		}
@@ -403,7 +403,7 @@ class Vfs extends Vfs\Base
 			],
 		]);
 
-		$url = $options['url'];
+		$url = $options['url'] ?? null;
 
 		if (!is_array($base))
 		{
@@ -422,7 +422,7 @@ class Vfs extends Vfs\Base
 				$options['remove'] = count($base) == 1 ? count(explode('/',$path))-3+(int)(substr($path,-1)!='/') : 0;
 			}
 			$is_dir = is_dir($path);
-			if ((int)$options['mindepth'] == 0 && (!$dirs_last || !$is_dir))
+			if (empty($options['mindepth']) && (!$dirs_last || !$is_dir))
 			{
 				self::_check_add($options,$path,$result);
 			}
@@ -434,11 +434,11 @@ class Vfs extends Vfs\Base
 				{
 					if ($fname == '.' || $fname == '..') continue;	// ignore current and parent dir!
 
-					if (self::is_hidden($fname, $options['show-deleted']) && !$options['hidden']) continue;	// ignore hidden files
+					if (self::is_hidden($fname, $options['show-deleted'] ?? false) && !$options['hidden']) continue;	// ignore hidden files
 
 					$file = self::concat($path, $fname);
 
-					if ((int)$options['mindepth'] <= 1)
+					if (!isset($options['mindepth']) || (int)$options['mindepth'] <= 1)
 					{
 						self::_check_add($options,$file,$result);
 					}
@@ -459,7 +459,7 @@ class Vfs extends Vfs\Base
 				}
 				closedir($dir);
 			}
-			if ($is_dir && (int)$options['mindepth'] == 0 && $dirs_last)
+			if ($is_dir && empty($options['mindepth']) && $dirs_last)
 			{
 				self::_check_add($options,$path,$result);
 			}
@@ -569,9 +569,9 @@ class Vfs extends Vfs\Base
 	 */
 	private static function _check_add($options,$path,&$result)
 	{
-		$type = $options['type'];	// 'd' or 'f'
+		$type = $options['type'] ?? null;	// 'd' or 'f'
 
-		if ($options['url'])
+		if (!empty($options['url']))
 		{
 			if (($stat = @lstat($path)))
 			{
@@ -595,7 +595,7 @@ class Vfs extends Vfs\Base
 		$stat['path'] = self::parse_url($path,PHP_URL_PATH);
 		$stat['name'] = $options['remove'] > 0 ? implode('/',array_slice(explode('/',$stat['path']),$options['remove'])) : self::basename($path);
 
-		if ($options['mime'] || $options['need_mime'])
+		if (!empty($options['mime']) || !empty($options['need_mime']))
 		{
 			$stat['mime'] = self::mime_content_type($path);
 		}
@@ -642,7 +642,7 @@ class Vfs extends Vfs\Base
 			return;	// not create/modified in the spezified time
 		}
 		// do we return url or just vfs pathes
-		if (!$options['url'])
+		if (empty($options['url']))
 		{
 			$path = self::parse_url($path,PHP_URL_PATH);
 		}
@@ -1227,7 +1227,7 @@ class Vfs extends Vfs\Base
 				}
 			}
 		}
-		return $component >= 0 ? $result[$component2str[$component]] : $result;
+		return $component >= 0 ? ($result[$component2str[$component]] ?? null) : $result;
 	}
 
 	/**
@@ -1240,7 +1240,7 @@ class Vfs extends Vfs\Base
 	 */
 	static function dirname($_url)
 	{
-		list($url,$query) = explode('?',$_url,2);	// strip the query first, as it can contain slashes
+		if (strpos($url=$_url, '?') !== false) list($url, $query) = explode('?',$_url,2);	// strip the query first, as it can contain slashes
 
 		if ($url == '/' || $url[0] != '/' && self::parse_url($url,PHP_URL_PATH) == '/')
 		{
@@ -1283,7 +1283,7 @@ class Vfs extends Vfs\Base
 	 */
 	static function concat($_url,$relative)
 	{
-		list($url,$query) = explode('?',$_url,2);
+		if (strpos($url=$_url, '?') !== false) list($url, $query) = explode('?',$_url,2);
 		if (substr($url,-1) == '/') $url = substr($url,0,-1);
 		$ret = ($relative === '' || $relative[0] == '/' ? $url.$relative : $url.'/'.$relative);
 
@@ -2264,17 +2264,17 @@ class Vfs extends Vfs\Base
 				}
 			}
 		}
-		if (!$mime && is_dir($url))
+		if (empty($mime) && is_dir($url))
 		{
 			$mime = self::DIR_MIME_TYPE;
 		}
 		// if we operate on the regular filesystem and the mime_content_type function is available --> use it
-		if (!$mime && !$scheme && function_exists('mime_content_type'))
+		if (empty($mime) && !$scheme && function_exists('mime_content_type'))
 		{
 			$mime = mime_content_type($path);
 		}
 		// using EGw's own mime magic (currently only checking the extension!)
-		if (!$mime)
+		if (empty($mime))
 		{
 			$mime = MimeMagic::filename2mime(self::parse_url($url,PHP_URL_PATH));
 		}
diff --git a/api/src/loader.php b/api/src/loader.php
index da84d77aae..241d4582ec 100644
--- a/api/src/loader.php
+++ b/api/src/loader.php
@@ -21,7 +21,7 @@ use EGroupware\Api\Egw;
 
 // E_STRICT in PHP 5.4 gives various strict warnings in working code, which can NOT be easy fixed in all use-cases :-(
 // Only variables should be assigned by reference, eg. soetemplate::tree_walk()
-// Declaration of <extended method> should be compatible with <parent method>, varios places where method parameters change
+// Declaration of <extended method> should be compatible with <parent method>, various places where method parameters change
 // --> switching it off for now, as it makes error-log unusable
 error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED);
 
diff --git a/api/src/loader/exception.php b/api/src/loader/exception.php
index 21fb53b8b5..8b95ede10d 100755
--- a/api/src/loader/exception.php
+++ b/api/src/loader/exception.php
@@ -16,7 +16,7 @@ use EGroupware\Api;
 /**
  * Translate message only if translation object is already loaded
  *
- * This function is usefull for exception handlers or early stages of the initialisation of the egw object,
+ * This function is useful for exception handlers or early stages of the initialisation of the egw object,
  * as calling lang would try to load the translations, evtl. cause more errors, eg. because there's no db-connection.
  *
  * @param string $key message in englich with %1, %2, ... placeholders
@@ -36,7 +36,7 @@ function try_lang($key,$vars=null)
 }
 
 /**
- * Clasify exception for a headline and log it to error_log, if not running as cli
+ * Classify exception for a headline and log it to error_log, if not running as cli
  *
  * @param Exception|Error $e
  * @param string &$headline
@@ -82,7 +82,7 @@ function _egw_log_exception($e,&$headline=null)
 }
 
 /**
- * Fail a little bit more gracefully then an uncought exception
+ * Fail a little more gracefully then an uncaught exception
  *
  * Does NOT return
  *
@@ -159,7 +159,7 @@ if (!isset($GLOBALS['egw_info']['flags']['no_exception_handler']) || $GLOBALS['e
 }
 
 /**
- * Fail a little bit more gracefully then a catchable fatal error, by throwing an exception
+ * Fail a little more gracefully then a catchable fatal error, by throwing an exception
  *
  * @param int $errno  level of the error raised: E_* constants
  * @param string $errstr error message
@@ -178,7 +178,7 @@ function egw_error_handler ($errno, $errstr, $errfile, $errline)
 
 		case E_WARNING:
 		case E_USER_WARNING:
-			// skip message for warnings supressed via @-error-control-operator (eg. @is_dir($path))
+			// skip message for warnings suppressed via @-error-control-operator (eg. @is_dir($path))
 			// can be commented out to get suppressed warnings too!
 			if ((error_reporting() & $errno) && PHP_VERSION < 8.0)
 			{
diff --git a/api/src/loader/security.php b/api/src/loader/security.php
index 06e8ca16dd..6d7396076d 100755
--- a/api/src/loader/security.php
+++ b/api/src/loader/security.php
@@ -96,7 +96,7 @@ foreach(array('_COOKIE','_GET','_POST','_REQUEST','HTTP_GET_VARS','HTTP_POST_VAR
 		}
 	}
 	// do the check for script-tags only for _GET and _POST or if we found something in _GET and _POST
-	// speeds up the execusion a bit
+	// speeds up the execution a bit
 	if (isset($GLOBALS[$where]) && is_array($GLOBALS[$where]) && ($n < 3 || isset($GLOBALS['egw_unset_vars'])))
 	{
 		_check_script_tag($GLOBALS[$where],$where);
@@ -143,8 +143,8 @@ if (ini_get('register_globals'))
  *
  * Should be used for all external content, to guard against exploidts.
  *
- * PHP 7.0+ can be told not to instanciate any classes (and calling eg. it's destructor).
- * In fact it instanciates it as __PHP_Incomplete_Class without any methods and therefore disarming threads.
+ * PHP 7.0+ can be told not to instantiate any classes (and calling eg. it's destructor).
+ * In fact it instantiates it as __PHP_Incomplete_Class without any methods and therefore disarming threads.
  *
  * @param string $str
  * @return mixed