diff options
Diffstat (limited to 'modules/gallery/libraries')
-rw-r--r-- | modules/gallery/libraries/Gallery_I18n.php | 72 | ||||
-rw-r--r-- | modules/gallery/libraries/IdentityProvider.php | 5 | ||||
-rw-r--r-- | modules/gallery/libraries/MY_Kohana_Exception.php | 116 | ||||
-rw-r--r-- | modules/gallery/libraries/Menu.php | 30 | ||||
-rw-r--r-- | modules/gallery/libraries/drivers/Cache/Database.php | 14 | ||||
-rw-r--r-- | modules/gallery/libraries/drivers/IdentityProvider.php | 2 |
6 files changed, 211 insertions, 28 deletions
diff --git a/modules/gallery/libraries/Gallery_I18n.php b/modules/gallery/libraries/Gallery_I18n.php index cfed046a..f1e77744 100644 --- a/modules/gallery/libraries/Gallery_I18n.php +++ b/modules/gallery/libraries/Gallery_I18n.php @@ -73,12 +73,26 @@ class Gallery_I18n_Core { public function locale($locale=null) { if ($locale) { $this->_config['default_locale'] = $locale; - // Attempt to set PHP's locale as well (for number formatting, collation, etc.) - // TODO: See G2 for better fallack code. - $locale_prefs = array($locale); - $locale_prefs[] = 'en_US'; - $new_locale = setlocale(LC_ALL, $locale_prefs); - if (is_string($new_locale) && strpos($new_locale, 'tr') === 0) { + $php_locale = setlocale(LC_ALL, 0); + list ($php_locale, $unused) = explode('.', $php_locale . '.'); + if ($php_locale != $locale) { + // Attempt to set PHP's locale as well (for number formatting, collation, etc.) + $locale_prefs = array($locale); + // Try appending some character set names; some systems (like FreeBSD) need this. + // Some systems require a format with hyphen (eg. Gentoo) and others without (eg. FreeBSD). + $charsets = array('utf8', 'UTF-8', 'UTF8', 'ISO8859-1', 'ISO-8859-1'); + if (substr($locale, 0, 2) != 'en') { + $charsets = array_merge($charsets, array( + 'EUC', 'Big5', 'euc', 'ISO8859-2', 'ISO8859-5', 'ISO8859-7', + 'ISO8859-9', 'ISO-8859-2', 'ISO-8859-5', 'ISO-8859-7', 'ISO-8859-9')); + } + foreach ($charsets as $charset) { + $locale_prefs[] = $locale . '.' . $charset; + } + $locale_prefs[] = 'en_US'; + $php_locale = setlocale(LC_ALL, $locale_prefs); + } + if (is_string($php_locale) && substr($php_locale, 0, 2) == 'tr') { // Make PHP 5 work with Turkish (the localization results are mixed though). // Hack for http://bugs.php.net/18556 setlocale(LC_CTYPE, 'C'); @@ -136,33 +150,44 @@ class Gallery_I18n_Core { private function lookup($locale, $message) { if (!isset($this->_cache[$locale])) { - $this->_cache[$locale] = array(); - // TODO: Load data from locale file instead of the DB. + $this->_cache[$locale] = self::load_translations($locale); + } + + $key = self::get_message_key($message); + + if (isset($this->_cache[$locale][$key])) { + return $this->_cache[$locale][$key]; + } else { + return null; + } + } + + private static function load_translations($locale) { + $cache_key = "translation|" . $locale; + $cache = Cache::instance(); + $translations = $cache->get($cache_key); + if (!isset($translations) || !is_array($translations)) { + $translations = array(); foreach (db::build() ->select("key", "translation") ->from("incoming_translations") ->where("locale", "=", $locale) ->execute() as $row) { - $this->_cache[$locale][$row->key] = unserialize($row->translation); + $translations[$row->key] = unserialize($row->translation); } - + // Override incoming with outgoing... foreach (db::build() ->select("key", "translation") ->from("outgoing_translations") ->where("locale", "=", $locale) ->execute() as $row) { - $this->_cache[$locale][$row->key] = unserialize($row->translation); + $translations[$row->key] = unserialize($row->translation); } + + $cache->set($cache_key, $translations, array("translation"), 0); } - - $key = self::get_message_key($message); - - if (isset($this->_cache[$locale][$key])) { - return $this->_cache[$locale][$key]; - } else { - return null; - } + return $translations; } public function has_translation($message, $options=null) { @@ -242,6 +267,15 @@ class Gallery_I18n_Core { return $this->_call_log; } + public static function clear_cache($locale=null) { + $cache = Cache::instance(); + if ($locale) { + $cache->delete("translation|" . $locale); + } else { + $cache->delete_tag("translation"); + } + } + private static function get_plural_key($locale, $count) { $parts = explode('_', $locale); $language = $parts[0]; diff --git a/modules/gallery/libraries/IdentityProvider.php b/modules/gallery/libraries/IdentityProvider.php index 3f1666eb..01ea9ad7 100644 --- a/modules/gallery/libraries/IdentityProvider.php +++ b/modules/gallery/libraries/IdentityProvider.php @@ -66,6 +66,11 @@ class IdentityProvider_Core { } static function change_provider($new_provider) { + if (!identity::active_user()->admin && PHP_SAPI != "cli") { + // Below, the active user is set to the primary admin. + access::forbidden(); + } + $current_provider = module::get_var("gallery", "identity_provider"); if (!empty($current_provider)) { module::uninstall($current_provider); diff --git a/modules/gallery/libraries/MY_Kohana_Exception.php b/modules/gallery/libraries/MY_Kohana_Exception.php index 1c40091a..1712d895 100644 --- a/modules/gallery/libraries/MY_Kohana_Exception.php +++ b/modules/gallery/libraries/MY_Kohana_Exception.php @@ -33,6 +33,120 @@ class Kohana_Exception extends Kohana_Exception_Core { if ($e instanceof ORM_Validation_Exception) { Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1)); } - return parent::handle($e); + try { + $user = identity::active_user(); + $try_themed_view = $user && !$user->admin; + } catch (Exception $e2) { + $try_themed_view = false; + } + + if ($try_themed_view) { + try { + return self::_show_themed_error_page($e); + } catch (Exception $e3) { + Kohana_Log::add("error", "Exception in exception handling code: " . self::text($e3)); + return parent::handle($e); + } + } else { + return parent::handle($e); + } + } + + /** + * Shows a themed error page. + * @see Kohana_Exception::handle + */ + private static function _show_themed_error_page(Exception $e) { + // Create a text version of the exception + $error = Kohana_Exception::text($e); + + // Add this exception to the log + Kohana_Log::add('error', $error); + + // Manually save logs after exceptions + Kohana_Log::save(); + + if (!headers_sent()) { + if ($e instanceof Kohana_Exception) { + $e->sendHeaders(); + } else { + header("HTTP/1.1 500 Internal Server Error"); + } + } + + $view = new Theme_View("page.html", "other", "error"); + if ($e instanceof Kohana_404_Exception) { + $view->page_title = t("Dang... Page not found!"); + $view->content = new View("error_404.html"); + $user = identity::active_user(); + $view->content->is_guest = $user && $user->guest; + if ($view->content->is_guest) { + $view->content->login_form = new View("login_ajax.html"); + $view->content->login_form->form = auth::get_login_form("login/auth_html"); + // Avoid anti-phishing protection by passing the url as session variable. + Session::instance()->set("continue_url", url::current(true)); + } + } else { + $view->page_title = t("Dang... Something went wrong!"); + $view->content = new View("error.html"); + } + print $view; + } + + /** + * @see Kohana_Exception::dump() + */ + public static function dump($value, $length=128, $max_level=5) { + return self::safe_dump($value, null, $length, $max_level); + } + + /** + * A safer version of dump(), eliding sensitive information in the dumped + * data, such as session ids and passwords / hashes. + */ + public static function safe_dump($value, $key, $length=128, $max_level=5) { + return parent::dump(self::_sanitize_for_dump($value, $key), $length, $max_level); + } + + /** + * Elides sensitive data which shouldn't be echoed to the client, + * such as passwords, and other secrets. + */ + /* Visible for testing*/ static function _sanitize_for_dump($value, $key=null) { + // Better elide too much than letting something through. + // Note: unanchored match is intended. + $sensitive_info_pattern = + '/(password|pass|email|hash|private_key|session_id|session|g3sid|csrf|secret)/i'; + if (preg_match($sensitive_info_pattern, $key) || + (is_string($value) && preg_match('/[a-f0-9]{20,}/i', $value))) { + return 'removed for display'; + } else if (is_object($value)) { + if ($value instanceof Database) { + // Elide database password, host, name, user, etc. + return get_class($value) . ' object - details omitted for display'; + } else if ($value instanceof User_Model) { + return get_class($value) . ' object for "' . $value->name . '" - details omitted for display'; + } + return self::_sanitize_for_dump((array) $value, $key); + } else if (is_array($value)) { + $result = array(); + foreach ($value as $k => $v) { + $actual_key = $k; + $key_for_display = $k; + if ($k[0] === "\x00") { + // Remove the access level from the variable name + $actual_key = substr($k, strrpos($k, "\x00") + 1); + $access = $k[1] === '*' ? 'protected' : 'private'; + $key_for_display = "$access: $actual_key"; + } + if (is_object($v)) { + $key_for_display .= ' (type: ' . get_class($v) . ')'; + } + $result[$key_for_display] = self::_sanitize_for_dump($v, $actual_key); + } + } else { + $result = $value; + } + return $result; } }
\ No newline at end of file diff --git a/modules/gallery/libraries/Menu.php b/modules/gallery/libraries/Menu.php index e2b68d1a..fef07916 100644 --- a/modules/gallery/libraries/Menu.php +++ b/modules/gallery/libraries/Menu.php @@ -184,7 +184,7 @@ class Menu_Core extends Menu_Element { } /** - * Add a new element to this menu + * Add a new element to this menu, after the specific element */ public function add_after($target_id, $new_menu_element) { $copy = array(); @@ -199,6 +199,21 @@ class Menu_Core extends Menu_Element { } /** + * Add a new element to this menu, before the specific element + */ + public function add_before($target_id, $new_menu_element) { + $copy = array(); + foreach ($this->elements as $id => $menu_element) { + if ($id == $target_id) { + $copy[$new_menu_element->id] = $new_menu_element; + } + $copy[$id] = $menu_element; + } + $this->elements = $copy; + return $this; + } + + /** * Remove an element from the menu */ public function remove($target_id) { @@ -216,6 +231,19 @@ class Menu_Core extends Menu_Element { return null; } + public function is_empty() { + foreach ($this->elements as $element) { + if ($element instanceof Menu) { + if (!$element->is_empty()) { + return false; + } + } else { + return false; + } + } + return true; + } + public function render() { $view = new View(isset($this->view) ? $this->view : "menu.html"); $view->menu = $this; diff --git a/modules/gallery/libraries/drivers/Cache/Database.php b/modules/gallery/libraries/drivers/Cache/Database.php index 82a09ab9..ff982396 100644 --- a/modules/gallery/libraries/drivers/Cache/Database.php +++ b/modules/gallery/libraries/drivers/Cache/Database.php @@ -130,7 +130,7 @@ class Cache_Database_Driver extends Cache_Driver { // Make sure the expiration is valid and that the hash matches if ($cache->expiration != 0 && $cache->expiration <= time()) { // Cache is not valid, delete it now - $this->delete($cache->id); + $this->delete(array($cache->id)); } else { // Disable notices for unserializing $ER = error_reporting(~E_NOTICE); @@ -153,15 +153,17 @@ class Cache_Database_Driver extends Cache_Driver { * @param bool delete a tag * @return bool */ - public function delete($id, $tag=false) { + public function delete($keys, $is_tag=false) { $db = db::build() ->delete("caches"); - if ($id === true) { + if ($keys === true) { // Delete all caches - } else if ($tag === true) { - $db->where("tags", "LIKE", "%<$id>%"); + } else if ($is_tag === true) { + foreach ($keys as $tag) { + $db->where("tags", "LIKE", "%<$tag>%"); + } } else { - $db->where("key", "=", $id); + $db->where("key", "IN", $keys); } $status = $db->execute(); diff --git a/modules/gallery/libraries/drivers/IdentityProvider.php b/modules/gallery/libraries/drivers/IdentityProvider.php index b7b1fbe8..09cdd093 100644 --- a/modules/gallery/libraries/drivers/IdentityProvider.php +++ b/modules/gallery/libraries/drivers/IdentityProvider.php @@ -26,7 +26,7 @@ interface IdentityProvider_Driver { public function guest(); /** - * Return the admins user. + * Return the primary admin user. * * @return User_Definition the user object */ |