X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Futil.php;h=49764f86a5fe40cc32effaa60a75fb682547202c;hb=7c57aab44e3fad989b85872d416d0c525dbb9de8;hp=e6b62f750f18adb9dee887247cf0c8714fdc3469;hpb=5d12ec0532fa9bcc71644186f6ff80f2b527703c;p=quix0rs-gnu-social.git diff --git a/lib/util.php b/lib/util.php index e6b62f750f..49764f86a5 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1,7 +1,7 @@ $info) { + if ($info['lang'] == $lang) { + return true; + } + } + } + return false; +} + function common_language() { + // Allow ?uselang=xx override, very useful for debugging + // and helping translators check usage and context. + if (isset($_GET['uselang'])) { + $uselang = strval($_GET['uselang']); + if (common_valid_language($uselang)) { + return $uselang; + } + } + // If there is a user logged in and they've set a language preference // then return that one... if (_have_config() && common_logged_in()) { $user = common_current_user(); - $user_language = $user->language; - - if ($user->language) { - // Validate -- we don't want to end up with a bogus code - // left over from some old junk. - foreach (common_config('site', 'languages') as $code => $info) { - if ($info['lang'] == $user_language) { - return $user_language; - } - } + + if (common_valid_language($user->language)) { + return $user->language; } } @@ -217,7 +233,13 @@ function common_check_user($nickname, $password) $authenticatedUser = false; if (Event::handle('StartCheckPassword', array($nickname, $password, &$authenticatedUser))) { - $user = User::staticGet('nickname', common_canonical_nickname($nickname)); + + if (common_is_email($nickname)) { + $user = User::staticGet('email', common_canonical_email($nickname)); + } else { + $user = User::staticGet('nickname', common_canonical_nickname($nickname)); + } + if (!empty($user)) { if (!empty($password)) { // never allow login with blank password if (0 == strcmp(common_munge_password($password, $user->id), @@ -300,7 +322,11 @@ function common_set_user($user) if ($user) { if (Event::handle('StartSetUser', array(&$user))) { - if($user){ + if (!empty($user)) { + if (!$user->hasRight(Right::WEBLOGIN)) { + // TRANS: Authorisation exception thrown when a user a not allowed to login. + throw new AuthorizationException(_('Not allowed to log in.')); + } common_ensure_session(); $_SESSION['userid'] = $user->id; $_cur = $user; @@ -387,7 +413,7 @@ function common_remembered_user() return null; } - $rm = Remember_me::staticGet($code); + $rm = Remember_me::staticGet('code', $code); if (!$rm) { common_log(LOG_WARNING, 'No such remember code: ' . $code); @@ -401,7 +427,7 @@ function common_remembered_user() return null; } - $user = User::staticGet($rm->user_id); + $user = User::staticGet('id', $rm->user_id); if (!$user) { common_log(LOG_WARNING, 'No such user for rememberme: ' . $rm->user_id); @@ -517,14 +543,29 @@ function common_user_cache_hash($user=false) } } -// get canonical version of nickname for comparison +/** + * get canonical version of nickname for comparison + * + * @param string $nickname + * @return string + * + * @throws NicknameException on invalid input + * @deprecated call Nickname::normalize() directly. + */ function common_canonical_nickname($nickname) { - // XXX: UTF-8 canonicalization (like combining chars) - return strtolower($nickname); + return Nickname::normalize($nickname); } -// get canonical version of email for comparison +/** + * get canonical version of email for comparison + * + * @fixme actually normalize + * @fixme reject invalid input + * + * @param string $email + * @return string + */ function common_canonical_email($email) { // XXX: canonicalize UTF-8 @@ -532,15 +573,33 @@ function common_canonical_email($email) return $email; } +/** + * Partial notice markup rendering step: build links to !group references. + * + * @param string $text partially rendered HTML + * @param Notice $notice in whose context we're working + * @return string partially rendered HTML + */ function common_render_content($text, $notice) { $r = common_render_text($text); $id = $notice->profile_id; $r = common_linkify_mentions($r, $notice); - $r = preg_replace('/(^|[\s\.\,\:\;]+)!([A-Za-z0-9]{1,64})/e', "'\\1!'.common_group_link($id, '\\2')", $r); + $r = preg_replace('/(^|[\s\.\,\:\;]+)!(' . Nickname::DISPLAY_FMT . ')/e', + "'\\1!'.common_group_link($id, '\\2')", $r); return $r; } +/** + * Finds @-mentions within the partially-rendered text section and + * turns them into live links. + * + * Should generally not be called except from common_render_content(). + * + * @param string $text partially-rendered HTML + * @param Notice $notice in-progress or complete Notice object for context + * @return string partially-rendered HTML + */ function common_linkify_mentions($text, $notice) { $mentions = common_find_mentions($text, $notice); @@ -585,7 +644,7 @@ function common_linkify_mention($mention) $xs->elementStart('span', 'vcard'); $xs->elementStart('a', $attrs); - $xs->element('span', 'fn nickname', $mention['text']); + $xs->element('span', 'fn nickname mention', $mention['text']); $xs->elementEnd('a'); $xs->elementEnd('span'); @@ -597,6 +656,21 @@ function common_linkify_mention($mention) return $output; } +/** + * Find @-mentions in the given text, using the given notice object as context. + * References will be resolved with common_relative_profile() against the user + * who posted the notice. + * + * Note the return data format is internal, to be used for building links and + * such. Should not be used directly; rather, call common_linkify_mentions(). + * + * @param string $text + * @param Notice $notice notice in whose context we're building links + * + * @return array + * + * @access private + */ function common_find_mentions($text, $notice) { $mentions = array(); @@ -631,20 +705,15 @@ function common_find_mentions($text, $notice) } } - preg_match_all('/^T ([A-Z0-9]{1,64}) /', - $text, - $tmatches, - PREG_OFFSET_CAPTURE); - - preg_match_all('/(?:^|\s+)@(['.NICKNAME_FMT.']{1,64})/', - $text, - $atmatches, - PREG_OFFSET_CAPTURE); - - $matches = array_merge($tmatches[1], $atmatches[1]); + $matches = common_find_mentions_raw($text); foreach ($matches as $match) { - $nickname = common_canonical_nickname($match[0]); + try { + $nickname = Nickname::normalize($match[0]); + } catch (NicknameException $e) { + // Bogus match? Drop it. + continue; + } // Try to get a profile for this nickname. // Start with conversation context, then go to @@ -691,17 +760,19 @@ function common_find_mentions($text, $notice) foreach ($hmatches[1] as $hmatch) { $tag = common_canonical_tag($hmatch[0]); - - $tagged = Profile_tag::getTagged($sender->id, $tag); - - $url = common_local_url('subscriptions', - array('nickname' => $sender->nickname, - 'tag' => $tag)); - - $mentions[] = array('mentioned' => $tagged, - 'text' => $hmatch[0], - 'position' => $hmatch[1], - 'url' => $url); + $plist = Profile_list::getByTaggerAndTag($sender->id, $tag); + if (!empty($plist) && !$plist->private) { + $tagged = $sender->getTaggedSubscribers($tag); + + $url = common_local_url('showprofiletag', + array('tagger' => $sender->nickname, + 'tag' => $tag)); + + $mentions[] = array('mentioned' => $tagged, + 'text' => $hmatch[0], + 'position' => $hmatch[1], + 'url' => $url); + } } Event::handle('EndFindMentions', array($sender, $text, &$mentions)); @@ -710,18 +781,50 @@ function common_find_mentions($text, $notice) return $mentions; } +/** + * Does the actual regex pulls to find @-mentions in text. + * Should generally not be called directly; for use in common_find_mentions. + * + * @param string $text + * @return array of PCRE match arrays + */ +function common_find_mentions_raw($text) +{ + $tmatches = array(); + preg_match_all('/^T (' . Nickname::DISPLAY_FMT . ') /', + $text, + $tmatches, + PREG_OFFSET_CAPTURE); + + $atmatches = array(); + preg_match_all('/(?:^|\s+)@(' . Nickname::DISPLAY_FMT . ')\b/', + $text, + $atmatches, + PREG_OFFSET_CAPTURE); + + $matches = array_merge($tmatches[1], $atmatches[1]); + return $matches; +} + function common_render_text($text) { $r = htmlspecialchars($text); $r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r); $r = common_replace_urls_callback($r, 'common_linkify'); - $r = preg_replace('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/e', "'\\1#'.common_tag_link('\\2')", $r); + $r = preg_replace('/(^|\"\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/ue', "'\\1#'.common_tag_link('\\2')", $r); // XXX: machine tags return $r; } -function common_replace_urls_callback($text, $callback, $notice_id = null) { +/** + * Find links in the given text and pass them to the given callback function. + * + * @param string $text + * @param function($text, $arg) $callback: return replacement text + * @param mixed $arg: optional argument will be passed on to the callback + */ +function common_replace_urls_callback($text, $callback, $arg = null) { // Start off with a regex $regex = '#'. '(?:^|[\s\<\>\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'. @@ -762,10 +865,21 @@ function common_replace_urls_callback($text, $callback, $notice_id = null) { '#ixu'; //preg_match_all($regex,$text,$matches); //print_r($matches); - return preg_replace_callback($regex, curry('callback_helper',$callback,$notice_id) ,$text); + return preg_replace_callback($regex, curry('callback_helper',$callback,$arg) ,$text); } -function callback_helper($matches, $callback, $notice_id) { +/** + * Intermediate callback for common_replace_links(), helps resolve some + * ambiguous link forms before passing on to the final callback. + * + * @param array $matches + * @param callable $callback + * @param mixed $arg optional argument to pass on as second param to callback + * @return string + * + * @access private + */ +function callback_helper($matches, $callback, $arg=null) { $url=$matches[1]; $left = strpos($matches[0],$url); $right = $left+strlen($url); @@ -808,11 +922,7 @@ function callback_helper($matches, $callback, $notice_id) { } }while($original_url!=$url); - if(empty($notice_id)){ - $result = call_user_func_array($callback, array($url)); - }else{ - $result = call_user_func_array($callback, array(array($url,$notice_id)) ); - } + $result = call_user_func_array($callback, array($url, $arg)); return substr($matches[0],0,$left) . $result . substr($matches[0],$right); } @@ -840,15 +950,15 @@ function common_linkify($url) { // functions $url = htmlspecialchars_decode($url); - if(strpos($url, '@') !== false && strpos($url, ':') === false) { - //url is an email address without the mailto: protocol - $canon = "mailto:$url"; - $longurl = "mailto:$url"; - }else{ + if (strpos($url, '@') !== false && strpos($url, ':') === false && Validate::email($url)) { + //url is an email address without the mailto: protocol + $canon = "mailto:$url"; + $longurl = "mailto:$url"; + } else { $canon = File_redirection::_canonUrl($url); - $longurl_data = File_redirection::where($canon); + $longurl_data = File_redirection::where($canon, common_config('attachments', 'process_links')); if (is_array($longurl_data)) { $longurl = $longurl_data['url']; } elseif (is_string($longurl_data)) { @@ -872,8 +982,10 @@ function common_linkify($url) { $f = File::staticGet('url', $longurl); if (empty($f)) { - // XXX: this writes to the database. :< - $f = File::processNew($longurl); + if (common_config('attachments', 'process_links')) { + // XXX: this writes to the database. :< + $f = File::processNew($longurl); + } } if (!empty($f)) { @@ -910,11 +1022,33 @@ function common_linkify($url) { return XMLStringer::estring('a', $attrs, $url); } -function common_shorten_links($text, $always = false) +/** + * Find and shorten links in a given chunk of text if it's longer than the + * configured notice content limit (or unconditionally). + * + * Side effects: may save file and file_redirection records for referenced URLs. + * + * Pass the $user option or call $user->shortenLinks($text) to ensure the proper + * user's options are used; otherwise the current web session user's setitngs + * will be used or ur1.ca if there is no active web login. + * + * @param string $text + * @param boolean $always (optional) + * @param User $user (optional) + * + * @return string + */ +function common_shorten_links($text, $always = false, User $user=null) { - $maxLength = Notice::maxContent(); - if (!$always && ($maxLength == 0 || mb_strlen($text) <= $maxLength)) return $text; - return common_replace_urls_callback($text, array('File_redirection', 'makeShort')); + $user = common_current_user(); + + $maxLength = User_urlshortener_prefs::maxNoticeLength($user); + + if ($always || mb_strlen($text) > $maxLength) { + return common_replace_urls_callback($text, array('File_redirection', 'forceShort'), $user); + } else { + return common_replace_urls_callback($text, array('File_redirection', 'makeShort'), $user); + } } /** @@ -975,9 +1109,9 @@ function common_tag_link($tag) $canonical = common_canonical_tag($tag); if (common_config('singleuser', 'enabled')) { // regular TagAction isn't set up in 1user mode - $user = User::singleUser(); + $nickname = User::singleUserNickname(); $url = common_local_url('showstream', - array('nickname' => $user->nickname, + array('nickname' => $nickname, 'tag' => $canonical)); } else { $url = common_local_url('tag', array('tag' => $canonical)); @@ -993,8 +1127,11 @@ function common_tag_link($tag) function common_canonical_tag($tag) { + // only alphanum + $tag = preg_replace('/[^\pL\pN]/u', '', $tag); $tag = mb_convert_case($tag, MB_CASE_LOWER, "UTF-8"); - return str_replace(array('-', '_', '.'), '', $tag); + $tag = substr($tag, 0, 64); + return $tag; } function common_valid_profile_tag($str) @@ -1002,6 +1139,13 @@ function common_valid_profile_tag($str) return preg_match('/^[A-Za-z0-9_\-\.]{1,64}$/', $str); } +/** + * + * @param $sender_id + * @param $nickname + * @return + * @access private + */ function common_group_link($sender_id, $nickname) { $sender = Profile::staticGet($sender_id); @@ -1015,7 +1159,7 @@ function common_group_link($sender_id, $nickname) $xs = new XMLStringer(); $xs->elementStart('span', 'vcard'); $xs->elementStart('a', $attrs); - $xs->element('span', 'fn nickname', $nickname); + $xs->element('span', 'fn nickname group', $nickname); $xs->elementEnd('a'); $xs->elementEnd('span'); return $xs->getString(); @@ -1024,13 +1168,37 @@ function common_group_link($sender_id, $nickname) } } +/** + * Resolve an ambiguous profile nickname reference, checking in following order: + * - profiles that $sender subscribes to + * - profiles that subscribe to $sender + * - local user profiles + * + * WARNING: does not validate or normalize $nickname -- MUST BE PRE-VALIDATED + * OR THERE MAY BE A RISK OF SQL INJECTION ATTACKS. THIS FUNCTION DOES NOT + * ESCAPE SQL. + * + * @fixme validate input + * @fixme escape SQL + * @fixme fix or remove mystery third parameter + * @fixme is $sender a User or Profile? + * + * @param $sender the user or profile in whose context we're looking + * @param string $nickname validated nickname of + * @param $dt unused mystery parameter; in Notice reply-to handling a timestamp is passed. + * + * @return Profile or null + */ function common_relative_profile($sender, $nickname, $dt=null) { + // Will throw exception on invalid input. + $nickname = Nickname::normalize($nickname); + // Try to find profiles this profile is subscribed to that have this nickname $recipient = new Profile(); // XXX: use a join instead of a subquery - $recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.$sender->id.' and subscribed = id)', 'AND'); - $recipient->whereAdd("nickname = '" . trim($nickname) . "'", 'AND'); + $recipient->whereAdd('EXISTS (SELECT subscribed from subscription where subscriber = '.intval($sender->id).' and subscribed = id)', 'AND'); + $recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND'); if ($recipient->find(true)) { // XXX: should probably differentiate between profiles with // the same name by date of most recent update @@ -1039,8 +1207,8 @@ function common_relative_profile($sender, $nickname, $dt=null) // Try to find profiles that listen to this profile and that have this nickname $recipient = new Profile(); // XXX: use a join instead of a subquery - $recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.$sender->id.' and subscriber = id)', 'AND'); - $recipient->whereAdd("nickname = '" . trim($nickname) . "'", 'AND'); + $recipient->whereAdd('EXISTS (SELECT subscriber from subscription where subscribed = '.intval($sender->id).' and subscriber = id)', 'AND'); + $recipient->whereAdd("nickname = '" . $recipient->escape($nickname) . "'", 'AND'); if ($recipient->find(true)) { // XXX: should probably differentiate between profiles with // the same name by date of most recent update @@ -1062,19 +1230,22 @@ function common_relative_profile($sender, $nickname, $dt=null) function common_local_url($action, $args=null, $params=null, $fragment=null, $addSession=true) { - $r = Router::get(); - $path = $r->build($action, $args, $params, $fragment); + if (Event::handle('StartLocalURL', array(&$action, &$params, &$fragment, &$addSession, &$url))) { + $r = Router::get(); + $path = $r->build($action, $args, $params, $fragment); - $ssl = common_is_sensitive($action); + $ssl = common_is_sensitive($action); - if (common_config('site','fancy')) { - $url = common_path(mb_substr($path, 1), $ssl, $addSession); - } else { - if (mb_strpos($path, '/index.php') === 0) { - $url = common_path(mb_substr($path, 1), $ssl, $addSession); + if (common_config('site','fancy')) { + $url = common_path($path, $ssl, $addSession); } else { - $url = common_path('index.php'.$path, $ssl, $addSession); + if (mb_strpos($path, '/index.php') === 0) { + $url = common_path($path, $ssl, $addSession); + } else { + $url = common_path('index.php/'.$path, $ssl, $addSession); + } } + Event::handle('EndLocalURL', array(&$action, &$params, &$fragment, &$addSession, &$url)); } return $url; } @@ -1179,28 +1350,28 @@ function common_date_string($dt) } else if ($diff < 3300) { $minutes = round($diff/60); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf( ngettext('about one minute ago', 'about %d minutes ago', $minutes), $minutes); + return sprintf( _m('about one minute ago', 'about %d minutes ago', $minutes), $minutes); } else if ($diff < 5400) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about an hour ago'); } else if ($diff < 22 * 3600) { $hours = round($diff/3600); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf( ngettext('about one hour ago', 'about %d hours ago', $hours), $hours); + return sprintf( _m('about one hour ago', 'about %d hours ago', $hours), $hours); } else if ($diff < 37 * 3600) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a day ago'); } else if ($diff < 24 * 24 * 3600) { $days = round($diff/(24*3600)); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf( ngettext('about one day ago', 'about %d days ago', $days), $days); + return sprintf( _m('about one day ago', 'about %d days ago', $days), $days); } else if ($diff < 46 * 24 * 3600) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a month ago'); } else if ($diff < 330 * 24 * 3600) { $months = round($diff/(30*24*3600)); // TRANS: Used in notices to indicate when the notice was made compared to now. - return sprintf( ngettext('about one month ago', 'about %d months ago',$months), $months); + return sprintf( _m('about one month ago', 'about %d months ago',$months), $months); } else if ($diff < 480 * 24 * 3600) { // TRANS: Used in notices to indicate when the notice was made compared to now. return _('about a year ago'); @@ -1298,18 +1469,11 @@ function common_redirect($url, $code=307) exit; } -function common_broadcast_notice($notice, $remote=false) -{ - // DO NOTHING! -} +// Stick the notice on the queue -/** - * Stick the notice on the queue. - */ function common_enqueue_notice($notice) { - static $localTransports = array('omb', - 'ping'); + static $localTransports = array('ping'); $transports = array(); if (common_config('sms', 'enabled')) { @@ -1319,18 +1483,9 @@ function common_enqueue_notice($notice) $transports[] = 'plugin'; } - $xmpp = common_config('xmpp', 'enabled'); - - if ($xmpp) { - $transports[] = 'jabber'; - } - // We can skip these for gatewayed notices. if ($notice->isLocal()) { $transports = array_merge($transports, $localTransports); - if ($xmpp) { - $transports[] = 'public'; - } } if (Event::handle('StartEnqueueNotice', array($notice, &$transports))) { @@ -1349,16 +1504,18 @@ function common_enqueue_notice($notice) } /** - * Broadcast profile updates to OMB and other remote subscribers. + * Legacy function to broadcast profile updates to OMB remote subscribers. + * + * XXX: This probably needs killing, but there are several bits of code + * that broadcast profile changes that need to be dealt with. AFAIK + * this function is only used for OMB. -z * * Since this may be slow with a lot of subscribers or bad remote sites, * this is run through the background queues if possible. */ function common_broadcast_profile(Profile $profile) { - $qm = QueueManager::get(); - $qm->enqueue($profile, "profile"); - return true; + Event::handle('BroadcastProfile', array($profile)); } function common_profile_url($nickname) @@ -1499,6 +1656,7 @@ function common_request_id() function common_log($priority, $msg, $filename=null) { if(Event::handle('StartLog', array(&$priority, &$msg, &$filename))){ + $msg = (empty($filename)) ? $msg : basename($filename) . ' - ' . $msg; $msg = '[' . common_request_id() . '] ' . $msg; $logfile = common_config('site', 'logfile'); if ($logfile) { @@ -1712,6 +1870,30 @@ function common_config($main, $sub) array_key_exists($sub, $config[$main])) ? $config[$main][$sub] : false; } +function common_config_set($main, $sub, $value) +{ + global $config; + if (!array_key_exists($main, $config)) { + $config[$main] = array(); + } + $config[$main][$sub] = $value; +} + +function common_config_append($main, $sub, $value) +{ + global $config; + if (!array_key_exists($main, $config)) { + $config[$main] = array(); + } + if (!array_key_exists($sub, $config[$main])) { + $config[$main][$sub] = array(); + } + if (!is_array($config[$main][$sub])) { + $config[$main][$sub] = array($config[$main][$sub]); + } + array_push($config[$main][$sub], $value); +} + /** * Pull arguments from a GET/POST/REQUEST array with first-level input checks: * strips "magic quotes" slashes if necessary, and kills invalid UTF-8 strings. @@ -1783,30 +1965,68 @@ function common_confirmation_code($bits) // convert markup to HTML -function common_markup_to_html($c) +function common_markup_to_html($c, $args=null) { + if (is_null($args)) { + $args = array(); + } + + // XXX: not very efficient + + foreach ($args as $name => $value) { + $c = preg_replace('/%%arg.'.$name.'%%/', $value, $c); + } + + $c = preg_replace('/%%user.(\w+)%%/e', "common_user_property('\\1')", $c); $c = preg_replace('/%%action.(\w+)%%/e', "common_local_url('\\1')", $c); $c = preg_replace('/%%doc.(\w+)%%/e', "common_local_url('doc', array('title'=>'\\1'))", $c); $c = preg_replace('/%%(\w+).(\w+)%%/e', 'common_config(\'\\1\', \'\\2\')', $c); return Markdown($c); } -function common_profile_uri($profile) +function common_user_property($property) { - if (!$profile) { + $profile = Profile::current(); + + if (empty($profile)) { return null; } - $user = User::staticGet($profile->id); - if ($user) { - return $user->uri; + + switch ($property) { + case 'profileurl': + case 'nickname': + case 'fullname': + case 'location': + case 'bio': + return $profile->$property; + break; + case 'avatar': + return $profile->getAvatar(AVATAR_STREAM_SIZE); + break; + case 'bestname': + return $profile->getBestName(); + break; + default: + return null; } +} + +function common_profile_uri($profile) +{ + $uri = null; - $remote = Remote_profile::staticGet($profile->id); - if ($remote) { - return $remote->uri; + if (!empty($profile)) { + if (Event::handle('StartCommonProfileURI', array($profile, &$uri))) { + $user = User::staticGet($profile->id); + if (!empty($user)) { + $uri = $user->uri; + } + Event::handle('EndCommonProfileURI', array($profile, &$uri)); + } } + // XXX: this is a very bad profile! - return null; + return $uri; } function common_canonical_sms($sms) @@ -1868,21 +2088,6 @@ function common_session_token() return $_SESSION['token']; } -function common_cache_key($extra) -{ - return Cache::key($extra); -} - -function common_keyize($str) -{ - return Cache::keyize($str); -} - -function common_memcache() -{ - return Cache::instance(); -} - function common_license_terms($uri) { if(preg_match('/creativecommons.org\/licenses\/([^\/]+)/', $uri, $matches)) { @@ -1923,30 +2128,46 @@ function common_database_tablename($tablename) /** * Shorten a URL with the current user's configured shortening service, * or ur1.ca if configured, or not at all if no shortening is set up. - * Length is not considered. * - * @param string $long_url + * @param string $long_url original URL + * @param User $user to specify a particular user's options + * @param boolean $force Force shortening (used when notice is too long) * @return string may return the original URL if shortening failed * * @fixme provide a way to specify a particular shortener - * @fixme provide a way to specify to use a given user's shortening preferences */ -function common_shorten_url($long_url) +function common_shorten_url($long_url, User $user=null, $force = false) { $long_url = trim($long_url); + $user = common_current_user(); - if (empty($user)) { - // common current user does not find a user when called from the XMPP daemon - // therefore we'll set one here fix, so that XMPP given URLs may be shortened - $shortenerName = 'ur1.ca'; - } else { - $shortenerName = $user->urlshorteningservice; - } - if(Event::handle('StartShortenUrl', array($long_url,$shortenerName,&$shortenedUrl))){ - //URL wasn't shortened, so return the long url + $maxUrlLength = User_urlshortener_prefs::maxUrlLength($user); + + // $force forces shortening even if it's not strictly needed + // I doubt URL shortening is ever 'strictly' needed. - ESP + + if (mb_strlen($long_url) < $maxUrlLength && !$force) { return $long_url; - }else{ + } + + $shortenerName = User_urlshortener_prefs::urlShorteningService($user); + + if (Event::handle('StartShortenUrl', + array($long_url, $shortenerName, &$shortenedUrl))) { + if ($shortenerName == 'internal') { + $f = File::processNew($long_url); + if (empty($f)) { + return $long_url; + } else { + $shortenedUrl = common_local_url('redirecturl', + array('id' => $f->id)); + return $shortenedUrl; + } + } else { + return $long_url; + } + } else { //URL was shortened, so return the result return trim($shortenedUrl); } @@ -1993,7 +2214,7 @@ function common_url_to_nickname($url) $parts = parse_url($url); - # If any of these parts exist, this won't work + // If any of these parts exist, this won't work foreach ($bad as $badpart) { if (array_key_exists($badpart, $parts)) { @@ -2001,15 +2222,15 @@ function common_url_to_nickname($url) } } - # We just have host and/or path + // We just have host and/or path - # If it's just a host... + // If it's just a host... if (array_key_exists('host', $parts) && (!array_key_exists('path', $parts) || strcmp($parts['path'], '/') == 0)) { $hostparts = explode('.', $parts['host']); - # Try to catch common idiom of nickname.service.tld + // Try to catch common idiom of nickname.service.tld if ((count($hostparts) > 2) && (strlen($hostparts[count($hostparts) - 2]) > 3) && # try to skip .co.uk, .com.au @@ -2017,12 +2238,12 @@ function common_url_to_nickname($url) { return common_nicknamize($hostparts[0]); } else { - # Do the whole hostname + // Do the whole hostname return common_nicknamize($parts['host']); } } else { if (array_key_exists('path', $parts)) { - # Strip starting, ending slashes + // Strip starting, ending slashes $path = preg_replace('@/$@', '', $parts['path']); $path = preg_replace('@^/@', '', $path); $path = basename($path); @@ -2049,3 +2270,73 @@ function common_nicknamize($str) $str = preg_replace('/\W/', '', $str); return strtolower($str); } + +function common_perf_counter($key, $val=null) +{ + global $_perfCounters; + if (isset($_perfCounters)) { + if (common_config('site', 'logperf')) { + if (array_key_exists($key, $_perfCounters)) { + $_perfCounters[$key][] = $val; + } else { + $_perfCounters[$key] = array($val); + } + if (common_config('site', 'logperf_detail')) { + common_log(LOG_DEBUG, "PERF COUNTER HIT: $key $val"); + } + } + } +} + +function common_log_perf_counters() +{ + if (common_config('site', 'logperf')) { + global $_startTime, $_perfCounters; + + if (isset($_startTime)) { + $endTime = microtime(true); + $diff = round(($endTime - $_startTime) * 1000); + common_log(LOG_DEBUG, "PERF runtime: ${diff}ms"); + } + $counters = $_perfCounters; + ksort($counters); + foreach ($counters as $key => $values) { + $count = count($values); + $unique = count(array_unique($values)); + common_log(LOG_DEBUG, "PERF COUNTER: $key $count ($unique unique)"); + } + } +} + +function common_is_email($str) +{ + return (strpos($str, '@') !== false); +} + +function common_init_stats() +{ + global $_mem, $_ts; + + $_mem = memory_get_usage(true); + $_ts = microtime(true); +} + +function common_log_delta($comment=null) +{ + global $_mem, $_ts; + + $mold = $_mem; + $told = $_ts; + + $_mem = memory_get_usage(true); + $_ts = microtime(true); + + $mtotal = $_mem - $mold; + $ttotal = $_ts - $told; + + if (empty($comment)) { + $comment = 'Delta'; + } + + common_debug(sprintf("%s: %d %d", $comment, $mtotal, round($ttotal * 1000000))); +}