From ce76d61957b22a70214d953f9580db61d09c5a66 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 27 Jun 2009 05:07:14 -0700 Subject: marker in sessions --- lib/util.php | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index f6d50b180..e5a8eaea0 100644 --- a/lib/util.php +++ b/lib/util.php @@ -139,8 +139,19 @@ function common_have_session() function common_ensure_session() { + $c = null; + if (array_key_exists(session_name, $_COOKIE)) { + $c = $_COOKIE[session_name()]; + } if (!common_have_session()) { @session_start(); + if (!isset($_SESSION['started'])) { + $_SESSION['started'] = time(); + if (!empty($c)) { + common_log(LOG_WARNING, 'Session cookie "' . $_COOKIE[session_name()] . '" ' . + ' is set but started value is null'); + } + } } } -- cgit v1.2.3-54-g00ecf From 0ca22cf6e2bd80247520f7c1f83535f8de5fed0a Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 27 Jun 2009 05:48:22 -0700 Subject: a memcached_dataobject class for saving sessions --- classes/Session.php | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.php | 7 +++++- 2 files changed, 73 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/classes/Session.php b/classes/Session.php index 9b48dabac..6f13c7d27 100755 --- a/classes/Session.php +++ b/classes/Session.php @@ -39,4 +39,71 @@ class Session extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + + static function open($save_path, $session_name) + { + return true; + } + + static function close() + { + return true; + } + + static function read($id) + { + $session = Session::staticGet('id', $id); + + if (empty($session)) { + return ''; + } else { + return (string)$session->session_data; + } + } + + static function write($id, $session_data) + { + $session = Session::staticGet('id', $id); + + if (empty($session)) { + $session = new Session(); + + $session->id = $id; + $session->session_data = $session_data; + $session->created = common_sql_now(); + + return $session->insert(); + } else { + $session->session_data = $session_data; + + return $session->update(); + } + } + + static function destroy($id) + { + $session = Session::staticGet('id', $id); + + if (!empty($session)) { + return $session->delete(); + } + } + + static function gc($maxlifetime) + { + $epoch = time() - $maxlifetime; + + $qry = 'DELETE FROM session ' . + 'WHERE modified < "'.$epoch.'"'; + + $session = new Session(); + + $session->query($qry); + } + + static function setSaveHandler() + { + session_set_save_handler('Session::open', 'Session::close', 'Session::read', + 'Session::write', 'Session::destroy', 'Session::gc'); + } } diff --git a/lib/util.php b/lib/util.php index e5a8eaea0..b3496a09e 100644 --- a/lib/util.php +++ b/lib/util.php @@ -828,7 +828,12 @@ function common_date_iso8601($dt) function common_sql_now() { - return strftime('%Y-%m-%d %H:%M:%S', time()); + return common_sql_date(time()); +} + +function common_sql_date($datetime) +{ + return strftime('%Y-%m-%d %H:%M:%S', $datetime); } function common_redirect($url, $code=307) -- cgit v1.2.3-54-g00ecf From 71dad1ff62b842578656f34a1aa33f00399309e2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 27 Jun 2009 06:20:24 -0700 Subject: use the session class to store sessions --- README | 10 ++++++++++ index.php | 46 +++++++++++++++++++++++++++++++++------------- lib/common.php | 2 ++ lib/util.php | 3 +++ 4 files changed, 48 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/README b/README index 1a57d6a80..7f8748b3f 100644 --- a/README +++ b/README @@ -1278,6 +1278,16 @@ type: type of search. Ignored if PostgreSQL or Sphinx are enabled. Can either systems. We'll probably add another type sometime in the future, with our own indexing system (maybe like MediaWiki's). +sessions +-------- + +Session handling. + +handle: boolean. Whether we should register our own PHP session-handling + code (using the database and memcache if enabled). Defaults to false. + Setting this to true makes some sense on large or multi-server + sites, but it probably won't hurt for smaller ones, either. + Troubleshooting =============== diff --git a/index.php b/index.php index cb6a0fe60..f9b57e9d7 100644 --- a/index.php +++ b/index.php @@ -73,6 +73,38 @@ function handleError($error) exit(-1); } +function checkMirror($action_obj) +{ + global $config; + + static $alwaysRW = array('session', 'remember_me'); + + if (common_config('db', 'mirror') && $action_obj->isReadOnly($args)) { + if (is_array(common_config('db', 'mirror'))) { + // "load balancing", ha ha + $arr = common_config('db', 'mirror'); + $k = array_rand($arr); + $mirror = $arr[$k]; + } else { + $mirror = common_config('db', 'mirror'); + } + + // We ensure that these tables always are used + // on the master DB + + $config['db']['database_rw'] = $config['db']['database']; + $config['db']['ini_rw'] = INSTALLDIR.'/classes/laconica.ini'; + + foreach ($alwaysRW as $table) { + $config['db']['table_'.$table] = 'rw'; + } + + // everyone else uses the mirror + + $config['db']['database'] = $mirror; + } +} + function main() { // quick check for fancy URL auto-detection support in installer. @@ -146,19 +178,7 @@ function main() } else { $action_obj = new $action_class(); - // XXX: find somewhere for this little block to live - - if (common_config('db', 'mirror') && $action_obj->isReadOnly($args)) { - if (is_array(common_config('db', 'mirror'))) { - // "load balancing", ha ha - $arr = common_config('db', 'mirror'); - $k = array_rand($arr); - $mirror = $arr[$k]; - } else { - $mirror = common_config('db', 'mirror'); - } - $config['db']['database'] = $mirror; - } + checkMirror($action_obj); try { if ($action_obj->prepare($args)) { diff --git a/lib/common.php b/lib/common.php index bb1a4255d..3a5913f85 100644 --- a/lib/common.php +++ b/lib/common.php @@ -254,6 +254,8 @@ $config = 'oohembed' => array('endpoint' => 'http://oohembed.com/oohembed/'), 'search' => array('type' => 'fulltext'), + 'sessions' => + array('handle' => false), // whether to handle sessions ourselves ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); diff --git a/lib/util.php b/lib/util.php index b3496a09e..2face6777 100644 --- a/lib/util.php +++ b/lib/util.php @@ -144,6 +144,9 @@ function common_ensure_session() $c = $_COOKIE[session_name()]; } if (!common_have_session()) { + if (common_config('sessions', 'handle')) { + Session::setSaveHandler(); + } @session_start(); if (!isset($_SESSION['started'])) { $_SESSION['started'] = time(); -- cgit v1.2.3-54-g00ecf From 7af94dc12562b8114f0f823dc8438234125022da Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 27 Jun 2009 07:09:21 -0700 Subject: some debugging code for sessions --- classes/Session.php | 24 +++++++++++++++++++++--- lib/util.php | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/classes/Session.php b/classes/Session.php index 6f13c7d27..5c48e4aa9 100644 --- a/classes/Session.php +++ b/classes/Session.php @@ -40,6 +40,11 @@ class Session extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE + static function logdeb($msg) + { + common_debug("Session: " . $msg); + } + static function open($save_path, $session_name) { return true; @@ -52,6 +57,8 @@ class Session extends Memcached_DataObject static function read($id) { + self::logdeb("Fetching session '$id'"); + $session = Session::staticGet('id', $id); if (empty($session)) { @@ -63,6 +70,8 @@ class Session extends Memcached_DataObject static function write($id, $session_data) { + self::logdeb("Writing session '$id'"); + $session = Session::staticGet('id', $id); if (empty($session)) { @@ -82,6 +91,8 @@ class Session extends Memcached_DataObject static function destroy($id) { + self::logdeb("Deleting session $id"); + $session = Session::staticGet('id', $id); if (!empty($session)) { @@ -91,6 +102,8 @@ class Session extends Memcached_DataObject static function gc($maxlifetime) { + self::logdeb("garbage collection (maxlifetime = $maxlifetime)"); + $epoch = time() - $maxlifetime; $qry = 'DELETE FROM session ' . @@ -98,12 +111,17 @@ class Session extends Memcached_DataObject $session = new Session(); - $session->query($qry); + $result = $session->query($qry); + + self::logdeb("garbage collection result = $result"); } static function setSaveHandler() { - session_set_save_handler('Session::open', 'Session::close', 'Session::read', - 'Session::write', 'Session::destroy', 'Session::gc'); + self::logdeb("setting save handlers"); + $result = session_set_save_handler('Session::open', 'Session::close', 'Session::read', + 'Session::write', 'Session::destroy', 'Session::gc'); + self::logdeb("save handlers result = $result"); + return $result; } } diff --git a/lib/util.php b/lib/util.php index 2face6777..c8da8c7dd 100644 --- a/lib/util.php +++ b/lib/util.php @@ -145,6 +145,7 @@ function common_ensure_session() } if (!common_have_session()) { if (common_config('sessions', 'handle')) { + common_log(LOG_INFO, "Using our own session handler"); Session::setSaveHandler(); } @session_start(); -- cgit v1.2.3-54-g00ecf From 70521d55a811347fa30f37187e43b8a1fd932e21 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 27 Jun 2009 07:37:58 -0700 Subject: log IP for API auth errors --- actions/api.php | 4 +++- lib/util.php | 26 +++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/actions/api.php b/actions/api.php index 1fe5875ad..08f5fadad 100644 --- a/actions/api.php +++ b/actions/api.php @@ -67,7 +67,9 @@ class ApiAction extends Action $this->process_command(); } else { # basic authentication failed - common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname."); + list($proxy, $ip) = common_client_ip(); + + common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip."); $this->show_basic_auth_error(); } } diff --git a/lib/util.php b/lib/util.php index c8da8c7dd..9c1af7a0d 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1490,4 +1490,28 @@ function common_shorten_url($long_url) curl_close($curlh); return $short_url; -} \ No newline at end of file +} + +function common_client_ip() +{ + if (!isset($_SERVER) || !array_key_exists('REQUEST_METHOD', $_SERVER)) { + return null; + } + + if ($_SERVER['HTTP_X_FORWARDED_FOR']) { + if ($_SERVER['HTTP_CLIENT_IP']) { + $proxy = $_SERVER['HTTP_CLIENT_IP']; + } else { + $proxy = $_SERVER['REMOTE_ADDR']; + } + $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; + } else { + if ($_SERVER['HTTP_CLIENT_IP']) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } else { + $ip = $_SERVER['REMOTE_ADDR']; + } + } + + return array($ip, $proxy); +} -- cgit v1.2.3-54-g00ecf From 871f598dcc81d7018f25590d767591722bb977f2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 27 Jun 2009 08:11:09 -0700 Subject: debug flag for sessions --- README | 2 ++ classes/Session.php | 4 +++- lib/common.php | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/README b/README index 7f8748b3f..c8c529ed8 100644 --- a/README +++ b/README @@ -1287,6 +1287,8 @@ handle: boolean. Whether we should register our own PHP session-handling code (using the database and memcache if enabled). Defaults to false. Setting this to true makes some sense on large or multi-server sites, but it probably won't hurt for smaller ones, either. +debug: whether to output debugging info for session storage. Can help + with weird session bugs, sometimes. Default false. Troubleshooting =============== diff --git a/classes/Session.php b/classes/Session.php index 5c48e4aa9..93fd99baa 100644 --- a/classes/Session.php +++ b/classes/Session.php @@ -42,7 +42,9 @@ class Session extends Memcached_DataObject static function logdeb($msg) { - common_debug("Session: " . $msg); + if (common_config('sessions', 'debug')) { + common_debug("Session: " . $msg); + } } static function open($save_path, $session_name) diff --git a/lib/common.php b/lib/common.php index 3a5913f85..e2936f075 100644 --- a/lib/common.php +++ b/lib/common.php @@ -255,7 +255,8 @@ $config = 'search' => array('type' => 'fulltext'), 'sessions' => - array('handle' => false), // whether to handle sessions ourselves + array('handle' => false, // whether to handle sessions ourselves + 'debug' => false), // debugging output for sessions ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); -- cgit v1.2.3-54-g00ecf From 495c85544a740cd0330e73d9c48ca4b84f3d8e97 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 28 Jun 2009 15:21:15 -0400 Subject: don't canonicalize people's text into URLs --- lib/util.php | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 9c1af7a0d..469f132b8 100644 --- a/lib/util.php +++ b/lib/util.php @@ -500,17 +500,19 @@ function common_linkify($url) { // It comes in special'd, so we unspecial it before passing to the stringifying // functions $url = htmlspecialchars_decode($url); - $display = File_redirection::_canonUrl($url); + + $canon = File_redirection::_canonUrl($url); + $longurl_data = File_redirection::where($url); if (is_array($longurl_data)) { $longurl = $longurl_data['url']; } elseif (is_string($longurl_data)) { $longurl = $longurl_data; } else { - die('impossible to linkify'); + throw new ServerException("Can't linkify url '$url'"); } - $attrs = array('href' => $longurl, 'rel' => 'external'); + $attrs = array('href' => $canon, 'rel' => 'external'); $is_attachment = false; $attachment_id = null; @@ -528,13 +530,13 @@ function common_linkify($url) { } } -// if this URL is an attachment, then we set class='attachment' and id='attahcment-ID' -// where ID is the id of the attachment for the given URL. -// -// we need a better test telling what can be shown as an attachment -// we're currently picking up oembeds only. -// I think the best option is another file_view table in the db -// and associated dbobject. + // if this URL is an attachment, then we set class='attachment' and id='attahcment-ID' + // where ID is the id of the attachment for the given URL. + // + // we need a better test telling what can be shown as an attachment + // we're currently picking up oembeds only. + // I think the best option is another file_view table in the db + // and associated dbobject. $query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'"; $file = new File; @@ -564,7 +566,7 @@ function common_linkify($url) { $attrs['id'] = "attachment-{$attachment_id}"; } - return XMLStringer::estring('a', $attrs, $display); + return XMLStringer::estring('a', $attrs, $url); } function common_shorten_links($text) -- cgit v1.2.3-54-g00ecf From 6ca4dfa7ef42faf024599375b2ff81bfeb3d6208 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 28 Jun 2009 16:12:23 -0400 Subject: Daemon can optionally not go into the background --- lib/daemon.php | 20 +++++++++++++++----- lib/queuehandler.php | 5 +++-- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/daemon.php b/lib/daemon.php index a0df00bdc..72e8bc202 100644 --- a/lib/daemon.php +++ b/lib/daemon.php @@ -23,6 +23,13 @@ if (!defined('LACONICA')) { class Daemon { + var $daemonize = true; + + function __construct($daemonize = true) + { + $this->daemonize = $daemonize; + } + function name() { return null; @@ -129,12 +136,15 @@ class Daemon common_log(LOG_INFO, $this->name() . ' already running. Exiting.'); exit(0); } - if ($this->background()) { - $this->writePidFile(); - $this->changeUser(); - $this->run(); - $this->clearPidFile(); + + if ($this->daemonize) { + $this->background(); } + + $this->writePidFile(); + $this->changeUser(); + $this->run(); + $this->clearPidFile(); } function run() diff --git a/lib/queuehandler.php b/lib/queuehandler.php index ae403c65e..c1c4f3309 100644 --- a/lib/queuehandler.php +++ b/lib/queuehandler.php @@ -27,11 +27,12 @@ require_once(INSTALLDIR.'/classes/Notice.php'); class QueueHandler extends Daemon { - var $_id = 'generic'; - function QueueHandler($id=null) + function __construct($id=null, $daemonize=true) { + parent::__construct($daemonize); + if ($id) { $this->set_id($id); } -- cgit v1.2.3-54-g00ecf From 9f079764aa945e9e126ffa41cece17bc8951fb78 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 28 Jun 2009 16:38:27 -0400 Subject: extract log-line formatting to its own function --- lib/util.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 469f132b8..1ae43a056 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1104,15 +1104,20 @@ function common_ensure_syslog() } } +function common_log_line($priority, $msg) +{ + static $syslog_priorities = array('LOG_EMERG', 'LOG_ALERT', 'LOG_CRIT', 'LOG_ERR', + 'LOG_WARNING', 'LOG_NOTICE', 'LOG_INFO', 'LOG_DEBUG'); + return date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . "\n"; +} + function common_log($priority, $msg, $filename=null) { $logfile = common_config('site', 'logfile'); if ($logfile) { $log = fopen($logfile, "a"); if ($log) { - static $syslog_priorities = array('LOG_EMERG', 'LOG_ALERT', 'LOG_CRIT', 'LOG_ERR', - 'LOG_WARNING', 'LOG_NOTICE', 'LOG_INFO', 'LOG_DEBUG'); - $output = date('Y-m-d H:i:s') . ' ' . $syslog_priorities[$priority] . ': ' . $msg . "\n"; + $output = common_log_line($priority, $msg); fwrite($log, $output); fclose($log); } -- cgit v1.2.3-54-g00ecf From 5cc58f1e01c38fbf33f3d663231b7a66cdf3310e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 28 Jun 2009 17:38:02 -0400 Subject: note when going background --- lib/daemon.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/daemon.php b/lib/daemon.php index 72e8bc202..90dd773c6 100644 --- a/lib/daemon.php +++ b/lib/daemon.php @@ -138,6 +138,7 @@ class Daemon } if ($this->daemonize) { + common_log('Backgrounding daemon "'.$this->name().'"'); $this->background(); } -- cgit v1.2.3-54-g00ecf From 6557a569e595eee75609eb6cf12e6e788061daa9 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 28 Jun 2009 17:41:16 -0400 Subject: fix logging error --- lib/daemon.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/daemon.php b/lib/daemon.php index 90dd773c6..9d89c63e7 100644 --- a/lib/daemon.php +++ b/lib/daemon.php @@ -138,7 +138,7 @@ class Daemon } if ($this->daemonize) { - common_log('Backgrounding daemon "'.$this->name().'"'); + common_log(LOG_INFO, 'Backgrounding daemon "'.$this->name().'"'); $this->background(); } -- cgit v1.2.3-54-g00ecf From 14575fe6fc0de65f0234c73147ca877cc4c46cb8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 28 Jun 2009 19:24:14 -0400 Subject: better output for common error handler --- lib/util.php | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 1ae43a056..f9ff38c8a 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1348,18 +1348,39 @@ function common_canonical_sms($sms) function common_error_handler($errno, $errstr, $errfile, $errline, $errcontext) { switch ($errno) { + + case E_ERROR: + case E_COMPILE_ERROR: + case E_CORE_ERROR: case E_USER_ERROR: - common_log(LOG_ERR, "[$errno] $errstr ($errfile:$errline)"); - exit(1); + case E_PARSE: + case E_RECOVERABLE_ERROR: + common_log(LOG_ERR, "[$errno] $errstr ($errfile:$errline) [ABORT]"); + die(); break; + case E_WARNING: + case E_COMPILE_WARNING: + case E_CORE_WARNING: case E_USER_WARNING: common_log(LOG_WARNING, "[$errno] $errstr ($errfile:$errline)"); break; + case E_NOTICE: case E_USER_NOTICE: common_log(LOG_NOTICE, "[$errno] $errstr ($errfile:$errline)"); break; + + case E_STRICT: + case E_DEPRECATED: + case E_USER_DEPRECATED: + // XXX: config variable to log this stuff, too + break; + + default: + common_log(LOG_ERR, "[$errno] $errstr ($errfile:$errline) [UNKNOWN LEVEL, die()'ing]"); + die(); + break; } // FIXME: show error page if we're on the Web -- cgit v1.2.3-54-g00ecf