--- a/includes/cache.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/cache.php Mon Nov 19 11:40:35 2012 -0500
@@ -21,6 +21,59 @@
class CacheManager
{
+ public static function factory($backend = 'auto')
+ {
+ if ( function_exists('xcache_set') )
+ return new CacheManager_XCache();
+ else
+ return new CacheManager_File();
+ }
+}
+
+class CacheManager_XCache
+{
+ private $prefix;
+
+ /**
+ * Constructor. Merely generates the prefix that will be prepended to cache objects.
+ */
+
+ public function __construct()
+ {
+ global $crypto_key;
+ $this->prefix = 'enano' . substr(md5($crypto_key), 0, 8) . '_';
+ }
+
+ /**
+ * @see CacheManager_File::fetch()
+ */
+
+ public function fetch($cache_id)
+ {
+ return xcache_isset($this->prefix . $cache_id) ? xcache_get($this->prefix . $cache_id) : false;
+ }
+
+ /**
+ * @see CacheManager_File::store()
+ */
+
+ public function store($cache_id, $data, $ttl = 20)
+ {
+ return xcache_set($this->prefix . $cache_id, $data, $ttl * 60);
+ }
+
+ /**
+ * @see CacheManager_File::purge()
+ */
+
+ public function purge($cache_id)
+ {
+ return xcache_unset($this->prefix . $cache_id);
+ }
+}
+
+class CacheManager_File
+{
/**
* Fetch a cached piece of data.
* @param string Cache ID. The timestamp is checked automatically.
--- a/includes/clientside/static/login.js Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/clientside/static/login.js Mon Nov 19 11:40:35 2012 -0500
@@ -753,9 +753,9 @@
if ( !show_captcha )
links.innerHTML += $lang.get('user_login_ajax_link_fullform', { link_full_form: makeUrlNS('Special', 'Login/' + title) }) + ' • ';
// Always shown
- links.innerHTML += $lang.get('user_login_ajax_link_forgotpass', { forgotpass_link: makeUrlNS('Special', 'PasswordReset') }) + ' • ';
+ links.innerHTML += $lang.get('user_login_ajax_link_forgotpass', { forgotpass_link: makeUrlNS('Special', 'PasswordReset') });
if ( !show_captcha )
- links.innerHTML += $lang.get('user_login_ajax_createaccount_blurb', { reg_link: makeUrlNS('Special', 'Register') });
+ links.innerHTML += ' • ' + $lang.get('user_login_ajax_createaccount_blurb', { reg_link: makeUrlNS('Special', 'Register') });
div.appendChild(links);
}
--- a/includes/common.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/common.php Mon Nov 19 11:40:35 2012 -0500
@@ -355,7 +355,7 @@
profiler_log('Ran checks');
// Init cache
-$cache = new CacheManager();
+$cache = CacheManager::factory();
// Load plugin manager
$plugins = new pluginLoader();
--- a/includes/common_cli.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/common_cli.php Mon Nov 19 11:40:35 2012 -0500
@@ -125,7 +125,7 @@
profiler_log('Ran checks');
// Init cache
-$cache = new CacheManager();
+$cache = CacheManager::factory();
// Load plugin manager
$plugins = new pluginLoader();
--- a/includes/dbal.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/dbal.php Mon Nov 19 11:40:35 2012 -0500
@@ -208,7 +208,19 @@
$host_line = ( preg_match('/^:/', $dbhost) ) ? $dbhost : "{$dbhost}:{$dbport}";
- $this->_conn = @mysql_connect($host_line, $dbuser, $dbpasswd);
+ // Try a peristent connection twice
+ // http://us2.php.net/manual/en/function.mysql-pconnect.php#99380
+ $this->_conn = @mysql_pconnect($host_line, $dbuser, $dbpasswd);
+ if ( !@mysql_query("SELECT 1;", $this->_conn) )
+ {
+ $this->_conn = @mysql_pconnect($host_line, $dbuser, $dbpasswd);
+ if ( !@mysql_query("SELECT 1;", $this->_conn) )
+ {
+ // if that doesn't work, use a normal connection
+ $this->_conn = @mysql_connect($host_line, $dbuser, $dbpasswd);
+ trigger_error(E_USER_WARNING, "Forced to use nonpersistent mysql connection");
+ }
+ }
unset($dbuser);
unset($dbpasswd); // Security
@@ -536,6 +548,9 @@
function close()
{
+ // anything we locked should certainly be unlocked now;
+ @mysql_query("COMMIT;", $this->_conn);
+ @mysql_query("UNLOCK TABLES;", $this->_conn);
@mysql_close($this->_conn);
unset($this->_conn);
}
--- a/includes/functions.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/functions.php Mon Nov 19 11:40:35 2012 -0500
@@ -589,7 +589,7 @@
{
header('Location: ' . $url);
header('Content-length: 0');
- header('HTTP/1.1 307 Temporary Redirect');
+ header('HTTP/1.1 302 Found');
// with 3xx codes HTTP clients expect a response of 0 bytes, so just die here
exit();
--- a/includes/output.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/output.php Mon Nov 19 11:40:35 2012 -0500
@@ -273,6 +273,41 @@
}
/**
+ * Output engine that sends data using Comet. This allows incremental pushing of data.
+ * Note that this tends to not work with every server.
+ */
+
+class Output_Comet extends Output_Naked
+{
+ /**
+ * Be warned: this header function will flush ALL output buffers!
+ */
+
+ public function header()
+ {
+ while ( ob_get_level() )
+ ob_end_flush();
+ }
+
+ /**
+ * Write data and immediately send it to the client.
+ * @param string Data to write
+ */
+
+ public function write($data)
+ {
+ echo $data;
+ flush();
+ if ( $data === 'STOP' || !stristr(@$_SERVER['HTTP_USER_AGENT'], 'gecko') || stristr(@$_SERVER['HTTP_USER_AGENT'], 'like gecko') )
+ {
+ global $db;
+ $db->close();
+ exit;
+ }
+ }
+}
+
+/**
* Safe template outputter
*/
--- a/includes/plugins.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/plugins.php Mon Nov 19 11:40:35 2012 -0500
@@ -27,7 +27,23 @@
* @access private
*/
- var $hook_list;
+ var $hook_list = array();
+
+ /**
+ * List of hooks which are lambda (anonymous) functions
+ * @var array
+ * @access private
+ */
+
+ var $hook_list_lambda = array();
+
+ /**
+ * Temporary array which holds closures currently being called
+ * @var array
+ * @access private Technically public access, but seriously just don't touch it
+ */
+
+ var $__current_hook = array();
/**
* The list of plugins that should be loaded. Used only by common.php.
@@ -104,6 +120,12 @@
function setHook($name, $dont_split = false)
{
+ if ( !empty($this->hook_list_lambda[$name]) )
+ {
+ $this->__current_hook =& $this->hook_list_lambda[$name];
+ // This is kind of terrible right now, I'm not sure how to handle inheritance and such.
+ $this->attachHook($name, 'foreach ( $plugins->__current_hook as $func ) { call_user_func($func); }; unset($plugins->__current_hook);');
+ }
if ( !empty($this->hook_list[$name]) && is_array($this->hook_list[$name]) )
{
if ( $dont_split )
@@ -136,11 +158,22 @@
function attachHook($name, $code)
{
- if ( !isset($this->hook_list[$name]) )
+ if ( is_callable($code) )
{
- $this->hook_list[$name] = Array();
+ if ( !isset($this->hook_list_lambda[$name]) )
+ {
+ $this->hook_list_lambda[$name] = Array();
+ }
+ $this->hook_list_lambda[$name][] = $code;
}
- $this->hook_list[$name][] = $code;
+ else
+ {
+ if ( !isset($this->hook_list[$name]) )
+ {
+ $this->hook_list[$name] = Array();
+ }
+ $this->hook_list[$name][] = $code;
+ }
}
/**
--- a/includes/search.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/search.php Mon Nov 19 11:40:35 2012 -0500
@@ -276,7 +276,7 @@
if ( strstr($word_cs, $qword) )
$lev_array[ $qword ] = levenshtein($qword, $word_cs);
}
- if ( min($lev_array) > 3 )
+ if ( count($lev_array) && min($lev_array) > 3 )
{
$inc /= array_sum($lev_array) / count($lev_array);
}
--- a/includes/sessions.php Sat Sep 15 13:16:59 2012 -0400
+++ b/includes/sessions.php Mon Nov 19 11:40:35 2012 -0500
@@ -3500,7 +3500,7 @@
else if ( $prev_l == 'p' && mt_rand(0, 5) == 1 )
$word .= 'h';
// this rule allows "ck" which can result in the occasional "dick", "fuck", etc. that tends
- // to end up on 4chan, but I decided to keep it, because it increases word complexity.
+ // to end up on /r/funny, but I decided to keep it, because it increases word complexity.
else if ( $prev_l == 'c' && mt_rand(0, 3) == 1 )
$word .= 'k';
else if ( $prev_l == 'q' && mt_rand(0, 5) != 1 )
--- a/language/english/admin.json Sat Sep 15 13:16:59 2012 -0400
+++ b/language/english/admin.json Mon Nov 19 11:40:35 2012 -0500
@@ -447,7 +447,7 @@
field_avatar_max_dimensions_hint: 'The format is width × height. Typically you want to have this square (the same width and height). These are only maximum dimensions; users are not prevented from having smaller images.',
field_avatar_allow_anim_title: 'Allow animated avatars:',
field_avatar_allow_anim_hint: 'If this is checked, users can upload APNG and Animated GIF℠ avatars. Sometimes such images can be specifically made to be distracting, like rapidly flashing images. If this is unchecked, these formats will be blocked, and only still PNGs and GIFs will be allowed.',
- field_avatar_allow_anim: 'Don\'t block animated images',
+ field_avatar_allow_anim: 'Allow animated images',
field_avatar_upload_methods: 'Allowed upload methods:',
field_avatar_upload_file: 'Allow users to upload image files from their computers',
field_avatar_upload_http: 'Allow users to enter a URL to their desired avatar',
--- a/plugins/SpecialSearch.php Sat Sep 15 13:16:59 2012 -0400
+++ b/plugins/SpecialSearch.php Mon Nov 19 11:40:35 2012 -0500
@@ -137,7 +137,18 @@
$result['page_text'] = str_replace(array('<highlight>', '</highlight>'), array('<span class="search-term">', '</span>'), $result['page_text']);
if ( !empty($result['page_text']) )
$result['page_text'] .= '<br />';
- $result['page_name'] = str_replace(array('<highlight>', '</highlight>'), array('<span class="title-search-term">', '</span>'), $result['page_name']);
+
+ // localize the title... if it comes back from the language code, replace the title, losing highlighting.
+ // otherwise, keep the highlighted title from the search backend
+ if ( ($l10n_title = $lang->get(strip_tags($result['page_name']))) !== strip_tags($result['page_name']) )
+ {
+ $result['page_name'] = $l10n_title;
+ }
+ else
+ {
+ $result['page_name'] = str_replace(array('<highlight>', '</highlight>'), array('<span class="title-search-term">', '</span>'), $result['page_name']);
+ }
+
$result['url_highlight'] = str_replace(array('<highlight>', '</highlight>'), array('<span class="url-search-term">', '</span>'), $result['url_highlight']);
if ( $result['page_length'] >= 1048576 )
{