diff --git a/classes/config.php b/classes/config.php index 1c65fc76f..2c78b908d 100644 --- a/classes/config.php +++ b/classes/config.php @@ -6,7 +6,7 @@ class Config { const T_STRING = 2; const T_INT = 3; - const SCHEMA_VERSION = 145; + const SCHEMA_VERSION = 146; /** override default values, defined below in _DEFAULTS[], prefixing with _ENVVAR_PREFIX: * diff --git a/classes/errors.php b/classes/errors.php index 31be558cf..aa626d017 100644 --- a/classes/errors.php +++ b/classes/errors.php @@ -14,4 +14,27 @@ class Errors { static function to_json(string $code, array $params = []): string { return json_encode(["error" => ["code" => $code, "params" => $params]]); } + + static function libxml_last_error() : string { + $error = libxml_get_last_error(); + $error_formatted = ""; + + if ($error) { + foreach (libxml_get_errors() as $error) { + if ($error->level == LIBXML_ERR_FATAL) { + // currently only the first error is reported + $error_formatted = self::format_libxml_error($error); + break; + } + } + } + + return UConverter::transcode($error_formatted, 'UTF-8', 'UTF-8'); + } + + static function format_libxml_error(LibXMLError $error) : string { + return sprintf("LibXML error %s at line %d (column %d): %s", + $error->code, $error->line, $error->column, + $error->message); + } } diff --git a/classes/feedparser.php b/classes/feedparser.php index 6ce69cc89..3ed0647d2 100644 --- a/classes/feedparser.php +++ b/classes/feedparser.php @@ -193,10 +193,9 @@ class FeedParser { } } + /** @deprecated use Errors::format_libxml_error() instead */ function format_error(LibXMLError $error) : string { - return sprintf("LibXML error %s at line %d (column %d): %s", - $error->code, $error->line, $error->column, - $error->message); + return Errors::format_libxml_error($error); } // libxml may have invalid unicode data in error messages diff --git a/classes/feeds.php b/classes/feeds.php index a9afb70f2..2c37d659a 100755 --- a/classes/feeds.php +++ b/classes/feeds.php @@ -133,7 +133,7 @@ class Feeds extends Handler_Protected { $reply['vfeed_group_enabled'] = $vfeed_group_enabled; $plugin_menu_items = ""; - PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM, + PluginHost::getInstance()->chain_hooks_callback(PluginHost::HOOK_HEADLINE_TOOLBAR_SELECT_MENU_ITEM2, function ($result) use (&$plugin_menu_items) { $plugin_menu_items .= $result; }, @@ -254,6 +254,10 @@ class Feeds extends Handler_Protected { $line["buttons_left"] .= $button_doc->saveXML($button_doc->firstChild); } + } else if ($result) { + user_error(get_class($plugin) . + " plugin: content provided in HOOK_ARTICLE_LEFT_BUTTON is not valid XML: " . + Errors::libxml_last_error() . " $result", E_USER_WARNING); } }, $line); @@ -273,6 +277,10 @@ class Feeds extends Handler_Protected { $line["buttons"] .= $button_doc->saveXML($button_doc->firstChild); } + } else if ($result) { + user_error(get_class($plugin) . + " plugin: content provided in HOOK_ARTICLE_BUTTON is not valid XML: " . + Errors::libxml_last_error() . " $result", E_USER_WARNING); } }, $line); @@ -718,7 +726,7 @@ class Feeds extends Handler_Protected {
@@ -955,7 +963,8 @@ class Feeds extends Handler_Protected { $sth->execute([$owner_uid, $feed]); $row = $sth->fetch(); - return $row["count"]; + // Handle 'SUM()' returning null if there are no results + return $row["count"] ?? 0; } else if ($n_feed == -1) { $match_part = "marked = true"; @@ -1359,7 +1368,8 @@ class Feeds extends Handler_Protected { $sth->execute([$user_id]); $row = $sth->fetch(); - return $row["count"]; + // Handle 'SUM()' returning null if there are no articles/results (e.g. admin user with no feeds) + return $row["count"] ?? 0; } static function _get_cat_title(int $cat_id): string { @@ -2132,7 +2142,7 @@ class Feeds extends Handler_Protected { $owner_uid = $row["owner_uid"]; if (Config::get(Config::FORCE_ARTICLE_PURGE) != 0) { - Debug::log("purge_feed: FORCE_ARTICLE_PURGE is set, overriding interval to " . Config::get(Config::FORCE_ARTICLE_PURGE), Debug::$LOG_VERBOSE); + Debug::log("purge_feed: FORCE_ARTICLE_PURGE is set, overriding interval to " . Config::get(Config::FORCE_ARTICLE_PURGE), Debug::LOG_VERBOSE); $purge_unread = true; $purge_interval = Config::get(Config::FORCE_ARTICLE_PURGE); } else { @@ -2141,10 +2151,10 @@ class Feeds extends Handler_Protected { $purge_interval = (int) $purge_interval; - Debug::log("purge_feed: interval $purge_interval days for feed $feed_id, owner: $owner_uid, purge unread: $purge_unread", Debug::$LOG_VERBOSE); + Debug::log("purge_feed: interval $purge_interval days for feed $feed_id, owner: $owner_uid, purge unread: $purge_unread", Debug::LOG_VERBOSE); if ($purge_interval <= 0) { - Debug::log("purge_feed: purging disabled for this feed, nothing to do.", Debug::$LOG_VERBOSE); + Debug::log("purge_feed: purging disabled for this feed, nothing to do.", Debug::LOG_VERBOSE); return null; } @@ -2177,10 +2187,10 @@ class Feeds extends Handler_Protected { $rows_deleted = $sth->rowCount(); - Debug::log("purge_feed: deleted $rows_deleted articles.", Debug::$LOG_VERBOSE); + Debug::log("purge_feed: deleted $rows_deleted articles.", Debug::LOG_VERBOSE); } else { - Debug::log("purge_feed: owner of $feed_id not found", Debug::$LOG_VERBOSE); + Debug::log("purge_feed: owner of $feed_id not found", Debug::LOG_VERBOSE); } return $rows_deleted; diff --git a/classes/plugin.php b/classes/plugin.php index be8376925..39af6a9a1 100644 --- a/classes/plugin.php +++ b/classes/plugin.php @@ -98,7 +98,7 @@ abstract class Plugin { /* GLOBAL hooks are invoked in global context, only available to system plugins (loaded via .env for all users) */ - /** Adds buttons for article (on the right) - e.g. mail, share, add note. + /** Adds buttons for article (on the right) - e.g. mail, share, add note. Generated markup must be valid XML. * @param array $line * @return string * @see PluginHost::HOOK_ARTICLE_BUTTON @@ -307,7 +307,7 @@ abstract class Plugin { return []; } - /** Adds per-article buttons on the left side + /** Adds per-article buttons on the left side. Generated markup must be valid XML. * @param array $row * @return string * @see PluginHost::HOOK_ARTICLE_LEFT_BUTTON @@ -647,6 +647,7 @@ abstract class Plugin { } /** Allows adding custom elements to headlines Select... dropdown + * @deprecated removed, see Plugin::hook_headline_toolbar_select_menu_item2() * @param int $feed_id * @param int $is_cat * @return string @@ -658,6 +659,18 @@ abstract class Plugin { return ""; } + /** Allows adding custom elements to headlines Select... select dropdown (