From 91bd7c7aeb704f5c2be06a60d26ef088634727bf Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 10:14:08 +0200 Subject: [PATCH 01/70] an other chunk of fixed PHP 8.0 Warnings --- api/src/Auth.php | 17 ++-- api/src/Contacts/Storage.php | 4 +- api/src/Db.php | 4 +- api/src/Db/Pdo.php | 2 +- api/src/Etemplate.php | 14 ++-- api/src/Etemplate/Request.php | 4 +- api/src/Etemplate/Widget/Customfields.php | 20 ++--- api/src/Etemplate/Widget/Description.php | 2 +- api/src/Etemplate/Widget/Image.php | 8 +- api/src/Etemplate/Widget/Nextmatch.php | 8 +- api/src/Etemplate/Widget/Password.php | 3 +- api/src/Etemplate/Widget/Select.php | 20 ++--- api/src/Etemplate/Widget/Template.php | 12 +-- api/src/Etemplate/Widget/Textbox.php | 6 +- api/src/Etemplate/Widget/Tree.php | 16 ++-- api/src/Etemplate/Widget/Vfs.php | 4 +- api/src/Framework/Ajax.php | 24 +++--- api/src/Framework/Bundle.php | 10 +-- api/src/Framework/CssIncludes.php | 2 +- api/src/Html.php | 3 +- api/src/Link/Storage.php | 4 +- api/src/Mail.php | 2 +- api/src/Mail/Account.php | 2 +- api/src/Mail/Html.php | 4 +- api/src/Mail/Imap.php | 10 +-- api/src/Mail/Notifications.php | 4 +- api/src/Mail/Script.php | 10 +-- api/src/Mail/Smtp/Sql.php | 8 +- api/src/Mailer.php | 6 +- api/src/Session.php | 2 +- api/src/Storage/Tracking.php | 16 ++-- api/src/Vfs/Base.php | 21 +++-- api/src/Vfs/StreamWrapper.php | 6 +- infolog/inc/class.infolog_bo.inc.php | 18 ++-- infolog/inc/class.infolog_egw_record.inc.php | 7 +- infolog/inc/class.infolog_merge.inc.php | 2 +- infolog/inc/class.infolog_tracking.inc.php | 12 +-- infolog/inc/class.infolog_ui.inc.php | 20 ++--- mail/inc/class.mail_compose.inc.php | 84 +++++++++---------- mail/inc/class.mail_ui.inc.php | 6 +- .../inc/class.notifications_popup.inc.php | 4 +- pixelegg/inc/class.pixelegg_framework.inc.php | 12 +-- 42 files changed, 222 insertions(+), 221 deletions(-) diff --git a/api/src/Auth.php b/api/src/Auth.php index 5fdfa1c5a6..74a086de23 100644 --- a/api/src/Auth.php +++ b/api/src/Auth.php @@ -15,8 +15,7 @@ namespace EGroupware\Api; // allow to set an application depending authentication type (eg. for syncml, groupdav, ...) -if (isset($GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]) && - $GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]) +if (!empty($GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']])) { $GLOBALS['egw_info']['server']['auth_type'] = $GLOBALS['egw_info']['server']['auth_type_'.$GLOBALS['egw_info']['flags']['currentapp']]; } @@ -223,11 +222,11 @@ class Auth { return true; } - if (is_null($passwordAgeBorder) && $GLOBALS['egw_info']['server']['change_pwd_every_x_days']) + if (is_null($passwordAgeBorder) && !empty($GLOBALS['egw_info']['server']['change_pwd_every_x_days'])) { $passwordAgeBorder = (DateTime::to('now','ts')-($GLOBALS['egw_info']['server']['change_pwd_every_x_days']*86400)); } - if (is_null($daysLeftUntilChangeReq) && $GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change']) + if (is_null($daysLeftUntilChangeReq) && !empty($GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'])) { // maxage - passwordage = days left until change is required $daysLeftUntilChangeReq = ($GLOBALS['egw_info']['server']['change_pwd_every_x_days'] - ((DateTime::to('now','ts')-($alpwchange_val?$alpwchange_val:0))/86400)); @@ -235,9 +234,9 @@ class Auth if ($alpwchange_val == 0 || // admin requested password change $passwordAgeBorder > $alpwchange_val || // change password every N days policy requests change // user should be warned N days in advance about change and is not yet - $GLOBALS['egw_info']['server']['change_pwd_every_x_days'] && - $GLOBALS['egw_info']['user']['apps']['preferences'] && - $GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'] && + !empty($GLOBALS['egw_info']['server']['change_pwd_every_x_days']) && + !empty($GLOBALS['egw_info']['user']['apps']['preferences']) && + !empty($GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change']) && $GLOBALS['egw_info']['server']['warn_about_upcoming_pwd_change'] > $daysLeftUntilChangeReq && $UserKnowsAboutPwdChange !== true) { @@ -255,8 +254,8 @@ class Auth else { // login page does not inform user about passwords about to expire - if ($GLOBALS['egw_info']['flags']['currentapp'] != 'login' && - ($GLOBALS['egw_info']['flags']['currentapp'] != 'home' || + if ($GLOBALS['egw_info']['flags']['currentapp'] !== 'login' && + ($GLOBALS['egw_info']['flags']['currentapp'] !== 'home' || strpos($_SERVER['SCRIPT_NAME'], '/home/') !== false)) { $UserKnowsAboutPwdChange = true; diff --git a/api/src/Contacts/Storage.php b/api/src/Contacts/Storage.php index 0cb66f4b6d..c594cfd94f 100755 --- a/api/src/Contacts/Storage.php +++ b/api/src/Contacts/Storage.php @@ -415,9 +415,9 @@ class Storage */ function allow_account_edit($user=null) { - return $GLOBALS['egw_info']['server']['allow_account_edit'] && + return !empty($GLOBALS['egw_info']['server']['allow_account_edit']) && array_intersect($GLOBALS['egw_info']['server']['allow_account_edit'], - $GLOBALS['egw']->accounts->memberships($user ? $user : $this->user, true)); + $GLOBALS['egw']->accounts->memberships($user ?: $this->user, true)); } /** diff --git a/api/src/Db.php b/api/src/Db.php index cb42718df4..c2160cc0a8 100644 --- a/api/src/Db.php +++ b/api/src/Db.php @@ -591,7 +591,7 @@ class Db $this->setupType = $this->Type; $this->Type = 'mysql'; } - if ($new_connection) + if (!empty($new_connection)) { foreach(get_included_files() as $file) { @@ -1599,7 +1599,7 @@ class Db { return $array; } - if (!$column_definitions) + if (empty($column_definitions)) { $column_definitions = $this->column_definitions; } diff --git a/api/src/Db/Pdo.php b/api/src/Db/Pdo.php index cd038c6f15..353409d523 100644 --- a/api/src/Db/Pdo.php +++ b/api/src/Db/Pdo.php @@ -125,7 +125,7 @@ class Pdo // Exception reveals password, so we ignore the exception and connect again without pw, to get the right exception without pw self::$pdo = new \PDO($dsn,$egw_db->User,'$egw_db->Password'); } - if ($query) + if (!empty($query)) { self::$pdo->exec($query); } diff --git a/api/src/Etemplate.php b/api/src/Etemplate.php index 0631d9e3b7..45e88ae271 100644 --- a/api/src/Etemplate.php +++ b/api/src/Etemplate.php @@ -117,22 +117,22 @@ class Etemplate extends Etemplate\Widget\Template foreach(count(array_filter(array_keys($extras), 'is_int')) ? $extras : array($extras) as $extra) { - if ($extra['data'] && is_array($extra['data'])) + if (!empty($extra['data']) && is_array($extra['data'])) { $content = array_merge($content, $extra['data']); } - if ($extra['preserve'] && is_array($extra['preserve'])) + if (!empty($extra['preserve']) && is_array($extra['preserve'])) { $preserv = array_merge($preserv, $extra['preserve']); } - if ($extra['readonlys'] && is_array($extra['readonlys'])) + if (!empty($extra['readonlys']) && is_array($extra['readonlys'])) { $readonlys = array_merge($readonlys, $extra['readonlys']); } - if ($extra['sel_options'] && is_array($extra['sel_options'])) + if (!empty($extra['sel_options']) && is_array($extra['sel_options'])) { $sel_options = array_merge($sel_options, $extra['sel_options']); } @@ -177,7 +177,7 @@ class Etemplate extends Etemplate\Widget\Template } // some apps (eg. InfoLog) set app_header only in get_rows depending on filter settings - self::$request->app_header = $GLOBALS['egw_info']['flags']['app_header']; + self::$request->app_header = $GLOBALS['egw_info']['flags']['app_header'] ?? null; // compile required translations translations $currentapp = $GLOBALS['egw_info']['flags']['currentapp']; @@ -209,7 +209,7 @@ class Etemplate extends Etemplate\Widget\Template 'currentapp' => $currentapp, ); - if($data['content']['nm']['rows'] && is_array($data['content']['nm']['rows'])) + if (!empty($data['content']['nm']['rows']) && is_array($data['content']['nm']['rows'])) { // Deep copy rows so we don't lose them when request is set to null // (some content by reference) @@ -420,7 +420,7 @@ class Etemplate extends Etemplate\Widget\Template } $tcontent = is_array($content) ? $content : - self::complete_array_merge(self::$request->preserv, $validated); + self::complete_array_merge(self::$request->preserv ?? [], $validated); $hook_data = Hooks::process( array( diff --git a/api/src/Etemplate/Request.php b/api/src/Etemplate/Request.php index f4823645b9..4843c9503d 100644 --- a/api/src/Etemplate/Request.php +++ b/api/src/Etemplate/Request.php @@ -428,9 +428,9 @@ class Request * @param string $var * @param mixed $val */ - public function __set($var,$val) + public function __set($var, $val) { - if ($this->data[$var] !== $val) + if (!isset($this->data[$var]) || $this->data[$var] !== $val) { $this->data[$var] = $val; //error_log(__METHOD__."('$var', ...) data of id=$this->id changed ..."); diff --git a/api/src/Etemplate/Widget/Customfields.php b/api/src/Etemplate/Widget/Customfields.php index 0964a7fd9b..466ff5f5bc 100644 --- a/api/src/Etemplate/Widget/Customfields.php +++ b/api/src/Etemplate/Widget/Customfields.php @@ -98,7 +98,7 @@ class Customfields extends Transformer $form_name = self::form_name($cname, $this->id, $expand); // Store properties at top level, so all customfield widgets can share - if($this->attrs['app']) + if (!empty($this->attrs['app'])) { $app = $this->attrs['app']; } @@ -141,12 +141,12 @@ class Customfields extends Transformer // app changed $customfields = Api\Storage\Customfields::get($app); } - if($this->attrs['customfields']) + if (!empty($this->attrs['customfields'])) { $customfields = $this->attrs['customfields']; } // Filter fields - if($this->attrs['field-names']) + if (!empty($this->attrs['field-names'])) { $fields_name = explode(',', $this->attrs['field-names']); foreach($fields_name as &$f) @@ -162,8 +162,8 @@ class Customfields extends Transformer $fields = $customfields; - $use_private = self::expand_name($this->attrs['use-private'],0,0,'','',self::$cont); - $this->attrs['sub-type'] = self::expand_name($this->attrs['sub-type'],0,0,'','',self::$cont); + $use_private = self::expand_name($this->attrs['use-private'] ?? null,0,0,'','',self::$cont); + $this->attrs['sub-type'] = self::expand_name($this->attrs['sub-type'] ?? null,0,0,'','',self::$cont); foreach((array)$fields as $key => $field) { @@ -174,7 +174,7 @@ class Customfields extends Transformer } // Remove filtered fields - if($field_filters && in_array($key, $negate_fields) && in_array($key, $field_filters)) + if (!empty($field_filters) && in_array($key, $negate_fields) && in_array($key, $field_filters)) { unset($fields[$key]); } @@ -284,7 +284,7 @@ class Customfields extends Transformer $type = $field['type']; // Link-tos needs to change from appname to link-to - if($link_types[$field['type']]) + if (!empty($link_types[$field['type']])) { if($type == 'filemanager') { @@ -314,8 +314,8 @@ class Customfields extends Transformer { $widget->attrs['data_format'] = $type == 'date' ? 'Y-m-d' : 'Y-m-d H:i:s'; } - if($field['values']['min']) $widget->attrs['min'] = $field['values']['min']; - if($field['values']['max']) $widget->attrs['min'] = $field['values']['max']; + if (isset($field['values']['min'])) $widget->attrs['min'] = $field['values']['min']; + if (isset($field['values']['max'])) $widget->attrs['min'] = $field['values']['max']; break; case 'vfs-upload': @@ -355,7 +355,7 @@ class Customfields extends Transformer $field['values'] = Api\Storage\Customfields::get_options_from_file($field['values']['@']); } // keep extra values set by app code, eg. addressbook advanced search - if (is_array(self::$request->sel_options[self::$prefix.$fname])) + if (!empty(self::$request->sel_options[self::$prefix.$fname]) && is_array(self::$request->sel_options[self::$prefix.$fname])) { self::$request->sel_options[self::$prefix.$fname] += (array)$field['values']; } diff --git a/api/src/Etemplate/Widget/Description.php b/api/src/Etemplate/Widget/Description.php index 338e80f15d..e69bcdfd19 100644 --- a/api/src/Etemplate/Widget/Description.php +++ b/api/src/Etemplate/Widget/Description.php @@ -42,7 +42,7 @@ class Description extends Etemplate\Widget */ public function beforeSendToClient($cname, array $expand=null) { - if ($this->attrs['activate_links']) + if (!empty($this->attrs['activate_links'])) { $form_name = self::form_name($cname, $this->id, $expand); $value =& self::get_array(self::$request->content, $form_name); diff --git a/api/src/Etemplate/Widget/Image.php b/api/src/Etemplate/Widget/Image.php index 7969ab83dc..f77067f082 100644 --- a/api/src/Etemplate/Widget/Image.php +++ b/api/src/Etemplate/Widget/Image.php @@ -36,17 +36,17 @@ class Image extends Etemplate\Widget $image = $value != '' ? $value : $this->attrs['src']; - if (is_string($image)) list($app,$img) = explode('/',$image,2); - if (!$app || !$img || !is_dir(EGW_SERVER_ROOT.'/'.$app) || strpos($img,'/')!==false) + if (is_string($image)) list($app,$img) = explode('/',$image,2)+[null,null]; + if (empty($app) || empty($img) || !is_dir(EGW_SERVER_ROOT.'/'.$app) || strpos($img,'/')!==false) { $img = $image; list($app) = explode('.',$form_name); } $src = Api\Image::find($app, $img); - if(!$this->id) + /*if(!$this->id) { // self::setElementAttribute($this->attrs['src'], 'id', $this->attrs['src']); - } + }*/ self::setElementAttribute($this->attrs['src'], 'src', $src); } } diff --git a/api/src/Etemplate/Widget/Nextmatch.php b/api/src/Etemplate/Widget/Nextmatch.php index d6ccd128c7..10004d276e 100644 --- a/api/src/Etemplate/Widget/Nextmatch.php +++ b/api/src/Etemplate/Widget/Nextmatch.php @@ -130,13 +130,13 @@ class Nextmatch extends Etemplate\Widget $send_value = $value; list($app) = explode('.',$value['get_rows']); - if(!$GLOBALS['egw_info']['apps'][$app]) + if (empty($GLOBALS['egw_info']['apps'][$app])) { list($app) = explode('.',$this->attrs['template']); } // Check for a favorite in URL - if($_GET['favorite'] && $value['favorites']) + if (!empty($_GET['favorite']) && !empty($value['favorites'])) { $safe_name = preg_replace('/[^A-Za-z0-9-_]/','_',strip_tags($_GET['favorite'])); $pref_name = "favorite_" .$safe_name; @@ -210,7 +210,7 @@ class Nextmatch extends Etemplate\Widget } // Favorite group for admins - if($GLOBALS['egw_info']['apps']['admin'] && $value['favorites']) + if (!empty($GLOBALS['egw_info']['apps']['admin']) && !empty($value['favorites'])) { self::$request->sel_options[$form_name]['favorite']['group'] = array('all' => lang('All users')) + Select::typeOptions('select-account',',groups'); @@ -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 && empty($egw_actions[$prefix.'select_all'])) + if ($first_level && $group !== false && ($action['group']??null) != $group && empty($egw_actions[$prefix.'select_all'])) { $egw_actions[$prefix.'select_all'] = array( diff --git a/api/src/Etemplate/Widget/Password.php b/api/src/Etemplate/Widget/Password.php index ae4d5ef7f3..3e7cbe9997 100644 --- a/api/src/Etemplate/Widget/Password.php +++ b/api/src/Etemplate/Widget/Password.php @@ -49,7 +49,8 @@ class Password extends Etemplate\Widget\Textbox { $form_name = self::form_name($cname, $this->id, $expand); $value =& self::get_array(self::$request->content, $form_name); - $plaintext = !in_array(self::expand_name($this->attrs['plaintext'],$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']), + $plaintext = !empty($this->attrs['plaintext']) && !in_array( + self::expand_name($this->attrs['plaintext'], $expand['c'] ?? null, $expand['row'] ?? null, $expand['c_'] ?? null, $expand['row_'] ?? null, $expand['cont']), ['false', '0']); if (!empty($value)) diff --git a/api/src/Etemplate/Widget/Select.php b/api/src/Etemplate/Widget/Select.php index 84817c9aa5..0b56a22d57 100644 --- a/api/src/Etemplate/Widget/Select.php +++ b/api/src/Etemplate/Widget/Select.php @@ -109,14 +109,14 @@ class Select extends Etemplate\Widget { parent::set_attrs($xml, $cloned); - if ($this->attrs['multiple'] !== 'dynamic') + if (!isset($this->attrs['multiple']) || $this->attrs['multiple'] !== 'dynamic') { $this->attrs['multiple'] = !isset($this->attrs['multiple']) ? false : !(!$this->attrs['multiple'] || $this->attrs['multiple'] === 'false'); } // set attrs[multiple] from attrs[options], unset options only if it just contains number or rows - if ($this->attrs['options'] > 1) + if (isset($this->attrs['options']) && $this->attrs['options'] > 1) { $this->attrs['multiple'] = (int)$this->attrs['options']; if ((string)$this->attrs['multiple'] == $this->attrs['options']) @@ -124,7 +124,7 @@ class Select extends Etemplate\Widget unset($this->attrs['options']); } } - elseif($this->attrs['rows'] > 1) + elseif(isset($this->attrs['rows']) && $this->attrs['rows'] > 1) { $this->attrs['multiple'] = true; } @@ -311,8 +311,8 @@ class Select extends Etemplate\Widget { $form_name = self::form_name($cname, $this->id, $expand); } - if (!is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = array(); - $type = $this->attrs['type'] ? $this->attrs['type'] : $this->type; + if (empty(self::$request->sel_options[$form_name]) || !is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = []; + $type = $this->attrs['type'] ?? $this->type; if ($type != 'select' && $type != 'menupopup') { // Check selection preference, we may be able to skip reading some data @@ -335,8 +335,8 @@ class Select extends Etemplate\Widget if (!isset($form_names_done[$form_name]) && ($type_options = self::typeOptions($this, // typeOptions thinks # of rows is the first thing in options - ($this->attrs['rows'] && strpos($this->attrs['options'], $this->attrs['rows']) !== 0 ? $this->attrs['rows'].','.$this->attrs['options'] : $this->attrs['options']), - $no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name), $form_name))) + (!empty($this->attrs['rows']) && !empty($this->attrs['options']) && strpos($this->attrs['options'], $this->attrs['rows']) !== 0 ? $this->attrs['rows'].','.$this->attrs['options'] : $this->attrs['options']), + $no_lang, $this->attrs['readonly'] ?? false, self::get_array(self::$request->content, $form_name), $form_name))) { self::fix_encoded_options($type_options); @@ -356,7 +356,7 @@ class Select extends Etemplate\Widget $options = (isset(self::$request->sel_options[$form_name]) ? $form_name : $this->id); if(is_array(self::$request->sel_options[$options])) { - if(in_array($this->attrs['type'], self::$cached_types) && !isset($form_names_done[$options])) + if (isset($this->attrs['type']) && in_array($this->attrs['type'], self::$cached_types) && !isset($form_names_done[$options])) { // Fix any custom options from application self::fix_encoded_options(self::$request->sel_options[$options],true); @@ -561,7 +561,7 @@ class Select extends Etemplate\Widget $field = self::expand_name($field, 0, 0,'','',self::$cont); } - list($rows,$type,$type2,$type3,$type4,$type5) = $legacy_options; + list($rows,$type,$type2,$type3,$type4,$type5) = $legacy_options+[null,null,null,null,null,null]; $no_lang = false; $options = array(); switch ($widget_type) @@ -644,7 +644,7 @@ class Select extends Etemplate\Widget // These are extra info for easy dealing with categories // client side, without extra loading 'main' => (int)$cat['main'], - 'children' => $cat['children'], + 'children' => $cat['children'] ?? null, //add different class per level to allow different styling for each category level: 'class' => "cat_level". $cat['level'] ); diff --git a/api/src/Etemplate/Widget/Template.php b/api/src/Etemplate/Widget/Template.php index 5b9c30435f..da2021ec17 100644 --- a/api/src/Etemplate/Widget/Template.php +++ b/api/src/Etemplate/Widget/Template.php @@ -68,7 +68,7 @@ class Template extends Etemplate\Widget list($name) = explode('?', $_name); // remove optional cache-buster if (isset(self::$cache[$name]) || !($path = self::relPath($name, $template_set, $version, $load_via))) { - if ((!$path || self::read($load_via, $template_set)) && isset(self::$cache[$name])) + if ((empty($path) || self::read($load_via, $template_set)) && isset(self::$cache[$name])) { //error_log(__METHOD__."('$name', '$template_set', '$version', '$load_via') read from cache"); return self::$cache[$name]; @@ -146,7 +146,7 @@ class Template extends Etemplate\Widget { static $prefixes = null; unset($version); // not used currently - list($app, $rest) = explode('.', $load_via ?: $name, 2); + list($app, $rest) = explode('.', $load_via ?: $name, 2)+[null,null]; if (empty($template_set)) { @@ -184,7 +184,7 @@ class Template extends Etemplate\Widget $path = $prefix.$path; } //error_log(__METHOD__."('$name', '$template_set') returning ".array2string($path)); - return $path; + return $path ?? null; } /** @@ -243,16 +243,16 @@ class Template extends Etemplate\Widget { $cname =& $params[0]; $old_cname = $params[0]; - if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content'], $params[1]); + if (!empty($this->attrs['content'])) $cname = self::form_name($cname, $this->attrs['content'], $params[1]); // Check for template from content, and run over it // templates included via template tag have their name to load them from in attribute "template" - $expand_name = self::expand_name($this->id ? $this->id : $this->attrs['template'], '','','','',self::$request->content); + $expand_name = self::expand_name($this->id ?: $this->attrs['template'], '','','','',self::$request->content); if(!$expand_name && $this->id && $this->attrs['template']) { $expand_name = $this->attrs['template']; } - if($this->original_name) + if (!empty($this->original_name)) { $expand_name = self::expand_name($this->original_name, '','','','',self::$request->content); } diff --git a/api/src/Etemplate/Widget/Textbox.php b/api/src/Etemplate/Widget/Textbox.php index fe8e836671..55dbc721e2 100644 --- a/api/src/Etemplate/Widget/Textbox.php +++ b/api/src/Etemplate/Widget/Textbox.php @@ -62,14 +62,14 @@ class Textbox extends Etemplate\Widget parent::set_attrs($xml, $cloned); // Legacy handling only - // A negative size triggered the HTML readonly attibute, but not etemplate readonly, + // A negative size triggered the HTML readonly attribute, but not etemplate readonly, // so you got an input element, but it was not editable. - if ($this->attrs['size'] < 0) + if (isset($this->attrs['size']) && $this->attrs['size'] < 0) { self::setElementAttribute($this->id, 'size', abs($this->attrs['size'])); self::$request->readonlys[$this->id] = false; self::setElementAttribute($this->id, 'readonly', true); - trigger_error("Using a negative size to set textbox readonly. " .$this, E_USER_DEPRECATED); + //trigger_error("Using a negative size to set textbox readonly. " .$this, E_USER_DEPRECATED); } return $this; } diff --git a/api/src/Etemplate/Widget/Tree.php b/api/src/Etemplate/Widget/Tree.php index 1fa12c56d0..dcab22cced 100644 --- a/api/src/Etemplate/Widget/Tree.php +++ b/api/src/Etemplate/Widget/Tree.php @@ -143,7 +143,7 @@ class Tree extends Etemplate\Widget parent::set_attrs($xml, $cloned); // set attrs[multiple] from attrs[options] - if ($this->attrs['options'] > 1) + if (isset($this->attrs['options']) && (int)$this->attrs['options'] > 1) { self::setElementAttribute($this->id, 'multiple', true); } @@ -297,21 +297,21 @@ class Tree extends Etemplate\Widget { $form_name = self::form_name($cname, $this->id); - if (($templated_path = self::templateImagePath($this->attrs['image_path'])) != $this->attrs['image_path']) + if (!empty($this->attrs['image_path']) && ($templated_path = self::templateImagePath($this->attrs['image_path'])) != $this->attrs['image_path']) { self::setElementAttribute($form_name, 'image_path', $this->attrs['image_path'] = $templated_path); //error_log(__METHOD__."() setting templated image-path for $form_name: $templated_path"); } - if (!is_array(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = array(); - if ($this->attrs['type']) + if (empty(self::$request->sel_options[$form_name])) self::$request->sel_options[$form_name] = []; + if (!empty($this->attrs['type'])) { // += to keep further options set by app code - self::$request->sel_options[$form_name] += self::typeOptions($this->attrs['type'], $this->attrs['options'], - $no_lang, $this->attrs['readonly'], self::get_array(self::$request->content, $form_name), $form_name); + self::$request->sel_options[$form_name] += self::typeOptions($this->attrs['type'], $this->attrs['options'] ?? null, + $no_lang, $this->attrs['readonly'] ?? null, self::get_array(self::$request->content, $form_name), $form_name); // if no_lang was modified, forward modification to the client - if ($no_lang != $this->attr['no_lang']) + if (!isset($this->attr['no_lang']) || $no_lang != $this->attr['no_lang']) { self::setElementAttribute($form_name, 'no_lang', $no_lang); } @@ -440,7 +440,7 @@ class Tree extends Etemplate\Widget */ public static function typeOptions($widget_type, $legacy_options, &$no_lang=false, $readonly=false, $value=null, $form_name=null) { - list($rows,$type,$type2,$type3) = explode(',',$legacy_options); + list($rows,$type,$type2,$type3) = explode(',', $legacy_options)+[null,null,null,null]; $no_lang = false; $options = array(); diff --git a/api/src/Etemplate/Widget/Vfs.php b/api/src/Etemplate/Widget/Vfs.php index 9781da9ad7..f378538697 100644 --- a/api/src/Etemplate/Widget/Vfs.php +++ b/api/src/Etemplate/Widget/Vfs.php @@ -37,10 +37,10 @@ class Vfs extends File */ public function beforeSendToClient($cname, $expand = array()) { - if($this->type == 'vfs-upload' || $this->attrs['type'] == 'vfs-upload') + if ($this->type === 'vfs-upload' || !empty($this->attrs['type']) && $this->attrs['type'] === 'vfs-upload') { $form_name = self::form_name($cname, $this->id, $expand ? $expand : array('cont'=>self::$request->content)); - if($this->attrs['path']) + if (!empty($this->attrs['path'])) { $path = self::expand_name($this->attrs['path'],$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']); } diff --git a/api/src/Framework/Ajax.php b/api/src/Framework/Ajax.php index 77f0e67530..e10618fa2c 100755 --- a/api/src/Framework/Ajax.php +++ b/api/src/Framework/Ajax.php @@ -2,12 +2,12 @@ /** * EGroupware - Framework for Ajax based templates: jdots & Pixelegg * - * @link http://www.stylite.de + * @link https://www.egroupware.org * @package api * @subpackage framework - * @author Andreas Stöckel - * @author Ralf Becker - * @author Nathan Gray + * @author Andreas Stöckel + * @author Ralf Becker + * @author Nathan Gray * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License */ @@ -16,7 +16,7 @@ namespace EGroupware\Api\Framework; use EGroupware\Api; /** -* Stylite jdots template +* Framework for Ajax based templates */ abstract class Ajax extends Api\Framework { @@ -88,13 +88,13 @@ abstract class Ajax extends Api\Framework $width = self::DEFAULT_SIDEBAR_WIDTH; //Check whether the width had been stored explicitly for the jdots template, use that value - if ($GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth']) + if (!empty($GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth'])) { $width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['jdotssideboxwidth']; // error_log(__METHOD__.__LINE__."($app):$width --> reading jdotssideboxwidth"); } //Otherwise use the legacy "idotssideboxwidth" value - else if ($GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth']) + elseif (!empty($GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth'])) { $width = (int)$GLOBALS['egw_info']['user']['preferences'][$app]['idotssideboxwidth']; // error_log(__METHOD__.__LINE__."($app):$width --> reading idotssideboxwidth"); @@ -249,7 +249,7 @@ abstract class Ajax extends Api\Framework { if (empty($GLOBALS['egw_info']['flags']['java_script'])) $GLOBALS['egw_info']['flags']['java_script']=''; // eT2 sets $GLOBALS['egw_info']['flags']['nonavbar'] === 'popup' for popups, Etemplate::exec($outputmode === 2) - $extra['check-framework'] = $_GET['cd'] !== 'no' && $GLOBALS['egw_info']['flags']['nonavbar'] !== 'popup'; + $extra['check-framework'] = (!isset($_GET['cd']) || $_GET['cd'] !== 'no') && $GLOBALS['egw_info']['flags']['nonavbar'] !== 'popup'; } } @@ -1047,16 +1047,16 @@ abstract class Ajax extends Api\Framework if (self::$footer_done) return; // prevent (multiple) footers self::$footer_done = true; - if (!isset($GLOBALS['egw_info']['flags']['nofooter']) || !$GLOBALS['egw_info']['flags']['nofooter']) + if (empty($GLOBALS['egw_info']['flags']['nofooter'])) { - if ($no_framework && $GLOBALS['egw_info']['user']['preferences']['common']['show_generation_time']) + if ($no_framework && !empty($GLOBALS['egw_info']['user']['preferences']['common']['show_generation_time'])) { $vars = $this->_get_footer(); $footer = "\n".$vars['page_generation_time']."\n"; } } - return $footer. - $GLOBALS['egw_info']['flags']['need_footer']."\n". // eg. javascript, which need to be at the end of the page + return ($footer??''). + ($GLOBALS['egw_info']['flags']['need_footer']??'')."\n". // eg. javascript, which need to be at the end of the page "\n\n"; } diff --git a/api/src/Framework/Bundle.php b/api/src/Framework/Bundle.php index 09d5cfe23e..3fecfb39ee 100644 --- a/api/src/Framework/Bundle.php +++ b/api/src/Framework/Bundle.php @@ -49,12 +49,12 @@ class Bundle unset($GLOBALS['egw_info']['server']['debug_minify']); $file2bundle = array(); - if ($GLOBALS['egw_info']['server']['debug_minify'] !== 'True') + if (!isset($GLOBALS['egw_info']['server']['debug_minify']) || $GLOBALS['egw_info']['server']['debug_minify'] !== 'True') { // get used bundles and cache them on tree-level for 2h //$bundles = self::all(); Cache::setTree(__CLASS__, 'bundles', $bundles, 7200); $bundles = Cache::getTree(__CLASS__, 'bundles', array(__CLASS__, 'all'), array(), 7200); - $bundles_ts = $bundles['.ts']; + $bundles_ts = $bundles['.ts'] ?? null; unset($bundles['.ts']); foreach($bundles as $name => $files) { @@ -83,7 +83,7 @@ class Bundle if (!isset($to_include[$file])) { - if (($bundle = $file2bundle[$file])) + if (($bundle = $file2bundle[$file] ?? false)) { //error_log(__METHOD__."() requiring bundle $bundle for $file"); if (!in_array($bundle, $included_bundles)) @@ -108,10 +108,10 @@ class Bundle else { unset($query); - list($path, $query) = explode('?', $file, 2); + list($path, $query) = explode('?', $file, 2)+[null,null]; $mod = filemtime(EGW_SERVER_ROOT.$path); // check if we have a more recent minified version of the file and use it - if ($GLOBALS['egw_info']['server']['debug_minify'] !== 'True' && + if ((!isset($GLOBALS['egw_info']['server']['debug_minify']) || $GLOBALS['egw_info']['server']['debug_minify'] !== 'True') && substr($path, -3) == '.js' && file_exists(EGW_SERVER_ROOT.($min_path = substr($path, 0, -3).'.min.js')) && (($min_mod = filemtime(EGW_SERVER_ROOT.$min_path)) >= $mod)) { diff --git a/api/src/Framework/CssIncludes.php b/api/src/Framework/CssIncludes.php index 539af4d32d..bdc4c30d80 100644 --- a/api/src/Framework/CssIncludes.php +++ b/api/src/Framework/CssIncludes.php @@ -113,7 +113,7 @@ class CssIncludes { foreach(self::resolve_css_includes($path) as $path) { - list($file,$query) = explode('?',$path,2); + list($file,$query) = explode('?',$path,2)+[null,null]; if (($mod = filemtime(EGW_SERVER_ROOT.$file)) > $max_modified) $max_modified = $mod; // do NOT include app.css or categories.php, as it changes from app to app diff --git a/api/src/Html.php b/api/src/Html.php index 4acfa409c6..ff27717008 100644 --- a/api/src/Html.php +++ b/api/src/Html.php @@ -100,6 +100,7 @@ class Html // use preg_replace_callback as we experienced problems with links such as $result4 = preg_replace_callback( $Expr, function ($match) { //error_log(__METHOD__.__LINE__.array2string($match)); + $match += [null,null,null,null]; if ($match[4]==';' && (strlen($match[3])-4) >=0 && strpos($match[3],'>',strlen($match[3])-4)!==false) { $match[3] = substr($match[3],0,strpos($match[3],'>',strlen($match[3])-4)); @@ -111,7 +112,7 @@ class Html $match[4] = ">"; } //error_log(__METHOD__.__LINE__.array2string($match)); - return $match[1].""."www".$match[2].$match[3]."".$match[4]; + return $match[1].""."www".$match[2].$match[3]."".$match[4]; }, $result3 ); } return $result4; diff --git a/api/src/Link/Storage.php b/api/src/Link/Storage.php index d55a8f323b..bdac0f380e 100644 --- a/api/src/Link/Storage.php +++ b/api/src/Link/Storage.php @@ -127,7 +127,7 @@ class Storage { echo "

