diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ec53bf567..755ca4148 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -125,21 +125,11 @@ parameters: count: 1 path: program/actions/contacts/index.php - - - message: "#^Call to function is_object\\(\\) with rcube_result_set will always evaluate to true\\.$#" - count: 1 - path: program/actions/contacts/mailto.php - - message: "#^Access to an undefined property rcube_addressbook\\:\\:\\$deletable\\.$#" count: 1 path: program/actions/contacts/move.php - - - message: "#^Left side of && is always true\\.$#" - count: 1 - path: program/actions/contacts/photo.php - - message: "#^Right side of && is always true\\.$#" count: 1 @@ -155,11 +145,6 @@ parameters: count: 1 path: program/actions/contacts/save.php - - - message: "#^Right side of && is always true\\.$#" - count: 1 - path: program/actions/contacts/save.php - - message: "#^Implicit array creation is not allowed \\- variable \\$fields might not exist\\.$#" count: 1 @@ -175,11 +160,6 @@ parameters: count: 1 path: program/actions/mail/attachment_upload.php - - - message: "#^If condition is always true\\.$#" - count: 1 - path: program/actions/mail/autocomplete.php - - message: "#^Access to an undefined property rcube_message\\:\\:\\$size\\.$#" count: 1 @@ -525,76 +505,6 @@ parameters: count: 2 path: program/include/rcmail_sendmail.php - - - message: "#^Method rcmail_string_replacer\\:\\:mailto_callback\\(\\) should return int but returns string\\.$#" - count: 1 - path: program/include/rcmail_string_replacer.php - - - - message: "#^Return type \\(int\\) of method rcmail_string_replacer\\:\\:mailto_callback\\(\\) should be compatible with return type \\(string\\) of method rcube_string_replacer\\:\\:mailto_callback\\(\\)$#" - count: 1 - path: program/include/rcmail_string_replacer.php - - - - message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#" - count: 2 - path: program/lib/Roundcube/bootstrap.php - - - - message: "#^Call to function is_array\\(\\) with non\\-empty\\-array will always evaluate to true\\.$#" - count: 1 - path: program/lib/Roundcube/bootstrap.php - - - - message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" - count: 1 - path: program/lib/Roundcube/bootstrap.php - - - - message: "#^Function array_first\\(\\) should return mixed but return statement is missing\\.$#" - count: 1 - path: program/lib/Roundcube/bootstrap.php - - - - message: "#^Function parse_bytes\\(\\) never returns null so it can be removed from the return type\\.$#" - count: 1 - path: program/lib/Roundcube/bootstrap.php - - - - message: "#^Result of \\|\\| is always false\\.$#" - count: 1 - path: program/lib/Roundcube/bootstrap.php - - - - message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#" - count: 2 - path: program/lib/Roundcube/html.php - - - - message: "#^Call to function is_string\\(\\) with array will always evaluate to false\\.$#" - count: 2 - path: program/lib/Roundcube/html.php - - - - message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#" - count: 1 - path: program/lib/Roundcube/html.php - - - - message: "#^html_hiddenfield\\:\\:__construct\\(\\) does not call parent constructor from html\\.$#" - count: 1 - path: program/lib/Roundcube/html.php - - - - message: "#^html_inputfield\\:\\:__construct\\(\\) does not call parent constructor from html\\.$#" - count: 1 - path: program/lib/Roundcube/html.php - - - - message: "#^html_table\\:\\:__construct\\(\\) does not call parent constructor from html\\.$#" - count: 1 - path: program/lib/Roundcube/html.php - - message: "#^Access to an undefined property rcube\\:\\:\\$password\\.$#" count: 1 @@ -680,56 +590,6 @@ parameters: count: 1 path: program/lib/Roundcube/rcube.php - - - message: "#^Comparison operation \"\\>\" between int\\<1, max\\> and 0 is always true\\.$#" - count: 2 - path: program/lib/Roundcube/rcube_addressbook.php - - - - message: "#^Instanceof between rcube_result_set and rcube_result_set will always evaluate to true\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addressbook.php - - - - message: "#^Method rcube_addressbook\\:\\:insert\\(\\) should return mixed but return statement is missing\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addressbook.php - - - - message: "#^Method rcube_addressbook\\:\\:update\\(\\) should return mixed but return statement is missing\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addressbook.php - - - - message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#" - count: 2 - path: program/lib/Roundcube/rcube_addresses.php - - - - message: "#^Left side of && is always true\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addresses.php - - - - message: "#^Method rcube_addresses\\:\\:list_records\\(\\) should return array but returns rcube_result_set\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addresses.php - - - - message: "#^Return type \\(array\\) of method rcube_addresses\\:\\:list_records\\(\\) should be compatible with return type \\(rcube_result_set\\) of method rcube_contacts\\:\\:list_records\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_addresses.php - - - - message: "#^Right side of && is always true\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addresses.php - - - - message: "#^rcube_addresses\\:\\:__construct\\(\\) does not call parent constructor from rcube_contacts\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_addresses.php - - message: "#^Foreach overwrites \\$key with its value variable\\.$#" count: 1 @@ -755,46 +615,6 @@ parameters: count: 1 path: program/lib/Roundcube/rcube_charset.php - - - message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#" - count: 3 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^Foreach overwrites \\$value with its value variable\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^If condition is always true\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^Left side of && is always true\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^Parameter \\#1 \\$cols \\(array\\) of method rcube_contacts\\:\\:list_records\\(\\) should be contravariant with parameter \\$cols \\(array\\|null\\) of method rcube_addressbook\\:\\:list_records\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^Parameter \\#1 \\$filter \\(string\\) of method rcube_contacts\\:\\:set_search_set\\(\\) should be contravariant with parameter \\$filter \\(mixed\\) of method rcube_addressbook\\:\\:set_search_set\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^Parameter \\#1 \\$search \\(string\\) of method rcube_contacts\\:\\:list_groups\\(\\) should be contravariant with parameter \\$search \\(string\\|null\\) of method rcube_addressbook\\:\\:list_groups\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - - - message: "#^Return type \\(mixed\\) of method rcube_contacts\\:\\:get_result\\(\\) should be covariant with return type \\(rcube_result_set\\|null\\) of method rcube_addressbook\\:\\:get_result\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_contacts.php - - message: "#^Left side of && is always true\\.$#" count: 2 @@ -805,86 +625,6 @@ parameters: count: 1 path: program/lib/Roundcube/rcube_html2text.php - - - message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Call to function is_array\\(\\) with mixed will always evaluate to false\\.$#" - count: 2 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Method rcube_ldap\\:\\:rename_group\\(\\) should return bool but returns string\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Offset '%%dn' on non\\-empty\\-array in empty\\(\\) always exists and is not falsy\\.$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Parameter \\#1 \\$cols \\(array\\) of method rcube_ldap\\:\\:list_records\\(\\) should be contravariant with parameter \\$cols \\(array\\|null\\) of method rcube_addressbook\\:\\:list_records\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Parameter \\#1 \\$filter \\(string\\) of method rcube_ldap\\:\\:set_search_set\\(\\) should be contravariant with parameter \\$filter \\(mixed\\) of method rcube_addressbook\\:\\:set_search_set\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Parameter \\#1 \\$search \\(string\\) of method rcube_ldap\\:\\:list_groups\\(\\) should be contravariant with parameter \\$search \\(string\\|null\\) of method rcube_addressbook\\:\\:list_groups\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Parameter \\#1 \\$sort_col \\(string\\) of method rcube_ldap\\:\\:set_sort_order\\(\\) should be contravariant with parameter \\$sort_col \\(string\\|null\\) of method rcube_addressbook\\:\\:set_sort_order\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Parameter \\#2 \\$sort_order \\(string\\) of method rcube_ldap\\:\\:set_sort_order\\(\\) should be contravariant with parameter \\$sort_order \\(string\\|null\\) of method rcube_addressbook\\:\\:set_sort_order\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Parameter \\#6 \\$required \\(array\\) of method rcube_ldap\\:\\:search\\(\\) should be contravariant with parameter \\$required \\(array\\\\|string\\) of method rcube_addressbook\\:\\:search\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Result of && is always false\\.$#" - count: 2 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Return type \\(bool\\) of method rcube_ldap\\:\\:rename_group\\(\\) should be covariant with return type \\(string\\|false\\) of method rcube_addressbook\\:\\:rename_group\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Return type \\(bool\\|int\\) of method rcube_ldap\\:\\:delete\\(\\) should be covariant with return type \\(int\\|false\\) of method rcube_addressbook\\:\\:delete\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Return type \\(mixed\\) of method rcube_ldap\\:\\:create_group\\(\\) should be covariant with return type \\(array\\|false\\) of method rcube_addressbook\\:\\:create_group\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Return type \\(mixed\\) of method rcube_ldap\\:\\:get_record\\(\\) should be covariant with return type \\(array\\|rcube_result_set\\) of method rcube_addressbook\\:\\:get_record\\(\\)$#" - count: 1 - path: program/lib/Roundcube/rcube_ldap.php - - - - message: "#^Right side of && is always true\\.$#" - count: 3 - path: program/lib/Roundcube/rcube_ldap.php - - message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#" count: 1 diff --git a/program/actions/contacts/mailto.php b/program/actions/contacts/mailto.php index e19da5fca..6d044f08e 100644 --- a/program/actions/contacts/mailto.php +++ b/program/actions/contacts/mailto.php @@ -65,7 +65,7 @@ class rcmail_action_contacts_mailto extends rcmail_action_contacts_index } foreach ($sources as $source) { - while (is_object($source) && ($rec = $source->iterate())) { + foreach ($source as $rec) { $emails = rcube_addressbook::get_col_values('email', $rec, true); if (!empty($emails)) { diff --git a/program/actions/contacts/photo.php b/program/actions/contacts/photo.php index a1c8b516b..31b1f15ad 100644 --- a/program/actions/contacts/photo.php +++ b/program/actions/contacts/photo.php @@ -54,7 +54,7 @@ class rcmail_action_contacts_photo extends rcmail_action_contacts_index foreach ($rcmail->get_address_sources() as $s) { $abook = $rcmail->get_address_book($s['id']); $result = $abook->search(['email'], $email, 1, true, true, 'photo'); - while ($result && ($record = $result->iterate())) { + foreach ($result as $record) { if (!empty($record['photo'])) { break 2; } diff --git a/program/actions/contacts/save.php b/program/actions/contacts/save.php index da2a10661..44f85bf16 100644 --- a/program/actions/contacts/save.php +++ b/program/actions/contacts/save.php @@ -154,9 +154,12 @@ class rcmail_action_contacts_save extends rcmail_action_contacts_index // show notice if existing contacts with same e-mail are found foreach ($contacts->get_col_values('email', $a_record, true) as $email) { - if ($email && ($res = $contacts->search('email', $email, 1, false, true)) && $res->count) { - $rcmail->output->show_message('contactexists', 'notice', null, false); - break; + if ($email) { + $res = $contacts->search('email', $email, 1, false, true); + if ($res->count) { + $rcmail->output->show_message('contactexists', 'notice', null, false); + break; + } } } diff --git a/program/actions/mail/autocomplete.php b/program/actions/mail/autocomplete.php index 9d9c8e9a8..b28d267bd 100644 --- a/program/actions/mail/autocomplete.php +++ b/program/actions/mail/autocomplete.php @@ -49,9 +49,10 @@ class rcmail_action_mail_autocomplete extends rcmail_action foreach ($book_types as $abook_id) { $abook = $rcmail->get_address_book($abook_id); $abook->set_pagesize($MAXNUM); + $result = $abook->search($fields, $search, $mode, true, true, 'email'); - if ($result = $abook->search($fields, $search, $mode, true, true, 'email')) { - while ($record = $result->iterate()) { + if ($result->count) { + foreach ($result as $record) { // Contact can have more than one e-mail address $email_arr = (array) $abook->get_col_values('email', $record, true); $email_cnt = count($email_arr); diff --git a/program/include/rcmail_string_replacer.php b/program/include/rcmail_string_replacer.php index dab502942..708b8cd82 100644 --- a/program/include/rcmail_string_replacer.php +++ b/program/include/rcmail_string_replacer.php @@ -30,7 +30,7 @@ class rcmail_string_replacer extends rcube_string_replacer * * @param array $matches Matches result from preg_replace_callback * - * @return int Index of saved string value + * @return string Replacement string * * @see rcube_string_replacer::mailto_callback() */ diff --git a/program/lib/Roundcube/bootstrap.php b/program/lib/Roundcube/bootstrap.php index 2c68fb5ba..d4657924b 100644 --- a/program/lib/Roundcube/bootstrap.php +++ b/program/lib/Roundcube/bootstrap.php @@ -115,16 +115,12 @@ if (class_exists('PEAR')) { * Similar function as in_array() but case-insensitive with multibyte support. * * @param string $needle Needle value - * @param array $haystack Array to search in + * @param ?array $haystack Array to search in * * @return bool True if found, False if not */ function in_array_nocase($needle, $haystack) { - if (!is_string($needle) || !is_array($haystack)) { - return false; - } - // use much faster method for ascii if (is_ascii($needle)) { foreach ((array) $haystack as $value) { @@ -147,9 +143,9 @@ function in_array_nocase($needle, $haystack) /** * Parse a human readable string for a number of bytes. * - * @param string $str Input string + * @param string|int|float $str Input string * - * @return int|false|null Number of bytes + * @return int|false Number of bytes */ function parse_bytes($str) { @@ -200,7 +196,7 @@ function unslashify($str) /** * Returns number of seconds for a specified offset string. * - * @param string $str String representation of the offset (e.g. 20min, 5h, 2days, 1week) + * @param string|int $str String representation of the offset (e.g. 20min, 5h, 2days, 1week) * * @return int Number of seconds */ @@ -284,7 +280,8 @@ function array_keys_recursive($array) { $keys = []; - if (!empty($array) && is_array($array)) { + // @phpstan-ignore-next-line + if (is_array($array)) { foreach ($array as $key => $child) { $keys[] = $key; foreach (array_keys_recursive($child) as $val) { @@ -305,12 +302,15 @@ function array_keys_recursive($array) */ function array_first($array) { - if (is_array($array)) { + // @phpstan-ignore-next-line + if (is_array($array) && !empty($array)) { reset($array); foreach ($array as $element) { return $element; } } + + return null; } /** diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php index f15da76f6..5d222318c 100644 --- a/program/lib/Roundcube/html.php +++ b/program/lib/Roundcube/html.php @@ -40,6 +40,7 @@ class html */ public function __construct($attrib = []) { + // @phpstan-ignore-next-line if (is_array($attrib)) { $this->attrib = $attrib; } @@ -60,10 +61,10 @@ class html /** * Generic method to create a HTML tag * - * @param string $tagname Tag name - * @param array $attrib Tag attributes as key/value pairs - * @param string $content Optional Tag content (creates a container tag) - * @param array $allowed List with allowed attributes, omit to allow all + * @param string $tagname Tag name + * @param array|string $attrib Tag attributes as key/value pairs, or 'class' attribute value + * @param string $content Optional Tag content (creates a container tag) + * @param array $allowed List with allowed attributes, omit to allow all * * @return string The XHTML tag */ @@ -387,13 +388,8 @@ class html * * @return string The quoted string */ - public static function quote($str) + public static function quote(string $str) { - // PHP8 does not like e.g. an array as htmlspecialchars() argument - if (!is_string($str)) { - return (string) $str; - } - return @htmlspecialchars($str, \ENT_COMPAT | \ENT_SUBSTITUTE, RCUBE_CHARSET); } } @@ -419,9 +415,7 @@ class html_inputfield extends html */ public function __construct($attrib = []) { - if (is_array($attrib)) { - $this->attrib = $attrib; - } + parent::__construct($attrib); if (!empty($attrib['type'])) { $this->type = $attrib['type']; @@ -479,6 +473,8 @@ class html_hiddenfield extends html */ public function __construct($attrib = null) { + parent::__construct(); + if (is_array($attrib)) { $this->add($attrib); } @@ -710,8 +706,11 @@ class html_table extends html */ public function __construct($attrib = []) { - $default_attrib = self::$doctype == 'xhtml' ? ['border' => '0'] : []; - $this->attrib = array_merge($attrib, $default_attrib); + parent::__construct($attrib); + + if (self::$doctype == 'xhtml') { + $this->attrib['border'] = '0'; + } if (!empty($attrib['tagname']) && $attrib['tagname'] != 'table') { $this->tagname = $attrib['tagname']; @@ -722,8 +721,8 @@ class html_table extends html /** * Add a table cell * - * @param array $attr Cell attributes - * @param string $cont Cell content + * @param array|string $attr Cell attributes or 'class' attribute value + * @param string $cont Cell content */ public function add($attr, $cont) { diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index 2155dc421..0c0a94d22 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -259,7 +259,7 @@ abstract class rcube_addressbook * @param mixed $id Record identifier(s) * @param bool $assoc True to return record as associative array, otherwise a result set is returned * - * @return rcube_result_set|array Result object with all record fields + * @return rcube_result_set|array|null Result object with all record fields */ abstract public function get_record($id, $assoc = false); @@ -316,7 +316,7 @@ abstract class rcube_addressbook * @param ?string $sort_col Sort column * @param ?string $sort_order Sort order */ - public function set_sort_order($sort_col, $sort_order = null) + public function set_sort_order($sort_col = null, $sort_order = null) { if ($sort_col && (array_key_exists($sort_col, $this->coltypes) || in_array($sort_col, $this->coltypes))) { $this->sort_col = $sort_col; @@ -384,6 +384,7 @@ abstract class rcube_addressbook public function insert($save_data, $check = false) { // empty for read-only address books + return false; } /** @@ -397,6 +398,8 @@ abstract class rcube_addressbook public function insertMultiple($recset, $check = false) { $ids = []; + + // @phpstan-ignore-next-line if ($recset instanceof rcube_result_set) { foreach ($recset as $row) { if ($insert = $this->insert($row, $check)) { @@ -421,13 +424,14 @@ abstract class rcube_addressbook public function update($id, $save_cols) { // empty for read-only address books + return false; } /** * Mark one or more contact records as deleted * - * @param array $ids Record identifiers - * @param bool $force Remove records irreversible (see self::undelete) + * @param array|string $ids Record identifiers + * @param bool $force Remove records irreversible (see self::undelete) * * @return int|false Number of removed records, False on failure */ @@ -440,7 +444,7 @@ abstract class rcube_addressbook /** * Unmark delete flag on contact record(s) * - * @param array $ids Record identifiers + * @param array|string $ids Record identifiers */ public function undelete($ids) { @@ -621,7 +625,7 @@ abstract class rcube_addressbook // remove duplicates if ($flat && !empty($out)) { - $out = array_unique($out); + $out = array_values(array_unique($out)); } return $out; @@ -740,7 +744,7 @@ abstract class rcube_addressbook $fn = $org; } // ... email address - elseif (($email = self::get_col_values('email', $contact, true)) && count($email) > 0) { + elseif (($email = self::get_col_values('email', $contact, true)) && isset($email[0])) { $fn = $email[0]; } } @@ -827,7 +831,7 @@ abstract class rcube_addressbook $key = $contact[$sort_col] ?? null; // add email to a key to not skip contacts with the same name (#1488375) - if (($email = self::get_col_values('email', $contact, true)) && count($email) > 0) { + if (($email = self::get_col_values('email', $contact, true)) && isset($email[0])) { $key .= ':' . implode(':', (array) $email); } diff --git a/program/lib/Roundcube/rcube_addresses.php b/program/lib/Roundcube/rcube_addresses.php index 46815a01a..e56e62e4c 100644 --- a/program/lib/Roundcube/rcube_addresses.php +++ b/program/lib/Roundcube/rcube_addresses.php @@ -45,10 +45,9 @@ class rcube_addresses extends rcube_contacts */ public function __construct($dbconn, $user, $type) { - $this->db = $dbconn; - $this->user_id = $user; + parent::__construct($dbconn, $user); + $this->type = $type; - $this->ready = $this->db && !$this->db->is_error(); } /** @@ -72,11 +71,11 @@ class rcube_addresses extends rcube_contacts /** * List the current set of contact records * - * @param array $cols List of cols to show, Null means all - * @param int $subset Only return this number of records, use negative values for tail - * @param bool $nocount True to skip the count query (select only) + * @param ?array $cols List of cols to show, Null means all + * @param int $subset Only return this number of records, use negative values for tail + * @param bool $nocount True to skip the count query (select only) * - * @return array Indexed list of contact records, each a hash array + * @return rcube_result_set Indexed list of contact records, each a hash array */ public function list_records($cols = null, $subset = 0, $nocount = false) { @@ -241,7 +240,7 @@ class rcube_addresses extends rcube_contacts * @param mixed $id Record identifier(s) * @param bool $assoc Enables returning associative array * - * @return rcube_result_set|array Result object with all record fields + * @return rcube_result_set|array|null Result object with all record fields */ public function get_record($id, $assoc = false) { @@ -306,15 +305,12 @@ class rcube_addresses extends rcube_contacts * @param array $save_data Associative array with save data * @param bool $check Enables validity checks * - * @return int|bool The created record ID on success, False on error + * @return mixed The created record ID on success, False on error */ public function insert($save_data, $check = false) { - if (!is_array($save_data)) { - return false; - } - - if ($check && ($existing = $this->search('email', $save_data['email'], false, false))) { + if ($check) { + $existing = $this->search('email', $save_data['email'], false, false); if ($existing->count) { return false; } @@ -351,8 +347,8 @@ class rcube_addresses extends rcube_contacts /** * Delete one or more contact records * - * @param array $ids Record identifiers - * @param bool $force Remove record(s) irreversible (unsupported) + * @param array|string $ids Record identifiers as an array or a string with self::SEPARATOR + * @param bool $force Remove record(s) irreversible (unsupported) * * @return int|false Number of removed records */ diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index a2554e714..ab364c807 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -71,7 +71,7 @@ class rcube_contacts extends rcube_addressbook { $this->db = $dbconn; $this->user_id = $user; - $this->ready = $this->db && !$this->db->is_error(); + $this->ready = !$this->db->is_error(); } /** @@ -87,7 +87,7 @@ class rcube_contacts extends rcube_addressbook /** * Save a search string for future listings * - * @param string $filter SQL params to use in listing method + * @param mixed $filter SQL params to use in listing method */ public function set_search_set($filter): void { @@ -128,8 +128,8 @@ class rcube_contacts extends rcube_addressbook /** * List all active contact groups of this source * - * @param string $search Search string to match group name - * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* + * @param ?string $search Search string to match group name + * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* * * @return array Indexed list of contact groups, each a hash array */ @@ -196,9 +196,9 @@ class rcube_contacts extends rcube_addressbook /** * List the current set of contact records * - * @param array $cols List of cols to show, Null means all - * @param int $subset Only return this number of records, use negative values for tail - * @param bool $nocount True to skip the count query (select only) + * @param ?array $cols List of cols to show, Null means all + * @param int $subset Only return this number of records, use negative values for tail + * @param bool $nocount True to skip the count query (select only) * * @return rcube_result_set Indexed list of contact records, each a hash array */ @@ -382,8 +382,8 @@ class rcube_contacts extends rcube_addressbook $pos = strpos($col, ':'); $colname = $pos ? substr($col, 0, $pos) : $col; $search = $post_search[$colname]; - foreach ((array) $row[$col] as $value) { - if ($this->compare_search_value($colname, $value, $search, $mode)) { + foreach ((array) $row[$col] as $_value) { + if ($this->compare_search_value($colname, $_value, $search, $mode)) { $found[$colname] = true; break; } @@ -425,7 +425,7 @@ class rcube_contacts extends rcube_addressbook // when we know we have an empty result if ($ids == '0') { $this->set_search_set($where); - return $this->result = new rcube_result_set(0, 0); + return $this->result = new rcube_result_set(); } } @@ -436,6 +436,8 @@ class rcube_contacts extends rcube_addressbook } else { $this->result = $this->count(); } + } else { + return $this->result = new rcube_result_set(); } return $this->result; @@ -516,7 +518,7 @@ class rcube_contacts extends rcube_addressbook /** * Return the last result set * - * @return mixed Result array or NULL if nothing selected yet + * @return rcube_result_set|null Result array or NULL if nothing selected yet */ public function get_result() { @@ -529,7 +531,7 @@ class rcube_contacts extends rcube_addressbook * @param mixed $id Record identifier(s) * @param bool $assoc Enables returning associative array * - * @return rcube_result_set|array Result object with all record fields + * @return rcube_result_set|array|null Result object with all record fields */ public function get_record($id, $assoc = false) { @@ -624,21 +626,18 @@ class rcube_contacts extends rcube_addressbook * @param array $save_data Associative array with save data * @param bool $check Enables validity checks * - * @return int|bool The created record ID on success, False on error + * @return mixed The created record ID on success, False on error */ public function insert($save_data, $check = false) { - if (!is_array($save_data)) { - return false; - } - $insert_id = $existing = false; if ($check) { foreach ($save_data as $col => $values) { if (strpos($col, 'email') === 0) { foreach ((array) $values as $email) { - if ($existing = $this->search('email', $email, false, false)) { + $existing = $this->search('email', $email, false, false); + if ($existing->count) { break 2; } } @@ -805,8 +804,8 @@ class rcube_contacts extends rcube_addressbook /** * Mark one or more contact records as deleted * - * @param array $ids Record identifiers - * @param bool $force Remove record(s) irreversible (unsupported) + * @param array|string $ids Record identifiers array or string separated with self::SEPARATOR + * @param bool $force Remove record(s) irreversible (unsupported) * * @return int|false Number of removed records, False on failure */ @@ -835,7 +834,7 @@ class rcube_contacts extends rcube_addressbook /** * Undelete one or more contact records * - * @param array $ids Record identifiers + * @param array|string $ids Record identifiers array or string separated with self::SEPARATOR * * @return int Number of undeleted contact records */ diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index c6b28cce3..de2acd67e 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -436,6 +436,7 @@ class rcube_ldap extends rcube_addressbook } } + // @phpstan-ignore-next-line if ($this->cache && !empty($replaces['%dn'])) { $this->cache->set($cache_key, $replaces['%dn']); } @@ -549,10 +550,10 @@ class rcube_ldap extends rcube_addressbook /** * Set internal sort settings * - * @param string $sort_col Sort column - * @param string $sort_order Sort order + * @param ?string $sort_col Sort column + * @param ?string $sort_order Sort order */ - public function set_sort_order($sort_col, $sort_order = null) + public function set_sort_order($sort_col = null, $sort_order = null) { if (!empty($this->coltypes[$sort_col]['attributes'])) { $this->sort_col = $this->coltypes[$sort_col]['attributes'][0]; @@ -562,7 +563,7 @@ class rcube_ldap extends rcube_addressbook /** * Save a search string for future listings * - * @param string $filter Filter string + * @param mixed $filter Filter string */ public function set_search_set($filter): void { @@ -592,9 +593,9 @@ class rcube_ldap extends rcube_addressbook /** * List the current set of contact records * - * @param array $cols List of cols to show - * @param int $subset Only return this number of records - * @param bool $nocount True to skip the count query (Not used) + * @param ?array $cols List of cols to show + * @param int $subset Only return this number of records + * @param bool $nocount True to skip the count query (Not used) * * @return rcube_result_set Indexed list of contact records, each a hash array */ @@ -793,12 +794,12 @@ class rcube_ldap extends rcube_addressbook /** * Search contacts * - * @param mixed $fields The field name of array of field names to search in - * @param mixed $value Search value (or array of values when $fields is array) - * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* - * @param bool $select True if results are requested, False if count only - * @param bool $nocount (Not used) - * @param array $required List of fields that cannot be empty + * @param mixed $fields The field name of array of field names to search in + * @param mixed $value Search value (or array of values when $fields is array) + * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* + * @param bool $select True if results are requested, False if count only + * @param bool $nocount (Not used) + * @param array|string $required List of fields that cannot be empty, or a single field * * @return rcube_result_set List of contact records */ @@ -829,7 +830,7 @@ class rcube_ldap extends rcube_addressbook if (!empty($this->prop['vlv_search']) && $this->ready && implode(',', (array) $fields) == implode(',', $list_fields) ) { - $this->result = new rcube_result_set(0); + $this->result = new rcube_result_set(); $this->ldap->config_set('fuzzy_search', $fuzzy_search); @@ -1084,7 +1085,7 @@ class rcube_ldap extends rcube_addressbook * @param mixed $dn Record identifier * @param bool $assoc Return as associative array * - * @return mixed Hash array or rcube_result_set with all record fields + * @return array|rcube_result_set|null Hash array or rcube_result_set with all record fields */ public function get_record($dn, $assoc = false) { @@ -1178,19 +1179,19 @@ class rcube_ldap extends rcube_addressbook // try to extract surname and firstname from displayname $name_parts = preg_split('/[\s,.]+/', $save_data['name']); - if ($sn_field && $missing[$sn_field]) { + if ($sn_field && !empty($missing[$sn_field])) { $save_data['surname'] = array_pop($name_parts); unset($missing[$sn_field]); } - if ($fn_field && $missing[$fn_field]) { + if ($fn_field && !empty($missing[$fn_field])) { $save_data['firstname'] = array_shift($name_parts); unset($missing[$fn_field]); } // try to fix missing e-mail, very often on import // from vCard we have email:other only defined - if ($mail_field && $missing[$mail_field]) { + if ($mail_field && !empty($missing[$mail_field])) { $emails = $this->get_col_values('email', $save_data, true); if (!empty($emails) && ($email = array_first($emails))) { $save_data['email'] = $email; @@ -1320,9 +1321,11 @@ class rcube_ldap extends rcube_addressbook } // $this->_map_data() result and _raw_attrib use different format // make sure comparing array with one element with a string works as expected + // @phpstan-ignore-next-line if (is_array($old) && count($old) == 1 && !is_array($val)) { $old = array_pop($old); } + // @phpstan-ignore-next-line if (is_array($val) && count($val) == 1 && !is_array($old)) { $val = array_pop($val); } @@ -1464,10 +1467,10 @@ class rcube_ldap extends rcube_addressbook /** * Mark one or more contact records as deleted * - * @param array $ids Record identifiers - * @param bool $force Remove record(s) irreversible (unsupported) + * @param array|string $ids Record identifiers array or comma-separated string + * @param bool $force Remove record(s) irreversible (unsupported) * - * @return int|bool Number of deleted records on success, False on error + * @return int|false Number of deleted records on success, False on error */ public function delete($ids, $force = true) { @@ -1820,8 +1823,8 @@ class rcube_ldap extends rcube_addressbook /** * List all active contact groups of this source * - * @param string $search Optional search string to match group name - * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* + * @param ?string $search Optional search string to match group name + * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* * * @return array Indexed list of contact groups, each a hash array */ @@ -2038,7 +2041,7 @@ class rcube_ldap extends rcube_addressbook * * @param string $group_name The group name * - * @return mixed False on error, array with record props in success + * @return array|false False on error, array with record props in success */ public function create_group($group_name) { @@ -2096,7 +2099,7 @@ class rcube_ldap extends rcube_addressbook * @param string $new_name New name to set for this group * @param string &$new_gid New group identifier (if changed, otherwise don't set) * - * @return bool New name on success, false if no data was changed + * @return string|false New name on success, false if no data was changed */ public function rename_group($group_id, $new_name, &$new_gid) {