3 * Name: Twitter Connector
4 * Description: Relay public postings to a connected Twitter account
6 * Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
7 * Author: Michael Vogel <https://pirati.ca/profile/heluecht>
9 * Copyright (c) 2011-2013 Tobias Diekershoff, Michael Vogel
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 * * Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above
17 * * copyright notice, this list of conditions and the following disclaimer in
18 * the documentation and/or other materials provided with the distribution.
19 * * Neither the name of the <organization> nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 /* Twitter Plugin for Friendica
38 * Author: Tobias Diekershoff
39 * tobias.diekershoff@gmx.net
41 * License:3-clause BSD license
44 * To use this plugin you need a OAuth Consumer key pair (key & secret)
45 * you can get it from Twitter at https://twitter.com/apps
47 * Register your Friendica site as "Client" application with "Read & Write" access
48 * we do not need "Twitter as login". When you've registered the app you get the
49 * OAuth Consumer key and secret pair for your application/site.
51 * Add this key pair to your global .htconfig.php or use the admin panel.
53 * $a->config['twitter']['consumerkey'] = 'your consumer_key here';
54 * $a->config['twitter']['consumersecret'] = 'your consumer_secret here';
56 * To activate the plugin itself add it to the $a->config['system']['addon']
57 * setting. After this, your user can configure their Twitter account settings
58 * from "Settings -> Plugin Settings".
60 * Requirements: PHP5, curl [Slinky library]
63 define('TWITTER_DEFAULT_POLL_INTERVAL', 5); // given in minutes
65 function twitter_install() {
66 // we need some hooks, for the configuration and for sending tweets
67 register_hook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings');
68 register_hook('connector_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
69 register_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
70 register_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
71 register_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
72 register_hook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
73 register_hook('queue_predeliver', 'addon/twitter/twitter.php', 'twitter_queue_hook');
74 register_hook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
75 logger("installed twitter");
79 function twitter_uninstall() {
80 unregister_hook('connector_settings', 'addon/twitter/twitter.php', 'twitter_settings');
81 unregister_hook('connector_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
82 unregister_hook('post_local', 'addon/twitter/twitter.php', 'twitter_post_local');
83 unregister_hook('notifier_normal', 'addon/twitter/twitter.php', 'twitter_post_hook');
84 unregister_hook('jot_networks', 'addon/twitter/twitter.php', 'twitter_jot_nets');
85 unregister_hook('cron', 'addon/twitter/twitter.php', 'twitter_cron');
86 unregister_hook('queue_predeliver', 'addon/twitter/twitter.php', 'twitter_queue_hook');
87 unregister_hook('follow', 'addon/twitter/twitter.php', 'twitter_follow');
89 // old setting - remove only
90 unregister_hook('post_local_end', 'addon/twitter/twitter.php', 'twitter_post_hook');
91 unregister_hook('plugin_settings', 'addon/twitter/twitter.php', 'twitter_settings');
92 unregister_hook('plugin_settings_post', 'addon/twitter/twitter.php', 'twitter_settings_post');
96 function twitter_follow($a, &$contact) {
98 logger("twitter_follow: Check if contact is twitter contact. ".$contact["url"], LOGGER_DEBUG);
100 if (!strstr($contact["url"], "://twitter.com") AND !strstr($contact["url"], "@twitter.com"))
103 // contact seems to be a twitter contact, so continue
104 $nickname = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $contact["url"]);
105 $nickname = str_replace("@twitter.com", "", $nickname);
107 $uid = $a->user["uid"];
109 $ckey = get_config('twitter', 'consumerkey');
110 $csecret = get_config('twitter', 'consumersecret');
111 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
112 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
114 require_once("addon/twitter/codebird.php");
116 $cb = \Codebird\Codebird::getInstance();
117 $cb->setConsumerKey($ckey, $csecret);
118 $cb->setToken($otoken, $osecret);
120 $parameters = array();
121 $parameters["screen_name"] = $nickname;
123 $user = $cb->friendships_create($parameters);
125 twitter_fetchuser($a, $uid, $nickname);
127 $r = q("SELECT name,nick,url,addr,batch,notify,poll,request,confirm,poco,photo,priority,network,alias,pubkey
128 FROM `contact` WHERE `uid` = %d AND `nick` = '%s'",
132 $contact["contact"] = $r[0];
135 function twitter_jot_nets(&$a,&$b) {
139 $tw_post = get_pconfig(local_user(),'twitter','post');
140 if(intval($tw_post) == 1) {
141 $tw_defpost = get_pconfig(local_user(),'twitter','post_by_default');
142 $selected = ((intval($tw_defpost) == 1) ? ' checked="checked" ' : '');
143 $b .= '<div class="profile-jot-net"><input type="checkbox" name="twitter_enable"' . $selected . ' value="1" /> '
144 . t('Post to Twitter') . '</div>';
148 function twitter_settings_post ($a,$post) {
151 // don't check twitter settings if twitter submit button is not clicked
152 if (!x($_POST,'twitter-submit'))
155 if (isset($_POST['twitter-disconnect'])) {
157 * if the twitter-disconnect checkbox is set, clear the OAuth key/secret pair
158 * from the user configuration
160 del_pconfig(local_user(), 'twitter', 'consumerkey');
161 del_pconfig(local_user(), 'twitter', 'consumersecret');
162 del_pconfig(local_user(), 'twitter', 'oauthtoken');
163 del_pconfig(local_user(), 'twitter', 'oauthsecret');
164 del_pconfig(local_user(), 'twitter', 'post');
165 del_pconfig(local_user(), 'twitter', 'post_by_default');
166 del_pconfig(local_user(), 'twitter', 'post_taglinks');
167 del_pconfig(local_user(), 'twitter', 'lastid');
168 del_pconfig(local_user(), 'twitter', 'mirror_posts');
169 del_pconfig(local_user(), 'twitter', 'intelligent_shortening');
170 del_pconfig(local_user(), 'twitter', 'import');
171 del_pconfig(local_user(), 'twitter', 'create_user');
172 del_pconfig(local_user(), 'twitter', 'own_id');
174 if (isset($_POST['twitter-pin'])) {
175 // if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
176 logger('got a Twitter PIN');
177 require_once('library/twitteroauth.php');
178 $ckey = get_config('twitter', 'consumerkey');
179 $csecret = get_config('twitter', 'consumersecret');
180 // the token and secret for which the PIN was generated were hidden in the settings
181 // form as token and token2, we need a new connection to Twitter using these token
182 // and secret to request a Access Token with the PIN
183 $connection = new TwitterOAuth($ckey, $csecret, $_POST['twitter-token'], $_POST['twitter-token2']);
184 $token = $connection->getAccessToken( $_POST['twitter-pin'] );
185 // ok, now that we have the Access Token, save them in the user config
186 set_pconfig(local_user(),'twitter', 'oauthtoken', $token['oauth_token']);
187 set_pconfig(local_user(),'twitter', 'oauthsecret', $token['oauth_token_secret']);
188 set_pconfig(local_user(),'twitter', 'post', 1);
189 set_pconfig(local_user(),'twitter', 'post_taglinks', 1);
190 // reload the Addon Settings page, if we don't do it see Bug #42
191 goaway($a->get_baseurl().'/settings/connectors');
193 // if no PIN is supplied in the POST variables, the user has changed the setting
194 // to post a tweet for every new __public__ posting to the wall
195 set_pconfig(local_user(),'twitter','post',intval($_POST['twitter-enable']));
196 set_pconfig(local_user(),'twitter','post_by_default',intval($_POST['twitter-default']));
197 set_pconfig(local_user(),'twitter','post_taglinks',intval($_POST['twitter-sendtaglinks']));
198 set_pconfig(local_user(), 'twitter', 'mirror_posts', intval($_POST['twitter-mirror']));
199 set_pconfig(local_user(), 'twitter', 'intelligent_shortening', intval($_POST['twitter-shortening']));
200 set_pconfig(local_user(), 'twitter', 'import', intval($_POST['twitter-import']));
201 set_pconfig(local_user(), 'twitter', 'create_user', intval($_POST['twitter-create_user']));
202 info( t('Twitter settings updated.') . EOL);
205 function twitter_settings(&$a,&$s) {
208 $a->page['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . $a->get_baseurl() . '/addon/twitter/twitter.css' . '" media="all" />' . "\r\n";
210 * 1) Check that we have global consumer key & secret
211 * 2) If no OAuthtoken & stuff is present, generate button to get some
212 * 3) Checkbox for "Send public notices (140 chars only)
214 $ckey = get_config('twitter', 'consumerkey' );
215 $csecret = get_config('twitter', 'consumersecret' );
216 $otoken = get_pconfig(local_user(), 'twitter', 'oauthtoken' );
217 $osecret = get_pconfig(local_user(), 'twitter', 'oauthsecret' );
218 $enabled = get_pconfig(local_user(), 'twitter', 'post');
219 $checked = (($enabled) ? ' checked="checked" ' : '');
220 $defenabled = get_pconfig(local_user(),'twitter','post_by_default');
221 $defchecked = (($defenabled) ? ' checked="checked" ' : '');
222 $linksenabled = get_pconfig(local_user(),'twitter','post_taglinks');
223 $linkschecked = (($linksenabled) ? ' checked="checked" ' : '');
224 $mirrorenabled = get_pconfig(local_user(),'twitter','mirror_posts');
225 $mirrorchecked = (($mirrorenabled) ? ' checked="checked" ' : '');
226 $shorteningenabled = get_pconfig(local_user(),'twitter','intelligent_shortening');
227 $shorteningchecked = (($shorteningenabled) ? ' checked="checked" ' : '');
228 $importenabled = get_pconfig(local_user(),'twitter','import');
229 $importchecked = (($importenabled) ? ' checked="checked" ' : '');
230 $create_userenabled = get_pconfig(local_user(),'twitter','create_user');
231 $create_userchecked = (($create_userenabled) ? ' checked="checked" ' : '');
233 $s .= '<span id="settings_twitter_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_twitter_expanded\'); openClose(\'settings_twitter_inflated\');">';
234 $s .= '<h3>'. t('Twitter Settings') .'</h3>';
236 $s .= '<div id="settings_twitter_expanded" class="settings-block" style="display: none;">';
237 $s .= '<span class="fakelink" onclick="openClose(\'settings_twitter_expanded\'); openClose(\'settings_twitter_inflated\');">';
238 $s .= '<h3>'. t('Twitter Settings') .'</h3>';
241 if ( (!$ckey) && (!$csecret) ) {
243 * no global consumer keys
244 * display warning and skip personal config
246 $s .= '<p>'. t('No consumer key pair for Twitter found. Please contact your site administrator.') .'</p>';
249 * ok we have a consumer key pair now look into the OAuth stuff
251 if ( (!$otoken) && (!$osecret) ) {
253 * the user has not yet connected the account to twitter...
254 * get a temporary OAuth key/secret pair and display a button with
255 * which the user can request a PIN to connect the account to a
256 * account at Twitter.
258 require_once('library/twitteroauth.php');
259 $connection = new TwitterOAuth($ckey, $csecret);
260 $request_token = $connection->getRequestToken();
261 $token = $request_token['oauth_token'];
263 * make some nice form
265 $s .= '<p>'. t('At this Friendica instance the Twitter plugin was enabled but you have not yet connected your account to your Twitter account. To do so click the button below to get a PIN from Twitter which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to Twitter.') .'</p>';
266 $s .= '<a href="'.$connection->getAuthorizeURL($token).'" target="_twitter"><img src="addon/twitter/lighter.png" alt="'.t('Log in with Twitter').'"></a>';
267 $s .= '<div id="twitter-pin-wrapper">';
268 $s .= '<label id="twitter-pin-label" for="twitter-pin">'. t('Copy the PIN from Twitter here') .'</label>';
269 $s .= '<input id="twitter-pin" type="text" name="twitter-pin" />';
270 $s .= '<input id="twitter-token" type="hidden" name="twitter-token" value="'.$token.'" />';
271 $s .= '<input id="twitter-token2" type="hidden" name="twitter-token2" value="'.$request_token['oauth_token_secret'].'" />';
272 $s .= '</div><div class="clear"></div>';
273 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="twitter-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
276 * we have an OAuth key / secret pair for the user
277 * so let's give a chance to disable the postings to Twitter
279 require_once('library/twitteroauth.php');
280 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
281 $details = $connection->get('account/verify_credentials');
282 $s .= '<div id="twitter-info" ><img id="twitter-avatar" src="'.$details->profile_image_url.'" /><p id="twitter-info-block">'. t('Currently connected to: ') .'<a href="https://twitter.com/'.$details->screen_name.'" target="_twitter">'.$details->screen_name.'</a><br /><em>'.$details->description.'</em></p></div>';
283 $s .= '<p>'. t('If enabled all your <strong>public</strong> postings can be posted to the associated Twitter account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry.') .'</p>';
284 if ($a->user['hidewall']) {
285 $s .= '<p>'. t('<strong>Note</strong>: Due your privacy settings (<em>Hide your profile details from unknown viewers?</em>) the link potentially included in public postings relayed to Twitter will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted.') .'</p>';
287 $s .= '<div id="twitter-enable-wrapper">';
288 $s .= '<label id="twitter-enable-label" for="twitter-checkbox">'. t('Allow posting to Twitter'). '</label>';
289 $s .= '<input id="twitter-checkbox" type="checkbox" name="twitter-enable" value="1" ' . $checked . '/>';
290 $s .= '<div class="clear"></div>';
291 $s .= '<label id="twitter-default-label" for="twitter-default">'. t('Send public postings to Twitter by default') .'</label>';
292 $s .= '<input id="twitter-default" type="checkbox" name="twitter-default" value="1" ' . $defchecked . '/>';
293 $s .= '<div class="clear"></div>';
295 $s .= '<label id="twitter-mirror-label" for="twitter-mirror">'.t('Mirror all posts from twitter that are no replies').'</label>';
296 $s .= '<input id="twitter-mirror" type="checkbox" name="twitter-mirror" value="1" '. $mirrorchecked . '/>';
297 $s .= '<div class="clear"></div>';
299 $s .= '<label id="twitter-shortening-label" for="twitter-shortening">'.t('Shortening method that optimizes the tweet').'</label>';
300 $s .= '<input id="twitter-shortening" type="checkbox" name="twitter-shortening" value="1" '. $shorteningchecked . '/>';
301 $s .= '<div class="clear"></div>';
303 $s .= '<label id="twitter-sendtaglinks-label" for="twitter-sendtaglinks">'.t('Send linked #-tags and @-names to Twitter').'</label>';
304 $s .= '<input id="twitter-sendtaglinks" type="checkbox" name="twitter-sendtaglinks" value="1" '. $linkschecked . '/>';
305 $s .= '</div><div class="clear"></div>';
307 $s .= '<label id="twitter-import-label" for="twitter-import">'.t('Import the remote timeline').'</label>';
308 $s .= '<input id="twitter-import" type="checkbox" name="twitter-import" value="1" '. $importchecked . '/>';
309 $s .= '<div class="clear"></div>';
311 $s .= '<label id="twitter-create_user-label" for="twitter-create_user">'.t('Automatically create contacts').'</label>';
312 $s .= '<input id="twitter-create_user" type="checkbox" name="twitter-create_user" value="1" '. $create_userchecked . '/>';
313 $s .= '<div class="clear"></div>';
315 $s .= '<div id="twitter-disconnect-wrapper">';
316 $s .= '<label id="twitter-disconnect-label" for="twitter-disconnect">'. t('Clear OAuth configuration') .'</label>';
317 $s .= '<input id="twitter-disconnect" type="checkbox" name="twitter-disconnect" value="1" />';
318 $s .= '</div><div class="clear"></div>';
319 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="twitter-submit" class="settings-submit" value="' . t('Save Settings') . '" /></div>';
322 $s .= '</div><div class="clear"></div>';
326 function twitter_post_local(&$a,&$b) {
331 if((local_user()) && (local_user() == $b['uid']) && (! $b['private']) && (! $b['parent']) ) {
333 $twitter_post = intval(get_pconfig(local_user(),'twitter','post'));
334 $twitter_enable = (($twitter_post && x($_REQUEST,'twitter_enable')) ? intval($_REQUEST['twitter_enable']) : 0);
336 // if API is used, default to the chosen settings
337 if($_REQUEST['api_source'] && intval(get_pconfig(local_user(),'twitter','post_by_default')))
340 if(! $twitter_enable)
343 if(strlen($b['postopts']))
344 $b['postopts'] .= ',';
345 $b['postopts'] .= 'twitter';
349 if (! function_exists('short_link')) {
350 function short_link ($url) {
351 require_once('library/slinky.php');
352 $slinky = new Slinky( $url );
353 $yourls_url = get_config('yourls','url1');
355 $yourls_username = get_config('yourls','username1');
356 $yourls_password = get_config('yourls', 'password1');
357 $yourls_ssl = get_config('yourls', 'ssl1');
358 $yourls = new Slinky_YourLS();
359 $yourls->set( 'username', $yourls_username );
360 $yourls->set( 'password', $yourls_password );
361 $yourls->set( 'ssl', $yourls_ssl );
362 $yourls->set( 'yourls-url', $yourls_url );
363 $slinky->set_cascade( array( $yourls, new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
366 // setup a cascade of shortening services
367 // try to get a short link from these services
368 // in the order ur1.ca, trim, id.gd, tinyurl
369 $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
371 return $slinky->short();
374 function twitter_shortenmsg($b, $shortlink = false) {
375 require_once("include/bbcode.php");
376 require_once("include/html2plain.php");
380 // Looking for the first image
382 if(preg_match("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/is",$b['body'],$matches))
383 $image = $matches[3];
386 if(preg_match("/\[img\](.*?)\[\/img\]/is",$b['body'],$matches))
387 $image = $matches[1];
389 $multipleimages = (strpos($b['body'], "[img") != strrpos($b['body'], "[img"));
391 // When saved into the database the content is sent through htmlspecialchars
392 // That means that we have to decode all image-urls
393 $image = htmlspecialchars_decode($image);
396 if ($b["title"] != "")
397 $body = $b["title"]."\n\n".$body;
399 if (strpos($body, "[bookmark") !== false) {
400 // splitting the text in two parts:
401 // before and after the bookmark
402 $pos = strpos($body, "[bookmark");
403 $body1 = substr($body, 0, $pos);
404 $body2 = substr($body, $pos);
406 // Removing all quotes after the bookmark
407 // they are mostly only the content after the bookmark.
408 $body2 = preg_replace("/\[quote\=([^\]]*)\](.*?)\[\/quote\]/ism",'',$body2);
409 $body2 = preg_replace("/\[quote\](.*?)\[\/quote\]/ism",'',$body2);
410 $body = $body1.$body2;
413 // Add some newlines so that the message could be cut better
414 $body = str_replace(array("[quote", "[bookmark", "[/bookmark]", "[/quote]"),
415 array("\n[quote", "\n[bookmark", "[/bookmark]\n", "[/quote]\n"), $body);
417 // remove the recycle signs and the names since they aren't helpful on twitter
419 $recycle = html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8');
420 $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
422 $recycle = html_entity_decode("◌ ", ENT_QUOTES, 'UTF-8');
423 $body = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', "\n", $body);
425 // remove the share element
426 //$body = preg_replace("/\[share(.*?)\](.*?)\[\/share\]/ism","\n\n$2\n\n",$body);
428 // At first convert the text to html
429 $html = bbcode($body, false, false, 2);
431 // Then convert it to plain text
432 $msg = trim(html2plain($html, 0, true));
433 $msg = html_entity_decode($msg,ENT_QUOTES,'UTF-8');
435 // Removing multiple newlines
436 while (strpos($msg, "\n\n\n") !== false)
437 $msg = str_replace("\n\n\n", "\n\n", $msg);
439 // Removing multiple spaces
440 while (strpos($msg, " ") !== false)
441 $msg = str_replace(" ", " ", $msg);
443 $origmsg = trim($msg);
446 $msg = preg_replace('/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', "", $msg);
451 // look for bookmark-bbcode and handle it with priority
452 if(preg_match("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/is",$b['body'],$matches))
455 $multiplelinks = (strpos($b['body'], "[bookmark") != strrpos($b['body'], "[bookmark"));
457 // If there is no bookmark element then take the first link
459 $links = collecturls($html);
461 foreach($links AS $singlelink) {
462 $img_str = fetch_url($singlelink);
464 $tempfile = tempnam(get_config("system","temppath"), "cache");
465 file_put_contents($tempfile, $img_str);
466 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
469 if (substr($mime, 0, 6) == "image/") {
470 $image = $singlelink;
471 unset($links[$singlelink]);
475 if (sizeof($links) > 0) {
477 $link = current($links);
479 $multiplelinks = (sizeof($links) > 1);
484 $msglink = $b["plink"];
485 else if ($link != "")
487 else if ($multipleimages)
488 $msglink = $b["plink"];
489 else if ($image != "")
492 if (($msglink == "") and strlen($msg) > $max_char)
493 $msglink = $b["plink"];
495 // If the message is short enough then don't modify it.
496 if ((strlen($origmsg) <= $max_char) AND ($msglink == ""))
497 return(array("msg"=>$origmsg, "image"=>""));
499 // If the message is short enough and contains a picture then post the picture as well
500 if ((strlen($origmsg) <= ($max_char - 23)) AND strpos($origmsg, $msglink))
501 return(array("msg"=>$origmsg, "image"=>$image));
503 // If the message is short enough and the link exists in the original message don't modify it as well
504 // -3 because of the bad shortener of twitter
505 if ((strlen($origmsg) <= ($max_char - 3)) AND strpos($origmsg, $msglink))
506 return(array("msg"=>$origmsg, "image"=>""));
508 // Preserve the unshortened link
509 $orig_link = $msglink;
511 // Just replace the message link with a 22 character long string
512 // Twitter calculates with this length
513 if (trim($msglink) <> '')
514 $msglink = "1234567890123456789012";
516 if (strlen(trim($msg." ".$msglink)) > ($max_char)) {
517 $msg = substr($msg, 0, ($max_char) - (strlen($msglink)));
518 $lastchar = substr($msg, -1);
519 $msg = substr($msg, 0, -1);
520 $pos = strrpos($msg, "\n");
522 $msg = substr($msg, 0, $pos);
523 else if ($lastchar != "\n")
524 $msg = substr($msg, 0, -3)."...";
526 // if the post contains a picture and a link then the system tries to cut the post earlier.
527 // So the link and the picture can be posted.
528 if (($image != "") AND ($orig_link != $image)) {
529 $msg2 = substr($msg, 0, ($max_char - 20) - (strlen($msglink)));
530 $lastchar = substr($msg2, -1);
531 $msg2 = substr($msg2, 0, -1);
532 $pos = strrpos($msg2, "\n");
534 $msg = substr($msg2, 0, $pos);
535 else if ($lastchar == "\n")
540 // Removing multiple spaces - again
541 while (strpos($msg, " ") !== false)
542 $msg = str_replace(" ", " ", $msg);
546 // Removing multiple newlines
547 //while (strpos($msg, "\n\n") !== false)
548 // $msg = str_replace("\n\n", "\n", $msg);
550 // Looking if the link points to an image
551 $img_str = fetch_url($orig_link);
553 $tempfile = tempnam(get_config("system","temppath"), "cache");
554 file_put_contents($tempfile, $img_str);
555 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
558 if (($image == $orig_link) OR (substr($mime, 0, 6) == "image/"))
559 return(array("msg"=>$msg, "image"=>$orig_link));
560 else if (($image != $orig_link) AND ($image != "") AND (strlen($msg." ".$msglink) <= ($max_char - 23))) {
562 $orig_link = short_link($orig_link);
564 return(array("msg"=>$msg." ".$orig_link, "image"=>$image));
567 $orig_link = short_link($orig_link);
569 return(array("msg"=>$msg." ".$orig_link, "image"=>""));
573 function twitter_action($a, $uid, $pid, $action) {
575 $ckey = get_config('twitter', 'consumerkey');
576 $csecret = get_config('twitter', 'consumersecret');
577 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
578 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
580 require_once("addon/twitter/codebird.php");
582 $cb = \Codebird\Codebird::getInstance();
583 $cb->setConsumerKey($ckey, $csecret);
584 $cb->setToken($otoken, $osecret);
586 $post = array('id' => $pid);
588 logger("twitter_action '".$action."' ID: ".$pid." data: " . print_r($post, true), LOGGER_DATA);
592 $result = $cb->statuses_destroy($post);
595 $result = $cb->favorites_create($post);
598 $result = $cb->favorites_destroy($post);
601 logger("twitter_action '".$action."' send, result: " . print_r($result, true), LOGGER_DEBUG);
604 function twitter_post_hook(&$a,&$b) {
610 if (!get_pconfig($b["uid"],'twitter','import')) {
611 if($b['deleted'] || $b['private'] || ($b['created'] !== $b['edited']))
615 if($b['parent'] != $b['id']) {
616 logger("twitter_post_hook: parameter ".print_r($b, true), LOGGER_DATA);
618 // Looking if its a reply to a twitter post
619 if ((substr($b["parent-uri"], 0, 9) != "twitter::") AND (substr($b["extid"], 0, 9) != "twitter::") AND (substr($b["thr-parent"], 0, 9) != "twitter::")) {
620 logger("twitter_post_hook: no twitter post ".$b["parent"]);
624 $r = q("SELECT * FROM item WHERE item.uri = '%s' AND item.uid = %d LIMIT 1",
625 dbesc($b["thr-parent"]),
629 logger("twitter_post_hook: no parent found ".$b["thr-parent"]);
636 $nickname = preg_replace("=https?://twitter.com/(.*)=ism", "$1", $orig_post["author-link"]);
637 $nickname = "@[url=".$orig_post["author-link"]."]".$nickname."[/url]";
639 logger("twitter_post_hook: comparing ".$nickname." with ".$b["body"], LOGGER_DEBUG);
640 if (strpos($b["body"], $nickname) === false)
641 $b["body"] = $nickname." ".$b["body"];
643 logger("twitter_post_hook: parent found ".print_r($orig_post, true), LOGGER_DATA);
647 if($b['private'] OR !strstr($b['postopts'],'twitter'))
651 if (($b['verb'] == ACTIVITY_POST) AND $b['deleted'])
652 twitter_action($a, $b["uid"], substr($orig_post["uri"], 9), "delete");
654 if($b['verb'] == ACTIVITY_LIKE) {
655 logger("twitter_post_hook: parameter 2 ".substr($b["thr-parent"], 9), LOGGER_DEBUG);
657 twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "unlike");
659 twitter_action($a, $b["uid"], substr($b["thr-parent"], 9), "like");
663 if($b['deleted'] || ($b['created'] !== $b['edited']))
666 // if post comes from twitter don't send it back
667 if($b['app'] == "Twitter")
670 logger('twitter post invoked');
673 load_pconfig($b['uid'], 'twitter');
675 $ckey = get_config('twitter', 'consumerkey');
676 $csecret = get_config('twitter', 'consumersecret');
677 $otoken = get_pconfig($b['uid'], 'twitter', 'oauthtoken');
678 $osecret = get_pconfig($b['uid'], 'twitter', 'oauthsecret');
679 $intelligent_shortening = get_pconfig($b['uid'], 'twitter', 'intelligent_shortening');
681 // Global setting overrides this
682 if (get_config('twitter','intelligent_shortening'))
683 $intelligent_shortening = get_config('twitter','intelligent_shortening');
685 if($ckey && $csecret && $otoken && $osecret) {
686 logger('twitter: we have customer key and oauth stuff, going to send.', LOGGER_DEBUG);
688 require_once('library/twitteroauth.php');
689 require_once('include/bbcode.php');
690 $tweet = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
691 // in theory max char is 140 but T. uses t.co to make links
692 // longer so we give them 10 characters extra
693 if (!$intelligent_shortening) {
694 $max_char = 130; // max. length for a tweet
695 // we will only work with up to two times the length of the dent
696 // we can later send to Twitter. This way we can "gain" some
697 // information during shortening of potential links but do not
698 // shorten all the links in a 200000 character long essay.
699 if (! $b['title']=='') {
700 $tmp = $b['title'] . ' : '. $b['body'];
701 // $tmp = substr($tmp, 0, 4*$max_char);
703 $tmp = $b['body']; // substr($b['body'], 0, 3*$max_char);
705 // if [url=bla][img]blub.png[/img][/url] get blub.png
706 $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\]\[img\](\\w+.*?)\\[\\/img\]\\[\\/url\]/i', '$2', $tmp);
707 // preserve links to images, videos and audios
708 $tmp = preg_replace( '/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism', '$3', $tmp);
709 $tmp = preg_replace( '/\[\\/?img(\\s+.*?\]|\])/i', '', $tmp);
710 $tmp = preg_replace( '/\[\\/?video(\\s+.*?\]|\])/i', '', $tmp);
711 $tmp = preg_replace( '/\[\\/?youtube(\\s+.*?\]|\])/i', '', $tmp);
712 $tmp = preg_replace( '/\[\\/?vimeo(\\s+.*?\]|\])/i', '', $tmp);
713 $tmp = preg_replace( '/\[\\/?audio(\\s+.*?\]|\])/i', '', $tmp);
714 $linksenabled = get_pconfig($b['uid'],'twitter','post_taglinks');
715 // if a #tag is linked, don't send the [url] over to SN
716 // that is, don't send if the option is not set in the
717 // connector settings
718 if ($linksenabled=='0') {
720 $tmp = preg_replace( '/#\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '#$2', $tmp);
722 $tmp = preg_replace( '/@\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', '@$2', $tmp);
724 $recycle = html_entity_decode("♲ ", ENT_QUOTES, 'UTF-8');
725 $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
727 $recycle = html_entity_decode("◌ ", ENT_QUOTES, 'UTF-8');
728 $tmp = preg_replace( '/'.$recycle.'\[url\=(\w+.*?)\](\w+.*?)\[\/url\]/i', $recycle.'$2', $tmp);
730 $tmp = preg_replace( '/\[url\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/url\]/i', '$2 $1', $tmp);
731 $tmp = preg_replace( '/\[bookmark\=(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)\](\w+.*?)\[\/bookmark\]/i', '$2 $1', $tmp);
732 // find all http or https links in the body of the entry and
733 // apply the shortener if the link is longer then 20 characters
734 if (( strlen($tmp)>$max_char ) && ( $max_char > 0 )) {
735 preg_match_all ( '/(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/i', $tmp, $allurls );
736 foreach ($allurls as $url) {
737 foreach ($url as $u) {
739 $sl = short_link($u);
740 $tmp = str_replace( $u, $sl, $tmp );
745 // ok, all the links we want to send out are save, now strip
746 // away the remaining bbcode
747 //$msg = strip_tags(bbcode($tmp, false, false));
748 $msg = bbcode($tmp, false, false, true);
749 $msg = str_replace(array('<br>','<br />'),"\n",$msg);
750 $msg = strip_tags($msg);
752 // quotes not working - let's try this
753 $msg = html_entity_decode($msg);
754 if (( strlen($msg) > $max_char) && $max_char > 0) {
755 $shortlink = short_link( $b['plink'] );
756 // the new message will be shortened such that "... $shortlink"
757 // will fit into the character limit
758 $msg = nl2br(substr($msg, 0, $max_char-strlen($shortlink)-4));
759 $msg = str_replace(array('<br>','<br />'),' ',$msg);
760 $e = explode(' ', $msg);
761 // remove the last word from the cut down message to
762 // avoid sending cut words to the MicroBlog
764 $msg = implode(' ', $e);
765 $msg .= '... ' . $shortlink;
771 $msgarr = twitter_shortenmsg($b);
772 $msg = $msgarr["msg"];
773 $image = $msgarr["image"];
775 // and now tweet it :-)
776 if(strlen($msg) and ($image != "")) {
777 $img_str = fetch_url($image);
779 $tempfile = tempnam(get_config("system","temppath"), "cache");
780 file_put_contents($tempfile, $img_str);
782 // Twitter had changed something so that the old library doesn't work anymore
783 // so we are using a new library for twitter
785 // Switching completely to this library with all functions
786 require_once("addon/twitter/codebird.php");
788 $cb = \Codebird\Codebird::getInstance();
789 $cb->setConsumerKey($ckey, $csecret);
790 $cb->setToken($otoken, $osecret);
792 $post = array('status' => $msg, 'media[]' => $tempfile);
795 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
797 $result = $cb->statuses_updateWithMedia($post);
802 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
805 $filename = "upload";
807 $result = $tweet->post('statuses/update_with_media', array('media[]' => "{$img_str};type=".$mime.";filename={$filename}" , 'status' => $msg));
810 logger('twitter_post_with_media send, result: ' . print_r($result, true), LOGGER_DEBUG);
811 if ($result->errors OR $result->error) {
812 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
814 // Workaround: Remove the picture link so that the post can be reposted without it
817 } elseif ($iscomment) {
818 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
819 q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
820 dbesc("twitter::".$result->id_str),
821 dbesc($result->text),
827 if(strlen($msg) and ($image == "")) {
828 $url = 'statuses/update';
829 $post = array('status' => $msg);
832 $post["in_reply_to_status_id"] = substr($orig_post["uri"], 9);
834 $result = $tweet->post($url, $post);
835 logger('twitter_post send, result: ' . print_r($result, true), LOGGER_DEBUG);
836 if ($result->errors) {
837 logger('Send to Twitter failed: "' . print_r($result->errors, true) . '"');
839 $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", intval($b['uid']));
841 $a->contact = $r[0]["id"];
843 $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $post));
844 require_once('include/queue_fn.php');
845 add_to_queue($a->contact,NETWORK_TWITTER,$s);
846 notice(t('Twitter post failed. Queued for retry.').EOL);
847 } elseif ($iscomment) {
848 logger('twitter_post: Update extid '.$result->id_str." for post id ".$b['id']);
849 q("UPDATE `item` SET `extid` = '%s' WHERE `id` = %d",
850 dbesc("twitter::".$result->id_str),
853 //q("UPDATE `item` SET `extid` = '%s', `body` = '%s' WHERE `id` = %d",
854 // dbesc("twitter::".$result->id_str),
855 // dbesc($result->text),
863 function twitter_plugin_admin_post(&$a){
864 $consumerkey = ((x($_POST,'consumerkey')) ? notags(trim($_POST['consumerkey'])) : '');
865 $consumersecret = ((x($_POST,'consumersecret')) ? notags(trim($_POST['consumersecret'])): '');
866 $applicationname = ((x($_POST, 'applicationname')) ? notags(trim($_POST['applicationname'])):'');
867 set_config('twitter','consumerkey',$consumerkey);
868 set_config('twitter','consumersecret',$consumersecret);
869 set_config('twitter','application_name',$applicationname);
870 info( t('Settings updated.'). EOL );
872 function twitter_plugin_admin(&$a, &$o){
873 $t = get_markup_template( "admin.tpl", "addon/twitter/" );
875 $o = replace_macros($t, array(
876 '$submit' => t('Save Settings'),
877 // name, label, value, help, [extra values]
878 '$consumerkey' => array('consumerkey', t('Consumer key'), get_config('twitter', 'consumerkey' ), ''),
879 '$consumersecret' => array('consumersecret', t('Consumer secret'), get_config('twitter', 'consumersecret' ), ''),
880 '$applicationname' => array('applicationname', t('Name of the Twitter Application'), get_config('twitter','application_name'),t('set this to avoid mirroring postings from ~friendica back to ~friendica'))
884 function twitter_cron($a,$b) {
885 $last = get_config('twitter','last_poll');
887 $poll_interval = intval(get_config('twitter','poll_interval'));
889 $poll_interval = TWITTER_DEFAULT_POLL_INTERVAL;
892 $next = $last + ($poll_interval * 60);
894 logger('twitter: poll intervall not reached');
898 logger('twitter: cron_start');
900 $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'mirror_posts' AND `v` = '1' ORDER BY RAND()");
903 logger('twitter: fetching for user '.$rr['uid']);
904 twitter_fetchtimeline($a, $rr['uid']);
909 $r = q("SELECT * FROM `pconfig` WHERE `cat` = 'twitter' AND `k` = 'import' AND `v` = '1' ORDER BY RAND()");
912 logger('twitter: importing timeline from user '.$rr['uid']);
913 twitter_fetchhometimeline($a, $rr["uid"]);
917 // check for new contacts once a day
918 $last_contact_check = get_pconfig($rr['uid'],'pumpio','contact_check');
919 if($last_contact_check)
920 $next_contact_check = $last_contact_check + 86400;
922 $next_contact_check = 0;
924 if($next_contact_check <= time()) {
925 pumpio_getallusers($a, $rr["uid"]);
926 set_pconfig($rr['uid'],'pumpio','contact_check',time());
933 logger('twitter: cron_end');
935 set_config('twitter','last_poll', time());
938 function twitter_fetchtimeline($a, $uid) {
939 $ckey = get_config('twitter', 'consumerkey');
940 $csecret = get_config('twitter', 'consumersecret');
941 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
942 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
943 $lastid = get_pconfig($uid, 'twitter', 'lastid');
945 $application_name = get_config('twitter', 'application_name');
947 if ($application_name == "")
948 $application_name = $a->get_hostname();
950 $has_picture = false;
952 require_once('mod/item.php');
954 require_once('library/twitteroauth.php');
955 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
957 $parameters = array("exclude_replies" => true, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
959 $first_time = ($lastid == "");
962 $parameters["since_id"] = $lastid;
964 $items = $connection->get('statuses/user_timeline', $parameters);
966 if (!is_array($items))
969 $posts = array_reverse($items);
972 foreach ($posts as $post) {
973 if ($post->id_str > $lastid)
974 $lastid = $post->id_str;
979 if (!strpos($post->source, $application_name)) {
980 $_SESSION["authenticated"] = true;
981 $_SESSION["uid"] = $uid;
984 $_REQUEST["type"] = "wall";
985 $_REQUEST["api_source"] = true;
986 $_REQUEST["profile_uid"] = $uid;
987 $_REQUEST["source"] = "Twitter";
989 //$_REQUEST["date"] = $post->created_at;
991 $_REQUEST["title"] = "";
993 if (is_object($post->retweeted_status)) {
995 $_REQUEST['body'] = $post->retweeted_status->text;
998 if (is_array($post->retweeted_status->entities->media)) {
999 foreach($post->retweeted_status->entities->media AS $media) {
1000 switch($media->type) {
1002 $_REQUEST['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $_REQUEST['body']);
1003 $has_picture = true;
1009 $converted = twitter_convertmsg($a, $_REQUEST['body'], true, $has_picture);
1010 $_REQUEST['body'] = $converted["body"];
1012 $_REQUEST['body'] = "[share author='".$post->retweeted_status->user->name.
1013 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1014 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1015 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1017 $_REQUEST['body'] .= "[/share]";
1019 $_REQUEST["body"] = $post->text;
1021 if (is_array($post->entities->media)) {
1022 foreach($post->entities->media AS $media) {
1023 switch($media->type) {
1025 $_REQUEST['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $_REQUEST['body']);
1026 $has_picture = true;
1032 $converted = twitter_convertmsg($a, $_REQUEST["body"], true, $has_picture);
1033 $_REQUEST['body'] = $converted["body"];
1036 if (is_string($post->place->name))
1037 $_REQUEST["location"] = $post->place->name;
1039 if (is_string($post->place->full_name))
1040 $_REQUEST["location"] = $post->place->full_name;
1042 if (is_array($post->geo->coordinates))
1043 $_REQUEST["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1045 if (is_array($post->coordinates->coordinates))
1046 $_REQUEST["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1048 //print_r($_REQUEST);
1049 logger('twitter: posting for user '.$uid);
1051 // require_once('mod/item.php');
1057 set_pconfig($uid, 'twitter', 'lastid', $lastid);
1060 function twitter_queue_hook(&$a,&$b) {
1062 $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'",
1063 dbesc(NETWORK_TWITTER)
1068 require_once('include/queue_fn.php');
1070 foreach($qi as $x) {
1071 if($x['network'] !== NETWORK_TWITTER)
1074 logger('twitter_queue: run');
1076 $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid`
1077 WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1",
1085 $ckey = get_config('twitter', 'consumerkey');
1086 $csecret = get_config('twitter', 'consumersecret');
1087 $otoken = get_pconfig($user['uid'], 'twitter', 'oauthtoken');
1088 $osecret = get_pconfig($user['uid'], 'twitter', 'oauthsecret');
1092 if ($ckey AND $csecret AND $otoken AND $osecret) {
1094 logger('twitter_queue: able to post');
1096 $z = unserialize($x['content']);
1098 require_once("addon/twitter/codebird.php");
1100 $cb = \Codebird\Codebird::getInstance();
1101 $cb->setConsumerKey($ckey, $csecret);
1102 $cb->setToken($otoken, $osecret);
1104 if ($z['url'] == "statuses/update")
1105 $result = $cb->statuses_update($z['post']);
1107 logger('twitter_queue: post result: ' . print_r($result, true), LOGGER_DEBUG);
1109 if ($result->errors)
1110 logger('twitter_queue: Send to Twitter failed: "' . print_r($result->errors, true) . '"');
1113 remove_queue_item($x['id']);
1116 logger("twitter_queue: Error getting tokens for user ".$user['uid']);
1119 logger('twitter_queue: delayed');
1120 update_queue_time($x['id']);
1125 function twitter_fetch_contact($uid, $contact, $create_user) {
1127 // Check if the unique contact is existing
1128 // To-Do: only update once a while
1129 $r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
1130 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
1133 q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
1134 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1135 dbesc($contact->name),
1136 dbesc($contact->screen_name),
1137 dbesc($contact->profile_image_url_https));
1139 q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
1140 dbesc($contact->name),
1141 dbesc($contact->screen_name),
1142 dbesc($contact->profile_image_url_https),
1143 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)));
1145 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1146 intval($uid), dbesc("twitter::".$contact->id_str));
1148 if(!count($r) AND !$create_user)
1151 if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
1152 logger("twitter_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
1157 // create contact record
1158 q("INSERT INTO `contact` ( `uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
1159 `name`, `nick`, `photo`, `network`, `rel`, `priority`,
1160 `writable`, `blocked`, `readonly`, `pending` )
1161 VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0 ) ",
1163 dbesc(datetime_convert()),
1164 dbesc("https://twitter.com/".$contact->screen_name),
1165 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1166 dbesc($contact->screen_name."@twitter.com"),
1167 dbesc("twitter::".$contact->id_str),
1169 dbesc("twitter::".$contact->id_str),
1170 dbesc($contact->name),
1171 dbesc($contact->screen_name),
1172 dbesc($contact->profile_image_url_https),
1173 dbesc(NETWORK_TWITTER),
1174 intval(CONTACT_IS_FRIEND),
1179 $r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
1180 dbesc("twitter::".$contact->id_str),
1187 $contact_id = $r[0]['id'];
1189 $g = q("SELECT def_gid FROM user WHERE uid = %d LIMIT 1",
1193 if($g && intval($g[0]['def_gid'])) {
1194 require_once('include/group.php');
1195 group_add_member($uid,'',$contact_id,$g[0]['def_gid']);
1198 require_once("Photo.php");
1200 $photos = import_profile_photo($contact->profile_image_url_https,$uid,$contact_id);
1202 q("UPDATE `contact` SET `photo` = '%s',
1207 `avatar-date` = '%s'
1212 dbesc(datetime_convert()),
1213 dbesc(datetime_convert()),
1214 dbesc(datetime_convert()),
1219 // update profile photos once every two weeks as we have no notification of when they change.
1221 //$update_photo = (($r[0]['avatar-date'] < datetime_convert('','','now -2 days')) ? true : false);
1222 $update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
1224 // check that we have all the photos, this has been known to fail on occasion
1226 if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
1228 logger("twitter_fetch_contact: Updating contact ".$contact->screen_name, LOGGER_DEBUG);
1230 require_once("Photo.php");
1232 $photos = import_profile_photo($contact->profile_image_url_https, $uid, $r[0]['id']);
1234 q("UPDATE `contact` SET `photo` = '%s',
1239 `avatar-date` = '%s',
1249 dbesc(datetime_convert()),
1250 dbesc(datetime_convert()),
1251 dbesc(datetime_convert()),
1252 dbesc("https://twitter.com/".$contact->screen_name),
1253 dbesc(normalise_link("https://twitter.com/".$contact->screen_name)),
1254 dbesc($contact->screen_name."@twitter.com"),
1255 dbesc($contact->name),
1256 dbesc($contact->screen_name),
1262 return($r[0]["id"]);
1265 function twitter_fetchuser($a, $uid, $screen_name = "", $user_id = "") {
1266 $ckey = get_config('twitter', 'consumerkey');
1267 $csecret = get_config('twitter', 'consumersecret');
1268 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1269 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1271 require_once("addon/twitter/codebird.php");
1273 $cb = \Codebird\Codebird::getInstance();
1274 $cb->setConsumerKey($ckey, $csecret);
1275 $cb->setToken($otoken, $osecret);
1277 $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1285 $parameters = array();
1287 if ($screen_name != "")
1288 $parameters["screen_name"] = $screen_name;
1291 $parameters["user_id"] = $user_id;
1293 // Fetching user data
1294 $user = $cb->users_show($parameters);
1296 if (!is_object($user))
1299 $contact_id = twitter_fetch_contact($uid, $user, true);
1304 function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing_contact) {
1306 $has_picture = false;
1308 $postarray = array();
1309 $postarray['network'] = NETWORK_TWITTER;
1310 $postarray['gravity'] = 0;
1311 $postarray['uid'] = $uid;
1312 $postarray['wall'] = 0;
1313 $postarray['uri'] = "twitter::".$post->id_str;
1315 $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1316 dbesc($postarray['uri']),
1325 if ($post->in_reply_to_status_id_str != "") {
1327 $parent = "twitter::".$post->in_reply_to_status_id_str;
1329 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1334 $postarray['thr-parent'] = $r[0]["uri"];
1335 $postarray['parent-uri'] = $r[0]["parent-uri"];
1337 $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
1342 $postarray['thr-parent'] = $r[0]['uri'];
1343 $postarray['parent-uri'] = $r[0]['parent-uri'];
1345 $postarray['thr-parent'] = $postarray['uri'];
1346 $postarray['parent-uri'] = $postarray['uri'];
1351 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1353 if ($post->user->id_str == $own_id) {
1354 $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1358 $contactid = $r[0]["id"];
1360 $postarray['owner-name'] = $r[0]["name"];
1361 $postarray['owner-link'] = $r[0]["url"];
1362 $postarray['owner-avatar'] = $r[0]["photo"];
1367 $postarray['parent-uri'] = $postarray['uri'];
1369 if ($contactid == 0) {
1370 $contactid = twitter_fetch_contact($uid, $post->user, $create_user);
1372 $postarray['owner-name'] = $post->user->name;
1373 $postarray['owner-link'] = "https://twitter.com/".$post->user->screen_name;
1374 $postarray['owner-avatar'] = $post->user->profile_image_url_https;
1377 if(($contactid == 0) AND !$only_existing_contact)
1378 $contactid = $self['id'];
1379 elseif ($contactid <= 0)
1382 $postarray['contact-id'] = $contactid;
1384 $postarray['verb'] = ACTIVITY_POST;
1385 $postarray['author-name'] = $postarray['owner-name'];
1386 $postarray['author-link'] = $postarray['owner-link'];
1387 $postarray['author-avatar'] = $postarray['owner-avatar'];
1388 $postarray['plink'] = "https://twitter.com/".$post->user->screen_name."/status/".$post->id_str;
1389 $postarray['app'] = strip_tags($post->source);
1391 if ($post->user->protected) {
1392 $postarray['private'] = 1;
1393 $postarray['allow_cid'] = '<' . $self['id'] . '>';
1396 $postarray['body'] = $post->text;
1399 if (is_array($post->entities->media)) {
1400 foreach($post->entities->media AS $media) {
1401 switch($media->type) {
1403 $postarray['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1404 $has_picture = true;
1407 $postarray['body'] .= print_r($media, true);
1412 $converted = twitter_convertmsg($a, $postarray['body'], false, $has_picture);
1413 $postarray['body'] = $converted["body"];
1414 $postarray['tag'] = $converted["tags"];
1416 $postarray['created'] = datetime_convert('UTC','UTC',$post->created_at);
1417 $postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at);
1419 if (is_string($post->place->name))
1420 $postarray["location"] = $post->place->name;
1422 if (is_string($post->place->full_name))
1423 $postarray["location"] = $post->place->full_name;
1425 if (is_array($post->geo->coordinates))
1426 $postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
1428 if (is_array($post->coordinates->coordinates))
1429 $postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0];
1431 if (is_object($post->retweeted_status)) {
1433 $postarray['body'] = $post->retweeted_status->text;
1436 if (is_array($post->retweeted_status->entities->media)) {
1437 foreach($post->retweeted_status->entities->media AS $media) {
1438 switch($media->type) {
1440 $postarray['body'] = str_replace($media->url, "\n\n[img]".$media->media_url_https."[/img]\n", $postarray['body']);
1441 $has_picture = true;
1444 $postarray['body'] .= print_r($media, true);
1449 $converted = twitter_convertmsg($a, $postarray['body'], false, $has_picture);
1450 $postarray['body'] = $converted["body"];
1451 $postarray['tag'] = $converted["tags"];
1453 twitter_fetch_contact($uid, $post->retweeted_status->user, false);
1455 // Deactivated at the moment, since there are problems with answers to retweets
1456 if (false AND !intval(get_config('system','wall-to-wall_share'))) {
1457 $postarray['body'] = "[share author='".$post->retweeted_status->user->name.
1458 "' profile='https://twitter.com/".$post->retweeted_status->user->screen_name.
1459 "' avatar='".$post->retweeted_status->user->profile_image_url_https.
1460 "' link='https://twitter.com/".$post->retweeted_status->user->screen_name."/status/".$post->retweeted_status->id_str."']".
1462 $postarray['body'] .= "[/share]";
1464 // Let retweets look like wall-to-wall posts
1465 $postarray['author-name'] = $post->retweeted_status->user->name;
1466 $postarray['author-link'] = "https://twitter.com/".$post->retweeted_status->user->screen_name;
1467 $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url_https;
1474 function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
1476 $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
1484 if (link_compare($user[0]["url"], $postarray['author-link']))
1487 $own_user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1489 dbesc("twitter::".$own_id)
1492 if(!count($own_user))
1495 // Is it me from twitter?
1496 if (link_compare($own_user[0]["url"], $postarray['author-link']))
1499 $myconv = q("SELECT `author-link`, `author-avatar`, `parent` FROM `item` WHERE `parent-uri` = '%s' AND `uid` = %d AND `parent` != 0 AND `deleted` = 0",
1500 dbesc($postarray['parent-uri']),
1504 if(count($myconv)) {
1506 foreach($myconv as $conv) {
1507 // now if we find a match, it means we're in this conversation
1509 if(!link_compare($conv['author-link'],$user[0]["url"]) AND !link_compare($conv['author-link'],$own_user[0]["url"]))
1512 require_once('include/enotify.php');
1514 $conv_parent = $conv['parent'];
1517 'type' => NOTIFY_COMMENT,
1518 'notify_flags' => $user[0]['notify-flags'],
1519 'language' => $user[0]['language'],
1520 'to_name' => $user[0]['username'],
1521 'to_email' => $user[0]['email'],
1522 'uid' => $user[0]['uid'],
1523 'item' => $postarray,
1524 'link' => $a->get_baseurl() . '/display/' . $user[0]['nickname'] . '/' . $top_item,
1525 'source_name' => $postarray['author-name'],
1526 'source_link' => $postarray['author-link'],
1527 'source_photo' => $postarray['author-avatar'],
1528 'verb' => ACTIVITY_POST,
1530 'parent' => $conv_parent,
1533 // only send one notification
1539 function twitter_fetchhometimeline($a, $uid) {
1540 $ckey = get_config('twitter', 'consumerkey');
1541 $csecret = get_config('twitter', 'consumersecret');
1542 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1543 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1544 $create_user = get_pconfig($uid, 'twitter', 'create_user');
1546 logger("twitter_fetchhometimeline: Fetching for user ".$uid, LOGGER_DEBUG);
1548 require_once('library/twitteroauth.php');
1549 require_once('include/items.php');
1551 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1553 $own_contact = twitter_fetch_own_contact($a, $uid);
1555 $r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
1556 intval($own_contact),
1560 $own_id = $r[0]["nick"];
1562 logger("twitter_fetchhometimeline: Own twitter contact not found for user ".$uid, LOGGER_DEBUG);
1566 $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
1572 logger("twitter_fetchhometimeline: Own contact not found for user ".$uid, LOGGER_DEBUG);
1576 $u = q("SELECT * FROM user WHERE uid = %d LIMIT 1",
1579 logger("twitter_fetchhometimeline: Own user not found for user ".$uid, LOGGER_DEBUG);
1583 $parameters = array("exclude_replies" => false, "trim_user" => false, "contributor_details" => true, "include_rts" => true);
1584 //$parameters["count"] = 200;
1587 // Fetching timeline
1588 $lastid = get_pconfig($uid, 'twitter', 'lasthometimelineid');
1590 $first_time = ($lastid == "");
1593 $parameters["since_id"] = $lastid;
1595 $items = $connection->get('statuses/home_timeline', $parameters);
1597 if (!is_array($items)) {
1598 logger("twitter_fetchhometimeline: Error fetching home timeline: ".print_r($items, true), LOGGER_DEBUG);
1602 $posts = array_reverse($items);
1604 logger("twitter_fetchhometimeline: Fetching timeline for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1606 if (count($posts)) {
1607 foreach ($posts as $post) {
1608 if ($post->id_str > $lastid)
1609 $lastid = $post->id_str;
1614 $postarray = twitter_createpost($a, $uid, $post, $self, $create_user, true);
1616 if (trim($postarray['body']) == "")
1619 $item = item_store($postarray);
1621 logger('twitter_fetchhometimeline: User '.$self["nick"].' posted home timeline item '.$item);
1624 twitter_checknotification($a, $uid, $own_id, $item, $postarray);
1628 set_pconfig($uid, 'twitter', 'lasthometimelineid', $lastid);
1630 // Fetching mentions
1631 $lastid = get_pconfig($uid, 'twitter', 'lastmentionid');
1633 $first_time = ($lastid == "");
1636 $parameters["since_id"] = $lastid;
1638 $items = $connection->get('statuses/mentions_timeline', $parameters);
1640 if (!is_array($items)) {
1641 logger("twitter_fetchhometimeline: Error fetching mentions: ".print_r($items, true), LOGGER_DEBUG);
1645 $posts = array_reverse($items);
1647 logger("twitter_fetchhometimeline: Fetching mentions for user ".$uid." ".sizeof($posts)." items", LOGGER_DEBUG);
1649 if (count($posts)) {
1650 foreach ($posts as $post) {
1651 if ($post->id_str > $lastid)
1652 $lastid = $post->id_str;
1657 $postarray = twitter_createpost($a, $uid, $post, $self, false, false);
1659 if (trim($postarray['body']) == "")
1662 $item = item_store($postarray);
1664 logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
1667 $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
1668 dbesc($postarray['uri']),
1672 $item = $r[0]['id'];
1676 require_once('include/enotify.php');
1678 'type' => NOTIFY_TAGSELF,
1679 'notify_flags' => $u[0]['notify-flags'],
1680 'language' => $u[0]['language'],
1681 'to_name' => $u[0]['username'],
1682 'to_email' => $u[0]['email'],
1683 'uid' => $u[0]['uid'],
1684 'item' => $postarray,
1685 'link' => $a->get_baseurl() . '/display/' . $u[0]['nickname'] . '/' . $item,
1686 'source_name' => $postarray['author-name'],
1687 'source_link' => $postarray['author-link'],
1688 'source_photo' => $postarray['author-avatar'],
1689 'verb' => ACTIVITY_TAG,
1696 set_pconfig($uid, 'twitter', 'lastmentionid', $lastid);
1699 function twitter_original_url($url, $depth=1, $fetchbody = false) {
1703 $siteinfo = array();
1705 curl_setopt($ch, CURLOPT_URL, $url);
1706 curl_setopt($ch, CURLOPT_HEADER, 1);
1709 curl_setopt($ch, CURLOPT_NOBODY, 0);
1711 curl_setopt($ch, CURLOPT_NOBODY, 1);
1713 curl_setopt($ch, CURLOPT_TIMEOUT, 10);
1714 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1715 curl_setopt($ch,CURLOPT_USERAGENT,'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Firefox/24.0');
1717 $header = curl_exec($ch);
1718 $curl_info = @curl_getinfo($ch);
1719 $http_code = $curl_info['http_code'];
1722 if ((($curl_info['http_code'] == "301") OR ($curl_info['http_code'] == "302"))
1723 AND (($curl_info['redirect_url'] != "") OR ($curl_info['location'] != ""))) {
1724 if ($curl_info['redirect_url'] != "")
1725 return(twitter_original_url($curl_info['redirect_url'], ++$depth, $fetchbody));
1727 return(twitter_original_url($curl_info['location'], ++$depth, $fetchbody));
1730 $pos = strpos($header, "\r\n\r\n");
1733 $body = trim(substr($header, $pos));
1737 if (trim($body) == "")
1738 return(twitter_original_url($url, ++$depth, true));
1740 $doc = new DOMDocument();
1741 @$doc->loadHTML($body);
1743 $xpath = new DomXPath($doc);
1745 $list = $xpath->query("//meta[@content]");
1746 foreach ($list as $node) {
1748 if ($node->attributes->length)
1749 foreach ($node->attributes as $attribute)
1750 $attr[$attribute->name] = $attribute->value;
1752 if (@$attr["http-equiv"] == 'refresh') {
1753 $path = $attr["content"];
1754 $pathinfo = explode(";", $path);
1756 foreach ($pathinfo AS $value)
1757 if (substr(strtolower($value), 0, 4) == "url=")
1758 return(twitter_original_url(substr($value, 4), ++$depth));
1765 function twitter_siteinfo($url, $dontincludemedia) {
1766 require_once("mod/parse_url.php");
1768 // Fetch site infos - but only from the meta data
1769 $data = parseurl_getsiteinfo($url, true);
1771 if ($dontincludemedia)
1772 unset($data["images"]);
1774 if (!is_string($data["text"]) AND (sizeof($data["images"]) == 0) AND ($data["title"] == $url))
1777 if (is_string($data["title"]))
1778 $text .= "[bookmark=".$url."]".trim($data["title"])."[/bookmark]\n";
1780 // Add a spoiler to the extra information
1781 //if ((sizeof($data["images"]) > 0) OR is_string($data["text"]))
1782 // $text .= "[spoiler]";
1784 if (sizeof($data["images"]) > 0) {
1785 $imagedata = $data["images"][0];
1786 //$text .= '[img='.$imagedata["width"].'x'.$imagedata["height"].']'.$imagedata["src"].'[/img]' . "\n";
1787 $text .= '[img]'.$imagedata["src"].'[/img]'."\n";
1790 if (is_string($data["text"]))
1791 $text .= "[quote]".$data["text"]."[/quote]";
1793 //if ((sizeof($data["images"]) > 0) OR is_string($data["text"]))
1794 // $text .= "[/spoiler]";
1800 function twitter_convertmsg($a, $body, $no_tags = false, $dontincludemedia) {
1802 require_once("include/oembed.php");
1804 $links = preg_match_all("/([^\]\='".'"'."]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism", $body,$matches,PREG_SET_ORDER);
1811 foreach ($matches AS $match) {
1812 $expanded_url = twitter_original_url($match[2]);
1814 $oembed_data = oembed_fetch_url($expanded_url);
1817 $type = $oembed_data->type;
1822 // if (strstr($expanded_url, "//www.youtube.com/"))
1823 // $body = str_replace($match[2], "\n[youtube]".$expanded_url."[/youtube]\n", $body);
1824 // elseif (strstr($expanded_url, "//player.vimeo.com/"))
1825 // $body = str_replace($match[2], "\n[vimeo]".$expanded_url."[/vimeo]\n", $body);
1826 // elseif (strstr($expanded_url, "//twitpic.com/")) // Test
1827 // $body = str_replace($match[2], "\n[url]".$expanded_url."[/url]\n", $body);
1828 // elseif (strstr($expanded_url, "//instagram.com/"))
1829 // $body = str_replace($match[2], "\n[url]".$expanded_url."[/url]\n", $body);
1830 if ($oembed_data->type != "link")
1831 $body = str_replace($match[2], "\n[url]".$expanded_url."[/url]\n", $body);
1833 $img_str = fetch_url($expanded_url, true, $redirects, 4);
1835 $tempfile = tempnam(get_config("system","temppath"), "cache");
1836 file_put_contents($tempfile, $img_str);
1837 $mime = image_type_to_mime_type(exif_imagetype($tempfile));
1840 if (substr($mime, 0, 6) == "image/") {
1842 $body = str_replace($match[2], "[img]".$expanded_url."[/img]", $body);
1843 $dontincludemedia = true;
1845 $type = $oembed_data->type;
1846 $footerurl = $expanded_url;
1847 $footerlink = "[url=".$expanded_url."]".$expanded_url."[/url]";
1849 $body = str_replace($match[2], $footerlink, $body);
1854 if ($footerurl != "")
1855 $footer = twitter_siteinfo($footerurl, $dontincludemedia);
1857 if (($footerlink != "") AND (trim($footer) != "")) {
1858 $removedlink = trim(str_replace($footerlink, "", $body));
1860 if (strstr($body, $removedlink))
1861 $body = $removedlink;
1863 $body .= "\n\n[class=type-".$type."]".$footer."[/class]";
1868 return(array("body" => $body, $tags => ""));
1872 $tags = get_tags($body);
1875 foreach($tags as $tag) {
1876 if (strstr(trim($tag), " "))
1879 if(strpos($tag,'#') === 0) {
1880 if(strpos($tag,'[url='))
1883 // don't link tags that are already embedded in links
1885 if(preg_match('/\[(.*?)' . preg_quote($tag,'/') . '(.*?)\]/',$body))
1887 if(preg_match('/\[(.*?)\]\((.*?)' . preg_quote($tag,'/') . '(.*?)\)/',$body))
1890 $basetag = str_replace('_',' ',substr($tag,1));
1891 $body = str_replace($tag,'#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1892 if(strlen($str_tags))
1894 $str_tags .= '#[url=' . $a->get_baseurl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
1896 } elseif(strpos($tag,'@') === 0) {
1897 $basetag = substr($tag,1);
1898 $body = str_replace($tag,'@[url=https://twitter.com/' . rawurlencode($basetag) . ']' . $basetag . '[/url]',$body);
1904 $cnt = preg_match_all('/@\[url=(.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER);
1906 foreach($matches as $mtch) {
1907 if(strlen($str_tags))
1909 $str_tags .= '@[url=' . $mtch[1] . '[/url]';
1913 return(array("body"=>$body, "tags"=>$str_tags));
1917 function twitter_fetch_own_contact($a, $uid) {
1918 $ckey = get_config('twitter', 'consumerkey');
1919 $csecret = get_config('twitter', 'consumersecret');
1920 $otoken = get_pconfig($uid, 'twitter', 'oauthtoken');
1921 $osecret = get_pconfig($uid, 'twitter', 'oauthsecret');
1923 $own_id = get_pconfig($uid, 'twitter', 'own_id');
1927 if ($own_id == "") {
1928 require_once('library/twitteroauth.php');
1930 $connection = new TwitterOAuth($ckey,$csecret,$otoken,$osecret);
1932 // Fetching user data
1933 $user = $connection->get('account/verify_credentials');
1935 set_pconfig($uid, 'twitter', 'own_id', $user->id_str);
1937 $contact_id = twitter_fetch_contact($uid, $user, true);
1940 $r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
1941 intval($uid), dbesc("twitter::".$own_id));
1943 $contact_id = $r[0]["id"];
1945 del_pconfig($uid, 'twitter', 'own_id');
1949 return($contact_id);