]> git.mxchange.org Git - friendica.git/blobdiff - include/socgraph.php
The index mustn't be 192 characters long
[friendica.git] / include / socgraph.php
index db843614a4a2cda6c4ee4b1cd0152328f3aa3884..7a39e388be8bba407ef3ba73fe11a39c1ea070ce 100644 (file)
@@ -1,18 +1,22 @@
 <?php
 /**
  * @file include/socgraph.php
- * 
+ *
  * @todo Move GNU Social URL schemata (http://server.tld/user/number) to http://server.tld/username
  * @todo Fetch profile data from profile page for Redmatrix users
  * @todo Detect if it is a forum
  */
 
-require_once('include/datetime.php');
-require_once("include/Scrape.php");
-require_once("include/network.php");
-require_once("include/html2bbcode.php");
-require_once("include/Contact.php");
-require_once("include/Photo.php");
+use Friendica\App;
+use Friendica\Core\Config;
+use Friendica\Network\Probe;
+
+require_once 'include/datetime.php';
+require_once 'include/probe.php';
+require_once 'include/network.php';
+require_once 'include/html2bbcode.php';
+require_once 'include/Contact.php';
+require_once 'include/Photo.php';
 
 /**
  * @brief Fetch POCO data
@@ -172,10 +176,13 @@ function poco_load_worker($cid, $uid, $zcid, $url) {
                                "contact-type" => $contact_type,
                                "generation" => $generation);
 
-               if (sanitized_gcontact($gcontact)) {
+               try {
+                       $gcontact = sanitize_gcontact($gcontact);
                        $gcid = update_gcontact($gcontact);
 
                        link_gcontact($gcid, $uid, $cid, $zcid);
+               } catch (Exception $e) {
+                       logger($e->getMessage(), LOGGER_DEBUG);
                }
        }
        logger("poco_load: loaded $total entries",LOGGER_DEBUG);
@@ -191,6 +198,7 @@ function poco_load_worker($cid, $uid, $zcid, $url) {
  * @brief Sanitize the given gcontact data
  *
  * @param array $gcontact array with gcontact data
+ * @throw Exception
  *
  * Generation:
  *  0: No definition
@@ -200,20 +208,20 @@ function poco_load_worker($cid, $uid, $zcid, $url) {
  *  4: ...
  *
  */
-function sanitized_gcontact(&$gcontact) {
+function sanitize_gcontact($gcontact) {
 
        if ($gcontact['url'] == "") {
-               return false;
+               throw new Exception('URL is empty');
        }
 
        $urlparts = parse_url($gcontact['url']);
        if (!isset($urlparts["scheme"])) {
-               return false;
+               throw new Exception("This (".$gcontact['url'].") doesn't seem to be an url.");
        }
 
        if (in_array($urlparts["host"], array("www.facebook.com", "facebook.com", "twitter.com",
                                                "identi.ca", "alpha.app.net"))) {
-               return false;
+               throw new Exception('Contact from a non federated network ignored. ('.$gcontact['url'].')');
        }
 
        // Don't store the statusnet connector as network
@@ -252,6 +260,9 @@ function sanitized_gcontact(&$gcontact) {
                }
        }
 
+       $gcontact['server_url'] = '';
+       $gcontact['network'] = '';
+
        $x = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
                dbesc(normalise_link($gcontact['url']))
        );
