Author URI: http://www.davidcramer.net */ define(LIFESTREAM_VERSION, '0.99.6.1'); //define(LIFESTREAM_PLUGIN_FILE, 'lifestream/lifestream.php'); define(LIFESTREAM_PLUGIN_FILE, plugin_basename(__FILE__)); define(LIFESTREAM_FEEDS_PER_PAGE, 10); define(LIFESTREAM_EVENTS_PER_PAGE, 25); define(LIFESTREAM_ERRORS_PER_PAGE, 25); if (!class_exists('SimplePie')) { require_once(dirname(__FILE__) . '/lib/simplepie.inc.php'); } global $wpdb, $userdata, $lifestream; if (!function_exists('array_key_pop')) { function array_key_pop($array, $key) { $value = $array[$key]; unset($array[$key]); return $value; } } if (!function_exists('str_startswith')) { function str_startswith($string, $chunk) { return substr($string, 0, strlen($chunk)) == $chunk; } } if (!function_exists('str_endswith')) { function str_endswith($string, $chunk) { return substr($string, strlen($chunk)*-1) == $chunk; } } if (!function_exists('get_class_constant')) { function get_class_constant($class, $const) { return constant(sprintf('%s::%s', $class, $const)); } } class LifeStream_Error extends Exception { } class LifeStream_ValidationError extends Exception { } class LifeStream_FeedFetchError extends LifeStream_Error { } class LifeStream_Event { /** * Represents a single event in the database. */ function __construct(&$lifestream, $row) { $this->lifestream = $lifestream; $this->date = $row->timestamp; $this->data = array(unserialize($row->data)); $this->id = $row->id; $this->timestamp = $row->timestamp; $this->total = 1; $this->is_grouped = false; $this->key = $row->key; $this->owner = $row->owner; $this->owner_id = $row->owner_id; $this->visible = $row->visible; $this->link = ($this->data['link'] ? $this->data['link'] : $row->link); $cls = $this->lifestream->get_feed($row->feed); $this->feed = new $cls($this->lifestream, unserialize($row->options), $row->feed_id); } function __toString() { return $this->data[0]['title']; } function get_event_display() { return $this->feed->get_event_display($this, $this->data[0]); } function get_date() { return $this->date + LIFESTREAM_DATE_OFFSET*60*60; } /** * Returns an HTML-ready string. */ function render($options=array()) { return $this->feed->render($this, $options); } function get_url() { if (count($this->data) > 1) { // return the public url if it's grouped $url = $this->feed->get_public_url(); if ($url) return $url; } else { $url = $this->data[0]['link']; if ($url) return $url; } return '#'; } } class LifeStream_EventGroup extends LifeStream_Event { /** * Represents a grouped event in the database. */ function __construct(&$lifestream, $row) { parent::__construct($lifestream, $row); $this->total = $row->total ? $row->total : 1; $this->data = unserialize($row->data); $this->is_grouped = true; } function get_event_display($bit) { return $this->feed->get_event_display($this, $bit); } } class Lifestream { public $feeds = array(); protected $valid_image_types = array('image/gif' => 'gif', 'image/jpeg' => 'jpeg', 'image/png' => 'png', 'image/gif' => 'gif', 'image/x-icon' => 'ico', 'image/bmp' => 'bmp', 'image/vnd.microsoft.icon' => 'ico' ); protected $valid_image_extensions = array( 'gif', 'jpg', 'jpeg', 'gif', 'png', 'ico' ); function html_entity_decode($string) { $string = html_entity_decode($string); $string = preg_replace('~�*([0-9a-f]+);~ei', 'chr(hexdec("\\1"))', $string); $string = preg_replace('~�*([0-9]+);~e', 'chr(\\1)', $string); return $string; } function validate_image($url) { // // Check the extension // $bits = explode('.', basename($url)); // if (count($bits) > 1) // { // $ext = $bits[count($bits)-1]; // return (in_array($ext, $this->valid_image_extensions)); // } $handler = $this->get_option('url_handler'); $use_fsock = true; if (($handler == 'auto' && function_exists('curl_init')) || $handler == 'curl') { $use_fsock = false; } $file = new SimplePie_File($url, 10, 5, null, SIMPLEPIE_USERAGENT, $use_fsock); if (!$file->success) { return false; } // Attempt to check content type if (!empty($file->headers['content-type'])) { return (in_array($file->headers['content-type'], $this->valid_image_types)); } // Use GD if we can if (function_exists('imagecreatefromstring')) { return (imagecreatefromstring($file->body) !== false); } // Everything has failed, we'll just let it pass return true; } // options and their default values protected $_options = array( 'day_format' => 'F jS', 'hour_format' => 'g:ia', 'timezone' => '6', 'number_of_items' => '50', 'date_interval' => '1 month', 'digest_title' => 'Daily Digest for %s', 'digest_body' => '%1$s', 'digest_category' => '1', 'digest_author' => '1', 'daily_digest' => '0', 'digest_interval' => 'daily', 'digest_time' => '0', 'update_interval' => '15', 'show_owners' => '0', 'use_ibox' => '1', 'show_credits' => '1', 'hide_details_default' => '1', 'url_handler' => 'auto', 'feed_items' => '10', 'truncate_length' => '128', ); function __construct() { $this->path = WP_CONTENT_URL . '/plugins/lifestream'; $this->_optioncache = null; add_filter('cron_schedules', array(&$this, 'get_cron_schedules')); add_action('admin_menu', array(&$this, 'options_menu')); add_action('wp_head', array(&$this, 'header')); add_filter('the_content', array(&$this, 'embed_callback')); add_action('init', array(&$this, 'init')); add_action('lifestream_digest_cron', array(&$this, 'digest_update')); add_action('lifestream_cron', array(&$this, 'update')); register_activation_hook(LIFESTREAM_PLUGIN_FILE, array(&$this, 'activate')); register_deactivation_hook(LIFESTREAM_PLUGIN_FILE, array(&$this, 'deactivate')); } function truncate($string, $length=128) { if (!($length > 0)) return $string; if (strlen($string) > $length) { $string = substr($string, 0, $length-3).'...'; } return $string; } // To be quite honest, WordPress should be doing this kind of magic itself. function _populate_option_cache() { if (!$this->_optioncache) { $this->_optioncache = get_option('lifestream_options'); if (!$this->_optioncache) $this->_optioncache = $this->_options; } } /** * Fetches the value of an option. Returns `null` if the option is not set. */ function get_option($option, $default=null) { $this->_populate_option_cache(); $value = $this->_optioncache[$option]; if (!$value) return $default; return $value; } /** * Removes an option. */ function delete_option($option) { $this->_populate_option-cache(); unset($this->_optioncache[$option]); update_option('lifestream_options', $this->_optioncache); } /** * Updates the value of an option. */ function update_option($option, $value) { $this->_populate_option_cache(); $this->_optioncache[$option] = $value; update_option('lifestream_options', $this->_optioncache); } /** * Sets an option if it doesn't exist. */ function add_option($option, $value) { $this->_populate_option_cache(); if (!array_key_exists($option, $this->_optioncache)) { $this->_optioncache[$option] = $value; add_option('lifestream_options', serialize($this->_optioncache)); } } function __($text, $params=null) { if (!is_array($params)) { $params = func_get_args(); $params = array_slice($params, 1); } return vsprintf(__($text, 'lifestream'), $params); } function _e($text, $params=null) { if (!is_array($params)) { $params = func_get_args(); $params = array_slice($params, 1); } echo vsprintf(__($text, 'lifestream'), $params); } function init() { global $wpdb; $offset = $this->get_option('timezone'); define(LIFESTREAM_DATE_OFFSET, $offset); load_plugin_textdomain('lifestream', false, 'lifestream/locales'); if (is_admin() && str_startswith($_GET['page'], 'lifestream')) { wp_enqueue_script('jquery'); wp_enqueue_script('admin-forms'); } add_feed('lifestream-feed', 'lifestream_rss_feed'); // If this is an update we need to force reactivation if (LIFESTREAM_VERSION != $this->get_option('_version')) { $this->get_option('_version'); $this->deactivate(); $this->activate(); } } function log_error($message, $feed_id=null) { global $wpdb; if ($feed_id) { $result = $wpdb->query($wpdb->prepare("INSERT INTO `".$wpdb->prefix."lifestream_error_log` (`feed_id`, `message`, `timestamp`) VALUES (%s, %s, %d)", $wpdb->escape($feed_id), $wpdb->escape($message), time())); } else { $result = $wpdb->query($wpdb->prepare("INSERT INTO `".$wpdb->prefix."lifestream_error_log` (`feed_id`, `message`, `timestamp`) VALUES (NULL, %s, %d)", $wpdb->escape($message), time())); } } function get_digest_interval() { $interval = $this->get_option('digest_interval'); switch ($interval) { case 'weekly': return 3600*24*7; case 'daily': return 3600*24; case 'hourly': return 3600; } } function get_cron_schedules() { $cron['lifestream'] = array( 'interval' => $this->get_option('update_interval') * 60, 'display' => $this->__('On LifeStream update') ); $cron['lifestream_digest'] = array( 'interval' => $this->get_digest_interval(), 'display' => $this->__('On LifeStream daily digest update') ); return $cron; } function get_single_event($feed_type) { $events = $this->get_events(array('feed_types'=>array($feed_type), 'limit'=>1, 'break_groups'=>true)); $event = $events[0]; return $event; } function digest_update() { global $wpdb; if ($this->get_option('daily_digest') != '1') return; $hour_format = $this->get_option('hour_format'); $day_format = $this->get_option('day_format'); $interval = $this->get_digest_interval(); $now = time(); // If there was a previous digest, we show only events since it $from = $this->get_option('_last_digest'); // Otherwise we show events within the interval period if (!$from) $from = $now - $interval; // make sure the post doesn't exist $results = $wpdb->get_results($wpdb->prepare("SELECT `post_id` FROM `".$wpdb->prefix."postmeta` WHERE `meta_key` = '_lifestream_digest_date' AND `meta_value` = %d LIMIT 0, 1", $now)); if ($results) continue; $sql = $wpdb->prepare("SELECT t1.*, t2.`options` FROM `".$wpdb->prefix."lifestream_event_group` as `t1` INNER JOIN `".$wpdb->prefix."lifestream_feeds` as t2 ON t1.`feed_id` = t2.`id` WHERE t1.`timestamp` > %s AND t1.`timestamp` < %s ORDER BY t1.`timestamp` ASC", $from, $now); $results =& $wpdb->get_results($sql); $events = array(); foreach ($results as &$result) { $events[] = new LifeStream_EventGroup($this, $result); } if (count($events)) { ob_start(); if (!include(dirname(__FILE__) . '/pages/daily-digest.inc.php')) return; $content = sprintf($this->get_option('digest_body'), ob_get_clean(), date($this->get_option('day_format'), $now), count($events)); $data = array( 'post_content' => $wpdb->escape($content), 'post_title' => $wpdb->escape(sprintf($this->get_option('digest_title'), date($day_format, $now), date($hour_format, $now))), 'post_date' => date('Y-m-d H:i:s', $now), 'post_category' => array($this->get_option('digest_category')), 'post_status' => 'publish', 'post_author' => $wpdb->escape($this->get_option('digest_author')), ); $post_id = wp_insert_post($data); add_post_meta($post_id, '_lifestream_digest_date', $now, true); } $this->update_option('_last_digest', $now); } // page output function options_menu() { global $wpdb; if (function_exists('add_menu_page')) { $basename = basename(LIFESTREAM_PLUGIN_FILE); $results =& $wpdb->get_results("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_error_log` WHERE has_viewed = 0"); $errors = $results[0]->count; add_menu_page('LifeStream', 'LifeStream', 'edit_posts', $basename, array(&$this, 'options_page')); add_submenu_page($basename, $this->__('LifeStream Feeds'), $this->__('Feeds'), 'edit_posts', $basename, array(&$this, 'options_page')); add_submenu_page($basename, $this->__('LifeStream Events'), $this->__('Events'), 'edit_posts', 'lifestream-events.php', array(&$this, 'options_page')); add_submenu_page($basename, $this->__('LifeStream Settings'), $this->__('Settings'), 'manage_options', 'lifestream-settings.php', array(&$this, 'options_page')); add_submenu_page($basename, $this->__('LifeStream Change Log'), $this->__('Change Log'), 'manage_options', 'lifestream-changelog.php', array(&$this, 'options_page')); add_submenu_page($basename, $this->__('LifeStream Errors'), $this->__('Errors (%d)', $errors), 'manage_options', 'lifestream-errors.php', array(&$this, 'options_page')); add_submenu_page($basename, $this->__('LifeStream Support Forums'), $this->__('Support Forums'), 'manage_options', 'lifestream-forums.php', array(&$this, 'options_page')); } } function header() { echo ''; echo ''; } function options_page() { global $wpdb, $userdata; $wpdb->show_errors(); $this->install(); get_currentuserinfo(); $date_format = sprintf('%s @ %s', $this->get_option('day_format'), $this->get_option('hour_format')); $basename = basename(LIFESTREAM_PLUGIN_FILE); $errors = array(); $message = null; switch ($_GET['page']) { case 'lifestream-events.php': switch (strtolower($_REQUEST['op'])) { case 'delete': if (!($ids = $_REQUEST['id'])) break; if (!is_array($ids)) $ids = array($ids); foreach ($ids as $id) { $result =& $wpdb->get_results($wpdb->prepare("SELECT `id`, `feed_id`, `timestamp`, `owner_id` FROM `".$wpdb->prefix."lifestream_event` WHERE `id` = %d", $id)); if (!$result) { $errors[] = $this->__('The selected feed was not found.'); } elseif (!current_user_can('manage_options') && $result[0]->owner_id != $userdata->ID) { $errors[] = $this->__('You do not have permission to do that.'); } else { $result =& $result[0]; $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event` SET `visible` = 0 WHERE `id` = %d", $result->id)); $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event_group` SET `visible` = 0 WHERE `event_id` = %d", $result->id)); // Now we have to update the batch if it exists. $group =& $wpdb->get_results($wpdb->prepare("SELECT `id` FROM `".$wpdb->prefix."lifestream_event_group` WHERE `event_id` IS NULL AND DATE(FROM_UNIXTIME(`timestamp`)) = DATE(FROM_UNIXTIME(%d)) AND `feed_id` = %d LIMIT 0, 1", $result->timestamp, $result->feed_id)); if (count($group) == 1) { $group =& $group[0]; $results =& $wpdb->get_results($wpdb->prepare("SELECT `data`, `link` FROM `".$wpdb->prefix."lifestream_event` WHERE `feed_id` = %d AND `visible` = 1 AND DATE(FROM_UNIXTIME(`timestamp`)) = DATE(FROM_UNIXTIME(%d))", $result->feed_id, $result->timestamp)); if (count($results)) { $events = array(); foreach ($results as &$result) { $result->data = unserialize($result->data); $result->data['link'] = $result->link; $events[] = $result->data; } $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event_group` SET `data` = %s, `total` = %d, `updated` = 1 WHERE `id` = %d", $wpdb->escape(serialize($events)), count($events), $group->id)); } else { $wpdb->query($wpdb->prepare("DELETE FROM `".$wpdb->prefix."lifestream_event_group` WHERE `id` = %d", $group->id)); } } else { $wpdb->query($wpdb->prepare("DELETE FROM `".$wpdb->prefix."lifestream_event_group` WHERE `event_id` = %d", $result->id)); } } $message = $this->__('The selected events were hidden.'); } break; } break; case 'lifestream-settings.php': if ($_POST['save']) { foreach (array_keys($this->_options) as $value) { $this->update_option($value, stripslashes($_POST['lifestream_'.$value])); } // We need to make sure the cron runs now $this->reschedule_cron(); } break; default: $feedmsgs = array(); switch (strtolower($_REQUEST['op'])) { case 'refreshall': $results = $this->update_all($userdata->ID); foreach ($results as $id=>$result) { if (is_int($result)) $feedmsgs[$id] = $result; else $errors[] = $this->__('There was an error refreshing the selected feed: ID %s', $id); } $message = $this->__('All of your feeds have been refreshed.'); break; case 'refresh': if (!$_REQUEST['id']) break; foreach ($_REQUEST['id'] as $id) { $result =& $wpdb->get_results($wpdb->prepare("SELECT * FROM `".$wpdb->prefix."lifestream_feeds` WHERE `id` = %d LIMIT 0, 1", $id)); if (!$result) { $errors[] = $this->__('The selected feed was not found.'); } elseif (!current_user_can('manage_options') && $result[0]->owner_id != $userdata->ID) { $errors[] = $this->__('You do not have permission to do that.'); } else { $instance = LifeStream_Feed::construct_from_query_result($this, $result[0]); $msg_arr = $instance->refresh(); if ($msg_arr[0] !== false) { $message = $this->__('The selected feeds and their events have been refreshed.'); $feedmsgs[$instance->id] = $msg_arr[1]; } else { $errors[] = $this->__('There was an error refreshing the selected feed: ID %s', $instance->id); } } } break; case 'delete': if (!$_REQUEST['id']) break; foreach ($_REQUEST['id'] as $id) { $result =& $wpdb->get_results($wpdb->prepare("SELECT * FROM `".$wpdb->prefix."lifestream_feeds` WHERE `id` = %d LIMIT 0, 1", $id)); if (!$result) { $errors[] = $this->__('The selected feed was not found.'); } elseif (!current_user_can('manage_options') && $result[0]->owner_id != $userdata->ID) { $errors[] = $this->__('You do not have permission to do that.'); } else { $instance = LifeStream_Feed::construct_from_query_result($this, $result[0]); $instance->delete(); $message = $this->__('The selected feeds and all related events has been removed.'); } } break; case 'edit': $result =& $wpdb->get_results($wpdb->prepare("SELECT * FROM `".$wpdb->prefix."lifestream_feeds` WHERE `id` = %d LIMIT 0, 1", $_GET['id'])); if (!$result) { $errors[] = $this->__('The selected feed was not found.'); } elseif (!current_user_can('manage_options') && $result[0]->owner_id != $userdata->ID) { $errors[] = $this->__('You do not have permission to do that.'); } else { $instance = LifeStream_Feed::construct_from_query_result($this, $result[0]); $options = $instance->get_options(); if ($_POST['save']) { $values = array(); foreach ($options as $option=>$option_meta) { if ($option_meta[1] && !$_POST[$option]) { $errors[] = $option_meta[0].' is required.'; } else { $values[$option] = stripslashes($_POST[$option]); } } if ($instance->get_constant('MUST_GROUP')) { $values['grouped'] = 1; } elseif ($instance->get_constant('CAN_GROUP')) { $values['grouped'] = $_POST['grouped']; } if ($instance->get_constant('HAS_EXCERPTS')) { $values['excerpt'] = $_POST['excerpt']; } $values['feed_label'] = $_POST['feed_label']; $values['icon_url'] = $_POST['icon_url']; $values['auto_icon'] = $_POST['auto_icon']; if ($_POST['owner'] != $instance->owner_id && current_user_can('manage_options')) { $instance->owner_id = $_POST['owner']; $usero = new WP_User($author->user_id); $owner = $usero->data; $instance->owner = $owner->display_name; } if (!count($errors)) { $instance->options = $values; $instance->save(); unset($_POST); } } } break; case 'add': if ($_POST) { $class_name = $this->get_feed($_GET['feed']); if (!$class_name) break; $feed = new $class_name($this); $values = array(); $options = $feed->get_options(); foreach ($options as $option=>$option_meta) { if ($option_meta[1] && !$_POST[$option]) { $errors[] = $option_meta[0].' is required.'; } else { $values[$option] = stripslashes($_POST[$option]); } } if ($feed->get_constant('MUST_GROUP')) { $values['grouped'] = 1; } elseif ($feed->get_constant('CAN_GROUP')) { $values['grouped'] = $_POST['grouped']; } if ($feed->get_constant('HAS_EXCERPTS')) { $values['excerpt'] = $_POST['excerpt']; } $values['feed_label'] = $_POST['feed_label']; $values['icon_url'] = $_POST['icon_url']; $values['auto_icon'] = $_POST['auto_icon']; if (current_user_can('manage_options')) { $feed->owner_id = $_POST['owner']; $usero = new WP_User($feed->owner_id); $owner = $usero->data; $feed->owner = $owner->display_name; } else { $feed->owner_id = $userdata->ID; $feed->owner = $userdata->display_name; } $feed->options = $values; if (!count($errors)) { if (!($error = $feed->test())) { $result = $feed->save(); if ($result !== false) { unset($_POST); unset($_REQUEST['op']); $msg_arr = $feed->refresh(null, true); if ($msg_arr[0] !== false) { $message = $this->__('A new %s feed was added to your LifeStream.', $feed->get_constant('NAME')); $feedmsgs[$feed->id] = $msg_arr[1]; unset($_POST); } } } else { $errors[] = $error; } } } break; } break; } $lifestream = &$this; ob_start(); ?>

