17 require_once SQ_INCLUDE_PATH.
'/general_occasional.inc';
18 require_once SQ_CORE_PACKAGE_PATH.
'/system/triggers/trigger_action/trigger_action.inc';
19 require_once SQ_ATTRIBUTES_PATH.
'/oauth/oauth.inc';
22 require_once
'I18N/UnicodeNormalizer.php';
52 public static function execute($settings, &$state)
54 if ($state[
'asset']) {
55 $asset = $state[
'asset'];
56 }
else if ($state[
'assetid']) {
57 $asset = $GLOBALS[
'SQ_SYSTEM']->am->getAsset($state[
'assetid']);
60 if (empty($settings[
'access_token']) === TRUE) {
62 trigger_localised_error(
'CORE0289', E_USER_WARNING);
67 $tweet_format = $settings[
'tweet_contents'];
68 $asset_keywords = retrieve_keywords_replacements($tweet_format);
69 $replacements = Array();
70 foreach ($asset_keywords as $keyword) {
71 $additional_rep = self::getAdditionalKeywordReplacement($asset, $keyword);
72 if ($additional_rep !== NULL) {
73 $replacements[$keyword] = $additional_rep;
75 $replacements[$keyword] = $state[
'asset']->getKeywordReplacement($keyword);
78 replace_keywords($tweet_format, $replacements);
79 replace_global_keywords($tweet_format);
81 if (strlen($tweet_format) === 0) {
82 trigger_localised_error(
'CORE0290', E_USER_WARNING);
87 if (mb_detect_encoding($tweet_format) !==
'UTF-8') {
88 $tweet_format = mb_convert_encoding($tweet_format,
'UTF-8');
92 $tweet_format = I18N_UnicodeNormalizer::toNFC($tweet_format);
93 $tweet_length = mb_strlen($tweet_format,
'UTF-8');
96 switch ($settings[
'if_tweet_too_long']) {
98 if ($tweet_length > 140) {
99 trigger_localised_error(
'CORE0291', E_USER_WARNING);
106 $tweet_format = self::abbreviateStatus($tweet_format);
107 $tweet_length = mb_strlen($tweet_format,
'UTF-8');
110 if ($tweet_length > 140) {
111 trigger_localised_error(
'CORE0292', E_USER_WARNING);
119 $settings[
'tweet_contents'] = $tweet_format;
120 $return = self::processUpdateStatus($settings);
122 $result = json_decode_array($return);
124 if (isset($result[
'errors'])) {
125 trigger_localised_error(
'CORE0293', E_USER_WARNING, (
string)$result[
'errors'][0][
'message']);
129 $tweet_time = strtotime((
string) $result[
'created_at']);
133 'status' => $tweet_format,
134 'time' => $tweet_time,
150 public static function getInterface($settings, $prefix, $write_access=FALSE,
Trigger $trigger=NULL, $action_id=NULL)
153 $settings[
'tweet_contents'] = array_get_index($settings,
'tweet_contents',
'');
154 $settings[
'if_tweet_too_long'] = array_get_index($settings,
'if_tweet_too_long',
'abbrev');
156 $settings[
'consumer_key'] = array_get_index($settings,
'consumer_key');
157 $settings[
'consumer_secret'] = array_get_index($settings,
'consumer_secret');
158 $settings[
'request_token'] = array_get_index($settings,
'request_token');
159 $settings[
'request_token_secret'] = array_get_index($settings,
'request_token_secret');
160 $settings[
'access_token'] = array_get_index($settings,
'access_token');
161 $settings[
'access_token_secret'] = array_get_index($settings,
'access_token_secret');
162 $settings[
'access_token_acct_for'] = array_get_index($settings,
'access_token_acct_for');
164 if ((empty($_REQUEST[
'oauth_token']) === FALSE) && (empty($_REQUEST[
'oauth_verifier']) === FALSE)) {
167 if ($settings[
'request_token'] === $_REQUEST[
'oauth_token']) {
168 if ($write_access === TRUE) {
169 $trigger_actions = $trigger->attr(
'actions');
170 self::processCallback($settings, $_REQUEST[
'oauth_verifier']);
171 $trigger_actions[$action_id][
'data'] = $settings;
172 $trigger->setAttrValue(
'actions', $trigger_actions);
173 $trigger->saveAttributes();
178 if ((empty($_REQUEST[
'denied']) === FALSE)) {
182 if ($settings[
'request_token'] === $_REQUEST[
'denied']) {
183 trigger_localised_error(
'CORE0294', E_USER_WARNING);
191 if (empty($settings[
'access_token']) === FALSE) {
192 $cache_mgr = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'cache_manager');
193 $cache_key = strtolower(__CLASS__).
'_creds_verified_'.$settings[
'access_token'];
195 $result = $cache_mgr->loadFromCache($trigger->id,
'trigger', $cache_key, FALSE);
197 if ($result !==
'1') {
198 $creds_response = self::processVerify($settings);
199 $response = json_decode_array($creds_response);
202 if (isset($response[
'error'])) {
204 $cache_mgr->saveToCache($trigger->id,
'trigger', $cache_key,
'0', FALSE, 1);
207 if (((
string)$response[
'error']) ===
'Could not authenticate you.') {
208 $settings[
'access_token'] = NULL;
209 $settings[
'access_token_secret'] = NULL;
210 trigger_localised_error(
'CORE0295', E_USER_NOTICE);
213 trigger_localised_error(
'CORE0296', E_USER_NOTICE, (
string)$response[
'error']);
216 $cache_mgr->saveToCache($trigger->id,
'trigger', $cache_key,
'1', FALSE, 60);
222 $credentials_provided = ((empty($settings[
'consumer_key']) === FALSE) && (empty($settings[
'consumer_secret']) === FALSE)) ? TRUE : FALSE;
223 $consumer_details_locked = ((empty($settings[
'access_token']) === TRUE) && (empty($_REQUEST[
'oauth_verifier']) === TRUE)) ? FALSE : TRUE;
227 if (($credentials_provided === TRUE) && ($consumer_details_locked === FALSE)) {
228 if ($write_access === TRUE) {
229 $trigger_actions = $trigger->attr(
'actions');
230 self::processRequestToken($settings);
231 $trigger_actions[$action_id][
'data'] = $settings;
232 $trigger->setAttrValue(
'actions', $trigger_actions);
233 $trigger->saveAttributes();
242 hidden_field($prefix.
'[request_token]', $settings[
'request_token']);
243 hidden_field($prefix.
'[request_token_secret]', $settings[
'request_token_secret']);
244 hidden_field($prefix.
'[access_token]', $settings[
'access_token']);
245 hidden_field($prefix.
'[access_token_secret]', $settings[
'access_token_secret']);
246 hidden_field($prefix.
'[access_token_acct_for]', $settings[
'access_token_acct_for']);
248 <div style=
"padding: 10px">
249 <p
class=
"sq-backend-section-subheading"><?php echo translate(
'trigger_action_update_twitter_status_register_system_header') ?></p>
251 <?php echo translate(
'trigger_action_update_twitter_status_register_system_note') ?>
254 <div style=
"padding: 10px">
255 <p
class=
"sq-backend-section-subheading"><?php echo translate(
'trigger_action_update_twitter_status_client_credentials_header') ?></p>
257 <table
class=
"sq-backend-table">
266 <th><?php echo translate(
'trigger_action_update_twitter_status_client_credentials_key') ?></th>
268 if (($write_access === TRUE) && ($consumer_details_locked === FALSE)) {
269 text_box($prefix.
'[consumer_key]', $settings[
'consumer_key'], 30, 0);
271 echo $settings[
'consumer_key'];
272 hidden_field($prefix.
'[consumer_key]', $settings[
'consumer_key']);
277 <th><?php echo translate(
'trigger_action_update_twitter_status_client_credentials_secret') ?></th>
279 if (($write_access === TRUE) && ($consumer_details_locked === FALSE)) {
280 text_box($prefix.
'[consumer_secret]', $settings[
'consumer_secret'], 30, 0);
282 echo $settings[
'consumer_secret'];
283 hidden_field($prefix.
'[consumer_secret]', $settings[
'consumer_secret']);
288 <th><?php echo translate(
'trigger_action_update_twitter_status_client_credentials_status') ?></th>
290 if ((empty($settings[
'consumer_key']) === TRUE) || (empty($settings[
'consumer_secret']) === TRUE)) {
291 echo translate(
'trigger_action_update_twitter_status_client_credentials_status_no_consumer');
294 if (empty($settings[
'access_token']) === FALSE) {
295 echo translate(
'trigger_action_update_twitter_status_client_credentials_status_yes', $settings[
'access_token_acct_for']);
297 check_box($prefix.
'[deauthorise]');
298 ?> <label
for=
"<?php echo $prefix ?>[deauthorise]"><?php
299 echo translate(
'trigger_action_update_twitter_status_client_credentials_deauthorise');
300 }
else if (empty($settings[
'request_token']) === FALSE) {
301 if ($write_access === TRUE) {
302 $url =
'http://api.twitter.com/oauth/authenticate?oauth_token='.$settings[
'request_token'].
'&force_login=true';
303 echo translate(
'trigger_action_update_twitter_status_client_credentials_status_no', $url);
305 echo translate(
'trigger_action_update_twitter_status_client_credentials_status_no_unlocked');
308 ?><strong style=
"color: #f00">Error: failed to gain request token</strong><?php
309 foreach ($settings[
'request_token_errors'] as $error) {
310 ?><br/><?php echo $error ?><?php
320 <div style=
"padding: 10px">
321 <?php echo translate(
'trigger_action_update_twitter_status_client_credentials_note') ?>
324 <div style=
"padding: 10px">
325 <p
class=
"sq-backend-section-subheading"><?php echo translate(
'trigger_action_update_twitter_status_tweet_format_header') ?></p>
327 <table
class=
"sq-backend-table">
336 <th><?php echo translate(
'trigger_action_update_twitter_status_tweet_format_format') ?></th>
338 if ($write_access === TRUE) {
339 text_box($prefix.
'[tweet_contents]', $settings[
'tweet_contents'], 70, 0, FALSE,
'onkeyup="document.getElementById(\''.$prefix.
'_tweet_length\').innerHTML = (140 - this.value.length).toString(); return true;"');
341 echo $settings[
'tweet_contents'];
342 hidden_field($prefix.
'[tweet_contents]', $settings[
'tweet_contents']);
343 }?> <?php echo translate(
'trigger_action_update_twitter_status_tweet_format_char_count', $prefix, 140 - strlen($settings[
'tweet_contents'])); ?></td>
346 <th><?php echo translate(
'trigger_action_update_twitter_status_tweet_format_iftoolong') ?></th>
349 'abbrev' => translate(
'trigger_action_update_twitter_status_tweet_format_iftoolong_option_abbrev'),
350 'fail' => translate(
'trigger_action_update_twitter_status_tweet_format_iftoolong_option_fail'),
352 if ($write_access === TRUE) {
353 combo_box($prefix.
'[if_tweet_too_long]', $options, FALSE, $settings[
'if_tweet_too_long']);
355 echo $options[$settings[
'if_tweet_too_long']];
356 hidden_field($prefix.
'[if_tweet_too_long]', $settings[
'if_tweet_too_long']);
362 <div style=
"padding: 10px">
363 <?php echo translate(
'trigger_action_update_twitter_status_tweet_format_note') ?>
367 $contents = ob_get_clean();
387 $settings[
'tweet_contents'] = array_get_index($request_data,
'tweet_contents');
388 $settings[
'if_tweet_too_long'] = array_get_index($request_data,
'if_tweet_too_long');
389 $settings[
'consumer_key'] = array_get_index($request_data,
'consumer_key');
390 $settings[
'consumer_secret'] = array_get_index($request_data,
'consumer_secret');
391 $settings[
'request_token'] = array_get_index($request_data,
'request_token');
392 $settings[
'request_token_secret'] = array_get_index($request_data,
'request_token_secret');
393 $settings[
'access_token'] = array_get_index($request_data,
'access_token');
394 $settings[
'access_token_secret'] = array_get_index($request_data,
'access_token_secret');
395 $settings[
'access_token_acct_for'] = array_get_index($request_data,
'access_token_acct_for');
397 $oauth_verifier = array_get_index($request_data,
'oauth_verifier');
398 $deauthorise = (boolean)array_get_index($request_data,
'deauthorise', FALSE);
400 if ($deauthorise === TRUE) {
402 $settings[
'request_token'] = NULL;
403 $settings[
'request_token_secret'] = NULL;
404 $settings[
'request_token_errors'] = NULL;
406 $settings[
'access_token'] = NULL;
407 $settings[
'access_token_secret'] = NULL;
408 $settings[
'access_token_errors'] = NULL;
429 $callback_url = replace_query_string_vars(Array(), NULL, NULL, TRUE);
430 $additional_params =
'SQ_BACKEND_PAGE=frames';
431 if (strpos($callback_url,
'?') === FALSE) {
432 $callback_url .=
'?'.$additional_params;
434 $callback_url .=
'&'.$additional_params;
438 $oauth_attr_values = Array(
439 'consumer_key' => $settings[
'consumer_key'],
440 'consumer_secret' => $settings[
'consumer_secret'],
441 'request_token_url' =>
'http://api.twitter.com/oauth/request_token',
442 'callback_url' => $callback_url,
444 'signature_method' =>
'HMAC-SHA1',
445 'request_headers' => Array(),
446 'request_body' =>
'',
448 'cache_options' =>
'NEVER',
449 'follow_redirect' => FALSE,
451 $oauth_attr->setValue($oauth_attr_values);
453 $settings[
'request_token'] = NULL;
454 $settings[
'request_token_secret'] = NULL;
455 $settings[
'request_token_errors'] = NULL;
457 $settings[
'access_token'] = NULL;
458 $settings[
'access_token_secret'] = NULL;
459 $settings[
'access_token_errors'] = NULL;
461 $result = $oauth_attr->getRequestToken();
463 if ($result === NULL) {
464 $settings[
'request_token_errors'] = $oauth_attr->getErrors();
466 $settings[
'request_token'] = $result[
'request_token'][
'oauth_token'];
467 $settings[
'request_token_secret'] = $result[
'request_token'][
'oauth_token_secret'];
489 $oauth_attr_values = Array(
490 'consumer_key' => $settings[
'consumer_key'],
491 'consumer_secret' => $settings[
'consumer_secret'],
492 'access_token_url' =>
'http://api.twitter.com/oauth/access_token',
494 'signature_method' =>
'HMAC-SHA1',
495 'request_headers' => Array(),
496 'request_body' =>
'',
498 'cache_options' =>
'NEVER',
499 'follow_redirect' => FALSE,
501 $oauth_attr->setValue($oauth_attr_values);
504 $settings[
'access_token'] = NULL;
505 $settings[
'access_token_secret'] = NULL;
506 $settings[
'access_token_errors'] = NULL;
509 $result = $oauth_attr->getAccessToken($settings[
'request_token'], $oauth_verifier, $settings[
'request_token_secret']);
510 if ($result === NULL) {
511 $settings[
'access_token_errors'] = $oauth_attr->getErrors();
513 $settings[
'access_token'] = $result[
'access_token'][
'oauth_token'];
514 $settings[
'access_token_secret'] = $result[
'access_token'][
'oauth_token_secret'];
515 $settings[
'access_token_acct_for'] = $result[
'access_token'][
'screen_name'];
535 $oauth_attr_values = Array(
536 'consumer_key' => $settings[
'consumer_key'],
537 'consumer_secret' => $settings[
'consumer_secret'],
539 'signature_method' =>
'HMAC-SHA1',
540 'request_headers' => Array(),
541 'request_body' =>
'',
543 'cache_options' =>
'NEVER',
544 'follow_redirect' => FALSE,
546 $oauth_attr->setValue($oauth_attr_values);
549 $url =
'http://api.twitter.com/1.1/account/verify_credentials.json';
550 $header = $oauth_attr->getUserDataAuthHeader($url, $settings[
'access_token'], $settings[
'access_token_secret']);
552 $details = fetch_url($url, array(
'RETURNTRANSFER' => 1), array($header));
554 return $details[
'response'];
573 $oauth_attr_values = Array(
574 'consumer_key' => $settings[
'consumer_key'],
575 'consumer_secret' => $settings[
'consumer_secret'],
577 'signature_method' =>
'HMAC-SHA1',
578 'request_headers' =>
'',
579 'request_body' =>
'',
581 'cache_options' =>
'NEVER',
582 'follow_redirect' => FALSE,
584 $oauth_attr->setValue($oauth_attr_values);
586 $oauth_attr_values = $oauth_attr->value;
591 $settings[
'tweet_contents'] = str_replace(
'+',
' ', str_replace(
'%7E',
'~', rawurlencode($settings[
'tweet_contents'])));
592 $url =
'http://api.twitter.com/1.1/statuses/update.json';
593 $url_for_signing = $url.
'?status='.$settings[
'tweet_contents'];
597 $header = $oauth_attr->getUserDataAuthHeader($url_for_signing, $settings[
'access_token'], $settings[
'access_token_secret'], FALSE);
598 $header = substr_replace($header,
'', 0, strlen(
'Authorization: OAuth '));
600 $post_items = Array();
601 $post_bits = Array();
603 $found = preg_match_all(
'/([^,=]*)="([^"]*)"/U', $header, $matches, PREG_SET_ORDER);
604 foreach ($matches as $match) {
607 $post_items[$key] = $value;
610 $post_items[
'status'] = $settings[
'tweet_contents'];
612 foreach ($post_items as $key => $value) {
613 $post_bits[] = $key.
'='.$value;
616 $post_data = implode(
'&', $post_bits);
618 $curl_options = array(
619 'RETURNTRANSFER' => 1,
621 'POSTFIELDS' => $post_data,
624 $details = fetch_url($url, $curl_options);
626 return $details[
'response'];
648 case 'asset_short_url':
652 $current_url = $asset->getUrl();
654 if (empty($current_url) === FALSE) {
655 $urls[] = $current_url;
658 $remap_mgr = $GLOBALS[
'SQ_SYSTEM']->am->getSystemAsset(
'remap_manager');
659 $remapped_urls = $remap_mgr->getRemapURLs($asset);
661 foreach ($remapped_urls as $url_item) {
662 if ($url_item[
'remap_url'] === $current_url) {
663 $urls[] = $url_item[
'url'];
667 usort($urls, create_function(
'$a,$b',
'return strlen($a) - strlen($b);'));
669 $replacement = reset($urls);
705 $pattern =
'/\s+(([A-Za-z0-9\-\.\+]+):\/\/[a-z0-9]+(([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,})?((:[0-9]{1,5})?\/[^\s]*)?)\s+/i';
706 $search_status =
' '.$status.
' ';
708 $string_bits = Array();
710 $found = preg_match($pattern, $search_status, $matches, PREG_OFFSET_CAPTURE);
714 $start_pos = $matches[1][1];
715 $length = mb_strlen($matches[1][0]);
717 if ($start_pos > 0) {
719 $string_bits[] = Array(
720 'text' => trim(mb_substr($search_status, 0, $start_pos)),
725 $string_bits[] = Array(
726 'link' => mb_substr($search_status, $start_pos, $length),
730 $search_status = mb_substr($search_status, $start_pos + $length);
731 $found = preg_match($pattern, $search_status, $matches, PREG_OFFSET_CAPTURE);
736 $search_status = trim($search_status);
737 if (mb_strlen($search_status) > 0) {
738 $string_bits[] = Array(
739 'text' => $search_status,
745 $char_count = count($string_bits) - 1;
746 $text_bits_lengths = Array();
748 foreach ($string_bits as $string_key => $string_bit) {
751 switch (key($string_bit)) {
753 $text_bits_lengths[$string_key] = mb_strlen($string_bit[
'text']);
757 $char_count += mb_strlen($string_bit[key($string_bit)]);
763 if (count($text_bits_lengths) > 0) {
765 arsort($text_bits_lengths);
766 reset($text_bits_lengths);
767 $excess = $char_count - 140;
770 while ($excess > 0) {
773 $key = key($text_bits_lengths);
774 $size = current($text_bits_lengths);
778 $new_size = max(10, max($size / 2, $size - $excess));
780 if ($new_size < $size) {
781 $string_bits[$key][
'text'] = mb_substr($string_bits[$key][
'text'], 0, $new_size - 3).
'...';
784 $excess -= ($size - $new_size);
785 $text_bits_lengths[$key] = $new_size;
788 next($text_bits_lengths);
792 if (key($text_bits_lengths) === NULL) {
793 if ($modified === FALSE)
break;
797 arsort($text_bits_lengths);
798 reset($text_bits_lengths);
806 foreach ($string_bits as &$string_bit) {
807 $string_bit = $string_bit[key($string_bit)];
811 return implode(
' ', $string_bits);