// we can set in another locale that may not be set up
// (say, ga_ES for Galego/Galician) it seems to take it.
common_init_locale("en_US");
-
+
+ // Note that this setlocale() call may "fail" but this is harmless;
+ // gettext will still select the right language.
$language = common_language();
$locale_set = common_init_locale($language);
+
setlocale(LC_CTYPE, 'C');
-
- // So we don't have to make people install the gettext locales
+ // So we do not have to make people install the gettext locales
$path = common_config('site','locale_path');
bindtextdomain("statusnet", $path);
bind_textdomain_codeset("statusnet", "UTF-8");
textdomain("statusnet");
-
- if(!$locale_set) {
- common_log(LOG_INFO, 'Language requested:' . $language . ' - locale could not be set. Perhaps that system locale is not installed.', __FILE__);
- }
}
function common_timezone()
if (_have_config() && common_logged_in()) {
$user = common_current_user();
$user_language = $user->language;
- if ($user_language)
- return $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;
+ }
+ }
+ }
}
// Otherwise, find the best match for the languages requested by the
function common_munge_password($password, $id)
{
+ if (is_object($id) || is_object($password)) {
+ $e = new Exception();
+ common_log(LOG_ERR, __METHOD__ . ' object in param to common_munge_password ' .
+ str_replace("\n", " ", $e->getTraceAsString()));
+ }
return md5($password . $id);
}
// check if a username exists and has matching password
+
function common_check_user($nickname, $password)
{
- $authenticated = false;
- $eventResult = Event::handle('CheckPassword', array($nickname, $password, &$authenticated));
- $user = User::staticGet('nickname', $nickname);
- if (is_null($user) || $user === false) {
- //user does not exist
- if($authenticated){
- //a handler said these are valid credentials, so see if a plugin wants to auto register the user
- if(Event::handle('AutoRegister', array($nickname))){
- //no handler registered the user
- return false;
- }else{
- $user = User::staticGet('nickname', $nickname);
- if (is_null($user) || $user === false) {
- common_log(LOG_WARNING, "A plugin handled the AutoRegister event, but did not actually register the user, nickname: $nickname");
- return false;
- }else{
- return $user;
- }
- }
- }else{
- //no handler indicated the credentials were valid, and we know their not valid because the user isn't in the database
- return false;
- }
- } else {
- if($eventResult && ! $authenticated){
- //no handler was authoritative
- if (mb_strlen($password) == 0) {
- // NEVER allow blank passwords, even if they match the DB
- return false;
- }else{
+ $authenticatedUser = false;
+
+ if (Event::handle('StartCheckPassword', array($nickname, $password, &$authenticatedUser))) {
+ $user = User::staticGet('nickname', $nickname);
+ if (!empty($user)) {
+ if (!empty($password)) { // never allow login with blank password
if (0 == strcmp(common_munge_password($password, $user->id),
$user->password)) {
//internal checking passed
- $authenticated = true;
+ $authenticatedUser = $user;
}
}
}
- if($authenticated){
- return $user;
- } else {
- return false;
- }
+ Event::handle('EndCheckPassword', array($nickname, $password, $authenticatedUser));
}
+
+ return $authenticatedUser;
}
// is the current user logged in?
}
if ($user) {
- common_ensure_session();
- $_SESSION['userid'] = $user->id;
- $_cur = $user;
- return $_cur;
+ if (Event::handle('StartSetUser', array(&$user))) {
+ if($user){
+ common_ensure_session();
+ $_SESSION['userid'] = $user->id;
+ $_cur = $user;
+ Event::handle('EndSetUser', array($user));
+ return $_cur;
+ }
+ }
}
return false;
}
common_ensure_session();
$id = isset($_SESSION['userid']) ? $_SESSION['userid'] : false;
if ($id) {
- $_cur = User::staticGet($id);
- return $_cur;
+ $user = User::staticGet($id);
+ if ($user) {
+ $_cur = $user;
+ return $_cur;
+ }
}
}
return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
}
-function curry($fn) {
- //TODO switch to a PHP 5.3 function closure based approach if PHP 5.3 is used
- $args = func_get_args();
- array_shift($args);
- $id = uniqid('_partial');
- $GLOBALS[$id] = array($fn, $args);
- return create_function('',
- '$args = func_get_args(); '.
- 'return call_user_func_array('.
- '$GLOBALS["'.$id.'"][0],'.
- 'array_merge('.
- '$args,'.
- '$GLOBALS["'.$id.'"][1]));');
+if (version_compare(PHP_VERSION, '5.3.0', 'ge')) {
+ // lambda implementation in a separate file; PHP 5.2 won't parse it.
+ require_once INSTALLDIR . "/lib/curry.php";
+} else {
+ function curry($fn) {
+ $args = func_get_args();
+ array_shift($args);
+ $id = uniqid('_partial');
+ $GLOBALS[$id] = array($fn, $args);
+ return create_function('',
+ '$args = func_get_args(); '.
+ 'return call_user_func_array('.
+ '$GLOBALS["'.$id.'"][0],'.
+ 'array_merge('.
+ '$args,'.
+ '$GLOBALS["'.$id.'"][1]));');
+ }
}
function common_linkify($url) {
return strftime('%Y-%m-%d %H:%M:%S', $datetime);
}
+/**
+ * Return an SQL fragment to calculate an age-based weight from a given
+ * timestamp or datetime column.
+ *
+ * @param string $column name of field we're comparing against current time
+ * @param integer $dropoff divisor for age in seconds before exponentiation
+ * @return string SQL fragment
+ */
+function common_sql_weight($column, $dropoff)
+{
+ if (common_config('db', 'type') == 'pgsql') {
+ // PostgreSQL doesn't support timestampdiff function.
+ // @fixme will this use the right time zone?
+ // @fixme does this handle cross-year subtraction correctly?
+ return "sum(exp(-extract(epoch from (now() - $column)) / $dropoff))";
+ } else {
+ return "sum(exp(timestampdiff(second, utc_timestamp(), $column) / $dropoff))";
+ }
+}
+
function common_redirect($url, $code=307)
{
static $status = array(301 => "Moved Permanently",
return date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . "\n";
}
+function common_request_id()
+{
+ $pid = getmypid();
+ if (php_sapi_name() == 'cli') {
+ return $pid;
+ } else {
+ static $req_id = null;
+ if (!isset($req_id)) {
+ $req_id = substr(md5(mt_rand()), 0, 8);
+ }
+ if (isset($_SERVER['REQUEST_URI'])) {
+ $url = $_SERVER['REQUEST_URI'];
+ }
+ $method = $_SERVER['REQUEST_METHOD'];
+ return "$pid.$req_id $method $url";
+ }
+}
+
function common_log($priority, $msg, $filename=null)
{
- $logfile = common_config('site', 'logfile');
- if ($logfile) {
- $log = fopen($logfile, "a");
- if ($log) {
- $output = common_log_line($priority, $msg);
- fwrite($log, $output);
- fclose($log);
+ if(Event::handle('StartLog', array(&$priority, &$msg, &$filename))){
+ $msg = '[' . common_request_id() . '] ' . $msg;
+ $logfile = common_config('site', 'logfile');
+ if ($logfile) {
+ $log = fopen($logfile, "a");
+ if ($log) {
+ $output = common_log_line($priority, $msg);
+ fwrite($log, $output);
+ fclose($log);
+ }
+ } else {
+ common_ensure_syslog();
+ syslog($priority, $msg);
}
- } else {
- common_ensure_syslog();
- syslog($priority, $msg);
+ Event::handle('EndLog', array($priority, $msg, $filename));
}
}
$arr = $object->toArray();
$fields = array();
foreach ($arr as $k => $v) {
- $fields[] = "$k='$v'";
+ if (is_object($v)) {
+ $fields[] = "$k='".get_class($v)."'";
+ } else {
+ $fields[] = "$k='$v'";
+ }
}
$objstring = $object->tableName() . '[' . implode(',', $fields) . ']';
return $objstring;
return $to;
}
-// Neutralise the evil effects of magic_quotes_gpc in the current request.
-// This is used before handing a request off to OAuthRequest::from_request.
+/**
+ * Neutralise the evil effects of magic_quotes_gpc in the current request.
+ * This is used before handing a request off to OAuthRequest::from_request.
+ * @fixme Doesn't consider vars other than _POST and _GET?
+ * @fixme Can't be undone and could corrupt data if run twice.
+ */
function common_remove_magic_from_request()
{
if(get_magic_quotes_gpc()) {
function common_cache_key($extra)
{
- $base_key = common_config('memcached', 'base');
-
- if (empty($base_key)) {
- $base_key = common_keyize(common_config('site', 'name'));
- }
-
- return 'statusnet:' . $base_key . ':' . $extra;
+ return Cache::key($extra);
}
function common_keyize($str)
{
- $str = strtolower($str);
- $str = preg_replace('/\s/', '_', $str);
- return $str;
+ return Cache::keyize($str);
}
function common_memcache()
{
- static $cache = null;
- if (!common_config('memcached', 'enabled')) {
- return null;
- } else {
- if (!$cache) {
- $cache = new Memcache();
- $servers = common_config('memcached', 'server');
- if (is_array($servers)) {
- foreach($servers as $server) {
- $cache->addServer($server);
- }
- } else {
- $cache->addServer($servers);
- }
- }
- return $cache;
- }
+ return Cache::instance();
}
function common_license_terms($uri)
return $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
+ * @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)
{
$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
- $svc = 'ur1.ca';
+ $shortenerName = 'ur1.ca';
} else {
- $svc = $user->urlshorteningservice;
- }
- global $_shorteners;
- if (!isset($_shorteners[$svc])) {
- //the user selected service doesn't exist, so default to ur1.ca
- $svc = 'ur1.ca';
- }
- if (!isset($_shorteners[$svc])) {
- // no shortener plugins installed.
- return $long_url;
+ $shortenerName = $user->urlshorteningservice;
}
- $reflectionObj = new ReflectionClass($_shorteners[$svc]['callInfo'][0]);
- $short_url_service = $reflectionObj->newInstanceArgs($_shorteners[$svc]['callInfo'][1]);
- $short_url = $short_url_service->shorten($long_url);
-
- return $short_url;
+ if(Event::handle('StartShortenUrl', array($long_url,$shortenerName,&$shortenedUrl))){
+ //URL wasn't shortened, so return the long url
+ return $long_url;
+ }else{
+ //URL was shortened, so return the result
+ return $shortenedUrl;
+ }
}
+/**
+ * @return mixed array($proxy, $ip) for web requests; proxy may be null
+ * null if not a web request
+ *
+ * @fixme X-Forwarded-For can be chained by multiple proxies;
+ we should parse the list and provide a cleaner array
+ * @fixme X-Forwarded-For can be forged by clients; only use them if trusted
+ * @fixme X_Forwarded_For headers will override X-Forwarded-For read through $_SERVER;
+ * use function to get exact request headers from Apache if possible.
+ */
function common_client_ip()
{
if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) {