diff options
Diffstat (limited to 'lib/util.php')
-rw-r--r-- | lib/util.php | 456 |
1 files changed, 83 insertions, 373 deletions
diff --git a/lib/util.php b/lib/util.php index c5a092f63..5345a08bb 100644 --- a/lib/util.php +++ b/lib/util.php @@ -394,32 +394,32 @@ function common_render_text($text) function common_replace_urls_callback($text, $callback) { // Start off with a regex - $regex = '# - (?: - (?: - (?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc):// - | - (?:mailto|aim|tel): - ) - [^.\s]+\.[^\s]+ - | - (?:[^.\s/:]+\.)+ - (?:museum|travel|[a-z]{2,4}) - (?:[:/][^\s]*)? - ) - #ix'; + $regex = '#'. + '(?:'. + '(?:'. + '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc)://'. + '|'. + '(?:mailto|aim|tel):'. + ')'. + '[^.\s]+\.[^\s]+'. + '|'. + '(?:[^.\s/:]+\.)+'. + '(?:museum|travel|[a-z]{2,4})'. + '(?:[:/][^\s]*)?'. + ')'. + '#ix'; preg_match_all($regex, $text, $matches); // Then clean up what the regex left behind $offset = 0; - foreach($matches[0] as $url) { - $url = htmlspecialchars_decode($url); + foreach($matches[0] as $orig_url) { + $url = htmlspecialchars_decode($orig_url); // Make sure we didn't pick up an email address if (preg_match('#^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$#i', $url)) continue; - // Remove trailing punctuation - $url = rtrim($url, '.?!,;:\'"`'); + // Remove surrounding punctuation + $url = trim($url, '.?!,;:\'"`([<'); // Remove surrounding parens and the like preg_match('/[)\]>]+$/', $url, $trailing); @@ -446,7 +446,7 @@ function common_replace_urls_callback($text, $callback) { // If the first part wasn't cap'd but the last part was, we captured too much if ((!$prev_part && $last_part)) { - $url = substr_replace($url, '', mb_strpos($url, '.'.$url_parts[2], 0)); + $url = mb_substr($url, 0 , mb_strpos($url, '.'.$url_parts['2'], 0)); } // Capture the new TLD @@ -456,6 +456,9 @@ function common_replace_urls_callback($text, $callback) { if (!in_array($url_parts[2], $tlds)) continue; + // Put the url back the way we found it. + $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url); + // Call user specified func $modified_url = $callback($url); @@ -469,16 +472,25 @@ function common_replace_urls_callback($text, $callback) { } function common_linkify($url) { + // It comes in special'd, so we unspecial it before passing to the stringifying + // functions + $ext = pathinfo($url, PATHINFO_EXTENSION); + $url = htmlspecialchars_decode($url); + $video_ext = array('mp4', 'flv', 'avi', 'mpg', 'mp3', 'ogg'); $display = $url; - $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url:$url; + $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url; + + $attrs = array('href' => $url, 'rel' => 'external'); + + if (in_array($ext, $video_ext)) { + $attrs['class'] = 'media'; + } if ($longurl = common_longurl($url)) { - $longurl = htmlentities($longurl, ENT_QUOTES, 'UTF-8'); - $title = "title=\"$longurl\""; + $attrs['title'] = $longurl; } - else $title = ''; - return "<a href=\"$url\" $title rel=\"external\">$display</a>"; + return XMLStringer::estring('a', $attrs, $display); } function common_longurl($short_url) @@ -579,7 +591,13 @@ function common_tag_link($tag) { $canonical = common_canonical_tag($tag); $url = common_local_url('tag', array('tag' => $canonical)); - return '<span class="tag"><a href="' . htmlspecialchars($url) . '" rel="tag">' . htmlspecialchars($tag) . '</a></span>'; + $xs = new XMLStringer(); + $xs->elementStart('span', 'tag'); + $xs->element('a', array('href' => $url, + 'rel' => 'tag'), + $tag); + $xs->elementEnd('span'); + return $xs->getString(); } function common_canonical_tag($tag) @@ -597,7 +615,14 @@ function common_at_link($sender_id, $nickname) $sender = Profile::staticGet($sender_id); $recipient = common_relative_profile($sender, common_canonical_nickname($nickname)); if ($recipient) { - return '<span class="vcard"><a href="'.htmlspecialchars($recipient->profileurl).'" class="url"><span class="fn nickname">'.$nickname.'</span></a></span>'; + $xs = new XMLStringer(false); + $xs->elementStart('span', 'vcard'); + $xs->elementStart('a', array('href' => $recipient->profileurl, + 'class' => 'url')); + $xs->element('span', 'fn nickname', $nickname); + $xs->elementEnd('a'); + $xs->elementEnd('span'); + return $xs->getString(); } else { return $nickname; } @@ -608,7 +633,14 @@ function common_group_link($sender_id, $nickname) $sender = Profile::staticGet($sender_id); $group = User_group::staticGet('nickname', common_canonical_nickname($nickname)); if ($group && $sender->isMember($group)) { - return '<span class="vcard"><a href="'.htmlspecialchars($group->permalink()).'" class="url"><span class="fn nickname">'.$nickname.'</span></a></span>'; + $xs = new XMLStringer(); + $xs->elementStart('span', 'vcard'); + $xs->elementStart('a', array('href' => $group->permalink(), + 'class' => 'url')); + $xs->element('span', 'fn nickname', $nickname); + $xs->elementEnd('a'); + $xs->elementEnd('span'); + return $xs->getString(); } else { return $nickname; } @@ -625,7 +657,13 @@ function common_at_hash_link($sender_id, $tag) $url = common_local_url('subscriptions', array('nickname' => $user->nickname, 'tag' => $tag)); - return '<span class="tag"><a href="'.htmlspecialchars($url).'" rel="tag">'.$tag.'</a></span>'; + $xs = new XMLStringer(); + $xs->elementStart('span', 'tag'); + $xs->element('a', array('href' => $url, + 'rel' => $tag), + $tag); + $xs->elementEnd('span'); + return $xs->getString(); } else { return $tag; } @@ -667,277 +705,20 @@ function common_relative_profile($sender, $nickname, $dt=null) return null; } -function common_local_url($action, $args=null, $fragment=null) +function common_local_url($action, $args=null, $params=null, $fragment=null) { - $url = null; + $r = Router::get(); + $path = $r->build($action, $args, $params, $fragment); + if ($path) { + } if (common_config('site','fancy')) { - $url = common_fancy_url($action, $args); + $url = common_path(mb_substr($path, 1)); } else { - $url = common_simple_url($action, $args); - } - if (!is_null($fragment)) { - $url .= '#'.$fragment; + $url = common_path('index.php'.$path); } return $url; } -function common_fancy_url($action, $args=null) -{ - switch (strtolower($action)) { - case 'public': - if ($args && isset($args['page'])) { - return common_path('?page=' . $args['page']); - } else { - return common_path(''); - } - case 'featured': - if ($args && isset($args['page'])) { - return common_path('featured?page=' . $args['page']); - } else { - return common_path('featured'); - } - case 'favorited': - if ($args && isset($args['page'])) { - return common_path('favorited?page=' . $args['page']); - } else { - return common_path('favorited'); - } - case 'publicrss': - return common_path('rss'); - case 'publicatom': - return common_path("api/statuses/public_timeline.atom"); - case 'publicxrds': - return common_path('xrds'); - case 'tagrss': - return common_path('tag/' . $args['tag'] . '/rss'); - case 'featuredrss': - return common_path('featuredrss'); - case 'favoritedrss': - return common_path('favoritedrss'); - case 'opensearch': - if ($args && $args['type']) { - return common_path('opensearch/'.$args['type']); - } else { - return common_path('opensearch/people'); - } - case 'doc': - return common_path('doc/'.$args['title']); - case 'block': - case 'login': - case 'logout': - case 'subscribe': - case 'unsubscribe': - case 'invite': - return common_path('main/'.$action); - case 'tagother': - return common_path('main/tagother?id='.$args['id']); - case 'register': - if ($args && $args['code']) { - return common_path('main/register/'.$args['code']); - } else { - return common_path('main/register'); - } - case 'remotesubscribe': - if ($args && $args['nickname']) { - return common_path('main/remote?nickname=' . $args['nickname']); - } else { - return common_path('main/remote'); - } - case 'nudge': - return common_path($args['nickname'].'/nudge'); - case 'openidlogin': - return common_path('main/openid'); - case 'profilesettings': - return common_path('settings/profile'); - case 'passwordsettings': - return common_path('settings/password'); - case 'emailsettings': - return common_path('settings/email'); - case 'openidsettings': - return common_path('settings/openid'); - case 'smssettings': - return common_path('settings/sms'); - case 'twittersettings': - return common_path('settings/twitter'); - case 'othersettings': - return common_path('settings/other'); - case 'deleteprofile': - return common_path('settings/delete'); - case 'newnotice': - if ($args && $args['replyto']) { - return common_path('notice/new?replyto='.$args['replyto']); - } else { - return common_path('notice/new'); - } - case 'shownotice': - return common_path('notice/'.$args['notice']); - case 'deletenotice': - if ($args && $args['notice']) { - return common_path('notice/delete/'.$args['notice']); - } else { - return common_path('notice/delete'); - } - case 'microsummary': - case 'xrds': - case 'foaf': - return common_path($args['nickname'].'/'.$action); - case 'all': - case 'replies': - case 'inbox': - case 'outbox': - if ($args && isset($args['page'])) { - return common_path($args['nickname'].'/'.$action.'?page=' . $args['page']); - } else { - return common_path($args['nickname'].'/'.$action); - } - case 'subscriptions': - case 'subscribers': - $nickname = $args['nickname']; - unset($args['nickname']); - if (isset($args['tag'])) { - $tag = $args['tag']; - unset($args['tag']); - } - $params = http_build_query($args); - if ($params) { - return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '') . '?' . $params); - } else { - return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '')); - } - case 'allrss': - return common_path($args['nickname'].'/all/rss'); - case 'repliesrss': - return common_path($args['nickname'].'/replies/rss'); - case 'userrss': - if (isset($args['limit'])) - return common_path($args['nickname'].'/rss?limit=' . $args['limit']); - return common_path($args['nickname'].'/rss'); - case 'showstream': - if ($args && isset($args['page'])) { - return common_path($args['nickname'].'?page=' . $args['page']); - } else { - return common_path($args['nickname']); - } - - case 'usertimeline': - return common_path("api/statuses/user_timeline/".$args['nickname'].".atom"); - case 'confirmaddress': - return common_path('main/confirmaddress/'.$args['code']); - case 'userbyid': - return common_path('user/'.$args['id']); - case 'recoverpassword': - $path = 'main/recoverpassword'; - if ($args['code']) { - $path .= '/' . $args['code']; - } - return common_path($path); - case 'imsettings': - return common_path('settings/im'); - case 'avatarsettings': - return common_path('settings/avatar'); - case 'groupsearch': - return common_path('search/group' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'peoplesearch': - return common_path('search/people' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'noticesearch': - return common_path('search/notice' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'noticesearchrss': - return common_path('search/notice/rss' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'avatarbynickname': - return common_path($args['nickname'].'/avatar/'.$args['size']); - case 'tag': - $path = 'tag/' . $args['tag']; - unset($args['tag']); - return common_path($path . (($args) ? ('?' . http_build_query($args)) : '')); - case 'publictagcloud': - return common_path('tags'); - case 'peopletag': - $path = 'peopletag/' . $args['tag']; - unset($args['tag']); - return common_path($path . (($args) ? ('?' . http_build_query($args)) : '')); - case 'tags': - return common_path('tags' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'favor': - return common_path('main/favor'); - case 'disfavor': - return common_path('main/disfavor'); - case 'showfavorites': - if ($args && isset($args['page'])) { - return common_path($args['nickname'].'/favorites?page=' . $args['page']); - } else { - return common_path($args['nickname'].'/favorites'); - } - case 'favoritesrss': - return common_path($args['nickname'].'/favorites/rss'); - case 'showmessage': - return common_path('message/' . $args['message']); - case 'newmessage': - return common_path('message/new' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'api': - // XXX: do fancy URLs for all the API methods - switch (strtolower($args['apiaction'])) { - case 'statuses': - switch (strtolower($args['method'])) { - case 'user_timeline.rss': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss'); - case 'user_timeline.atom': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.atom'); - case 'user_timeline.json': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.json'); - case 'user_timeline.xml': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.xml'); - default: return common_simple_url($action, $args); - } - default: return common_simple_url($action, $args); - } - case 'sup': - if ($args && isset($args['seconds'])) { - return common_path('main/sup?seconds='.$args['seconds']); - } else { - return common_path('main/sup'); - } - case 'newgroup': - return common_path('group/new'); - case 'showgroup': - return common_path('group/'.$args['nickname'] . (($args['page']) ? ('?page=' . $args['page']) : '')); - case 'editgroup': - return common_path('group/'.$args['nickname'].'/edit'); - case 'joingroup': - return common_path('group/'.$args['nickname'].'/join'); - case 'leavegroup': - return common_path('group/'.$args['nickname'].'/leave'); - case 'groupbyid': - return common_path('group/'.$args['id'].'/id'); - case 'grouprss': - return common_path('group/'.$args['nickname'].'/rss'); - case 'groupmembers': - return common_path('group/'.$args['nickname'].'/members' . (($args['page']) ? ('?page=' . $args['page']) : '')); - case 'grouplogo': - return common_path('group/'.$args['nickname'].'/logo'); - case 'usergroups': - $nickname = $args['nickname']; - unset($args['nickname']); - return common_path($nickname.'/groups' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'groups': - return common_path('group' . (($args) ? ('?' . http_build_query($args)) : '')); - default: - return common_simple_url($action, $args); - } -} - -function common_simple_url($action, $args=null) -{ - global $config; - /* XXX: pretty URLs */ - $extra = ''; - if ($args) { - foreach ($args as $key => $value) { - $extra .= "&${key}=${value}"; - } - } - return common_path("index.php?action=${action}${extra}"); -} - function common_path($relative) { global $config; @@ -1046,24 +827,6 @@ function common_redirect($url, $code=307) function common_broadcast_notice($notice, $remote=false) { - - // Check to see if notice should go to Twitter - $flink = Foreign_link::getByUserID($notice->profile_id, 1); // 1 == Twitter - if (($flink->noticesync & FOREIGN_NOTICE_SEND) == FOREIGN_NOTICE_SEND) { - - // If it's not a Twitter-style reply, or if the user WANTS to send replies... - - if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || - (($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) == FOREIGN_NOTICE_SEND_REPLY)) { - - $result = common_twitter_broadcast($notice, $flink); - - if (!$result) { - common_debug('Unable to send notice: ' . $notice->id . ' to Twitter.', __FILE__); - } - } - } - if (common_config('queue', 'enabled')) { // Do it later! return common_enqueue_notice($notice); @@ -1072,73 +835,11 @@ function common_broadcast_notice($notice, $remote=false) } } -function common_twitter_broadcast($notice, $flink) -{ - global $config; - $success = true; - $fuser = $flink->getForeignUser(); - $twitter_user = $fuser->nickname; - $twitter_password = $flink->credentials; - $uri = 'http://www.twitter.com/statuses/update.json'; - - // XXX: Hack to get around PHP cURL's use of @ being a a meta character - $statustxt = preg_replace('/^@/', ' @', $notice->content); - - $options = array( - CURLOPT_USERPWD => "$twitter_user:$twitter_password", - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => array( - 'status' => $statustxt, - 'source' => $config['integration']['source'] - ), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FAILONERROR => true, - CURLOPT_HEADER => false, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_USERAGENT => "Laconica", - CURLOPT_CONNECTTIMEOUT => 120, // XXX: Scary!!!! How long should this be? - CURLOPT_TIMEOUT => 120, - - # Twitter is strict about accepting invalid "Expect" headers - CURLOPT_HTTPHEADER => array('Expect:') - ); - - $ch = curl_init($uri); - curl_setopt_array($ch, $options); - $data = curl_exec($ch); - $errmsg = curl_error($ch); - - if ($errmsg) { - common_debug("cURL error: $errmsg - trying to send notice for $twitter_user.", - __FILE__); - $success = false; - } - - curl_close($ch); - - if (!$data) { - common_debug("No data returned by Twitter's API trying to send update for $twitter_user", - __FILE__); - $success = false; - } - - // Twitter should return a status - $status = json_decode($data); - - if (!$status->id) { - common_debug("Unexpected data returned by Twitter API trying to send update for $twitter_user", - __FILE__); - $success = false; - } - - return $success; -} - // Stick the notice on the queue function common_enqueue_notice($notice) { - foreach (array('jabber', 'omb', 'sms', 'public') as $transport) { + foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook') as $transport) { $qi = new Queue_item(); $qi->notice_id = $notice->id; $qi->transport = $transport; @@ -1185,6 +886,15 @@ function common_real_broadcast($notice, $remote=false) common_log(LOG_ERR, 'Error in public broadcast for notice ' . $notice->id); } } + if ($success) { + $success = broadcast_twitter($notice); + if (!$success) { + common_log(LOG_ERR, 'Error in Twitter broadcast for notice ' . $notice->id); + } + } + + // XXX: Do a real-time FB broadcast here? + // XXX: broadcast notices to other IM return $success; } |