', $text);
diff --git a/src/Core/Protocol.php b/src/Core/Protocol.php
index 9890b8f28..977684875 100644
--- a/src/Core/Protocol.php
+++ b/src/Core/Protocol.php
@@ -315,7 +315,12 @@ class Protocol
*/
public static function supportsProbe($protocol): bool
{
- if (in_array($protocol, self::NATIVE_SUPPORT)) {
+ // "Mail" can only be probed for a specific user in a specific condition, so we are ignoring it here.
+ if ($protocol == self::MAIL) {
+ return false;
+ }
+
+ if (in_array($protocol, array_merge(self::NATIVE_SUPPORT, [self::ZOT, self::PHANTOM]))) {
return true;
}
diff --git a/src/Core/Search.php b/src/Core/Search.php
index 45b64eb51..8b114a468 100644
--- a/src/Core/Search.php
+++ b/src/Core/Search.php
@@ -55,40 +55,42 @@ class Search
* @throws HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
- public static function getContactsFromProbe(string $user): ResultList
+ public static function getContactsFromProbe(string $user, $only_forum = false): ResultList
{
- $emptyResultList = new ResultList(1, 0, 1);
+ $emptyResultList = new ResultList();
- if ((filter_var($user, FILTER_VALIDATE_EMAIL) && Network::isEmailDomainValid($user)) ||
- (substr(Strings::normaliseLink($user), 0, 7) == 'http://')) {
-
- $user_data = Contact::getByURL($user);
- if (empty($user_data)) {
- return $emptyResultList;
- }
-
- if (!in_array($user_data['network'], Protocol::FEDERATED)) {
- return $emptyResultList;
- }
-
- $contactDetails = Contact::getByURLForUser($user_data['url'] ?? '', DI::userSession()->getLocalUserId());
-
- $result = new ContactResult(
- $user_data['name'] ?? '',
- $user_data['addr'] ?? '',
- ($contactDetails['addr'] ?? '') ?: ($user_data['url'] ?? ''),
- new Uri($user_data['url'] ?? ''),
- $user_data['photo'] ?? '',
- $user_data['network'] ?? '',
- $contactDetails['cid'] ?? 0,
- $user_data['id'] ?? 0,
- $user_data['tags'] ?? ''
- );
-
- return new ResultList(1, 1, 1, [$result]);
- } else {
+ if (empty(parse_url($user, PHP_URL_SCHEME)) && !(filter_var($user, FILTER_VALIDATE_EMAIL) || Network::isEmailDomainValid($user))) {
return $emptyResultList;
}
+
+ $user_data = Contact::getByURL($user);
+ if (empty($user_data)) {
+ return $emptyResultList;
+ }
+
+ if ($only_forum && ($user_data['contact-type'] != Contact::TYPE_COMMUNITY)) {
+ return $emptyResultList;
+ }
+
+ if (!Protocol::supportsProbe($user_data['network'])) {
+ return $emptyResultList;
+ }
+
+ $contactDetails = Contact::getByURLForUser($user_data['url'], DI::userSession()->getLocalUserId());
+
+ $result = new ContactResult(
+ $user_data['name'],
+ $user_data['addr'],
+ $user_data['addr'] ?: $user_data['url'],
+ new Uri($user_data['url']),
+ $user_data['photo'],
+ $user_data['network'],
+ $contactDetails['cid'] ?? 0,
+ $user_data['id'],
+ $user_data['tags']
+ );
+
+ return new ResultList(1, 1, 1, [$result]);
}
/**
@@ -129,7 +131,7 @@ class Search
$resultList = new ResultList(
($results['page'] ?? 0) ?: 1,
- $results['count'] ?? 0,
+ $results['count'] ?? 0,
($results['itemsperpage'] ?? 0) ?: 30
);
@@ -174,7 +176,7 @@ class Search
$contacts = Contact::searchByName($search, $type == self::TYPE_FORUM ? 'community' : '', true);
- $resultList = new ResultList($start, $itemPage, count($contacts));
+ $resultList = new ResultList($start, count($contacts), $itemPage);
foreach ($contacts as $contact) {
$result = new ContactResult(
@@ -284,4 +286,4 @@ class Search
return 'search?q=' . urlencode($search);
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Core/Update.php b/src/Core/Update.php
index a4c5cf313..2718d03d0 100644
--- a/src/Core/Update.php
+++ b/src/Core/Update.php
@@ -129,20 +129,6 @@ class Update
DI::lock()->release('dbupdate', true);
}
- if (!DBStructure::existsTable('config')) {
- DBA::e(<<get('system', 'build');
if (empty($build)) {
diff --git a/src/Core/Worker/Cron.php b/src/Core/Worker/Cron.php
index e9b77229b..dcb9fd3ab 100644
--- a/src/Core/Worker/Cron.php
+++ b/src/Core/Worker/Cron.php
@@ -151,8 +151,8 @@ class Cron
// We are acquiring the two locks from the worker to avoid locking problems
if (DI::lock()->acquire(Worker::LOCK_PROCESS, 10)) {
if (DI::lock()->acquire(Worker::LOCK_WORKER, 10)) {
- DBA::e("OPTIMIZE TABLE `workerqueue`");
- DBA::e("OPTIMIZE TABLE `process`");
+ DBA::optimizeTable('workerqueue');
+ DBA::optimizeTable('process');
DI::lock()->release(Worker::LOCK_WORKER);
}
DI::lock()->release(Worker::LOCK_PROCESS);
@@ -197,7 +197,7 @@ class Cron
// Optimizing this table only last seconds
if (DI::config()->get('system', 'optimize_tables')) {
Logger::info('Optimize start');
- DBA::e("OPTIMIZE TABLE `post-delivery`");
+ DBA::optimizeTable('post-delivery');
Logger::info('Optimize end');
}
}
diff --git a/src/Database/DBA.php b/src/Database/DBA.php
index d609f108e..930e60472 100644
--- a/src/Database/DBA.php
+++ b/src/Database/DBA.php
@@ -821,6 +821,27 @@ class DBA
return DI::dba()->processlist();
}
+ /**
+ * Optimizes tables
+ *
+ * @param string $table a given table
+ *
+ * @return bool True, if successfully optimized, otherwise false
+ * @throws \Exception
+ */
+ public static function optimizeTable(string $table): bool
+ {
+ return DI::dba()->optimizeTable($table);
+ }
+
+ /**
+ * Kill sleeping database processes
+ */
+ public static function deleteSleepingProcesses()
+ {
+ DI::dba()->deleteSleepingProcesses();
+ }
+
/**
* Fetch a database variable
*
diff --git a/src/Database/DBStructure.php b/src/Database/DBStructure.php
index dc1e785a5..6291d0ffc 100644
--- a/src/Database/DBStructure.php
+++ b/src/Database/DBStructure.php
@@ -57,6 +57,18 @@ class DBStructure
echo DI::l10n()->t('The database version had been set to %s.', $version);
}
+ /**
+ * Drops a specific table
+ *
+ * @param string $table the table name
+ *
+ * @return bool true if possible, otherwise false
+ */
+ public static function dropTable(string $table): bool
+ {
+ return DBA::isResult(DBA::e('DROP TABLE ' . DBA::quoteIdentifier($table) . ';'));
+ }
+
/**
* Drop unused tables
*
@@ -94,8 +106,7 @@ class DBStructure
$sql = 'DROP TABLE ' . DBA::quoteIdentifier($table) . ';';
echo $sql . "\n";
- $result = DBA::e($sql);
- if (!DBA::isResult($result)) {
+ if (!static::dropTable($table)) {
self::printUpdateError($sql);
}
} else {
diff --git a/src/Database/Database.php b/src/Database/Database.php
index b1ea6c1e4..f931169ce 100644
--- a/src/Database/Database.php
+++ b/src/Database/Database.php
@@ -1357,6 +1357,15 @@ class Database
}
$fields = $this->castFields($table, $fields);
+ $direct_fields = [];
+
+ foreach ($fields as $key => $value) {
+ if (is_numeric($key)) {
+ $direct_fields[] = $value;
+ unset($fields[$key]);
+ }
+ }
+
$table_string = DBA::buildTableString([$table]);
@@ -1369,7 +1378,8 @@ class Database
}
$sql = "UPDATE " . $ignore . $table_string . " SET "
- . implode(" = ?, ", array_map([DBA::class, 'quoteIdentifier'], array_keys($fields))) . " = ?"
+ . ((count($fields) > 0) ? implode(" = ?, ", array_map([DBA::class, 'quoteIdentifier'], array_keys($fields))) . " = ?" : "")
+ . ((count($direct_fields) > 0) ? ((count($fields) > 0) ? " , " : "") . implode(" , ", $direct_fields) : "")
. $condition_string;
// Combines the updated fields parameter values with the condition parameter values
@@ -1758,6 +1768,37 @@ class Database
return (['list' => $statelist, 'amount' => $processes]);
}
+ /**
+ * Optimizes tables
+ *
+ * @param string $table a given table
+ *
+ * @return bool True, if successfully optimized, otherwise false
+ * @throws \Exception
+ */
+ public function optimizeTable(string $table): bool
+ {
+ return $this->e("OPTIMIZE TABLE " . DBA::buildTableString([$table])) !== false;
+ }
+
+ /**
+ * Kill sleeping database processes
+ *
+ * @return void
+ */
+ public function deleteSleepingProcesses()
+ {
+ $processes = $this->p("SHOW FULL PROCESSLIST");
+ while ($process = $this->fetch($processes)) {
+ if (($process['Command'] != 'Sleep') || ($process['Time'] < 300) || ($process['db'] != $this->databaseName())) {
+ continue;
+ }
+
+ $this->e("KILL ?", $process['Id']);
+ }
+ $this->close($processes);
+ }
+
/**
* Fetch a database variable
*
diff --git a/src/Database/DatabaseException.php b/src/Database/DatabaseException.php
index ba1ccfce5..8c99b9a7e 100644
--- a/src/Database/DatabaseException.php
+++ b/src/Database/DatabaseException.php
@@ -38,22 +38,24 @@ class DatabaseException extends Exception
*
* @link https://php.net/manual/en/exception.construct.php
*
- * @param string $message The Database error message.
- * @param int $code The Database error code.
- * @param string $query The Database error query.
- * @param Throwable $previous [optional] The previous throwable used for the exception chaining.
+ * @param string $message The Database error message.
+ * @param int $code The Database error code.
+ * @param string $query The Database error query.
+ * @param Throwable|null $previous [optional] The previous throwable used for the exception chaining.
*/
public function __construct(string $message, int $code, string $query, Throwable $previous = null)
{
- parent::__construct($message, $code, $previous);
+ parent::__construct(sprintf('"%s" at "%s"', $message, $query) , $code, $previous);
$this->query = $query;
}
/**
- * {@inheritDoc}
+ * Returns the query, which caused the exception
+ *
+ * @return string
*/
- public function __toString()
+ public function getQuery(): string
{
- return sprintf('Database error %d "%s" at "%s"', $this->message, $this->code, $this->query);
+ return $this->query;
}
}
diff --git a/src/Federation/Repository/DeliveryQueueItem.php b/src/Federation/Repository/DeliveryQueueItem.php
index 815cf89b5..37d4ad84c 100644
--- a/src/Federation/Repository/DeliveryQueueItem.php
+++ b/src/Federation/Repository/DeliveryQueueItem.php
@@ -88,7 +88,10 @@ final class DeliveryQueueItem extends \Friendica\BaseRepository
public function remove(Entity\DeliveryQueueItem $deliveryQueueItem): bool
{
- return $this->db->delete(self::$table_name, ['uri-id' => $deliveryQueueItem->postUriId, 'gsid' => $deliveryQueueItem->targetServerId]);
+ return $this->db->delete(self::$table_name, [
+ 'uri-id' => $deliveryQueueItem->postUriId,
+ 'gsid' => $deliveryQueueItem->targetServerId
+ ]);
}
public function removeFailedByServerId(int $gsid, int $failedThreshold): bool
@@ -98,16 +101,17 @@ final class DeliveryQueueItem extends \Friendica\BaseRepository
public function incrementFailed(Entity\DeliveryQueueItem $deliveryQueueItem): bool
{
- return $this->db->e("
- UPDATE " . DBA::buildTableString([self::$table_name]) . "
- SET `failed` = `failed` + 1
- WHERE `uri-id` = ? AND `gsid` = ?",
- $deliveryQueueItem->postUriId, $deliveryQueueItem->targetServerId
- );
+ return $this->db->update(self::$table_name, [
+ "`failed` = `failed` + 1"
+ ], [
+ "`uri-id` = ? AND `gsid` = ?",
+ $deliveryQueueItem->postUriId,
+ $deliveryQueueItem->targetServerId
+ ]);
}
public function optimizeStorage(): bool
{
- return $this->db->e("OPTIMIZE TABLE " . DBA::buildTableString([self::$table_name]));
+ return $this->db->optimizeTable(self::$table_name);
}
}
diff --git a/src/Model/Contact.php b/src/Model/Contact.php
index b06cbff87..99edf3fe2 100644
--- a/src/Model/Contact.php
+++ b/src/Model/Contact.php
@@ -361,7 +361,7 @@ class Contact
$background_update = DI::config()->get('system', 'update_active_contacts') ? $contact['local-data'] : true;
// Update the contact in the background if needed
- if ($background_update && !self::isLocal($url) && Probe::isProbable($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
+ if ($background_update && !self::isLocal($url) && Protocol::supportsProbe($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
try {
UpdateContact::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], $contact['id']);
} catch (\InvalidArgumentException $e) {
@@ -1279,7 +1279,7 @@ class Contact
$background_update = DI::config()->get('system', 'update_active_contacts') ? $contact['local-data'] : true;
- if ($background_update && !self::isLocal($url) && Probe::isProbable($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
+ if ($background_update && !self::isLocal($url) && Protocol::supportsProbe($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
try {
UpdateContact::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], $contact['id']);
} catch (\InvalidArgumentException $e) {
@@ -2682,6 +2682,8 @@ class Contact
return true;
}
+ $has_local_data = self::hasLocalData($id, $contact);
+
$uid = $contact['uid'];
unset($contact['uid']);
@@ -2702,18 +2704,20 @@ class Contact
$updated = DateTimeFormat::utcNow();
- $has_local_data = self::hasLocalData($id, $contact);
-
- if (!Probe::isProbable($ret['network'])) {
+ if (!Protocol::supportsProbe($ret['network']) && !Protocol::supportsProbe($contact['network'])) {
// Periodical checks are only done on federated contacts
$failed_next_update = null;
$success_next_update = null;
} elseif ($has_local_data) {
$failed_next_update = GServer::getNextUpdateDate(false, $created, $last_update, !in_array($contact['network'], Protocol::FEDERATED));
$success_next_update = GServer::getNextUpdateDate(true, $created, $last_update, !in_array($contact['network'], Protocol::FEDERATED));
- } else {
+ } elseif (in_array($ret['network'], array_merge(Protocol::NATIVE_SUPPORT, [Protocol::ZOT, Protocol::PHANTOM]))) {
$failed_next_update = DateTimeFormat::utc('now +6 month');
$success_next_update = DateTimeFormat::utc('now +1 month');
+ } else {
+ // We don't check connector networks very often to not run into API rate limits
+ $failed_next_update = DateTimeFormat::utc('now +12 month');
+ $success_next_update = DateTimeFormat::utc('now +12 month');
}
if (Strings::normaliseLink($contact['url']) != Strings::normaliseLink($ret['url'])) {
@@ -3596,7 +3600,7 @@ class Contact
if (empty($contact['id']) && Network::isValidHttpUrl($url)) {
Worker::add(Worker::PRIORITY_LOW, 'AddContact', 0, $url);
++$added;
- } elseif (!empty($contact['network']) && Probe::isProbable($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
+ } elseif (!empty($contact['network']) && Protocol::supportsProbe($contact['network']) && ($contact['next-update'] < DateTimeFormat::utcNow())) {
try {
UpdateContact::add(['priority' => Worker::PRIORITY_LOW, 'dont_fork' => true], $contact['id']);
++$updated;
diff --git a/src/Model/Photo.php b/src/Model/Photo.php
index 74031a822..1b87e82d5 100644
--- a/src/Model/Photo.php
+++ b/src/Model/Photo.php
@@ -918,9 +918,7 @@ class Photo
*/
public static function getResourceData(string $name): array
{
- $base = DI::baseUrl();
-
- $guid = str_replace([Strings::normaliseLink($base), '/photo/'], '', Strings::normaliseLink($name));
+ $guid = str_replace([Strings::normaliseLink((string)DI::baseUrl()), '/photo/'], '', Strings::normaliseLink($name));
if (parse_url($guid, PHP_URL_SCHEME)) {
return [];
@@ -982,9 +980,7 @@ class Photo
*/
public static function isLocalPage(string $name): bool
{
- $base = DI::baseUrl();
-
- $guid = str_replace(Strings::normaliseLink($base), '', Strings::normaliseLink($name));
+ $guid = str_replace(Strings::normaliseLink((string)DI::baseUrl()), '', Strings::normaliseLink($name));
$guid = preg_replace("=/photos/.*/image/(.*)=ism", '$1', $guid);
if (empty($guid)) {
return false;
diff --git a/src/Model/Post/Delivery.php b/src/Model/Post/Delivery.php
index 0e343e871..c53014fa5 100644
--- a/src/Model/Post/Delivery.php
+++ b/src/Model/Post/Delivery.php
@@ -78,7 +78,7 @@ class Delivery
*/
public static function incrementFailed(int $uri_id, string $inbox)
{
- return DBA::e('UPDATE `post-delivery` SET `failed` = `failed` + 1 WHERE `uri-id` = ? AND `inbox-id` = ?', $uri_id, ItemURI::getIdByURI($inbox));
+ return DBA::update('post-delivery', ["`failed` = `failed` + 1"], ['uri-id' => $uri_id, 'inbox-id' => ItemURI::getIdByURI($inbox)]);
}
public static function selectForInbox(string $inbox)
diff --git a/src/Model/Post/DeliveryData.php b/src/Model/Post/DeliveryData.php
index e87bb0e01..c1aad730c 100644
--- a/src/Model/Post/DeliveryData.php
+++ b/src/Model/Post/DeliveryData.php
@@ -82,27 +82,27 @@ class DeliveryData
*/
public static function incrementQueueDone(int $uri_id, int $protocol = 0)
{
- $sql = '';
+ $increments = ["`queue_done` = `queue_done` + 1"];
switch ($protocol) {
case self::ACTIVITYPUB:
- $sql = ", `activitypub` = `activitypub` + 1";
+ $increments[] = "`activitypub` = `activitypub` + 1";
break;
case self::DFRN:
- $sql = ", `dfrn` = `dfrn` + 1";
+ $increments[] = "`dfrn` = `dfrn` + 1";
break;
case self::LEGACY_DFRN:
- $sql = ", `legacy_dfrn` = `legacy_dfrn` + 1";
+ $increments[] = "`legacy_dfrn` = `legacy_dfrn` + 1";
break;
case self::DIASPORA:
- $sql = ", `diaspora` = `diaspora` + 1";
+ $increments[] = "`diaspora` = `diaspora` + 1";
break;
case self::OSTATUS:
- $sql = ", `ostatus` = `ostatus` + 1";
+ $increments[] = "`ostatus` = `ostatus` + 1";
break;
}
- return DBA::e('UPDATE `post-delivery-data` SET `queue_done` = `queue_done` + 1' . $sql . ' WHERE `uri-id` = ?', $uri_id);
+ return DBA::update('post-delivery-data', $increments, ['uri-id' => $uri_id]);
}
/**
@@ -116,7 +116,7 @@ class DeliveryData
*/
public static function incrementQueueFailed(int $uri_id)
{
- return DBA::e('UPDATE `post-delivery-data` SET `queue_failed` = `queue_failed` + 1 WHERE `uri-id` = ?', $uri_id);
+ return DBA::update('post-delivery-data', ["`queue_failed` = `queue_failed` + 1"], ['uri-id' => $uri_id]);
}
/**
@@ -129,7 +129,7 @@ class DeliveryData
*/
public static function incrementQueueCount(int $uri_id, int $increment = 1)
{
- return DBA::e('UPDATE `post-delivery-data` SET `queue_count` = `queue_count` + ? WHERE `uri-id` = ?', $increment, $uri_id);
+ return DBA::update('post-delivery-data', ["`queue_count` = `queue_count` + $increment"], ['uri-id' => $uri_id]);
}
/**
diff --git a/src/Model/User.php b/src/Model/User.php
index 11d55e7f7..3be13bebf 100644
--- a/src/Model/User.php
+++ b/src/Model/User.php
@@ -167,7 +167,7 @@ class User
$system['region'] = '';
$system['postal-code'] = '';
$system['country-name'] = '';
- $system['homepage'] = DI::baseUrl();
+ $system['homepage'] = (string)DI::baseUrl();
$system['dob'] = '0000-00-00';
// Ensure that the user contains data
diff --git a/src/Module/BaseSearch.php b/src/Module/BaseSearch.php
index 675deb8fb..262ec94a2 100644
--- a/src/Module/BaseSearch.php
+++ b/src/Module/BaseSearch.php
@@ -23,6 +23,7 @@ namespace Friendica\Module;
use Friendica\BaseModule;
use Friendica\Content\Pager;
+use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\Search;
use Friendica\DI;
@@ -62,18 +63,13 @@ class BaseSearch extends BaseModule
}
$header = '';
+ $results = new ResultList();
if (strpos($search, '@') === 0) {
$search = trim(substr($search, 1));
$type = Search::TYPE_PEOPLE;
$header = DI::l10n()->t('People Search - %s', $search);
-
- if (strrpos($search, '@') > 0) {
- $results = Search::getContactsFromProbe(Network::convertToIdn($search));
- }
- }
-
- if (strpos($search, '!') === 0) {
+ } elseif (strpos($search, '!') === 0) {
$search = trim(substr($search, 1));
$type = Search::TYPE_FORUM;
$header = DI::l10n()->t('Forum Search - %s', $search);
@@ -91,14 +87,18 @@ class BaseSearch extends BaseModule
$pager = new Pager(DI::l10n(), DI::args()->getQueryString(), $itemsPerPage);
- if ($localSearch && empty($results)) {
- $pager->setItemsPerPage(80);
- $results = Search::getContactsFromLocalDirectory($search, $type, $pager->getStart(), $pager->getItemsPerPage());
- } elseif (Search::getGlobalDirectory() && empty($results)) {
+ if (!$results->getTotal() && !$localSearch && Search::getGlobalDirectory()) {
$results = Search::getContactsFromGlobalDirectory($search, $type, $pager->getPage());
$pager->setItemsPerPage($results->getItemsPage());
- } else {
- $results = new ResultList();
+ }
+
+ if (!$results->getTotal()) {
+ $pager->setItemsPerPage(80);
+ $results = Search::getContactsFromLocalDirectory($search, $type, $pager->getStart(), $pager->getItemsPerPage());
+ }
+
+ if (!$results->getTotal()) {
+ $results = Search::getContactsFromProbe(Network::convertToIdn($search), $type == Search::TYPE_FORUM);
}
return self::printResult($results, $pager, $header);
@@ -151,4 +151,4 @@ class BaseSearch extends BaseModule
'$paginate' => $pager->renderFull($results->getTotal()),
]);
}
-}
+}
\ No newline at end of file
diff --git a/src/Module/HCard.php b/src/Module/HCard.php
index 92627125a..ce63d77c3 100644
--- a/src/Module/HCard.php
+++ b/src/Module/HCard.php
@@ -64,9 +64,9 @@ class HCard extends BaseModule
$page['htmlhead'] .= '' . "\r\n";
}
- $baseUrl = DI::baseUrl();
+ $baseUrl = (string)DI::baseUrl();
- $uri = urlencode('acct:' . $profile['nickname'] . '@' . $baseUrl->getHost() . ($baseUrl->getPath() ? '/' . $baseUrl->getPath() : ''));
+ $uri = urlencode('acct:' . $profile['nickname'] . '@' . DI::baseUrl()->getHost() . (DI::baseUrl()->getPath() ? '/' . DI::baseUrl()->getPath() : ''));
$page['htmlhead'] .= '' . "\r\n";
$page['htmlhead'] .= '' . "\r\n";
diff --git a/src/Module/Magic.php b/src/Module/Magic.php
index 0f710b6a0..5276252de 100644
--- a/src/Module/Magic.php
+++ b/src/Module/Magic.php
@@ -21,6 +21,7 @@
namespace Friendica\Module;
+use Exception;
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\L10n;
@@ -30,7 +31,6 @@ use Friendica\Database\Database;
use Friendica\Model\Contact;
use Friendica\Model\User;
use Friendica\Network\HTTPClient\Capability\ICanSendHttpRequests;
-use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Util\HTTPSignature;
use Friendica\Util\Profiler;
@@ -65,120 +65,102 @@ class Magic extends BaseModule
protected function rawContent(array $request = [])
{
- $this->logger->info('magic module: invoked');
+ if ($_SERVER['REQUEST_METHOD'] == 'HEAD') {
+ $this->logger->debug('Got a HEAD request');
+ System::exit();
+ }
- $this->logger->debug('args', ['request' => $_REQUEST]);
+ $this->logger->debug('Invoked', ['request' => $request]);
$addr = $request['addr'] ?? '';
$dest = $request['dest'] ?? '';
$bdest = $request['bdest'] ?? '';
$owa = intval($request['owa'] ?? 0);
- $cid = 0;
- // bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing
+ // bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing
if (!empty($bdest)) {
$dest = hex2bin($bdest);
- $this->logger->info('bdest detected. ', ['dest' => $dest]);
+ $this->logger->debug('bdest detected', ['dest' => $dest]);
}
- if (!empty($addr)) {
- $cid = Contact::getIdForURL($addr);
- } elseif (!empty($dest)) {
- $cid = Contact::getIdForURL($dest);
- }
- $this->logger->info('Contact ID: ', ['cid' => $cid]);
-
- $contact = false;
- if (!$cid) {
- $this->logger->info('No contact record found', $_REQUEST);
+ if ($addr ?: $dest) {
+ $contact = Contact::getByURL($addr ?: $dest);
+ }
+
+ if (empty($contact)) {
if (!$owa) {
- // @TODO Finding a more elegant possibility to redirect to either internal or external URL
+ $this->logger->info('No contact record found, no oWA, redirecting to destination.', ['request' => $request, 'server' => $_SERVER, 'dest' => $dest]);
$this->app->redirect($dest);
}
} else {
- $contact = $this->dba->selectFirst('contact', ['id', 'nurl', 'url'], ['id' => $cid]);
-
// Redirect if the contact is already authenticated on this site.
if ($this->app->getContactId() && strpos($contact['nurl'], Strings::normaliseLink($this->baseUrl)) !== false) {
- $this->logger->info('Contact is already authenticated');
+ $this->logger->info('Contact is already authenticated, redirecting to destination.', ['dest' => $dest]);
System::externalRedirect($dest);
}
- $this->logger->info('Contact URL: ', ['url' => $contact['url']]);
+ $this->logger->debug('Contact found', ['url' => $contact['url']]);
+ }
+
+ if (!$this->userSession->getLocalUserId() || !$owa) {
+ $this->logger->notice('Not logged in or not OWA, redirecting to destination.', ['uid' => $this->userSession->getLocalUserId(), 'owa' => $owa, 'dest' => $dest]);
+ $this->app->redirect($dest);
}
// OpenWebAuth
- if ($this->userSession->getLocalUserId() && $owa) {
- $this->logger->info('Checking OWA now');
- $user = User::getById($this->userSession->getLocalUserId());
+ $owner = User::getOwnerDataById($this->userSession->getLocalUserId());
- $basepath = false;
- if (!empty($contact)) {
- $this->logger->info('Contact found - trying friendica style basepath extraction');
- // Extract the basepath
- // NOTE: we need another solution because this does only work
- // for friendica contacts :-/ . We should have the basepath
- // of a contact also in the contact table.
- $contact_url = $contact['url'];
- if (!(strpos($contact_url, '/profile/') === false)) {
- $exp = explode('/profile/', $contact['url']);
- $basepath = $exp[0];
- $this->logger->info('Basepath: ', ['basepath' => $basepath]);
- } else {
- $this->logger->info('Not possible to extract basepath in friendica style');
- }
- }
- if (!$basepath) {
- // For the rest of the OpenWebAuth-enabled Fediverse
- $parsed = parse_url($dest);
- $this->logger->info('Parsed URL: ', ['parsed URL' => $parsed]);
- if (!$parsed) {
- System::externalRedirect($dest);
- }
- $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (isset($parsed['port']) ? ':' . $parsed['port'] : '');
- }
-
- $accept_headers = ['application/x-dfrn+json', 'application/x-zot+json'];
- $header = [
- 'Accept' => $accept_headers,
- 'X-Open-Web-Auth' => [Strings::getRandomHex()],
- ];
-
- // Create a header that is signed with the local users private key.
- $header = HTTPSignature::createSig(
- $header,
- $user['prvkey'],
- 'acct:' . $user['nickname'] . '@' . $this->baseUrl->getHost() . ($this->baseUrl->getPath() ? '/' . $this->baseUrl->getPath() : '')
- );
-
- $this->logger->info('Headers: ', ['headers' => $header]);
-
- // Try to get an authentication token from the other instance.
- $curlResult = $this->httpClient->get($basepath . '/owa', HttpClientAccept::DEFAULT, [HttpClientOptions::HEADERS => $header, HttpClientOptions::ACCEPT_CONTENT => $accept_headers]);
-
- if ($curlResult->isSuccess()) {
- $j = json_decode($curlResult->getBody(), true);
- $this->logger->info('Curl result body: ', ['body' => $j]);
-
- if ($j['success']) {
- $token = '';
- if ($j['encrypted_token']) {
- // The token is encrypted. If the local user is really the one the other instance
- // thinks he/she is, the token can be decrypted with the local users public key.
- openssl_private_decrypt(Strings::base64UrlDecode($j['encrypted_token']), $token, $user['prvkey']);
- } else {
- $token = $j['token'];
- }
- $args = (strpbrk($dest, '?&') ? '&' : '?') . 'owt=' . $token;
-
- $this->logger->info('Redirecting', ['path' => $dest . $args]);
- System::externalRedirect($dest . $args);
- }
- }
+ $gserver = $this->dba->selectFirst('gserver', ['url'], ['id' => $contact['gsid']]);
+ if (empty($gserver)) {
+ $this->logger->notice('Server not found, redirecting to destination.', ['gsid' => $contact['gsid'], 'dest' => $dest]);
System::externalRedirect($dest);
}
- // @TODO Finding a more elegant possibility to redirect to either internal or external URL
- $this->app->redirect($dest);
+ $basepath = $gserver['url'];
+
+ $header = [
+ 'Accept' => ['application/x-dfrn+json', 'application/x-zot+json'],
+ 'X-Open-Web-Auth' => [Strings::getRandomHex()],
+ ];
+
+ // Create a header that is signed with the local users private key.
+ $header = HTTPSignature::createSig(
+ $header,
+ $owner['prvkey'],
+ 'acct:' . $owner['addr']
+ );
+
+ $this->logger->info('Fetch from remote system', ['basepath' => $basepath, 'headers' => $header]);
+
+ // Try to get an authentication token from the other instance.
+ try {
+ $curlResult = $this->httpClient->request('get', $basepath . '/owa', [HttpClientOptions::HEADERS => $header]);
+ } catch (Exception $exception) {
+ $this->logger->notice('URL is invalid, redirecting to destination.', ['url' => $basepath, 'error' => $exception, 'dest' => $dest]);
+ System::externalRedirect($dest);
+ }
+ if (!$curlResult->isSuccess()) {
+ $this->logger->notice('OWA request failed, redirecting to destination.', ['returncode' => $curlResult->getReturnCode(), 'dest' => $dest]);
+ System::externalRedirect($dest);
+ }
+
+ $j = json_decode($curlResult->getBody(), true);
+ if (empty($j) || !$j['success']) {
+ $this->logger->notice('Invalid JSON, redirecting to destination.', ['json' => $j, 'dest' => $dest]);
+ $this->app->redirect($dest);
+ }
+
+ if ($j['encrypted_token']) {
+ // The token is encrypted. If the local user is really the one the other instance
+ // thinks they is, the token can be decrypted with the local users public key.
+ $token = '';
+ openssl_private_decrypt(Strings::base64UrlDecode($j['encrypted_token']), $token, $owner['prvkey']);
+ } else {
+ $token = $j['token'];
+ }
+ $args = (strpbrk($dest, '?&') ? '&' : '?') . 'owt=' . $token;
+
+ $this->logger->debug('Redirecting', ['path' => $dest . $args]);
+ System::externalRedirect($dest . $args);
}
}
diff --git a/src/Module/OpenSearch.php b/src/Module/OpenSearch.php
index f01baafad..7c44bc510 100644
--- a/src/Module/OpenSearch.php
+++ b/src/Module/OpenSearch.php
@@ -40,7 +40,7 @@ class OpenSearch extends BaseModule
protected function rawContent(array $request = [])
{
$hostname = DI::baseUrl()->getHost();
- $baseUrl = DI::baseUrl();
+ $baseUrl = (string)DI::baseUrl();
/** @var DOMDocument $xml */
XML::fromArray([
diff --git a/src/Module/Register.php b/src/Module/Register.php
index e5c5840d2..d26fb0a3d 100644
--- a/src/Module/Register.php
+++ b/src/Module/Register.php
@@ -298,7 +298,7 @@ class Register extends BaseModule
$user = $result['user'];
- $base_url = DI::baseUrl();
+ $base_url = (string)DI::baseUrl();
if ($netpublish && intval(DI::config()->get('config', 'register_policy')) !== self::APPROVE) {
$url = $base_url . '/profile/' . $user['nickname'];
diff --git a/src/Module/WellKnown/HostMeta.php b/src/Module/WellKnown/HostMeta.php
index 75976ac36..eadc9f221 100644
--- a/src/Module/WellKnown/HostMeta.php
+++ b/src/Module/WellKnown/HostMeta.php
@@ -46,7 +46,7 @@ class HostMeta extends BaseModule
$config->set('system', 'site_pubkey', $res['pubkey']);
}
- $domain = DI::baseUrl();
+ $domain = (string)DI::baseUrl();
XML::fromArray([
'XRD' => [
diff --git a/src/Navigation/Notifications/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php
index b7a007a2f..45f450b1d 100644
--- a/src/Navigation/Notifications/Entity/Notify.php
+++ b/src/Navigation/Notifications/Entity/Notify.php
@@ -134,6 +134,6 @@ class Notify extends BaseEntity
*/
public static function formatMessage(string $name, string $message): string
{
- return str_replace('{0}', '' . strip_tags(BBCode::convert($name)) . '', $message);
+ return str_replace('{0}', '' . strip_tags(BBCode::convert($name)) . '', htmlspecialchars($message));
}
}
diff --git a/src/Protocol/ActivityPub/Queue.php b/src/Protocol/ActivityPub/Queue.php
index d77785fe6..beb8817bf 100644
--- a/src/Protocol/ActivityPub/Queue.php
+++ b/src/Protocol/ActivityPub/Queue.php
@@ -312,7 +312,7 @@ class Queue
// Optimizing this table only last seconds
if (DI::config()->get('system', 'optimize_tables')) {
Logger::info('Optimize start');
- DBA::e("OPTIMIZE TABLE `inbox-entry`");
+ DBA::optimizeTable('inbox-entry');
Logger::info('Optimize end');
}
}
diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php
index c24c29fee..3d945180a 100644
--- a/src/Protocol/ActivityPub/Transmitter.php
+++ b/src/Protocol/ActivityPub/Transmitter.php
@@ -330,7 +330,7 @@ class Transmitter
return [
'type' => 'Service',
'name' => App::PLATFORM . " '" . App::CODENAME . "' " . App::VERSION . '-' . DB_UPDATE_VERSION,
- 'url' => DI::baseUrl()
+ 'url' => (string)DI::baseUrl()
];
}
diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php
index d4eeae61e..fced3526d 100644
--- a/src/Protocol/Feed.php
+++ b/src/Protocol/Feed.php
@@ -478,7 +478,7 @@ class Feed
$attachments = [];
- $enclosures = $xpath->query("enclosure|' . $atomns . ':link[@rel='enclosure']", $entry);
+ $enclosures = $xpath->query("enclosure|$atomns:link[@rel='enclosure']", $entry);
if (!empty($enclosures)) {
foreach ($enclosures as $enclosure) {
$href = '';
diff --git a/src/Worker/Cron.php b/src/Worker/Cron.php
index 8c9ea58a1..73d158070 100644
--- a/src/Worker/Cron.php
+++ b/src/Worker/Cron.php
@@ -163,15 +163,6 @@ class Cron
{
Logger::info('Looking for sleeping processes');
- $processes = DBA::p("SHOW FULL PROCESSLIST");
- while ($process = DBA::fetch($processes)) {
- if (($process['Command'] != 'Sleep') || ($process['Time'] < 300) || ($process['db'] != DBA::databaseName())) {
- continue;
- }
-
- DBA::e("KILL ?", $process['Id']);
- Logger::notice('Killed sleeping process', ['id' => $process['Id']]);
- }
- DBA::close($processes);
+ DBA::deleteSleepingProcesses();
}
}
diff --git a/src/Worker/OptimizeTables.php b/src/Worker/OptimizeTables.php
index bb4cc9e48..784c72fde 100644
--- a/src/Worker/OptimizeTables.php
+++ b/src/Worker/OptimizeTables.php
@@ -40,36 +40,36 @@ class OptimizeTables
Logger::info('Optimize start');
- DBA::e("OPTIMIZE TABLE `cache`");
- DBA::e("OPTIMIZE TABLE `locks`");
- DBA::e("OPTIMIZE TABLE `oembed`");
- DBA::e("OPTIMIZE TABLE `parsed_url`");
- DBA::e("OPTIMIZE TABLE `session`");
+ DBA::optimizeTable('cache');
+ DBA::optimizeTable('locks');
+ DBA::optimizeTable('oembed');
+ DBA::optimizeTable('parsed_url');
+ DBA::optimizeTable('session');
if (DI::config()->get('system', 'optimize_all_tables')) {
- DBA::e("OPTIMIZE TABLE `apcontact`");
- DBA::e("OPTIMIZE TABLE `contact`");
- DBA::e("OPTIMIZE TABLE `contact-relation`");
- DBA::e("OPTIMIZE TABLE `conversation`");
- DBA::e("OPTIMIZE TABLE `diaspora-contact`");
- DBA::e("OPTIMIZE TABLE `diaspora-interaction`");
- DBA::e("OPTIMIZE TABLE `fcontact`");
- DBA::e("OPTIMIZE TABLE `gserver`");
- DBA::e("OPTIMIZE TABLE `gserver-tag`");
- DBA::e("OPTIMIZE TABLE `inbox-status`");
- DBA::e("OPTIMIZE TABLE `item-uri`");
- DBA::e("OPTIMIZE TABLE `notification`");
- DBA::e("OPTIMIZE TABLE `notify`");
- DBA::e("OPTIMIZE TABLE `photo`");
- DBA::e("OPTIMIZE TABLE `post`");
- DBA::e("OPTIMIZE TABLE `post-content`");
- DBA::e("OPTIMIZE TABLE `post-delivery-data`");
- DBA::e("OPTIMIZE TABLE `post-link`");
- DBA::e("OPTIMIZE TABLE `post-thread`");
- DBA::e("OPTIMIZE TABLE `post-thread-user`");
- DBA::e("OPTIMIZE TABLE `post-user`");
- DBA::e("OPTIMIZE TABLE `storage`");
- DBA::e("OPTIMIZE TABLE `tag`");
+ DBA::optimizeTable('apcontact');
+ DBA::optimizeTable('contact');
+ DBA::optimizeTable('contact-relation');
+ DBA::optimizeTable('conversation');
+ DBA::optimizeTable('diaspora-contact');
+ DBA::optimizeTable('diaspora-interaction');
+ DBA::optimizeTable('fcontact');
+ DBA::optimizeTable('gserver');
+ DBA::optimizeTable('gserver-tag');
+ DBA::optimizeTable('inbox-status');
+ DBA::optimizeTable('item-uri');
+ DBA::optimizeTable('notification');
+ DBA::optimizeTable('notify');
+ DBA::optimizeTable('photo');
+ DBA::optimizeTable('post');
+ DBA::optimizeTable('post-content');
+ DBA::optimizeTable('post-delivery-data');
+ DBA::optimizeTable('post-link');
+ DBA::optimizeTable('post-thread');
+ DBA::optimizeTable('post-thread-user');
+ DBA::optimizeTable('post-user');
+ DBA::optimizeTable('storage');
+ DBA::optimizeTable('tag');
}
Logger::info('Optimize end');
diff --git a/tests/datasets/api.fixture.php b/tests/datasets/api.fixture.php
index b50f70625..f5b16f9c6 100644
--- a/tests/datasets/api.fixture.php
+++ b/tests/datasets/api.fixture.php
@@ -35,6 +35,15 @@ return [
'workerqueue',
'mail',
'post-delivery-data',
+ 'gserver' => [
+ [
+ 'url' => 'https://friendica.local',
+ 'nurl' => 'http://friendica.local',
+ 'register_policy' => 0,
+ 'registered-users' => 0,
+ 'network' => 'unkn',
+ ],
+ ],
// Base test config to avoid notice messages
'user' => [
[
diff --git a/tests/src/Content/Text/BBCodeTest.php b/tests/src/Content/Text/BBCodeTest.php
index 74d34f5a5..889b12caa 100644
--- a/tests/src/Content/Text/BBCodeTest.php
+++ b/tests/src/Content/Text/BBCodeTest.php
@@ -259,12 +259,12 @@ Karl Marx - Die ursprüngliche Akkumulation
'text' => '[emoji=https://fedi.underscore.world/emoji/custom/custom/heart_nb.png]:heart_nb:[/emoji]',
],
'task-12900-multiple-paragraphs' => [
- 'expectedHTML' => '
Header
One
Two
This is a paragraph with a line feed.
Second Chapter
',
- 'text' => "[h1]Header[/h1][ul][*]One[*]Two[/ul]\n\nThis is a paragraph\nwith a line feed.\n\nSecond Chapter",
+ 'expectedHTML' => '
Header
One
Two
This is a paragraph with a line feed.
Second Chapter
',
+ 'text' => "[h4]Header[/h4][ul][*]One[*]Two[/ul]\n\nThis is a paragraph\nwith a line feed.\n\nSecond Chapter",
],
'task-12900-header-with-paragraphs' => [
- 'expectedHTML' => '