diff --git a/include/conversation.php b/include/conversation.php index 5b7ccbd8a1..0eb94181f0 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -376,17 +376,17 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o . "\r\n"; } diff --git a/mod/network.php b/mod/network.php index 1506c70737..433d4079c1 100644 --- a/mod/network.php +++ b/mod/network.php @@ -58,8 +58,8 @@ function network_init(App $a) $group_id = (($a->argc > 1 && is_numeric($a->argv[1])) ? intval($a->argv[1]) : 0); $cid = 0; - if (!empty($_GET['cid'])) { - $cid = $_GET['cid']; + if (!empty($_GET['contactid'])) { + $cid = $_GET['contactid']; $_GET['nets'] = ''; $group_id = 0; } @@ -466,12 +466,12 @@ function networkThreadedView(App $a, $update, $parent) $o = ''; - $cid = intval($_GET['cid'] ?? 0); - $star = intval($_GET['star'] ?? 0); - $bmark = intval($_GET['bmark'] ?? 0); - $conv = intval($_GET['conv'] ?? 0); + $cid = intval($_GET['contactid'] ?? 0); + $star = intval($_GET['star'] ?? 0); + $bmark = intval($_GET['bmark'] ?? 0); + $conv = intval($_GET['conv'] ?? 0); $order = Strings::escapeTags(($_GET['order'] ?? '') ?: 'activity'); - $nets = $_GET['nets'] ?? ''; + $nets = $_GET['nets'] ?? ''; $allowedCids = []; if ($cid) { @@ -786,6 +786,13 @@ function networkThreadedView(App $a, $update, $parent) $top_limit = DateTimeFormat::utcNow(); } + // Handle bad performance situations when the distance between top and bottom is too high + // See issue https://github.com/friendica/friendica/issues/8619 + if (strtotime($top_limit) - strtotime($bottom_limit) > 86400) { + // Set the bottom limit to one day in the past at maximum + $bottom_limit = DateTimeFormat::utc(date('c', strtotime($top_limit) - 86400)); + } + $items = DBA::p("SELECT `item`.`parent-uri` AS `uri`, 0 AS `item_id`, `item`.$ordering AS `order_date`, `author`.`url` AS `author-link` FROM `item` STRAIGHT_JOIN (SELECT `uri-id` FROM `tag-search-view` WHERE `name` IN (SELECT SUBSTR(`term`, 2) FROM `search` WHERE `uid` = ? AND `term` LIKE '#%') AND `uid` = 0) AS `tag-search` @@ -891,8 +898,8 @@ function network_tabs(App $a) $cmd = DI::args()->getCommand(); $def_param = []; - if (!empty($_GET['cid'])) { - $def_param['cid'] = $_GET['cid']; + if (!empty($_GET['contactid'])) { + $def_param['contactid'] = $_GET['contactid']; } // tabs diff --git a/src/Content/ForumManager.php b/src/Content/ForumManager.php index 7d3cb89a71..9441e9dbb0 100644 --- a/src/Content/ForumManager.php +++ b/src/Content/ForumManager.php @@ -126,7 +126,7 @@ class ForumManager $selected = (($cid == $contact['id']) ? ' forum-selected' : ''); $entry = [ - 'url' => 'network?cid=' . $contact['id'], + 'url' => 'network?contactid=' . $contact['id'], 'external_url' => Contact::magicLink($contact['url']), 'name' => $contact['name'], 'cid' => $contact['id'], diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 98c1552930..67dbe3b19a 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -1724,7 +1724,15 @@ class BBCode // Replace non graphical smilies for external posts if (!$nosmile && !$for_plaintext) { - $text = Smilies::replace($text); + $text = Smilies::replace($text); + } + + if (!$for_plaintext && DI::config()->get('system', 'big_emojis') && ($simple_html != self::DIASPORA)) { + $conv = html_entity_decode(str_replace([' ', "\n", "\r"], '', $text)); + // Emojis are always 4 byte Unicode characters + if (!empty($conv) && (strlen($conv) / mb_strlen($conv) == 4)) { + $text = '' . $text . ''; + } } if (!$for_plaintext) { diff --git a/src/Database/Database.php b/src/Database/Database.php index 7adb88ffa8..05ce3693b4 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -135,8 +135,9 @@ class Database } $this->emulate_prepares = (bool)$this->configCache->get('database', 'emulate_prepares'); + $this->pdo_emulate_prepares = (bool)$this->configCache->get('database', 'pdo_emulate_prepares'); - if (class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) { + if (!$this->configCache->get('database', 'disable_pdo') && class_exists('\PDO') && in_array('mysql', PDO::getAvailableDrivers())) { $this->driver = 'pdo'; $connect = "mysql:host=" . $server . ";dbname=" . $db; @@ -150,7 +151,7 @@ class Database try { $this->connection = @new PDO($connect, $user, $pass); - $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares); $this->connected = true; } catch (PDOException $e) { $this->connected = false; @@ -504,6 +505,7 @@ class Database $sql = "/*" . System::callstack() . " */ " . $sql; } + $is_error = false; $this->error = ''; $this->errorno = 0; $this->affected_rows = 0; @@ -533,6 +535,7 @@ class Database $this->error = $errorInfo[2]; $this->errorno = $errorInfo[1]; $retval = false; + $is_error = true; break; } $this->affected_rows = $retval->rowCount(); @@ -545,6 +548,7 @@ class Database $this->error = $errorInfo[2]; $this->errorno = $errorInfo[1]; $retval = false; + $is_error = true; break; } @@ -562,6 +566,7 @@ class Database $this->error = $errorInfo[2]; $this->errorno = $errorInfo[1]; $retval = false; + $is_error = true; } else { $retval = $stmt; $this->affected_rows = $retval->rowCount(); @@ -580,6 +585,7 @@ class Database $this->error = $this->connection->error; $this->errorno = $this->connection->errno; $retval = false; + $is_error = true; } else { if (isset($retval->num_rows)) { $this->affected_rows = $retval->num_rows; @@ -596,6 +602,7 @@ class Database $this->error = $stmt->error; $this->errorno = $stmt->errno; $retval = false; + $is_error = true; break; } @@ -623,6 +630,7 @@ class Database $this->error = $this->connection->error; $this->errorno = $this->connection->errno; $retval = false; + $is_error = true; } else { $stmt->store_result(); $retval = $stmt; @@ -631,6 +639,16 @@ class Database break; } + // See issue https://github.com/friendica/friendica/issues/8572 + // Ensure that we always get an error message on an error. + if ($is_error && empty($this->errorno)) { + $this->errorno = -1; + } + + if ($is_error && empty($this->error)) { + $this->error = 'Unknown database error'; + } + // We are having an own error logging in the function "e" if (($this->errorno != 0) && !$called_from_e) { // We have to preserve the error code, somewhere in the logging it get lost @@ -642,8 +660,8 @@ class Database } $this->logger->error('DB Error', [ - 'code' => $this->errorno, - 'error' => $this->error, + 'code' => $errorno, + 'error' => $error, 'callstack' => System::callstack(8), 'params' => $this->replaceParameters($sql, $args), ]); @@ -654,21 +672,21 @@ class Database // It doesn't make sense to continue when the database connection was lost if ($this->in_retrial) { $this->logger->notice('Giving up retrial because of database error', [ - 'code' => $this->errorno, - 'error' => $this->error, + 'code' => $errorno, + 'error' => $error, ]); } else { $this->logger->notice('Couldn\'t reconnect after database error', [ - 'code' => $this->errorno, - 'error' => $this->error, + 'code' => $errorno, + 'error' => $error, ]); } exit(1); } else { // We try it again $this->logger->notice('Reconnected after database error', [ - 'code' => $this->errorno, - 'error' => $this->error, + 'code' => $errorno, + 'error' => $error, ]); $this->in_retrial = true; $ret = $this->p($sql, $args); @@ -745,8 +763,8 @@ class Database } $this->logger->error('DB Error', [ - 'code' => $this->errorno, - 'error' => $this->error, + 'code' => $errorno, + 'error' => $error, 'callstack' => System::callstack(8), 'params' => $this->replaceParameters($sql, $params), ]); @@ -755,8 +773,8 @@ class Database // A reconnect like in $this->p could be dangerous with modifications if ($errorno == 2006) { $this->logger->notice('Giving up because of database error', [ - 'code' => $this->errorno, - 'error' => $this->error, + 'code' => $errorno, + 'error' => $error, ]); exit(1); } @@ -1029,7 +1047,7 @@ class Database $success = $this->e("LOCK TABLES " . DBA::buildTableString($table) . " WRITE"); if ($this->driver == 'pdo') { - $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares); } if (!$success) { @@ -1062,7 +1080,7 @@ class Database $success = $this->e("UNLOCK TABLES"); if ($this->driver == 'pdo') { - $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $this->connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, $this->pdo_emulate_prepares); $this->e("SET autocommit=1"); } else { $this->connection->autocommit(true); diff --git a/src/Model/GServer.php b/src/Model/GServer.php index bc189af9d6..f750ed99ea 100644 --- a/src/Model/GServer.php +++ b/src/Model/GServer.php @@ -353,6 +353,15 @@ class GServer return; } + // Sanitize incoming data, see https://github.com/friendica/friendica/issues/8565 + $data['subscribe'] = (bool)$data['subscribe'] ?? false; + + if (!$data['subscribe'] || empty($data['scope']) || !in_array(strtolower($data['scope']), ['all', 'tags'])) { + $data['scope'] = ''; + $data['subscribe'] = false; + $data['tags'] = []; + } + $gserver = DBA::selectFirst('gserver', ['id', 'relay-subscribe', 'relay-scope'], ['nurl' => Strings::normaliseLink($server_url)]); if (!DBA::isResult($gserver)) { return; diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index dd1f678d58..243550862b 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -3139,7 +3139,9 @@ class Diaspora $json = json_encode(["iv" => $b_iv, "key" => $b_aes_key]); $encrypted_key_bundle = ""; - openssl_public_encrypt($json, $encrypted_key_bundle, $pubkey); + if (!@openssl_public_encrypt($json, $encrypted_key_bundle, $pubkey)) { + return false; + } $json_object = json_encode( ["aes_key" => base64_encode($encrypted_key_bundle), diff --git a/static/defaults.config.php b/static/defaults.config.php index d0725aa9bc..a1d50bb84f 100644 --- a/static/defaults.config.php +++ b/static/defaults.config.php @@ -45,8 +45,23 @@ return [ 'database' => '', // charset (String) - // Database connexion charset. Changing this value will likely corrupt special characters. + // Database connection charset. Changing this value will likely corrupt special characters. 'charset' => 'utf8mb4', + + // emulate_prepares (Boolean) (Experimental) + // If enabled, prepared statements will be emulated. + // In combination with MySQLi this will cast all return values to strings. + 'emulate_prepares' => false, + + // pdo_emulate_prepares (Boolean) (Experimental) + // If enabled, the builtin emulation for prepared statements is used. + // Due to limitations of that emulation (all return values are casted as strings) + // this will most likely cause issues and should not be used on production systems. + 'pdo_emulate_prepares' => false, + + // disable_pdo (Boolean) + // PDO is used by default (if available). Otherwise MySQLi will be used. + 'disable_pdo' => false, ], 'config' => [ // admin_email (Comma-separated list) @@ -88,6 +103,10 @@ return [ // chose "Remember me" when logging in is considered logged out. 'auth_cookie_lifetime' => 7, + // big_emojis (Boolean) + // Display "Emoji Only" posts in big. + 'big_emojis' => false, + // block_local_dir (Boolean) // Deny public access to the local user directory. 'block_local_dir' => false, diff --git a/tests/Util/Database/StaticDatabase.php b/tests/Util/Database/StaticDatabase.php index f2ed6c700e..c95b690c63 100644 --- a/tests/Util/Database/StaticDatabase.php +++ b/tests/Util/Database/StaticDatabase.php @@ -56,6 +56,8 @@ class StaticDatabase extends Database $this->driver = 'pdo'; $this->connection = self::$staticConnection; $this->connected = true; + $this->emulate_prepares = false; + $this->pdo_emulate_prepares = false; return $this->connected; } diff --git a/tests/src/Content/Text/BBCodeTest.php b/tests/src/Content/Text/BBCodeTest.php index 1a1d06dc7b..35dff87d9f 100644 --- a/tests/src/Content/Text/BBCodeTest.php +++ b/tests/src/Content/Text/BBCodeTest.php @@ -58,6 +58,9 @@ class BBCodeTest extends MockedTest $this->configMock->shouldReceive('get') ->with('system', 'no_smilies') ->andReturn(false); + $this->configMock->shouldReceive('get') + ->with('system', 'big_emojis') + ->andReturn(false); $l10nMock = \Mockery::mock(L10n::class); $l10nMock->shouldReceive('t')->withAnyArgs()->andReturnUsing(function ($args) { return $args; }); diff --git a/view/theme/vier/theme.php b/view/theme/vier/theme.php index cc3a668e6a..cec5e5ba63 100644 --- a/view/theme/vier/theme.php +++ b/view/theme/vier/theme.php @@ -202,7 +202,7 @@ function vier_community_info() $selected = (($cid == $contact['id']) ? ' forum-selected' : ''); $entry = [ - 'url' => 'network?cid=' . $contact['id'], + 'url' => 'network?contactid=' . $contact['id'], 'external_url' => Contact::magicLink($contact['url']), 'name' => $contact['name'], 'cid' => $contact['id'],