MyBB Community Forums

Full Version: Twitter Feeds why it works on PHP 5.6, but not on 7+
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hey guys,

The plugin from mybb extend page with code below runs perfectly on php 5.6, but on php 7+ it just doesn't show newest tweets, it updates the time of currently shown tweets, but new ones are not appearing.

Is there some error which is incompatible with php7+ or some PHP extension which needs to be added? (I have PHP oauth enabled on 7)

Testing it on XAMPP and web host both react in the same way and there are no error_logs which is so hard to debug.

<?php

/**
 * MyBB 1.8
 * Copyright 2014 MyBB Group, All Rights Reserved
 *
 * Website: http://www.mybb.com
 * License: http://www.mybb.com/about/license
 *
 *  Much taken from here - http://stackoverflow.com/a/28948626/4364192
 *
 *  MYBB Twitter Feed Extension
 *  **** Written by Megan Starr (megstarr.com)
 *
 */

// Make sure we can't access this file directly from the browser.
if(!defined('IN_MYBB')) {
	die('This file cannot be accessed directly.');
}

function twitterfeed_info() {
  return array(
   'name'			=> 'Twitter Feed Widget',
   'description'	=> 'Loads customizable feed from provided twitter account.',
   'website'		=> '',
   'author'		=> 'Megan Lyle',
   'authorsite'	=> 'http://megstarr.com',
   'version'		=> '1.0',
   'compatibility'	=> '18*'
  );
}

