586 lines
16 KiB
PHP
586 lines
16 KiB
PHP
<?php
|
|
/**
|
|
* Invision Power Services
|
|
* IP.Board v3.0.5
|
|
* Facebook Connect Library
|
|
* Created by Matt M
|
|
* Last Updated: $Date: 2009-01-05 22:21:54 +0000 (Mon, 05 Jan 2009) $
|
|
*
|
|
* @author $Author: bfarber $
|
|
* @copyright (c) 2001 - 2009 Invision Power Services, Inc.
|
|
* @license http://www.iinvisionpower.com/community/board/license.html
|
|
* @package Invision Power Board
|
|
* @link http://www.iinvisionpower.com
|
|
* @version $Rev: 3572 $
|
|
*
|
|
*/
|
|
|
|
class facebook_connect
|
|
{
|
|
/**#@+
|
|
* Registry Object Shortcuts
|
|
*
|
|
* @access protected
|
|
* @var object
|
|
*/
|
|
protected $DB;
|
|
protected $settings;
|
|
protected $lang;
|
|
protected $member;
|
|
protected $memberData;
|
|
protected $cache;
|
|
protected $caches;
|
|
/**#@-*/
|
|
|
|
/**
|
|
* IPBs log in handler
|
|
*
|
|
* @access private
|
|
* @var object
|
|
*/
|
|
private $_login;
|
|
|
|
/**
|
|
* Facebooks class wrapper
|
|
*
|
|
* @access private
|
|
* @var object
|
|
*/
|
|
private $_fb;
|
|
|
|
/**
|
|
* Facebooks REST API wrapper
|
|
*
|
|
* @access private
|
|
* @var object
|
|
*/
|
|
private $_api;
|
|
|
|
/**
|
|
* Construct.
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function __construct( $registry, $app_directory='' )
|
|
{
|
|
/* Make object */
|
|
$this->registry = $registry;
|
|
$this->DB = $this->registry->DB();
|
|
$this->settings =& $this->registry->fetchSettings();
|
|
$this->request =& $this->registry->fetchRequest();
|
|
$this->lang = $this->registry->getClass('class_localization');
|
|
$this->member = $this->registry->member();
|
|
$this->memberData =& $this->registry->member()->fetchMemberData();
|
|
$this->cache = $this->registry->cache();
|
|
$this->caches =& $this->registry->cache()->fetchCaches();
|
|
|
|
/* Test */
|
|
if ( IPSLib::fbc_enabled() !== TRUE )
|
|
{
|
|
throw new Exception( 'FACEBOOK_DISABLED_OR_NOT_SET_UP' );
|
|
}
|
|
|
|
/* Load and set up the facebook stuff */
|
|
require_once( IPS_KERNEL_PATH . 'facebook-client/facebook.php' );
|
|
$this->_fb = new Facebook( $this->settings['fbc_api_id'], $this->settings['fbc_secret'], true );
|
|
$this->_api = $this->_fb->api_client;
|
|
}
|
|
|
|
/**
|
|
* Accessor for the facebook functions
|
|
*
|
|
* @access public
|
|
* @return object
|
|
*/
|
|
public function FB()
|
|
{
|
|
return $this->_fb;
|
|
}
|
|
|
|
/**
|
|
* Accessor for the facebook REST API functions
|
|
*
|
|
* @access public
|
|
* @return object
|
|
*/
|
|
public function API()
|
|
{
|
|
return $this->_api;
|
|
}
|
|
|
|
/**
|
|
* Function to resync a member's FB data
|
|
*
|
|
* @access public
|
|
* @param mixed Member Data in an array form (result of IPSMember::load( $id, 'all' ) ) or a member ID
|
|
* @return array Updated member data
|
|
*
|
|
* EXCEPTION CODES:
|
|
* NO_MEMBER Member ID does not exist
|
|
* NOT_LINKED Member ID or data specified is not linked to a FB profile
|
|
*/
|
|
public function syncMember( $memberData )
|
|
{
|
|
//-----------------------------------------
|
|
// INIT
|
|
//-----------------------------------------
|
|
|
|
$exProfile = array();
|
|
|
|
/* Do we need to load a member? */
|
|
if ( ! is_array( $memberData ) )
|
|
{
|
|
$memberData = IPSMember::load( intval( $memberData ), 'all' );
|
|
}
|
|
|
|
/* Got a member? */
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( 'NO_MEMBER' );
|
|
}
|
|
|
|
/* Linked account? */
|
|
if ( ! $memberData['fb_uid'] )
|
|
{
|
|
throw new Exception( 'NOT_LINKED' );
|
|
}
|
|
|
|
/* Thaw Options */
|
|
$bwOptions = IPSBWOptions::thaw( $memberData['fb_bwoptions'], 'facebook' );
|
|
|
|
/* Grab the data */
|
|
try
|
|
{
|
|
$_fbData = $this->API()->users_getInfo( $memberData['fb_uid'], array( 'first_name', 'last_name', 'name', 'status', 'pic', 'pic_square', 'pic_square_with_logo', 'about_me', 'email_hashes' ) );
|
|
$fbData = $_fbData[0];
|
|
|
|
/* Format data */
|
|
$emailHash = ( is_array( $fbData['email_hashes'] ) AND $fbData['email_hashes'][0] ) ? $fbData['email_hashes'][0] : $memberData['fb_emailhash'];
|
|
|
|
/* Update.. */
|
|
$exProfile['fb_photo'] = ( $bwOptions['fbc_s_pic'] ) ? $fbData['pic'] : '';
|
|
$exProfile['fb_photo_thumb'] = ( $bwOptions['fbc_s_pic'] ) ? ( strstr( $memberData['email'], '@proxymail.facebook.com' ) ? $fbData['pic_square_with_logo'] : $fbData['pic_square'] ) : '';
|
|
|
|
if ( $bwOptions['fbc_s_avatar'] )
|
|
{
|
|
$exProfile['avatar_location'] = $fbData['pic_square'];
|
|
$exProfile['avatar_type'] = 'facebook';
|
|
}
|
|
|
|
if ( $bwOptions['fbc_s_aboutme'] )
|
|
{
|
|
$exProfile['pp_about_me'] = IPSText::getTextClass( 'bbcode' )->stripBadWords( IPSText::convertCharsets( $fbData['about_me'], 'utf-8', IPS_DOC_CHAR_SET ) );
|
|
}
|
|
|
|
if ( $bwOptions['fbc_s_status'] AND is_array($fbData['status']) AND $fbData['status']['message'] )
|
|
{
|
|
$exProfile['pp_status'] = IPSText::getTextClass( 'bbcode' )->stripBadWords( IPSText::convertCharsets( $fbData['status']['message'], 'utf-8', IPS_DOC_CHAR_SET ) );
|
|
$exProfile['pp_status_update'] = $fbData['status']['time'];
|
|
}
|
|
|
|
/* Update member */
|
|
IPSMember::save( $memberData['member_id'], array( 'core' => array( 'fb_emailhash' => $emailHash, 'fb_lastsync' => time() ),
|
|
'extendedProfile' => $exProfile ) );
|
|
|
|
/* merge and return */
|
|
$memberData['fb_lastsync'] = time();
|
|
$memberData = array_merge( $memberData, $exProfile );
|
|
}
|
|
catch( Exception $e )
|
|
{
|
|
}
|
|
|
|
return $memberData;
|
|
}
|
|
|
|
/**
|
|
* Link to IPB account
|
|
*
|
|
* @access public
|
|
* @param int Member ID
|
|
* @return boolean
|
|
*
|
|
* EXCEPTION CODES:
|
|
* NO_FACEBOOK_USER_LOGGED_IN System cannot detect a logged in facebook user
|
|
* ALREADY_LINKED Auth member is already linked to a different FB account
|
|
*/
|
|
public function linkMember( $memberID )
|
|
{
|
|
$loggedInUser = $this->FB()->get_loggedin_user();
|
|
|
|
if ( ! $loggedInUser )
|
|
{
|
|
throw new Exception( 'NO_FACEBOOK_USER_LOGGED_IN' );
|
|
}
|
|
|
|
$memberData = IPSMember::load( $memberID, 'all' );
|
|
|
|
/* Already FBd? */
|
|
if ( $memberData['fb_uid'] AND ( $memberData['fb_uid'] != $loggedInUser ) )
|
|
{
|
|
throw new Exception( 'ALREADY_LINKED' );
|
|
}
|
|
|
|
/* Ensure that there is not already a linked account */
|
|
$_member = IPSMember::load( $loggedInUser, 'all', 'fb_uid' );
|
|
|
|
if ( $_member['fb_uid'] AND ( $_member['member_id'] != $memberID ) )
|
|
{
|
|
throw new Exception( 'ALREADY_LINKED' );
|
|
}
|
|
|
|
/* Associate this account with FBC */
|
|
$hash = $this->generateEmailhash( $memberData['email'] );
|
|
|
|
/* Update... */
|
|
IPSMember::save( $memberData['member_id'], array( 'core' => array( 'fb_uid' => $loggedInUser, 'fb_emailhash' => $hash ) ) );
|
|
|
|
/* Register with Facebook */
|
|
try
|
|
{
|
|
$reg = $this->API()->connect_registerUsers( json_encode( array( array( 'email_hash' => $hash, 'account_id' => $memberData['member_id'] ) ) ) );
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
//print $error->getMessage(); exit();
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Log in and create a brand new forum account
|
|
*
|
|
* @access public
|
|
* @return mixed On success, an array containing a message and redirect URL
|
|
*
|
|
* EXCEPTION CODES:
|
|
* NO_FACEBOOK_USER_LOGGED_IN System cannot detect a logged in facebook user
|
|
* NO_FB_EMAIL Could not locate a facebook proxy email
|
|
* CREATION_FAIL Account creation failed
|
|
* ALREADY_LINKED_MEMBER The facebook UID is already linked to another IPB account
|
|
*/
|
|
public function loginWithNewAccount()
|
|
{
|
|
$loggedInUser = $this->FB()->get_loggedin_user();
|
|
|
|
if ( ! $loggedInUser )
|
|
{
|
|
throw new Exception( 'NO_FACEBOOK_USER_LOGGED_IN' );
|
|
}
|
|
|
|
/* Ensure that there is not already a linked account */
|
|
/* Now get the linked user */
|
|
$_member = IPSMember::load( $loggedInUser, 'all', 'fb_uid' );
|
|
|
|
if ( $_member['member_id'] )
|
|
{
|
|
throw new Exception( 'ALREADY_LINKED_MEMBER' );
|
|
}
|
|
|
|
/* Now fetch more data */
|
|
$_fbData = $this->API()->users_getInfo( $loggedInUser, array( 'name', 'proxied_email', 'timezone', 'pic', 'pic_square', 'pic_square_with_logo', 'about_me' ) );
|
|
$fbData = $_fbData[0];
|
|
|
|
if ( ! $fbData['proxied_email'] )
|
|
{
|
|
throw new Exception( 'NO_FB_EMAIL' );
|
|
}
|
|
|
|
/* Generate BW options */
|
|
foreach( array( 'fbc_s_pic', 'fbc_s_avatar', 'fbc_s_status', 'fbc_s_aboutme' ) as $field )
|
|
{
|
|
$toSave[ $field ] = 1;
|
|
}
|
|
|
|
$fb_bwoptions = IPSBWOptions::freeze( $toSave, 'facebook' );
|
|
|
|
/* Generate FB hash */
|
|
$hash = $this->generateEmailHash( $fbData['proxied_email'] );
|
|
|
|
/* Data to save */
|
|
$toSave = array( 'core' => array( 'name' => IPSText::convertCharsets( $fbData['name'], 'utf-8', IPS_DOC_CHAR_SET ),
|
|
'members_display_name' => IPSText::convertCharsets( $fbData['name'], 'utf-8', IPS_DOC_CHAR_SET ),
|
|
'members_created_remote' => 1,
|
|
'member_group_id' => ( $this->settings['fbc_mgid'] ) ? $this->settings['fbc_mgid'] : $this->settings['member_group'],
|
|
'email' => $fbData['proxied_email'],
|
|
'time_offset' => $fbData['timezone'],
|
|
'fb_uid' => $loggedInUser,
|
|
'fb_emailhash' => $hash ),
|
|
'extendedProfile' => array( 'pp_about_me' => IPSText::getTextClass( 'bbcode' )->stripBadWords( IPSText::convertCharsets( $fbData['about_me'], 'utf-8', IPS_DOC_CHAR_SET ) ),
|
|
'fb_photo' => $fbData['pic'],
|
|
'fb_photo_thumb' => $fbData['pic_square_with_logo'],
|
|
'fb_bwoptions' => $fb_bwoptions,
|
|
'avatar_location' => $fbData['pic_square'],
|
|
'avatar_type' => 'facebook' ) );
|
|
|
|
/* Ensure we don't already have a partially created FB member */
|
|
$testMember = IPSMember::load( $toSave['core']['email'], 'core' );
|
|
|
|
if ( $testMember['member_id'] )
|
|
{
|
|
IPSMember::save( $testMember['member_id'], $toSave );
|
|
$memberData = array_merge( $testMember, $toSave );
|
|
}
|
|
else
|
|
{
|
|
$memberData = IPSMember::create( $toSave, TRUE );
|
|
}
|
|
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( 'CREATION_FAIL' );
|
|
}
|
|
|
|
/* Register with Facebook */
|
|
try
|
|
{
|
|
$reg = $this->API()->connect_registerUsers( json_encode( array( array( 'email_hash' => $hash, 'account_id' => $memberData['member_id'] ) ) ) );
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
//print $error->getMessage(); exit();
|
|
}
|
|
|
|
//-----------------------------------------
|
|
// Update Stats
|
|
//-----------------------------------------
|
|
|
|
$cache = $this->cache->getCache('stats');
|
|
|
|
if( $memberData['members_display_name'] AND $memberData['member_id'] )
|
|
{
|
|
$cache['last_mem_name'] = $memberData['members_display_name'];
|
|
$cache['last_mem_id'] = $memberData['member_id'];
|
|
}
|
|
|
|
$cache['mem_count'] += 1;
|
|
|
|
$this->cache->setCache( 'stats', $cache, array( 'array' => 1 ) );
|
|
|
|
//-----------------------------------------
|
|
// New registration emails
|
|
//-----------------------------------------
|
|
|
|
if( $this->settings['new_reg_notify'] )
|
|
{
|
|
$this->lang->loadLanguageFile( array( 'public_register' ), 'core' );
|
|
|
|
$date = $this->registry->class_localization->getDate( time(), 'LONG', 1 );
|
|
|
|
IPSText::getTextClass('email')->getTemplate( 'admin_newuser' );
|
|
IPSText::getTextClass('email')->buildMessage( array( 'DATE' => $date,
|
|
'LOG_IN_NAME' => $memberData['name'],
|
|
'EMAIL' => $memberData['email'],
|
|
'IP' => $memberData['ip_address'],
|
|
'DISPLAY_NAME' => $memberData['members_display_name'] ) );
|
|
|
|
IPSText::getTextClass('email')->subject = $this->lang->words['new_registration_email1'] . $this->settings['board_name'];
|
|
IPSText::getTextClass('email')->to = $this->settings['email_in'];
|
|
IPSText::getTextClass('email')->sendMail();
|
|
}
|
|
|
|
/* Here, so log us in!! */
|
|
return $this->_login()->loginWithoutCheckingCredentials( $memberData['member_id'], TRUE );
|
|
}
|
|
|
|
/**
|
|
* Log in with an existing FB->IPB link
|
|
*
|
|
* @access public
|
|
* @return mixed On success, an array containing a message and redirect URL
|
|
*
|
|
* EXCEPTION CODES:
|
|
* NO_FACEBOOK_USER_LOGGED_IN System cannot detect a logged in facebook user
|
|
* NO_LINKED_MEMBER Could not locate a linked member
|
|
*/
|
|
public function loginWithExistingLink()
|
|
{
|
|
$loggedInUser = $this->FB()->get_loggedin_user();
|
|
|
|
if ( ! $loggedInUser )
|
|
{
|
|
throw new Exception( 'NO_FACEBOOK_USER_LOGGED_IN' );
|
|
}
|
|
|
|
/* Now get the linked user */
|
|
$memberData = IPSMember::load( $loggedInUser, 'all', 'fb_uid' );
|
|
|
|
if ( ! $memberData['member_id'] )
|
|
{
|
|
throw new Exception( 'NO_LINKED_MEMBER' );
|
|
}
|
|
|
|
/* Here, so log us in!! */
|
|
return $this->_login()->loginWithoutCheckingCredentials( $memberData['member_id'], TRUE );
|
|
}
|
|
|
|
/**
|
|
* Link to IPB account and log in
|
|
* Allows the user to link to an existing facebook account by passing a username and password
|
|
*
|
|
* @access public
|
|
* @param string Email address
|
|
* @param string Plain text password
|
|
* @return mixed On success, an array containing a message and redirect URL
|
|
*
|
|
* EXCEPTION CODES:
|
|
* NO_FACEBOOK_USER_LOGGED_IN System cannot detect a logged in facebook user
|
|
* AUTH_FAIL Email address or password incorrect
|
|
* ALREADY_LINKED Auth member is already linked to a different FB account
|
|
*/
|
|
public function loginWithCreateLink( $email, $password )
|
|
{
|
|
$loggedInUser = $this->FB()->get_loggedin_user();
|
|
|
|
if ( ! $loggedInUser )
|
|
{
|
|
throw new Exception( 'NO_FACEBOOK_USER_LOGGED_IN' );
|
|
}
|
|
|
|
/* Force email check */
|
|
$this->_login()->setForceEmailCheck( TRUE );
|
|
|
|
/* Now attempt to authorize member */
|
|
$return = $this->_login()->loginPasswordCheck( '', $email, $password );
|
|
|
|
if ( $return !== TRUE )
|
|
{
|
|
throw new Exception( 'AUTH_FAIL' );
|
|
}
|
|
else
|
|
{
|
|
$memberData = $this->_login()->member_data;
|
|
|
|
/* Already FBd? */
|
|
if ( $memberData['fb_uid'] AND ( $memberData['fb_uid'] != $loggedInUser ) )
|
|
{
|
|
throw new Exception( 'AUTH_FAIL' );
|
|
}
|
|
|
|
/* Un-force email check */
|
|
$this->_login()->setForceEmailCheck( FALSE );
|
|
|
|
/* Ok, now the easiest way to get them logged in is to do this.. .*/
|
|
$this->request['username'] = $memberData['name'];
|
|
$this->request['rememberMe'] = 1;
|
|
|
|
$result = $this->_login()->verifyLogin();
|
|
|
|
if ( $result[2] )
|
|
{
|
|
throw new Exception( 'AUTH_FAIL' );
|
|
}
|
|
else
|
|
{
|
|
/* Associate this account with FBC */
|
|
$hash = $this->generateEmailhash( $memberData['email'] );
|
|
|
|
/* Update... */
|
|
IPSMember::save( $memberData['member_id'], array( 'core' => array( 'fb_uid' => $loggedInUser, 'fb_emailhash' => $hash ) ) );
|
|
|
|
/* Register with Facebook */
|
|
try
|
|
{
|
|
$reg = $this->API()->connect_registerUsers( json_encode( array( array( 'email_hash' => $hash, 'account_id' => $memberData['member_id'] ) ) ) );
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
//print $error->getMessage(); exit();
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Facebook Connect Bug Fix: Test the API and delete cookies
|
|
* if we get a session error: http://bugs.developers.facebook.com/show_bug.cgi?id=3237
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function testConnectSession()
|
|
{
|
|
try
|
|
{
|
|
$loggedInUser = $this->API()->users_getLoggedInUser();
|
|
}
|
|
catch( Exception $error )
|
|
{
|
|
$msg = $error->getMessage();
|
|
|
|
$this->unsetCookies();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Unset cookies
|
|
*
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function unsetCookies()
|
|
{
|
|
foreach( array( '_user', '_session_key', '_expires', '_ss' ) as $key )
|
|
{
|
|
IPSCookie::set( $this->settings['fbc_api_id'] . $key, -1, 0, -1 );
|
|
unset( $_COOKIE[ $this->settings['fbc_api_id'] . $key ] );
|
|
}
|
|
|
|
IPSCookie::set( $this->settings['fbc_api_id'], -1, 0, -1 );
|
|
IPSCookie::set( 'fbsetting_' . $this->settings['fbc_api_id'], -1, 0, -1 );
|
|
}
|
|
|
|
/**
|
|
* Facebook: Generate Email Hash
|
|
*
|
|
* @access public
|
|
* @param string Email Address
|
|
* @return string Facebook Hash (crc32 _ md5 )
|
|
*/
|
|
static public function generateEmailhash( $email )
|
|
{
|
|
if ( $email != NULL )
|
|
{
|
|
$email = trim( strtolower( $email ) );
|
|
|
|
return sprintf( "%u", crc32( $email ) ) . '_' . md5( $email );
|
|
}
|
|
else
|
|
{
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns 1 if the user has the specified permission, 0 otherwise.
|
|
* http://wiki.developers.facebook.com/index.php/Users.hasAppPermission
|
|
*
|
|
* @return integer 1 or 0
|
|
*/
|
|
public function users_hasAppPermission($ext_perm, $uid=null)
|
|
{
|
|
return $this->_api->call_method('facebook.users.hasAppPermission', array('ext_perm' => $ext_perm, 'uid' => $uid) );
|
|
}
|
|
|
|
/**
|
|
* Accessor for the log in functions
|
|
*
|
|
* @access public
|
|
* @return object
|
|
*/
|
|
public function _login()
|
|
{
|
|
if ( ! is_object( $this->_login ) )
|
|
{
|
|
require_once( IPS_ROOT_PATH . 'sources/handlers/han_login.php' );
|
|
$this->_login = new han_login( $this->registry );
|
|
$this->_login->init();
|
|
}
|
|
|
|
return $this->_login;
|
|
}
|
|
} |