solink.get_links($app,".print_r($id,true).",$only_app,$order,$deleted)

\n"; } - if (($not_only = $only_app[0] == '!')) + if (!empty($only_app) && ($not_only = $only_app[0] == '!')) { $only_app = substr($only_app,1); } @@ -173,7 +173,7 @@ class Storage catch(Api\Db\Exception $e) { _egw_log_exception($e); } - return is_array($id) ? $links : ($links[$id] ? $links[$id] : array()); + return is_array($id) ? $links : ($links[$id] ?? []); } private static function _add2links($row,$left,$only_app,$not_only,array &$links) diff --git a/api/src/Mail.php b/api/src/Mail.php index 1731ecd4a9..cc8dc088ad 100644 --- a/api/src/Mail.php +++ b/api/src/Mail.php @@ -3211,7 +3211,7 @@ class Mail } //error_log(__METHOD__.__LINE__.array2string($autoFolderObjects)); if (!$isGoogleMail) { - $folders = array_merge($inboxFolderObject,$autoFolderObjects,(array)$inboxSubFolderObjects,(array)$folders,(array)$typeFolderObject['others'] ?? [],(array)$typeFolderObject['shared'] ?? []); + $folders = array_merge($inboxFolderObject,$autoFolderObjects,(array)$inboxSubFolderObjects,(array)$folders,(array)($typeFolderObject['others'] ?? []),(array)($typeFolderObject['shared'] ?? [])); } else { // avoid calling sortByAutoFolder as it is not regarding subfolders $gAutoFolderObjectsTmp = $googleAutoFolderObjects; diff --git a/api/src/Mail/Account.php b/api/src/Mail/Account.php index c535b39026..39a2812de5 100644 --- a/api/src/Mail/Account.php +++ b/api/src/Mail/Account.php @@ -549,7 +549,7 @@ class Account implements \ArrayAccess $row = array_merge($row, Credentials::from_session($row)); } // fill an empty ident_realname or ident_email of current user with data from user account - if ($replace_placeholders && (!isset($user) || $user == $GLOBALS['egw_info']['user']['acount_id'])) + if ($replace_placeholders && (!isset($user) || $user == $GLOBALS['egw_info']['user']['account_id'])) { if (empty($row['ident_realname'])) $row['ident_realname'] = $GLOBALS['egw_info']['user']['account_fullname']; if (empty($row['ident_email'])) $row['ident_email'] = $GLOBALS['egw_info']['user']['account_email']; diff --git a/api/src/Mail/Html.php b/api/src/Mail/Html.php index 9f134cdd89..667b845e4f 100644 --- a/api/src/Mail/Html.php +++ b/api/src/Mail/Html.php @@ -169,7 +169,7 @@ class Html if ($addbracesforendtag === true ) { if (stripos($_body,'<'.$tag)!==false) $ct = preg_match_all('#<'.$tag.'(?:\s.*)?>(.+)#isU', $_body, $found); - if ($ct>0) + if (isset($ct) && $ct>0) { //error_log(__METHOD__.__LINE__.array2string($found[0])); // only replace what we have found @@ -495,7 +495,7 @@ class Html $html = preg_replace('/&(?!#?[a-zA-Z0-9]+;)/', '&', $html); $dom = new \DOMDocument('1.0','UTF-8'); - if(!$dom->loadHTML( + if (!@$dom->loadHTML( ''. Api\Translation::convert($html,preg_match('/]+content="[^>"]+charset=([^;"]+)/i', $html, $matches) ? $matches[1] : false, 'utf8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOBLANKS )) diff --git a/api/src/Mail/Imap.php b/api/src/Mail/Imap.php index 8a9ddd8780..b24eb9f8ed 100644 --- a/api/src/Mail/Imap.php +++ b/api/src/Mail/Imap.php @@ -360,8 +360,8 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface */ static function getTimeOut($_use='IMAP') { - $timeout = $GLOBALS['egw_info']['user']['preferences']['mail']['connectionTimeout']; - if (empty($timeout) || !($timeout > 0)) $timeout = $_use == 'SIEVE' ? 10 : 20; // this is the default value + if (empty($timeout = $GLOBALS['egw_info']['user']['preferences']['mail']['connectionTimeout']) || !((int)$timeout > 0)) + $timeout = $_use == 'SIEVE' ? 10 : 20; // this is the default value return $timeout; } @@ -742,7 +742,7 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface * @param string $returnAttributes true means return an assoc array containing mailbox names and mailbox attributes * false - the default - means return an array of mailboxes with only selected attributes like delimiter * - * @return mixed array of mailboxes + * @return ?array array of mailboxes or null */ function listSubscribedMailboxes($reference = '' , $restriction_search = 0, $returnAttributes = false) { @@ -794,10 +794,10 @@ class Imap extends Horde_Imap_Client_Socket implements Imap\PushIface } else { - $ret[$k]=array('MAILBOX'=>$k,'ATTRIBUTES'=>$box['attributes'],'delimiter'=>($box['delimiter']?$box['delimiter']:$this->getDelimiter('personal')),'SUBSCRIBED'=>true); + $ret[$k]=array('MAILBOX'=>$k,'ATTRIBUTES'=>$box['attributes'],'delimiter'=>($box['delimiter']?:$this->getDelimiter('personal')),'SUBSCRIBED'=>true); } } - return $ret; + return $ret ?? null; } /** diff --git a/api/src/Mail/Notifications.php b/api/src/Mail/Notifications.php index d1a1d02301..54b8343967 100644 --- a/api/src/Mail/Notifications.php +++ b/api/src/Mail/Notifications.php @@ -73,7 +73,7 @@ class Notifications $account_specific = 0; foreach($rows as $row) { - if ($row['account_id']) + if (!empty($row['account_id'])) { $account_specific = $row['account_id']; } @@ -82,7 +82,7 @@ class Notifications { self::$cache[$acc_id][$row['account_id']][] = $row['notif_folder']; } // make sure set the account_specific correctly when notify_folder gets removed - elseif (!$row['account_id'] && !is_array($account_id) && is_array($rows[$account_id])) + elseif (empty($row['account_id']) && !is_array($account_id) && is_array($rows[$account_id])) { $account_specific = $account_id; } diff --git a/api/src/Mail/Script.php b/api/src/Mail/Script.php index 28fdf9823c..ed963cb1f0 100644 --- a/api/src/Mail/Script.php +++ b/api/src/Mail/Script.php @@ -150,10 +150,10 @@ class Script $rule['anyof'] = ($bits[8] & $anyofbit); $rule['keep'] = ($bits[8] & $keepbit); $rule['regexp'] = ($bits[8] & $regexbit); - $rule['bodytransform'] = ($bits[12]); - $rule['field_bodytransform'] = ($bits[13]); - $rule['ctype'] = ($bits[14]); - $rule['field_ctype_val'] = ($bits[15]); + $rule['bodytransform'] = ($bits[12]??null); + $rule['field_bodytransform'] = ($bits[13]??null); + $rule['ctype'] = ($bits[14]??null); + $rule['field_ctype_val'] = ($bits[15]??null); $rule['unconditional'] = 0; if (!$rule['from'] && !$rule['to'] && !$rule['subject'] && !$rule['field'] && !$rule['size'] && $rule['action']) { @@ -188,7 +188,7 @@ class Script } $vacation['addresses'] = &$vaddresses; - $vacation['forwards'] = $bits[5]; + $vacation['forwards'] = $bits[5]??null; } break; case "notify": diff --git a/api/src/Mail/Smtp/Sql.php b/api/src/Mail/Smtp/Sql.php index 83a443cf83..7e20377cf7 100644 --- a/api/src/Mail/Smtp/Sql.php +++ b/api/src/Mail/Smtp/Sql.php @@ -94,7 +94,7 @@ class Sql extends Mail\Smtp ); } } - if ($this->debug) error_log(__METHOD__."('$_accountName') returning ".array2string($emailAddresses)); + if (!empty($this->debug)) error_log(__METHOD__."('$_accountName') returning ".array2string($emailAddresses)); return $emailAddresses; } @@ -191,7 +191,7 @@ class Sql extends Mail\Smtp case self::TYPE_MAILBOX: $userData['mailMessageStore'] = $row['mail_value']; //error_log(__METHOD__."('$user') row=".array2string($row).', enabled[$row[account_id]]='.array2string($enabled[$row['account_id']]).', forwardOnly[$row[account_id]]='.array2string($forwardOnly[$row['account_id']])); - if ($row['account_id'] > 0 && $enabled[$row['account_id']] && !$forwardOnly[$row['account_id']]) + if ($row['account_id'] > 0 && !empty($enabled[$row['account_id']]) && empty($forwardOnly[$row['account_id']])) { $userData['uid'][] = $this->accounts->id2name($row['account_id'], 'account_lid'); $userData['mailbox'][] = $row['mail_value']; @@ -218,7 +218,7 @@ class Sql extends Mail\Smtp } } } - if ($this->debug) error_log(__METHOD__."('$user') returning ".array2string($userData)); + if (!empty($this->debug)) error_log(__METHOD__."('$user') returning ".array2string($userData)); return $userData; } @@ -240,7 +240,7 @@ class Sql extends Mail\Smtp function setUserData($_uidnumber, array $_mailAlternateAddress, array $_mailForwardingAddress, $_deliveryMode, $_accountStatus, $_mailLocalAddress, $_quota, $_forwarding_only=false, $_setMailbox=null) { - if ($this->debug) error_log(__METHOD__."($_uidnumber, ".array2string($_mailAlternateAddress).', '.array2string($_mailForwardingAddress).", '$_deliveryMode', '$_accountStatus', '$_mailLocalAddress', $_quota, forwarding_only=".array2string($_forwarding_only).') '.function_backtrace()); + if (!empty($this->debug)) error_log(__METHOD__."($_uidnumber, ".array2string($_mailAlternateAddress).', '.array2string($_mailForwardingAddress).", '$_deliveryMode', '$_accountStatus', '$_mailLocalAddress', $_quota, forwarding_only=".array2string($_forwarding_only).') '.function_backtrace()); if (!$_forwarding_only && $this->accounts->id2name($_uidnumber, 'account_email') !== $_mailLocalAddress) { diff --git a/api/src/Mailer.php b/api/src/Mailer.php index d002c5d1cd..75fe433c37 100644 --- a/api/src/Mailer.php +++ b/api/src/Mailer.php @@ -564,7 +564,7 @@ class Mailer extends Horde_Mime_Mail if (!isset($flowed)) $flowed = $this->_body && !in_array($this->_body->getType(), array('multipart/encrypted', 'multipart/signed')); // check if flowed is disabled in mail site configuration - if (($config = Config::read('mail')) && $config['disable_rfc3676_flowed']) + if (($config = Config::read('mail')) && !empty($config['disable_rfc3676_flowed'])) { $flowed = false; } @@ -616,7 +616,7 @@ class Mailer extends Horde_Mime_Mail } // log mails to file specified in $GLOBALS['egw_info']['server']['log_mail'] or error_log for true - if ($GLOBALS['egw_info']['server']['log_mail']) + if (!empty($GLOBALS['egw_info']['server']['log_mail'])) { $msg = $GLOBALS['egw_info']['server']['log_mail'] !== true ? date('Y-m-d H:i:s')."\n" : ''; $msg .= (!isset($e) ? 'Mail send' : 'Mail NOT send'). @@ -732,7 +732,7 @@ class Mailer extends Horde_Mime_Mail $recipients->add($h->getAddressList()); } } - if ($this->_bcc) { + if (!empty($this->_bcc)) { $recipients->add($this->_bcc); } diff --git a/api/src/Session.php b/api/src/Session.php index 29d6692975..f9f3a4bec1 100644 --- a/api/src/Session.php +++ b/api/src/Session.php @@ -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 - if (strpos($ret_url=$url, '?') !== false) list($ret_url,$othervars) = explode('?', $url, 2)+[null,null]; + list($ret_url,$othervars) = explode('?', $url, 2)+[null,null]; if ($extravars && is_array($extravars)) { $vars += $extravars; diff --git a/api/src/Storage/Tracking.php b/api/src/Storage/Tracking.php index 7a6bbbf1f7..4b08c0929c 100644 --- a/api/src/Storage/Tracking.php +++ b/api/src/Storage/Tracking.php @@ -636,13 +636,13 @@ abstract class Tracking { //error_log(__METHOD__."() data[$this->assigned_field]=".print_r($data[$this->assigned_field],true).", old[$this->assigned_field]=".print_r($old[$this->assigned_field],true)); $old_assignees = array(); - $assignees = $assigned ? $assigned : array(); - if ($data[$this->assigned_field]) // current assignments + $assignees = $assigned ?? array(); + if (!empty($data[$this->assigned_field])) // current assignments { $assignees = is_array($data[$this->assigned_field]) ? $data[$this->assigned_field] : explode(',',$data[$this->assigned_field]); } - if ($old && $old[$this->assigned_field]) + if ($old && !empty($old[$this->assigned_field])) { $old_assignees = is_array($old[$this->assigned_field]) ? $old[$this->assigned_field] : explode(',',$old[$this->assigned_field]); @@ -1127,18 +1127,18 @@ abstract class Tracking //if ($modified) error_log("data[$name]=".print_r($data[$name],true).", old[$name]=".print_r($old[$name],true)." --> modified=".(int)$modified); if (empty($detail['value']) && !$modified) continue; // skip unchanged, empty values - $body .= $this->format_line($html_email,$detail['type'],$modified, - $detail['label'] ? $detail['label'] : '', $detail['value']); + $body .= $this->format_line($html_email, $detail['type'] ?? null, $modified, + $detail['label'] ?? '', $detail['value']); } if ($html_email) { $body .= "\n"; } - if(($sig = $this->get_signature($data,$old,$receiver))) + if (($sig = $this->get_signature($data,$old,$receiver))) { $body .= ($html_email ? '
':'') . "\n$sig"; } - if (!$html_email && $data['tr_edit_mode'] == 'html') + if (!$html_email && isset($data['tr_edit_mode']) && $data['tr_edit_mode'] === 'html') { $body = Api\Mail\Html::convertHTMLToText($body); } @@ -1271,7 +1271,7 @@ abstract class Tracking $merge_class = $this->app.'_merge'; $merge = new $merge_class(); $error = null; - $sig = $merge->merge_string($config['signature'], array($data[$this->id_field]), $error, 'text/html'); + $sig = $merge->merge_string($config['signature']??null, array($data[$this->id_field]), $error, 'text/html'); if($error) { error_log($error); diff --git a/api/src/Vfs/Base.php b/api/src/Vfs/Base.php index 9f9eea7486..1521ce3eb0 100644 --- a/api/src/Vfs/Base.php +++ b/api/src/Vfs/Base.php @@ -335,21 +335,20 @@ class Base $url = str_replace($matches[0], $matches[1] . Vfs::concat($matches[2], substr($parts['path'], strlen($mounted))), $url); } - if($replace_user_pass_host) + if ($replace_user_pass_host) { - $url = str_replace(array('$user', - '$pass', - '$host', - '$home'), array($parts['user'], - $parts['pass'], - $parts['host'], - $parts['home']), $url); + $url = strtr($url, [ + '$user' => $parts['user'], + '$pass' => $parts['pass'], + '$host' => $parts['host'], + '$home' => $parts['home'], + ]); } - if($parts['query']) + if (isset($parts['query'])) { $url .= '?' . $parts['query']; } - if($parts['fragment']) + if (isset($parts['fragment'])) { $url .= '#' . $parts['fragment']; } @@ -657,7 +656,7 @@ class Base return false; } $k = (string)Vfs::parse_url($url, PHP_URL_SCHEME); - if(!(is_array($scheme2urls[$k]))) + if (!isset($scheme2urls[$k])) { $scheme2urls[$k] = array(); } diff --git a/api/src/Vfs/StreamWrapper.php b/api/src/Vfs/StreamWrapper.php index acf8690b74..b3794d1a74 100644 --- a/api/src/Vfs/StreamWrapper.php +++ b/api/src/Vfs/StreamWrapper.php @@ -798,11 +798,11 @@ class StreamWrapper extends Base implements StreamWrapperIface { $stat['url'] = $url; } - if (($stat['mode'] & 0222) && self::url_is_readonly($stat['url'])) + if ($stat && ($stat['mode'] & 0222) && self::url_is_readonly($stat['url'])) { $stat['mode'] &= ~0222; } - if($stat['url'] && $query && strpos($stat['url'],'?'.$query)===false) + if ($stat && $stat['url'] && $query && strpos($stat['url'],'?'.$query) === false) { $stat['url'] .= '?'.$query; } @@ -998,7 +998,7 @@ class StreamWrapper extends Base implements StreamWrapperIface } else { - $vfs_fstab = $GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab']; + $vfs_fstab = $GLOBALS['egw_info']['user']['preferences']['common']['vfs_fstab'] ?? []; } if (!empty($vfs_fstab) && is_array($vfs_fstab)) { diff --git a/infolog/inc/class.infolog_bo.inc.php b/infolog/inc/class.infolog_bo.inc.php index 9bcfd37f3c..5b74a943b2 100644 --- a/infolog/inc/class.infolog_bo.inc.php +++ b/infolog/inc/class.infolog_bo.inc.php @@ -228,7 +228,7 @@ class infolog_bo { foreach(array_keys($config_data['status']) as $key) { - if (!is_array($this->status[$key])) + if (!isset($this->status[$key]) || !is_array($this->status[$key])) { $this->status[$key] = array(); } @@ -262,17 +262,17 @@ class infolog_bo $save_config = true; } } - if ($save_config) Api\Config::save_value('customfields',$this->customfields,'infolog'); + if (!empty($save_config)) Api\Config::save_value('customfields',$this->customfields,'infolog'); } - if (is_array($config_data['responsible_edit'])) + if (isset($config_data['responsible_edit']) && is_array($config_data['responsible_edit'])) { $this->responsible_edit = array_merge($this->responsible_edit,$config_data['responsible_edit']); } - if (is_array($config_data['copy_excludefields'])) + if (isset($config_data['copy_excludefields']) && is_array($config_data['copy_excludefields'])) { $this->copy_excludefields = array_merge($this->copy_excludefields,$config_data['copy_excludefields']); } - if (is_array($config_data['sub_excludefields']) && $config_data['sub_excludefields']) + if (!empty($config_data['sub_excludefields']) && is_array($config_data['sub_excludefields'])) { $this->sub_excludefields = array_merge($this->sub_excludefields,$config_data['sub_excludefields']); } @@ -286,7 +286,7 @@ class infolog_bo } $this->history = $config_data['history']; - $this->limit_modified_n_month = $config_data['limit_modified_n_month']; + $this->limit_modified_n_month = $config_data['limit_modified_n_month'] ?? null; } // sort types by there translation foreach($this->enums['type'] as $key => $val) @@ -629,12 +629,14 @@ class infolog_bo if (!$info_id || ($data = $this->so->read($info_id)) === False) { - return null; + $null = null; + return $null; } if (!$ignore_acl && !$this->check_access($data,Acl::READ)) // check behind read, to prevent a double read { - return False; + $false = False; + return $false; } if ($data['info_subject'] == $this->subject_from_des($data['info_des'])) diff --git a/infolog/inc/class.infolog_egw_record.inc.php b/infolog/inc/class.infolog_egw_record.inc.php index b389e3c626..7deb2b15f7 100644 --- a/infolog/inc/class.infolog_egw_record.inc.php +++ b/infolog/inc/class.infolog_egw_record.inc.php @@ -1,6 +1,6 @@ record[$_attribute_name]; + return $this->record[$_attribute_name] ?? null; } /** diff --git a/infolog/inc/class.infolog_merge.inc.php b/infolog/inc/class.infolog_merge.inc.php index c53c3370bc..520c3f2299 100644 --- a/infolog/inc/class.infolog_merge.inc.php +++ b/infolog/inc/class.infolog_merge.inc.php @@ -138,7 +138,7 @@ class infolog_merge extends Api\Storage\Merge // Set any missing custom fields, or the marker will stay foreach($this->bo->customfields as $name => $field) { - if(!$array['#'.$name]) + if (empty($array['#'.$name])) { $array['#'.$name] = ''; } diff --git a/infolog/inc/class.infolog_tracking.inc.php b/infolog/inc/class.infolog_tracking.inc.php index 69c3a810c0..23f3cfb302 100644 --- a/infolog/inc/class.infolog_tracking.inc.php +++ b/infolog/inc/class.infolog_tracking.inc.php @@ -144,7 +144,7 @@ class infolog_tracking extends Api\Storage\Tracking */ function get_subject($data, $old, $deleted = null, $receiver = null) { - if ($data['prefix']) + if (!empty($data['prefix'])) { $prefix = $data['prefix']; // async notification } @@ -172,7 +172,7 @@ class infolog_tracking extends Api\Storage\Tracking */ function get_message($data, $old, $receiver = null) { - if ($data['message']) return $data['message']; // async notification + if (!empty($data['message'])) return $data['message']; // async notification if (!$old || $old['info_status'] == 'deleted') { @@ -345,16 +345,16 @@ class infolog_tracking extends Api\Storage\Tracking return ''; } // Per-type notification - $type_config = $info_config[self::CUSTOM_NOTIFICATION][$data['info_type']]; + $type_config = $info_config[self::CUSTOM_NOTIFICATION][$data['info_type']] ?? null; $global = $info_config[self::CUSTOM_NOTIFICATION]['~global~']; // Disabled - if(!$type_config['use_custom'] && !$global['use_custom']) return ''; + if(empty($type_config['use_custom']) && empty($global['use_custom'])) return ''; - // Type or globabl + // Type or global $config = trim(strip_tags($type_config['message'])) != '' && $type_config['use_custom'] ? $type_config['message'] : $global['message']; break; } - return $config; + return $config ?? null; } } diff --git a/infolog/inc/class.infolog_ui.inc.php b/infolog/inc/class.infolog_ui.inc.php index 5e8673f56b..830748f0fc 100644 --- a/infolog/inc/class.infolog_ui.inc.php +++ b/infolog/inc/class.infolog_ui.inc.php @@ -1874,7 +1874,7 @@ class infolog_ui $content['link_to']['to_app'] = 'infolog'; $content['link_to']['to_id'] = $info_id; - + /* $info_link_id is never defined if ($info_link_id && strpos($info_link_id,':') !== false) // updating info_link_id if necessary { list($app,$id) = explode(':',$info_link_id); @@ -1903,7 +1903,7 @@ class infolog_ui // we need eg. the new modification date, for further updates $content = array_merge($content,$to_write); } - } + }*/ // Need to purge description history after encryption? if($content['clean_history']) @@ -2115,7 +2115,7 @@ class infolog_ui // remove types owned by groups the user has no edit grant (current type is made readonly) foreach($this->bo->group_owners as $type => $group) { - if (!($this->bo->grants[$group] & Acl::EDIT)) + if (!(($this->bo->grants[$group]??0) & Acl::EDIT)) { if ($type == $content['info_type']) { @@ -2172,7 +2172,7 @@ class infolog_ui $readonlys['action'] = true; } // ToDo: use the old status before the delete - if ($info_id && $undelete) + if ($info_id && !empty($undelete)) { $content['info_status'] = $this->bo->status['defaults'][$content['info_type']]; $this->tmpl->setElementAttribute('button[save]', 'label', 'Un-Delete'); @@ -2187,7 +2187,7 @@ class infolog_ui // use a typ-specific template (infolog.edit.xyz), if one exists, otherwise fall back to the generic one if (!$this->tmpl->read('infolog.edit.'.$content['info_type'])) { - $this->tmpl->read($print ? 'infolog.edit.print':'infolog.edit'); + $this->tmpl->read(!empty($print) ? 'infolog.edit.print' : 'infolog.edit'); } if ($this->bo->has_customfields($content['info_type'])) { @@ -2252,7 +2252,7 @@ class infolog_ui $tracking = new infolog_tracking($this); foreach($tracking->field2history as $field => $history) { - $history_stati[$history] = $tracking->field2label[$field]; + $history_stati[$history] = $tracking->field2label[$field] ?? null; } // Modified date removed from field2history, we don't need that in the history $history_stati['Mo'] = $tracking->field2label['info_datemodified']; @@ -2276,20 +2276,20 @@ class infolog_ui 'to_tracker' => array('label' => 'Tracker', 'title' => 'Convert to a ticket'), ), ); - if ($GLOBALS['egw_info']['user']['apps']['calendar']) + if (!empty($GLOBALS['egw_info']['user']['apps']['calendar'])) { $sel_options['action']['schedule'] = array('label' => 'Schedule', 'title' => 'Schedule appointment'); } - if ($GLOBALS['egw_info']['user']['apps']['stylite'] && !$GLOBALS['egw_info']['server']['disable_pgp_encryption']) + if (!empty($GLOBALS['egw_info']['user']['apps']['stylite']) && empty($GLOBALS['egw_info']['server']['disable_pgp_encryption'])) { $content['encryption_ts'] = filemtime(EGW_SERVER_ROOT.'/stylite/js/app.js'); } - elseif ($GLOBALS['egw_info']['server']['disable_pgp_encryption']) + elseif (!empty($GLOBALS['egw_info']['server']['disable_pgp_encryption'])) { $readonlys['encrypt'] = true; } $GLOBALS['egw_info']['flags']['app_header'] = lang('InfoLog').' - '. - ($content['status_only'] ? lang('Edit Status') : lang('Edit')); + (!empty($content['status_only']) ? lang('Edit Status') : lang('Edit')); $GLOBALS['egw_info']['flags']['params']['manual'] = array('page' => ($info_id ? 'ManualInfologEdit' : 'ManualInfologAdd')); //error_log(substr($content['info_des'],1793,10)); //$content['info_des'] = substr($content['info_des'],0,1793); diff --git a/mail/inc/class.mail_compose.inc.php b/mail/inc/class.mail_compose.inc.php index 0a6078d3d4..c485255826 100644 --- a/mail/inc/class.mail_compose.inc.php +++ b/mail/inc/class.mail_compose.inc.php @@ -216,7 +216,7 @@ class mail_compose ); $acc_smime = Mail\Smime::get_acc_smime($content['mailaccount']); - if ($acc_smime['acc_smime_password']) + if ($acc_smime && !empty($acc_smime['acc_smime_password'])) { $actions = array_merge($actions, array( 'smime_sign' => array ( @@ -271,9 +271,9 @@ class mail_compose } unset($actions['pgp']); } - if ($GLOBALS['egw_info']['server']['disable_pgp_encryption']) unset($actions['pgp']); + if (!empty($GLOBALS['egw_info']['server']['disable_pgp_encryption'])) unset($actions['pgp']); // remove vfs actions if the user has no run access to filemanager - if (!$GLOBALS['egw_info']['user']['apps']['filemanager']) + if (empty($GLOBALS['egw_info']['user']['apps']['filemanager'])) { unset($actions['save2vfs']); unset($actions['selectFromVFSForCompose']); @@ -1242,16 +1242,16 @@ class mail_compose // address stuff like from, to, cc, replyto $destinationRows = 0; foreach(self::$destinations as $destination) { - if (!is_array($content[$destination])) + if (!empty($content[$destination]) && !is_array($content[$destination])) { - if (!empty($content[$destination])) $content[$destination] = (array)$content[$destination]; + $content[$destination] = (array)$content[$destination]; } - $addr_content = $content[strtolower($destination)]; + $addr_content = $content[strtolower($destination)] ?? []; // we clear the given address array and rebuild it unset($content[strtolower($destination)]); - foreach((array)$addr_content as $key => $value) { - if ($value=="NIL@NIL") continue; - if ($destination=='replyto' && str_replace('"','',$value) == + foreach($addr_content as $value) { + if ($value === "NIL@NIL") continue; + if ($destination === 'replyto' && str_replace('"','',$value) === str_replace('"','',$identities[$this->mail_bo->getDefaultIdentity()])) { // preserve/restore the value to content. @@ -1261,7 +1261,7 @@ class mail_compose //error_log(__METHOD__.__LINE__.array2string(array('key'=>$key,'value'=>$value))); $value = str_replace("\"\"",'"', htmlspecialchars_decode($value, ENT_COMPAT)); foreach(Mail::parseAddressList($value) as $addressObject) { - if ($addressObject->host == '.SYNTAX-ERROR.') continue; + if ($addressObject->host === '.SYNTAX-ERROR.') continue; $address = imap_rfc822_write_address($addressObject->mailbox,$addressObject->host,$addressObject->personal); //$address = Mail::htmlentities($address, $this->displayCharset); $content[strtolower($destination)][]=$address; @@ -1289,7 +1289,7 @@ class mail_compose $content['mail_'.($content['mimeType'] == 'html'?'html':'plain').'text'] =$content['body']; $content['showtempname']=0; //if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.'before merging content with uploadforCompose:'.array2string($content['attachments'])); - $content['attachments']=(is_array($content['attachments'])&&is_array($content['uploadForCompose'])?array_merge($content['attachments'],(!empty($content['uploadForCompose'])?$content['uploadForCompose']:array())):(is_array($content['uploadForCompose'])?$content['uploadForCompose']:(is_array($content['attachments'])?$content['attachments']:null))); + $content['attachments'] = array_merge($content['attachments'] ?? [], $content['uploadForCompose'] ?? []); //if (is_array($content['attachments'])) foreach($content['attachments'] as $k => &$file) $file['delete['.$file['tmp_name'].']']=0; $content['no_griddata'] = empty($content['attachments']); $preserv['attachments'] = $content['attachments']; @@ -1297,21 +1297,21 @@ class mail_compose //if (is_array($content['attachments']))error_log(__METHOD__.__LINE__.' Attachments:'.array2string($content['attachments'])); // if no filemanager -> no vfsFileSelector - if (!$GLOBALS['egw_info']['user']['apps']['filemanager']) + if (empty($GLOBALS['egw_info']['user']['apps']['filemanager'])) { $content['vfsNotAvailable'] = "mail_DisplayNone"; } // if no infolog -> no save as infolog - if (!$GLOBALS['egw_info']['user']['apps']['infolog']) + if (empty($GLOBALS['egw_info']['user']['apps']['infolog'])) { $content['noInfologAvailable'] = "mail_DisplayNone"; } // if no tracker -> no save as tracker - if (!$GLOBALS['egw_info']['user']['apps']['tracker']) + if (empty($GLOBALS['egw_info']['user']['apps']['tracker'])) { $content['noTrackerAvailable'] = "mail_DisplayNone"; } - if (!$GLOBALS['egw_info']['user']['apps']['infolog'] && !$GLOBALS['egw_info']['user']['apps']['tracker']) + if (empty($GLOBALS['egw_info']['user']['apps']['infolog']) && empty($GLOBALS['egw_info']['user']['apps']['tracker'])) { $content['noSaveAsAvailable'] = "mail_DisplayNone"; } @@ -1324,12 +1324,12 @@ class mail_compose $sel_options['mimeType'] = self::$mimeTypes; $sel_options['priority'] = self::$priorities; $sel_options['filemode'] = Vfs\Sharing::$modes; - if (!isset($content['priority']) || empty($content['priority'])) $content['priority']=3; + if (empty($content['priority'])) $content['priority']=3; //$GLOBALS['egw_info']['flags']['currentapp'] = 'mail';//should not be needed $etpl = new Etemplate('mail.compose'); $etpl->setElementAttribute('composeToolbar', 'actions', self::getToolbarActions($content)); - if ($content['mimeType']=='html') + if ($content['mimeType'] === 'html') { //mode="$cont[rtfEditorFeatures]" validation_rules="$cont[validation_rules]" base_href="$cont[upload_dir]" $_htmlConfig = Mail::$htmLawed_config; @@ -1340,7 +1340,7 @@ class mail_compose Mail::$htmLawed_config = $_htmlConfig; } - if (isset($content['composeID'])&&!empty($content['composeID'])) + if (!empty($content['composeID'])) { $composeCache = $content; unset($composeCache['body']); @@ -1348,23 +1348,23 @@ class mail_compose unset($composeCache['mail_plaintext']); Api\Cache::setCache(Api\Cache::SESSION,'mail','composeCache'.trim($GLOBALS['egw_info']['user']['account_id']).'_'.$this->composeID,$composeCache,$expiration=60*60*2); } - if (!isset($_content['serverID'])||empty($_content['serverID'])) + if (empty($_content['serverID'])) { $content['serverID'] = $this->mail_bo->profileID; } $preserv['serverID'] = $content['serverID']; - $preserv['lastDrafted'] = $content['lastDrafted']; - $preserv['processedmail_id'] = $content['processedmail_id']; - $preserv['references'] = $content['references']; - $preserv['in-reply-to'] = $content['in-reply-to']; + $preserv['lastDrafted'] = $content['lastDrafted'] ?? null; + $preserv['processedmail_id'] = $content['processedmail_id'] ?? null; + $preserv['references'] = $content['references'] ?? null; + $preserv['in-reply-to'] = $content['in-reply-to'] ?? null; // thread-topic is a proprietary microsoft header and deprecated with the current version // horde does not support the encoding of thread-topic, and probably will not no so in the future //$preserv['thread-topic'] = $content['thread-topic']; - $preserv['thread-index'] = $content['thread-index']; - $preserv['list-id'] = $content['list-id']; - $preserv['mode'] = $content['mode']; + $preserv['thread-index'] = $content['thread-index'] ?? null; + $preserv['list-id'] = $content['list-id'] ?? null; + $preserv['mode'] = $content['mode'] ?? null; // convert it back to checkbox expectations - if($content['mimeType'] == 'html') { + if($content['mimeType'] === 'html') { $content['mimeType']=1; } else { $content['mimeType']=0; @@ -1391,11 +1391,11 @@ class mail_compose // Resolve distribution list before send content to client foreach(array('to', 'cc', 'bcc', 'replyto') as $f) { - if (is_array($content[$f])) $content[$f]= self::resolveEmailAddressList ($content[$f]); + if (isset($content[$f]) && is_array($content[$f])) $content[$f]= self::resolveEmailAddressList ($content[$f]); } // set filemode icons for all attachments - if($content['attachments'] && is_array($content['attachments'])) + if(!empty($content['attachments'])) { foreach($content['attachments'] as &$attach) { @@ -1407,9 +1407,9 @@ class mail_compose } } - $content['to'] = self::resolveEmailAddressList($content['to']); + if (isset($content['to'])) $content['to'] = self::resolveEmailAddressList($content['to']); $content['html_toolbar'] = empty(Mail::$mailConfig['html_toolbar']) ? - join(',', Etemplate\Widget\HtmlArea::$toolbar_default_list) : join(',', Mail::$mailConfig['html_toolbar']); + implode(',', Etemplate\Widget\HtmlArea::$toolbar_default_list) : implode(',', Mail::$mailConfig['html_toolbar']); //error_log(__METHOD__.__LINE__.array2string($content)); $etpl->exec('mail.mail_compose.compose',$content,$sel_options,array(),$preserv,2); } @@ -2485,7 +2485,7 @@ class mail_compose if(!empty($_formData['list-id'])) { $_mailObject->addHeader('List-Id', $_formData['list-id']); } - if($_formData['disposition']=='on') { + if(isset($_formData['disposition']) && $_formData['disposition'] === 'on') { $_mailObject->addHeader('Disposition-Notification-To', $_identity['ident_email']); } @@ -2522,7 +2522,7 @@ class mail_compose if ($_formData['attachments'] && $_formData['filemode'] != Vfs\Sharing::ATTACH && !$_autosaving) { $attachment_links = $this->_getAttachmentLinks($_formData['attachments'], $_formData['filemode'], - $_formData['mimeType'] == 'html', + $_formData['mimeType'] === 'html', array_unique(array_merge((array)$_formData['to'], (array)$_formData['cc'], (array)$_formData['bcc'])), $_formData['expiration'], $_formData['password']); } @@ -2530,7 +2530,7 @@ class mail_compose { case 'html': $body = $_formData['body']; - if ($attachment_links) + if (!empty($attachment_links)) { if (strpos($body, '') !== false) { @@ -2567,7 +2567,7 @@ class mail_compose default: $body = $this->convertHTMLToText($_formData['body'],false, false, true, true); - if ($attachment_links) $body .= $attachment_links; + if (!empty($attachment_links)) $body .= $attachment_links; #$_mailObject->Body = $_formData['body']; if(!empty($signature)) { @@ -2653,7 +2653,7 @@ class mail_compose } if ($connection_opened) $mail_bo->closeConnection(); } - return is_array($inline_images)?$inline_images:array(); + return $inline_images ?? []; } /** @@ -2761,7 +2761,7 @@ class mail_compose $dmailbox = $dhA['folder']; // beware: do not delete the original mail as found in processedmail_id $pMuid=''; - if ($content['processedmail_id']) + if (!empty($content['processedmail_id'])) { $pMhA = mail_ui::splitRowID($content['processedmail_id']); $pMuid = $pMhA['msgUID']; @@ -3021,7 +3021,7 @@ class mail_compose // create the messages and store inline images $inline_images = $this->createMessage($mail, $_formData, $identity); // remember the identity - if ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on') $fromAddress = $mail->From;//$mail->FromName.($mail->FromName?' <':'').$mail->From.($mail->FromName?'>':''); + if (!empty($mail->From) && ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on')) $fromAddress = $mail->From;//$mail->FromName.($mail->FromName?' <':'').$mail->From.($mail->FromName?'>':''); #print "
". $mail->getMessageHeader() ."


"; #print "
". $mail->getMessageBody() ."


"; #exit; @@ -3317,14 +3317,14 @@ class mail_compose if (isset($lastDrafted['uid']) && !empty($lastDrafted['uid'])) $lastDrafted['uid']=trim($lastDrafted['uid']); // manually drafted, do not delete // will be handled later on IF mode was $_formData['mode']=='composefromdraft' - if (isset($lastDrafted['uid']) && (empty($lastDrafted['uid']) || $lastDrafted['uid'] == $this->sessionData['uid'])) $lastDrafted=false; + if (isset($lastDrafted['uid']) && (empty($lastDrafted['uid']) || $lastDrafted['uid'] == ($this->sessionData['uid']??null))) $lastDrafted=false; //error_log(__METHOD__.__LINE__.array2string($lastDrafted)); } if ($lastDrafted && is_array($lastDrafted) && $mail_bo->isDraftFolder($lastDrafted['folder'])) { try { - if ($this->sessionData['lastDrafted'] != $this->sessionData['uid'] || !($_formData['mode']=='composefromdraft' && + if ($this->sessionData['lastDrafted'] != ($this->sessionData['uid']??null) || !($_formData['mode']=='composefromdraft' && ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' )&&$this->sessionData['attachments'])) { //error_log(__METHOD__.__LINE__."#".$lastDrafted['uid'].'#'.$lastDrafted['folder'].array2string($_formData)); @@ -3399,7 +3399,7 @@ class mail_compose } if (is_array($this->sessionData['cc'])) $mailaddresses['cc'] = $this->sessionData['cc']; if (is_array($this->sessionData['bcc'])) $mailaddresses['bcc'] = $this->sessionData['bcc']; - if (!empty($mailaddresses)) $mailaddresses['from'] = Mail\Html::decodeMailHeader($fromAddress); + if (!empty($mailaddresses) && !empty($fromAddress)) $mailaddresses['from'] = Mail\Html::decodeMailHeader($fromAddress); if ($_formData['to_infolog'] == 'on' || $_formData['to_tracker'] == 'on' || $_formData['to_calendar'] == 'on' ) { @@ -3407,7 +3407,7 @@ class mail_compose foreach(array('to_infolog','to_tracker','to_calendar') as $app_key) { - $entryid = $_formData['to_integrate_ids'][0][$app_key]; + $entryid = $_formData['to_integrate_ids'][0][$app_key] ?? null; if ($_formData[$app_key] == 'on') { $app_name = substr($app_key,3); diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 90b9528ff7..1e55829c96 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -425,7 +425,7 @@ class mail_ui protected static function image_proxy() { $configs = Api\Config::read('mail'); - $image_proxy = $configs[self::IMAGE_PROXY_CONFIG] ?: self::DEFAULT_IMAGE_PROXY; + $image_proxy = $configs[self::IMAGE_PROXY_CONFIG] ?? self::DEFAULT_IMAGE_PROXY; if (strpos(self::EGROUPWARE_IMAGE_PROXY, parse_url($image_proxy, PHP_URL_HOST))) { $image_proxy = self::EGROUPWARE_IMAGE_PROXY; @@ -565,7 +565,7 @@ class mail_ui $etpl->setElementAttribute(self::$nm_index.'[foldertree]','actions', $this->get_tree_actions()); // sending preview toolbar actions - if ($content['mailSplitter']) $etpl->setElementAttribute('mailPreview[toolbar]', 'actions', $this->get_toolbar_actions()); + if (!empty($content['mailSplitter'])) $etpl->setElementAttribute('mailPreview[toolbar]', 'actions', $this->get_toolbar_actions()); // We need to send toolbar actions to client-side because view template needs them if (Api\Header\UserAgent::mobile()) $sel_options['toolbar'] = $this->get_toolbar_actions(); @@ -1827,7 +1827,7 @@ $filter['before']= date("d-M-Y", $cutoffdate2); // we have an own created rowID; prepend app=mail array_unshift($res,'mail'); } - return array('app'=>$res[0], 'accountID'=>$res[1], 'profileID'=>$res[2], 'folder'=>base64_decode($res[3]), 'msgUID'=>$res[4]); + return array('app'=>$res[0], 'accountID'=>$res[1]??null, 'profileID'=>$res[2]??null, 'folder'=>base64_decode($res[3]??null), 'msgUID'=>$res[4]??null); } /** diff --git a/notifications/inc/class.notifications_popup.inc.php b/notifications/inc/class.notifications_popup.inc.php index 3452e5ec6a..2c0f780416 100644 --- a/notifications/inc/class.notifications_popup.inc.php +++ b/notifications/inc/class.notifications_popup.inc.php @@ -160,7 +160,7 @@ class notifications_popup implements notifications_iface { foreach ($rs as $notification) { $actions = null; $data = json_decode($notification['notify_data'], true); - if ($data['appname'] && $data['data']) + if (!empty($data['appname']) && !empty($data['data'])) { $_actions = Api\Hooks::process (array( 'location' => 'notifications_actions', @@ -175,7 +175,7 @@ class notifications_popup implements notifications_iface { 'created' => Api\DateTime::server2user($notification['notify_created']), 'current' => new Api\DateTime('now'), 'actions' => is_array($actions)?$actions:NULL, - 'extra_data' => ($data['data'] ? $data['data'] : array()) + 'extra_data' => $data['data'] ?? [], ); } diff --git a/pixelegg/inc/class.pixelegg_framework.inc.php b/pixelegg/inc/class.pixelegg_framework.inc.php index 073f8f8ee3..7dba756528 100755 --- a/pixelegg/inc/class.pixelegg_framework.inc.php +++ b/pixelegg/inc/class.pixelegg_framework.inc.php @@ -85,13 +85,13 @@ class pixelegg_framework extends Api\Framework\Ajax { $ret = parent::_get_css(); // color to use - $color = str_replace('custom',$GLOBALS['egw_info']['user']['preferences']['common']['template_custom_color'], - $GLOBALS['egw_info']['user']['preferences']['common']['template_color']); + $color = str_replace('custom', $GLOBALS['egw_info']['user']['preferences']['common']['template_custom_color'] ?? null, + $GLOBALS['egw_info']['user']['preferences']['common']['template_color'] ?? null); // Create a dark variant of the color $color_darker = empty($color) ? '' :$this->_color_shader($color, -30); - if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color'])) + if (!empty($GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color']) && preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color'])) { $sidebox_color_hover = $GLOBALS['egw_info']['user']['preferences']['common']['sidebox_custom_color']; $sidebox_color = $this->_color_shader($sidebox_color_hover, -30); @@ -101,7 +101,7 @@ class pixelegg_framework extends Api\Framework\Ajax $sidebox_color_hover = $color; $sidebox_color = $color_darker; } - if (preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color'])) + if (!empty($GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color']) && preg_match('/^(#[0-9A-F]+|[A-Z]+)$/i', $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color'])) { $loginbox_color = $GLOBALS['egw_info']['user']['preferences']['common']['loginbox_custom_color']; } @@ -109,8 +109,8 @@ class pixelegg_framework extends Api\Framework\Ajax { $loginbox_color = $color_darker; } - //alway set header logo used in sharing regardless of custom color being set - $header = $GLOBALS['egw_info']['server']['login_logo_header'] ? Api\Framework::get_login_logo_or_bg_url('login_logo_header', 'logo') + //always set header logo used in sharing regardless of custom color being set + $header = !empty($GLOBALS['egw_info']['server']['login_logo_header']) ? Api\Framework::get_login_logo_or_bg_url('login_logo_header', 'logo') : Api\Framework::get_login_logo_or_bg_url('login_logo_file', 'logo'); $ret['app_css'] .= " /* From d00d6f65f01dd231013de2d2d3a4368ac2ea4e90 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 10:44:23 +0200 Subject: [PATCH 02/70] fix PHP 8.0 error when deleting a Kanban card - link deletion failed when link_id was "" as in PHP 8.0 "" < 0 --> gave the error - link to card was never deleted as board_id is not stored in card --- api/src/Link.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/Link.php b/api/src/Link.php index 68298cfb91..386d01ca99 100644 --- a/api/src/Link.php +++ b/api/src/Link.php @@ -683,15 +683,15 @@ class Link extends Link\Storage { echo "

Link::unlink('$link_id','$app',".array2string($id).",'$owner','$app2','$id2', $hold_for_purge)

\n"; } - if ($link_id < 0) // vfs-link? + if ((int)$link_id < 0) // vfs-link? { return self::delete_attached(-$link_id); } - elseif ($app == self::VFS_APPNAME) + elseif ($app === self::VFS_APPNAME) { return self::delete_attached($app2,$id2,$id); } - elseif ($app2 == self::VFS_APPNAME) + elseif ($app2 === self::VFS_APPNAME) { return self::delete_attached($app,$id,$id2); } From e4f95d9c20604ca7a1aa29e32efce19253fe89fc Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 11:57:20 +0200 Subject: [PATCH 03/70] fix missing icons after previous commit --- api/src/Etemplate/Widget/Tree.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/Etemplate/Widget/Tree.php b/api/src/Etemplate/Widget/Tree.php index dcab22cced..b05deaac1c 100644 --- a/api/src/Etemplate/Widget/Tree.php +++ b/api/src/Etemplate/Widget/Tree.php @@ -297,7 +297,7 @@ class Tree extends Etemplate\Widget { $form_name = self::form_name($cname, $this->id); - if (!empty($this->attrs['image_path']) && ($templated_path = self::templateImagePath($this->attrs['image_path'])) != $this->attrs['image_path']) + if (($templated_path = self::templateImagePath($this->attrs['image_path'] ?? null)) !== ($this->attrs['image_path'] ?? null)) { self::setElementAttribute($form_name, 'image_path', $this->attrs['image_path'] = $templated_path); //error_log(__METHOD__."() setting templated image-path for $form_name: $templated_path"); From b1780a35bc4c4bb9b42d6b1454d3a9948fc39b7c Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 12:17:33 +0200 Subject: [PATCH 04/70] fix Api\Storage\Merge::document_editable_action(): Argument #1 ($action) must be of type array, null given --- api/src/Storage/Merge.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index ca01c49612..1c1f0d9742 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -2254,16 +2254,19 @@ abstract class Merge switch($count) { case (count($name_arr) - 1): - $current_level[$prefix . $file['name']]; + if (!isset($current_level[$prefix . $file['name']])) + { + $current_level[$prefix . $file['name']] = []; + } self::document_editable_action($current_level[$prefix . $file['name']], $file); - if($file['mime'] == 'message/rfc822') + if ($file['mime'] === 'message/rfc822') { self::document_mail_action($current_level[$prefix . $file['name']], $file); } break; default: - if(!is_array($current_level[$prefix . $name_arr[$count]])) + if (!isset($current_level[$prefix . $name_arr[$count]])) { // create parent folder $current_level[$prefix . $name_arr[$count]] = array( From d915b25bba96b7981af743d10a6b3ef76eace3b2 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 12:37:10 +0200 Subject: [PATCH 05/70] fix PHP 8.0 error Illegal string offset folder object need to be cast to string (folder name) as objects are not allowed as array keys --- api/src/Mail.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/Mail.php b/api/src/Mail.php index cc8dc088ad..4e4d56d44f 100644 --- a/api/src/Mail.php +++ b/api/src/Mail.php @@ -5589,10 +5589,10 @@ class Mail if (empty($_folder)) $_folder = $this->sessionData['mailbox']?: $this->icServer->getCurrentMailbox(); $_uid = !(is_object($_uid) || is_array($_uid)) ? (array)$_uid : $_uid; - if (!$_stream && isset($rawBody[$this->icServer->ImapServerId][$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)])) + if (!$_stream && isset($rawBody[$this->icServer->ImapServerId][(string)$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)])) { //error_log(__METHOD__.' ('.__LINE__.') '." Using Cache for raw Body $_uid, $_partID in Folder $_folder"); - return $rawBody[$this->icServer->ImapServerId][$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)]; + return $rawBody[$this->icServer->ImapServerId][(string)$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)]; } $uidsToFetch = new Horde_Imap_Client_Ids(); @@ -5629,7 +5629,7 @@ class Mail if (!$_stream) { //error_log(__METHOD__.' ('.__LINE__.') '."[{$this->icServer->ImapServerId}][$_folder][$_uid][".(empty($_partID)?'NIL':$_partID)."]"); - $rawBody[$this->icServer->ImapServerId][$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)] = $body; + $rawBody[$this->icServer->ImapServerId][(string)$_folder][$_uid[0]][(empty($_partID)?'NIL':$_partID)] = $body; } return $body; } From 7c4914d8dbca61b72b8c752573d09a255ba703f7 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 16:16:12 +0200 Subject: [PATCH 06/70] fix PHP 8.0 error "array_key_exists(): Argument #2 ($array) must be of type array, null given" when creating a category --- admin/inc/class.admin_cmd_category.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/inc/class.admin_cmd_category.inc.php b/admin/inc/class.admin_cmd_category.inc.php index 7059cde539..a5b88fb0e8 100644 --- a/admin/inc/class.admin_cmd_category.inc.php +++ b/admin/inc/class.admin_cmd_category.inc.php @@ -87,7 +87,7 @@ class admin_cmd_category extends admin_cmd unset($set['old_parent'], $set['base_url'], $set['last_mod'], $set['all_cats'], $set['no_private']); foreach($set as $key => $value) { - if(array_key_exists($key, $old) && $old[$key] == $value) + if ($old && array_key_exists($key, $old) && $old[$key] == $value) { unset($set[$key]); unset($old[$key]); From a8d14ffa0a6cf0c23228a4522e7caa6b1aec8455 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 16:53:33 +0200 Subject: [PATCH 07/70] fix TypeError: Argument 1 passed to EGroupware\Api\Accounts::username() must be of the type int, null given --- api/src/Accounts.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/api/src/Accounts.php b/api/src/Accounts.php index 889f6c1907..61765c64f1 100644 --- a/api/src/Accounts.php +++ b/api/src/Accounts.php @@ -595,11 +595,15 @@ class Accounts /** * Return formatted username for a given account_id * - * @param int $account_id account id + * @param ?int $account_id account id, default current user * @return string full name of user or "#$account_id" if user not found */ - static function username(int $account_id) + static function username(int $account_id=null) { + if (empty($account_id)) + { + $account_id = $GLOBALS['egw_info']['user']['account_id']; + } if (!($account = self::cache_read($account_id))) { return '#'.$account_id; From 460d8cbe0dda6448c62ab13f06cdf5263687a4f6 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Thu, 7 Oct 2021 17:28:06 +0200 Subject: [PATCH 08/70] fix not working preferences GUI after ddddc5ba0590320ae2f3de01d4e64d281ba0ac85 --- api/src/Etemplate/Widget/Box.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/Etemplate/Widget/Box.php b/api/src/Etemplate/Widget/Box.php index de3a379091..74a198d239 100644 --- a/api/src/Etemplate/Widget/Box.php +++ b/api/src/Etemplate/Widget/Box.php @@ -50,7 +50,7 @@ class Box extends Etemplate\Widget $old_expand = $params[1]; if ($this->id && $this->type != 'groupbox') $cname = self::form_name($cname, $this->id, $params[1]); - if (!empty($expand['cname']) && $expand['cname'] !== $cname && trim($cname)) + if (($expand['cname'] ?? null) !== $cname && trim($cname)) { $expand['cont'] =& self::get_array(self::$request->content, $cname); $expand['cname'] = $cname; From 40af04e38e5cf7ac6e5439e9d93eac8b20784488 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 7 Oct 2021 09:31:43 -0600 Subject: [PATCH 09/70] Fix broken Merge::get_app_class(), we need it to autoload the class --- api/src/Storage/Merge.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index 1c1f0d9742..f27137a172 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -1644,7 +1644,7 @@ abstract class Merge public static function get_app_class($appname) { $classname = "{$appname}_merge"; - if(class_exists($classname, false) && is_subclass_of($classname, 'EGroupware\\Api\\Storage\\Merge')) + if(class_exists($classname) && is_subclass_of($classname, 'EGroupware\\Api\\Storage\\Merge')) { $document_merge = new $classname(); } From da6a16e62d9759c5daa3a90c2fe4d455aade77c7 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 7 Oct 2021 10:22:45 -0600 Subject: [PATCH 10/70] - Add generation target path preference to all apps - Use common method to get merge preferences to reduce duplication --- .../inc/class.addressbook_hooks.inc.php | 37 +- api/src/Storage/Merge.php | 1456 ++++++++++------- calendar/inc/class.calendar_hooks.inc.php | 27 +- .../inc/class.filemanager_hooks.inc.php | 42 +- infolog/inc/class.infolog_hooks.inc.php | 37 +- timesheet/inc/class.timesheet_hooks.inc.php | 37 +- 6 files changed, 884 insertions(+), 752 deletions(-) diff --git a/addressbook/inc/class.addressbook_hooks.inc.php b/addressbook/inc/class.addressbook_hooks.inc.php index 9a514656a6..9a59821007 100644 --- a/addressbook/inc/class.addressbook_hooks.inc.php +++ b/addressbook/inc/class.addressbook_hooks.inc.php @@ -291,41 +291,8 @@ class addressbook_hooks if ($GLOBALS['egw_info']['user']['apps']['filemanager']) { - $settings['default_document'] = array( - 'type' => 'vfs_file', - 'size' => 60, - 'label' => 'Default document to insert contacts', - 'name' => 'default_document', - 'help' => lang('If you specify a document (full vfs path) here, %1 displays an extra document icon for each entry. That icon allows to download the specified document with the data inserted.', lang('addressbook')).' '. - lang('The document can contain placeholder like {{%1}}, to be replaced with the data.','n_fn').' '. - lang('The following document-types are supported:'). implode(',',Api\Storage\Merge::get_file_extensions()), - 'run_lang' => false, - 'xmlrpc' => True, - 'admin' => False, - ); - $settings['document_dir'] = array( - 'type' => 'vfs_dirs', - 'size' => 60, - 'label' => 'Directory with documents to insert contacts', - 'name' => 'document_dir', - 'help' => lang('If you specify a directory (full vfs path) here, %1 displays an action for each document. That action allows to download the specified document with the data inserted.', lang('addressbook')) . ' ' . - lang('The document can contain placeholder like {{%1}}, to be replaced with the data.', 'n_fn') . ' ' . - lang('The following document-types are supported:') . implode(',', Api\Storage\Merge::get_file_extensions()), - 'run_lang' => false, - 'xmlrpc' => True, - 'admin' => False, - 'default' => '/templates/addressbook', - ); - $settings[Api\Storage\Merge::PREF_DOCUMENT_FILENAME] = array( - 'type' => 'taglist', - 'label' => 'Document download filename', - 'name' => 'document_download_name', - 'values' => Api\Storage\Merge::DOCUMENT_FILENAME_OPTIONS, - 'help' => 'Choose the default filename for downloaded documents.', - 'xmlrpc' => True, - 'admin' => False, - 'default' => 'document', - ); + $merge = new Api\Contacts\Merge(); + $settings += $merge->merge_preferences(); } if ($GLOBALS['egw_info']['user']['apps']['felamimail'] || $GLOBALS['egw_info']['user']['apps']['mail']) diff --git a/api/src/Storage/Merge.php b/api/src/Storage/Merge.php index f27137a172..f86a651bb7 100644 --- a/api/src/Storage/Merge.php +++ b/api/src/Storage/Merge.php @@ -32,6 +32,16 @@ use ZipArchive; */ abstract class Merge { + /** + * Preference, path where we look for merge templates + */ + public const PREF_TEMPLATE_DIR = 'document_dir'; + + /** + * Preference, path to special documents that are listed first + */ + public const PREF_DEFAULT_TEMPLATE = 'default_document'; + /** * Preference, path where we will put the generated document */ @@ -104,21 +114,21 @@ abstract class Merge public $export_limit; public $public_functions = array( - "merge_entries" => true + "merge_entries" => true ); /** * Configuration for HTML Tidy to clean up any HTML content that is kept */ public static $tidy_config = array( - 'output-xml' => true, // Entity encoding - 'show-body-only' => true, - 'output-encoding' => 'utf-8', - 'input-encoding' => 'utf-8', - 'quote-ampersand' => false, // Prevent double encoding - 'quote-nbsp' => true, // XSLT can handle spaces easier - 'preserve-entities' => true, - 'wrap' => 0, // Wrapping can break output + 'output-xml' => true, // Entity encoding + 'show-body-only' => true, + 'output-encoding' => 'utf-8', + 'input-encoding' => 'utf-8', + 'quote-ampersand' => false, // Prevent double encoding + 'quote-nbsp' => true, // XSLT can handle spaces easier + 'preserve-entities' => true, + 'wrap' => 0, // Wrapping can break output ); /** @@ -156,8 +166,8 @@ abstract class Merge $this->contacts = new Api\Contacts(); - $this->datetime_format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'].' '. - ($GLOBALS['egw_info']['user']['preferences']['common']['timeformat']==12 ? 'h:i a' : 'H:i'); + $this->datetime_format = $GLOBALS['egw_info']['user']['preferences']['common']['dateformat'] . ' ' . + ($GLOBALS['egw_info']['user']['preferences']['common']['timeformat'] == 12 ? 'h:i a' : 'H:i'); $this->export_limit = self::getExportLimit(); } @@ -171,8 +181,8 @@ abstract class Merge { $accountsel = new uiaccountsel(); - return ''. - $accountsel->selection('newsettings[export_limit_excepted]','export_limit_excepted',$config['export_limit_excepted'],'both',4); + return '' . + $accountsel->selection('newsettings[export_limit_excepted]', 'export_limit_excepted', $config['export_limit_excepted'], 'both', 4); } /** @@ -183,10 +193,10 @@ abstract class Merge * - format_datetime($time,$format=null) * * @param int $id id of entry - * @param string &$content=null content to create some replacements only if they are use + * @param string &$content =null content to create some replacements only if they are use * @return array|boolean array with replacements or false if entry not found */ - abstract protected function get_replacements($id,&$content=null); + abstract protected function get_replacements($id, &$content = null); /** * Return if merge-print is implemented for given mime-type (and/or extension) @@ -194,47 +204,56 @@ abstract class Merge * @param string $mimetype eg. text/plain * @param string $extension only checked for applications/msword and .rtf */ - static public function is_implemented($mimetype,$extension=null) + static public function is_implemented($mimetype, $extension = null) { - static $zip_available=null; - if (is_null($zip_available)) + static $zip_available = null; + if(is_null($zip_available)) { $zip_available = check_load_extension('zip') && - class_exists('ZipArchive'); // some PHP has zip extension, but no ZipArchive (eg. RHEL5!) + class_exists('ZipArchive'); // some PHP has zip extension, but no ZipArchive (eg. RHEL5!) } - switch ($mimetype) + switch($mimetype) { case 'application/msword': - if (strtolower($extension) != '.rtf') break; + if(strtolower($extension) != '.rtf') + { + break; + } case 'application/rtf': case 'text/rtf': - return true; // rtf files - case 'application/vnd.oasis.opendocument.text': // oo text - case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet + return true; // rtf files + case 'application/vnd.oasis.opendocument.text': // oo text + case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet case 'application/vnd.oasis.opendocument.presentation': case 'application/vnd.oasis.opendocument.text-template': case 'application/vnd.oasis.opendocument.spreadsheet-template': case 'application/vnd.oasis.opendocument.presentation-template': - if (!$zip_available) break; - return true; // open office write xml files - case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms word 2007 xml format - case 'application/vnd.openxmlformats-officedocument.wordprocessingml.d': // mimetypes in vfs are limited to 64 chars + if(!$zip_available) + { + break; + } + return true; // open office write xml files + case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms word 2007 xml format + case 'application/vnd.openxmlformats-officedocument.wordprocessingml.d': // mimetypes in vfs are limited to 64 chars case 'application/vnd.ms-word.document.macroenabled.12': - case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': // ms excel 2007 xml format + case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': // ms excel 2007 xml format case 'application/vnd.openxmlformats-officedocument.spreadsheetml.shee': case 'application/vnd.ms-excel.sheet.macroenabled.12': - if (!$zip_available) break; - return true; // ms word xml format + if(!$zip_available) + { + break; + } + return true; // ms word xml format case 'application/xml': - return true; // alias for text/xml, eg. ms office 2003 word format + return true; // alias for text/xml, eg. ms office 2003 word format case 'message/rfc822': return true; // ToDo: check if you are theoretical able to send mail case 'application/x-yaml': - return true; // yaml file, plain text with marginal syntax support for multiline replacements + return true; // yaml file, plain text with marginal syntax support for multiline replacements default: - if (substr($mimetype,0,5) == 'text/') + if(substr($mimetype, 0, 5) == 'text/') { - return true; // text files + return true; // text files } break; } @@ -252,13 +271,16 @@ abstract class Merge * @param boolean $ignore_acl =false true: no acl check * @return array */ - public function contact_replacements($contact,$prefix='',$ignore_acl=false, &$content = '') + public function contact_replacements($contact, $prefix = '', $ignore_acl = false, &$content = '') { - if (!is_array($contact)) + if(!is_array($contact)) { $contact = $this->contacts->read($contact, $ignore_acl); } - if (!is_array($contact)) return array(); + if(!is_array($contact)) + { + return array(); + } $replacements = array(); foreach(array_keys($this->contacts->contact_fields) as $name) @@ -362,15 +384,15 @@ abstract class Merge } // Format date cfs per user Api\Preferences if($this->mimetype !== 'application/x-yaml' && $contact[$name] && - ($field['type'] == 'date' || $field['type'] == 'date-time')) + ($field['type'] == 'date' || $field['type'] == 'date-time')) { - $this->date_fields[] = '#'.$name; - $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = Api\DateTime::to($contact[$name], $field['type'] == 'date' ? true : ''); + $this->date_fields[] = '#' . $name; + $replacements['$$' . ($prefix ? $prefix . '/' : '') . $name . '$$'] = Api\DateTime::to($contact[$name], $field['type'] == 'date' ? true : ''); } - $replacements['$$'.($prefix ? $prefix.'/':'').$name.'$$'] = + $replacements['$$' . ($prefix ? $prefix . '/' : '') . $name . '$$'] = // use raw data for yaml, no user-preference specific formatting $this->mimetype == 'application/x-yaml' || $field['type'] == 'htmlarea' ? (string)$contact[$name] : - Customfields::format($field, (string)$contact[$name]); + Customfields::format($field, (string)$contact[$name]); } if($content && strpos($content, '$$#') !== FALSE) @@ -380,22 +402,27 @@ abstract class Merge // Add in extra cat field $cats = array(); - foreach(is_array($contact['cat_id']) ? $contact['cat_id'] : explode(',',$contact['cat_id']) as $cat_id) + foreach(is_array($contact['cat_id']) ? $contact['cat_id'] : explode(',', $contact['cat_id']) as $cat_id) { - if(!$cat_id) continue; - if($GLOBALS['egw']->categories->id2name($cat_id,'main') != $cat_id) + if(!$cat_id) + { + continue; + } + if($GLOBALS['egw']->categories->id2name($cat_id, 'main') != $cat_id) { $path = explode(' / ', $GLOBALS['egw']->categories->id2name($cat_id, 'path')); unset($path[0]); // Drop main - $cats[$GLOBALS['egw']->categories->id2name($cat_id,'main')][] = implode(' / ', $path); - } elseif($cat_id) { + $cats[$GLOBALS['egw']->categories->id2name($cat_id, 'main')][] = implode(' / ', $path); + } + elseif($cat_id) + { $cats[$cat_id] = array(); } } - $replacements['$$'.($prefix ? $prefix.'/':'').'categories$$'] = ''; + $replacements['$$' . ($prefix ? $prefix . '/' : '') . 'categories$$'] = ''; foreach($cats as $main => $cat) { - $replacements['$$'.($prefix ? $prefix.'/':'').'categories$$'] .= $GLOBALS['egw']->categories->id2name($main,'name') + $replacements['$$' . ($prefix ? $prefix . '/' : '') . 'categories$$'] .= $GLOBALS['egw']->categories->id2name($main, 'name') . (count($cat) > 0 ? ': ' : '') . implode(', ', $cats[$main]) . "\n"; } return $replacements; @@ -411,11 +438,11 @@ abstract class Merge * @param only_app Restrict links to only given application * @param exclude Exclude links to these applications * @param style String One of: - * 'title' - plain text, just the title of the link - * 'link' - URL to the entry - * 'href' - HREF tag wrapped around the title + * 'title' - plain text, just the title of the link + * 'link' - URL to the entry + * 'href' - HREF tag wrapped around the title */ - protected function get_links($app, $id, $only_app='', $exclude = array(), $style = 'title') + protected function get_links($app, $id, $only_app = '', $exclude = array(), $style = 'title') { $links = Api\Link::get_links($app, $id, $only_app); $link_titles = array(); @@ -425,34 +452,40 @@ abstract class Merge if(!is_array($link_info) && $only_app && $only_app[0] !== '!') { $link_info = array( - 'app' => $only_app, - 'id' => $link_info + 'app' => $only_app, + 'id' => $link_info ); } - if($exclude && in_array($link_info['id'], $exclude)) continue; + if($exclude && in_array($link_info['id'], $exclude)) + { + continue; + } $title = Api\Link::title($link_info['app'], $link_info['id']); - + if($style == 'href' || $style == 'link') { $link = Api\Link::view($link_info['app'], $link_info['id'], $link_info); if($link_info['app'] != Api\Link::VFS_APPNAME) { // Set app to false so we always get an external link - $link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php',$link, false)); + $link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php', $link, false)); } else { $link = Api\Framework::link($link, array()); } // Prepend site - if ($link[0] == '/') $link = Api\Framework::getUrl($link); + if($link[0] == '/') + { + $link = Api\Framework::getUrl($link); + } $title = $style == 'href' ? Api\Html::a_href(Api\Html::htmlspecialchars($title), $link) : $link; } $link_titles[] = $title; } - return implode("\n",$link_titles); + return implode("\n", $link_titles); } /** @@ -469,7 +502,7 @@ abstract class Merge { $array = array(); $pattern = '@\$\$(links_attachments|links|attachments|link)\/?(title|href|link)?\/?([a-z]*)\$\$@'; - static $link_cache=null; + static $link_cache = null; $matches = null; if(preg_match_all($pattern, $content, $matches)) { @@ -495,38 +528,44 @@ abstract class Merge if($app != Api\Link::VFS_APPNAME) { // Set app to false so we always get an external link - $link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php',$link, false)); + $link = str_replace(',', '%2C', $GLOBALS['egw']->framework->link('/index.php', $link, false)); } else { $link = Api\Framework::link($link, array()); } // Prepend site - if ($link[0] == '/') $link = Api\Framework::getUrl($link); + if($link[0] == '/') + { + $link = Api\Framework::getUrl($link); + } // Formatting if($matches[2][$i] == 'title') { $link = $title; } - else if($matches[2][$i] == 'href') + else { - // Turn on HTML style parsing or the link will be escaped - $this->parse_html_styles = true; - $link = Api\Html::a_href(Api\Html::htmlspecialchars($title), $link); + if($matches[2][$i] == 'href') + { + // Turn on HTML style parsing or the link will be escaped + $this->parse_html_styles = true; + $link = Api\Html::a_href(Api\Html::htmlspecialchars($title), $link); + } } - $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $link; + $array['$$' . ($prefix ? $prefix . '/' : '') . $placeholder . '$$'] = $link; break; case 'links': - $link_app = $matches[3][$i] ? $matches[3][$i] : '!'.Api\Link::VFS_APPNAME; - $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $this->get_links($app, $id, $link_app, array(),$matches[2][$i]); + $link_app = $matches[3][$i] ? $matches[3][$i] : '!' . Api\Link::VFS_APPNAME; + $array['$$' . ($prefix ? $prefix . '/' : '') . $placeholder . '$$'] = $this->get_links($app, $id, $link_app, array(), $matches[2][$i]); break; case 'attachments': - $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $this->get_links($app, $id, Api\Link::VFS_APPNAME,array(),$matches[2][$i]); + $array['$$' . ($prefix ? $prefix . '/' : '') . $placeholder . '$$'] = $this->get_links($app, $id, Api\Link::VFS_APPNAME, array(), $matches[2][$i]); break; default: - $array['$$'.($prefix?$prefix.'/':'').$placeholder.'$$'] = $this->get_links($app, $id, $matches[3][$i], array(), $matches[2][$i]); + $array['$$' . ($prefix ? $prefix . '/' : '') . $placeholder . '$$'] = $this->get_links($app, $id, $matches[3][$i], array(), $matches[2][$i]); break; } $link_cache[$id][$placeholder] = $array[$placeholder]; @@ -553,7 +592,7 @@ abstract class Merge if(!$GLOBALS['egw_info']['user']['apps']['stylite']) { - $replacements['$$'.$prefix.'share$$'] = lang('EPL Only'); + $replacements['$$' . $prefix . 'share$$'] = lang('EPL Only'); return $replacements; } @@ -562,7 +601,7 @@ abstract class Merge if($share) { - $replacements['$$'.$prefix.'share$$'] = $link = Api\Sharing::share2link($share); + $replacements['$$' . $prefix . 'share$$'] = $link = Api\Sharing::share2link($share); } return $replacements; @@ -589,7 +628,8 @@ abstract class Merge // Need to create the share here. // No way to know here if it should be writable, or who it's going to - $mode = /* ? ? Sharing::WRITABLE :*/ Api\Sharing::READONLY; + $mode = /* ? ? Sharing::WRITABLE :*/ + Api\Sharing::READONLY; $recipients = array(); $extra = array(); @@ -603,15 +643,18 @@ abstract class Merge * * @param int|string|DateTime $time unix timestamp or Y-m-d H:i:s string (in user time!) * @param string $format =null format string, default $this->datetime_format - * @deprecated use Api\DateTime::to($time='now',$format='') * @return string + * @deprecated use Api\DateTime::to($time='now',$format='') */ - protected function format_datetime($time,$format=null) + protected function format_datetime($time, $format = null) { trigger_error(__METHOD__ . ' is deprecated, use Api\DateTime::to($time, $format)', E_USER_DEPRECATED); - if (is_null($format)) $format = $this->datetime_format; + if(is_null($format)) + { + $format = $this->datetime_format; + } - return Api\DateTime::to($time,$format); + return Api\DateTime::to($time, $format); } /** @@ -623,19 +666,19 @@ abstract class Merge */ public static function is_export_limit_excepted() { - static $is_excepted=null; + static $is_excepted = null; - if (is_null($is_excepted)) + if(is_null($is_excepted)) { $is_excepted = isset($GLOBALS['egw_info']['user']['apps']['admin']); // check export-limit and fail if user tries to export more entries then allowed - if (!$is_excepted && (is_array($export_limit_excepted = $GLOBALS['egw_info']['server']['export_limit_excepted']) || - is_array($export_limit_excepted = unserialize($export_limit_excepted)))) + if(!$is_excepted && (is_array($export_limit_excepted = $GLOBALS['egw_info']['server']['export_limit_excepted']) || + is_array($export_limit_excepted = unserialize($export_limit_excepted)))) { - $id_and_memberships = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'],true); + $id_and_memberships = $GLOBALS['egw']->accounts->memberships($GLOBALS['egw_info']['user']['account_id'], true); $id_and_memberships[] = $GLOBALS['egw_info']['user']['account_id']; - $is_excepted = (bool) array_intersect($id_and_memberships, $export_limit_excepted); + $is_excepted = (bool)array_intersect($id_and_memberships, $export_limit_excepted); } } return $is_excepted; @@ -646,30 +689,36 @@ abstract class Merge * * @param string $app ='common' checks and validates app_limit, if not set returns the global limit * @return mixed - no if no export is allowed, false if there is no restriction and int as there is a valid restriction - * you may have to cast the returned value to int, if you want to use it as number + * you may have to cast the returned value to int, if you want to use it as number */ - public static function getExportLimit($app='common') + public static function getExportLimit($app = 'common') { - static $exportLimitStore=array(); - if (empty($app)) $app='common'; + static $exportLimitStore = array(); + if(empty($app)) + { + $app = 'common'; + } //error_log(__METHOD__.__LINE__.' called with app:'.$app); - if (!array_key_exists($app,$exportLimitStore)) + if(!array_key_exists($app, $exportLimitStore)) { //error_log(__METHOD__.__LINE__.' -> '.$app_limit.' '.function_backtrace()); $exportLimitStore[$app] = $GLOBALS['egw_info']['server']['export_limit']; - if ($app !='common') + if($app != 'common') { - $app_limit = Api\Hooks::single('export_limit',$app); - if ($app_limit) $exportLimitStore[$app] = $app_limit; + $app_limit = Api\Hooks::single('export_limit', $app); + if($app_limit) + { + $exportLimitStore[$app] = $app_limit; + } } //error_log(__METHOD__.__LINE__.' building cache for app:'.$app.' -> '.$exportLimitStore[$app]); - if (empty($exportLimitStore[$app])) + if(empty($exportLimitStore[$app])) { $exportLimitStore[$app] = false; return false; } - if (is_numeric($exportLimitStore[$app])) + if(is_numeric($exportLimitStore[$app])) { $exportLimitStore[$app] = (int)$exportLimitStore[$app]; } @@ -691,12 +740,24 @@ abstract class Merge * * @return bool - true if no export is allowed or a limit is set, false if there is no restriction */ - public static function hasExportLimit($app_limit,$checkas='AND') + public static function hasExportLimit($app_limit, $checkas = 'AND') { - if (strtoupper($checkas) == 'ISALLOWED') return (empty($app_limit) || ($app_limit !='no' && $app_limit > 0) ); - if (empty($app_limit)) return false; - if ($app_limit == 'no') return true; - if ($app_limit > 0) return true; + if(strtoupper($checkas) == 'ISALLOWED') + { + return (empty($app_limit) || ($app_limit != 'no' && $app_limit > 0)); + } + if(empty($app_limit)) + { + return false; + } + if($app_limit == 'no') + { + return true; + } + if($app_limit > 0) + { + return true; + } } /** @@ -709,31 +770,34 @@ abstract class Merge * @param array $fix =null regular expression => replacement pairs eg. to fix garbled placeholders * @return string|boolean merged document or false on error */ - public function &merge($document,$ids,&$err,$mimetype,array $fix=null) + public function &merge($document, $ids, &$err, $mimetype, array $fix = null) { - if (!($content = file_get_contents($document))) + if(!($content = file_get_contents($document))) { - $err = lang("Document '%1' does not exist or is not readable for you!",$document); + $err = lang("Document '%1' does not exist or is not readable for you!", $document); $ret = false; return $ret; } - if (self::hasExportLimit($this->export_limit) && !self::is_export_limit_excepted() && count($ids) > (int)$this->export_limit) + if(self::hasExportLimit($this->export_limit) && !self::is_export_limit_excepted() && count($ids) > (int)$this->export_limit) { - $err = lang('No rights to export more than %1 entries!',(int)$this->export_limit); + $err = lang('No rights to export more than %1 entries!', (int)$this->export_limit); $ret = false; return $ret; } // fix application/msword mimetype for rtf files - if ($mimetype == 'application/msword' && strtolower(substr($document,-4)) == '.rtf') + if($mimetype == 'application/msword' && strtolower(substr($document, -4)) == '.rtf') { $mimetype = 'application/rtf'; } - try { - $content = $this->merge_string($content,$ids,$err,$mimetype,$fix); - } catch (\Exception $e) { + try + { + $content = $this->merge_string($content, $ids, $err, $mimetype, $fix); + } + catch (\Exception $e) + { _egw_log_exception($e); $err = $e->getMessage(); $ret = false; @@ -742,51 +806,51 @@ abstract class Merge return $content; } - protected function apply_styles (&$content, $mimetype, $mso_application_progid=null) + protected function apply_styles(&$content, $mimetype, $mso_application_progid = null) { - if (!isset($mso_application_progid)) + if(!isset($mso_application_progid)) { $matches = null; $mso_application_progid = $mimetype == 'application/xml' && - preg_match('/'.preg_quote('', '/').'/',substr($content,0,200),$matches) ? - $matches[1] : ''; + preg_match('/' . preg_quote('', '/') . '/', substr($content, 0, 200), $matches) ? + $matches[1] : ''; } // Tags we can replace with the target document's version $replace_tags = array(); - switch($mimetype.$mso_application_progid) + switch($mimetype . $mso_application_progid) { - case 'application/vnd.oasis.opendocument.text': // oo text - case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet + case 'application/vnd.oasis.opendocument.text': // oo text + case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet case 'application/vnd.oasis.opendocument.presentation': case 'application/vnd.oasis.opendocument.text-template': case 'application/vnd.oasis.opendocument.spreadsheet-template': case 'application/vnd.oasis.opendocument.presentation-template': $doc = new DOMDocument(); $xslt = new XSLTProcessor(); - $doc->load(EGW_INCLUDE_ROOT.'/api/templates/default/Merge/openoffice.xslt'); + $doc->load(EGW_INCLUDE_ROOT . '/api/templates/default/Merge/openoffice.xslt'); $xslt->importStyleSheet($doc); //echo $content;die(); break; - case 'application/xmlWord.Document': // Word 2003*/ - case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 + case 'application/xmlWord.Document': // Word 2003*/ + case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 case 'application/vnd.ms-word.document.macroenabled.12': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': case 'application/vnd.ms-excel.sheet.macroenabled.12': // It seems easier to split the parent tags here $replace_tags = array( // Tables, lists don't go inside - '/<(ol|ul|table)( [^>]*)?>/' => '<$1$2>', - '/<\/(ol|ul|table)>/' => '', + '/<(ol|ul|table)( [^>]*)?>/' => '<$1$2>', + '/<\/(ol|ul|table)>/' => '', // Fix for things other than text (newlines) inside table row '/<(td)( [^>]*)?>((?!))(.*?)<\/td>[\s]*?/' => '<$1$2>$4', // Remove extra whitespace - '/]*?)>[^:print:]*?(.*?)<\/li>/' => '$2', // This doesn't get it all - '/[\s]+(.*?)<\/w:t>/' => '$1', + '/]*?)>[^:print:]*?(.*?)<\/li>/' => '$2', // This doesn't get it all + '/[\s]+(.*?)<\/w:t>/' => '$1', // Remove spans with no attributes, linebreaks inside them cause problems - '/(.*?)<\/span>/' => '$1' + '/(.*?)<\/span>/' => '$1' ); - $content = preg_replace(array_keys($replace_tags),array_values($replace_tags),$content); + $content = preg_replace(array_keys($replace_tags), array_values($replace_tags), $content); /* In the case where you have something like (invalid - mismatched tags), @@ -796,14 +860,15 @@ abstract class Merge $count = $i = 0; do { - $content = preg_replace('/(.*?)<\/span>/','$1',$content, -1, $count); + $content = preg_replace('/(.*?)<\/span>/', '$1', $content, -1, $count); $i++; - } while($count > 0 && $i < 10); + } + while($count > 0 && $i < 10); $doc = new DOMDocument(); $xslt = new XSLTProcessor(); $xslt_file = $mimetype == 'application/xml' ? 'wordml.xslt' : 'msoffice.xslt'; - $doc->load(EGW_INCLUDE_ROOT.'/api/templates/default/Merge/'.$xslt_file); + $doc->load(EGW_INCLUDE_ROOT . '/api/templates/default/Merge/' . $xslt_file); $xslt->importStyleSheet($doc); break; } @@ -822,8 +887,9 @@ abstract class Merge $content = $xslt->transformToXml($element); //echo $content;die(); // Word 2003 needs two declarations, add extra declaration back in - if($mimetype == 'application/xml' && $mso_application_progid == 'Word.Document' && strpos($content, ''.$content; + if($mimetype == 'application/xml' && $mso_application_progid == 'Word.Document' && strpos($content, '' . $content; } // Validate /* @@ -845,12 +911,12 @@ abstract class Merge * @param string $charset =null charset to override default set by mimetype or export charset * @return string|boolean merged document or false on error */ - public function &merge_string($_content,$ids,&$err,$mimetype,array $fix=null,$charset=null) + public function &merge_string($_content, $ids, &$err, $mimetype, array $fix = null, $charset = null) { $ids = empty($ids) ? [] : (array)$ids; $matches = null; - if ($mimetype == 'application/xml' && - preg_match('/'.preg_quote('', '/').'/',substr($_content,0,200),$matches)) + if($mimetype == 'application/xml' && + preg_match('/' . preg_quote('', '/') . '/', substr($_content, 0, 200), $matches)) { $mso_application_progid = $matches[1]; } @@ -860,33 +926,38 @@ abstract class Merge } // alternative syntax using double curly brackets (eg. {{cat_id}} instead $$cat_id$$), // agressivly removing all xml-tags eg. Word adds within placeholders - $content = preg_replace_callback('/{{[^}]+}}/i', function($matches) + $content = preg_replace_callback('/{{[^}]+}}/i', function ($matches) { - return '$$'.strip_tags(substr($matches[0], 2, -2)).'$$'; - }, $_content); + return '$$' . strip_tags(substr($matches[0], 2, -2)) . '$$'; + }, $_content); // Handle escaped placeholder markers in RTF, they won't match when escaped if($mimetype == 'application/rtf') { - $content = preg_replace('/\\\{\\\{([^\\}]+)\\\}\\\}/i','$$\1$$',$content); + $content = preg_replace('/\\\{\\\{([^\\}]+)\\\}\\\}/i', '$$\1$$', $content); } // make currently processed mimetype available to class methods; $this->mimetype = $mimetype; // fix garbled placeholders - if ($fix && is_array($fix)) + if($fix && is_array($fix)) { - $content = preg_replace(array_keys($fix),array_values($fix),$content); + $content = preg_replace(array_keys($fix), array_values($fix), $content); //die("
".htmlspecialchars($content)."
\n"); } - list($contentstart,$contentrepeat,$contentend) = preg_split('/\$\$pagerepeat\$\$/',$content,-1, PREG_SPLIT_NO_EMPTY)+[null,null,null]; //get differt parts of document, seperatet by Pagerepeat - if ($mimetype == 'text/plain' && $ids && count($ids) > 1) + list($contentstart, $contentrepeat, $contentend) = preg_split('/\$\$pagerepeat\$\$/', $content, -1, PREG_SPLIT_NO_EMPTY) + [null, + null, + null]; //get differt parts of document, seperatet by Pagerepeat + if($mimetype == 'text/plain' && $ids && count($ids) > 1) { // textdocuments are simple, they do not hold start and end, but they may have content before and after the $$pagerepeat$$ tag // header and footer should not hold any $$ tags; if we find $$ tags with the header, we assume it is the pagerepeatcontent $nohead = false; - if (stripos($contentstart,'$$') !== false) $nohead = true; - if ($nohead) + if(stripos($contentstart, '$$') !== false) + { + $nohead = true; + } + if($nohead) { $contentend = $contentrepeat; $contentrepeat = $contentstart; @@ -894,51 +965,58 @@ abstract class Merge } } - if (in_array($mimetype, array('application/vnd.oasis.opendocument.text','application/vnd.oasis.opendocument.text-template')) && count($ids) > 1) + if(in_array($mimetype, array('application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.text-template')) && count($ids) > 1) { if(strpos($content, '$$pagerepeat') === false) { //for odt files we have to split the content and add a style for page break to the style area - list($contentstart,$contentrepeat,$contentend) = preg_split('/office:body>/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat - $contentstart = substr($contentstart,0,strlen($contentstart)-1); //remove "<" - $contentrepeat = substr($contentrepeat,0,strlen($contentrepeat)-2); //remove "/', $content, -1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat + $contentstart = substr($contentstart, 0, strlen($contentstart) - 1); //remove "<" + $contentrepeat = substr($contentrepeat, 0, strlen($contentrepeat) - 2); //remove "/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document style sheets - $contentstart = $stylestart.''; + list($stylestart, $stylerepeat, $styleend) = preg_split('/<\/office:automatic-styles>/', $content, -1, PREG_SPLIT_NO_EMPTY); //get differt parts of document style sheets + $contentstart = $stylestart . ''; $contentstart .= ''; $contentend = ''; } else { // Template specifies where to repeat - list($contentstart,$contentrepeat,$contentend) = preg_split('/\$\$pagerepeat\$\$/',$content,-1, PREG_SPLIT_NO_EMPTY); //get different parts of document, seperated by pagerepeat + list($contentstart, $contentrepeat, $contentend) = preg_split('/\$\$pagerepeat\$\$/', $content, -1, PREG_SPLIT_NO_EMPTY); //get different parts of document, seperated by pagerepeat } } - if (in_array($mimetype, array('application/vnd.ms-word.document.macroenabled.12', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')) && count($ids) > 1) + if(in_array($mimetype, array('application/vnd.ms-word.document.macroenabled.12', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')) && count($ids) > 1) { //for Word 2007 XML files we have to split the content and add a style for page break to the style area - list($contentstart,$contentrepeat,$contentend) = preg_split('/w:body>/',$content,-1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat - $contentstart = substr($contentstart,0,strlen($contentstart)-1); //remove "/', $content, -1, PREG_SPLIT_NO_EMPTY); //get differt parts of document, seperatet by Pagerepeat + $contentstart = substr($contentstart, 0, strlen($contentstart) - 1); //remove "'; $contentend = ''; } - list($Labelstart,$Labelrepeat,$Labeltend) = preg_split('/\$\$label\$\$/',$contentrepeat,-1, PREG_SPLIT_NO_EMPTY)+[null,null,null]; //get the label content - preg_match_all('/\$\$labelplacement\$\$/',$contentrepeat,$countlables, PREG_SPLIT_NO_EMPTY); + list($Labelstart, $Labelrepeat, $Labeltend) = preg_split('/\$\$label\$\$/', $contentrepeat, -1, PREG_SPLIT_NO_EMPTY) + [null, + null, + null]; //get the label content + preg_match_all('/\$\$labelplacement\$\$/', $contentrepeat, $countlables, PREG_SPLIT_NO_EMPTY); $countlables = count($countlables[0]); - preg_replace('/\$\$labelplacement\$\$/','',$Labelrepeat,1); + preg_replace('/\$\$labelplacement\$\$/', '', $Labelrepeat, 1); $lableprint = $countlables > 1; - if (count($ids) > 1 && !$contentrepeat) + if(count($ids) > 1 && !$contentrepeat) { $err = lang('for more than one contact in a document use the tag pagerepeat!'); $ret = false; return $ret; } - if ($this->report_memory_usage) error_log(__METHOD__."(count(ids)=".count($ids).") strlen(contentrepeat)=".strlen($contentrepeat).', strlen(labelrepeat)='.strlen($Labelrepeat)); - - if ($contentrepeat) + if($this->report_memory_usage) { - $content_stream = fopen('php://temp','r+'); + error_log(__METHOD__ . "(count(ids)=" . count($ids) . ") strlen(contentrepeat)=" . strlen($contentrepeat) . ', strlen(labelrepeat)=' . strlen($Labelrepeat)); + } + + if($contentrepeat) + { + $content_stream = fopen('php://temp', 'r+'); fwrite($content_stream, $contentstart); $joiner = ''; switch($mimetype) @@ -947,8 +1025,8 @@ abstract class Merge case 'text/rtf': $joiner = '\\par \\page\\pard\\plain'; break; - case 'application/vnd.oasis.opendocument.text': // oo text - case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet + case 'application/vnd.oasis.opendocument.text': // oo text + case 'application/vnd.oasis.opendocument.spreadsheet': // oo spreadsheet case 'application/vnd.oasis.opendocument.presentation': case 'application/vnd.oasis.opendocument.text-template': case 'application/vnd.oasis.opendocument.spreadsheet-template': @@ -968,20 +1046,26 @@ abstract class Merge $joiner = "\r\n"; break; default: - $err = lang('%1 not implemented for %2!','$$pagerepeat$$',$mimetype); + $err = lang('%1 not implemented for %2!', '$$pagerepeat$$', $mimetype); $ret = false; return $ret; } } - foreach ((array)$ids as $n => $id) + foreach((array)$ids as $n => $id) { - if ($contentrepeat) $content = $contentrepeat; //content to repeat - if ($lableprint) $content = $Labelrepeat; + if($contentrepeat) + { + $content = $contentrepeat; + } //content to repeat + if($lableprint) + { + $content = $Labelrepeat; + } // generate replacements; if exception is thrown, catch it set error message and return false try { - if(!($replacements = $this->get_replacements($id,$content))) + if(!($replacements = $this->get_replacements($id, $content))) { $err = lang('Entry not found!'); $ret = false; @@ -995,114 +1079,120 @@ abstract class Merge $ret = false; return $ret; } - if ($this->report_memory_usage) error_log(__METHOD__."() $n: $id ".Api\Vfs::hsize(memory_get_usage(true))); + if($this->report_memory_usage) + { + error_log(__METHOD__ . "() $n: $id " . Api\Vfs::hsize(memory_get_usage(true))); + } // some general replacements: current user, date and time if(strpos($content, '$$user/') !== false && ($user = $GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'], 'person_id'))) { $replacements += $this->contact_replacements($user, 'user', false, $content); $replacements['$$user/primary_group$$'] = $GLOBALS['egw']->accounts->id2name($GLOBALS['egw']->accounts->id2name($GLOBALS['egw_info']['user']['account_id'], 'account_primary_group')); } - $replacements['$$date$$'] = Api\DateTime::to('now',true); + $replacements['$$date$$'] = Api\DateTime::to('now', true); $replacements['$$datetime$$'] = Api\DateTime::to('now'); - $replacements['$$time$$'] = Api\DateTime::to('now',false); + $replacements['$$time$$'] = Api\DateTime::to('now', false); $app = $this->get_app(); $replacements += $this->share_placeholder($app, $id, '', $content); // does our extending class registered table-plugins AND document contains table tags - if ($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s',$content,$matches,PREG_SET_ORDER)) + if($this->table_plugins && preg_match_all('/\\$\\$table\\/([A-Za-z0-9_]+)\\$\\$(.*?)\\$\\$endtable\\$\\$/s', $content, $matches, PREG_SET_ORDER)) { // process each table foreach($matches as $match) { - $plugin = $match[1]; // plugin name + $plugin = $match[1]; // plugin name $callback = $this->table_plugins[$plugin]; - $repeat = $match[2]; // line to repeat + $repeat = $match[2]; // line to repeat $repeats = ''; - if (isset($callback)) + if(isset($callback)) { - for($n = 0; ($row_replacements = $this->$callback($plugin,$id,$n,$repeat)); ++$n) + for($n = 0; ($row_replacements = $this->$callback($plugin, $id, $n, $repeat)); ++$n) { $_repeat = $this->process_commands($repeat, $row_replacements); - $repeats .= $this->replace($_repeat,$row_replacements,$mimetype,$mso_application_progid); + $repeats .= $this->replace($_repeat, $row_replacements, $mimetype, $mso_application_progid); } } - $content = str_replace($match[0],$repeats,$content); + $content = str_replace($match[0], $repeats, $content); } } - $content = $this->process_commands($this->replace($content,$replacements,$mimetype,$mso_application_progid,$charset), $replacements); + $content = $this->process_commands($this->replace($content, $replacements, $mimetype, $mso_application_progid, $charset), $replacements); // remove not existing replacements (eg. from calendar array) - if (strpos($content,'$$') !== null) + if(strpos($content, '$$') !== null) { - $content = preg_replace('/\$\$[a-z0-9_\/]+\$\$/i','',$content); + $content = preg_replace('/\$\$[a-z0-9_\/]+\$\$/i', '', $content); } - if ($contentrepeat) + if($contentrepeat) { fwrite($content_stream, ($n == 0 ? '' : $joiner) . $content); } if($lableprint) { - $contentrep[is_array($id) ? implode(':',$id) : $id] = $content; + $contentrep[is_array($id) ? implode(':', $id) : $id] = $content; } } - if ($Labelrepeat) + if($Labelrepeat) { - $countpage=0; - $count=0; - $contentrepeatpages[$countpage] = $Labelstart.$Labeltend; + $countpage = 0; + $count = 0; + $contentrepeatpages[$countpage] = $Labelstart . $Labeltend; - foreach ($contentrep as $Label) + foreach($contentrep as $Label) { - $contentrepeatpages[$countpage] = preg_replace('/\$\$labelplacement\$\$/',$Label,$contentrepeatpages[$countpage],1); - $count=$count+1; - if (($count % $countlables) == 0 && count($contentrep)>$count) //new page + $contentrepeatpages[$countpage] = preg_replace('/\$\$labelplacement\$\$/', $Label, $contentrepeatpages[$countpage], 1); + $count = $count + 1; + if(($count % $countlables) == 0 && count($contentrep) > $count) //new page { - $countpage = $countpage+1; - $contentrepeatpages[$countpage] = $Labelstart.$Labeltend; + $countpage = $countpage + 1; + $contentrepeatpages[$countpage] = $Labelstart . $Labeltend; } } - $contentrepeatpages[$countpage] = preg_replace('/\$\$labelplacement\$\$/','',$contentrepeatpages[$countpage],-1); //clean empty fields + $contentrepeatpages[$countpage] = preg_replace('/\$\$labelplacement\$\$/', '', $contentrepeatpages[$countpage], -1); //clean empty fields switch($mimetype) { case 'application/rtf': case 'text/rtf': - $ret = $contentstart.implode('\\par \\page\\pard\\plain',$contentrepeatpages).$contentend; + $ret = $contentstart . implode('\\par \\page\\pard\\plain', $contentrepeatpages) . $contentend; break; case 'application/vnd.oasis.opendocument.text': case 'application/vnd.oasis.opendocument.presentation': case 'application/vnd.oasis.opendocument.text-template': case 'application/vnd.oasis.opendocument.presentation-template': - $ret = $contentstart.implode('',$contentrepeatpages).$contentend; + $ret = $contentstart . implode('', $contentrepeatpages) . $contentend; break; case 'application/vnd.oasis.opendocument.spreadsheet': case 'application/vnd.oasis.opendocument.spreadsheet-template': - $ret = $contentstart.implode('',$contentrepeatpages).$contentend; + $ret = $contentstart . implode('', $contentrepeatpages) . $contentend; break; case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': case 'application/vnd.ms-word.document.macroenabled.12': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': case 'application/vnd.ms-excel.sheet.macroenabled.12': - $ret = $contentstart.implode('',$contentrepeatpages).$contentend; + $ret = $contentstart . implode('', $contentrepeatpages) . $contentend; break; case 'text/plain': - $ret = $contentstart.implode("\r\n",$contentrep).$contentend; + $ret = $contentstart . implode("\r\n", $contentrep) . $contentend; break; default: - $err = lang('%1 not implemented for %2!','$$labelplacement$$',$mimetype); + $err = lang('%1 not implemented for %2!', '$$labelplacement$$', $mimetype); $ret = false; } return $ret; } - if ($contentrepeat) + if($contentrepeat) { fwrite($content_stream, $contentend); rewind($content_stream); $content = stream_get_contents($content_stream); } - if ($this->report_memory_usage) error_log(__METHOD__."() returning ".Api\Vfs::hsize(memory_get_peak_usage(true))); + if($this->report_memory_usage) + { + error_log(__METHOD__ . "() returning " . Api\Vfs::hsize(memory_get_peak_usage(true))); + } return $content; } @@ -1117,54 +1207,57 @@ abstract class Merge * @param string $charset =null charset to override default set by mimetype or export charset * @return string */ - protected function replace($content,array $replacements,$mimetype,$mso_application_progid='',$charset=null) + protected function replace($content, array $replacements, $mimetype, $mso_application_progid = '', $charset = null) { switch($mimetype) { - case 'application/vnd.oasis.opendocument.text': // open office + case 'application/vnd.oasis.opendocument.text': // open office case 'application/vnd.oasis.opendocument.spreadsheet': case 'application/vnd.oasis.opendocument.presentation': case 'application/vnd.oasis.opendocument.text-template': case 'application/vnd.oasis.opendocument.spreadsheet-template': case 'application/vnd.oasis.opendocument.presentation-template': - case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 + case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': // ms office 2007 case 'application/vnd.ms-word.document.macroenabled.12': case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': case 'application/vnd.ms-excel.sheet.macroenabled.12': case 'application/xml': case 'text/xml': $is_xml = true; - $charset = 'utf-8'; // xml files --> always use utf-8 + $charset = 'utf-8'; // xml files --> always use utf-8 break; case 'application/rtf': case 'text/rtf': - $charset = 'iso-8859-1'; // rtf seems to user iso-8859-1 or equivalent windows charset, not utf-8 + $charset = 'iso-8859-1'; // rtf seems to user iso-8859-1 or equivalent windows charset, not utf-8 break; case 'text/html': $is_xml = true; $matches = null; - if (preg_match('/ use our export-charset, defined in addressbook prefs - if (empty($charset)) $charset = $this->contacts->prefs['csv_charset']; + default: // div. text files --> use our export-charset, defined in addressbook prefs + if(empty($charset)) + { + $charset = $this->contacts->prefs['csv_charset']; + } break; } //error_log(__METHOD__."('$document', ... ,$mimetype) --> $charset (egw=".Api\Translation::charset().', export='.$this->contacts->prefs['csv_charset'].')'); // do we need to convert charset - if ($charset && $charset != Api\Translation::charset()) + if($charset && $charset != Api\Translation::charset()) { - $replacements = Api\Translation::convert($replacements,Api\Translation::charset(),$charset); + $replacements = Api\Translation::convert($replacements, Api\Translation::charset(), $charset); } // Date only placeholders for timestamps @@ -1172,14 +1265,14 @@ abstract class Merge { foreach($this->date_fields as $field) { - if(($value = $replacements['$$'.$field.'$$'] ?? null)) + if(($value = $replacements['$$' . $field . '$$'] ?? null)) { - $time = Api\DateTime::createFromFormat('+'.Api\DateTime::$user_dateformat.' '.Api\DateTime::$user_timeformat.'*', $value); - $replacements['$$'.$field.'/date$$'] = $time ? $time->format(Api\DateTime::$user_dateformat) : ''; + $time = Api\DateTime::createFromFormat('+' . Api\DateTime::$user_dateformat . ' ' . Api\DateTime::$user_timeformat . '*', $value); + $replacements['$$' . $field . '/date$$'] = $time ? $time->format(Api\DateTime::$user_dateformat) : ''; } } } - if ($is_xml) // zip'ed xml document (eg. OO) + if($is_xml) // zip'ed xml document (eg. OO) { // Numeric fields $names = array(); @@ -1187,35 +1280,35 @@ abstract class Merge // Tags we can replace with the target document's version $replace_tags = array(); // only keep tags, if we have xsl extension available - if (class_exists('XSLTProcessor') && class_exists('DOMDocument') && $this->parse_html_styles) + if(class_exists('XSLTProcessor') && class_exists('DOMDocument') && $this->parse_html_styles) { - switch($mimetype.$mso_application_progid) + switch($mimetype . $mso_application_progid) { case 'text/html': $replace_tags = array( - '','','','','','','
    ','