t('Local path')), array('data' => t('FeedBurner')), array('data' => t('Verified')), array('data' => t('Operations'), 'colspan' => '3'), ); $feeds = _feedburner_get_feeds($cat, array('match' => $keys)); $rows = array(); foreach ($feeds as $feed) { $row = array(); $row[] = l((isset($feed['alias']) ? $feed['alias'] . ' (' . $feed['path'] . ')' : $feed['path']), $feed['path']); if (isset($feed['feedburner'])) { $row[] = l($feed['feedburner'], _feedburner_construct_url($feed['feedburner'])); $row[] = $feed['verified'] ? t('Yes') : t('No'); $row[] = l(t('Edit'), 'admin/build/feedburner/burn/' . $feed['path']); $row[] = l(t('Unburn'), 'admin/build/feedburner/unburn/' . $feed['path']); $row[] = l(t('Source'), $feed['path'], array('query' => 'redirect=no')); } else { $row[] = '-'; $row[] = l(t('Burn'), 'admin/build/feedburner/burn/' . $feed['path']); $row[] = ''; $row[] = ''; $row[] = ''; } $rows[] = $row; } if (empty($rows)) { $empty_message = $keys ? t('No feeds found.') : t('No feeds available.') ; $rows[] = array(array('data' => $empty_message, 'colspan' => 5)); } $output .= theme('table', $header, $rows); $output .= _feedburner_blurb(); //drupal_add_js('misc/collapse.js'); return $output; } /** * Return a form to filter URL aliases. */ function feedburner_build_filter_form(&$form_state, $cat, $keys = '') { $form['#attributes'] = array('class' => 'search-form'); $form['basic'] = array( '#type' => 'fieldset', '#title' => t('Filter feeds'), ); $form['basic']['inline'] = array( '#prefix' => '
', '#suffix' => '
', ); $form['basic']['inline']['filter'] = array( '#type' => 'textfield', '#title' => '', '#default_value' => $keys, '#maxlength' => 64, '#size' => 25, ); $form['basic']['inline']['submit'] = array( '#type' => 'submit', '#value' => t('Filter'), '#submit' => array('feedburner_build_filter_form_submit_filter'), ); $form['cat'] = array( '#type' => 'value', '#value' => $cat, ); if (!empty($keys)) { $form['basic']['inline']['reset'] = array( '#type' => 'submit', '#value' => t('Reset'), '#submit' => array('feedburner_build_filter_form_submit_reset'), ); } return $form; } /** * Process filter form submission when the Filter button is pressed. */ function feedburner_build_filter_form_submit_filter($form, &$form_state) { $form_state['redirect'] = 'admin/build/feedburner/list/' . $form_state['values']['cat'] . '/' . trim($form_state['values']['filter']); } /** * Process filter form submission when the Reset button is pressed. */ function feedburner_build_filter_form_submit_reset($form, &$form_state) { $form_state['redirect'] = 'admin/build/feedburner/list/' . $form_state['values']['cat']; } function feedburner_burn_form() { $path = _feedburner_get_path(5); $feed = db_result(db_query("SELECT feedburner FROM {feedburner} WHERE path = '%s'", $path)); //$feed = _feedburner_load_feed($path); $form['path'] = array( '#type' => 'textfield', '#title' => t('Local Feed'), '#default_value' => $path, '#maxlength' => 128, '#size' => 45, '#description' => t('Specify the existing feed on your site from which to redirect.'), '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='), '#autocomplete_path' => 'feedburner/autocomplete/all', ); $form['feedburner'] = array( '#type' => 'textfield', '#title' => t('FeedBurner Feed'), '#default_value' => $feed, '#maxlength' => 100, '#size' => 45, '#description' => t('Requests to the above feed will be requested to this FeedBurner feed. This field is case-sensitive and alphanumeric.'), '#field_prefix' => _feedburner_construct_url(), '#autocomplete_path' => 'feedburner/autocomplete/feedburner', ); //$form['options'] = array( // '#type' => 'fieldset', // '#title' => t('Options'), // '#collapsible' => TRUE, // '#description' => t('FeedBurner Management API features coming soon.'), //); // TODO: Feed Management API Options $form['submit'] = array('#type' => 'submit', '#value' => t('Save')); $form['cancel'] = array('#value' => l(t('Cancel'), 'admin/build/feedburner')); return $form; } function feedburner_burn_form_validate($form, &$form_state) { $path = $form_state['values']['path']; $feedburner = $form_state['values']['feedburner']; $path_menu = menu_get_item($path); if (!valid_url($path) || !$path_menu || !$path_menu['access']) { form_set_error('path', t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $path))); } if (preg_match('/[^\w-]/', $feedburner)) { form_set_error('feedburner', 'Invalid FeedBurner feed name'); } } function feedburner_burn_form_submit($form, &$form_state) { _feedburner_save_feed($form_state['values']['path'], $form_state['values']['feedburner']); drupal_set_message(t('The feed redirection for %path has been saved.', array('%path' => $form_state['values']['path']))); if (_feedburner_can_api(TRUE)) { // TODO: AddFeed / ModifyFeed Management API Calls } $form_state['redirect'] = 'admin/build/feedburner'; return; } function feedburner_unburn_form() { $path = _feedburner_get_path(5); $feed = db_result(db_query("SELECT feedburner FROM {feedburner} WHERE path = '%s'", $path)); if (empty($path) || empty($feed)) { drupal_goto('admin/build/feedburner'); exit(); } $form['path'] = array( '#type' => 'hidden', '#value' => $path, ); //$form['unburn'] = array( // '#type' => 'checkbox', // '#title' => t('Delete the FeedBurner feed %feed from my FeedBurner account.', array('%feed' => $feed->fb_uri)), // '#default_value' => FALSE, // '#disabled' => TRUE, // '#description' => t('FeedBurner Management API features coming soon.'), //); // //if (!_feedburner_can_api(TRUE)) { // $form['unburn']['#disabled'] = TRUE; //} $form['#redirect'] = 'admin/build/feedburner'; return confirm_form($form, t('Are you sure you want to unburn %feed?', array('%feed' => $path)), 'admin/build/feedburner', t('Requests for this feed will no longer be redirected to FeedBurner. But don\'t worry, you can always re-burn this feed to FeedBurner.')); } function feedburner_unburn_form_submit($form, &$form_state) { if ($form_state['values']['confirm']) { if ($form_state['values']['unburn']) { // TODO DeleteFeed API implementation for unburn feed submit } _feedburner_save_feed($form_state['values']['path']); drupal_set_message(t('Redirection for %url has been removed.', array('%url' => $form_state['values']['path']))); $form_state['redirect'] = 'admin/build/feedburner'; return; } } function feedburner_settings_form() { $form['redirection'] = array( '#type' => 'fieldset', '#title' => t('Feed Redirection'), ); $form['redirection']['feedburner_redirect_status'] = array( '#type' => 'select', '#title' => t('Redirection HTTP header status code'), '#default_value' => variable_get('feedburner_redirect_status', 307), '#options' => array( 301 => '301 Moved Permanently', 302 => '302 Found', 307 => '307 Temporary Redirect'), '#description' => t('Please note that the "307 Temporary Redirect" is recommended. For detailed descriptions of HTTP redirect status codes, see the Wikipedia article on HTTP status codes.', array('@link' => 'http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection')), ); if (module_exists('blog')) { $form['redirection']['feedburner_blogs'] = array( '#type' => 'checkbox', '#title' => t('Allow users to specify a FeedBurner feed for their own blog\'s feed.'), '#default_value' => variable_get('feedburner_blogs', 0), '#description' => t('If the user has the permission to blog, this option is found in his/her edit account page. If FeedFlare is enabled for blog content types, this option will also override FeedFlare.', array('@link' => url('user/' . $GLOBALS['user']->uid . '/edit'))), ); } $feeds = array(0 => 'None (disabled)'); $result = db_query('SELECT DISTINCT feedburner FROM {feedburner} ORDER BY feedburner'); while ($feed = db_result($result)) { $feeds[$feed] = $feed; } $form['feedflare'] = array( '#type' => 'fieldset', '#title' => t('FeedFlare/Standard Stats/Ad Network'), '#description' => t('See @link for more information.', array('@link' => 'http://www.feedburner.com/fb/a/publishers/feedflare')), '#collapsible' => FALSE, ); $form['feedflare']['feedburner_feedflare_feed'] = array( '#type' => 'select', '#title' => t('FeedFlare/Standard Stats feed'), '#default_value' => variable_get('feedburner_feedflare_feed', 0), '#options' => $feeds, ); $form['feedflare']['feedburner_feedflare_node_types'] = array( '#type' => 'checkboxes', '#title' => t('Display in node types'), '#default_value' => variable_get('feedburner_feedflare_node_types', array()), '#options' => node_get_types('names'), ); $form['feedflare']['feedburner_feedflare_display'] = array( '#type' => 'checkboxes', '#title' => t('How to display FeedFlare/Ad Network'), '#default_value' => variable_get('feedburner_feedflare_display', array('page')), '#options' => array( 'teaser' => t('Teaser view'), 'page' => t('Full-page view'), ), // TODO: A better way to list node display types? '#description' => t('When to display the FeedFlare after the node text. There is also a FeedFlare block available.', array('@block' => url('admin/build/block/configure/feedburner/0'))), ); //$form['feedflare']['feedburner_standardstats'] = array( // '#type' => 'checkbox', // '#default_value' => variable_get('feedburner_standardstats', TRUE), // '#title' => t('Include StandardStats code on pages that don\'t display FeedFlare or Ad Network'), //); //$form['account'] = array( // '#type' => 'fieldset', // '#title' => t('FeedBurner Account'), // '#description' => t('To use more advanced features like FeedFlare, e-mail subscriptions, and feed stats, you need to enter your FeedBurner account details. If you do not yet have a FeedBurner account, you can register at @link.', array('@link' => 'https://www.feedburner.com/fb/a/register')), // '#collapsible' => TRUE, // '#collapsed' => FALSE, //); //$auth = variable_get('feedburner_auth', NULL); //$form['account']['feedburner_username'] = array( // '#type' => 'textfield', // '#title' => t('Your FeedBurner username'), // '#default_value' => (!empty($auth) ? strtok(base64_decode($auth), ':') : ''), // '#size' => 25, // '#maxlength' => 30, //); //$form['account']['feedburner_password'] = array( // '#type' => 'password', // '#title' => t('Your FeedBurner password'), // //'#default_value' => '', // '#size' => 25, // '#maxlength' => 30, //); //$form['account']['verified'] = array( // '#type' => 'markup', // '#value' => '

