function short_link($url) { require_once 'library/slinky.php'; $slinky = new Slinky($url); $yourls_url = get_config('yourls', 'url1'); if ($yourls_url) { $yourls_username = get_config('yourls', 'username1'); $yourls_password = get_config('yourls', 'password1'); $yourls_ssl = get_config('yourls', 'ssl1'); $yourls = new Slinky_YourLS(); $yourls->set('username', $yourls_username); $yourls->set('password', $yourls_password); $yourls->set('ssl', $yourls_ssl); $yourls->set('yourls-url', $yourls_url); $slinky->set_cascade(array($yourls, new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL())); } else { // setup a cascade of shortening services // try to get a short link from these services // in the order ur1.ca, trim, id.gd, tinyurl $slinky->set_cascade(array(new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL())); } return $slinky->short(); }
/** * @param App $a * @param object $b * @return mixed */ function facebook_post_hook(&$a, &$b) { if ($b['deleted'] || $b['created'] !== $b['edited']) { return; } /** * Post to Facebook stream */ require_once 'include/group.php'; require_once 'include/html2plain.php'; logger('Facebook post'); $reply = false; $likes = false; $deny_arr = array(); $allow_arr = array(); $toplevel = $b['id'] == $b['parent'] ? true : false; $linking = get_pconfig($b['uid'], 'facebook', 'no_linking') ? 0 : 1; if (!$toplevel && $linking) { $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($b['parent']), intval($b['uid'])); if (count($r) && substr($r[0]['uri'], 0, 4) === 'fb::') { $reply = substr($r[0]['uri'], 4); } elseif (count($r) && substr($r[0]['extid'], 0, 4) === 'fb::') { $reply = substr($r[0]['extid'], 4); } else { return; } $u = q("SELECT * FROM user where uid = %d limit 1", intval($b['uid'])); if (!count($u)) { return; } // only accept comments from the item owner. Other contacts are unknown to FB. if (!link_compare($b['author-link'], $a->get_baseurl() . '/profile/' . $u[0]['nickname'])) { return; } logger('facebook reply id=' . $reply); } if (strstr($b['postopts'], 'facebook') || $b['private'] || $reply) { if ($b['private'] && $reply === false) { $allow_people = expand_acl($b['allow_cid']); $allow_groups = expand_groups(expand_acl($b['allow_gid'])); $deny_people = expand_acl($b['deny_cid']); $deny_groups = expand_groups(expand_acl($b['deny_gid'])); $recipients = array_unique(array_merge($allow_people, $allow_groups)); $deny = array_unique(array_merge($deny_people, $deny_groups)); $allow_str = dbesc(implode(', ', $recipients)); if ($allow_str) { $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( {$allow_str} ) AND `network` = 'face'"); if (count($r)) { foreach ($r as $rr) { $allow_arr[] = $rr['notify']; } } } $deny_str = dbesc(implode(', ', $deny)); if ($deny_str) { $r = q("SELECT `notify` FROM `contact` WHERE `id` IN ( {$deny_str} ) AND `network` = 'face'"); if (count($r)) { foreach ($r as $rr) { $deny_arr[] = $rr['notify']; } } } if (count($deny_arr) && !count($allow_arr)) { // One or more FB folks were denied access but nobody on FB was specifically allowed access. // This might cause the post to be open to public on Facebook, but only to selected members // on another network. Since this could potentially leak a post to somebody who was denied, // we will skip posting it to Facebook with a slightly vague but relevant message that will // hopefully lead somebody to this code comment for a better explanation of what went wrong. notice(t('Post to Facebook cancelled because of multi-network access permission conflict.') . EOL); return; } // if it's a private message but no Facebook members are allowed or denied, skip Facebook post if (!count($allow_arr) && !count($deny_arr)) { return; } } if ($b['verb'] == ACTIVITY_LIKE) { $likes = true; } $appid = get_config('facebook', 'appid'); $secret = get_config('facebook', 'appsecret'); if ($appid && $secret) { logger('facebook: have appid+secret'); $fb_token = get_pconfig($b['uid'], 'facebook', 'access_token'); // post to facebook if it's a public post and we've ticked the 'post to Facebook' box, // or it's a private message with facebook participants // or it's a reply or likes action to an existing facebook post if ($fb_token && ($toplevel || $b['private'] || $reply)) { logger('facebook: able to post'); require_once 'library/facebook.php'; require_once 'include/bbcode.php'; $msg = $b['body']; logger('Facebook post: original msg=' . $msg, LOGGER_DATA); // make links readable before we strip the code // unless it's a dislike - just send the text as a comment // if($b['verb'] == ACTIVITY_DISLIKE) // $msg = trim(strip_tags(bbcode($msg))); // Old code /*$search_str = $a->get_baseurl() . '/search'; if(preg_match("/\[url=(.*?)\](.*?)\[\/url\]/is",$msg,$matches)) { // don't use hashtags for message link if(strpos($matches[2],$search_str) === false) { $link = $matches[1]; if(substr($matches[2],0,5) != '[img]') $linkname = $matches[2]; } } // strip tag links to avoid link clutter, this really should be // configurable because we're losing information $msg = preg_replace("/\#\[url=(.*?)\](.*?)\[\/url\]/is",'#$2',$msg); // provide the link separately for normal links $msg = preg_replace("/\[url=(.*?)\](.*?)\[\/url\]/is",'$2 $1',$msg); if(preg_match("/\[img\](.*?)\[\/img\]/is",$msg,$matches)) $image = $matches[1]; $msg = preg_replace("/\[img\](.*?)\[\/img\]/is", t('Image: ') . '$1', $msg); if((strpos($link,z_root()) !== false) && (! $image)) $image = $a->get_baseurl() . '/images/friendica-64.jpg'; $msg = trim(strip_tags(bbcode($msg)));*/ // New code // Looking for the first image $image = ''; if (preg_match("/\\[img\\=([0-9]*)x([0-9]*)\\](.*?)\\[\\/img\\]/is", $b['body'], $matches)) { $image = $matches[3]; } if ($image == '') { if (preg_match("/\\[img\\](.*?)\\[\\/img\\]/is", $b['body'], $matches)) { $image = $matches[1]; } } // Checking for a bookmark element $body = $b['body']; if (strpos($body, "[bookmark") !== false) { // splitting the text in two parts: // before and after the bookmark $pos = strpos($body, "[bookmark"); $body1 = substr($body, 0, $pos); $body2 = substr($body, $pos); // Removing the bookmark and all quotes after the bookmark // they are mostly only the content after the bookmark. $body2 = preg_replace("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/ism", '', $body2); $body2 = preg_replace("/\\[quote\\=([^\\]]*)\\](.*?)\\[\\/quote\\]/ism", '', $body2); $body2 = preg_replace("/\\[quote\\](.*?)\\[\\/quote\\]/ism", '', $body2); $body = $body1 . $body2; } // At first convert the text to html $html = bbcode($body); // Then convert it to plain text $msg = trim($b['title'] . " \n\n" . html2plain($html, 0, true)); $msg = html_entity_decode($msg, ENT_QUOTES, 'UTF-8'); // Removing multiple newlines while (strpos($msg, "\n\n\n") !== false) { $msg = str_replace("\n\n\n", "\n\n", $msg); } // add any attachments as text urls $arr = explode(',', $b['attach']); if (count($arr)) { $msg .= "\n"; foreach ($arr as $r) { $matches = false; $cnt = preg_match('|\\[attach\\]href=\\"(.*?)\\" size=\\"(.*?)\\" type=\\"(.*?)\\" title=\\"(.*?)\\"\\[\\/attach\\]|', $r, $matches); if ($cnt) { $msg .= "\n" . $matches[1]; } } } $link = ''; $linkname = ''; // look for bookmark-bbcode and handle it with priority if (preg_match("/\\[bookmark\\=([^\\]]*)\\](.*?)\\[\\/bookmark\\]/is", $b['body'], $matches)) { $link = $matches[1]; $linkname = $matches[2]; } // If there is no bookmark element then take the first link if ($link == '') { $links = collecturls($html); if (sizeof($links) > 0) { reset($links); $link = current($links); } } // Remove trailing and leading spaces $msg = trim($msg); // Since facebook increased the maxpostlen massively this never should happen again :) if (strlen($msg) > FACEBOOK_MAXPOSTLEN) { require_once 'library/slinky.php'; $display_url = $b['plink']; $slinky = new Slinky($display_url); // setup a cascade of shortening services // try to get a short link from these services // in the order ur1.ca, trim, id.gd, tinyurl $slinky->set_cascade(array(new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL())); $shortlink = $slinky->short(); // the new message will be shortened such that "... $shortlink" // will fit into the character limit $msg = substr($msg, 0, FACEBOOK_MAXPOSTLEN - strlen($shortlink) - 4); $msg .= '... ' . $shortlink; } // Fallback - if message is empty if (!strlen($msg)) { $msg = $link; } if (!strlen($msg)) { $msg = $image; } if (!strlen($msg)) { $msg = $linkname; } // If there is nothing to post then exit if (!strlen($msg)) { return; } logger('Facebook post: msg=' . $msg, LOGGER_DATA); if ($likes) { $postvars = array('access_token' => $fb_token); } else { $postvars = array('access_token' => $fb_token, 'message' => $msg); if (isset($image)) { $postvars['picture'] = $image; //$postvars['type'] = "photo"; } if (isset($link)) { $postvars['link'] = $link; //$postvars['type'] = "link"; } if (isset($linkname)) { $postvars['name'] = $linkname; } } if ($b['private'] && $toplevel) { $postvars['privacy'] = '{"value": "CUSTOM", "friends": "SOME_FRIENDS"'; if (count($allow_arr)) { $postvars['privacy'] .= ',"allow": "' . implode(',', $allow_arr) . '"'; } if (count($deny_arr)) { $postvars['privacy'] .= ',"deny": "' . implode(',', $deny_arr) . '"'; } $postvars['privacy'] .= '}'; } if ($reply) { $url = 'https://graph.facebook.com/' . $reply . '/' . ($likes ? 'likes' : 'comments'); } else { if ($link != "" or $image != "" or $b['title'] == '' or strlen($msg) < 500) { $url = 'https://graph.facebook.com/me/feed'; if ($b['plink']) { $postvars['actions'] = '{"name": "' . t('View on Friendica') . '", "link": "' . $b['plink'] . '"}'; } } else { // if its only a message and a subject and the message is larger than 500 characters then post it as note $postvars = array('access_token' => $fb_token, 'message' => bbcode($b['body']), 'subject' => $b['title']); $url = 'https://graph.facebook.com/me/notes'; } } logger('facebook: post to ' . $url); logger('facebook: postvars: ' . print_r($postvars, true)); // "test_mode" prevents anything from actually being posted. // Otherwise, let's do it. if (!get_config('facebook', 'test_mode')) { $x = post_url($url, $postvars); logger('Facebook post returns: ' . $x, LOGGER_DEBUG); $retj = json_decode($x); if ($retj->id) { q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d LIMIT 1", dbesc('fb::' . $retj->id), intval($b['id'])); } else { if (!$likes) { $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $postvars)); require_once 'include/queue_fn.php'; add_to_queue($a->contact, NETWORK_FACEBOOK, $s); notice(t('Facebook post failed. Queued for retry.') . EOL); } if (isset($retj->error) && $retj->error->type == "OAuthException" && $retj->error->code == 190) { logger('Facebook session has expired due to changed password.', LOGGER_DEBUG); $last_notification = get_pconfig($b['uid'], 'facebook', 'session_expired_mailsent'); if (!$last_notification || $last_notification < time() - FACEBOOK_SESSION_ERR_NOTIFICATION_INTERVAL) { require_once 'include/enotify.php'; $r = q("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval($b['uid'])); notification(array('uid' => $b['uid'], 'type' => NOTIFY_SYSTEM, 'system_type' => 'facebook_connection_invalid', 'language' => $r[0]['language'], 'to_name' => $r[0]['username'], 'to_email' => $r[0]['email'], 'source_name' => t('Administrator'), 'source_link' => $a->config["system"]["url"], 'source_photo' => $a->config["system"]["url"] . '/images/person-80.jpg')); set_pconfig($b['uid'], 'facebook', 'session_expired_mailsent', time()); } else { logger('Facebook: No notification, as the last one was sent on ' . $last_notification, LOGGER_DEBUG); } } } } } } } }