2 /****************************************************************/
4 /****************************************************************/
5 /* Copyright (c) 2002-2009 */
6 /* Inclusive Design Institute */
9 /* This program is free software. You can redistribute it and/or*/
10 /* modify it under the terms of the GNU General Public License */
11 /* as published by the Free Software Foundation. */
12 /****************************************************************/
15 require_once(dirname(__FILE__) . '/Applications.class.php');
16 require_once(dirname(__FILE__) .'/../SecurityToken.php');
17 require_once(dirname(__FILE__) .'/../BlobCrypter.php');
18 require_once(dirname(__FILE__) .'/../Crypto.php');
19 require_once(dirname(__FILE__) .'/../BasicSecurityToken.php');
20 require_once(dirname(__FILE__) .'/../BasicBlobCrypter.php');
23 * Object for Application, (aka Gadgets)
25 class Application extends Applications{
26 var $id; //application id
27 var $url, $title, $height, $screenshot, $thumbnail, $author, $author_email, $description, $settings, $views;
31 function Application ($id=0){
34 $this->getApplicationPrefs();
39 * Add application by URL
40 * @param object gadget object retrieved from JSON + cURL
42 function addApplication($gadget_obj){
43 global $db, $addslashes;
44 //TODO: Many more fields to add
45 // $id = $gadget_obj['moduleId']; //after i change the URL to the key.
46 $author = $addslashes($gadget_obj->author);
47 $author_location = $addslashes($gadget_obj->authorLocation);
48 $author_email = $addslashes($gadget_obj->authorEmail);
49 $description = $addslashes($gadget_obj->description);
50 $screenshot = $addslashes($gadget_obj->screenshot);
51 $thumbnail = $addslashes($gadget_obj->thumbnail);
52 $title = $addslashes($gadget_obj->title);
53 $height = intval($gadget_obj->height);
54 $module_id = intval($gadget_obj->module_id);
55 $url = $addslashes($gadget_obj->url);
56 $userPrefs = $addslashes(serialize($gadget_obj->userPrefs));
57 $views = $addslashes(serialize($gadget_obj->views));
58 $scrolling = intval(($gadget_obj->scrolling=='true'?1:0));
61 $sql = 'SELECT MAX(id) AS max_id FROM '.TABLE_PREFIX.'social_applications';
62 $result = mysql_query($sql, $db);
64 $row = mysql_fetch_assoc($result);
65 $id = $row['max_id'] + 1;
69 $member_id = $_SESSION['member_id'];
71 $sql = 'INSERT INTO '.TABLE_PREFIX."social_applications (id, url, title, height, scrolling, screenshot, thumbnail, author, author_email, description, settings, views, last_updated) VALUES ($id, '$url', '$title', $height, $scrolling, '$screenshot', '$thumbnail', '$author', '$author_email', '$description', '$userPrefs', '$views', NOW())";
72 $result = mysql_query($sql, $db);
74 //This application is already in the database, get its ID out
76 $sql = 'SELECT id, UNIX_TIMESTAMP(last_updated) AS last_updated FROM '.TABLE_PREFIX."social_applications WHERE url='$url'";
77 $result = mysql_query($sql, $db);
78 $row = mysql_fetch_assoc($result);
82 //TODO: Needs some sort of comparing instead of blinding updating everytime. Version(can't find any)? Date(need another field in db?)
83 //Use TIMESTAMP for now, but i perfer version #.
84 //If the gadget is SOCIAL_APPLICATION_UPDATE_SCHEDULE days old, update it
85 if (abs($row['last_updated']) < strtotime('-'.SOCIAL_APPLICATION_UPDATE_SCHEDULE.' day')){
86 $sql = 'UPDATE '.TABLE_PREFIX."social_applications SET title='$title', height=$height, scrolling=$scrolling, screenshot='$screenshot', thumbnail='$thumbnail', author='$author', author_email='$author_email', description='$description', settings='$userPrefs', views='$views', last_updated=NOW() WHERE url='$url'";
87 $result = mysql_query($sql, $db);
92 //Add a record into application_member table for mapping
93 $this->addMemberApplication($member_id, $id);
95 // Post gadget information to www.atutor.ca for sharing
96 $this->saveApplicationForShare($gadget_obj->url, $gadget_obj->title, $gadget_obj->height,
97 $gadget_obj->screenshot, $gadget_obj->thumbnail, $gadget_obj->description,
98 $gadget_obj->author, $gadget_obj->authorEmail);
103 * Add this application to the member's application list
104 * @param int member_id
105 * @param int application_id
107 function addMemberApplication($member_id, $app_id){
110 $member_id = intval($member_id);
111 $app_id = intval($app_id);
113 $sql = 'INSERT INTO '.TABLE_PREFIX."social_members_applications (member_id, application_id) VALUES ($member_id, $app_id)";
114 $result = mysql_query($sql, $db);
117 //Add this to the home page
118 $home_settings = $this->getHomeDisplaySettings();
119 $home_settings[$app_id] = 1; //manually set this application
120 $this->setHomeDisplaySettings($home_settings);
122 $act = new Activity();
123 $act->addActivity($_SESSION['member_id'], '', $app_id);
130 * Parse application details
131 * @return array of the attributes
134 function parseModulePrefs($app_url){
135 //parse all the attributes of the <ModulePrefs> tag
136 //and save everything in the object.
137 $securityToken = BasicSecurityToken::createFromValues(1, 1, 0, AT_BASE_HREF, urlencode($app_url), 0);
138 $gadget = $this->fetch_gadget_metadata($app_url, $securityToken);
139 return $gadget->gadgets;
143 // Restful - JSON CURL data transfer
144 private function fetch_gadget_metadata($app_url, $securityToken) {
145 $request = json_encode(array(
146 'context' => array('country' => 'US', 'language' => 'en', 'view' => 'default',
147 'container' => 'atutor'),
148 'gadgets' => array(array('url' => $app_url, 'moduleId' => $this->getModuleId()))));
150 curl_setopt($ch, CURLOPT_URL, AT_SHINDIG_URL.'/gadgets/metadata?st=' . urlencode(base64_encode($securityToken->toSerialForm())));;
151 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
152 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
153 curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
154 curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
155 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4);
156 curl_setopt($ch, CURLOPT_TIMEOUT, 20);
157 curl_setopt($ch, CURLOPT_POST, 1);
158 curl_setopt($ch, CURLOPT_POSTFIELDS, 'request=' . urlencode($request));
159 $content = @curl_exec($ch);
160 return json_decode($content);
165 * Add application perferences into the table.
166 * @param int member id
167 * @param string hash's key, usually the name of the application
168 * @param string hash's value, contains key, value, and st.
169 * @return true(1) if the perference has been updated, false(0) otherwise.
171 function setApplicationSettings($member_id, $key, $value){
172 global $addslashes, $db;
175 $member_id = intval($member_id);
176 $key = $addslashes($key);
177 $value = $addslashes($value);
179 $sql = 'INSERT INTO '.TABLE_PREFIX."social_application_settings (application_id, member_id, name, value) VALUES ($app_id, $member_id, '$key', '$value') ON DUPLICATE KEY UPDATE value='$value'";
180 $result = mysql_query($sql, $db);
182 //TODO: Might want to add something here to throw appropriate exceptions
188 * Get member's applications
189 * @param int the member id
191 function getMemberApplications($member_id){
195 $member_id = intval($member_id);
196 $sql = 'SELECT * FROM '.TABLE_PREFIX.'social_members_applications WHERE member_id='.$member_id;
197 $rs = mysql_query($sql, $db);
199 while($row = mysql_fetch_assoc($rs)){
200 $result[] = $row['app_id'];
208 * Get user perferences for this application
211 function getApplicationSettings($member_id){
214 $member_id = intval($member_id);
216 $sql = 'SELECT * FROM '.TABLE_PREFIX."social_application_settings WHERE member_id=$member_id AND application_id=".$this->id;
217 $rs = mysql_query($sql);
219 //loop cause an application can have multiple pairs of key=>value
220 while ($row = mysql_fetch_assoc($rs)){
221 $result[$row['name']] = $row['value'];
239 function getModuleId(){
240 return intval($this->module_id);
243 function getHeight(){
244 if ($this->height==0){
247 return $this->height;
250 function getScreenshot(){
251 return $this->screenshot;
254 function getThumbnail(){
255 //check if this thumbnail link is a relative link
256 $url = parse_url($this->thumbnail);
257 if (!isset($url['scheme']) && !isset($url['host'])){
258 $orig_url = parse_url($this->getUrl());
259 return $orig_url['scheme'].'://'.$orig_url['host'].$this->thumbnail;
261 return $this->thumbnail;
264 function getAuthor(){
265 return $this->author;
268 function getAuthorEmail(){
269 return $this->author_email;
272 function getAuthorLocation(){
273 return $this->author_location;
276 function getDescription(){
277 return $this->description;
280 function getScrolling(){
281 return ($this->scrolling==1?'yes':'no');
284 function getSettings(){
285 return unserialize($this->settings);
289 return unserialize($this->views);
293 * Return iframe URL based on the given parameters
294 * @param int owner id
295 * @param string avaiable options are 'profile', 'canvas'
296 * http://code.google.com/apis/orkut/docs/orkutdevguide/orkutdevguide-0.8.html#ops_mode
297 * @param string extra application parameters
300 function getIframeUrl($oid, $view='default', $appParams=''){
302 $app_settings = $this->getSettings();
303 $user_settings = $this->getApplicationSettings($_SESSION['member_id']);
305 //retrieve user preferences
306 foreach ($app_settings as $key => $setting) {
308 $value = isset($user_settings[$key]) ? $user_settings[$key] : (isset($setting->default) ? $setting->default : null);
309 if (isset($user_settings[$key])) {
310 unset($user_settings[$key]);
312 //shindig doesn't like ';', it only takes '&' as of Apr 6th, 2009
313 //$prefs .= SEP.'up_' . urlencode($key) . '=' . urlencode($value);
314 $prefs .= '&up_' . urlencode($key) . '=' . urlencode($value);
317 foreach ($user_settings as $name => $value) {
318 // if some keys _are_ set in the db, but not in the gadget metadata, we still parse them on the url
319 // (the above loop unsets the entries that matched
320 if (! empty($value) && ! isset($appParams[$name])) {
321 //shindig doesn't like ';', it only takes '&' as of Apr 6th, 2009
322 //$prefs .= SEP.'up_' . urlencode($name) . '=' . urlencode($value);
323 $prefs .= '&up_' . urlencode($name) . '=' . urlencode($value);
327 //generate security token
328 $securityToken = BasicSecurityToken::createFromValues(($oid > 0?$oid:$_SESSION['member_id']), // owner
329 $_SESSION['member_id'], // viewer
330 $this->getId(), // app id
331 'default', // domain key, shindig will check for php/config/<domain>.php for container specific configuration
332 urlencode($this->getUrl()), // app url
333 $this->getModuleId());// mod id
334 //debug($securityToken);
336 // all the & should be using the constant "SEP", however, shingdig isn't parsing ";",
337 // it only parses "&". Once shindig fixed this, we gotta change it back to SEP
338 //@harris July 23, 2009
339 $url = AT_SHINDIG_URL.'/gadgets/ifr?'
340 . "bpc=1&synd=ATutor" //container name
341 . "&container=default" //container name
342 . "&viewer=". $_SESSION['member_id'] //viewer ID
343 . "&owner=" . $oid //owner ID
344 . "&aid=" . $this->getId() //application id
345 . "&mid=" . $this->getModuleId() //module ID
346 . "&country=US" //country code
347 . "&lang=en" //language code
348 . "&view=" . $view //canvas for this big thing, should be a variable
349 . "&parent=" . urlencode("http://" . $_SERVER['HTTP_HOST']) . $prefs . (isset($appParams) ? '&view-params=' . urlencode($appParams) : '') //container URL
350 . "&st=" . urlencode(base64_encode($securityToken->toSerialForm())) //encrypted token
351 . "&v=" . $this->getVersion() //cache busting md5 of the gadget xml
352 . "&url=" . urlencode($this->getUrl()) //url of gadgets xml
353 . "#rpctoken=" . rand(0, getrandmax()); //random unique number
358 * Returns the cache busting md5 of the gadget XML
359 * @return md5 of the xml content.
361 function getVersion(){
362 //use the skeleton of the XML as version
363 //if it changed, then version is changed.
364 $xml = file_get_contents(($this->getUrl()));
370 * Retrieve all information about this gadget and save it in the object
373 function getApplicationPrefs(){
376 $sql = 'SELECT * FROM '.TABLE_PREFIX.'social_applications WHERE id='.$this->id;
377 $rs = mysql_query($sql);
380 $row = mysql_fetch_assoc($rs);
382 $this->url = $row['url'];
383 $this->title = $row['title'];
384 $this->height = $row['height'];
385 $this->scrolling = $row['scrolling'];
386 $this->screenshot = $row['screenshot'];
387 $this->thumbnail = $row['thumbnail'];
388 $this->author = $row['author'];
389 $this->author_email = $row['author_email'];
390 $this->description = $row['description'];
391 $this->settings = $row['settings'];
392 $this->views = $row['views'];
393 $this->last_updated = $row['last_updated'];
398 * Delete an application
400 function deleteApplication(){
403 //delete application mapping
404 $sql = 'DELETE FROM '.TABLE_PREFIX.'social_members_applications WHERE application_id='.$this->id.' AND member_id='.$_SESSION['member_id'];
405 $rs = mysql_query($sql);
407 //delete application data?
408 $sql = 'DELETE FROM '.TABLE_PREFIX.'social_application_settings WHERE application_id='.$this->id.' AND member_id='.$_SESSION['member_id'];
409 $rs = mysql_query($sql);
411 //delete application settings
412 $home_settings = $this->getHomeDisplaySettings();
413 if (isset($home_settings[$this->id])){
414 unset($home_settings[$this->id]);
415 $this->setHomeDisplaySettings($home_settings);
422 * Save gadget informaiton into atutor.ca/gadget_log.php to share among ATutor users
424 function saveApplicationForShare($url, $title, $height, $screenshot, $thumbnail, $description, $author, $authorEmail){
425 $request = "&url=".urlencode($url)."&title=".urlencode($title).
426 "&height=".urlencode($height)."&screenshot=".urlencode($screenshot).
427 "&thumbnail=".urlencode($thumbnail)."&desc=".urlencode($description).
428 "&author=".urlencode($author)."&authorEmail=".urlencode($authorEmail);
430 $header = "POST /gadget_log.php HTTP/1.1\r\n";
431 $header .= "Host: atutor.ca\r\n";
432 $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
433 $header .= "Content-Length: " . strlen($request) . "\r\n\r\n";
434 $fp = fsockopen('www.atutor.ca', 80, $errno, $errstr, 30);
437 fputs($fp, $header . $request . "\r\n\r\n");