function twitterfeed_install(){
  global $db;

  // Create Settings
	$twitter_group = array(
			'gid'    => 'NULL',
			'name'  => 'twitter',
			'title'      => 'Twitter Feed',
			'description'    => 'Fully peronalized twitter feed on index',
			'disporder'    => "1",
			'isdefault'  => "0",
	);

	$db->insert_query('settinggroups', $twitter_group);
	$gid = $db->insert_id();

  $twitter_settings[0] = array(
          'sid'            => 'NULL',
          'name'        => 'twitter_apikey',
          'title'            => 'API Key',
          'description'    => 'Can be found through the Twitter website (Consumer Key).',
          'optionscode'    => 'text',
          'value'        => '',
          'disporder'        => 1,
          'gid'            => intval($gid),
  );
  $twitter_settings[1] = array(
          'sid'            => 'NULL',
          'name'        => 'twitter_apisecret',
          'title'            => 'API Secret',
          'description'    => 'Can be found through the Twitter website (Consumer Secret).',
          'optionscode'    => 'text',
          'value'        => '',
          'disporder'        => 2,
          'gid'            => intval($gid),
  );
  $twitter_settings[2] = array(
          'sid'            => 'NULL',
          'name'        => 'twitter_handle',
          'title'            => 'Username',
          'description'    => 'Name of user.',
          'optionscode'    => 'text',
          'value'        => '',
          'disporder'        => 3,
          'gid'            => intval($gid),
  );
  $twitter_settings[3] = array(
          'sid'            => 'NULL',
          'name'        => 'twitter_tweetcount',
          'title'            => 'Tweet Count',
          'description'    => 'Number of tweets to retrieve.',
          'optionscode'    => 'text',
          'value'        => '3',
          'disporder'        => 4,
          'gid'            => intval($gid),
  );
	$twitter_settings[4] = array(
					'sid'            => 'NULL',
					'name'        => 'twitter_interval',
					'title'            => 'Time Interval',
					'description'    => 'Minutes between feed refreshes (for caching).',
					'optionscode'    => 'text',
					'value'        => '10',
					'disporder'        => 5,
					'gid'            => intval($gid),
	);
      foreach($twitter_settings as $setting) {
    		$db->insert_query('settings', $setting);
    	}
    	rebuild_settings();

  // Create any Templates
  $twitter_templates[0] = array(
      "title" 	=> "twitterfeed_feed",
      "template"	=> $db->escape_string('<div style="margin:20px auto;width:80%;padding:10px;border:1px solid;">
															<h2>Twitter Updates <small>via <a href="https://twitter.com/{$handle}">@{$handle}</a></h2>
															{$tweetlist}</div>'),
      "sid"		=> -1,
      "version"	=> 1.0,
      "dateline"	=> TIME_NOW
    );
  $twitter_templates[1] = array(
      "title" 	=> "twitterfeed_tweet",
      "template"	=> $db->escape_string('<small><strong>{$tweet[\'created_at_relative\']}</strong> &mdash; {$tweet[\'html\']}</small>
<hr>'),
      "sid"		=> -1,
      "version"	=> 1.0,
      "dateline"	=> TIME_NOW
  );
	$twitter_templates[2] = array(
      "title" 	=> "twitterfeed_empty",
      "template"	=> $db->escape_string('<small>No feed available</small><hr>'),
      "sid"		=> -1,
      "version"	=> 1.0,
      "dateline"	=> TIME_NOW
  );
  foreach ($twitter_templates as $row) {
    $db->insert_query('templates', $row);
  }

	// Apply any Template Edits
	//First undo
	require_once MYBB_ROOT."/inc/adminfunctions_templates.php";
	find_replace_templatesets('header', '#{\$awaitingusers}{\$twitterfeed}#', '{\$awaitingusers}');
	// Then apply
	find_replace_templatesets('header', '#{\$awaitingusers}#', '{\$awaitingusers}{\$twitterfeed}');
}

function twitterfeed_is_installed(){
  global $db;
	return $db->simple_select('settinggroups', '*','name = \'twitter\'')->num_rows;
}

function twitterfeed_uninstall(){
  global $db, $cache;

  // Delete settings
	$db->delete_query("settings", "name LIKE 'twitter_%'");
	$db->delete_query("settinggroups", "name = 'twitter'");
	rebuild_settings();

  $db->delete_query("templates", "title LIKE 'twitterfeed_%'");
	$db->delete_query("templategroups", "`prefix` = 'twitterfeed'");

	$cache->delete('twitterfeed');

	//Undo template edits
	require_once MYBB_ROOT."/inc/adminfunctions_templates.php";
	find_replace_templatesets('header', '#{\$awaitingusers}{\$twitterfeed}#', '{\$awaitingusers}');
}

function twitterfeed_activate() {

}

function twitterfeed_deactivate() {

}

/**
So that feed can exist in header, load on every page
Thus, we add the render to the global_start hook
*/
$plugins->add_hook("global_start", "twitter_render");
function twitter_render() {
	global $mybb, $cache, $twitterfeed, $tweetlist, $templates;

	$tweetdata = json_decode($cache->read('twitterfeed'), true);
	$handle = $mybb->settings['twitter_handle'];
	if($tweetdata) {
		// Twitter data exists in cache.  we want to ignore the first since it is the timestamp of update
		array_shift($tweetdata);
	  foreach($tweetdata as $tweet) {
			$tweet['created_at_relative'] = timeAgo($tweet['created_at']);
	    eval("\$tweetlist .= \"".$templates->get('twitterfeed_tweet')."\";");
	  }
	} else {
		eval("\$tweetlist = \"".$templates->get('twitterfeed_empty')."\";");
	}

  eval("\$twitterfeed = \"".$templates->get('twitterfeed_feed')."\";");
}

/**
Determines if enough time has passed and, if so, updates cached tweets
This function runs on index_end only to preserve performance on the site
*/
$plugins->add_hook("index_end", "twitter_store");
function twitter_store() {
	global $mybb, $cache;

	$cachedtweets = json_decode($cache->read('twitterfeed'), true);
	$interval = $mybb->settings['twitter_interval'] * 60;
	$twitterdata = array();
	$cache_updated = json_decode($cache->read('twitterfeed'));

	if(time() - (int)$cache_updated[0] > $interval) {
		$twitterupdates = query_twitter();
		if($twitterupdates) {
			$newtwitterdata = array();
			foreach(json_decode($twitterupdates, true) as $tweet) {
		    $tweet['html'] = parse_tweet($tweet['text']);
				$newtwitterdata[] = $tweet;
		  }
			array_unshift($newtwitterdata, time());
			$cache->update('twitterfeed', json_encode($newtwitterdata));
		}
	}

}

/**
Function that actually makes the api call
Stores retrieved tweet information in the mybb cache
*/
function query_twitter() {
  global $mybb;

  // auth parameters
  $api_key = urlencode($mybb->settings['twitter_apikey']); // Consumer Key (API Key)
  $api_secret = urlencode($mybb->settings['twitter_apisecret']); // Consumer Secret (API Secret)
  $auth_url = 'https://api.twitter.com/oauth2/token';

  // what we want?
  $data_username = $mybb->settings['twitter_handle']; // username
  $data_count = (int)$mybb->settings['twitter_tweetcount']; // number of tweets
  $data_url = 'https://api.twitter.com/1.1/statuses/user_timeline.json';

  // get api access token
  $api_credentials = base64_encode($api_key.':'.$api_secret);
  $auth_headers = 'Authorization: Basic '.$api_credentials."\r\n".
                  'Content-Type: application/x-www-form-urlencoded;charset=UTF-8'."\r\n";
  $auth_context = stream_context_create(
      array(
          'http' => array(
              'header' => $auth_headers,
              'method' => 'POST',
              'content'=> http_build_query(array('grant_type' => 'client_credentials', )),
          )
      )
  );

  //Again, hiding warnings
  $auth_response = json_decode(@file_get_contents($auth_url, 0, $auth_context), true);
  $auth_token = $auth_response['access_token'];

  // get tweets
  $data_context = stream_context_create( array( 'http' => array( 'header' => 'Authorization: Bearer '.$auth_token."\r\n", ) ) );
  $otherspecs = '&exclude_replies=true&trim_user=true';

	// Suppressing warning (not great, but handled later)
	return @file_get_contents($data_url.'?count='.$data_count.'&screen_name='.urlencode($data_username).$otherspecs, 0, $data_context);
}


/**
Helper functions to parse tweet information!
*/
/**
  * relative time calculator FROM TWITTER
  * @param {string} twitter date string returned from Twitter API
  * @return {string} relative time like "2 minutes ago"
  */
function timeAgo($dateString) {
    $rightNow = time();
    $then = strtotime($dateString);

    $diff = $rightNow - $then;
    $second = 1;
    $minute = $second * 60;
    $hour = $minute * 60;
    $day = $hour * 24;
    $week = $day * 7;
    $month = $week * 30;
    if (is_nan($diff) || $diff < 0) {
        return ""; // return blank string if unknown
    }
    if ($diff < $second * 2) {
        // within 2 seconds
        return "right now";
    }
    if ($diff < $minute) {
        return floor($diff / $second) . " seconds ago";
    }
    if ($diff < $minute * 2) {
        return "about 1 minute ago";
    }
    if ($diff < $hour) {
        return floor($diff / $minute) . " minutes ago";
    }
    if ($diff < $hour * 2) {
        return "about 1 hour ago";
    }
    if ($diff < $day) {
        return  floor($diff / $hour) . " hours ago";
    }
    if ($diff > $day && $diff < $day * 2) {
        return "yesterday";
    }
    if ($diff < $day * 365) {
        return floor($diff / $day) . " days ago";
    }
    else {
        return "over a year ago";
    }
}

/**
  * parse tweet text and add in links/tags/mentions
  * @param {string} twitter tweet plaintext retrieved from API
  * @return {string} html formatted tweet
  */
function parse_tweet($text){
    //links
    $text = preg_replace(
            '@(https?://([-\w\.]+)+(/([\w/_\.]*(\?\S+)?(#\S+)?)?)?)@',
             '<a href="$1">$1</a>',
            $text);

    //users
    $text = preg_replace(
            '/@(\w+)/',
            '<a href="http://twitter.com/$1">@$1</a>',
            $text);

    //hashtags
    $text = preg_replace(
            '/\s+#(\w+)/',
            ' <a href="http://search.twitter.com/search?q=%23$1">#$1</a>',
            $text);

    return $text;
}

?>
What plugin is this ?
Between you can use the javascript from twitter to add twitter feed.
(2018-10-12, 12:47 PM)WallBB Wrote: [ -> ]What plugin is this ?
Between you can use the javascript from twitter to add twitter feed.

It won't work as this plugin if added via javascript, plus javascript is browser-based hence no content when someone toggles it off.

Plugin page: https://community.mybb.com/mods.php?action=view&pid=604
(2018-10-12, 12:47 PM)WallBB Wrote: [ -> ]What plugin is this ?
Between you can use the javascript from twitter to add twitter feed.

'MYBB Twitter Feed Extension' is the name of the plugin.
bumpzor. Hopefully, some PHP nerd can look into this Big Grin

It's probably something around the line which is making it incompatible with php 7.1, 7.2

// get tweets
  $data_context = stream_context_create( array( 'http' => array( 'header' => 'Authorization: Bearer '.$auth_token."\r\n", ) ) );
  $otherspecs = '&exclude_replies=true&trim_user=true';

    // Suppressing warning (not great, but handled later)
    return @file_get_contents($data_url.'?count='.$data_count.'&screen_name='.urlencode($data_username).$otherspecs, 0, $data_context);
}