' . t('Account status:') . '
' . t('Verified') : 'red">' . t('NOT VERIFIED')) . '

', //); // //if (!_feedburner_can_api()) { // $form['account']['#title'] .= t(' (DISABLED - requires PHP 5)'); // $form['account']['#collapsed'] = TRUE; // $form['account']['feedburner_username']['#disabled'] = TRUE; // $form['account']['feedburner_password']['#disabled'] = TRUE; //} $form['advanced'] = array( '#type' => 'fieldset', '#title' => t('Advanced Settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['advanced']['feedburner_useragents'] = array( '#type' => 'textarea', '#title' => t('User agents allowed direct feed access'), '#description' => t('Enter one page per line as user agents that will be allowed to access your site\'s feeds without being redirected to FeedBurner. The \'*\' character is a wildcard. User agent strings do not need to be exact (e.g. "feed" will match "feedburner").'), '#default_value' => preg_replace(array('%^/(.*)/i$%', '/(? 3, ); $form['advanced']['feedburner_domain'] = array( '#type' => 'textfield', '#title' => t('MyBrand custom domain'), '#description' => t('MyBrand is a premium FeedBurner service that allows you to showcase your feeds by serving them from your own domain (e.g., @domain). You must have access to change your CNAME entry in the DNS records for the domain you wish to change. For more information, see @link.', array('@link' => 'http://www.feedburner.com/fb/a/mybrand', '@domain' => 'feeds.' . $_SERVER['SERVER_NAME'])), '#default_value' => variable_get('feedburner_domain', 'feeds.feedburner.com'), '#field_prefix' => 'http://', '#field_suffix' => '/feedname', '#size' => 30, '#maxlength' => 30, ); $form['array_filter'] = array('#type' => 'value', '#value' => TRUE); $form['blurb'] = array( '#type' => 'markup', '#value' => _feedburner_blurb(), '#weight' => 10, ); return system_settings_form($form); } function feedburner_settings_form_validate($form, &$form_state) { $values =& $form_state['values']; // Fix redirect code to int $values['feedburner_redirect_status'] = (int) $values['feedburner_redirect_status']; //// feedburner username && password //if (!preg_match('/^\w*$/', $values['feedburner_username'])) { // form_set_error('feedburner_username', 'Invalid FeedBurner username.'); //} //if (!preg_match('/^\w*$/', $values['feedburner_password'])) { // form_set_error('feedburner_username', 'Invalid FeedBurner password.'); //} //else { // unset($values['feedburner_password']); //} // feedburner_useragents $useragents = preg_replace('/^[|\s]+|[|\s]+$/m', '', $values['feedburner_useragents']); $useragents = preg_quote($useragents); if (empty($useragents) || !preg_match('/\w+/', $useragents)) { drupal_set_message(t('Please enter at least one user agent that will have access to your site\'s feeds. It is strongly recommended to allow both the "feedburner" and "feedvalidator" user agents.'), 'error'); } $useragents = '/' . preg_replace(array('/[\r\n]+/', '/\\\\\*/'), array('|', '.*'), $useragents) . '/i'; $values['feedburner_useragents'] = $useragents; // feedburner_domain $feedburner_domain = $values['feedburner_domain']; if (!variable_get('drupal_http_request_fails', FALSE) && $feedburner_domain != variable_get('feedburner_domain', 'feeds.feedburner.com') && $feedburner_domain != 'feeds.feedburner.com') { $request = drupal_http_request('http://' . $feedburner_domain . '/'); unset($request->data); if (!isset($request->headers['X-FB-Host']) || !isset($request->code) || $request->code != 400 || !isset($request->error) || $request->error != 'You must provide a feed uri') { // TODO: Insert help link for CNAME MyBrand editing (http://www.feedburner.com/fb/a/publishers/mybrand) drupal_set_message(t('The MyBrand domain @domain failed verification. Make sure you have edited the domain\'s CNAME settings before enabling this option.', array('@domain' => $feedburner_domain)), 'error'); } } } function _feedburner_save_feed($path, $feedburner = NULL) { $current = db_result(db_query("SELECT feedburner FROM {feedburner} WHERE path = '%s'", $path)); if (empty($feedburner) && !empty($current)) { db_query("DELETE FROM {feedburner} WHERE path = '%s'", $path); } else { if (!empty($current) && $current != $feedburner) { db_query("UPDATE {feedburner} SET feedburner = '%s' WHERE path = '%s'", $feedburner, $path); _feedburner_verify_feed($path, $feedburner); } elseif (empty($current)) { db_query("INSERT INTO {feedburner} (path, feedburner) VALUES ('%s', '%s')", $path, $feedburner); _feedburner_verify_feed($path, $feedburner); } } return (db_affected_rows() != 0); } // TODO: Split into _get_feeds and _process_feeds? function _feedburner_get_feeds($cat = 'site', $options = array()) { $default_options = array('sort' => TRUE, 'alias' => TRUE, 'feedburner' => TRUE, 'match' => FALSE); $options = array_merge($default_options, $options); $feeds = array(); // Site feeds (and various module feeds) if ($cat == 'site' || $cat == 'all') { $feeds[] = array('path' => 'rss.xml', 'description' => variable_get('site_name', 'Drupal') . ' RSS'); $feeds[] = array('path' => 'aggregator/feed', 'description' => 'Aggregator RSS', 'module' => 'aggregator'); //$feeds[] = array('path' => 'blog/feed', 'description' => 'Blogs', 'module' => 'blog'); $feeds[] = array('path' => 'crss', 'description' => variable_get('site_name', 'Drupal') . ' Comments', 'module' => 'commentrss'); $feeds[] = array('path' => 'atom/feed', 'description' => variable_get('site_name', 'Drupal') . ' Atom', 'module' => 'atom'); } // TODO: Views integration //if (preg_match('/all|views/', $cat) && module_exists('views')) { // $result = db_query("SELECT url, page_title FROM {view_view} WHERE page_type = 'views_rss' OR page_type = 'views_podcast'"); // while ($view_details = db_fetch_object($result)) { // $feeds[] = array('path' => $view_details->url, 'cat' => 'views', 'description' => $view_details->page_title); // } // $result = db_query("SELECT v.url, v.page_title FROM {view_view} v, {view_argument} a WHERE a.type = 'rss_feed' and v.vid = a.vid"); // while ($viewargs_details = db_fetch_object($result)) { // $feeds[] = array('path' => $viewargs_details->url . '/feed', 'cat' => 'views', 'description' => $viewargs_details->page_title); // } // unset($result); //} // TODO: Content integration //$result = db_query('SELECT nid, title FROM {node} WHERE status = 1'); //while ($node_details = db_fetch_object($result)) { // $feeds[] = array('path' => 'node/' . $node_details->nid . '/feed', 'cat' => 'content', 'description' => $node_details->title); //} //unset($result); // Blog module feeds if (($cat == 'all' || $cat == 'blogs') && module_exists('blog')) { $feeds[] = array('path' => 'blog/feed', 'description' => variable_get('site_name', 'Drupal') . ' blogs'); // Get all user blog feeds for users with the blogging permission granted $blog_roles = user_roles(TRUE, 'create blog entries'); $blog_roles_sql = (count($blog_roles) ? (isset($blog_roles[2]) ? ' OR u.uid > 1' : ' OR ur.rid IN (' . db_placeholders($blog_roles) . ')') : ''); $sql = "SELECT u.uid, u.name FROM {users} u LEFT JOIN {users_roles} ur ON ur.uid = u.uid WHERE u.uid = 1" . $blog_roles_sql; $result = db_query($sql, array_keys($blog_roles)); while ($user_details = db_fetch_object($result)) { $feeds[] = array('path' => 'blog/' . $user_details->uid . '/feed', 'description' => $user_details->name . "'s Blog"); } unset($result); } // Taxonomy feeds if (($cat == 'all' || $cat == 'taxonomy') && module_exists('taxonomy')) { $result = db_query('SELECT tid, name FROM {term_data}'); while ($term_details = db_fetch_object($result)) { $feeds[] = array('path' => 'taxonomy/term/' . $term_details->tid . '/0/feed', 'description' => $term_details->name); } unset($result); } // FeedBurner feeds // TODO: Fetch FeedBurner feeds from FeedManagement API $feedburner_feeds = array(); if ($cat == 'feedburner' || $options['feedburner']) { $query = db_query("SELECT path, feedburner, verified FROM {feedburner}"); while ($feed = db_fetch_array($query)) { if ($cat == 'all' || $cat == 'feedburner' || $cat == 'site') { $feeds[] = $feed; } else { $feedburner_feeds[$feed['path']] = $feed; } } } $keys = array(); $keepers = array(); foreach ($feeds as $feed) { if (isset($feed['module']) && !module_exists($feed['module'])) { continue; } // Merge information if (isset($keys[$feed['path']])) { $index = $keys[$feed['path']]; $keepers[$index] = array_merge($feed, $keepers[$index]); continue; } // Lookup alias if ($options['alias']) { $alias = drupal_get_path_alias($feed['path']); if ($alias != $feed['path']) { $feed['alias'] = $alias; } } // Match regular expressions if ($options['match']) { $regex = '/' . preg_quote($options['match'], '/') . '/i'; $feed['value'] = FALSE; foreach (array('path', 'alias', 'feedburner') as $field) { if (isset($feed[$field]) && preg_match($regex, $feed[$field])) { $value = levenshtein($options['match'], $feed[$field]); if ($feed['value'] === FALSE || $value < $feed['value']) { $feed['value'] = $value; } } } if ($feed['value'] === FALSE) { continue; } } // Load FeedBurner Data if ($options['feedburner'] && isset($feedburner_feeds[$feed['path']])) { $feed = array_merge($feed, $feedburner_feeds[$feed['path']]); } $keepers[] = $feed; $keys[$feed['path']] = count($keepers) - 1; } $feeds = $keepers; // Sort by array key (custom sort) if ($options['sort']) { // My funkly little sort function that sorts 'blog' and 'blog1' ahead of 'blog/...' and recurses down each section of the path function _feedburner_temp_sort_path($a, $b) { $a = explode('/', $a, 2); $b = explode('/', $b, 2); //return (intval($a[0]) xor intval($b[0]) ? intval($a[0]) : ($result = strnatcasecmp($a[0], $b[0]) ? $result : _feedburner_temp_sort_path($a[1], $b[1]))); if (intval($a[0]) xor intval($b[0])) { return intval($a[0]); } elseif ($result = strnatcasecmp($a[0], $b[0])) { return $result; } else { return _feedburner_temp_sort_path($a[1], $b[1]); } } function _feedburner_temp_sort_fields($a, $b) { if (isset($a['value']) && isset($b['value']) && $a['value'] != $b['value']) { return $a['value'] > $b['value']; } else { return _feedburner_temp_sort_path((isset($a['alias']) ? $a['alias'] : $a['path']), (isset($b['alias']) ? $b['alias'] : $b['path'])); } } usort($feeds, '_feedburner_temp_sort_fields'); } return $feeds; } // TODO: CLEANUP AND OPTIMIZE! // TODO: Make this a callback instead of private function function _feedburner_verify_feed($local, $feedburner) { if (!variable_get('drupal_http_request_fails', FALSE)) { for ($i = 0; $i < 3; $i++) { $url = NULL; $request = NULL; $message_start = NULL; $results = array(NULL, NULL, NULL, time()); switch ($i) { case 0: $url = url($local, array('absolute' => TRUE, 'query' => 'redirect=no')); $message_start = t('Local feed '); break; case 1: $url = _feedburner_construct_url($feedburner); $message_start = t('FeedBurner feed '); break; case 2: $url = url($local, array('absolute' => TRUE)); $message_start = t('Local feed redirection for '); break; } $request = drupal_http_request($url); unset($request->data); switch ($i) { case 0: $url = url($local, array('absolute' => TRUE)); case 1: $results[$i] = (isset($request->code) && $request->code == '200' && is_array($request->headers) && preg_match('/rss|atom|xml/', $request->headers['Content-Type'])); break; case 2: $results[$i] = (isset($request->code) && $request->code == variable_get('feedburner_redirect_status', 307) && isset($request->redirect_code) && $request->redirect_code == '200' && isset($request->redirect_url) && $request->redirect_url == _feedburner_construct_url($feedburner)); break; } //if ($result[$i]) { // drupal_set_message($message_start . t('@link verified.', array('@link' => $url))); //} if (!$results[$i]) { $results[3] = 0; drupal_set_message($message_start . t('@link failed verification. @error', array('@link' => $url, '@error' => $request->error)), 'error'); break; } } } db_query("UPDATE {feedburner} SET verified = %d WHERE path = '%s' AND feedburner = '%s'", $results[3], $local, $feedburner); } function feedburner_autocomplete($cat) { $key = trim(_feedburner_get_path(4)); $feeds = _feedburner_get_feeds($cat, array('match' => $key, 'feedburner' => FALSE)); $keepers = array(); foreach ($feeds as $feed) { if ($cat == 'feedburner') { $keepers[$feed['feedburner']] = $feed['feedburner']; } else { $keepers[$feed['path']] = ($feed['alias'] ? $feed['alias'] . ' (' . $feed['path'] . ')' : $feed['path']) . ($feed['description'] ? ' - ' . $feed['description'] : ''); } if (count($keepers) == 10) { break; } } print drupal_to_js($keepers); exit(); }