diff options
Diffstat (limited to 'p/api/fever.php')
| -rw-r--r-- | p/api/fever.php | 190 |
1 files changed, 107 insertions, 83 deletions
diff --git a/p/api/fever.php b/p/api/fever.php index 13907f16d..88bd05d81 100644 --- a/p/api/fever.php +++ b/p/api/fever.php @@ -17,7 +17,7 @@ require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader FreshRSS_Context::initSystem(); // check if API is enabled globally -if (!FreshRSS_Context::$system_conf->api_enabled) { +if (FreshRSS_Context::$system_conf == null || !FreshRSS_Context::$system_conf->api_enabled) { Minz_Log::warning('Fever API: service unavailable!'); Minz_Log::debug('Fever API: serviceUnavailable() ' . debugInfo(), API_LOG); header('HTTP/1.1 503 Service Unavailable'); @@ -29,12 +29,9 @@ Minz_Session::init('FreshRSS', true); // ================================================================================================ // <Debug> -$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1048576); +$ORIGINAL_INPUT = file_get_contents('php://input', false, null, 0, 1048576) ?: '';; -/** - * @return string - */ -function debugInfo() { +function debugInfo(): string { if (function_exists('getallheaders')) { $ALL_HEADERS = getallheaders(); } else { //nginx http://php.net/getallheaders#84262 @@ -62,8 +59,12 @@ function debugInfo() { //Minz_Log::debug(debugInfo(), API_LOG); // </Debug> -class FeverDAO extends Minz_ModelPdo +final class FeverDAO extends Minz_ModelPdo { + /** + * @param array<string|int> $values + * @param array<string,string|int> $bindArray + */ protected function bindParamArray(string $prefix, array $values, array &$bindArray): string { $str = ''; for ($i = 0; $i < count($values); $i++) { @@ -74,9 +75,11 @@ class FeverDAO extends Minz_ModelPdo } /** + * @param array<string|int> $feed_ids + * @param array<string> $entry_ids * @return FreshRSS_Entry[] */ - public function findEntries(array $feed_ids, array $entry_ids, string $max_id, string $since_id) { + public function findEntries(array $feed_ids, array $entry_ids, string $max_id, string $since_id): array { $values = array(); $order = ''; $entryDAO = FreshRSS_Factory::createEntryDao(); @@ -110,36 +113,34 @@ class FeverDAO extends Minz_ModelPdo $sql .= ' LIMIT 50'; $stm = $this->pdo->prepare($sql); - $stm->execute($values); - $result = $stm->fetchAll(PDO::FETCH_ASSOC); + if ($stm && $stm->execute($values)) { + $result = $stm->fetchAll(PDO::FETCH_ASSOC); - $entries = array(); - foreach ($result as $dao) { - $entries[] = FreshRSS_Entry::fromArray($dao); - } + $entries = array(); + foreach ($result as $dao) { + $entries[] = FreshRSS_Entry::fromArray($dao); + } - return $entries; + return $entries; + } + return []; } } /** * Class FeverAPI */ -class FeverAPI +final class FeverAPI { const API_LEVEL = 3; const STATUS_OK = 1; const STATUS_ERR = 0; - /** - * @var FreshRSS_EntryDAO|null - */ - private $entryDAO = null; + /** @var FreshRSS_EntryDAO */ + private $entryDAO; - /** - * @var FreshRSS_FeedDAO|null - */ - private $feedDAO = null; + /** @var FreshRSS_FeedDAO */ + private $feedDAO; /** * Authenticate the user @@ -148,6 +149,9 @@ class FeverAPI * your FreshRSS "username:your-api-password" combination */ private function authenticate(): bool { + if (FreshRSS_Context::$system_conf === null) { + throw new FreshRSS_Context_Exception('System configuration not initialised!'); + } FreshRSS_Context::$user_conf = null; Minz_Session::_param('currentUser'); $feverKey = empty($_POST['api_key']) ? '' : substr(trim($_POST['api_key']), 0, 128); @@ -176,16 +180,12 @@ class FeverAPI public function isAuthenticatedApiUser(): bool { $this->authenticate(); - - if (FreshRSS_Context::$user_conf !== null) { - return true; - } - - return false; + return FreshRSS_Context::$user_conf !== null; } /** * This does all the processing, since the fever api does not have a specific variable that specifies the operation + * @return array<string,mixed> * @throws Exception */ public function process(): array { @@ -226,37 +226,54 @@ class FeverAPI $response_arr['saved_item_ids'] = $this->getSavedItemIds(); } - $id = isset($_REQUEST['id']) ? '' . $_REQUEST['id'] : ''; - if (isset($_REQUEST['mark'], $_REQUEST['as'], $_REQUEST['id']) && ctype_digit($id)) { - $method_name = 'set' . ucfirst($_REQUEST['mark']) . 'As' . ucfirst($_REQUEST['as']); - $allowedMethods = array( - 'setFeedAsRead', 'setGroupAsRead', 'setItemAsRead', - 'setItemAsSaved', 'setItemAsUnread', 'setItemAsUnsaved' - ); - if (in_array($method_name, $allowedMethods)) { - switch (strtolower($_REQUEST['mark'])) { - case 'item': - $this->{$method_name}($id); - break; - case 'feed': - case 'group': - $before = $_REQUEST['before'] ?? ''; - $this->{$method_name}($id, $before); - break; - } + if (isset($_REQUEST['mark'], $_REQUEST['as'], $_REQUEST['id']) && ctype_digit($_REQUEST['id'])) { + $id = intval($_REQUEST['id']); + $before = intval($_REQUEST['before'] ?? '0'); + switch (strtolower($_REQUEST['mark'])) { + case 'item': + switch ($_REQUEST['as']) { + case 'read': + $this->setItemAsRead($id); + break; + case 'saved': + $this->setItemAsSaved($id); + break; + case 'unread': + $this->setItemAsUnread($id); + break; + case 'unsaved': + $this->setItemAsUnsaved($id); + break; + } + break; + case 'feed': + switch ($_REQUEST['as']) { + case 'read': + $this->setFeedAsRead($id, $before); + break; + } + break; + case 'group': + switch ($_REQUEST['as']) { + case 'read': + $this->setFeedAsRead($id, $before); + break; + } + break; + } - switch ($_REQUEST['as']) { - case 'read': - case 'unread': - $response_arr['unread_item_ids'] = $this->getUnreadItemIds(); - break; + switch ($_REQUEST['as']) { + case 'read': + case 'unread': + $response_arr['unread_item_ids'] = $this->getUnreadItemIds(); + break; - case 'saved': - case 'unsaved': - $response_arr['saved_item_ids'] = $this->getSavedItemIds(); - break; - } + case 'saved': + case 'unsaved': + $response_arr['saved_item_ids'] = $this->getSavedItemIds(); + break; } + } return $response_arr; @@ -264,6 +281,7 @@ class FeverAPI /** * Returns the complete JSON, with 'api_version' and status as 'auth'. + * @param array<string,mixed> $reply */ public function wrap(int $status, array $reply = array()): string { $arr = array('api_version' => self::API_LEVEL, 'auth' => $status); @@ -273,7 +291,7 @@ class FeverAPI $arr = array_merge($arr, $reply); } - return json_encode($arr); + return json_encode($arr) ?: ''; } /** @@ -292,6 +310,7 @@ class FeverAPI return $lastUpdate; } + /** @return array<array<string,string|int>> */ protected function getFeeds(): array { $feeds = array(); $myFeeds = $this->feedDAO->listFeeds(); @@ -312,6 +331,7 @@ class FeverAPI return $feeds; } + /** @return array<array<string,int|string>> */ protected function getGroups(): array { $groups = array(); @@ -329,12 +349,15 @@ class FeverAPI return $groups; } + /** @return array<array<string,int|string>> */ protected function getFavicons(): array { + if (FreshRSS_Context::$system_conf == null) { + return []; + } $favicons = array(); $salt = FreshRSS_Context::$system_conf->salt; $myFeeds = $this->feedDAO->listFeeds(); - /** @var FreshRSS_Feed $feed */ foreach ($myFeeds as $feed) { $id = hash('crc32b', $salt . $feed->url()); @@ -345,7 +368,7 @@ class FeverAPI $favicons[] = array( 'id' => $feed->id(), - 'data' => image_type_to_mime_type(exif_imagetype($filename)) . ';base64,' . base64_encode(file_get_contents($filename)) + 'data' => image_type_to_mime_type(exif_imagetype($filename) ?: 0) . ';base64,' . base64_encode(file_get_contents($filename) ?: '') ); } @@ -359,17 +382,19 @@ class FeverAPI return $this->entryDAO->count(); } + /** + * @return array<array<string,int|string>> + */ protected function getFeedsGroup(): array { $groups = array(); $ids = array(); $myFeeds = $this->feedDAO->listFeeds(); - /** @var FreshRSS_Feed $feed */ foreach ($myFeeds as $feed) { $ids[$feed->categoryId()][] = $feed->id(); } - foreach($ids as $category => $feedIds) { + foreach ($ids as $category => $feedIds) { $groups[] = array( 'group_id' => $category, 'feed_ids' => implode(',', $feedIds) @@ -381,13 +406,14 @@ class FeverAPI /** * AFAIK there is no 'hot links' alternative in FreshRSS + * @return array<string> */ protected function getLinks(): array { return array(); } /** - * @param array $ids + * @param array<string> $ids */ protected function entriesToIdList(array $ids = array()): string { return implode(',', array_values($ids)); @@ -398,10 +424,7 @@ class FeverAPI return $this->entriesToIdList($entries); } - /** - * @return string - */ - protected function getSavedItemIds() { + protected function getSavedItemIds(): string { $entries = $this->entryDAO->listIdsWhere('a', '', FreshRSS_Entry::STATE_FAVORITE, 'ASC', 0); return $this->entriesToIdList($entries); } @@ -409,31 +432,32 @@ class FeverAPI /** * @return integer|false */ - protected function setItemAsRead($id) { + protected function setItemAsRead(int $id) { return $this->entryDAO->markRead($id, true); } /** * @return integer|false */ - protected function setItemAsUnread($id) { + protected function setItemAsUnread(int $id) { return $this->entryDAO->markRead($id, false); } /** * @return integer|false */ - protected function setItemAsSaved($id) { + protected function setItemAsSaved(int $id) { return $this->entryDAO->markFavorite($id, true); } /** * @return integer|false */ - protected function setItemAsUnsaved($id) { + protected function setItemAsUnsaved(int $id) { return $this->entryDAO->markFavorite($id, false); } + /** @return array<array<string,string|int>> */ protected function getItems(): array { $feed_ids = array(); $entry_ids = array(); @@ -448,16 +472,16 @@ class FeverAPI if (isset($_REQUEST['group_ids'])) { $categoryDAO = FreshRSS_Factory::createCategoryDao(); $group_ids = explode(',', $_REQUEST['group_ids']); + $feeds = []; foreach ($group_ids as $id) { - /** @var FreshRSS_Category $category */ $category = $categoryDAO->searchById($id); //TODO: Transform to SQL query without loop! Consider FreshRSS_CategoryDAO::listCategories(true) - /** @var FreshRSS_Feed $feed */ - $feeds = []; + if ($category == null) { + continue; + } foreach ($category->feeds() as $feed) { $feeds[] = $feed->id(); } } - $feed_ids = array_unique($feeds); } } @@ -511,30 +535,30 @@ class FeverAPI /** * TODO replace by a dynamic fetch for id <= $before timestamp */ - protected function convertBeforeToId(string $beforeTimestamp): string { - return $beforeTimestamp == '0' ? '0' : $beforeTimestamp . '000000'; + protected function convertBeforeToId(int $beforeTimestamp): string { + return $beforeTimestamp == 0 ? '0' : $beforeTimestamp . '000000'; } /** * @return integer|false */ - protected function setFeedAsRead(string $id, string $before) { + protected function setFeedAsRead(int $id, int $before) { $before = $this->convertBeforeToId($before); - return $this->entryDAO->markReadFeed(intval($id), $before); + return $this->entryDAO->markReadFeed($id, $before); } /** * @return integer|false */ - protected function setGroupAsRead(string $id, string $before) { + protected function setGroupAsRead(int $id, int $before) { $before = $this->convertBeforeToId($before); // special case to mark all items as read - if ($id == '0') { + if ($id == 0) { return $this->entryDAO->markReadEntries($before); } - return $this->entryDAO->markReadCat(intval($id), $before); + return $this->entryDAO->markReadCat($id, $before); } } |
