My favorites | Sign in
Project Home Downloads Wiki Issues Source
Checkout   Browse   Changes    
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
<?php
/**
* Zeitgeist Application Framework
* http://www.zeitgeist-framework.com
*
* Facebook Userhandler class
*
* WORK IN PROGRESS!!
*
* @author Dirk Songür <dirk@zeitalter3.de>
* @license MIT License <http://creativecommons.org/licenses/MIT/>
*
* @package ZEITGEIST
* @subpackage ZEITGEIST FACEBOOK
*/

defined( 'ZEITGEIST_ACTIVE' ) or die();

require_once ( ZEITGEIST_ROOTDIRECTORY . 'modules/facebook/facebook-platform/facebook.php' );

/**
* NOTE: This class is a singleton.
* Other classes or files may initialize it with zgFacebookUserhandler::init();
* Extends the core zgUserhandler
*/
class zgFacebookUserhandler extends zgUserhandler
{
private static $instance = false;
protected $debug;
protected $messages;
protected $session;
protected $database;
protected $configuration;
public $facebook;
protected $loggedIn;


/**
* Class constructor
*
* The constructor is set to private to prevent files from calling the class as a class instead of a singleton.
*/
protected function __construct()
{
$this->debug = zgDebug::init();
$this->messages = zgMessages::init();
$this->configuration = zgConfiguration::init();

$this->session = zgSession::init();
$this->session->startSession();

$this->facebook = NULL;

$this->database = new zgDatabasePDO( "mysql:host=" . ZG_DB_DBSERVER . ";dbname=" . ZG_DB_DATABASE, ZG_DB_USERNAME, ZG_DB_USERPASS );
$this->database->query( "SET NAMES 'utf8'" );
$this->database->query( "SET CHARACTER SET utf8" );

parent::__construct();

if ( file_exists( ZEITGEIST_ROOTDIRECTORY . 'configuration/zgfacebook.ini' ) )
{
$this->configuration->loadConfiguration( 'facebook', ZEITGEIST_ROOTDIRECTORY . 'configuration/zgfacebook.ini' );
}

if ( file_exists( APPLICATION_ROOTDIRECTORY . 'configuration/zgfacebook.ini' ) )
{
$this->configuration->loadConfiguration( 'facebook', APPLICATION_ROOTDIRECTORY . 'configuration/zgfacebook.ini', true );
}

// initialize facebook api
// you already need the correct app information for this
$facebookConnectParameters = array();
$facebookConnectParameters[ 'appId' ] = $this->configuration->getConfiguration( 'facebook', 'api', 'app_id' );
$facebookConnectParameters[ 'secret' ] = $this->configuration->getConfiguration( 'facebook', 'api', 'app_secret' );
$this->facebook = new Facebook( $facebookConnectParameters );
}


/**
* Initialize the singleton
*
* @return zgFacebookUserhandler
*/
public static function init()
{
if ( self::$instance === false )
{
self::$instance = new zgFacebookUserhandler();
}

return self::$instance;
}


/**
* Tries to establish a login for a user from the session data
* Only works if the user was correctly logged in while the current session is active
*
* @return boolean
*/
public function establishUserSession()
{
$this->debug->guard();

// check if the session handling works
if ( !$this->session->getSessionId() )
{
$this->debug->write( 'Could not establish user session: could not find a session id', 'warning' );
$this->messages->setMessage( 'Could not establish user session: could not find a session id', 'warning' );

$this->debug->unguard( false );
return false;
}

// check if the user is already logged into facebook
// this only means that the user has registered the app, is logged into facebook and has a session
// it does not mean that the user is known to the apps user system
$fbid = $this->facebook->getUser();
if ( empty( $fbid ) )
{
$this->debug->write( 'Could not establish user session: facebook session not initialized', 'warning' );
$this->messages->setMessage( 'Could not establish user session: facebook session not initialized', 'warning' );

$this->debug->unguard( false );
return false;
}

// check if the users facebook id can be linked to a user account
if ( !$this->validateFacebookUser( $fbid ) )
{
$this->debug->write( 'Could not establish user session: facebook user can not be linked to a local user', 'warning' );
$this->messages->setMessage( 'Could not establish user session: facebook user can not be linked to a local user', 'warning' );

$this->debug->unguard( false );
return false;
}

$this->loggedIn = true;

$this->debug->unguard( $this->loggedIn );
return $this->loggedIn;
}


/**
* Checks if a facebook user is already known as a local user
* If not, the user will be created and the account linked to the facebook id
*
* @param integer $fbid facebook id of the user
*
* @return boolean
*/
public function validateFacebookUser( $fbid )
{
$this->debug->guard();

// check if the user has its facebook data already in the session
$fbSessionId = $this->session->getSessionVariable( 'user_facebookid' );
if ( !empty( $fbSessionId ) )
{
$this->debug->unguard( true );
return true;
}

// check if the facebook user is already known in the system
// if so, fill the session vars and create the user
$userInformation = $this->_getUserInformationFromFacebookId( $fbid );
if ( is_array( $userInformation ) )
{
$this->session->setSessionVariable( 'user_facebookid', $fbid );
$this->session->setSessionVariable( 'user_id', $userInformation [ 'user_id' ] );
$this->session->setSessionVariable( 'user_key', $userInformation [ 'user_key' ] );
$this->session->setSessionVariable( 'user_username', $userInformation [ 'user_username' ] );

$this->debug->unguard( true );
return true;
}

// seems like the user is logged in but not known to the system yet
// first create a new user based on the facebook data
$userid = $this->createUser( $fbid );
if ( !$userid )
{
$this->debug->write( 'Problem validating the user: could not create the user for the facebook account', 'warning' );
$this->messages->setMessage( 'Problem validating the user: could not create the user for the facebook account', 'warning' );

$this->debug->unguard( false );
return false;
}

// now the user should exist in the system
// if so, fill the session vars and create the user
$userInformation = $this->_getUserInformationFromFacebookId( $fbid );
if ( is_array( $userInformation ) )
{
$this->session->setSessionVariable( 'user_facebookid', $fbid );
$this->session->setSessionVariable( 'user_id', $userInformation [ 'user_id' ] );
$this->session->setSessionVariable( 'user_key', $userInformation [ 'user_key' ] );
$this->session->setSessionVariable( 'user_username', $userInformation [ 'user_username' ] );

$this->debug->unguard( true );
return true;
}

$this->debug->unguard( false );
return false;
}


/**
* Login a user with username and password
* If successfull it will gather the user specific data and tie it to the session
*
* @param string $username not needed
* @param string $password not needed
*
* @return boolean
*/
public function login( $username = '', $password = '' )
{
$this->debug->guard();

// check if the user is already known and logged in
if ( $this->loggedIn )
{
$this->debug->write( 'Problem logging in a user: user is already logged in. Cannot login user twice', 'warning' );
$this->messages->setMessage( 'Problem logging in a user: user is already logged in. Cannot login user twice', 'warning' );

$this->debug->unguard( false );
return false;
}

// call the facebook login and auth method
$fbid = $this->facebook->getUser();
if ( !empty( $fbid ) )
{
$this->debug->write( 'Problem logging in a user: user already has a facebook session', 'warning' );
$this->messages->setMessage( 'Problem logging in a user: user already has a facebook session', 'warning' );

$this->debug->unguard( false );
return false;
}

$tpl = new zgTemplate();
$tpl->redirect( $this->facebook->getLoginUrl() );
$this->debug->write( 'User login: redirecting to Facebook for authentication', 'message' );
$this->messages->setMessage( 'User login: redirecting to Facebook for authentication', 'message' );

$this->debug->unguard( true );
return true;
}


/**
* Log out the user if he is currently logged in
*
* @return boolean
*/
public function logout()
{
$this->debug->guard();

if ( $this->loggedIn )
{
$this->session->unsetAllSessionVariables();
$this->session->stopSession();
$this->loggedIn = false;

$tpl = new zgTemplate();
$tpl->redirect( $this->facebook->getLogoutUrl() );
$this->debug->write( 'User logout: redirecting to Facebook for logout', 'message' );
$this->messages->setMessage( 'User logout: redirecting to Facebook for logout', 'message' );
}
else
{
$this->debug->write( 'Problem logging out user: user is not logged in', 'warning' );
$this->messages->setMessage( 'Problem logging out user: user is not logged in', 'warning' );

$this->debug->unguard( false );
return false;
}

$this->session->stopSession();
$this->loggedIn = false;

$this->debug->unguard( true );
return true;
}


/**
* Create a user from its facebook profile
*
* @param integer $fbid facebook id to create user from
*
* @return boolean
*/
public function createUser( $fbid )
{
$this->debug->guard();

// begin transaction as we have multiple inserts depending on each other
if ( !$this->database->beginTransaction() )
{
$this->debug->write( 'Problem creating the user: could no begin database transaction', 'warning' );
$this->messages->setMessage( 'Problem creating the user: could no begin database transaction', 'warning' );

$this->debug->unguard( false );
return false;
}

// see if user already exists in database
$sql = $this->database->prepare( "SELECT * FROM " . $this->configuration->getConfiguration( 'facebook', 'tables', 'table_facebookusers' ) . " WHERE facebookuser_fbid = ?" );
$sql->bindParam( 1, $fbid );

if ( !$sql->execute() )
{
$this->debug->write( 'Problem creating the user: could not access the user table', 'warning' );
$this->messages->setMessage( 'Problem creating the user: could not access the user table', 'warning' );

$this->database->rollBack();
$this->debug->unguard( false );
return false;
}

if ( $sql->rowCount() > 0 )
{
$this->debug->write( 'Problem creating the user: a user with this facebook id already exists in the database', 'warning' );
$this->messages->setMessage( 'Problem creating the user: a user with this facebook id already exists in the database', 'warning' );

$this->database->rollBack();
$this->debug->unguard( false );
return false;
}

// get userdata from facebook
$fbuserdata = $this->facebook->api( '/me' );
if ( !is_array( $fbuserdata ) )
{
$this->debug->write( 'Problem creating the user: could not get user data for user', 'warning' );
$this->messages->setMessage( 'Problem creating the user: could not get user data for user', 'warning' );

$this->database->rollBack();
$this->debug->unguard( false );
return false;
}

// insert a new user into database
$active = 1;
$key = md5( uniqid( md5( mt_rand() ), true ) );
$fbusername = $fbuserdata [ 'name' ];

$sql = $this->database->prepare( "INSERT INTO " . $this->configuration->getConfiguration( 'zeitgeist', 'tables', 'table_users' ) . "(user_username, user_key, user_password, user_active) VALUES(?, ?, ?, ?)" );
$sql->bindParam( 1, $fbusername );
$sql->bindParam( 2, $key );
$sql->bindParam( 3, $key );
$sql->bindParam( 4, $active );

if ( !$sql->execute() )
{
$this->debug->write( 'Problem creating the user: could not insert the user into the database', 'warning' );
$this->messages->setMessage( 'Problem creating the user: could not insert the user into the database', 'warning' );

$this->database->rollBack();
$this->debug->unguard( false );
return false;
}

// this is the id for the user that just has been created
$currentId = $this->database->lastInsertId();

// insert facebook user to link table
$sql = $this->database->prepare( "INSERT INTO " . $this->configuration->getConfiguration( 'facebook', 'tables', 'table_facebookusers' ) . "(facebookuser_fbid, facebookuser_user) VALUES(?, ?)" );
$sql->bindParam( 1, $fbid );
$sql->bindParam( 2, $currentId );

if ( !$sql->execute() )
{
$this->debug->write( 'Problem creating the user: could not connect the user data to the facebook data', 'warning' );
$this->messages->setMessage( 'Problem creating the user: could not connect the user data to the facebook data', 'warning' );

$this->database->rollBack();
$this->debug->unguard( false );
return false;
}

// commit inserts into database
$this->database->commit();

$this->debug->unguard( $currentId );
return $currentId;
}


/**
* Gets user information from a facebook id
*
* @param integer $fbid facebook id of the user
*
* @return integer
*/
private function _getUserInformationFromFacebookId( $fbid )
{
$this->debug->guard();

// get userinformation from database
$sqlquery = "SELECT u.user_id, u.user_key, u.user_username FROM " . $this->configuration->getConfiguration( 'facebook', 'tables', 'table_facebookusers' ) . " fb ";
$sqlquery .= "LEFT JOIN " . $this->configuration->getConfiguration( 'zeitgeist', 'tables', 'table_users' ) . " u ON fb.facebookuser_user = u.user_id ";
$sqlquery .= "WHERE fb.facebookuser_fbid = ? AND u.user_active='1'";
$sql = $this->database->prepare( $sqlquery );
$sql->bindParam( 1, $fbid );

if ( !$sql->execute() )
{
$this->debug->write( 'Problem getting facebook user information: could not read the user table', 'warning' );
$this->messages->setMessage( 'Problem getting facebook user information: could not read the user table', 'warning' );

$this->debug->unguard( false );
return false;
}

if ( $sql->rowCount() != 1 )
{
$this->debug->write( 'Problem getting facebook user information: no linked user exists for this facebook id', 'warning' );
$this->messages->setMessage( 'Problem getting facebook user information: no linked user exists for this facebook id', 'warning' );

$this->debug->unguard( false );
return false;
}

$ret = $sql->fetch( PDO::FETCH_ASSOC );

$this->debug->unguard( $ret );
return $ret;
}


/**
* Gets the current facebook id for a user
*
* @return integer
*/
public function getFacebookUserID()
{
$this->debug->guard();

$fbid = $this->facebook->getUser();
if ( empty( $fbid ) )
{
$this->debug->write( 'Could not get facebook user id: facebook session not initialized', 'warning' );
$this->messages->setMessage( 'Could not get facebook user id: facebook session not initialized', 'warning' );

$this->debug->unguard( false );
return false;
}

$this->debug->unguard( $fbid );
return $fbid;
}
}

?>

Change log

r839 by d...@songuer.de on Oct 15, 2011   Diff
ZGFB: New Facebook API version, much
simpler OAuth handling
Go to: 
Project members, sign in to write a code review

Older revisions

r827 by DirkSonguer on May 3, 2011   Diff
ZG: Fixed some minor issues that
caused warnings in php strict mode
r819 by d...@songuer.de on Feb 24, 2011   Diff
ZG: Bugfixes and code cleanups for
modules. Unit tests still run but you
may want to be careful to roll this
version out untested
r817 by d...@songuer.de on Feb 24, 2011   Diff
ZG: Added database transactions for
insets with dependencies
All revisions of this file

File info

Size: 15216 bytes, 462 lines
Powered by Google Project Hosting