@@ -263,19 +274,12 @@ function sanitized_gcontact(&$gcontact) {
                if ($gcontact['updated'] <= NULL_DATE) {
                        $gcontact['updated'] = $x[0]["updated"];
                }
-               if (!isset($gcontact['server_url'])) {
+               if (!isset($gcontact['server_url']) AND (normalise_link($x[0]["server_url"]) != normalise_link($x[0]["url"]))) {
                        $gcontact['server_url'] = $x[0]["server_url"];
                }
                if (!isset($gcontact['addr'])) {
                        $gcontact['addr'] = $x[0]["addr"];
                }
-       } else {
-               if (!isset($gcontact['server_url'])) {
-                       $gcontact['server_url'] = '';
-               }
-               if (!isset($gcontact['network'])) {
-                       $gcontact['network'] = '';
-               }
        }
 
        if ((!isset($gcontact['network']) OR !isset($gcontact['name']) OR !isset($gcontact['addr']) OR !isset($gcontact['photo']) OR !isset($gcontact['server_url']) OR $alternate)
@@ -283,7 +287,7 @@ function sanitized_gcontact(&$gcontact) {
                $data = Probe::uri($gcontact['url']);
 
                if ($data["network"] == NETWORK_PHANTOM) {
-                       return false;
+                       throw new Exception('Probing for URL '.$gcontact['url'].' failed');
                }
 
                $orig_profile = $gcontact['url'];
@@ -303,11 +307,11 @@ function sanitized_gcontact(&$gcontact) {
        }
 
        if (!isset($gcontact['name']) OR !isset($gcontact['photo'])) {
-               return false;
+               throw new Exception('No name and photo for URL '.$gcontact['url']);
        }
 
        if (!in_array($gcontact['network'], array(NETWORK_DFRN, NETWORK_OSTATUS, NETWORK_DIASPORA))) {
-               return false;
+               throw new Exception('No federated network ('.$gcontact['network'].') detected for URL '.$gcontact['url']);
        }
 
        if (!isset($gcontact['server_url'])) {
@@ -325,7 +329,7 @@ function sanitized_gcontact(&$gcontact) {
                $gcontact['server_url'] = "";
        }
 
-       return true;
+       return $gcontact;
 }
 
 /**
@@ -463,15 +467,26 @@ function poco_last_updated($profile, $force = false) {
        $gcontacts = q("SELECT * FROM `gcontact` WHERE `nurl` = '%s'",
                        dbesc(normalise_link($profile)));
 
+       if (!dbm::is_result($gcontacts)) {
+               return false;
+       }
+
+       $contact = array("url" => $profile);
+
        if ($gcontacts[0]["created"] <= NULL_DATE) {
-               q("UPDATE `gcontact` SET `created` = '%s' WHERE `nurl` = '%s'",
-                       dbesc(datetime_convert()), dbesc(normalise_link($profile)));
+               $contact['created'] = datetime_convert();
+       }
+
+       if ($force) {
+               $server_url = normalise_link(poco_detect_server($profile));
        }
-       if ($gcontacts[0]["server_url"] != "") {
+
+       if (($server_url == '') AND ($gcontacts[0]["server_url"] != "")) {
                $server_url = $gcontacts[0]["server_url"];
        }
-       if (($server_url == '') OR ($gcontacts[0]["server_url"] == $gcontacts[0]["nurl"])) {
-               $server_url = poco_detect_server($profile);
+
+       if (!$force AND (($server_url == '') OR ($gcontacts[0]["server_url"] == $gcontacts[0]["nurl"]))) {
+               $server_url = normalise_link(poco_detect_server($profile));
        }
 
        if (!in_array($gcontacts[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_FEED, NETWORK_OSTATUS, ""))) {
@@ -481,67 +496,64 @@ function poco_last_updated($profile, $force = false) {
 
        if ($server_url != "") {
                if (!poco_check_server($server_url, $gcontacts[0]["network"], $force)) {
-
-                       if ($force)
+                       if ($force) {
                                q("UPDATE `gcontact` SET `last_failure` = '%s' WHERE `nurl` = '%s'",
                                        dbesc(datetime_convert()), dbesc(normalise_link($profile)));
+                       }
 
                        logger("Profile ".$profile.": Server ".$server_url." wasn't reachable.", LOGGER_DEBUG);
                        return false;
                }
-
-               q("UPDATE `gcontact` SET `server_url` = '%s' WHERE `nurl` = '%s'",
-                       dbesc($server_url), dbesc(normalise_link($profile)));
+               $contact['server_url'] = $server_url;
        }
 
        if (in_array($gcontacts[0]["network"], array("", NETWORK_FEED))) {
                $server = q("SELECT `network` FROM `gserver` WHERE `nurl` = '%s' AND `network` != ''",
                        dbesc(normalise_link($server_url)));
 
-               if ($server)
-                       q("UPDATE `gcontact` SET `network` = '%s' WHERE `nurl` = '%s'",
-                               dbesc($server[0]["network"]), dbesc(normalise_link($profile)));
-               else
+               if ($server) {
+                       $contact['network'] = $server[0]["network"];
+               } else {
                        return false;
+               }
        }
 
        // noscrape is really fast so we don't cache the call.
-       if (($gcontacts[0]["server_url"] != "") AND ($gcontacts[0]["nick"] != "")) {
+       if (($server_url != "") AND ($gcontacts[0]["nick"] != "")) {
 
                //  Use noscrape if possible
-               $server = q("SELECT `noscrape`, `network` FROM `gserver` WHERE `nurl` = '%s' AND `noscrape` != ''", dbesc(normalise_link($gcontacts[0]["server_url"])));
+               $server = q("SELECT `noscrape`, `network` FROM `gserver` WHERE `nurl` = '%s' AND `noscrape` != ''", dbesc(normalise_link($server_url)));
 
                if ($server) {
                        $noscraperet = z_fetch_url($server[0]["noscrape"]."/".$gcontacts[0]["nick"]);
 
-                        if ($noscraperet["success"] AND ($noscraperet["body"] != "")) {
+                       if ($noscraperet["success"] AND ($noscraperet["body"] != "")) {
 
                                $noscrape = json_decode($noscraperet["body"], true);
 
                                if (is_array($noscrape)) {
-                                       $contact = array("url" => $profile,
-                                                       "network" => $server[0]["network"],
-                                                       "generation" => $gcontacts[0]["generation"]);
+                                       $contact["network"] = $server[0]["network"];
 
-                                       if (isset($noscrape["fn"]))
+                                       if (isset($noscrape["fn"])) {
                                                $contact["name"] = $noscrape["fn"];
-
-                                       if (isset($noscrape["comm"]))
+                                       }
+                                       if (isset($noscrape["comm"])) {
                                                $contact["community"] = $noscrape["comm"];
-
+                                       }
                                        if (isset($noscrape["tags"])) {
                                                $keywords = implode(" ", $noscrape["tags"]);
-                                               if ($keywords != "")
+                                               if ($keywords != "") {
                                                        $contact["keywords"] = $keywords;
+                                               }
                                        }
 
                                        $location = formatted_location($noscrape);
-                                       if ($location)
+                                       if ($location) {
                                                $contact["location"] = $location;
-
-                                       if (isset($noscrape["dfrn-notify"]))
+                                       }
+                                       if (isset($noscrape["dfrn-notify"])) {
                                                $contact["notify"] = $noscrape["dfrn-notify"];
-
+                                       }
                                        // Remove all fields that are not present in the gcontact table
                                        unset($noscrape["fn"]);
                                        unset($noscrape["key"]);
@@ -579,8 +591,10 @@ function poco_last_updated($profile, $force = false) {
        }
 
        // If we only can poll the feed, then we only do this once a while
-       if (!$force AND !poco_do_update($gcontacts[0]["created"], $gcontacts[0]["updated"], $gcontacts[0]["last_failure"],  $gcontacts[0]["last_contact"])) {
+       if (!$force AND !poco_do_update($gcontacts[0]["created"], $gcontacts[0]["updated"], $gcontacts[0]["last_failure"], $gcontacts[0]["last_contact"])) {
                logger("Profile ".$profile." was last updated at ".$gcontacts[0]["updated"]." (cached)", LOGGER_DEBUG);
+
+               update_gcontact($contact);
                return $gcontacts[0]["updated"];
        }
 
@@ -600,10 +614,13 @@ function poco_last_updated($profile, $force = false) {
 
                $gcontact["server_url"] = $data["baseurl"];
 
-               if (sanitized_gcontact($gcontact)) {
+               try {
+                       $gcontact = sanitize_gcontact($gcontact);
                        update_gcontact($gcontact);
 
                        poco_last_updated($data["url"], $force);
+               } catch (Exception $e) {
+                       logger($e->getMessage(), LOGGER_DEBUG);
                }
 
                logger("Profile ".$profile." was deleted", LOGGER_DEBUG);
@@ -618,8 +635,6 @@ function poco_last_updated($profile, $force = false) {
                return false;
        }
 
-       $contact = array("generation" => $gcontacts[0]["generation"]);
-
        $contact = array_merge($contact, $data);
 
        $contact["server_url"] = $data["baseurl"];
@@ -666,9 +681,10 @@ function poco_last_updated($profile, $force = false) {
        q("UPDATE `gcontact` SET `updated` = '%s', `last_contact` = '%s' WHERE `nurl` = '%s'",
                dbesc(dbm::date($last_updated)), dbesc(dbm::date()), dbesc(normalise_link($profile)));
 
-       if (($gcontacts[0]["generation"] == 0))
+       if (($gcontacts[0]["generation"] == 0)) {
                q("UPDATE `gcontact` SET `generation` = 9 WHERE `nurl` = '%s'",
                        dbesc(normalise_link($profile)));
+       }
 
        logger("Profile ".$profile." was last updated at ".$last_updated, LOGGER_DEBUG);
 
@@ -874,9 +890,9 @@ function poco_fetch_nodeinfo($server_url) {
 function poco_detect_server_type($body) {
        $server = false;
 
-       $doc = new \DOMDocument();
+       $doc = new DOMDocument();
        @$doc->loadHTML($body);
-       $xpath = new \DomXPath($doc);
+       $xpath = new DomXPath($doc);
 
        $list = $xpath->query("//meta[@name]");
 
@@ -994,6 +1010,7 @@ function poco_check_server($server_url, $network = "", $force = false) {
        if (dbm::is_result($servers) AND ($orig_server_url == $server_url) AND
                ($serverret['errno'] == CURLE_OPERATION_TIMEDOUT)) {
                logger("Connection to server ".$server_url." timed out.", LOGGER_DEBUG);
+               dba::p("UPDATE `gserver` SET `last_failure` = ? WHERE `nurl` = ?", datetime_convert(), normalise_link($server_url));
                return false;
        }
 
@@ -1008,6 +1025,7 @@ function poco_check_server($server_url, $network = "", $force = false) {
                // Quit if there is a timeout
                if ($serverret['errno'] == CURLE_OPERATION_TIMEDOUT) {
                        logger("Connection to server ".$server_url." timed out.", LOGGER_DEBUG);
+                       dba::p("UPDATE `gserver` SET `last_failure` = ? WHERE `nurl` = ?", datetime_convert(), normalise_link($server_url));
                        return false;
                }
 
@@ -1017,12 +1035,10 @@ function poco_check_server($server_url, $network = "", $force = false) {
        if (!$serverret["success"] OR ($serverret["body"] == "") OR (sizeof($xmlobj) == 0) OR !is_object($xmlobj)) {
                // Workaround for bad configured servers (known nginx problem)
                if (!in_array($serverret["debug"]["http_code"], array("403", "404"))) {
-                       $last_failure = datetime_convert();
                        $failure = true;
                }
                $possible_failure = true;
-       } elseif ($network == NETWORK_DIASPORA)
-               $last_contact = datetime_convert();
+       }
 
        // If the server has no possible failure we reset the cached data
        if (!$possible_failure) {
@@ -1040,8 +1056,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                        $data = json_decode($serverret["body"]);
                        if (isset($data->totalResults)) {
                                $poco = $server_url."/poco";
-                               $last_contact = datetime_convert();
-
                                $server = poco_detect_poco_data($data);
                                if ($server) {
                                        $platform = $server['platform'];
@@ -1058,7 +1072,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                $serverret = z_fetch_url($server_url);
 
                if (!$serverret["success"] OR ($serverret["body"] == "")) {
-                       $last_failure = datetime_convert();
                        $failure = true;
                } else {
                        $server = poco_detect_server_type($serverret["body"]);
@@ -1067,7 +1080,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                                $network = $server['network'];
                                $version = $server['version'];
                                $site_name = $server['site_name'];
-                               $last_contact = datetime_convert();
                        }
 
                        $lines = explode("\n",$serverret["header"]);
@@ -1081,15 +1093,11 @@ function poco_check_server($server_url, $network = "", $force = false) {
                                                $network = NETWORK_DIASPORA;
                                                $versionparts = explode("-", $version);
                                                $version = $versionparts[0];
-                                               $last_contact = datetime_convert();
                                        }
 
                                        if(stristr($line,'Server: Mastodon')) {
                                                $platform = "Mastodon";
                                                $network = NETWORK_OSTATUS;
-                                               // Mastodon doesn't reveal version numbers
-                                               $version = "";
-                                               $last_contact = datetime_convert();
                                        }
                                }
                        }
@@ -1108,7 +1116,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                        $version = str_replace(chr(239).chr(187).chr(191), "", $serverret["body"]);
                        $version = trim($version, '"');
                        $network = NETWORK_OSTATUS;
-                       $last_contact = datetime_convert();
                }
 
                // Test for GNU Social
@@ -1120,7 +1127,19 @@ function poco_check_server($server_url, $network = "", $force = false) {
                        $version = str_replace(chr(239).chr(187).chr(191), "", $serverret["body"]);
                        $version = trim($version, '"');
                        $network = NETWORK_OSTATUS;
-                       $last_contact = datetime_convert();
+               }
+
+               // Test for Mastodon
+               $serverret = z_fetch_url($server_url."/api/v1/instance");
+               if ($serverret["success"] AND ($serverret["body"] != '')) {
+                       $data = json_decode($serverret["body"]);
+                       if (isset($data->version)) {
+                               $platform = "Mastodon";
+                               $version = $data->version;
+                               $site_name = $data->title;
+                               $info = $data->description;
+                               $network = NETWORK_OSTATUS;
+                       }
                }
        }
 
@@ -1130,8 +1149,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                if ($serverret["success"]) {
                        $data = json_decode($serverret["body"]);
                        if (isset($data->site->server)) {
-                               $last_contact = datetime_convert();
-
                                if (isset($data->site->platform)) {
                                        $platform = $data->site->platform->PLATFORM_NAME;
                                        $version = $data->site->platform->STD_VERSION;
@@ -1178,7 +1195,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                }
        }
 
-
        // Query statistics.json. Optional package for Diaspora, Friendica and Redmatrix
        if (!$failure) {
                $serverret = z_fetch_url($server_url."/statistics.json");
@@ -1206,9 +1222,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                        } else {
                                $register_policy = REGISTER_CLOSED;
                        }
-
-                       if (isset($data->version))
-                               $last_contact = datetime_convert();
                }
        }
 
@@ -1233,8 +1246,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                        if (isset($server['site_name'])) {
                                $site_name = $server['site_name'];
                        }
-
-                       $last_contact = datetime_convert();
                }
        }
 
@@ -1250,7 +1261,6 @@ function poco_check_server($server_url, $network = "", $force = false) {
                        $data = json_decode($serverret["body"]);
 
                        if (isset($data->version)) {
-                               $last_contact = datetime_convert();
                                $network = NETWORK_DFRN;
 
                                $noscrape = $data->no_scrape_url;
@@ -1276,13 +1286,14 @@ function poco_check_server($server_url, $network = "", $force = false) {
        }
 
        if ($possible_failure AND !$failure) {
-               $last_failure = datetime_convert();
                $failure = true;
        }
 
        if ($failure) {
                $last_contact = $orig_last_contact;
+               $last_failure = datetime_convert();
        } else {
+               $last_contact = datetime_convert();
                $last_failure = $orig_last_failure;
        }
 
@@ -1416,7 +1427,7 @@ function common_friends_zcid($uid,$zcid,$start = 0, $limit = 9999,$shuffle = fal
        $r = q("SELECT `gcontact`.*
                FROM `glink` INNER JOIN `gcontact` on `glink`.`gcid` = `gcontact`.`id`
                where `glink`.`zcid` = %d
-               and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 ) 
+               and `gcontact`.`nurl` in (select nurl from contact where uid = %d and self = 0 and blocked = 0 and hidden = 0 )
                $sql_extra limit %d, %d",
                intval($zcid),
                intval($uid),
@@ -1644,6 +1655,20 @@ function poco_discover_federation() {
                }
        }
 
+       // Disvover Mastodon servers
+       if (!Config::get('system','ostatus_disabled')) {
+               $serverdata = fetch_url("https://instances.mastodon.xyz/instances.json");
+
+               if ($serverdata) {
+                       $servers = json_decode($serverdata);
+
+                       foreach ($servers AS $server) {
+                               $url = (is_null($server->https_score) ? 'http' : 'https').'://'.$server->name;
+                               proc_run(PRIORITY_LOW, "include/discover_poco.php", "server", base64_encode($url));
+                       }
+               }
+       }
+
        // Currently disabled, since the service isn't available anymore.
        // It is not removed since I hope that there will be a successor.
        // Discover GNU Social Servers.
@@ -1883,8 +1908,11 @@ function poco_discover_server($data, $default_generation = 0) {
                                        "contact-type" => $contact_type,
                                        "generation" => $generation);
 
-                       if (sanitized_gcontact($gcontact)) {
+                       try {
+                               $gcontact = sanitize_gcontact($gcontact);
                                update_gcontact($gcontact);
+                       } catch (Exception $e) {
+                               logger($e->getMessage(), LOGGER_DEBUG);
                        }
 
                        logger("Done for profile ".$profile_url, LOGGER_DEBUG);
@@ -1967,10 +1995,11 @@ function get_gcontact_id($contact) {
        if (in_array($contact["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS)))
                $contact["url"] = clean_contact_url($contact["url"]);
 
-       $r = q("SELECT `id`, `last_contact`, `last_failure`, `network` FROM `gcontact` WHERE `nurl` = '%s' LIMIT 2",
+       dba::lock('gcontact');
+       $r = q("SELECT `id`, `last_contact`, `last_failure`, `network` FROM `gcontact` WHERE `nurl` = '%s' LIMIT 1",
                dbesc(normalise_link($contact["url"])));
 
-       if ($r) {
+       if (dbm::is_result($r)) {
                $gcontact_id = $r[0]["id"];
 
                // Update every 90 days
@@ -2008,17 +2037,13 @@ function get_gcontact_id($contact) {
                        $doprobing = in_array($r[0]["network"], array(NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""));
                }
        }
+       dba::unlock();
 
        if ($doprobing) {
                logger("Last Contact: ". $last_contact_str." - Last Failure: ".$last_failure_str." - Checking: ".$contact["url"], LOGGER_DEBUG);
                proc_run(PRIORITY_LOW, 'include/gprobe.php', bin2hex($contact["url"]));
        }
 
-       if ((dbm::is_result($r)) AND (count($r) > 1) AND ($gcontact_id > 0) AND ($contact["url"] != ""))
-        q("DELETE FROM `gcontact` WHERE `nurl` = '%s' AND `id` != %d",
-               dbesc(normalise_link($contact["url"])),
-               intval($gcontact_id));
-
        return $gcontact_id;
 }
 
@@ -2081,7 +2106,7 @@ function update_gcontact($contact) {
        fix_alternate_contact_address($contact);
 
        if (!isset($contact["updated"]))
-               $contact["updated"] = datetime_convert();
+               $contact["updated"] = dbm::date();
 
        if ($contact["server_url"] == "") {
                $server_url = $contact["url"];
@@ -2136,7 +2161,7 @@ function update_gcontact($contact) {
                        dbesc($contact["gender"]), dbesc($contact["keywords"]), intval($contact["hide"]),
                        intval($contact["nsfw"]), intval($contact["contact-type"]), dbesc($contact["alias"]),
                        dbesc($contact["notify"]), dbesc($contact["url"]), dbesc($contact["location"]),
-                       dbesc($contact["about"]), intval($contact["generation"]), dbesc($contact["updated"]),
+                       dbesc($contact["about"]), intval($contact["generation"]), dbesc(dbm::date($contact["updated"])),
                        dbesc($contact["server_url"]), dbesc($contact["connect"]),
                        dbesc(normalise_link($contact["url"])), intval($contact["generation"]));
 
@@ -2314,4 +2339,3 @@ function poco_serverlist() {
        }
        return $r;
 }
-?>