From d09ab35816fa31cec863626746aaa27b33c47fbe Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 22 Jul 2018 12:38:53 -0400 Subject: [PATCH 1/7] Fix getimagesizefromstring() read errors --- src/Object/Image.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Object/Image.php b/src/Object/Image.php index aafed8f95d..6a71038fad 100644 --- a/src/Object/Image.php +++ b/src/Object/Image.php @@ -782,6 +782,11 @@ class Image if (is_null($data) || !$data || !is_array($data)) { $img_str = Network::fetchUrl($url, true, $redirects, 4); + + if (!$img_str) { + return false; + } + $filesize = strlen($img_str); try { From 4e9ba728c450a4a95eeae0185451b9655e9e62b8 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 22 Jul 2018 12:41:48 -0400 Subject: [PATCH 2/7] Fix undefined index body in Model\Item --- src/Model/Item.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Model/Item.php b/src/Model/Item.php index bb53896efc..ea5abab452 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -2227,6 +2227,9 @@ class Item extends BaseObject */ private static function addLanguageToItemArray(&$item) { + // @TODO Find out why body can be empty here + $item['body'] = defaults($item, 'body', ''); + $naked_body = BBCode::toPlaintext($item['body'], false); $ld = new Text_LanguageDetect(); From 41fd5bef137fa2e2f52f6d7c07279f6d5f2334cd Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 22 Jul 2018 12:45:24 -0400 Subject: [PATCH 3/7] Fix by reference notice in Protocol\PortableContact --- src/Protocol/PortableContact.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Protocol/PortableContact.php b/src/Protocol/PortableContact.php index f1d878f5d6..7e4a94706a 100644 --- a/src/Protocol/PortableContact.php +++ b/src/Protocol/PortableContact.php @@ -1681,25 +1681,25 @@ class PortableContact } foreach ($data->entry as $entry) { - $username = ""; + $username = ''; if (isset($entry->urls)) { foreach ($entry->urls as $url) { if ($url->type == 'profile') { $profile_url = $url->value; - $urlparts = parse_url($profile_url); - $username = end(explode("/", $urlparts["path"])); + $path_array = explode('/', parse_url($profile_url, PHP_URL_PATH)); + $username = end($path_array); } } } - if ($username != "") { - logger("Fetch contacts for the user ".$username." from the server ".$server["nurl"], LOGGER_DEBUG); + if ($username != '') { + logger('Fetch contacts for the user ' . $username . ' from the server ' . $server['nurl'], LOGGER_DEBUG); // Fetch all contacts from a given user from the other server - $url = $server["poco"]."/".$username."/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation"; + $url = $server['poco'] . '/' . $username . '/?fields=displayName,urls,photos,updated,network,aboutMe,currentLocation,tags,gender,contactType,generation'; $retdata = Network::curl($url); - if ($retdata["success"]) { - self::discoverServer(json_decode($retdata["body"]), 3); + if ($retdata['success']) { + self::discoverServer(json_decode($retdata['body']), 3); } } } From adc47fc8eac02751a83918535fd4f6de99c1c883 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 22 Jul 2018 12:50:13 -0400 Subject: [PATCH 4/7] Fix Undefined index: nurl in Protocol\PortableContact --- src/Protocol/PortableContact.php | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Protocol/PortableContact.php b/src/Protocol/PortableContact.php index 7e4a94706a..a8bd28cb46 100644 --- a/src/Protocol/PortableContact.php +++ b/src/Protocol/PortableContact.php @@ -1647,27 +1647,33 @@ class PortableContact $no_of_queries = 5; - $requery_days = intval(Config::get("system", "poco_requery_days")); + $requery_days = intval(Config::get('system', 'poco_requery_days')); if ($requery_days == 0) { $requery_days = 7; } - $last_update = date("c", time() - (60 * 60 * 24 * $requery_days)); + $last_update = date('c', time() - (60 * 60 * 24 * $requery_days)); - $r = q("SELECT `id`, `url`, `nurl`, `network` FROM `gserver` WHERE `last_contact` >= `last_failure` AND `poco` != '' AND `last_poco_query` < '%s' ORDER BY RAND()", DBA::escape($last_update)); - if (DBA::isResult($r)) { - foreach ($r as $server) { - if (!self::checkServer($server["url"], $server["network"])) { + $gservers = q("SELECT `id`, `url`, `nurl`, `network` + FROM `gserver` + WHERE `last_contact` >= `last_failure` + AND `poco` != '' + AND `last_poco_query` < '%s' + ORDER BY RAND()", DBA::escape($last_update) + ); + if (DBA::isResult($gservers)) { + foreach ($gservers as $gserver) { + if (!self::checkServer($gserver['url'], $gserver['network'])) { // The server is not reachable? Okay, then we will try it later $fields = ['last_poco_query' => DateTimeFormat::utcNow()]; - DBA::update('gserver', $fields, ['nurl' => $server["nurl"]]); + DBA::update('gserver', $fields, ['nurl' => $gserver['nurl']]); continue; } - logger('Update directory from server '.$server['url'].' with ID '.$server['id'], LOGGER_DEBUG); - Worker::add(PRIORITY_LOW, "DiscoverPoCo", "update_server_directory", (int)$server['id']); + logger('Update directory from server ' . $gserver['url'] . ' with ID ' . $gserver['id'], LOGGER_DEBUG); + Worker::add(PRIORITY_LOW, 'DiscoverPoCo', 'update_server_directory', (int) $gserver['id']); - if (!$complete && (--$no_of_queries == 0)) { + if (!$complete && ( --$no_of_queries == 0)) { break; } } From df917251ff1ba8fee277e208742c1bcc3b5d38a9 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 22 Jul 2018 13:01:53 -0400 Subject: [PATCH 5/7] Fix undefined oembed properties - Add Object\OEmbed class --- src/Content/OEmbed.php | 173 ++++++++++++++++++++--------------------- src/Object/OEmbed.php | 50 ++++++++++++ 2 files changed, 134 insertions(+), 89 deletions(-) create mode 100644 src/Object/OEmbed.php diff --git a/src/Content/OEmbed.php b/src/Content/OEmbed.php index e2f3a31a1b..64ddc64f03 100644 --- a/src/Content/OEmbed.php +++ b/src/Content/OEmbed.php @@ -19,7 +19,6 @@ use Friendica\Database\DBA; use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use Friendica\Util\ParseUrl; -use stdClass; require_once 'include/dba.php'; require_once 'mod/proxy.php'; @@ -48,132 +47,128 @@ class OEmbed /** * @brief Get data from an URL to embed its content. * - * @param string $embedurl The URL from which the data should be fetched. - * @param bool $no_rich_type If set to true rich type content won't be fetched. + * @param string $embedurl The URL from which the data should be fetched. + * @param bool $no_rich_type If set to true rich type content won't be fetched. * - * @return bool|object Returns object with embed content or false if no embeddable - * content exists + * @return \Friendica\Object\OEmbed */ public static function fetchURL($embedurl, $no_rich_type = false) { - $embedurl = trim($embedurl, "'"); - $embedurl = trim($embedurl, '"'); + $embedurl = trim($embedurl, '\'"'); $a = get_app(); + $cache_key = 'oembed:' . $a->videowidth . ':' . $embedurl; + $condition = ['url' => normalise_link($embedurl), 'maxwidth' => $a->videowidth]; - $oembed = DBA::selectFirst('oembed', ['content'], $condition); - if (DBA::isResult($oembed)) { - $txt = $oembed["content"]; + $oembed_record = DBA::selectFirst('oembed', ['content'], $condition); + if (DBA::isResult($oembed_record)) { + $json_string = $oembed_record['content']; } else { - $txt = Cache::get($a->videowidth . $embedurl); + $json_string = Cache::get($cache_key); } + // These media files should now be caught in bbcode.php // left here as a fallback in case this is called from another source - - $noexts = ["mp3", "mp4", "ogg", "ogv", "oga", "ogm", "webm"]; + $noexts = ['mp3', 'mp4', 'ogg', 'ogv', 'oga', 'ogm', 'webm']; $ext = pathinfo(strtolower($embedurl), PATHINFO_EXTENSION); + $oembed = new \Friendica\Object\OEmbed($embedurl); - if (is_null($txt)) { - $txt = ""; + if ($json_string) { + $oembed->parseJSON($json_string); + } else { + $json_string = ''; if (!in_array($ext, $noexts)) { // try oembed autodiscovery $redirects = 0; - $html_text = Network::fetchUrl($embedurl, false, $redirects, 15, "text/*"); + $html_text = Network::fetchUrl($embedurl, false, $redirects, 15, 'text/*'); if ($html_text) { $dom = @DOMDocument::loadHTML($html_text); if ($dom) { $xpath = new DOMXPath($dom); $entries = $xpath->query("//link[@type='application/json+oembed']"); foreach ($entries as $e) { - $href = $e->getAttributeNode("href")->nodeValue; - $txt = Network::fetchUrl($href . '&maxwidth=' . $a->videowidth); + $href = $e->getAttributeNode('href')->nodeValue; + $json_string = Network::fetchUrl($href . '&maxwidth=' . $a->videowidth); break; } + $entries = $xpath->query("//link[@type='text/json+oembed']"); foreach ($entries as $e) { - $href = $e->getAttributeNode("href")->nodeValue; - $txt = Network::fetchUrl($href . '&maxwidth=' . $a->videowidth); + $href = $e->getAttributeNode('href')->nodeValue; + $json_string = Network::fetchUrl($href . '&maxwidth=' . $a->videowidth); break; } } } } - $txt = trim($txt); + $json_string = trim($json_string); - if (!$txt || $txt[0] != "{") { - $txt = '{"type":"error"}'; - } else { //save in cache - $j = json_decode($txt); - if (!empty($j->type) && $j->type != "error") { - DBA::insert('oembed', [ - 'url' => normalise_link($embedurl), - 'maxwidth' => $a->videowidth, - 'content' => $txt, - 'created' => DateTimeFormat::utcNow() - ], true); - } - - Cache::set($a->videowidth . $embedurl, $txt, CACHE_DAY); + if (!$json_string || $json_string[0] != '{') { + $json_string = '{"type":"error"}'; } + + $oembed->parseJSON($json_string); + if (!empty($oembed->type) && $oembed->type != 'error') { + DBA::insert('oembed', [ + 'url' => normalise_link($embedurl), + 'maxwidth' => $a->videowidth, + 'content' => $json_string, + 'created' => DateTimeFormat::utcNow() + ], true); + } + + Cache::set($cache_key, $json_string, CACHE_DAY); } - $j = json_decode($txt); - - if (!is_object($j)) { - return false; + if ($oembed->type == 'error') { + return $oembed; } // Always embed the SSL version - if (isset($j->html)) { - $j->html = str_replace(["http://www.youtube.com/", "http://player.vimeo.com/"], ["https://www.youtube.com/", "https://player.vimeo.com/"], $j->html); - } - - $j->embedurl = $embedurl; + $oembed->html = str_replace(['http://www.youtube.com/', 'http://player.vimeo.com/'], ['https://www.youtube.com/', 'https://player.vimeo.com/'], $oembed->html); // If fetching information doesn't work, then improve via internal functions - if ($no_rich_type && ($j->type == "rich")) { + if ($no_rich_type && ($oembed->type == 'rich')) { $data = ParseUrl::getSiteinfoCached($embedurl, true, false); - $j->type = $data["type"]; + $oembed->type = $data['type']; - if ($j->type == "photo") { - $j->url = $data["url"]; + if ($oembed->type == 'photo') { + $oembed->url = $data['url']; } - if (isset($data["title"])) { - $j->title = $data["title"]; + if (isset($data['title'])) { + $oembed->title = $data['title']; } - if (isset($data["text"])) { - $j->description = $data["text"]; + if (isset($data['text'])) { + $oembed->description = $data['text']; } - if (is_array($data["images"])) { - $j->thumbnail_url = $data["images"][0]["src"]; - $j->thumbnail_width = $data["images"][0]["width"]; - $j->thumbnail_height = $data["images"][0]["height"]; + if (is_array($data['images'])) { + $oembed->thumbnail_url = $data['images'][0]['src']; + $oembed->thumbnail_width = $data['images'][0]['width']; + $oembed->thumbnail_height = $data['images'][0]['height']; } } - Addon::callHooks('oembed_fetch_url', $embedurl, $j); + Addon::callHooks('oembed_fetch_url', $embedurl, $oembed); - return $j; + return $oembed; } - private static function formatObject(stdClass $j) + private static function formatObject(\Friendica\Object\OEmbed $oembed) { - $embedurl = $j->embedurl; - $jhtml = $j->html; - $ret = '
'; + $ret = '
'; - switch ($j->type) { + switch ($oembed->type) { case "video": - if (isset($j->thumbnail_url)) { - $tw = (isset($j->thumbnail_width) && intval($j->thumbnail_width)) ? $j->thumbnail_width : 200; - $th = (isset($j->thumbnail_height) && intval($j->thumbnail_height)) ? $j->thumbnail_height : 180; + if ($oembed->thumbnail_url) { + $tw = (isset($oembed->thumbnail_width) && intval($oembed->thumbnail_width)) ? $oembed->thumbnail_width : 200; + $th = (isset($oembed->thumbnail_height) && intval($oembed->thumbnail_height)) ? $oembed->thumbnail_height : 180; // make sure we don't attempt divide by zero, fallback is a 1:1 ratio $tr = (($th) ? $tw / $th : 1); @@ -182,63 +177,63 @@ class OEmbed $tpl = get_markup_template('oembed_video.tpl'); $ret .= replace_macros($tpl, [ '$baseurl' => System::baseUrl(), - '$embedurl' => $embedurl, - '$escapedhtml' => base64_encode($jhtml), + '$embedurl' => $oembed->embed_url, + '$escapedhtml' => base64_encode($oembed->html), '$tw' => $tw, '$th' => $th, - '$turl' => $j->thumbnail_url, + '$turl' => $oembed->thumbnail_url, ]); } else { - $ret = $jhtml; + $ret = $oembed->html; } break; case "photo": - $ret .= ''; + $ret .= ''; break; case "link": break; case "rich": - $ret .= proxy_parse_html($jhtml); + $ret .= proxy_parse_html($oembed->html); break; } // add link to source if not present in "rich" type - if ($j->type != 'rich' || !strpos($j->html, $embedurl)) { + if ($oembed->type != 'rich' || !strpos($oembed->html, $oembed->embed_url)) { $ret .= '

'; - if (!empty($j->title)) { - if (!empty($j->provider_name)) { - $ret .= $j->provider_name . ": "; + if (!empty($oembed->title)) { + if (!empty($oembed->provider_name)) { + $ret .= $oembed->provider_name . ": "; } - $ret .= '' . $j->title . ''; - if (!empty($j->author_name)) { - $ret .= ' (' . $j->author_name . ')'; + $ret .= '' . $oembed->title . ''; + if (!empty($oembed->author_name)) { + $ret .= ' (' . $oembed->author_name . ')'; } - } elseif (!empty($j->provider_name) || !empty($j->author_name)) { + } elseif (!empty($oembed->provider_name) || !empty($oembed->author_name)) { $embedlink = ""; - if (!empty($j->provider_name)) { - $embedlink .= $j->provider_name; + if (!empty($oembed->provider_name)) { + $embedlink .= $oembed->provider_name; } - if (!empty($j->author_name)) { + if (!empty($oembed->author_name)) { if ($embedlink != "") { $embedlink .= ": "; } - $embedlink .= $j->author_name; + $embedlink .= $oembed->author_name; } if (trim($embedlink) == "") { - $embedlink = $embedurl; + $embedlink = $oembed->embed_url; } - $ret .= '' . $embedlink . ''; + $ret .= '' . $embedlink . ''; } else { - $ret .= '' . $embedurl . ''; + $ret .= '' . $oembed->embed_url . ''; } $ret .= "

"; - } elseif (!strpos($j->html, $embedurl)) { + } elseif (!strpos($oembed->html, $oembed->embed_url)) { // add for html2bbcode conversion - $ret .= '' . $j->title . ''; + $ret .= '' . $oembed->title . ''; } $ret .= '
'; diff --git a/src/Object/OEmbed.php b/src/Object/OEmbed.php new file mode 100644 index 0000000000..3eebcc2265 --- /dev/null +++ b/src/Object/OEmbed.php @@ -0,0 +1,50 @@ + + */ +class OEmbed +{ + public $embed_url = ''; + + public $type = ''; + public $title = ''; + public $author_name = ''; + public $author_url = ''; + public $provider_name = ''; + public $provider_url = ''; + public $cache_age = ''; + public $thumbnail_url = ''; + public $thumbnail_width = ''; + public $thumbnail_height = ''; + public $html = ''; + public $url = ''; + public $width = ''; + public $height = ''; + + public function __construct($embed_url) + { + $this->embed_url = $embed_url; + } + + public function parseJSON($json_string) + { + $properties = json_decode($json_string, true); + + if (empty($properties)) { + return; + } + + foreach ($properties as $key => $value) { + if (property_exists(__CLASS__, $key)) { + $this->{$key} = $value; + } + } + } +} From b6e3da844313a5877d61d07d08367022ef9576c2 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 24 Jul 2018 08:52:25 -0400 Subject: [PATCH 6/7] Move addLanguageToItemArray call when body is ensured --- src/Model/Item.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index ea5abab452..8c803fff96 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -1330,8 +1330,6 @@ class Item extends BaseObject $item['uri-hash'] = $existing['uri-hash']; } - self::addLanguageToItemArray($item); - $item['wall'] = intval(defaults($item, 'wall', 0)); $item['extid'] = trim(defaults($item, 'extid', '')); $item['author-name'] = trim(defaults($item, 'author-name', '')); @@ -1383,6 +1381,8 @@ class Item extends BaseObject return 0; } + self::addLanguageToItemArray($item); + // Items cannot be stored before they happen ... if ($item['created'] > DateTimeFormat::utcNow()) { $item['created'] = DateTimeFormat::utcNow(); @@ -2227,9 +2227,6 @@ class Item extends BaseObject */ private static function addLanguageToItemArray(&$item) { - // @TODO Find out why body can be empty here - $item['body'] = defaults($item, 'body', ''); - $naked_body = BBCode::toPlaintext($item['body'], false); $ld = new Text_LanguageDetect(); From 677152216735cba287154c7a44bd75d6eeae67e4 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Tue, 24 Jul 2018 11:05:09 -0400 Subject: [PATCH 7/7] Reduce cache time for OEmbed error --- src/Content/OEmbed.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Content/OEmbed.php b/src/Content/OEmbed.php index 64ddc64f03..a1fe4f3064 100644 --- a/src/Content/OEmbed.php +++ b/src/Content/OEmbed.php @@ -112,6 +112,7 @@ class OEmbed } $oembed->parseJSON($json_string); + if (!empty($oembed->type) && $oembed->type != 'error') { DBA::insert('oembed', [ 'url' => normalise_link($embedurl), @@ -119,9 +120,12 @@ class OEmbed 'content' => $json_string, 'created' => DateTimeFormat::utcNow() ], true); + $cache_ttl = CACHE_DAY; + } else { + $cache_ttl = CACHE_FIVE_MINUTES; } - Cache::set($cache_key, $json_string, CACHE_DAY); + Cache::set($cache_key, $json_string, $cache_ttl); } if ($oembed->type == 'error') {