_e('There were errors with your request:') ?>

query("DELETE FROM `".$wpdb->prefix."lifestream_error_log`"); break; } $start = ($page-1)*LIFESTREAM_ERRORS_PER_PAGE; $end = $page*LIFESTREAM_ERRORS_PER_PAGE; $wpdb->query("UPDATE `".$wpdb->prefix."lifestream_error_log` SET has_viewed = 1"); $results =& $wpdb->get_results("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_error_log`"); $number_of_pages = ceil($results[0]->count/LIFESTREAM_EVENTS_PER_PAGE); $results =& $wpdb->get_results($wpdb->prepare("SELECT t1.*, t2.`feed`, t2.`options` FROM `".$wpdb->prefix."lifestream_error_log` as t1 LEFT JOIN `".$wpdb->prefix."lifestream_feeds` as t2 ON t1.`feed_id` = t2.`id` ORDER BY t1.`timestamp` DESC LIMIT %d, %d", $start, $end)); include(dirname(__FILE__) . '/pages/errors.inc.php'); break; case 'lifestream-changelog.php': include(dirname(__FILE__) . '/pages/changelog.inc.php'); break; case 'lifestream-forums.php': include(dirname(__FILE__) . '/pages/forums.inc.php'); break; case 'lifestream-settings.php': $lifestream_digest_intervals = array( 'weekly' => $this->__('Weekly'), 'daily' => $this->__('Daily'), 'hourly' => $this->__('Hourly'), ); include(dirname(__FILE__) . '/pages/settings.inc.php'); break; case 'lifestream-events.php': $page = $_GET['paged'] ? $_GET['paged'] : 1; $start = ($page-1)*LIFESTREAM_EVENTS_PER_PAGE; $end = $page*LIFESTREAM_EVENTS_PER_PAGE; if (!current_user_can('manage_options')) { $rows =& $wpdb->get_row($wpdb->prepare("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_event` WHERE `owner_id` = %d", $userdata->ID)); $number_of_pages = ceil($rows->count/LIFESTREAM_EVENTS_PER_PAGE); $rows =& $wpdb->get_results($wpdb->prepare("SELECT t1.*, t2.`feed`, t2.`options` FROM `".$wpdb->prefix."lifestream_event` as t1 JOIN `".$wpdb->prefix."lifestream_feeds` as t2 ON t1.`feed_id` = t2.`id` WHERE t1.`owner_id` = %d ORDER BY t1.`timestamp` DESC LIMIT %d, %d", $userdata->ID, $start, $end)); } else { $rows =& $wpdb->get_row("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_event`"); $number_of_pages = ceil($rows->count/LIFESTREAM_EVENTS_PER_PAGE); $rows =& $wpdb->get_results($wpdb->prepare("SELECT t1.*, t2.`feed`, t2.`options` FROM `".$wpdb->prefix."lifestream_event` as t1 JOIN `".$wpdb->prefix."lifestream_feeds` as t2 ON t1.`feed_id` = t2.`id` ORDER BY t1.`timestamp` DESC LIMIT %d, %d", $start, $end)); } $results = array(); foreach ($rows as $result) { $results[] = new LifeStream_Event($lifestream, $result); } unset($rows); include(dirname(__FILE__) . '/pages/events.inc.php'); break; default: switch ($_REQUEST['op']) { case 'edit': include(dirname(__FILE__) . '/pages/edit-feed.inc.php'); break; case 'add': $identifier = $_GET['feed']; $class_name = $this->get_feed($identifier); if (!$class_name) break; $feed = new $class_name($this); $options = $feed->get_options(); include(dirname(__FILE__) . '/pages/add-feed.inc.php'); break; default: $page = $_GET['paged'] ? $_GET['paged'] : 1; $start = ($page-1)*LIFESTREAM_FEEDS_PER_PAGE; $end = $page*LIFESTREAM_FEEDS_PER_PAGE; if (!current_user_can('manage_options')) { $rows =& $wpdb->get_row($wpdb->prepare("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_feeds` WHERE `owner_id` = %d", $userdata->ID)); $number_of_pages = ceil($rows->count/LIFESTREAM_FEEDS_PER_PAGE); $rows =& $wpdb->get_results($wpdb->prepare("SELECT t1.*, (SELECT COUNT(1) FROM `".$wpdb->prefix."lifestream_event` WHERE `feed_id` = t1.`id`) as `events` FROM `".$wpdb->prefix."lifestream_feeds` as t1 WHERE t1.`owner_id` = %d ORDER BY `id` LIMIT %d, %d", $userdata->ID, $start, $end)); } else { $rows =& $wpdb->get_row("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_feeds`"); $number_of_pages = ceil($rows->count/LIFESTREAM_FEEDS_PER_PAGE); $rows =& $wpdb->get_results($wpdb->prepare("SELECT t1.*, (SELECT COUNT(1) FROM `".$wpdb->prefix."lifestream_event` WHERE `feed_id` = t1.`id`) as `events` FROM `".$wpdb->prefix."lifestream_feeds` as t1 ORDER BY `id` LIMIT %d, %d", $start, $end)); } $results = array(); foreach ($rows as $result) { $results[] = LifeStream_Feed::construct_from_query_result($this, $result); } if ($results !== false) { include(dirname(__FILE__) . '/pages/feeds.inc.php'); } break; } break; } ?>
update_all(); $events = 0; foreach ($event_arr as $instance=>$result) { if (is_int($result)) $events += $result; } return $events; } function update_all() { global $wpdb; $this->update_option('_last_update', time()); $events = array(); $results =& $wpdb->get_results("SELECT * FROM `".$wpdb->prefix."lifestream_feeds`"); foreach ($results as $result) { $instance = LifeStream_Feed::construct_from_query_result($this, $result); try { $feed_msg = $instance->refresh(); $events[$instance->id] = $feed_msg[1]; } catch (LifeStream_FeedFetchError $ex) { $this->log_error($ex, $instance->id); $events[$instance->id] = $ex; } } return $events; } /** * Registers a feed class with LifeStream. */ function register_feed($class_name) { $this->feeds[get_class_constant($class_name, 'ID')] = $class_name; ksort($this->feeds); } function get_feed($class_name) { return $this->feeds[$class_name]; } /** * Similar to file_get_contents but will use curl by default. */ function file_get_contents($url) { $handler = $this->get_option('url_handler'); $use_fsock = true; if (($handler == 'auto' && function_exists('curl_init')) || $handler == 'curl') { $use_fsock = false; } $file = new SimplePie_File($url, 10, 5, null, SIMPLEPIE_USERAGENT, $use_fsock); if (!$file->success) { throw new LifeStream_FeedFetchError('Failed to open url: '.$url .' ('.$file->error.')'); } return $file->body; } /* * This is a wrapper function which initiates the callback for the custom tag embedding. */ function embed_callback($content) { return preg_replace_callback("|\[lifestream(?:\s+([^\]]+))?\]|i", array(&$this, 'embed_handler'), $content); return preg_replace_callback("|<\[]lifestream(?:\s+([^>\]+]))?/?[>\]]|i", array(&$this, 'embed_handler'), $content); } /* * This function handles the real meat by handing off the work to helper functions. */ function embed_handler($matches) { $args = array(); if (count($matches) > 1) { preg_match_all("|(?:([a-z_]+)=[\"']?([a-z0-9_-\s]+)[\"']?)\s*|i", $matches[1], $options); for ($i=0; $iget_option('digest_time'); $digest_interval = $this->get_option('digest_interval'); $time = time(); if ($digest_interval == 'hourly') { // Start at the next hour $time = strtotime(date('Y-m-d H:00:00', strtotime('+1 hour', $time))); } else { // If time has already passed for today, set it for tomorrow if (date('H') > $digest_time) $time = strtotime('+1 day', $time); $time = strtotime(date('Y-m-d '.$digest_time.':00:00', $time)); } wp_schedule_event($time, 'lifestream_digest', 'lifestream_digest_cron'); } function deactivate() { wp_clear_scheduled_hook('lifestream_cron'); wp_clear_scheduled_hook('lifestream_digest_cron'); } /** * Initializes the plug-in upon activation. */ function activate() { if (version_compare(PHP_VERSION, '5.0', '<')) { deactivate_plugins(LIFESTREAM_PLUGIN_FILE); return; } global $wpdb; // Options/database install $this->install(); // Cron job for the update $this->reschedule_cron(); // Add a feed for this blog $results =& $wpdb->get_results("SELECT COUNT(*) as `count` FROM `".$wpdb->prefix."lifestream_feeds`"); if (!$results[0]->count) { $rss_url = get_bloginfo('rss2_url'); $options = array('url' => $rss_url); $feed = new LifeStream_BlogFeed($this, $options); $feed->owner = 'admin'; $feed->owner_id = 1; $feed->save(); $feed->refresh(null, true); } } function credits() { return 'Powered by LifeStream from iBegin.'; } /** * Adds/updates the options on plug-in activation. */ function install($allow_database_install=true) { $version = (string)$this->get_option('_version'); if (!$version) $version = 0; if ($allow_database_install) { $this->install_database($version); } if (version_compare($version, 0.95, '<')) { foreach ($this->_options as $key=>$value) { $ovalue = get_option('lifestream_' . $key); if (!$ovalue) { $value = $value; } else { delete_option('lifestream_' . $key); } $this->add_option($key, $value); } } if (version_compare($version, LIFESTREAM_VERSION)) return; // default options and their values foreach ($this->_options as $key=>$value) { $this->add_option($key, $value); } $this->update_option('_version', LIFESTREAM_VERSION); } /** * Executes a MySQL query with exception handling. */ function safe_query($sql) { global $wpdb; $result = $wpdb->query($sql); if ($result === false) { if ($wpdb->error) { $reason = $wpdb->error->get_error_message(); } else { $reason = $this->__('Unknown SQL Error'); } $this->log_error($reason); throw new LifeStream_Error($reason); } return $result; } /** * Initializes the database if it's not already present. */ function install_database($version) { global $wpdb, $userdata; get_currentuserinfo(); $this->safe_query("CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."lifestream_event` ( `id` int(11) NOT NULL auto_increment, `feed_id` int(11) NOT NULL, `feed` varchar(32) NOT NULL, `link` varchar(200) NOT NULL, `data` blob NOT NULL, `visible` tinyint(1) default 1 NOT NULL, `timestamp` int(11) NOT NULL, `version` int(11) default 0 NOT NULL, `key` char(16) NOT NULL, `owner` varchar(128) NOT NULL, `owner_id` int(11) NOT NULL, PRIMARY KEY (`id`), INDEX `feed` (`feed`), UNIQUE `feed_id` (`feed_id`, `key`, `owner_id`, `link`) ) ENGINE=MyISAM;"); $this->safe_query("CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."lifestream_event_group` ( `id` int(11) NOT NULL auto_increment, `feed_id` int(11) NOT NULL, `event_id` int(11) NULL, `feed` varchar(32) NOT NULL, `data` blob NOT NULL, `total` int(11) default 1 NOT NULL, `updated` tinyint(1) default 0 NOT NULL, `visible` tinyint(1) default 1 NOT NULL, `timestamp` int(11) NOT NULL, `version` int(11) default 0 NOT NULL, `key` char(16) NOT NULL, `owner` varchar(128) NOT NULL, `owner_id` int(11) NOT NULL, PRIMARY KEY (`id`), INDEX `feed` (`feed`), INDEX `feed_id` (`feed_id`, `key`, `owner_id`, `timestamp`) ) ENGINE=MyISAM;"); $this->safe_query("CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."lifestream_feeds` ( `id` int(11) NOT NULL auto_increment, `feed` varchar(32) NOT NULL, `options` text default NULL, `timestamp` int(11) NOT NULL, `active` tinyint(1) default 1 NOT NULL, `owner` varchar(128) NOT NULL, `owner_id` int(11) NOT NULL, `version` int(11) default 0 NOT NULL, INDEX `owner_id` (`owner_id`), PRIMARY KEY (`id`) ) ENGINE=MyISAM;"); $this->safe_query("CREATE TABLE IF NOT EXISTS `".$wpdb->prefix."lifestream_error_log` ( `id` int(11) NOT NULL auto_increment, `message` varchar(255) NOT NULL, `trace` text NULL, `feed_id` int(11) NULL, `timestamp` int(11) NOT NULL, `has_viewed` tinyint(1) default 0 NOT NULL, INDEX `feed_id` (`feed_id`, `has_viewed`), INDEX `has_viewed` (`has_viewed`), PRIMARY KEY (`id`) ) ENGINE=MyISAM;"); if (!$version) return; // URGENT TODO: we need to solve alters when the column already exists due to WP issues if (version_compare($version, 0.5, '<')) { // Old wp-cron built-in stuff wp_clear_scheduled_hook('LifeStream_Hourly'); // Upgrade them to version 0.5 $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event_group` ADD `version` INT(11) NOT NULL DEFAULT '0' AFTER `timestamp`, ADD `key` CHAR( 16 ) NOT NULL AFTER `version`;"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event` ADD `version` INT(11) NOT NULL DEFAULT '0' AFTER `timestamp`, ADD `key` CHAR( 16 ) NOT NULL AFTER `version`;"); } if (version_compare($version, 0.6, '<')) { $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event_group` ADD `owner` VARCHAR(128) NOT NULL AFTER `key`, ADD `owner_id` INT(11) NOT NULL AFTER `owner`;"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event` ADD `owner` VARCHAR(128) NOT NULL AFTER `key`, ADD `owner_id` INT(11) NOT NULL AFTER `owner`;"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_feeds` ADD `owner` VARCHAR(128) NOT NULL AFTER `timestamp`, ADD `owner_id` INT(11) NOT NULL AFTER `owner`;"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event` DROP INDEX `feed_id`, ADD UNIQUE `feed_id` (`feed_id` , `key` , `owner_id` , `link` );"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event_group` DROP INDEX `feed_id`, ADD INDEX `feed_id` (`feed_id` , `key` , `timestamp` , `owner_id`);"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_feeds` ADD INDEX `owner_id` (`owner_id`);"); $this->safe_query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_feeds` SET `owner` = %s, `owner_id` = %d", $userdata->display_name, $userdata->ID)); $this->safe_query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event` SET `owner` = %s, `owner_id` = %d", $userdata->display_name, $userdata->ID)); $this->safe_query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event_group` SET `owner` = %s, `owner_id` = %d", $userdata->display_name, $userdata->ID)); } if (version_compare($version, 0.81, '<')) { $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event` ADD `feed` VARCHAR(32) NOT NULL AFTER `feed_id`"); $this->safe_query("UPDATE IGNORE `".$wpdb->prefix."lifestream_event` as t1 set t1.`feed` = (SELECT t2.`feed` FROM `".$wpdb->prefix."lifestream_feeds` as t2 WHERE t1.`feed_id` = t2.`id`)"); } if (version_compare($version, 0.84, '<')) { $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event` ADD INDEX ( `feed` )"); $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_event_group` ADD INDEX ( `feed` )"); } if (version_compare($version, 0.90, '<')) { $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_feeds` ADD `version` int(11) default 0 NOT NULL AFTER `owner_id`"); } if (version_compare($version, '0.99.6', '<')) { $wpdb->query("ALTER IGNORE TABLE `".$wpdb->prefix."lifestream_feeds` ADD `active` tinyint(1) default 1 NOT NULL AFTER `timestamp`"); } } /** * Gets recent events from the lifestream. * @param {Array} $_ An array of keyword args. */ function get_events($_=array()) { global $wpdb; $defaults = array( // number of events 'limit' => $this->get_option('number_of_items'), // offset of events (e.g. pagination) 'offset' => 0, // array of feed ids 'feed_ids' => array(), // array of user ids 'user_ids' => array(), // array of feed type identifiers 'feed_types' => array(), // interval for date cutoff (see mysql INTERVAL) 'date_interval' => $this->get_option('date_interval'), // start date of events 'start_date' => -1, // end date 'end_date' => -1, // minimum number of events in group 'event_total_min' => -1, // maximum 'event_total_max' => -1, // break groups into single events 'break_groups' => false, ); $_ = array_merge($defaults, $_); # If any arguments are invalid we bail out // Old-style if ($_['number_of_results']) $_['limit'] = $_['number_of_results']; if (!((int)$_['limit'] > 0)) return; if (!((int)$_['offset'] >= 0)) return; if (!preg_match('/[\d]+ (month|day|year|hour|second|microsecond|week|quarter)s?/', $_['date_interval'])) $_['date_interval'] = -1; else $_['date_interval'] = rtrim($_['date_interval'], 's'); $_['feed_ids'] = (array)$_['feed_ids']; $_['user_ids'] = (array)$_['user_ids']; $_['feed_types'] = (array)$_['feed_types']; $where = array('t1.`visible` = 1'); if (count($_['feed_ids'])) { foreach ($_['feed_ids'] as $key=>$value) { $_['feed_ids'][$key] = $wpdb->escape($value); } $where[] = 't1.`feed_id` IN ('.implode(', ', $_['feed_ids']).')'; } elseif (count($_['feed_types'])) { foreach ($_['feed_types'] as $key=>$value) { $_['feed_types'][$key] = $wpdb->escape($value); } $where[] = 't1.`feed` IN ("'.implode('", "', $_['feed_types']).'")'; } if (count($_['user_ids'])) { foreach ($_['user_ids'] as $key=>$value) { $_['user_ids'][$key] = $wpdb->escape($value); } $where[] = 't1.`owner_id` IN ('.implode(', ', $_['user_ids']).')'; } if ($_['event_total_max'] > -1) { $where[] = sprintf('t1.`total` <= %d', $_['event_total_max']); } if ($_['event_total_min'] > -1) { $where[] = sprintf('t1.`total` >= %d', $_['event_total_min']); } if ($_['date_interval'] !== -1) { $where[] = sprintf('t1.`timestamp` > UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL %s))', $_['date_interval']); } if ($_['start_date'] !== -1) { if (!is_int($_['start_date'])) $_['start_date'] = strtotime($_['start_date']); $where[] = sprintf('t1.`timestamp` >= %s', $_['start_date']); } if ($_['end_date'] !== -1) { if (!is_int($_['end_date'])) $_['end_date'] = strtotime($_['end_date']); $where[] = sprintf('t1.`timestamp` <= %s', $_['end_date']); } if ($_['break_groups']) { // we select from lifestream_event vs grouped $table = 'lifestream_event'; $cls = 'LifeStream_Event'; } else { $table = 'lifestream_event_group'; $cls = 'LifeStream_EventGroup'; } $sql = sprintf("SELECT t1.*, t2.`options` FROM `".$wpdb->prefix.$table."` as `t1` INNER JOIN `".$wpdb->prefix."lifestream_feeds` as t2 ON t1.`feed_id` = t2.`id` WHERE (%s) ORDER BY t1.`timestamp` DESC LIMIT %d, %d", implode(') AND (', $where), $_['offset'], $_['limit']); $results =& $wpdb->get_results($sql); $events = array(); foreach ($results as &$result) { if (array_key_exists($result->feed, $this->feeds)) { $events[] = new $cls($this, $result); } } return $events; } } $lifestream = new Lifestream(); function lifestream_get_single_event($feed_type) { global $lifestream; return $lifestream->get_single_event($feed_type); } require_once(dirname(__FILE__) . '/inc/labels.php'); abstract class LifeStream_Extension { /** * Represents a feed object in the database. */ public $options; // The ID must be a-z, 0-9, _, and - characters. It also must be unique. const ID = 'generic'; const NAME = 'Generic'; const AUTHOR = 'David Cramer'; const URL = ''; const DESCRIPTION = ''; // Can this feed be grouped? const CAN_GROUP = true; // Can this feed have a label? const MUST_GROUP = false; // Labels used in rendering each event // params: feed name, event descriptor const LABEL = 'LifeStream_Label'; // The version is so you can manage data in the database for old versions. const VERSION = 2; const MEDIA = 'automatic'; const HAS_EXCERPTS = false; /** * Instantiates this object through a feed database object. */ public static function construct_from_query_result(&$lifestream, $row) { $class = $lifestream->get_feed($row->feed); if (!$class) { $class = 'LifeStream_InvalidExtension'; } if (!empty($row->options)) $options = unserialize($row->options); else $options = null; $instance = new $class($lifestream, $options, $row->id, $row); $instance->date = $row->timestamp; return $instance; } function __construct(&$lifestream, $options=array(), $id=null, $row=null) { $this->lifestream = $lifestream; $this->options = $options; $this->id = $id; if ($row) { $this->owner = $row->owner; $this->owner_id = $row->owner_id; $this->_owner_id = $row->owner_id; $this->version = $row->version; $this->events = $row->events; $this->feed = $row->feed; } else { $this->version = $this->get_constant('VERSION'); } } function __toInt() { return $this->id; } function __toString() { return $this->get_url(); } function get_event_excerpt(&$event, &$bit) { if (!isset($this->option['excerpts'])) { // default legacy value $this->options['excerpt'] = 1; } if ($this->options['excerpt'] > 0) { $excerpt = $this->get_event_description($event, $bit); } if ($this->options['excerpt'] == 1) { $excerpt = $this->lifestream->truncate($excerpt, $this->lifestream->get_option('truncate_length')); } return $excerpt; } function has_excerpt(&$event, &$bit) { if (!isset($this->option['excerpts'])) { // default legacy value $this->options['excerpt'] = 1; } return ($this->options['excerpt'] > 0 && $this->get_event_description($event, $bit)); } /** * Returns the description (also used in excerpts) for this * event. * @return {String} event description */ function get_event_description(&$event, &$bit) { return $bit['description']; } function get_event_display(&$event, &$bit) { return $bit['title']; } function get_feed_display() { return $this->__toString(); } function get_icon_url() { if (!empty($this->options['icon_url'])) { return $this->options['icon_url']; } return $this->lifestream->path . '/images/' . $this->get_constant('ID') . '.png'; } function get_public_url() { return $this->get_constant('URL'); } function get_image_url($row, $item) { return is_array($item['image']) ? $item['image']['url'] : $item['image']; } function get_thumbnail_url($row, $item) { // Array checks are for backwards compatbility return is_array($item['thumbnail']) ? $item['thumbnail']['url'] : $item['thumbnail']; } function get_public_name() { if (!empty($this->options['feed_label'])) { return $this->options['feed_label']; } return $this->get_constant('NAME'); } /** * Returns a constant attached to this class. * @param {string} $constant * @return {string | integer} $value */ function get_constant($constant) { return constant(sprintf('%s::%s', get_class($this), $constant)); } /** * Returns an array of available options. * @return {array} Available options. */ function get_options() { return array( // key => array(label, required, default value, choices) 'url' => array($this->lifestream->__('Feed URL:'), true, '', ''), ); } function save() { global $wpdb; $this->save_options(); // If it has an ID it means it already exists. if ($this->id) { $result = $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_feeds` set `options` = %s, `owner` = %s, `owner_id` = %d WHERE `id` = %d", serialize($this->options), $this->owner, $this->owner_id, $this->id)); if ($this->_owner_id && $this->_owner_id != $this->owner_id) { $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event` SET `owner` = %s, `owner_id` = %d WHERE `feed_id` = %d", $this->owner, $this->owner_id, $this->id)); $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event_group` SET `owner` = %s, `owner_id` = %d WHERE `feed_id` = %d", $this->owner, $this->owner_id, $this->id)); } } else { $result = $wpdb->query($wpdb->prepare("INSERT INTO `".$wpdb->prefix."lifestream_feeds` (`feed`, `options`, `timestamp`, `owner`, `owner_id`, `version`) VALUES (%s, %s, %d, %s, %d, %d)", $this->get_constant('ID'), serialize($this->options), time(), $this->owner, $this->owner_id, $this->get_constant('VERSION'))); $this->id = $wpdb->insert_id; } return $result; } function delete() { global $wpdb; $this->lifestream->safe_query($wpdb->prepare("DELETE FROM `".$wpdb->prefix."lifestream_feeds` WHERE `id` = %d", $this->id)); $this->lifestream->safe_query($wpdb->prepare("DELETE FROM `".$wpdb->prefix."lifestream_event` WHERE `feed_id` = %d", $this->id)); $this->lifestream->safe_query($wpdb->prepare("DELETE FROM `".$wpdb->prefix."lifestream_event_group` WHERE `feed_id` = %d", $this->id)); $this->lifestream->safe_query($wpdb->prepare("DELETE FROM `".$wpdb->prefix."lifestream_error_log` WHERE `feed_id` = %d", $this->id)); $this->id = null; } /** * Called upon saving options to handle additional data management. */ function save_options() { } /** * Validates the feed. A success has no return value. */ function test() { try { $this->save_options(); $this->fetch(); } catch (LifeStream_Error $ex) { return $ex->getMessage(); } } function refresh($urls=null, $initial=false) { global $wpdb; date_default_timezone_set('UTC'); if (!$this->id) return array(false, $this->lifestream->__('Feed has not yet been saved.')); $grouped = array(); $ungrouped = array(); $total = 0; try { $items = $this->fetch($urls, $initial); } catch (LifeStream_Error $ex) { $this->lifestream->log_error($ex, $this->id); return array(false, $ex); } if (!$items) return array(false, $this->lifestream->__('Feed result was empty.')); if (!$initial) $default_timestamp = time(); else $default_timestamp = 0; foreach ($items as $item_key=>&$item) { // We need to set the default timestamp if no dates are set $date = array_key_pop($item, 'date'); $key = array_key_pop($item, 'key'); if (!($date > 0)) $date = $default_timestamp; if ($this->version == 2) { if ($item['guid']) $link_key = md5(array_key_pop($item, 'guid')); else $link_key = md5($item['link'] . $item['title']); } elseif ($this->version == 1) { $link_key = md5($item['link'] . $item['title']); } else { $link_key = $item['link']; } $affected = $wpdb->query($wpdb->prepare("INSERT IGNORE INTO `".$wpdb->prefix."lifestream_event` (`feed_id`, `feed`, `link`, `data`, `timestamp`, `version`, `key`, `owner`, `owner_id`) VALUES (%d, %s, %s, %s, %d, %d, %s, %s, %d)", $this->id, $this->get_constant('ID'), $link_key, serialize($item), $date, $this->get_constant('VERSION'), $key, $this->owner, $this->owner_id)); if ($affected) { $item['id'] = $wpdb->insert_id; $item['date'] = $date; $item['key'] = $key; $total += 1; $label = $this->get_label_class($key); if ($this->options['grouped'] && $this->get_constant('CAN_GROUP') && constant($label, 'CAN_GROUP')) { if (!array_key_exists($key, $grouped)) $grouped[$key] = array(); $grouped[$key][date('m d Y', $date)] = $date; } else { $ungrouped[] = $item; } } else { unset($items[$item_key]); } } // Grouping them by key foreach ($grouped as $key=>$dates) { // Grouping them by date foreach ($dates as $date_key=>$date) { // Get all of the current events for this date // (including the one we affected just now) $results =& $wpdb->get_results($wpdb->prepare("SELECT `data`, `link` FROM `".$wpdb->prefix."lifestream_event` WHERE `feed_id` = %d AND `visible` = 1 AND DATE(FROM_UNIXTIME(`timestamp`)) = DATE(FROM_UNIXTIME(%d)) AND `key` = %s", $this->id, $date, $key)); $events = array(); foreach ($results as &$result) { $result->data = unserialize($result->data); if (!$result->data['link']) $result->data['link'] = $result->link; $events[] = $result->data; } // First let's see if the group already exists in the database $group =& $wpdb->get_results($wpdb->prepare("SELECT `id` FROM `".$wpdb->prefix."lifestream_event_group` WHERE `feed_id` = %d AND DATE(FROM_UNIXTIME(`timestamp`)) = DATE(FROM_UNIXTIME(%d)) AND `key` = %s LIMIT 0, 1", $this->id, $date, $key)); if (count($group) == 1) { $group =& $group[0]; $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_event_group` SET `data` = %s, `total` = %d, `updated` = 1, `timestamp` = %d WHERE `id` = %d", serialize($events), count($events), $date, $group->id)); } else { $wpdb->query($wpdb->prepare("INSERT INTO `".$wpdb->prefix."lifestream_event_group` (`feed_id`, `feed`, `data`, `total`, `timestamp`, `version`, `key`, `owner`, `owner_id`) VALUES(%d, %s, %s, %d, %d, %d, %s, %s, %d)", $this->id, $this->get_constant('ID'), serialize($events), count($events), $date, $this->get_constant('VERSION'), $key, $this->owner, $this->owner_id)); } } } foreach ($ungrouped as &$item) { $date = array_key_pop($item, 'date'); $key = array_key_pop($item, 'key'); $wpdb->query($wpdb->prepare("INSERT INTO `".$wpdb->prefix."lifestream_event_group` (`feed_id`, `feed`, `event_id`, `data`, `timestamp`, `total`, `version`, `key`, `owner`, `owner_id`) VALUES(%d, %s, %d, %s, %d, 1, %d, %s, %s, %d)", $this->id, $this->get_constant('ID'), $item['id'], serialize(array($item)), $date, $this->get_constant('VERSION'), $key, $this->owner, $this->owner_id)); } $wpdb->query($wpdb->prepare("UPDATE `".$wpdb->prefix."lifestream_feeds` SET `timestamp` = UNIX_TIMESTAMP() WHERE `id` = %d", $this->id)); return array(true, $total); } abstract function fetch(); function render_item($row, $item) { $thumbnail = $this->get_thumbnail_url($row, $item); if (!empty($thumbnail) && $this->get_constant('MEDIA') == 'automatic') { $image = $this->get_image_url($row, $item); if ($this->lifestream->get_option('use_ibox') == '1' && !empty($image)) { // change it to be large size images $ibox = ' rel="ibox&target=\''.htmlspecialchars($image).'\'"'; } else $ibox = ''; return sprintf('%s', htmlspecialchars($item['link']), htmlspecialchars($item['title']), htmlspecialchars($thumbnail), htmlspecialchars($item['title'])); } return sprintf('%s', htmlspecialchars($item['link']), htmlspecialchars($item['title'])); } function get_label_class($key) { return $this->get_constant('LABEL'); } function get_label($event, $options=array()) { $cls = $this->get_label_class($event->key); return new $cls($this, $event, $options); } function render($event, $options) { $lifestream = $this->lifestream; $id = uniqid('ls_', true); $options['id'] = $id; $label_inst = $this->get_label($event, $options); if (count($event->data) > 1) { if ($this->lifestream->get_option('show_owners')) { $label = $label_inst->get_label_plural_user(); } else { $label = $label_inst->get_label_plural(); } } else { if ($this->lifestream->get_option('show_owners')) { $label = $label_inst->get_label_single_user(); } else { $label = $label_inst->get_label_single(); } } $feed_label = $label_inst->get_feed_label(); $hour_format = $this->lifestream->get_option('hour_format'); if ($event->is_grouped && count($event->data) == 1 && $this->get_constant('MUST_GROUP')) $visible = true; else $visible = $options['show_details']; if ($visible === null) $visible = !$this->lifestream->get_option('hide_details_default'); if ($options['hide_metadata']) $show_metadata = false; else $show_metadata = true; include('templates/'.$label_inst->get_template().'.inc.php'); } function get_events($limit=50, $offset=0) { global $wpdb; if (!$this->id) return false; if (!($limit > 0) || !($offset >= 0)) return false; $results =& $wpdb->get_results($wpdb->prepare("SELECT t1.*, t2.`feed`, t2.`options` FROM `".$wpdb->prefix."lifestream_event` as t1 JOIN `".$wpdb->prefix."lifestream_feeds` as t2 ON t1.`feed_id` = t2.`id` WHERE t1.`feed_id` = %d ORDER BY t1.`timestamp` DESC LIMIT %d, %d", $this->id, $offset, $limit)); $events = array(); foreach ($results as &$result) { $events[] = new LifeStream_Event($this->lifestream, $result); } return $events; } } class LifeStream_InvalidExtension extends LifeStream_Extension { const NAME = '(The extension could not be found)'; function get_url() { return $this->feed; } function fetch() { return; } } /** * Generic RSS/Atom feed extension. */ class LifeStream_Feed extends LifeStream_Extension { function save_options() { $urls = $this->get_url(); if (!is_array($urls)) $urls = array($urls); $url = $urls[0]; if (is_array($url)) $url = $url[0]; $feed = new SimplePie(); $feed->enable_cache(false); $data = $this->lifestream->file_get_contents($url); $feed->set_raw_data($data); $feed->enable_order_by_date(false); $feed->force_feed(true); $success = $feed->init(); if ($this->options['auto_icon'] && ($url = $feed->get_favicon())) { if ($this->lifestream->validate_image($url)) { $this->options['icon_url'] = $url; } else { $this->options['icon_url'] = ''; } } // elseif ($this->options['icon_url']) // { // if (!$this->lifestream->validate_image($this->options['icon_url'])) // { // throw new LifeStream_Error($this->lifestream->__('The icon url is not a valid image.')); // } // } parent::save_options(); } function fetch($urls=null, $initial=false) { if (!$urls) $urls = $this->get_url(); if (!is_array($urls)) $urls = array($urls); $items = array(); foreach ($urls as $url_data) { if (is_array($url_data)) { // url, key list($url, $key) = $url_data; } else { $url = $url_data; $key = ''; } $feed = new SimplePie(); $feed->enable_cache(false); $data = $this->lifestream->file_get_contents($url); $feed->set_raw_data($data); $feed->enable_order_by_date(false); $feed->force_feed(true); $success = $feed->init(); if (!$success) { $sample = substr($data, 0, 150); throw new LifeStream_FeedFetchError("Error fetching feed from {$url} ({$feed->error()})....\n\n{$sample}"); } $feed->handle_content_type(); foreach ($feed->get_items() as $row) { $row =& $this->yield($row, $url, $key); if (!$row) continue; if (!$row['key']) $row['key'] = $key; if (count($row)) $items[] = $row; } $feed->__destruct(); unset($feed); } return $items; } function yield($row, $url, $key) { // date and link are required // the rest of the data will be serialized into a `data` field // and is pulled out and used on the render($row) method $title = $row->get_title(); if (!$title) return false; $data = array( 'date' => $row->get_date('U'), 'link' => $this->lifestream->html_entity_decode($row->get_link()), 'title' => $this->lifestream->html_entity_decode($title), 'description' => $this->lifestream->html_entity_decode($row->get_description()), 'key' => $key, 'guid' => $row->get_id(), ); if ($enclosure = $row->get_enclosure()) { if ($thumbnail = $enclosure->get_thumbnail()) { $data['thumbnail'] = $thumbnail; } if ($image = $enclosure->get_medium()) { $data['image'] = $image; } elseif ($image = $enclosure->get_link()) { $data['image'] = $image; } if (!$data['key']) $data['key'] = 'photo'; } return $data; } function get_url() { return $this->options['url']; } function parse_urls($text) { # match http(s):// urls $text = preg_replace('@(https?://([-\w\.]+)+(:\d+)?(/([\w\=/\~_\.]*(\?\S+)?)?)?)@', '$1', $text); # match www urls $text = preg_replace('@((?$1', $text); # match email@address $text = preg_replace('/\b([A-Z0-9._%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4})\b/i', '$1', $text); return $text; } } /** * You need to pass a thumbnail item in yield() for PhotoFeed item's */ class LifeStream_PhotoFeed extends LifeStream_Feed { const LABEL = 'LifeStream_PhotoLabel'; const MUST_GROUP = true; } class LifeStream_GenericFeed extends LifeStream_Feed { const DESCRIPTION = 'The generic feed can handle both feeds with images (in enclosures), as well as your standard text based RSS and Atom feeds.'; function get_options() { return array( 'url' => array($this->lifestream->__('Feed URL:'), true, '', ''), ); } function get_public_url() { return $this->options['url']; } function get_label($event, $options) { if ($event->key == 'photo') $cls = LifeStream_PhotoFeed::LABEL; else $cls = $this->get_constant('LABEL'); return new $cls($this, $event, $options); } } $lifestream->register_feed('LifeStream_GenericFeed'); /** * Outputs the recent lifestream events. * @param {Array} $args An array of keyword args. */ function lifestream($args=array()) { global $lifestream; setlocale(LC_ALL, WPLANG); $_ = func_get_args(); $defaults = array( ); if (!is_array($_[0])) { // old style $_ = array( 'limit' => $_[0], 'feed_ids' => $_[1], 'date_interval' => $_[2], 'user_ids' => $_[4], ); foreach ($_ as $key=>$value) { if ($value == null) unset($_[$key]); } } else { $_ = $args; } $_ = array_merge($defaults, $_); // TODO: offset //$offset = $lifestream->get_option('lifestream_timezone'); $hour_format = $lifestream->get_option('hour_format'); $day_format = $lifestream->get_option('day_format'); $events = call_user_func(array(&$lifestream, 'get_events'), $_); include(dirname(__FILE__) . '/pages/lifestream-table.inc.php'); echo ''; if ($lifestream->get_option('show_credits') == '1') { echo '

'.$lifestream->credits().'

'; } } function lifestream_sidebar_widget($_=array()) { global $lifestream; setlocale(LC_ALL, WPLANG); $defaults = array( 'limit' => 10, 'break_groups' => true, 'show_details' => false, ); $_ = array_merge($defaults, $_); // TODO: offset //$offset = $lifestream->get_option('lifestream_timezone'); $hour_format = $lifestream->get_option('hour_format'); $day_format = $lifestream->get_option('day_format'); $events = call_user_func(array(&$lifestream, 'get_events'), $_); include(dirname(__FILE__) . '/pages/lifestream-list.inc.php'); } function lifestream_register_feed($class_name) { global $lifestream; $lifestream->register_feed($class_name); } include(dirname(__FILE__) . '/feeds.inc.php'); @include(dirname(__FILE__). '/local_feeds.inc.php'); // Require more of the codebase require_once(dirname(__FILE__) . '/inc/widget.php'); require_once(dirname(__FILE__) . '/inc/syndicate.php'); ?>