diff -urpN drupal-6.x-dev-200708231745/includes/bootstrap.inc drupal-6.x-dev-access-0.4.2/includes/bootstrap.inc
--- drupal-6.x-dev-200708231745/includes/bootstrap.inc 2007-08-07 16:41:24.000000000 +0800
+++ drupal-6.x-dev-access-0.4.2/includes/bootstrap.inc 2007-08-23 18:14:31.000000000 +0800
@@ -792,11 +792,60 @@ function drupal_get_messages($type = NUL
}
/**
+ * Initialize the access strategy.
+ */
+function _drupal_access_init() {
+ // NOTE: caching the access rules improves performance by 5% when serving cached pages.
+ $accesses = array();
+ if ($cached = cache_get('accesses', 'cache')) {
+ $accesses = $cached->data;
+ }
+ else {
+ $result = db_query('SELECT * FROM {access}');
+
+ // Classify, group and preprocess fetched access rules.
+ $array = array();
+ while ($rule = db_fetch_object($result)) {
+ $type = $rule->type;
+ $status = $rule->status ? 'allow' : 'deny';
+ $mask = $rule->mask;
+
+ // Mask is not starting with '^': in plain text format. Escape it
+ // with preg_quote().
+ if (substr($mask, 0, 1) != '^') {
+ $plain[$type][$status][] = '^' . preg_quote($mask) . '$';
+ }
+ // Mask is starting with '^': in regex expression. Use directly without
+ // additional processing.
+ else {
+ $regex[$type][$status][] = $mask;
+ }
+
+ // Record which type of rules are existing.
+ $record[$type][$status] = TRUE;
+ }
+
+ // Build regex expression for caching.
+ foreach ($record as $type => $tmp) {
+ foreach ($tmp as $status => $mask) {
+ // NOTE: non-regexp matches are always done first.
+ $rules = array_merge((array) $plain[$type][$status], (array) $regex[$type][$status]);
+ $accesses[$type][$status] = '/' . implode('|', $rules) . '/Ds';
+ }
+ }
+
+ cache_set('accesses', $accesses);
+ }
+
+ return $accesses;
+}
+
+/**
* Perform an access check for a given mask and rule type. Rules are usually
* created via admin/user/rules page.
*
- * If any allow rule matches, access is allowed. Otherwise, if any deny rule
- * matches, access is denied. If no rule matches, access is allowed.
+ * If any deny rule matches, access is denied. By the way, if any allow rule
+ * matches, access is allowed. If no rule matches, access is allowed.
*
* @param $type string
* Type of access to check: Allowed values are:
@@ -804,25 +853,33 @@ function drupal_get_messages($type = NUL
* - 'mail': e-mail address
* - 'user': username
* @param $mask string
- * String or mask to test: '_' matches any character, '%' matches any
- * number of characters.
+ * String to test.
* @return bool
* TRUE if access is denied, FALSE if access is allowed.
*/
function drupal_is_denied($type, $mask) {
- // Because this function is called for every page request, both cached
- // and non-cached pages, we tried to optimize it as much as possible.
- // We deny access if the only matching records in the {access} table have
- // status 0. If any have status 1, or if there are no matching records,
- // we allow access. So, select matching records in decreasing order of
- // 'status', returning NOT(status) for the first. If any have status 1,
- // they come first, and we return NOT(status) = 0 (allowed). Otherwise,
- // if we have some with status 0, we return 1 (denied). If no matching
- // records, we get no return from db_result, so we return (bool)NULL = 0
- // (allowed).
- // The use of ORDER BY / LIMIT is more efficient than "MAX(status) = 0"
- // in PostgreSQL <= 8.0.
- return (bool) db_result(db_query_range("SELECT CASE WHEN status=1 THEN 0 ELSE 1 END FROM {access} WHERE type = '%s' AND LOWER(mask) LIKE LOWER('%s') ORDER BY status DESC", $type, $mask, 0, 1));
+ global $access;
+
+ // First of all, assume access is allowed.
+ $denied = FALSE;
+
+ // Check if deny rules exists.
+ if (isset($access[$type]['deny']) && $access[$type]['deny']) {
+ // If any deny rule matches, access is denied.
+ if (preg_match($access[$type]['deny'], $mask)) {
+ $denied = TRUE;
+ }
+ }
+
+ // Check if allow rules exists.
+ if (isset($access[$type]['allow']) && $access[$type]['allow']) {
+ // If any allow rule matches, access is allowed.
+ if (preg_match($access[$type]['allow'], $mask)) {
+ $denied = FALSE;
+ }
+ }
+
+ return $denied;
}
/**
@@ -878,7 +935,7 @@ function drupal_bootstrap($phase) {
}
function _drupal_bootstrap($phase) {
- global $conf;
+ global $conf, $access;
switch ($phase) {
@@ -899,6 +956,9 @@ function _drupal_bootstrap($phase) {
break;
case DRUPAL_BOOTSTRAP_ACCESS:
+ // Initialize the access strategy.
+ $access = _drupal_access_init();
+
// Deny access to hosts which were banned - t() is not yet available.
if (drupal_is_denied('host', ip_address())) {
header('HTTP/1.1 403 Forbidden');
diff -urpN drupal-6.x-dev-200708231745/modules/user/user.module drupal-6.x-dev-access-0.4.2/modules/user/user.module
--- drupal-6.x-dev-200708231745/modules/user/user.module 2007-08-19 16:08:45.000000000 +0800
+++ drupal-6.x-dev-access-0.4.2/modules/user/user.module 2007-08-23 23:43:02.000000000 +0800
@@ -2005,8 +2005,8 @@ function user_admin_access_add($mask = N
form_set_error('mask', t('You must enter a mask.'));
}
else {
- db_query("INSERT INTO {access} (aid, mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'], $edit['type'], $edit['status']);
- $aid = db_last_insert_id('access', 'aid');
+ db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $edit['mask'], $edit['type'], $edit['status']);
+ cache_clear_all('accesses', 'cache');
drupal_set_message(t('The access rule has been added.'));
drupal_goto('admin/user/rules');
}
@@ -2038,6 +2038,7 @@ function user_admin_access_delete_confir
function user_admin_access_delete_confirm_submit($form, &$form_state) {
db_query('DELETE FROM {access} WHERE aid = %d', $form_state['values']['aid']);
+ cache_clear_all('accesses', 'cache');
drupal_set_message(t('The access rule has been deleted.'));
$form_state['redirect'] = 'admin/user/rules';
return;
@@ -2053,6 +2054,7 @@ function user_admin_access_edit($aid = 0
}
else {
db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'], $edit['type'], $edit['status'], $aid);
+ cache_clear_all('accesses', 'cache');
drupal_set_message(t('The access rule has been saved.'));
drupal_goto('admin/user/rules');
}
@@ -2083,7 +2085,7 @@ function user_admin_access_form(&$form_s
'#size' => 30,
'#maxlength' => 64,
'#default_value' => $edit['mask'],
- '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.
_: '. t('Matches exactly one character.'),
+ '#description' => t('Start the line with a ^ character to designate a regular expression match.') . '
' . t('NOTE: non-regexp matches are always done first.'),
'#required' => TRUE,
);
$form['submit'] = array('#type' => 'submit', '#value' => $submit);