From 19ef3412e28c6b21d74de94038ac80f9de6cb599 Mon Sep 17 00:00:00 2001 From: rurban Date: Mon, 24 Aug 2009 12:16:57 +0000 Subject: [PATCH] add READONLY git-svn-id: svn://svn.code.sf.net/p/phpwiki/code/trunk@7078 96ab9672-09ca-45d6-a79d-3d69d39ca109 --- lib/DbaDatabase.php | 31 ++++++++++++++++++++++++++++--- lib/IniConfig.php | 7 +++++-- lib/PagePerm.php | 8 ++++++++ lib/WikiDB.php | 26 ++++++++++++++++++++++++++ lib/WikiUserNew.php | 6 +++++- lib/main.php | 5 +++-- 6 files changed, 75 insertions(+), 8 deletions(-) diff --git a/lib/DbaDatabase.php b/lib/DbaDatabase.php index fab0459b9..12ac0cb9d 100644 --- a/lib/DbaDatabase.php +++ b/lib/DbaDatabase.php @@ -19,6 +19,7 @@ class DbaDatabase _("Supported handlers are: %s"), $handler, join(",",dba_handlers()))); } + $this->readonly = false; if ($mode) $this->open($mode); } @@ -42,6 +43,10 @@ class DbaDatabase echo "You don't seem to have DBA support compiled into PHP."; } + if (READONLY) { + $mode = 'r'; + } + // lock supported since 4.3.0: if (check_php_version(4,3,0) and (strlen($mode) == 1)) { // PHP 4.3.x Windows lock bug workaround: http://bugs.php.net/bug.php?id=23975 @@ -54,9 +59,19 @@ class DbaDatabase while (($dbh = dba_open($this->_file, $mode, $this->_handler)) < 1) { if ($watchdog <= 0) break; - flush(); // "c" failed, try "w" instead. - if (substr($mode,0,1) == "c" and file_exists($this->_file)) + if ($mode == "w" + and file_exists($this->_file) + and (isWindows() or !is_writable($this->_file))) + { + // try to continue with read-only + if (!defined("READONLY")) + define("READONLY", true); + $GLOBALS['request']->_dbi->readonly = true; + $this->readonly = true; + $mode = "r"; + } + if (substr($mode,0,1) == "c" and file_exists($this->_file) and !READONLY) $mode = "w"; // conflict: wait some random time to unlock (as with ethernet) $secs = 0.5 + ((double)rand(1,32767)/32767); @@ -72,7 +87,15 @@ class DbaDatabase $error->errstr .= "\nfile: " . $this->_file . "\nmode: " . $mode . "\nhandler: " . $this->_handler; - $ErrorManager->handleError($error); + // try to continue with read-only + if (!defined("READONLY")) + define("READONLY", true); + $GLOBALS['request']->_dbi->readonly = true; + $this->readonly = true; + if (!file_exist($this->_file)) { + $ErrorManager->handleError($error); + flush(); + } } else { trigger_error("dba_open failed", E_USER_ERROR); @@ -119,6 +142,7 @@ class DbaDatabase } function delete($key) { + if ($this->readonly) return; if (!dba_delete($key, $this->_dbh)) return $this->_error("delete($key)"); } @@ -129,6 +153,7 @@ class DbaDatabase function set($key, $val) { $dbh = &$this->_dbh; + if ($this->readonly) return; if (dba_exists($key, $dbh)) { if ($val !== false) { if (!dba_replace($key, $val, $dbh)) diff --git a/lib/IniConfig.php b/lib/IniConfig.php index 174a4d858..58bba1e02 100644 --- a/lib/IniConfig.php +++ b/lib/IniConfig.php @@ -203,7 +203,8 @@ function IniConfig($file) { 'ENABLE_SEARCHHIGHLIGHT', 'DISABLE_UPLOAD_ONLY_ALLOWED_EXTENSIONS', 'ENABLE_AUTH_OPENID', 'INSECURE_ACTIONS_LOCALHOST_ONLY', 'ENABLE_MAILNOTIFY', 'ENABLE_RECENTCHANGESBOX', 'ENABLE_PAGE_PUBLIC', - 'ENABLE_AJAX', 'ENABLE_EXTERNAL_PAGES' + 'ENABLE_AJAX', 'ENABLE_EXTERNAL_PAGES', + 'READONLY' ); $rs = @parse_ini_file($file); @@ -267,7 +268,7 @@ function IniConfig($file) { 'ALLOW_IMAP_LOGIN', 'ALLOW_USER_LOGIN', 'REQUIRE_SIGNIN_BEFORE_EDIT', 'WIKIDB_NOCACHE_MARKUP', - 'COMPRESS_OUTPUT', 'USE_BYTEA' + 'COMPRESS_OUTPUT', 'USE_BYTEA', 'READONLY', ))) { ; @@ -331,6 +332,8 @@ function IniConfig($file) { E_USER_ERROR); } } + // Detect readonly database, e.g. system mounted read-only for maintenance + // via dbh->readonly later. Unfortunately not possible as constant. // USE_DB_SESSION default logic: if (!defined('USE_DB_SESSION')) { diff --git a/lib/PagePerm.php b/lib/PagePerm.php index 12ddd02a1..049788168 100644 --- a/lib/PagePerm.php +++ b/lib/PagePerm.php @@ -234,12 +234,20 @@ function _requiredAuthorityForPagename($access, $pagename) { global $request; $page = $request->getPage($pagename); + + // Exceptions: if (defined('GFORGE') and GFORGE) { if ($pagename != '.' && isset($request->_user->_is_external) && $request->_user->_is_external && ! $page->get('external')) { $permcache[$pagename][$access] = 0; return 0; } } + if ((READONLY or $request->_dbi->readonly) + and in_array($access, array('edit','create','change'))) + { + return 0; + } + // Page not found; check against default permissions if (! $page->exists() ) { $perm = new PagePermission(); diff --git a/lib/WikiDB.php b/lib/WikiDB.php index 7e2b779e7..75d9c1fcd 100644 --- a/lib/WikiDB.php +++ b/lib/WikiDB.php @@ -91,6 +91,10 @@ class WikiDB { * * Which dba handler to use. Good choices are probably either * 'gdbm' or 'db2'. + * + *
readonly + *
Either set by config.ini: READONLY = true or detected automatically + * when a database can be read but cannot be updated. * * * @return WikiDB A WikiDB object. @@ -126,6 +130,8 @@ class WikiDB { if ((int)DEBUG & _DEBUG_SQL) { $this->_backend->check(); } + // might be changed when opening the database fails + $this->readonly = defined("READONLY") ? READONLY : false; } /** @@ -210,6 +216,7 @@ class WikiDB { * @see purgePage */ function deletePage($pagename) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } // don't create empty revisions of already purged pages. if ($this->_backend->get_latest_version($pagename)) $result = $this->_cache->delete_page($pagename); @@ -242,6 +249,7 @@ class WikiDB { * @see deletePage */ function purgePage($pagename) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $result = $this->_cache->purge_page($pagename); $this->deletePage($pagename); // just for the notification return $result; @@ -511,6 +519,7 @@ class WikiDB { * @return boolean true or false */ function renamePage($from, $to, $updateWikiLinks = false) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } assert(is_string($from) && $from != ''); assert(is_string($to) && $to != ''); $result = false; @@ -662,6 +671,7 @@ class WikiDB { * @param string $newval New value. */ function set($key, $newval) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } if (!$key || $key[0] == '%') return; @@ -790,6 +800,7 @@ class WikiDB_Page * use a WikiDB_PageRevision object here.) */ function deleteRevision($version) { + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $backend = &$this->_wikidb->_backend; $cache = &$this->_wikidb->_cache; $pagename = &$this->_pagename; @@ -839,6 +850,7 @@ class WikiDB_Page * */ function mergeRevision($version) { + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $backend = &$this->_wikidb->_backend; $cache = &$this->_wikidb->_cache; $pagename = &$this->_pagename; @@ -905,6 +917,7 @@ class WikiDB_Page * $version was incorrect, returns false */ function createRevision($version, &$content, $metadata, $links) { + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $backend = &$this->_wikidb->_backend; $cache = &$this->_wikidb->_cache; $pagename = &$this->_pagename; @@ -983,6 +996,7 @@ class WikiDB_Page * @param hash $meta Meta-data for new revision. */ function save($wikitext, $version, $meta, $formatted = null) { + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } if (is_null($formatted)) $formatted = new TransformedText($this, $wikitext, $meta); $type = $formatted->getType(); @@ -1317,6 +1331,7 @@ class WikiDB_Page and $key == '_cached_html' and method_exists($backend, 'set_cached_html')) { + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } return $backend->set_cached_html($pagename, $newval); } @@ -1331,6 +1346,7 @@ class WikiDB_Page return; // values identical, skip update. } + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $cache->update_pagedata($pagename, array($key => $newval)); } @@ -1351,6 +1367,7 @@ class WikiDB_Page * @access public */ function increaseHitCount() { + if ($this->_wikidb->readonly) { trigger_error("readonly database", E_USER_NOTICE); return; } if (method_exists($this->_wikidb->_backend, 'increaseHitCount')) $this->_wikidb->_backend->increaseHitCount($this->_pagename); else { @@ -2084,6 +2101,9 @@ class WikiDB_cache array_push ($this->_versiondata_cache, array()); $this->_glv_cache = array(); $this->_id_cache = array(); // formerly ->_dbi->_iwpcache (nonempty pages => id) + + if (isset($GLOBALS['request']->_dbi)) + $this->readonly = $GLOBALS['request']->_dbi->readonly; } function close() { @@ -2110,6 +2130,7 @@ class WikiDB_cache function update_pagedata($pagename, $newdata) { assert(is_string($pagename) && $pagename != ''); + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $this->_backend->update_pagedata($pagename, $newdata); @@ -2134,12 +2155,14 @@ class WikiDB_cache } function delete_page($pagename) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $result = $this->_backend->delete_page($pagename); $this->invalidate_cache($pagename); return $result; } function purge_page($pagename) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $result = $this->_backend->purge_page($pagename); $this->invalidate_cache($pagename); return $result; @@ -2192,6 +2215,7 @@ class WikiDB_cache function set_versiondata($pagename, $version, $data) { //unset($this->_versiondata_cache[$pagename][$version]); + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $new = $this->_backend->set_versiondata($pagename, $version, $data); // Update the cache $this->_versiondata_cache[$pagename][$version]['1'] = $data; @@ -2201,6 +2225,7 @@ class WikiDB_cache } function update_versiondata($pagename, $version, $data) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $new = $this->_backend->update_versiondata($pagename, $version, $data); // Update the cache $this->_versiondata_cache[$pagename][$version]['1'] = $data; @@ -2211,6 +2236,7 @@ class WikiDB_cache } function delete_versiondata($pagename, $version) { + if ($this->readonly) { trigger_error("readonly database", E_USER_WARNING); return; } $new = $this->_backend->delete_versiondata($pagename, $version); if (isset($this->_versiondata_cache[$pagename][$version])) unset ($this->_versiondata_cache[$pagename][$version]); diff --git a/lib/WikiUserNew.php b/lib/WikiUserNew.php index 39ef05c22..37e7b1c93 100644 --- a/lib/WikiUserNew.php +++ b/lib/WikiUserNew.php @@ -930,7 +930,11 @@ extends _AnonUser // Check the configured Prefs methods $dbi = $this->getAuthDbh(); $dbh = $GLOBALS['request']->getDbh(); - if ( $dbi and !isset($this->_prefs->_select) and $dbh->getAuthParam('pref_select')) { + if ( $dbi + and !$dbh->readonly + and !isset($this->_prefs->_select) + and $dbh->getAuthParam('pref_select')) + { if (!$this->_prefs) { $this->_prefs = new UserPreferences(); $need_pref = true; diff --git a/lib/main.php b/lib/main.php index 5b303f856..5b963fecf 100644 --- a/lib/main.php +++ b/lib/main.php @@ -77,8 +77,9 @@ class WikiRequest extends Request { if (USE_DB_SESSION) { include_once('lib/DbSession.php'); $dbi =& $this->_dbi; - $this->_dbsession = new DbSession($dbi, $dbi->getParam('prefix') - . $dbi->getParam('db_session_table')); + if (!READONLY) + $this->_dbsession = new DbSession($dbi, $dbi->getParam('prefix') + . $dbi->getParam('db_session_table')); } // Fixme: Does pear reset the error mask to 1? We have to find the culprit -- 2.45.0