Allows you to use a string of RSS/Atom data instead of a remote feed.
If you have a feed available as a string in PHP, you can tell SimplePie
to parse that data string instead of a remote feed. Any set feed URL
takes precedence.
public set_raw_data ( string $data ) | ||
$data | string | RSS or Atom data as a string. |
/** * Provided a URL, will return an array representing the feed item for that * URL. A feed item contains the content, url, simplepie object, and failure * status for the URL passed. Handles caching of content requests. * * @return array * @author Jared Lang **/ protected static function __new_feed($url) { $timer = Timer::start(); require_once THEME_DIR . '/third-party/simplepie.php'; $simplepie = null; $failed = False; $cache_key = 'feedmanager-' . md5($url); $content = get_site_transient($cache_key); if ($content === False) { $content = @file_get_contents($url); if ($content === False) { $failed = True; $content = null; error_log('FeedManager failed to fetch data using url of ' . $url); } else { set_site_transient($cache_key, $content, self::$cache_length); } } if ($content) { $simplepie = new SimplePie(); $simplepie->set_raw_data($content); $simplepie->init(); $simplepie->handle_content_type(); if ($simplepie->error) { error_log($simplepie->error); $simplepie = null; $failed = True; } } else { $failed = True; } $elapsed = round($timer->elapsed() * 1000); debug("__new_feed: {$elapsed} milliseconds"); return array('content' => $content, 'url' => $url, 'simplepie' => $simplepie, 'failed' => $failed); }
public static function simplepie($feed_url = NULL) { if (!$feed_url) { return false; } $data = new SimplePie(); //******************************* // Convert To GeoRSS feed // To Disable Uncomment these 3 lines //******************************* $geocoder = new Geocoder(); $georss_feed = $geocoder->geocode_feed($feed_url); if ($georss_feed == false or empty($georss_feed)) { // Our RSS feed pull failed, so let's grab the original RSS feed $data->set_feed_url($feed_url); } else { // Converting our feed to GeoRSS was successful, use that data $data->set_raw_data($georss_feed); } // Uncomment Below to disable geocoding //$data->set_feed_url( $feed_url ); //******************************* $data->enable_cache(false); $data->enable_order_by_date(true); $data->init(); $data->handle_content_type(); return $data; }
function rss_to_activity_streams($data) { // $feed = new SimplePie(); $feed->set_raw_data($data); // unset($data); // $feed->set_stupidly_fast(true); $feed->init(); $feed->handle_content_type(); // $id = md5($url); $title = 'submit'; $link = 'http://' . $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"]; $activityStream = new ActivityStreamsDoc($id, $title, $link); // foreach ($feed->get_items() as $item) { $author = $item->get_author(); if (!$author) { $author = $feed->get_author(); } // $activityStream->entry($item->get_id(), date("r", $item->get_date()), $author ? $author->get_name() : null, $author ? $author->get_link() : null, $item->get_title(), $item->get_permalink(), $item->get_description()); } return $activityStream; }
/** * Provided a URL, will return an array representing the feed item for that * URL. A feed item contains the content, url, simplepie object, and failure * status for the URL passed. Handles caching of content requests. * * @return array * @author Jared Lang * */ protected static function __new_feed($url) { require_once ABSPATH . '/wp-includes/class-simplepie.php'; $simplepie = null; $failed = False; $cache_key = 'feedmanager-' . md5($url); $content = get_site_transient($cache_key); if ($content === False) { $content = @file_get_contents($url); if ($content === False) { $failed = True; $content = null; error_log('FeedManager failed to fetch data using url of ' . $url); } else { set_site_transient($cache_key, $content, self::$cache_length); } } if ($content) { $simplepie = new SimplePie(); $simplepie->set_raw_data($content); $simplepie->init(); $simplepie->handle_content_type(); if ($simplepie->error) { error_log($simplepie->error); $simplepie = null; $failed = True; } } else { $failed = True; } return array('content' => $content, 'url' => $url, 'simplepie' => $simplepie, 'failed' => $failed); }
function feed() { $feed = new SimplePie(); $feed->set_raw_data($this->data); $feed->enable_cache(false); $feed->init(); return $feed; }
public function setUp() { parent::setUp(); $rss_sample = file_get_contents(dirname(__FILE__) . '/test-assets/rss'); $sampleFeed = new SimplePie(); $sampleFeed->set_raw_data($rss_sample); $sampleFeed->init(); self::$sampleFeed = $sampleFeed; $this->testFeedUrl = 'http://www.theguardian.com/world/rss'; }
static function parseFeed($url, $omitDB = false) { global $wgOut; //reset array self::$data = array('feedTitle' => '', 'images' => array()); if (!$omitDB) { //check DB for this URL - we might have it already (background task will refresh it) $data = self::getDataByUrl($url); } if ($omitDB || is_null($data)) { //no data in DB - fetch from feed $itemCount = 0; $rssContent = Http::get($url); $feed = new SimplePie(); $feed->set_raw_data($rssContent); $feed->init(); self::$data['feedTitle'] = $feed->get_title(); foreach ($feed->get_items() as $item) { $enclosures = $item->get_enclosures(); $enclosuresFound = false; //we have enclosures - use them instead of content of feed (usually there are bigger image while content uses thumbnails) if (!is_null($enclosures)) { foreach ($enclosures as $enclosure) { $type = $enclosure->get_type(); if (!empty($type) && substr($type, 0, 6) === 'image/') { self::$data['images'][] = array('src' => $enclosure->get_link(), 'caption' => $item->get_title(), 'link' => $item->get_link()); $enclosuresFound = true; break; //one image per feed } } } //if enclosures has not been found or doesn't contain any images - use regular method if (!$enclosuresFound) { //look for <img /> tags $description = $item->get_description(); preg_match('/<img .*?src=([\'"])(.*?\\.(?:jpg|jpeg|gif|png))\\1/', $description, $matches); if (!empty($matches[2])) { self::$data['images'][] = array('src' => $matches[2], 'caption' => $item->get_title(), 'link' => $item->get_link()); } } if (count(self::$data['images']) >= 20 || ++$itemCount > 50) { break; //take up to 20 images, from up to 50 articles. } } //store data in DB only if valid rss (images found) if (count(self::$data['images'])) { self::setData($url, self::$data); } } else { self::$data = $data; } return self::$data; }
public function loadStringIntoSimplePieObject($xmldata) { // Create a new instance of the SimplePie object $feed = new SimplePie(); $feed->enable_cache(false); // $feed->set_feed_url('http://simplepie.org/blog/feed/'); $feed->set_raw_data($xmldata); $feed->init(); $feed->handle_content_type(); return $feed; }
/** * Run a test using a sprintf template and data * * @param string $template */ protected function checkFromTemplate($template, $data, $expected) { if (!is_array($data)) { $data = array($data); } $xml = vsprintf($template, $data); $feed = new SimplePie(); $feed->set_raw_data($xml); $feed->enable_cache(false); $feed->init(); return $feed; }
function powerpress_get_news($feed_url, $limit = 10) { include_once ABSPATH . WPINC . '/feed.php'; $rss = fetch_feed($feed_url); // If feed doesn't work... if (is_wp_error($rss)) { require_once ABSPATH . WPINC . '/class-feed.php'; // Try fetching the feed using CURL directly... $content = powerpress_remote_fopen($feed_url, false, array(), 3, false, true); if (!$content) { return false; } // Load the content in a fetch_feed object... $rss = new SimplePie(); $rss->set_sanitize_class('WP_SimplePie_Sanitize_KSES'); // We must manually overwrite $feed->sanitize because SimplePie's // constructor sets it before we have a chance to set the sanitization class $rss->sanitize = new WP_SimplePie_Sanitize_KSES(); $rss->set_cache_class('WP_Feed_Cache'); $rss->set_file_class('WP_SimplePie_File'); $rss->set_raw_data($content); $rss->set_cache_duration(apply_filters('wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $feed_url)); do_action_ref_array('wp_feed_options', array(&$rss, $feed_url)); $rss->init(); $rss->set_output_encoding(get_option('blog_charset')); $rss->handle_content_type(); if ($rss->error()) { return false; } } $rss_items = $rss->get_items(0, $rss->get_item_quantity($limit)); // If the feed was erroneously if (!$rss_items) { $md5 = md5($this->feed); delete_transient('feed_' . $md5); delete_transient('feed_mod_' . $md5); $rss->__destruct(); unset($rss); $rss = fetch_feed($this->feed); $rss_items = $rss->get_items(0, $rss->get_item_quantity($num)); $rss->__destruct(); unset($rss); } return $rss_items; }
/** * Fetch feed w/o caching. * * @param int $limit Number of entries to fetch. * @param string $feed URI of RSS feed to import. * * @return array List of feed entries. */ public function fetch_feed($limit, $feed) { if (!class_exists('SimplePie_File')) { include_once ABSPATH . WPINC . DIRECTORY_SEPARATOR . 'SimplePie' . DIRECTORY_SEPARATOR . 'File.php'; } $result = array(); try { $file = new SimplePie_File($feed); $feed = new SimplePie(); $feed->set_raw_data($file->body); $feed->init(); if (!is_wp_error($feed)) { $result = $feed->get_items(0, $limit); } } catch (Exception $exception) { } // discard return $result; }
/** * Given the content of a page and its URL, returns an array of FeedItem objects (or false on failure) * @param $content * @param $url * @return array|bool */ function parseFeed($content, $url) { // Check for microformats if ($html = @\DOMDocument::loadHTML($content)) { try { $parser = new \Mf2\Parser($html, $url); $parsed_content = $parser->parse(); return $this->mf2FeedToFeedItems($parsed_content, $url); } catch (\Exception $e) { return false; } } // Try XML (RSS or Atom) $xml_parser = new \SimplePie(); $xml_parser->set_raw_data($content); $xml_parser->init(); if (!$xml_parser->error()) { return $this->xmlFeedToFeedItems($xml_parser->get_items(), $url); } return false; }
public static function simplepie($feed_url = NULL) { if (!$feed_url) { return false; } $data = new SimplePie(); //******************************* // Convert To GeoRSS feed // To Disable Uncomment these 3 lines //******************************* $geocoder = new Geocoder(); $georss_feed = $geocoder->geocode_feed($feed_url); $data->set_raw_data($georss_feed); // Uncomment Below to disable geocoding //$data->set_feed_url( $feed_url ); //******************************* $data->enable_cache(false); $data->enable_order_by_date(true); $data->init(); $data->handle_content_type(); return $data; }
/** * Geonames Feeds GeoCoding (RSS to GEORSS) * Due to limitations, this returns only 20 items * * @param string location / address * @return string raw georss data */ function geocode_feed($feed_url = NULL) { $base_url = "http://" . GEOCODER_GEONAMES . "/rssToGeoRSS?"; // Only requests service if we have an user $geocode_username = Settings_Model::get_setting('feed_geolocation_user'); if ($feed_url && !empty($geocode_username)) { // First check to make sure geonames webservice is running $geonames_status = @remote::status($base_url); if ($geonames_status == "200") { // Successful $request_url = $base_url . "&feedUrl=" . urlencode($feed_url) . "&username=" . $geocode_username; } else { // Down perhaps?? Use direct feed $request_url = $feed_url; } $request = new HttpClient($request_url); if (!($georss = $request->execute($request_url))) { // If the request failed, something may be wrong with the GEOCODER_GEONAMES service return false; } //$georss = utf8_encode($georss); // Lez verify this we got a good reply from the geocoder before proceeding $data = new SimplePie(); $data->set_raw_data($georss); $data->init(); $data->handle_content_type(); // Feed no good - get outta here! if ($data->error()) { Kohana::log('error', $data->error() . $request_url); return false; } return trim($georss); } else { return false; } }
/** * Update the feeds * */ function UpdateFeeds() { if (!is_dir('./tmp')) { mkdir('./tmp', 0777); } $feedData = array(); $lock = Lock("Update Feeds", false); if (isset($lock)) { // load the list of feeds require_once './settings/feeds.inc'; require_once './lib/simplepie.inc'; // loop through and update each one foreach ($feeds as $category => &$feedList) { $feedData[$category] = array(); foreach ($feedList as $feedSource => $feedUrl) { $feedUrl = trim($feedUrl); if (strlen($feedUrl)) { $feed = new SimplePie(); if ($feed) { $rawFeed = trim(http_fetch($feedUrl)); $feed->set_raw_data($rawFeed); $feed->enable_cache(false); $feed->init(); // try sanitizing the data if we have a problem parsing the feed if (strlen($feed->error())) { FixFeed($rawFeed); $feed->set_raw_data($rawFeed); $feed->enable_cache(false); $feed->init(); } foreach ($feed->get_items() as $item) { $dateStr = $item->get_date(DATE_RSS); if ($dateStr && strlen($dateStr)) { $date = strtotime($dateStr); if ($date) { // only include articles from the last 30 days $now = time(); $elapsed = 0; if ($now > $date) { $elapsed = $now - $date; } $days = (int) ($elapsed / 86400); if ($days <= 30) { // make sure we don't have another article from the exact same time while (isset($feedData[$category][$date])) { $date++; } $feedData[$category][$date] = array('source' => $feedSource, 'title' => $item->get_title(), 'link' => urldecode($item->get_permalink()), 'date' => $dateStr); } } } $item->__destruct(); } $feed->__destruct(); unset($feed); } } } if (count($feedData[$category])) { krsort($feedData[$category]); } } // save out the feed data file_put_contents('./tmp/feeds.dat', json_encode($feedData)); Unlock($lock); } }
function probe_url($url, $mode = PROBE_NORMAL) { require_once 'include/email.php'; $result = array(); if (!$url) { return $result; } $network = null; $diaspora = false; $diaspora_base = ''; $diaspora_guid = ''; $diaspora_key = ''; $has_lrdd = false; $email_conversant = false; $twitter = strpos($url, 'twitter.com') !== false ? true : false; $at_addr = strpos($url, '@') !== false ? true : false; if (!$twitter) { if (strpos($url, 'mailto:') !== false && $at_addr) { $url = str_replace('mailto:', '', $url); $links = array(); } else { $links = lrdd($url); } if (count($links)) { $has_lrdd = true; logger('probe_url: found lrdd links: ' . print_r($links, true), LOGGER_DATA); foreach ($links as $link) { if ($link['@attributes']['rel'] === NAMESPACE_ZOT) { $zot = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === NAMESPACE_DFRN) { $dfrn = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === 'salmon') { $notify = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === NAMESPACE_FEED) { $poll = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard') { $hcard = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') { $profile = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0') { $poco = unamp($link['@attributes']['href']); } if ($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') { $diaspora_base = unamp($link['@attributes']['href']); $diaspora = true; } if ($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') { $diaspora_guid = unamp($link['@attributes']['href']); $diaspora = true; } if ($link['@attributes']['rel'] === 'diaspora-public-key') { $diaspora_key = base64_decode(unamp($link['@attributes']['href'])); $pubkey = rsatopem($diaspora_key); $diaspora = true; } } // Status.Net can have more than one profile URL. We need to match the profile URL // to a contact on incoming messages to prevent spam, and we won't know which one // to match. So in case of two, one of them is stored as an alias. Only store URL's // and not webfinger user@host aliases. If they've got more than two non-email style // aliases, let's hope we're lucky and get one that matches the feed author-uri because // otherwise we're screwed. foreach ($links as $link) { if ($link['@attributes']['rel'] === 'alias') { if (strpos($link['@attributes']['href'], '@') === false) { if (isset($profile)) { if ($link['@attributes']['href'] !== $profile) { $alias = unamp($link['@attributes']['href']); } } else { $profile = unamp($link['@attributes']['href']); } } } } } elseif ($mode == PROBE_NORMAL) { // Check email $orig_url = $url; if (strpos($orig_url, '@') && validate_email($orig_url)) { $x = q("SELECT `prvkey` FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user())); $r = q("SELECT * FROM `mailacct` WHERE `uid` = %d AND `server` != '' LIMIT 1", intval(local_user())); if (count($x) && count($r)) { $mailbox = construct_mailbox_name($r[0]); $password = ''; openssl_private_decrypt(hex2bin($r[0]['pass']), $password, $x[0]['prvkey']); $mbox = email_connect($mailbox, $r[0]['user'], $password); if (!$mbox) { logger('probe_url: email_connect failed.'); } unset($password); } if ($mbox) { $msgs = email_poll($mbox, $orig_url); logger('probe_url: searching ' . $orig_url . ', ' . count($msgs) . ' messages found.', LOGGER_DEBUG); if (count($msgs)) { $addr = $orig_url; $network = NETWORK_MAIL; $name = substr($url, 0, strpos($url, '@')); $phost = substr($url, strpos($url, '@') + 1); $profile = 'http://' . $phost; // fix nick character range $vcard = array('fn' => $name, 'nick' => $name, 'photo' => avatar_img($url)); $notify = 'smtp ' . random_string(); $poll = 'email ' . random_string(); $priority = 0; $x = email_msg_meta($mbox, $msgs[0]); if (stristr($x->from, $orig_url)) { $adr = imap_rfc822_parse_adrlist($x->from, ''); } elseif (stristr($x->to, $orig_url)) { $adr = imap_rfc822_parse_adrlist($x->to, ''); } if (isset($adr)) { foreach ($adr as $feadr) { if (strcasecmp($feadr->mailbox, $name) == 0 && strcasecmp($feadr->host, $phost) == 0 && strlen($feadr->personal)) { $personal = imap_mime_header_decode($feadr->personal); $vcard['fn'] = ""; foreach ($personal as $perspart) { if ($perspart->charset != "default") { $vcard['fn'] .= iconv($perspart->charset, 'UTF-8//IGNORE', $perspart->text); } else { $vcard['fn'] .= $perspart->text; } } $vcard['fn'] = notags($vcard['fn']); } } } } imap_close($mbox); } } } } if ($mode == PROBE_NORMAL) { if (strlen($zot)) { $s = fetch_url($zot); if ($s) { $j = json_decode($s); if ($j) { $network = NETWORK_ZOT; $vcard = array('fn' => $j->fullname, 'nick' => $j->nickname, 'photo' => $j->photo); $profile = $j->url; $notify = $j->post; $pubkey = $j->pubkey; $poll = 'N/A'; } } } if (strlen($dfrn)) { $ret = scrape_dfrn($hcard ? $hcard : $dfrn); if (is_array($ret) && x($ret, 'dfrn-request')) { $network = NETWORK_DFRN; $request = $ret['dfrn-request']; $confirm = $ret['dfrn-confirm']; $notify = $ret['dfrn-notify']; $poll = $ret['dfrn-poll']; $vcard = array(); $vcard['fn'] = $ret['fn']; $vcard['nick'] = $ret['nick']; $vcard['photo'] = $ret['photo']; } } } if ($diaspora && $diaspora_base && $diaspora_guid) { if ($mode == PROBE_DIASPORA || !$notify) { $notify = $diaspora_base . 'receive/users/' . $diaspora_guid; $batch = $diaspora_base . 'receive/public'; } if (strpos($url, '@')) { $addr = str_replace('acct:', '', $url); } } if ($network !== NETWORK_ZOT && $network !== NETWORK_DFRN && $network !== NETWORK_MAIL) { if ($diaspora) { $network = NETWORK_DIASPORA; } elseif ($has_lrdd) { $network = NETWORK_OSTATUS; } $priority = 0; if ($hcard && !$vcard) { $vcard = scrape_vcard($hcard); // Google doesn't use absolute url in profile photos if (x($vcard, 'photo') && substr($vcard['photo'], 0, 1) == '/') { $h = @parse_url($hcard); if ($h) { $vcard['photo'] = $h['scheme'] . '://' . $h['host'] . $vcard['photo']; } } logger('probe_url: scrape_vcard: ' . print_r($vcard, true), LOGGER_DATA); } if ($twitter) { logger('twitter: setup'); $tid = basename($url); $tapi = 'https://api.twitter.com/1/statuses/user_timeline.rss'; if (intval($tid)) { $poll = $tapi . '?user_id=' . $tid; } else { $poll = $tapi . '?screen_name=' . $tid; } $profile = 'http://twitter.com/#!/' . $tid; $vcard['photo'] = 'https://api.twitter.com/1/users/profile_image/' . $tid; $vcard['nick'] = $tid; $vcard['fn'] = $tid . '@twitter'; } if (!x($vcard, 'fn')) { if (x($vcard, 'nick')) { $vcard['fn'] = $vcard['nick']; } } $check_feed = false; if ($twitter || !$poll) { $check_feed = true; } if (!isset($vcard) || !x($vcard, 'fn') || !$profile) { $check_feed = true; } if ($at_addr && !count($links)) { $check_feed = false; } if ($check_feed) { $feedret = scrape_feed($poll ? $poll : $url); logger('probe_url: scrape_feed ' . ($poll ? $poll : $url) . ' returns: ' . print_r($feedret, true), LOGGER_DATA); if (count($feedret) && ($feedret['feed_atom'] || $feedret['feed_rss'])) { $poll = x($feedret, 'feed_atom') ? unamp($feedret['feed_atom']) : unamp($feedret['feed_rss']); if (!x($vcard)) { $vcard = array(); } } if (x($feedret, 'photo') && !x($vcard, 'photo')) { $vcard['photo'] = $feedret['photo']; } require_once 'library/simplepie/simplepie.inc'; $feed = new SimplePie(); $xml = fetch_url($poll); logger('probe_url: fetch feed: ' . $poll . ' returns: ' . $xml, LOGGER_DATA); $a = get_app(); logger('probe_url: scrape_feed: headers: ' . $a->get_curl_headers(), LOGGER_DATA); $feed->set_raw_data($xml); $feed->init(); if ($feed->error()) { logger('probe_url: scrape_feed: Error parsing XML: ' . $feed->error()); } if (!x($vcard, 'photo')) { $vcard['photo'] = $feed->get_image_url(); } $author = $feed->get_author(); if ($author) { $vcard['fn'] = unxmlify(trim($author->get_name())); if (!$vcard['fn']) { $vcard['fn'] = trim(unxmlify($author->get_email())); } if (strpos($vcard['fn'], '@') !== false) { $vcard['fn'] = substr($vcard['fn'], 0, strpos($vcard['fn'], '@')); } $email = unxmlify($author->get_email()); if (!$profile && $author->get_link()) { $profile = trim(unxmlify($author->get_link())); } if (!$vcard['photo']) { $rawtags = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); if ($rawtags) { $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo') { $vcard['photo'] = $elems['link'][0]['attribs']['']['href']; } } } } else { $item = $feed->get_item(0); if ($item) { $author = $item->get_author(); if ($author) { $vcard['fn'] = trim(unxmlify($author->get_name())); if (!$vcard['fn']) { $vcard['fn'] = trim(unxmlify($author->get_email())); } if (strpos($vcard['fn'], '@') !== false) { $vcard['fn'] = substr($vcard['fn'], 0, strpos($vcard['fn'], '@')); } $email = unxmlify($author->get_email()); if (!$profile && $author->get_link()) { $profile = trim(unxmlify($author->get_link())); } } if (!$vcard['photo']) { $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/', 'thumbnail'); if ($rawmedia && $rawmedia[0]['attribs']['']['url']) { $vcard['photo'] = unxmlify($rawmedia[0]['attribs']['']['url']); } } if (!$vcard['photo']) { $rawtags = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); if ($rawtags) { $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo') { $vcard['photo'] = $elems['link'][0]['attribs']['']['href']; } } } } } if (!$vcard['photo'] && strlen($email)) { $vcard['photo'] = avatar_img($email); } if ($poll === $profile) { $lnk = $feed->get_permalink(); } if (isset($lnk) && strlen($lnk)) { $profile = $lnk; } if (!x($vcard, 'fn')) { $vcard['fn'] = notags($feed->get_title()); } if (!x($vcard, 'fn')) { $vcard['fn'] = notags($feed->get_description()); } if (strpos($vcard['fn'], 'Twitter / ') !== false) { $vcard['fn'] = substr($vcard['fn'], strpos($vcard['fn'], '/') + 1); $vcard['fn'] = trim($vcard['fn']); } if (!x($vcard, 'nick')) { $vcard['nick'] = strtolower(notags(unxmlify($vcard['fn']))); if (strpos($vcard['nick'], ' ')) { $vcard['nick'] = trim(substr($vcard['nick'], 0, strpos($vcard['nick'], ' '))); } } if (!$network) { $network = NETWORK_FEED; } if (!$priority) { $priority = 2; } } } if (!x($vcard, 'photo')) { $a = get_app(); $vcard['photo'] = $a->get_baseurl() . '/images/person-175.jpg'; } if (!$profile) { $profile = $url; } // No human could be associated with this link, use the URL as the contact name if ($network === NETWORK_FEED && $poll && !x($vcard, 'fn')) { $vcard['fn'] = $url; } $vcard['fn'] = notags($vcard['fn']); $vcard['nick'] = str_replace(' ', '', notags($vcard['nick'])); $result['name'] = $vcard['fn']; $result['nick'] = $vcard['nick']; $result['url'] = $profile; $result['addr'] = $addr; $result['batch'] = $batch; $result['notify'] = $notify; $result['poll'] = $poll; $result['request'] = $request; $result['confirm'] = $confirm; $result['poco'] = $poco; $result['photo'] = $vcard['photo']; $result['priority'] = $priority; $result['network'] = $network; $result['alias'] = $alias; $result['pubkey'] = $pubkey; logger('probe_url: ' . print_r($result, true), LOGGER_DEBUG); return $result; }
/** * Given the XML source of an export, imports each post into Known. * @param $xml */ static function importFeedXML($xml) { // Blogger will be imported as blog posts, so make sure we can import those ... if (!($text = site()->plugins()->get('Text'))) { return false; } $xml_parser = new \SimplePie(); $xml_parser->set_raw_data($xml); $xml_parser->init(); if ($items = $xml_parser->get_items()) { foreach ($items as $item) { /* @var \SimplePie_Item $item */ $post_type = 'post'; if ($categories = $item->get_categories()) { foreach ($categories as $category) { if (!empty($category->term) && !empty($category->scheme)) { if ($category->scheme == 'http://schemas.google.com/g/2005#kind') { foreach (['settings', 'template', 'comment'] as $term) { if (substr_count($category->term, $term)) { $post_type = $term; } } } } } } if ($post_type == 'post') { $body = $item->get_content(); $tags = []; if ($categories = $item->get_categories()) { foreach ($categories as $category) { if (empty($category->scheme) || $category->scheme != 'http://schemas.google.com/g/2005#kind') { $tags[] = '#' . preg_replace('/\\W+/', '', $category->term); } } } if (!empty($tags)) { $body .= '<p>' . implode(' ', $tags) . '</p>'; } self::importImagesFromBodyHTML($body, 'blogspot.com'); $object = new \IdnoPlugins\Text\Entry(); $object->setTitle(html_entity_decode($item->get_title())); $object->created = strtotime($item->get_date("c")); $object->body = $body; $object->save(true); } } } }
function salmon_post(&$a) { $xml = file_get_contents('php://input'); logger('mod-salmon: new salmon ' . $xml, LOGGER_DATA); $nick = $a->argc > 1 ? notags(trim($a->argv[1])) : ''; $mentions = $a->argc > 2 && $a->argv[2] === 'mention' ? true : false; $r = q("SELECT * FROM `user` WHERE `nickname` = '%s' AND `account_expired` = 0 AND `account_removed` = 0 LIMIT 1", dbesc($nick)); if (!count($r)) { http_status_exit(500); } $importer = $r[0]; // parse the xml $dom = simplexml_load_string($xml, 'SimpleXMLElement', 0, NAMESPACE_SALMON_ME); // figure out where in the DOM tree our data is hiding if ($dom->provenance->data) { $base = $dom->provenance; } elseif ($dom->env->data) { $base = $dom->env; } elseif ($dom->data) { $base = $dom; } if (!$base) { logger('mod-salmon: unable to locate salmon data in xml '); http_status_exit(400); } // Stash the signature away for now. We have to find their key or it won't be good for anything. $signature = base64url_decode($base->sig); // unpack the data // strip whitespace so our data element will return to one big base64 blob $data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $base->data); // stash away some other stuff for later $type = $base->data[0]->attributes()->type[0]; $keyhash = $base->sig[0]->attributes()->keyhash[0]; $encoding = $base->encoding; $alg = $base->alg; // Salmon magic signatures have evolved and there is no way of knowing ahead of time which // flavour we have. We'll try and verify it regardless. $stnet_signed_data = $data; $signed_data = $data . '.' . base64url_encode($type) . '.' . base64url_encode($encoding) . '.' . base64url_encode($alg); $compliant_format = str_replace('=', '', $signed_data); // decode the data $data = base64url_decode($data); // Remove the xml declaration $data = preg_replace('/\\<\\?xml[^\\?].*\\?\\>/', '', $data); // Create a fake feed wrapper so simplepie doesn't choke $tpl = get_markup_template('fake_feed.tpl'); $base = substr($data, strpos($data, '<entry')); $feedxml = $tpl . $base . '</feed>'; logger('mod-salmon: Processed feed: ' . $feedxml); // Now parse it like a normal atom feed to scrape out the author URI $feed = new SimplePie(); $feed->set_raw_data($feedxml); $feed->enable_order_by_date(false); $feed->init(); logger('mod-salmon: Feed parsed.'); if ($feed->get_item_quantity()) { foreach ($feed->get_items() as $item) { $author = $item->get_author(); $author_link = unxmlify($author->get_link()); break; } } if (!$author_link) { logger('mod-salmon: Could not retrieve author URI.'); http_status_exit(400); } // Once we have the author URI, go to the web and try to find their public key logger('mod-salmon: Fetching key for ' . $author_link); $key = get_salmon_key($author_link, $keyhash); if (!$key) { logger('mod-salmon: Could not retrieve author key.'); http_status_exit(400); } $key_info = explode('.', $key); $m = base64url_decode($key_info[1]); $e = base64url_decode($key_info[2]); logger('mod-salmon: key details: ' . print_r($key_info, true), LOGGER_DEBUG); $pubkey = metopem($m, $e); // We should have everything we need now. Let's see if it verifies. $verify = rsa_verify($compliant_format, $signature, $pubkey); if (!$verify) { logger('mod-salmon: message did not verify using protocol. Trying padding hack.'); $verify = rsa_verify($signed_data, $signature, $pubkey); } if (!$verify) { logger('mod-salmon: message did not verify using padding. Trying old statusnet hack.'); $verify = rsa_verify($stnet_signed_data, $signature, $pubkey); } if (!$verify) { logger('mod-salmon: Message did not verify. Discarding.'); http_status_exit(400); } logger('mod-salmon: Message verified.'); /* * * If we reached this point, the message is good. Now let's figure out if the author is allowed to send us stuff. * */ $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s' ) \n\t\tAND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), dbesc($author_link), intval($importer['uid'])); if (!count($r)) { logger('mod-salmon: Author unknown to us.'); if (get_pconfig($importer['uid'], 'system', 'ostatus_autofriend')) { require_once 'include/follow.php'; $result = new_contact($importer['uid'], $author_link); if ($result['success']) { $r = q("SELECT * FROM `contact` WHERE `network` = '%s' AND ( `url` = '%s' OR `alias` = '%s' ) \n\t\t\t\t\tAND `uid` = %d LIMIT 1", dbesc(NETWORK_OSTATUS), dbesc($author_link), dbesc($author_link), intval($importer['uid'])); } } } // is this a follower? Or have we ignored the person? // If so we can not accept this post. if (count($r) && ($r[0]['readonly'] || $r[0]['rel'] == CONTACT_IS_FOLLOWER || $r[0]['blocked'])) { logger('mod-salmon: Ignoring this author.'); http_status_exit(202); // NOTREACHED } require_once 'include/items.php'; // Placeholder for hub discovery. We shouldn't find any hubs // since we supplied the fake feed header - and it doesn't have any. $hub = ''; /** * * anti-spam measure: consume_feed will accept a follow activity from * this person (and nothing else) if there is no existing contact record. * */ $contact_rec = count($r) ? $r[0] : null; consume_feed($feedxml, $importer, $contact_rec, $hub); http_status_exit(200); }
/** * Gets the list of blogs from blogger into an array $this->blogs[] */ function get_blogs($iter = 0) { $xml = $this->connector->oauth_get('https://www.blogger.com/feeds/default/blogs'); // Give it a few retries... apparently this step often flakes out the first time. if (empty($xml)) { if ($iter < 3) { return $this->get_blogs($iter + 1); } else { return false; } } $feed = new SimplePie(); $feed->set_raw_data($xml); $feed->init(); $i = 0; foreach ($feed->get_items() as $item) { $blog = new Blogger_Importer_Blog(); $blog->ID = $i++; //Perhaps these could be passed as parameters to the new blog object or the init defaults call? $blog->title = $item->get_title(); $blog->summary = $item->get_description(); //ID is of the form tag:blogger.com,1999:blog-417730729915399755 //We need that number from the end $rawid = explode('-', $item->get_id()); $blog->id = $rawid[count($rawid) - 1]; $parts = parse_url($item->get_link(0, 'alternate')); $blog->host = $parts['host']; $blog->gateway = $item->get_link(0, 'edit'); $blog->posts_url = $item->get_link(0, 'http://schemas.google.com/g/2005#post'); //AGC:20/4/2012 Developers guide suggests that the correct feed is located as follows //See https://developers.google.com/blogger/docs/1.0/developers_guide_php $blog->comments_url = "http://www.blogger.com/feeds/{$blog->id}/comments/default"; $blog->init_defaults($this->connector->get_total_results($blog->posts_url),$this->connector->get_total_results($blog->comments_url)); $this->blogs[] = $blog; } return true; }
/** * setup simplepie */ private function _setup_simplepie($feed_url) { $data = new SimplePie(); // Convert To GeoRSS feed $geocoder = new Geocoder(); $georss_feed = $geocoder->geocode_feed($feed_url); $data->set_raw_data($georss_feed); $data->enable_cache(false); $data->enable_order_by_date(true); $data->init(); $data->handle_content_type(); return $data; }
function dfrn_notify_post(&$a) { $dfrn_id = notags(trim($_POST['dfrn_id'])); $challenge = notags(trim($_POST['challenge'])); $data = $_POST['data']; $r = q("SELECT * FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge)); if (!count($r)) { xml_status(3); } $r = q("DELETE FROM `challenge` WHERE `dfrn-id` = '%s' AND `challenge` = '%s' LIMIT 1", dbesc($dfrn_id), dbesc($challenge)); // find the local user who owns this relationship. $r = q("SELECT `contact`.*, `user`.* FROM `contact` LEFT JOIN `user` on `user`.`uid` = 1 \n\t\tWHERE ( `issued-id` = '%s' OR ( `duplex` = 1 AND `dfrn-id` = '%s' )) LIMIT 1", dbesc($dfrn_id), dbesc($dfrn_id)); if (!count($r)) { xml_status(3); return; //NOTREACHED } $importer = $r[0]; $feed = new SimplePie(); $feed->set_raw_data($data); $feed->enable_order_by_date(false); $feed->init(); $ismail = false; $rawmail = $feed->get_feed_tags(NAMESPACE_DFRN, 'mail'); if (isset($rawmail[0]['child'][NAMESPACE_DFRN])) { if ($importer['readonly']) { // We aren't receiving email from this person. But we will quietly ignore them // rather than a blatant "go away" message. xml_status(0); return; //NOTREACHED } $ismail = true; $base = $rawmail[0]['child'][NAMESPACE_DFRN]; $msg = array(); $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data'])); $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data'])); $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])); $msg['contact-id'] = $importer['id']; $msg['title'] = notags(unxmlify($base['subject'][0]['data'])); $msg['body'] = escape_tags(unxmlify($base['content'][0]['data'])); $msg['delivered'] = 1; $msg['seen'] = 0; $msg['replied'] = 0; $msg['uri'] = notags(unxmlify($base['id'][0]['data'])); $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data'])); $msg['created'] = datetime_convert(notags(unxmlify('UTC', 'UTC', $base['sentdate'][0]['data']))); dbesc_array($msg); $r = q("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) . "`) VALUES ('" . implode("', '", array_values($msg)) . "')"); require_once 'bbcode.php'; if ($importer['notify-flags'] & NOTIFY_MAIL) { $tpl = file_get_contents('view/mail_received_eml.tpl'); $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $importer['username'], '$email' => $importer['email'], '$from' => $msg['from-name'], '$title' => $msg['title'], '$body' => strip_tags(bbcode($msg['body'])))); $res = mail($importer['email'], t("New mail received at ") . $a->config['sitename'], $email_tpl, t("From: Administrator@") . $a->get_hostname()); } xml_status(0); return; // NOTREACHED } if ($importer['readonly'] && !x($a->config['rockstar'])) { // This contact is readonly and we're going to ignore him/her, except if we're in // RockStar configuration. Us rockstars wan't people to talk about us. We just don't // want to have to deal with them individually. So our "readonly" fans can post to // our wall and comment, but they can't send us email. xml_status(0); return; // NOTREACHED } foreach ($feed->get_items() as $item) { $deleted = false; $rawdelete = $item->get_item_tags("http://purl.org/atompub/tombstones/1.0", 'deleted-entry'); if (isset($rawdelete[0]['attribs']['']['ref'])) { $uri = $rawthread[0]['attribs']['']['ref']; $deleted = true; if (isset($rawdelete[0]['attribs']['']['when'])) { $when = $rawthread[0]['attribs']['']['when']; $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s'); } else { $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s'); } } if ($deleted) { $r = q("SELECT * FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($uri)); if (count($r)) { $item = $r[0]; if ($item['uri'] == $item['parent-uri']) { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s' , `changed` = '%s'\n\t\t\t\t\t\tWHERE `parent-uri` = '%s'", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri'])); } else { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s' , `changed` = '%s' \n\t\t\t\t\t\tWHERE `uri` = '%s' LIMIT 1", dbesc($when), dbesc(datetime_convert()), dbesc($uri)); } if ($item['last-child']) { // ensure that last-child is set in case the comment that had it just got wiped. $q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' ", dbesc(datetime_convert()), dbesc($item['parent-uri'])); // who is the last child now? $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 \n\t\t\t\t\t\tORDER BY `edited` DESC LIMIT 1", dbesc($item['parent-uri'])); if (count($r)) { q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d LIMIT 1", intval($r[0]['id'])); } } } continue; } $is_reply = false; $item_id = $item->get_id(); $rawthread = $item->get_item_tags("http://purl.org/syndication/thread/1.0", 'in-reply-to'); if (isset($rawthread[0]['attribs']['']['ref'])) { $is_reply = true; $parent_uri = $rawthread[0]['attribs']['']['ref']; } if ($is_reply) { if ($feed->get_item_quantity() == 1) { // remote reply to our post. Import and then notify everybody else. $datarray = get_atom_elements($item); $datarray['wall'] = 1; $datarray['type'] = 'remote-comment'; $datarray['parent-uri'] = $parent_uri; $datarray['contact-id'] = $importer['id']; $posted_id = post_remote($a, $datarray); if ($posted_id) { $r = q("SELECT `parent` FROM `item` WHERE `id` = %d LIMIT 1", intval($posted_id)); if (count($r)) { $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent` = %d", dbesc(datetime_convert()), intval($r[0]['parent'])); } $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), intval($posted_id)); $php_path = strlen($a->config['php_path']) ? $a->config['php_path'] : 'php'; proc_close(proc_open("\"{$php_path}\" \"include/notifier.php\" \"comment-import\" \"{$posted_id}\" &", array(), $foo)); if ($importer['notify-flags'] & NOTIFY_COMMENT && !$importer['self']) { require_once 'bbcode.php'; $from = stripslashes($datarray['author-name']); $tpl = file_get_contents('view/cmnt_received_eml.tpl'); $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $importer['username'], '$email' => $importer['email'], '$from' => $from, '$body' => strip_tags(bbcode(stripslashes($datarray['body']))))); $res = mail($importer['email'], $from . t(" commented on your item at ") . $a->config['sitename'], $email_tpl, t("From: Administrator@") . $a->get_hostname()); } } xml_status(0); return; } else { // regular comment that is part of this total conversation. Have we seen it? If not, import it. $item_id = $item->get_id(); $r = q("SELECT `last-child`, `edited` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($item_id)); // FIXME update content if 'updated' changes if (count($r)) { $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow'); if ($allow && $allow[0]['data'] != $r[0]['last-child']) { $r = q("UPDATE `item` SET `last-child` = %d, `changed` = '%s' WHERE `uri` = '%s' LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id)); } continue; } $datarray = get_atom_elements($item); $datarray['parent-uri'] = $parent_uri; $datarray['contact-id'] = $importer['id']; $r = post_remote($a, $datarray); // find out if our user is involved in this conversation and wants to be notified. if ($importer['notify-flags'] & NOTIFY_COMMENT) { $myconv = q("SELECT `author-link` FROM `item` WHERE `parent-uri` = '%s'", dbesc($parent_uri)); if (count($myconv)) { foreach ($myconv as $conv) { if ($conv['author-link'] != $importer['url']) { continue; } require_once 'bbcode.php'; $from = stripslashes($datarray['author-name']); $tpl = file_get_contents('view/cmnt_received_eml.tpl'); $email_tpl = replace_macros($tpl, array('$sitename' => $a->config['sitename'], '$siteurl' => $a->get_baseurl(), '$username' => $importer['username'], '$email' => $importer['email'], '$from' => $from, '$body' => strip_tags(bbcode(stripslashes($datarray['body']))))); $res = mail($importer['email'], $from . t(" commented on an item at ") . $a->config['sitename'], $email_tpl, t("From: Administrator@") . $a->get_hostname()); break; } } } continue; } } else { // Head post of a conversation. Have we seen it? If not, import it. $item_id = $item->get_id(); $r = q("SELECT `last-child`, `edited` FROM `item` WHERE `uri` = '%s' LIMIT 1", dbesc($item_id)); if (count($r)) { $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow'); if ($allow && $allow[0]['data'] != $r[0]['last-child']) { $r = q("UPDATE `item` SET `last-child` = %d, `changed` = '%s' WHERE `uri` = '%s' LIMIT 1", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id)); } continue; } $datarray = get_atom_elements($item); $datarray['parent-uri'] = $item_id; $datarray['contact-id'] = $importer['id']; $r = post_remote($a, $datarray); continue; } } xml_status(0); killme(); }
/** * Get a specific data metrics * * @param metrics - the metrics to get * @param startDate - the start date to get * @param endDate - the end date to get * @param dimensions - the dimensions to grab * @param sort - the properties to sort on * @param filter - the property to filter on * @param limit - the number of items to get * @return the specific metrics in array form **/ function getMetrics($metric, $startDate, $endDate, $dimensions = false, $sort = false, $filter = false, $limit = false) { # Ensure the start date is after Jan 1 2005 $startDate = $this->verifyStartDate($startDate); # Build the query url $url = $this->baseFeed . "/data?ids={$this->accountId}&start-date={$startDate}&end-date={$endDate}&metrics={$metric}"; # Add optional dimensions if ($dimensions) { $url .= "&dimensions={$dimensions}"; } # Add optional sort if ($sort) { $url .= "&sort={$sort}"; } # Add optional filter if ($filter) { $url .= "&filters={$filter}"; } # Add optional limit if ($limit) { $url .= "&max-results={$limit}"; } # Request the metric data $response = $this->http($url); # Check if the response received exists, else stop processing now if ($response == '' || $this->responseCode != '200') { return false; } # Parse the XML using SimplePie $simplePie = new SimplePie(); $simplePie->set_raw_data($response); $simplePie->enable_order_by_date(false); $simplePie->init(); $simplePie->handle_content_type(); $datas = $simplePie->get_items(); $ids = array(); # Read out the data until the metric is found foreach ($datas as $data) { $metrics = $data->get_item_tags('http://schemas.google.com/analytics/2009', 'metric'); $dimensions = $data->get_item_tags('http://schemas.google.com/analytics/2009', 'dimension'); $id = array(); $id['title'] = $data->get_title(); # Loop through the dimensions if (is_array($dimensions)) { foreach ($dimensions as $property) { # Get the property information $name = $property['attribs']['']['name']; $value = $property['attribs']['']['value']; # Add the propery data to the id array $id[$name] = $value; } } # Loop through the metrics if (is_array($metrics)) { foreach ($metrics as $property) { # Get the property information $name = $property['attribs']['']['name']; $value = $property['attribs']['']['value']; # Add the propery data to the id array $id[$name] = $value; } } $ids[] = $id; } return $ids; }
openssl_public_decrypt($challenge, $postvars['challenge'], $contact['pubkey']); } $final_dfrn_id = substr($final_dfrn_id, 0, strpos($final_dfrn_id, '.')); if ($final_dfrn_id != $idtosend) { // did not decode properly - cannot trust this site continue; } $postvars['dfrn_id'] = $idtosend; $xml = post_url($contact['poll'], $postvars); if (!strlen($xml)) { // an empty response may mean there's nothing new - record the fact that we checked $r = q("UPDATE `contact` SET `last-update` = '%s' WHERE `id` = %d LIMIT 1", dbesc(datetime_convert()), intval($contact['id'])); continue; } $feed = new SimplePie(); $feed->set_raw_data($xml); $feed->enable_order_by_date(false); $feed->init(); // Check at the feed level for updated contact name and/or photo $name_updated = ''; $new_name = ''; $photo_timestamp = ''; $photo_url = ''; $rawtags = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, author); if ($rawtags) { $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; if ($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) { $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']; $new_name = $elems['name'][0]['data']; } if ($elems['link'][0]['attribs']['']['rel'] == 'photo' && $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']) {
function discover_by_url($url, $arr = null) { require_once 'library/HTML5/Parser.php'; $x = scrape_feed($url); if (!$x) { if (!$arr) { return false; } $network = $arr['network'] ? $arr['network'] : 'unknown'; $name = $arr['name'] ? $arr['name'] : 'unknown'; $photo = $arr['photo'] ? $arr['photo'] : ''; $addr = $arr['addr'] ? $arr['addr'] : ''; $guid = $url; } $profile = $url; logger('scrape_feed results: ' . print_r($x, true)); if ($x['feed_atom']) { $guid = $x['feed_atom']; } if ($x['feed_rss']) { $guid = $x['feed_rss']; } if (!$guid) { return false; } // try and discover stuff from the feeed require_once 'library/simplepie/simplepie.inc'; $feed = new SimplePie(); $level = 0; $x = z_fetch_url($guid, false, $level, array('novalidate' => true)); if (!$x['success']) { logger('probe_url: feed fetch failed for ' . $poll); return false; } $xml = $x['body']; logger('probe_url: fetch feed: ' . $guid . ' returns: ' . $xml, LOGGER_DATA); logger('probe_url: scrape_feed: headers: ' . $x['header'], LOGGER_DATA); // Don't try and parse an empty string $feed->set_raw_data($xml ? $xml : '<?xml version="1.0" encoding="utf-8" ?><xml></xml>'); $feed->init(); if ($feed->error()) { logger('probe_url: scrape_feed: Error parsing XML: ' . $feed->error()); } $name = unxmlify(trim($feed->get_title())); $photo = $feed->get_image_url(); $author = $feed->get_author(); if ($author) { if (!$name) { $name = unxmlify(trim($author->get_name())); } if (!$name) { $name = trim(unxmlify($author->get_email())); if (strpos($name, '@') !== false) { $name = substr($name, 0, strpos($name, '@')); } } if (!$profile && $author->get_link()) { $profile = trim(unxmlify($author->get_link())); } if (!$photo) { $rawtags = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); if ($rawtags) { $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo') { $photo = $elems['link'][0]['attribs']['']['href']; } } } } else { $item = $feed->get_item(0); if ($item) { $author = $item->get_author(); if ($author) { if (!$name) { $name = trim(unxmlify($author->get_name())); if (!$name) { $name = trim(unxmlify($author->get_email())); } if (strpos($name, '@') !== false) { $name = substr($name, 0, strpos($name, '@')); } } if (!$profile && $author->get_link()) { $profile = trim(unxmlify($author->get_link())); } } if (!$photo) { $rawmedia = $item->get_item_tags('http://search.yahoo.com/mrss/', 'thumbnail'); if ($rawmedia && $rawmedia[0]['attribs']['']['url']) { $photo = unxmlify($rawmedia[0]['attribs']['']['url']); } } if (!$photo) { $rawtags = $item->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); if ($rawtags) { $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo') { $photo = $elems['link'][0]['attribs']['']['href']; } } } } } if ($poll === $profile) { $lnk = $feed->get_permalink(); } if (isset($lnk) && strlen($lnk)) { $profile = $lnk; } if (!$network) { $network = 'rss'; } if (!$name) { $name = notags($feed->get_description()); } if (!$guid) { return false; } $r = q("select * from xchan where xchan_hash = '%s' limit 1", dbesc($guid)); if ($r) { return true; } if (!$photo) { $photo = z_root() . '/images/rss_icon.png'; } $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_instance_url, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", dbesc($guid), dbesc($guid), dbesc($pubkey), dbesc($addr), dbesc($profile), dbesc($name), dbesc($network), dbesc(z_root()), dbesc(datetime_convert())); $photos = import_xchan_photo($photo, $guid); $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", dbesc(datetime_convert()), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), dbesc($photos[3]), dbesc($guid)); return true; }
/** * Main method to import the feed items * * @since 4.0 * @access public * @param string * @return */ public function import(EasyBlogTableFeed &$feed, $limit = 0) { // Load site language file EB::loadLanguages(); // Import simplepie library jimport('simplepie.simplepie'); // We need DomDocument to exist if (!class_exists('DomDocument')) { return false; } // Set the maximum execution time to a higher value @ini_set('max_execution_time', 720); // Get the feed params $params = EB::registry($feed->params); // Determines the limit of items to fetch $limit = $limit ? $limit : $params->get('feedamount', 0); // Setup the outgoing connection to the feed source $connector = EB::connector(); $connector->addUrl($feed->url); $connector->execute(); // Get the contents $contents = $connector->getResult($feed->url); // If contents is empty, we know something failed if (!$contents) { return EB::exception(JText::sprintf('COM_EASYBLOG_FEEDS_UNABLE_TO_REACH_TARGET_URL', $feed->url), EASYBLOG_MSG_ERROR); } // Get the cleaner to clean things up $cleaner = $this->getAdapter('Cleaner'); $contents = $cleaner->cleanup($contents); // Load up the xml parser $parser = new SimplePie(); $parser->strip_htmltags(false); $parser->set_raw_data($contents); @$parser->init(); // Get a list of items // We need to supress errors here because simplepie will throw errors on STRICT mode. $items = @$parser->get_items(); if (!$items) { // TODO: Language string return EB::exception('COM_EASYBLOG_FEEDS_NOTHING_TO_BE_IMPORTED_CURRENTLY', EASYBLOG_MSG_ERROR); } // Get the feeds model $model = EB::model('Feeds'); // Determines the total number of items migrated $total = 0; foreach ($items as $item) { // If it reaches limit, skip processing if ($limit && $total == $limit) { break; } // Get the item's unique id $uid = @$item->get_id(); // If item already exists, skip this if ($model->isFeedItemImported($feed->id, $uid)) { continue; } // Log down a new history record to avoid fetching of the same item again $history = EB::table('FeedHistory'); $history->feed_id = $feed->id; $history->uid = $uid; $history->created = EB::date()->toSql(); $history->store(); // Get the item's link $link = @$item->get_link(); // Load up the post library $post = EB::post(); $createOption = array('overrideDoctType' => 'legacy', 'checkAcl' => false, 'overrideAuthorId' => $feed->item_creator); $post->create($createOption); // Pass this to the adapter to map the items $mapper = $this->getAdapter('Mapper'); $mapper->map($post, $item, $feed, $params); // Now we need to get the content of the blog post $mapper->mapContent($post, $item, $feed, $params); $saveOptions = array('applyDateOffset' => false, 'validateData' => false, 'useAuthorAsRevisionOwner' => true, 'checkAcl' => false, 'overrideAuthorId' => $feed->item_creator); // Try to save the blog post now try { $post->save($saveOptions); // Update the history table $history->post_id = $post->id; $history->store(); $total++; } catch (EasyBlogException $exception) { // do nothing. } } return EB::exception(JText::sprintf('COM_EASYBLOG_FEEDS_POSTS_MIGRATED_FROM_FEED', $total, $feed->url), EASYBLOG_MSG_SUCCESS); }
function feed_meta($xml) { require_once 'library/simplepie/simplepie.inc'; $ret = array(); if (!strlen($xml)) { logger('empty input'); return $ret; } $feed = new SimplePie(); $feed->set_raw_data($xml); $feed->init(); if ($feed->error()) { logger('Error parsing XML: ' . $feed->error()); return $ret; } $ret['hubs'] = $feed->get_links('hub'); // logger('consume_feed: hubs: ' . print_r($hubs,true), LOGGER_DATA); $author = array(); $found_author = $feed->get_author(); if ($found_author) { $author['author_name'] = unxmlify($found_author->get_name()); $author['author_link'] = unxmlify($found_author->get_link()); $rawauthor = $feed->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); logger('rawauthor: ' . print_r($rawauthor, true)); if ($rawauthor) { if ($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']) { $base = $rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['link']; foreach ($base as $link) { if (!x($author, 'author_photo') || !$author['author_photo']) { if ($link['attribs']['']['rel'] === 'photo' || $link['attribs']['']['rel'] === 'avatar') { $author['author_photo'] = unxmlify($link['attribs']['']['href']); break; } } } } if ($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']) { $author['full_name'] = unxmlify($rawauthor[0]['child'][NAMESPACE_POCO]['displayName'][0]['data']); } if ($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']) { $author['author_uri'] = unxmlify($rawauthor[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']); } } } if (substr($author['author_link'], -1, 1) == '/') { $author['author_link'] = substr($author['author_link'], 0, -1); } $ret['author'] = $author; return $ret; }
/** * @brief Process atom feed and update anything/everything we might need to update. * * $hub = should we find a hub declation in the feed, pass it back to our calling process, who might (or * might not) try and subscribe to it. * $datedir sorts in reverse order * * @param array $xml * The (atom) feed to consume - RSS isn't as fully supported but may work for simple feeds. * @param $importer * The contact_record (joined to user_record) of the local user who owns this * relationship. It is this person's stuff that is going to be updated. * @param $contact * The person who is sending us stuff. If not set, we MAY be processing a "follow" activity * from an external network and MAY create an appropriate contact record. Otherwise, we MUST * have a contact record. * @param int $pass by default ($pass = 0) we cannot guarantee that a parent item has been * imported prior to its children being seen in the stream unless we are certain * of how the feed is arranged/ordered. * * With $pass = 1, we only pull parent items out of the stream. * * With $pass = 2, we only pull children (comments/likes). * * So running this twice, first with pass 1 and then with pass 2 will do the right * thing regardless of feed ordering. This won't be adequate in a fully-threaded * model where comments can have sub-threads. That would require some massive sorting * to get all the feed items into a mostly linear ordering, and might still require * recursion. */ function consume_feed($xml, $importer, &$contact, $pass = 0) { require_once 'library/simplepie/simplepie.inc'; if (!strlen($xml)) { logger('consume_feed: empty input'); return; } $feed = new SimplePie(); $feed->set_raw_data($xml); $feed->init(); if ($feed->error()) { logger('consume_feed: Error parsing XML: ' . $feed->error()); } $permalink = $feed->get_permalink(); // Check at the feed level for updated contact name and/or photo // process any deleted entries $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry'); if (is_array($del_entries) && count($del_entries) && $pass != 2) { foreach ($del_entries as $dentry) { $deleted = false; if (isset($dentry['attribs']['']['ref'])) { $mid = $dentry['attribs']['']['ref']; $deleted = true; if (isset($dentry['attribs']['']['when'])) { $when = $dentry['attribs']['']['when']; $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s'); } else { $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s'); } } if ($deleted && is_array($contact)) { $r = q("SELECT * from item where mid = '%s' and author_xchan = '%s' and uid = %d limit 1", dbesc(base64url_encode($mid)), dbesc($contact['xchan_hash']), intval($importer['channel_id'])); if ($r) { $item = $r[0]; if (!($item['item_restrict'] & ITEM_DELETED)) { logger('consume_feed: deleting item ' . $item['id'] . ' mid=' . base64url_decode($item['mid']), LOGGER_DEBUG); drop_item($item['id'], false); } } } } } // Now process the feed if ($feed->get_item_quantity()) { logger('consume_feed: feed item count = ' . $feed->get_item_quantity(), LOGGER_DEBUG); $items = $feed->get_items(); foreach ($items as $item) { $is_reply = false; $item_id = base64url_encode($item->get_id()); logger('consume_feed: processing ' . $item_id, LOGGER_DEBUG); $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to'); if (isset($rawthread[0]['attribs']['']['ref'])) { $is_reply = true; $parent_mid = base64url_encode($rawthread[0]['attribs']['']['ref']); } if ($is_reply) { if ($pass == 1) { continue; } // Have we seen it? If not, import it. $item_id = base64url_encode($item->get_id()); $author = array(); $datarray = get_atom_elements($feed, $item, $author); if (!x($author, 'author_name') || $author['author_is_feed']) { $author['author_name'] = $contact['xchan_name']; } if (!x($author, 'author_link') || $author['author_is_feed']) { $author['author_link'] = $contact['xchan_url']; } if (!x($author, 'author_photo') || $author['author_is_feed']) { $author['author_photo'] = $contact['xchan_photo_m']; } $datarray['author_xchan'] = ''; if ($author['author_link'] != $contact['xchan_url']) { $x = import_author_unknown(array('name' => $author['author_name'], 'url' => $author['author_link'], 'photo' => array('src' => $author['author_photo']))); if ($x) { $datarray['author_xchan'] = $x; } } if (!$datarray['author_xchan']) { $datarray['author_xchan'] = $contact['xchan_hash']; } $datarray['owner_xchan'] = $contact['xchan_hash']; $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id'])); // Update content if 'updated' changes if ($r) { if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) { // do not accept (ignore) an earlier edit than one we currently have. if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) { continue; } update_feed_item($importer['channel_id'], $datarray); } continue; } $datarray['parent_mid'] = $parent_mid; $datarray['uid'] = $importer['channel_id']; logger('consume_feed: ' . print_r($datarray, true), LOGGER_DATA); $xx = item_store($datarray); $r = $xx['item_id']; continue; } else { // Head post of a conversation. Have we seen it? If not, import it. $item_id = base64url_encode($item->get_id()); $author = array(); $datarray = get_atom_elements($feed, $item, $author); if (is_array($contact)) { if (!x($author, 'author_name') || $author['author_is_feed']) { $author['author_name'] = $contact['xchan_name']; } if (!x($author, 'author_link') || $author['author_is_feed']) { $author['author_link'] = $contact['xchan_url']; } if (!x($author, 'author_photo') || $author['author_is_feed']) { $author['author_photo'] = $contact['xchan_photo_m']; } } if (!x($author, 'author_name') || !x($author, 'author_link')) { logger('consume_feed: no author information! ' . print_r($author, true)); continue; } $datarray['author_xchan'] = ''; if ($author['author_link'] != $contact['xchan_url']) { $x = import_author_unknown(array('name' => $author['author_name'], 'url' => $author['author_link'], 'photo' => array('src' => $author['author_photo']))); if ($x) { $datarray['author_xchan'] = $x; } } if (!$datarray['author_xchan']) { $datarray['author_xchan'] = $contact['xchan_hash']; } $datarray['owner_xchan'] = $contact['xchan_hash']; $r = q("SELECT edited FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", dbesc($item_id), intval($importer['channel_id'])); // Update content if 'updated' changes if ($r) { if (x($datarray, 'edited') !== false && datetime_convert('UTC', 'UTC', $datarray['edited']) !== $r[0]['edited']) { // do not accept (ignore) an earlier edit than one we currently have. if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) { continue; } update_feed_item($importer['channel_id'], $datarray); } continue; } $datarray['parent_mid'] = $item_id; $datarray['uid'] = $importer['channel_id']; if (!link_compare($author['owner_link'], $contact['xchan_url'])) { logger('consume_feed: Correcting item owner.', LOGGER_DEBUG); $author['owner_name'] = $contact['name']; $author['owner_link'] = $contact['url']; $author['owner_avatar'] = $contact['thumb']; } logger('consume_feed: author ' . print_r($author, true), LOGGER_DEBUG); logger('consume_feed: ' . print_r($datarray, true), LOGGER_DATA); $xx = item_store($datarray); $r = $xx['item_id']; continue; } } } }
function local_delivery($importer, $data) { $a = get_app(); logger(__FUNCTION__, LOGGER_TRACE); if ($importer['readonly']) { // We aren't receiving stuff from this person. But we will quietly ignore them // rather than a blatant "go away" message. logger('local_delivery: ignoring'); return 0; //NOTREACHED } // Consume notification feed. This may differ from consuming a public feed in several ways // - might contain email or friend suggestions // - might contain remote followup to our message // - in which case we need to accept it and then notify other conversants // - we may need to send various email notifications $feed = new SimplePie(); $feed->set_raw_data($data); $feed->enable_order_by_date(false); $feed->init(); if ($feed->error()) { logger('local_delivery: Error parsing XML: ' . $feed->error()); } // Check at the feed level for updated contact name and/or photo $name_updated = ''; $new_name = ''; $photo_timestamp = ''; $photo_url = ''; $contact_updated = ''; $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'owner'); // Fallback should not be needed here. If it isn't DFRN it won't have DFRN updated tags // if(! $rawtags) // $rawtags = $feed->get_feed_tags( SIMPLEPIE_NAMESPACE_ATOM_10, 'author'); if ($rawtags) { $elems = $rawtags[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_10]; if ($elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']) { $name_updated = $elems['name'][0]['attribs'][NAMESPACE_DFRN]['updated']; $new_name = $elems['name'][0]['data']; // Manually checking for changed contact names if ($new_name != $importer['name'] and $new_name != "" and $name_updated <= $importer['name-date']) { $name_updated = date("c"); $photo_timestamp = date("c"); } } if (x($elems, 'link') && $elems['link'][0]['attribs']['']['rel'] === 'photo' && $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']) { if ($photo_timestamp == "") { $photo_timestamp = datetime_convert('UTC', 'UTC', $elems['link'][0]['attribs'][NAMESPACE_DFRN]['updated']); } $photo_url = $elems['link'][0]['attribs']['']['href']; } } if ($photo_timestamp && strlen($photo_url) && $photo_timestamp > $importer['avatar-date']) { $contact_updated = $photo_timestamp; logger('local_delivery: Updating photo for ' . $importer['name']); require_once "include/Photo.php"; $photos = import_profile_photo($photo_url, $importer['importer_uid'], $importer['id']); q("UPDATE `contact` SET `avatar-date` = '%s', `photo` = '%s', `thumb` = '%s', `micro` = '%s'\n\t\t\tWHERE `uid` = %d AND `id` = %d AND NOT `self`", dbesc(datetime_convert()), dbesc($photos[0]), dbesc($photos[1]), dbesc($photos[2]), intval($importer['importer_uid']), intval($importer['id'])); } if ($name_updated && strlen($new_name) && $name_updated > $importer['name-date']) { if ($name_updated > $contact_updated) { $contact_updated = $name_updated; } $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `id` = %d LIMIT 1", intval($importer['importer_uid']), intval($importer['id'])); $x = q("UPDATE `contact` SET `name` = '%s', `name-date` = '%s' WHERE `uid` = %d AND `id` = %d AND `name` != '%s' AND NOT `self`", dbesc(notags(trim($new_name))), dbesc(datetime_convert()), intval($importer['importer_uid']), intval($importer['id']), dbesc(notags(trim($new_name)))); // do our best to update the name on content items if (count($r) and notags(trim($new_name)) != $r[0]['name']) { q("UPDATE `item` SET `author-name` = '%s' WHERE `author-name` = '%s' AND `author-link` = '%s' AND `uid` = %d AND `author-name` != '%s'", dbesc(notags(trim($new_name))), dbesc($r[0]['name']), dbesc($r[0]['url']), intval($importer['importer_uid']), dbesc(notags(trim($new_name)))); } } if ($contact_updated and $new_name and $photo_url) { poco_check($importer['url'], $new_name, NETWORK_DFRN, $photo_url, "", "", "", "", "", $contact_updated, 2, $importer['id'], $importer['importer_uid']); } // Currently unsupported - needs a lot of work $reloc = $feed->get_feed_tags(NAMESPACE_DFRN, 'relocate'); if (isset($reloc[0]['child'][NAMESPACE_DFRN])) { $base = $reloc[0]['child'][NAMESPACE_DFRN]; $newloc = array(); $newloc['uid'] = $importer['importer_uid']; $newloc['cid'] = $importer['id']; $newloc['name'] = notags(unxmlify($base['name'][0]['data'])); $newloc['photo'] = notags(unxmlify($base['photo'][0]['data'])); $newloc['thumb'] = notags(unxmlify($base['thumb'][0]['data'])); $newloc['micro'] = notags(unxmlify($base['micro'][0]['data'])); $newloc['url'] = notags(unxmlify($base['url'][0]['data'])); $newloc['request'] = notags(unxmlify($base['request'][0]['data'])); $newloc['confirm'] = notags(unxmlify($base['confirm'][0]['data'])); $newloc['notify'] = notags(unxmlify($base['notify'][0]['data'])); $newloc['poll'] = notags(unxmlify($base['poll'][0]['data'])); $newloc['sitepubkey'] = notags(unxmlify($base['sitepubkey'][0]['data'])); /** relocated user must have original key pair */ /*$newloc['pubkey'] = notags(unxmlify($base['pubkey'][0]['data'])); $newloc['prvkey'] = notags(unxmlify($base['prvkey'][0]['data']));*/ logger("items:relocate contact " . print_r($newloc, true) . print_r($importer, true), LOGGER_DEBUG); // update contact $r = q("SELECT photo, url FROM contact WHERE id=%d AND uid=%d;", intval($importer['id']), intval($importer['importer_uid'])); if ($r === false) { return 1; } $old = $r[0]; $x = q("UPDATE contact SET\n\t\t\t\t\tname = '%s',\n\t\t\t\t\tphoto = '%s',\n\t\t\t\t\tthumb = '%s',\n\t\t\t\t\tmicro = '%s',\n\t\t\t\t\turl = '%s',\n\t\t\t\t\tnurl = '%s',\n\t\t\t\t\trequest = '%s',\n\t\t\t\t\tconfirm = '%s',\n\t\t\t\t\tnotify = '%s',\n\t\t\t\t\tpoll = '%s',\n\t\t\t\t\t`site-pubkey` = '%s'\n\t\t\tWHERE id=%d AND uid=%d;", dbesc($newloc['name']), dbesc($newloc['photo']), dbesc($newloc['thumb']), dbesc($newloc['micro']), dbesc($newloc['url']), dbesc(normalise_link($newloc['url'])), dbesc($newloc['request']), dbesc($newloc['confirm']), dbesc($newloc['notify']), dbesc($newloc['poll']), dbesc($newloc['sitepubkey']), intval($importer['id']), intval($importer['importer_uid'])); if ($x === false) { return 1; } // update items $fields = array('owner-link' => array($old['url'], $newloc['url']), 'author-link' => array($old['url'], $newloc['url']), 'owner-avatar' => array($old['photo'], $newloc['photo']), 'author-avatar' => array($old['photo'], $newloc['photo'])); foreach ($fields as $n => $f) { $x = q("UPDATE `item` SET `%s`='%s' WHERE `%s`='%s' AND uid=%d", $n, dbesc($f[1]), $n, dbesc($f[0]), intval($importer['importer_uid'])); if ($x === false) { return 1; } } // TODO // merge with current record, current contents have priority // update record, set url-updated // update profile photos // schedule a scan? return 0; } // handle friend suggestion notification $sugg = $feed->get_feed_tags(NAMESPACE_DFRN, 'suggest'); if (isset($sugg[0]['child'][NAMESPACE_DFRN])) { $base = $sugg[0]['child'][NAMESPACE_DFRN]; $fsugg = array(); $fsugg['uid'] = $importer['importer_uid']; $fsugg['cid'] = $importer['id']; $fsugg['name'] = notags(unxmlify($base['name'][0]['data'])); $fsugg['photo'] = notags(unxmlify($base['photo'][0]['data'])); $fsugg['url'] = notags(unxmlify($base['url'][0]['data'])); $fsugg['request'] = notags(unxmlify($base['request'][0]['data'])); $fsugg['body'] = escape_tags(unxmlify($base['note'][0]['data'])); // Does our member already have a friend matching this description? $r = q("SELECT * FROM `contact` WHERE `name` = '%s' AND `nurl` = '%s' AND `uid` = %d LIMIT 1", dbesc($fsugg['name']), dbesc(normalise_link($fsugg['url'])), intval($fsugg['uid'])); if (count($r)) { return 0; } // Do we already have an fcontact record for this person? $fid = 0; $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", dbesc($fsugg['url']), dbesc($fsugg['name']), dbesc($fsugg['request'])); if (count($r)) { $fid = $r[0]['id']; // OK, we do. Do we already have an introduction for this person ? $r = q("select id from intro where uid = %d and fid = %d limit 1", intval($fsugg['uid']), intval($fid)); if (count($r)) { return 0; } } if (!$fid) { $r = q("INSERT INTO `fcontact` ( `name`,`url`,`photo`,`request` ) VALUES ( '%s', '%s', '%s', '%s' ) ", dbesc($fsugg['name']), dbesc($fsugg['url']), dbesc($fsugg['photo']), dbesc($fsugg['request'])); } $r = q("SELECT * FROM `fcontact` WHERE `url` = '%s' AND `name` = '%s' AND `request` = '%s' LIMIT 1", dbesc($fsugg['url']), dbesc($fsugg['name']), dbesc($fsugg['request'])); if (count($r)) { $fid = $r[0]['id']; } else { return 0; } $hash = random_string(); $r = q("INSERT INTO `intro` ( `uid`, `fid`, `contact-id`, `note`, `hash`, `datetime`, `blocked` )\n\t\t\tVALUES( %d, %d, %d, '%s', '%s', '%s', %d )", intval($fsugg['uid']), intval($fid), intval($fsugg['cid']), dbesc($fsugg['body']), dbesc($hash), dbesc(datetime_convert()), intval(0)); notification(array('type' => NOTIFY_SUGGEST, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $fsugg, 'link' => $a->get_baseurl() . '/notifications/intros', 'source_name' => $importer['name'], 'source_link' => $importer['url'], 'source_photo' => $importer['photo'], 'verb' => ACTIVITY_REQ_FRIEND, 'otype' => 'intro')); return 0; } $ismail = false; $rawmail = $feed->get_feed_tags(NAMESPACE_DFRN, 'mail'); if (isset($rawmail[0]['child'][NAMESPACE_DFRN])) { logger('local_delivery: private message received'); $ismail = true; $base = $rawmail[0]['child'][NAMESPACE_DFRN]; $msg = array(); $msg['uid'] = $importer['importer_uid']; $msg['from-name'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['name'][0]['data'])); $msg['from-photo'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['avatar'][0]['data'])); $msg['from-url'] = notags(unxmlify($base['sender'][0]['child'][NAMESPACE_DFRN]['uri'][0]['data'])); $msg['contact-id'] = $importer['id']; $msg['title'] = notags(unxmlify($base['subject'][0]['data'])); $msg['body'] = escape_tags(unxmlify($base['content'][0]['data'])); $msg['seen'] = 0; $msg['replied'] = 0; $msg['uri'] = notags(unxmlify($base['id'][0]['data'])); $msg['parent-uri'] = notags(unxmlify($base['in-reply-to'][0]['data'])); $msg['created'] = datetime_convert(notags(unxmlify('UTC', 'UTC', $base['sentdate'][0]['data']))); dbesc_array($msg); $r = dbq("INSERT INTO `mail` (`" . implode("`, `", array_keys($msg)) . "`) VALUES ('" . implode("', '", array_values($msg)) . "')"); // send notifications. require_once 'include/enotify.php'; $notif_params = array('type' => NOTIFY_MAIL, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $msg, 'source_name' => $msg['from-name'], 'source_link' => $importer['url'], 'source_photo' => $importer['thumb'], 'verb' => ACTIVITY_POST, 'otype' => 'mail'); notification($notif_params); return 0; // NOTREACHED } $community_page = 0; $rawtags = $feed->get_feed_tags(NAMESPACE_DFRN, 'community'); if ($rawtags) { $community_page = intval($rawtags[0]['data']); } if (intval($importer['forum']) != $community_page) { q("update contact set forum = %d where id = %d", intval($community_page), intval($importer['id'])); $importer['forum'] = (string) $community_page; } logger('local_delivery: feed item count = ' . $feed->get_item_quantity()); // process any deleted entries $del_entries = $feed->get_feed_tags(NAMESPACE_TOMB, 'deleted-entry'); if (is_array($del_entries) && count($del_entries)) { foreach ($del_entries as $dentry) { $deleted = false; if (isset($dentry['attribs']['']['ref'])) { $uri = $dentry['attribs']['']['ref']; $deleted = true; if (isset($dentry['attribs']['']['when'])) { $when = $dentry['attribs']['']['when']; $when = datetime_convert('UTC', 'UTC', $when, 'Y-m-d H:i:s'); } else { $when = datetime_convert('UTC', 'UTC', 'now', 'Y-m-d H:i:s'); } } if ($deleted) { // check for relayed deletes to our conversation $is_reply = false; $r = q("select * from item where uri = '%s' and uid = %d limit 1", dbesc($uri), intval($importer['importer_uid'])); if (count($r)) { $parent_uri = $r[0]['parent-uri']; if ($r[0]['id'] != $r[0]['parent']) { $is_reply = true; } } if ($is_reply) { $community = false; if ($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) { $sql_extra = ''; $community = true; logger('local_delivery: possible community delete'); } else { $sql_extra = " and contact.self = 1 and item.wall = 1 "; } // was the top-level post for this reply written by somebody on this site? // Specifically, the recipient? $is_a_remote_delete = false; // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used? $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`,\n\t\t\t\t\t\t`contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item`\n\t\t\t\t\t\tINNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\t\t\t\tWHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s')\n\t\t\t\t\t\tAND `item`.`uid` = %d\n\t\t\t\t\t\t{$sql_extra}\n\t\t\t\t\t\tLIMIT 1", dbesc($parent_uri), dbesc($parent_uri), dbesc($parent_uri), intval($importer['importer_uid'])); if ($r && count($r)) { $is_a_remote_delete = true; } // Does this have the characteristics of a community or private group comment? // If it's a reply to a wall post on a community/prvgroup page it's a // valid community comment. Also forum_mode makes it valid for sure. // If neither, it's not. if ($is_a_remote_delete && $community) { if (!$r[0]['forum_mode'] && !$r[0]['wall']) { $is_a_remote_delete = false; logger('local_delivery: not a community delete'); } } if ($is_a_remote_delete) { logger('local_delivery: received remote delete'); } } $r = q("SELECT `item`.*, `contact`.`self` FROM `item` INNER JOIN contact on `item`.`contact-id` = `contact`.`id`\n\t\t\t\t\tWHERE `uri` = '%s' AND `item`.`uid` = %d AND `contact-id` = %d AND NOT `item`.`file` LIKE '%%[%%' LIMIT 1", dbesc($uri), intval($importer['importer_uid']), intval($importer['id'])); if (count($r)) { $item = $r[0]; if ($item['deleted']) { continue; } logger('local_delivery: deleting item ' . $item['id'] . ' uri=' . $item['uri'], LOGGER_DEBUG); if ($item['object-type'] === ACTIVITY_OBJ_EVENT) { logger("Deleting event " . $item['event-id'], LOGGER_DEBUG); event_delete($item['event-id']); } if ($item['verb'] === ACTIVITY_TAG && $item['object-type'] === ACTIVITY_OBJ_TAGTERM) { $xo = parse_xml_string($item['object'], false); $xt = parse_xml_string($item['target'], false); if ($xt->type === ACTIVITY_OBJ_NOTE) { $i = q("select * from `item` where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid'])); if (count($i)) { // For tags, the owner cannot remove the tag on the author's copy of the post. $owner_remove = $item['contact-id'] == $i[0]['contact-id'] ? true : false; $author_remove = $item['origin'] && $item['self'] ? true : false; $author_copy = $item['origin'] ? true : false; if ($owner_remove && $author_copy) { continue; } if ($author_remove || $owner_remove) { $tags = explode(',', $i[0]['tag']); $newtags = array(); if (count($tags)) { foreach ($tags as $tag) { if (trim($tag) !== trim($xo->body)) { $newtags[] = trim($tag); } } } q("update item set tag = '%s' where id = %d", dbesc(implode(',', $newtags)), intval($i[0]['id'])); create_tags_from_item($i[0]['id']); } } } } if ($item['uri'] == $item['parent-uri']) { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `parent-uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($item['uri']), intval($importer['importer_uid'])); create_tags_from_itemuri($item['uri'], $importer['importer_uid']); create_files_from_itemuri($item['uri'], $importer['importer_uid']); update_thread_uri($item['uri'], $importer['importer_uid']); } else { $r = q("UPDATE `item` SET `deleted` = 1, `edited` = '%s', `changed` = '%s',\n\t\t\t\t\t\t\t`body` = '', `title` = ''\n\t\t\t\t\t\t\tWHERE `uri` = '%s' AND `uid` = %d", dbesc($when), dbesc(datetime_convert()), dbesc($uri), intval($importer['importer_uid'])); create_tags_from_itemuri($uri, $importer['importer_uid']); create_files_from_itemuri($uri, $importer['importer_uid']); update_thread_uri($uri, $importer['importer_uid']); if ($item['last-child']) { // ensure that last-child is set in case the comment that had it just got wiped. q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d ", dbesc(datetime_convert()), dbesc($item['parent-uri']), intval($item['uid'])); // who is the last child now? $r = q("SELECT `id` FROM `item` WHERE `parent-uri` = '%s' AND `type` != 'activity' AND `deleted` = 0 AND `uid` = %d\n\t\t\t\t\t\t\t\tORDER BY `created` DESC LIMIT 1", dbesc($item['parent-uri']), intval($importer['importer_uid'])); if (count($r)) { q("UPDATE `item` SET `last-child` = 1 WHERE `id` = %d", intval($r[0]['id'])); } } // if this is a relayed delete, propagate it to other recipients if ($is_a_remote_delete) { proc_run('php', "include/notifier.php", "drop", $item['id']); } } } } } } foreach ($feed->get_items() as $item) { $is_reply = false; $item_id = $item->get_id(); $rawthread = $item->get_item_tags(NAMESPACE_THREAD, 'in-reply-to'); if (isset($rawthread[0]['attribs']['']['ref'])) { $is_reply = true; $parent_uri = $rawthread[0]['attribs']['']['ref']; } if ($is_reply) { $community = false; if ($importer['page-flags'] == PAGE_COMMUNITY || $importer['page-flags'] == PAGE_PRVGROUP) { $sql_extra = ''; $community = true; logger('local_delivery: possible community reply'); } else { $sql_extra = " and contact.self = 1 and item.wall = 1 "; } // was the top-level post for this reply written by somebody on this site? // Specifically, the recipient? $is_a_remote_comment = false; $top_uri = $parent_uri; $r = q("select `item`.`parent-uri` from `item`\n\t\t\t\tWHERE `item`.`uri` = '%s'\n\t\t\t\tLIMIT 1", dbesc($parent_uri)); if ($r && count($r)) { $top_uri = $r[0]['parent-uri']; // POSSIBLE CLEANUP --> Why select so many fields when only forum_mode and wall are used? $r = q("select `item`.`id`, `item`.`uri`, `item`.`tag`, `item`.`forum_mode`,`item`.`origin`,`item`.`wall`,\n\t\t\t\t\t`contact`.`name`, `contact`.`url`, `contact`.`thumb` from `item`\n\t\t\t\t\tINNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`\n\t\t\t\t\tWHERE `item`.`uri` = '%s' AND (`item`.`parent-uri` = '%s' or `item`.`thr-parent` = '%s')\n\t\t\t\t\tAND `item`.`uid` = %d\n\t\t\t\t\t{$sql_extra}\n\t\t\t\t\tLIMIT 1", dbesc($top_uri), dbesc($top_uri), dbesc($top_uri), intval($importer['importer_uid'])); if ($r && count($r)) { $is_a_remote_comment = true; } } // Does this have the characteristics of a community or private group comment? // If it's a reply to a wall post on a community/prvgroup page it's a // valid community comment. Also forum_mode makes it valid for sure. // If neither, it's not. if ($is_a_remote_comment && $community) { if (!$r[0]['forum_mode'] && !$r[0]['wall']) { $is_a_remote_comment = false; logger('local_delivery: not a community reply'); } } if ($is_a_remote_comment) { logger('local_delivery: received remote comment'); $is_like = false; // remote reply to our post. Import and then notify everybody else. $datarray = get_atom_elements($feed, $item); $r = q("SELECT `id`, `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid'])); // Update content if 'updated' changes if (count($r)) { $iid = $r[0]['id']; if (edited_timestamp_is_newer($r[0], $datarray)) { // do not accept (ignore) an earlier edit than one we currently have. if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) { continue; } logger('received updated comment', LOGGER_DEBUG); $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid'])); create_tags_from_itemuri($item_id, $importer['importer_uid']); proc_run('php', "include/notifier.php", "comment-import", $iid); } continue; } $own = q("select name,url,thumb from contact where uid = %d and self = 1 limit 1", intval($importer['importer_uid'])); $datarray['type'] = 'remote-comment'; $datarray['wall'] = 1; $datarray['parent-uri'] = $parent_uri; $datarray['uid'] = $importer['importer_uid']; $datarray['owner-name'] = $own[0]['name']; $datarray['owner-link'] = $own[0]['url']; $datarray['owner-avatar'] = $own[0]['thumb']; $datarray['contact-id'] = $importer['id']; if ($datarray['verb'] === ACTIVITY_LIKE || $datarray['verb'] === ACTIVITY_DISLIKE || $datarray['verb'] === ACTIVITY_ATTEND || $datarray['verb'] === ACTIVITY_ATTENDNO || $datarray['verb'] === ACTIVITY_ATTENDMAYBE) { $is_like = true; $datarray['type'] = 'activity'; $datarray['gravity'] = GRAVITY_LIKE; $datarray['last-child'] = 0; // only one like or dislike per person // splitted into two queries for performance issues $r = q("select id from item where uid = %d and `contact-id` = %d and verb = '%s' and (`parent-uri` = '%s') and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($datarray['parent-uri'])); if ($r && count($r)) { continue; } $r = q("select id from item where uid = %d and `contact-id` = %d and verb = '%s' and (`thr-parent` = '%s') and deleted = 0 limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($datarray['parent-uri'])); if ($r && count($r)) { continue; } } if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) { $xo = parse_xml_string($datarray['object'], false); $xt = parse_xml_string($datarray['target'], false); if ($xt->type == ACTIVITY_OBJ_NOTE && $xt->id) { // fetch the parent item $tagp = q("select * from item where uri = '%s' and uid = %d limit 1", dbesc($xt->id), intval($importer['importer_uid'])); if (!count($tagp)) { continue; } // extract tag, if not duplicate, and this user allows tags, add to parent item if ($xo->id && $xo->content) { $newtag = '#[url=' . $xo->id . ']' . $xo->content . '[/url]'; if (!stristr($tagp[0]['tag'], $newtag)) { $i = q("SELECT `blocktags` FROM `user` where `uid` = %d LIMIT 1", intval($importer['importer_uid'])); if (count($i) && !intval($i[0]['blocktags'])) { q("UPDATE item SET tag = '%s', `edited` = '%s', `changed` = '%s' WHERE id = %d", dbesc($tagp[0]['tag'] . (strlen($tagp[0]['tag']) ? ',' : '') . $newtag), intval($tagp[0]['id']), dbesc(datetime_convert()), dbesc(datetime_convert())); create_tags_from_item($tagp[0]['id']); } } } } } $posted_id = item_store($datarray); $parent = 0; if ($posted_id) { $datarray["id"] = $posted_id; $r = q("SELECT `parent`, `parent-uri` FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", intval($posted_id), intval($importer['importer_uid'])); if (count($r)) { $parent = $r[0]['parent']; $parent_uri = $r[0]['parent-uri']; } if (!$is_like) { $r1 = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `uid` = %d AND `parent` = %d", dbesc(datetime_convert()), intval($importer['importer_uid']), intval($r[0]['parent'])); $r2 = q("UPDATE `item` SET `last-child` = 1, `changed` = '%s' WHERE `uid` = %d AND `id` = %d", dbesc(datetime_convert()), intval($importer['importer_uid']), intval($posted_id)); } if ($posted_id && $parent) { proc_run('php', "include/notifier.php", "comment-import", "{$posted_id}"); if (!$is_like && !$importer['self']) { require_once 'include/enotify.php'; notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $parent, 'parent_uri' => $parent_uri)); } } return 0; // NOTREACHED } } else { // regular comment that is part of this total conversation. Have we seen it? If not, import it. $item_id = $item->get_id(); $datarray = get_atom_elements($feed, $item); if ($importer['rel'] == CONTACT_IS_FOLLOWER) { continue; } $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid'])); // Update content if 'updated' changes if (count($r)) { if (edited_timestamp_is_newer($r[0], $datarray)) { // do not accept (ignore) an earlier edit than one we currently have. if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) { continue; } $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid'])); create_tags_from_itemuri($item_id, $importer['importer_uid']); } // update last-child if it changes $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow'); if ($allow && $allow[0]['data'] != $r[0]['last-child']) { $r = q("UPDATE `item` SET `last-child` = 0, `changed` = '%s' WHERE `parent-uri` = '%s' AND `uid` = %d", dbesc(datetime_convert()), dbesc($parent_uri), intval($importer['importer_uid'])); $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid'])); } continue; } $datarray['parent-uri'] = $parent_uri; $datarray['uid'] = $importer['importer_uid']; $datarray['contact-id'] = $importer['id']; if ($datarray['verb'] === ACTIVITY_LIKE || $datarray['verb'] === ACTIVITY_DISLIKE || $datarray['verb'] === ACTIVITY_ATTEND || $datarray['verb'] === ACTIVITY_ATTENDNO || $datarray['verb'] === ACTIVITY_ATTENDMAYBE) { $datarray['type'] = 'activity'; $datarray['gravity'] = GRAVITY_LIKE; // only one like or dislike per person // splitted into two queries for performance issues $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`parent-uri` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri)); if ($r && count($r)) { continue; } $r = q("select id from item where uid = %d and `contact-id` = %d and verb ='%s' and deleted = 0 and (`thr-parent` = '%s') limit 1", intval($datarray['uid']), intval($datarray['contact-id']), dbesc($datarray['verb']), dbesc($parent_uri)); if ($r && count($r)) { continue; } } if ($datarray['verb'] === ACTIVITY_TAG && $datarray['object-type'] === ACTIVITY_OBJ_TAGTERM) { $xo = parse_xml_string($datarray['object'], false); $xt = parse_xml_string($datarray['target'], false); if ($xt->type == ACTIVITY_OBJ_NOTE) { $r = q("select * from item where `uri` = '%s' AND `uid` = %d limit 1", dbesc($xt->id), intval($importer['importer_uid'])); if (!count($r)) { continue; } // extract tag, if not duplicate, add to parent item if ($xo->content) { if (!stristr($r[0]['tag'], trim($xo->content))) { q("UPDATE item SET tag = '%s' WHERE id = %d", dbesc($r[0]['tag'] . (strlen($r[0]['tag']) ? ',' : '') . '#[url=' . $xo->id . ']' . $xo->content . '[/url]'), intval($r[0]['id'])); create_tags_from_item($r[0]['id']); } } } } $posted_id = item_store($datarray); // find out if our user is involved in this conversation and wants to be notified. if (!x($datarray['type']) || $datarray['type'] != 'activity') { $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0", dbesc($top_uri), intval($importer['importer_uid'])); if (count($myconv)) { $importer_url = $a->get_baseurl() . '/profile/' . $importer['nickname']; // first make sure this isn't our own post coming back to us from a wall-to-wall event if (!link_compare($datarray['author-link'], $importer_url)) { foreach ($myconv as $conv) { // now if we find a match, it means we're in this conversation if (!link_compare($conv['author-link'], $importer_url)) { continue; } require_once 'include/enotify.php'; $conv_parent = $conv['parent']; notification(array('type' => NOTIFY_COMMENT, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => ACTIVITY_POST, 'otype' => 'item', 'parent' => $conv_parent, 'parent_uri' => $parent_uri)); // only send one notification break; } } } } continue; } } else { // Head post of a conversation. Have we seen it? If not, import it. $item_id = $item->get_id(); $datarray = get_atom_elements($feed, $item); if (x($datarray, 'object-type') && $datarray['object-type'] === ACTIVITY_OBJ_EVENT) { $ev = bbtoevent($datarray['body']); if ((x($ev, 'desc') || x($ev, 'summary')) && x($ev, 'start')) { $ev['cid'] = $importer['id']; $ev['uid'] = $importer['uid']; $ev['uri'] = $item_id; $ev['edited'] = $datarray['edited']; $ev['private'] = $datarray['private']; $ev['guid'] = $datarray['guid']; $r = q("SELECT * FROM `event` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['uid'])); if (count($r)) { $ev['id'] = $r[0]['id']; } $xyz = event_store($ev); continue; } } $r = q("SELECT `uid`, `last-child`, `edited`, `body` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", dbesc($item_id), intval($importer['importer_uid'])); // Update content if 'updated' changes if (count($r)) { if (edited_timestamp_is_newer($r[0], $datarray)) { // do not accept (ignore) an earlier edit than one we currently have. if (datetime_convert('UTC', 'UTC', $datarray['edited']) < $r[0]['edited']) { continue; } $r = q("UPDATE `item` SET `title` = '%s', `body` = '%s', `tag` = '%s', `edited` = '%s', `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", dbesc($datarray['title']), dbesc($datarray['body']), dbesc($datarray['tag']), dbesc(datetime_convert('UTC', 'UTC', $datarray['edited'])), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid'])); create_tags_from_itemuri($item_id, $importer['importer_uid']); update_thread_uri($item_id, $importer['importer_uid']); } // update last-child if it changes $allow = $item->get_item_tags(NAMESPACE_DFRN, 'comment-allow'); if ($allow && $allow[0]['data'] != $r[0]['last-child']) { $r = q("UPDATE `item` SET `last-child` = %d , `changed` = '%s' WHERE `uri` = '%s' AND `uid` = %d", intval($allow[0]['data']), dbesc(datetime_convert()), dbesc($item_id), intval($importer['importer_uid'])); } continue; } $datarray['parent-uri'] = $item_id; $datarray['uid'] = $importer['importer_uid']; $datarray['contact-id'] = $importer['id']; if (!link_compare($datarray['owner-link'], $importer['url'])) { // The item owner info is not our contact. It's OK and is to be expected if this is a tgroup delivery, // but otherwise there's a possible data mixup on the sender's system. // the tgroup delivery code called from item_store will correct it if it's a forum, // but we're going to unconditionally correct it here so that the post will always be owned by our contact. logger('local_delivery: Correcting item owner.', LOGGER_DEBUG); $datarray['owner-name'] = $importer['senderName']; $datarray['owner-link'] = $importer['url']; $datarray['owner-avatar'] = $importer['thumb']; } if ($importer['rel'] == CONTACT_IS_FOLLOWER && !tgroup_check($importer['importer_uid'], $datarray)) { continue; } // This is my contact on another system, but it's really me. // Turn this into a wall post. $notify = item_is_remote_self($importer, $datarray); $posted_id = item_store($datarray, false, $notify); if (stristr($datarray['verb'], ACTIVITY_POKE)) { $verb = urldecode(substr($datarray['verb'], strpos($datarray['verb'], '#') + 1)); if (!$verb) { continue; } $xo = parse_xml_string($datarray['object'], false); if ($xo->type == ACTIVITY_OBJ_PERSON && $xo->id) { // somebody was poked/prodded. Was it me? $links = parse_xml_string("<links>" . unxmlify($xo->link) . "</links>", false); foreach ($links->link as $l) { $atts = $l->attributes(); switch ($atts['rel']) { case "alternate": $Blink = $atts['href']; break; default: break; } } if ($Blink && link_compare($Blink, $a->get_baseurl() . '/profile/' . $importer['nickname'])) { // send a notification require_once 'include/enotify.php'; notification(array('type' => NOTIFY_POKE, 'notify_flags' => $importer['notify-flags'], 'language' => $importer['language'], 'to_name' => $importer['username'], 'to_email' => $importer['email'], 'uid' => $importer['importer_uid'], 'item' => $datarray, 'link' => $a->get_baseurl() . '/display/' . urlencode(get_item_guid($posted_id)), 'source_name' => stripslashes($datarray['author-name']), 'source_link' => $datarray['author-link'], 'source_photo' => link_compare($datarray['author-link'], $importer['url']) ? $importer['thumb'] : $datarray['author-avatar'], 'verb' => $datarray['verb'], 'otype' => 'person', 'activity' => $verb, 'parent' => $datarray['parent'])); } } } continue; } } return 0; // NOTREACHED }
/** * Setup simplepie * @param string $raw_data */ private function _setup_simplepie($raw_data) { $data = new SimplePie(); $data->set_raw_data($raw_data); $data->enable_cache(false); $data->enable_order_by_date(true); $data->init(); $data->handle_content_type(); return $data; }
/** * Factory method to create a SimplePie instance * * If a file URL is set as feedUrl on the channel, the raw data will be set * on SimplePie to enable functional testing. * * @param \Planetflow3\Domain\Model\Channel $channel * @return \SimplePie */ protected function createSimplePie(Channel $channel) { $simplePie = new \SimplePie(); if (strpos($channel->getFeedUrl(), 'file://') === 0) { $simplePie->set_raw_data(file_get_contents($channel->getFeedUrl())); } else { $simplePie->set_feed_url($channel->getFeedUrl()); } $simplePie->enable_cache(FALSE); $simplePie->init(); return $simplePie; }