/[drupal]/contributions/sandbox/jamesandres/facebook_apps/facebook_apps.module
ViewVC logotype

Contents of /contributions/sandbox/jamesandres/facebook_apps/facebook_apps.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Tue Sep 18 00:01:01 2007 UTC (2 years, 2 months ago) by jamesandres
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +8 -1 lines
File MIME type: text/x-php
Small changes made by soconnor
1 <?php
2 /**
3 * @file facebook_apps.module
4 * A framework for handling the basic Drupal --> Facebook connections that
5 * are necessary when creating a Facebook application that has a Drupal
6 * back-end.
7 *
8 * Thanks! to Rob Barreca and ChipIn.com for supplying ideas and the basis for much
9 * of the authmap functionality.
10 *
11 * @author James Andres, with help from Rob Barreca and ChipIn.com
12 * @since August 1, 2007
13 **/
14
15 require_once('facebook_apps_helpers.inc');
16 require_once('facebook_apps_theme.inc');
17
18 /**
19 * Implementation of hook_menu().
20 */
21 function facebook_apps_menu($may_cache) {
22 // If necessary load the facebook user and theme.
23 _facebook_apps_theme_init();
24
25 return (array) $items;
26 }
27
28 /**
29 * Checks to see if the current path is a facebook path and handles the situation accordingly.
30 **/
31 function _facebook_apps_theme_init() {
32 global $_menu, $custom_theme, $fb_conf;
33
34 // Get the active menu item to see if it's a facebook menu item.
35 $mid = menu_get_active_item();
36 $item = $_menu['items'][$mid];
37
38 // Check if this was already set, don't repeat the process if hook_menu is
39 // called multiple times.
40 if (!$fb_conf) {
41 if ($item['fb_conf']) {
42 $fb_conf = $item['fb_conf'];
43 $fb_conf['app_url'] = 'http://apps.facebook.com/' . $fb_conf['canvas_path'];
44 $fb_conf['callback_url'] = _clean_url($fb_conf['callback_url']);
45 $custom_theme = 'facebook';
46 init_theme();
47
48 facebook_apps_login_both();
49 }
50 }
51 }
52
53 /**
54 * Implementation of hook_form_alter()
55 *
56 * This form_alter acts on all forms in the system. It's purpose is to make
57 * every form compatible with facebook.
58 **/
59 function facebook_apps_form_alter($form_id, &$form) {
60 global $fb_conf;
61
62 if ($fb_conf) {
63 $facebook =& facebook_get_facebook_object();
64
65 // Facebook doesn't appreciate it when we send 'Location: ..' headers.
66 $form['#redirect'] = FALSE;
67
68 $current_url = _clean_url($facebook->current_url());
69 // TODO: if $form['#action'] is set by the form creator, honour it.
70 if(!$fb_conf['no_canvas']) {
71 $form['#action'] = _fb_translate_url($current_url);
72 }
73 }
74 }
75
76 /**
77 * Implementation of hook_user()
78 *
79 * These are mostly helper data for the rest of this, and other, Facebook related modules.
80 **/
81 function facebook_apps_user($op, &$edit, &$account, $category = NULL) {
82 switch ($op) {
83 case 'load':
84 // Attach the facebook user ID to Facebook based users.
85 if ($fb_uid = facebook_apps_get_profile_id($account->uid)) {
86 $account->fb_uid = $fb_uid;
87 }
88 break;
89 }
90 }
91
92 // Log the user into Facebook and Drupal. Use this when you need a Drupal UID
93 // If present, user will be redirected to destination at end.
94 function facebook_apps_login_both($destination = NULL) {
95 global $user, $fb_conf;
96
97 // get the FB user if any
98 $facebook =& facebook_get_facebook_object();
99
100 // Added by soconnor - if Drupal session is dead and someone hits apps.facebook.com it would send
101 // the user to the 'add app' page instead of the log-in page.
102 $user = $facebook->require_login();
103
104 if (!$fb_conf['no_canvas']) {
105 $facebook->require_frame();
106 $facebook->require_add();
107 $fbuser = $facebook->get_loggedin_user();
108 } else {
109 // FIXME: This is really really dirty ... I don't like it one bit.
110 facebook_session_reload($facebook->api_key);
111 }
112
113 if ($fbuser) {
114 facebook_session_reload($facebook->api_key);
115
116 // successfully logged into FB
117 // if we are in bootstrap, load user.module ourselves
118 if (!module_exists('user')) {
119 drupal_load('module', 'user');
120 }
121
122 // try to log into Drupal. if unsuccessful, register the user
123 $test_user = user_external_load($fbuser);
124 if (!$test_user->uid) {
125 if (variable_get("user_register", 1) == 1) {
126 // i think the API call below could be done with nicer syntax
127 $return = $facebook->api_client->users_getInfo(array($fbuser), array('name'));
128 // validate the name before registering with it
129 $name = facebook_apps_name_check($return[0]['name'], $fbuser);
130
131 // TODO: add timezone and any other fields which we want in Drupal. Wish we could get email.
132 $user_default = array("name" => $name, "pass" => user_password(20), "init" => $fbuser, "authname_facebook" => $fbuser, "status" => 1);
133
134 // Bootstrap full so our ChipIn hook_user('insert') code runs and anything else.
135 // TODO: Is this undesired to do a full bootstrap here? If so, we can hardcode.
136 // drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
137 $user = user_save("", $user_default);
138 watchdog("user", t('New user: %name (Facebook)', array('%name' => $user->name)), l(t("edit user"), "admin/user/edit/$user->uid"));
139
140 // Force a rebuild of the menu so new users don't get access denied on first hit.
141 global $_menu;
142 unset($_menu['items']);
143 }
144 }
145 else{
146 // log the user into an existing drupal account
147 $user = $test_user;
148 }
149 // Save facebook session key and user for AJAX connects
150 $_SESSION['facebook_session_key'] = $facebook->api_client->session_key;
151 $_SESSION['facebook_user'] = $fbuser;
152
153 // Save session key for mini-feed operations when user isn't logged in.
154 facebook_apps_save_session_key($facebook);
155
156 // TODO: Try something this later for Safari maybe.
157 // user_login_submit('', array('name' => $user->name));
158
159 if ($destination) {
160 drupal_goto($destination);
161 }
162 else {
163 return $facebook;
164 }
165 }
166 else {
167 // do nothing. user isn't logged into FB. we shouldn't get here
168 }
169 }
170
171 /**
172 * Reload the session from the FB session key.
173 *
174 * See the Facebook Developers wiki: http://wiki.developers.facebook.com/index.php/PHP_Sessions
175 **/
176 function facebook_session_reload($api_key) {
177 $prefix = ($_REQUEST['fb_sig_user']) ? 'fb_sig' : $api_key;
178 $id = $_REQUEST[$prefix . '_session_key'];
179
180 if($id) {
181 $name = 'PHPSESS' . md5($id);
182 session_id($id);
183 session_name($name);
184
185 // Need to set up a false cookie to trick the Drupal session handler, see the sess_read() function.
186 $_COOKIE[session_name()] = TRUE;
187
188 // Now, force restore the session to the previous state.
189 session_start($id);
190
191 // FIXME: This seems very hackish, there has got to be a better way!
192 session_decode(sess_read($id));
193
194 // Set a bunch of facebook data to the session.
195 $_SESSION['fb_user'] = $_REQUEST[$prefix . '_user'];
196 $_SESSION['fb_session_key'] = $_REQUEST[$prefix . '_session_key'];
197 $_SESSION['fb_expires'] = $_REQUEST[$prefix . '_expires'];
198 $_SESSION['fb_in_canvas'] = $_REQUEST[$prefix . '_in_canvas'];
199 $_SESSION['fb_time'] = $_REQUEST[$prefix . '_time'];
200 $_SESSION['fb_profile_update_time'] = $_REQUEST[$prefix . '_profile_update_time'];
201 $_SESSION['fb_api_key'] = $_REQUEST[$prefix . '_api_key'];
202 } else {
203 // Just so there *is* a session for times when there is no fb session
204 session_start();
205 }
206 }
207
208 /**
209 * If this Drupal user has an infinite Facebook session key, store it for
210 * use when we want to post to this user's mini-feed later on when he or
211 * she isn't logged in.
212 *
213 * If the user removes our app, this key will throw a "Session key invalid"
214 * error, so this isn't the golden ticket.
215 */
216 function facebook_apps_save_session_key($facebook) {
217 global $user;
218 if (isset($facebook->fb_params['expires']) && $facebook->fb_params['expires'] == 0 && !empty($user->uid)) {
219 db_query("INSERT INTO {facebook_user_info} (uid, session_key) VALUES (%d, '%s')
220 ON DUPLICATE KEY UPDATE session_key = '%s'", $user->uid, $facebook->api_client->session_key, $facebook->api_client->session_key);
221 return TRUE;
222 }
223 return FALSE;
224 }
225
226 function facebook_apps_get_session_key($uid = NULL) {
227 if (!isset($uid)) {
228 global $user;
229 $uid = $user->uid;
230 }
231 $result = db_result(db_query('SELECT session_key FROM {facebook_user_info} WHERE uid = %d', $uid));
232 return $result;
233 }
234
235 // TODO: smarter alternate name if needed.
236 // return a valid username. checks for availability and validity of passed in name.
237 function facebook_apps_name_check($name, $fbuser) {
238 // availability check
239 $sql = "SELECT name FROM {users} WHERE name = '%s'";
240 if (!db_num_rows(db_query($sql, $name))) {
241 // validity check
242 if (!user_validate_name($name)) {
243 return $name;
244 }
245 }
246
247 // failed on of our checks. just use numeric ID until some other alogrithm is made
248 return $fbuser;
249 }
250
251 /**
252 * API function; gets Facebook user's profile pic.
253 *
254 * @param $drupal_user_id
255 * The desired user's Drupal UID.
256 * @param $size
257 * Can be pic, pic_big, pic_small, or pic_square.
258 *
259 * @return
260 * The URL of the desired user's picture or FALSE on error.
261 */
262 function facebook_apps_get_profile_pic($drupal_user_id, $size = 'pic_small') {
263 $cid = 'facebook_profile_pic_url:' . $drupal_user_id;
264
265 if ($cached = cache_get($cid, 'cache')) {
266 $pics = unserialize($cached->data);
267 return $pics[$size];
268 }
269
270 $facebook_user_id = db_result(db_query("SELECT authname FROM {authmap} WHERE uid = %d AND module = 'facebook'", $drupal_user_id));
271 if (!$facebook_user_id) {
272 return FALSE;
273 }
274
275 $facebook =& facebook_get_facebook_object();
276 $sizes = array('pic', 'pic_big', 'pic_small', 'pic_square');
277 try {
278 if ($pics = $facebook->api_client->users_getInfo(array($facebook_user_id), $sizes)) {
279 cache_set($cid, 'cache', serialize($pics[0]), time() + (1 * 5));
280 return $pics[0][$size];
281 }
282 } catch (FacebookRestClientException $fb_e) {
283 watchdog('Facebook', t('Exception thrown when getting Facebook profile picture for user @uid: %msg.', array('@uid' => $drupal_user_id, '%msg' => $fb_e->getMessage())), WATCHDOG_ERROR);
284 }
285 return FALSE;
286 }
287
288 /**
289 * gets facebook profile id given a drupal user id
290 */
291 function facebook_apps_get_profile_id($drupal_user_id) {
292 // TODO: Static cache, that invalidates when we create a new FB user.
293 $result = db_result(db_query("SELECT authname FROM {authmap} WHERE uid = %d AND module = 'facebook'", $drupal_user_id));
294
295 if (!$result) {
296 return FALSE;
297 }
298 else {
299 return $result;
300 }
301
302 }
303
304 /**
305 * gets facebook profile id given a drupal user id
306 */
307 function facebook_apps_get_profile_id_from_nid($nid) {
308 $sql ="SELECT authname FROM {authmap} WHERE uid = (select uid from usernode where nid = %d) AND module = 'facebook'";
309 $result = db_result(db_query($sql, $nid));
310
311 if (!$result) {
312 return FALSE;
313 }
314 else {
315 return $result;
316 }
317 }

  ViewVC Help
Powered by ViewVC 1.1.2