PluginProbe
Groups – Memberships and Access Control / 1.11.2
Groups – Memberships and Access Control v1.11.2
4.7.1 4.7.0 4.6.0 4.5.0 4.4.0 4.3.0 trunk 1.0.0-beta-1 1.0.0-beta-2 1.0.0-beta-3 1.0.0-beta-3b 1.0.0-beta-3c 1.0.0-beta-3d 1.1.4 1.1.5 1.10.0 1.10.1 1.10.2 1.10.3 1.11.0 1.11.1 1.11.2 1.11.3 1.12.0 1.13.0 All 131 releases
groups / lib / core / class-groups-user.php

class-groups-user.php in Groups – Memberships and Access Control 1.11.2, at lib/core/class-groups-user.php

459 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * class-groups-user.php
4 *
5 * Copyright (c) "kento" Karim Rahimpur www.itthinx.com
6 *
7 * This code is released under the GNU General Public License.
8 * See COPYRIGHT.txt and LICENSE.txt.
9 *
10 * This code is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * This header and all notices must be kept intact.
16 *
17 * @author Karim Rahimpur
18 * @package groups
19 * @since groups 1.0.0
20 */
21
22 if ( !defined( 'ABSPATH' ) ) {
23 exit;
24 }
25
26 require_once( GROUPS_CORE_LIB . "/interface-i-capable.php" );
27 require_once( GROUPS_CORE_LIB . "/class-groups-capability.php" );
28
29 /**
30 * User OPM.
31 */
32 class Groups_User implements I_Capable {
33
34 const CACHE_GROUP = 'groups';
35 const CAPABILITIES = 'capabilities';
36 const CAPABILITIES_BASE = 'capabilities_base';
37 const CAPABILITY_IDS = 'capability_ids';
38 const CAPABILITY_IDS_BASE = 'capability_ids_base';
39 const GROUP_IDS = 'group_ids';
40 const GROUP_IDS_BASE = 'group_ids_base';
41 const GROUPS = 'groups';
42 const GROUPS_BASE = 'groups_base';
43
44 /**
45 * User object.
46 *
47 * @var WP_User
48 */
49 var $user = null;
50
51 /**
52 * Hook cache clearers to actions that can modify the capabilities.
53 */
54 public static function init() {
55 add_action( 'groups_created_user_group', array( __CLASS__, 'clear_cache' ) );
56 add_action( 'groups_updated_user_group', array( __CLASS__, 'clear_cache' ) );
57 add_action( 'groups_deleted_user_group', array( __CLASS__, 'clear_cache' ) );
58 add_action( 'groups_created_user_capability', array( __CLASS__, 'clear_cache' ) );
59 add_action( 'groups_updated_user_capability', array( __CLASS__, 'clear_cache' ) );
60 add_action( 'groups_deleted_user_capability', array( __CLASS__, 'clear_cache' ) );
61 add_action( 'groups_created_group_capability', array( __CLASS__, 'clear_cache_for_group' ) );
62 add_action( 'groups_updated_group_capability', array( __CLASS__, 'clear_cache_for_group' ) );
63 add_action( 'groups_deleted_group_capability', array( __CLASS__, 'clear_cache_for_group' ) );
64 }
65
66 /**
67 * Clear cache objects for the user.
68 * @param int $user_id
69 */
70 public static function clear_cache( $user_id ) {
71 // be lazy, clear the entries so they are rebuilt when requested
72 Groups_Cache::delete( self::CAPABILITIES . $user_id, self::CACHE_GROUP );
73 Groups_Cache::delete( self::CAPABILITIES_BASE . $user_id, self::CACHE_GROUP );
74 Groups_Cache::delete( self::CAPABILITY_IDS . $user_id, self::CACHE_GROUP );
75 Groups_Cache::delete( self::CAPABILITY_IDS_BASE . $user_id, self::CACHE_GROUP );
76 Groups_Cache::delete( self::GROUP_IDS . $user_id, self::CACHE_GROUP );
77 Groups_Cache::delete( self::GROUP_IDS_BASE . $user_id, self::CACHE_GROUP );
78 Groups_Cache::delete( self::GROUPS . $user_id, self::CACHE_GROUP );
79 Groups_Cache::delete( self::GROUPS_BASE . $user_id, self::CACHE_GROUP );
80 }
81
82 /**
83 * Clear cache objects for all users in the group.
84 * @param unknown_type $group_id
85 */
86 public static function clear_cache_for_group( $group_id ) {
87 global $wpdb;
88 if ( $group = Groups_Group::read( $group_id ) ) {
89 // not using $group->users, as we don't need a lot of user objects created here
90 $user_group_table = _groups_get_tablename( "user_group" );
91 $users = $wpdb->get_results( $wpdb->prepare(
92 "SELECT ID FROM $wpdb->users LEFT JOIN $user_group_table ON $wpdb->users.ID = $user_group_table.user_id WHERE $user_group_table.group_id = %d",
93 Groups_Utility::id( $group_id )
94 ) );
95 if ( $users ) {
96 foreach( $users as $user ) {
97 self::clear_cache( $user->ID );
98 }
99 }
100 }
101 }
102
103 /**
104 * Create, if $user_id = 0 an anonymous user is assumed.
105 *
106 * @param int $user_id
107 */
108 public function __construct( $user_id ) {
109 if ( Groups_Utility::id( $user_id ) ) {
110 $this->user = get_user_by( "id", $user_id );
111 } else {
112 $this->user = new WP_User( 0 );
113 }
114 }
115
116 /**
117 * Retrieve a user property.
118 * Must be "capabilities", "groups" or a property of the WP_User class.
119 * @param string $name property's name
120 */
121 public function __get( $name ) {
122
123 global $wpdb;
124 $result = null;
125
126 if ( $this->user !== null ) {
127
128 switch ( $name ) {
129
130 case 'capability_ids' :
131 $cached = Groups_Cache::get( self::CAPABILITY_IDS_BASE . $this->user->ID, self::CACHE_GROUP );
132 if ( $cached !== null ) {
133 $result = $cached->value;
134 unset( $cached );
135 } else {
136 $user_capability_table = _groups_get_tablename( "user_capability" );
137 $rows = $wpdb->get_results( $wpdb->prepare(
138 "SELECT capability_id FROM $user_capability_table WHERE user_id = %d",
139 Groups_Utility::id( $this->user->ID )
140 ) );
141 if ( $rows ) {
142 $result = array();
143 foreach ( $rows as $row ) {
144 $result[] = $row->capability_id;
145 }
146 }
147 Groups_Cache::set( self::CAPABILITY_IDS_BASE . $this->user->ID, $result, self::CACHE_GROUP );
148 }
149 break;
150
151 case 'capability_ids_deep' :
152 if ( $this->user !== null ) {
153 $cached = Groups_Cache::get( self::CAPABILITY_IDS . $this->user->ID, self::CACHE_GROUP );
154 if ( $cached !== null ) {
155 $capability_ids = $cached->value;
156 unset( $cached );
157 } else {
158 $this->init_cache( $capability_ids );
159 }
160 $result = $capability_ids;
161 }
162 break;
163
164 case 'group_ids' :
165 $cached = Groups_Cache::get( self::GROUP_IDS_BASE . $this->user->ID, self::CACHE_GROUP );
166 if ( $cached !== null ) {
167 $result = $cached->value;
168 unset( $cached );
169 } else {
170 $user_group_table = _groups_get_tablename( "user_group" );
171 $rows = $wpdb->get_results( $wpdb->prepare(
172 "SELECT group_id FROM $user_group_table WHERE user_id = %d",
173 Groups_Utility::id( $this->user->ID )
174 ) );
175 if ( $rows ) {
176 $result = array();
177 foreach( $rows as $row ) {
178 $result[] = $row->group_id;
179 }
180 }
181 Groups_Cache::set( self::GROUP_IDS_BASE . $this->user->ID, $result, self::CACHE_GROUP );
182 }
183 break;
184
185 case 'group_ids_deep' :
186 if ( $this->user !== null ) {
187 $cached = Groups_Cache::get( self::GROUP_IDS . $this->user->ID, self::CACHE_GROUP );
188 if ( $cached !== null ) {
189 $group_ids = $cached->value;
190 unset( $cached );
191 } else {
192 $this->init_cache( $capability_ids, $capabilities, $group_ids );
193 }
194 $result = $group_ids;
195 }
196 break;
197
198 case 'capabilities' :
199 $cached = Groups_Cache::get( self::CAPABILITIES_BASE . $this->user->ID, self::CACHE_GROUP );
200 if ( $cached !== null ) {
201 $result = $cached->value;
202 unset( $cached );
203 } else {
204 $user_capability_table = _groups_get_tablename( "user_capability" );
205 $rows = $wpdb->get_results( $wpdb->prepare(
206 "SELECT capability_id FROM $user_capability_table WHERE user_id = %d",
207 Groups_Utility::id( $this->user->ID )
208 ) );
209 if ( $rows ) {
210 $result = array();
211 foreach ( $rows as $row ) {
212 $result[] = new Groups_Capability( $row->capability_id );
213 }
214 }
215 Groups_Cache::set( self::CAPABILITIES_BASE . $this->user->ID, $result, self::CACHE_GROUP );
216 }
217 break;
218
219 case 'capabilities_deep' :
220 if ( $this->user !== null ) {
221 $cached = Groups_Cache::get( self::CAPABILITIES . $this->user->ID, self::CACHE_GROUP );
222 if ( $cached !== null ) {
223 $capabilities = $cached->value;
224 unset( $cached );
225 } else {
226 $this->init_cache( $capability_ids, $capabilities );
227 }
228 $result = $capabilities;
229 }
230 break;
231
232 case 'groups' :
233 $cached = Groups_Cache::get( self::GROUPS_BASE . $this->user->ID, self::CACHE_GROUP );
234 if ( $cached !== null ) {
235 $result = $cached->value;
236 unset( $cached );
237 } else {
238 $user_group_table = _groups_get_tablename( "user_group" );
239 $rows = $wpdb->get_results( $wpdb->prepare(
240 "SELECT group_id FROM $user_group_table WHERE user_id = %d",
241 Groups_Utility::id( $this->user->ID )
242 ) );
243 if ( $rows ) {
244 $result = array();
245 foreach( $rows as $row ) {
246 $result[] = new Groups_Group( $row->group_id );
247 }
248 }
249 Groups_Cache::set( self::GROUPS_BASE . $this->user->ID, $result, self::CACHE_GROUP );
250 }
251 break;
252
253 case 'groups_deep' :
254 $cached = Groups_Cache::get( self::GROUPS . $this->user->ID, self::CACHE_GROUP );
255 if ( $cached !== null ) {
256 $result = $cached->value;
257 unset( $cached );
258 } else {
259 $result = array();
260 foreach( $this->group_ids_deep as $group_id ) {
261 $result[] = new Groups_Group( $group_id );
262 }
263 Groups_Cache::set( self::GROUPS . $this->user->ID, $result, self::CACHE_GROUP );
264 }
265 break;
266
267 default:
268 $result = $this->user->$name;
269 }
270 }
271 return $result;
272 }
273
274 /**
275 * (non-PHPdoc)
276 * @see I_Capable::can()
277 */
278 public function can( $capability ) {
279
280 global $wpdb;
281 $result = false;
282
283 if ( $this->user !== null ) {
284 if (
285 get_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE, GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE_DEFAULT ) &&
286 user_can( $this->user->ID, 'administrator' ) // just using $this->user would raise a warning on 3.2.1
287 ) {
288 $result = true;
289 } else {
290 // determine capability id
291 $capability_id = null;
292 if ( is_numeric( $capability ) ) {
293 $capability_id = Groups_Utility::id( $capability );
294 $cached = Groups_Cache::get( self::CAPABILITY_IDS . $this->user->ID, self::CACHE_GROUP );
295 if ( $cached !== null ) {
296 $capability_ids = $cached->value;
297 unset( $cached );
298 } else {
299 $this->init_cache( $capability_ids );
300 }
301 $result = in_array( $capability_id, $capability_ids );
302 } else if ( is_string( $capability ) ) {
303 $cached = Groups_Cache::get( self::CAPABILITIES . $this->user->ID, self::CACHE_GROUP );
304 if ( $cached !== null ) {
305 $capabilities = $cached->value;
306 unset( $cached );
307 } else {
308 $this->init_cache( $capability_ids, $capabilities );
309 }
310 $result = in_array( $capability, $capabilities );
311 }
312 }
313 }
314 $result = apply_filters_ref_array( "groups_user_can", array( $result, &$this, $capability ) );
315 return $result;
316 }
317
318 /**
319 * Returns true if the user belongs to the group.
320 *
321 * @param int $group_id
322 * @return boolean
323 */
324 public function is_member( $group_id ) {
325 $result = false;
326 if ( $this->user !== null ) {
327 if ( isset( $this->user->ID ) ) {
328 $user_group = Groups_User_Group::read(
329 Groups_Utility::id( $this->user->ID ),
330 Groups_Utility::id( $group_id )
331 );
332 $result = $user_group !== false;
333 unset( $user_group );
334 }
335 }
336 return $result;
337 }
338
339 /**
340 * Builds the cache entries for user groups and capabilities if needed.
341 * The cache entries are built only if they do not already exist.
342 * If you want them rebuilt, delete them before calling.
343 *
344 * @param array $capability_ids carries the capability ids for the user on return, but only if cache entries have been built; will provide an empty array by default
345 * @param array $capabilities carries the capabilities for the user on return, but only if cache entries have been built; will provide an empty array by default
346 * @param array $group_ids carries the group ids for the user on return, but only if cache entries have been built; will provide an empty array by default
347 */
348 private function init_cache( &$capability_ids = null, &$capabilities = null, &$group_ids = null ) {
349
350 global $wpdb;
351
352 $capabilities = array();
353 $capability_ids = array();
354 $group_ids = array();
355
356 if ( ( $this->user !== null ) && ( Groups_Cache::get( self::GROUP_IDS . $this->user->ID, self::CACHE_GROUP ) === null ) ) {
357 $group_table = _groups_get_tablename( "group" );
358 $capability_table = _groups_get_tablename( "capability" );
359 $group_capability_table = _groups_get_tablename( "group_capability" );
360 $user_group_table = _groups_get_tablename( "user_group" );
361 $user_capability_table = _groups_get_tablename( "user_capability" );
362
363 $limit = $wpdb->get_var( "SELECT COUNT(*) FROM $group_table" );
364 if ( $limit === null ) {
365 $limit = 1;
366 }
367
368 // note that limits by blog_id for multisite are
369 // enforced when a user is added to a blog
370 $user_groups = $wpdb->get_results( $wpdb->prepare(
371 "SELECT group_id FROM $user_group_table WHERE user_id = %d",
372 Groups_Utility::id( $this->user->ID )
373 ) );
374 // get all capabilities directly assigned (those granted through
375 // groups are added below
376 $user_capabilities = $wpdb->get_results( $wpdb->prepare(
377 "SELECT c.capability_id, c.capability FROM $user_capability_table uc LEFT JOIN $capability_table c ON c.capability_id = uc.capability_id WHERE user_id = %d",
378 Groups_Utility::id( $this->user->ID )
379 ) );
380 if ( $user_capabilities ) {
381 foreach( $user_capabilities as $user_capability ) {
382 $capabilities[] = $user_capability->capability;
383 $capability_ids[] = $user_capability->capability_id;
384 }
385 }
386
387 if ( apply_filters( 'groups_user_add_role_capabilities', true ) ) {
388 // Get all capabilities from the WP_User object.
389 $role_caps = $this->user->get_role_caps();
390 if ( !empty( $role_caps ) && is_array( $role_caps ) ) {
391 $caps = array();
392 foreach( $role_caps as $role_cap => $has ) {
393 if ( $has && !in_array( $role_cap, $capabilities ) ) {
394 $caps[] = "'" . $role_cap . "'";
395 }
396 }
397 if ( !empty( $caps ) ) {
398 // Retrieve the capabilities and only add those that are
399 // recognized. Note that this also effectively filters out
400 // all roles and that this is desired.
401 if ( $role_capabilities = $wpdb->get_results( "SELECT capability_id, capability FROM $capability_table c WHERE capability IN (" . implode( ',', $caps ) . ")" ) ) {
402 foreach( $role_capabilities as $role_capability ) {
403 $capabilities[] = $role_capability->capability;
404 $capability_ids[] = $role_capability->capability_id;
405 }
406 }
407 }
408 }
409 }
410
411 // Get all groups the user belongs to directly or through
412 // inheritance along with their capabilities.
413 if ( $user_groups ) {
414 foreach( $user_groups as $user_group ) {
415 $group_ids[] = Groups_Utility::id( $user_group->group_id );
416 }
417 if ( count( $group_ids ) > 0 ) {
418 $iterations = 0;
419 $old_group_ids_count = 0;
420 while( ( $iterations < $limit ) && ( count( $group_ids ) !== $old_group_ids_count ) ) {
421 $iterations++;
422 $old_group_ids_count = count( $group_ids );
423 $id_list = implode( ",", $group_ids );
424 $parent_group_ids = $wpdb->get_results(
425 "SELECT parent_id FROM $group_table WHERE parent_id IS NOT NULL AND group_id IN ($id_list)"
426 );
427 if ( $parent_group_ids ) {
428 foreach( $parent_group_ids as $parent_group_id ) {
429 $parent_group_id = Groups_Utility::id( $parent_group_id->parent_id );
430 if ( !in_array( $parent_group_id, $group_ids ) ) {
431 $group_ids[] = $parent_group_id;
432 }
433 }
434 }
435 }
436 $id_list = implode( ",", $group_ids );
437 $rows = $wpdb->get_results(
438 "SELECT $group_capability_table.capability_id, $capability_table.capability FROM $group_capability_table LEFT JOIN $capability_table ON $group_capability_table.capability_id = $capability_table.capability_id WHERE group_id IN ($id_list)"
439 );
440 if ( count( $rows ) > 0 ) {
441 foreach ( $rows as $row ) {
442 if ( !in_array( $row->capability_id, $capability_ids ) ) {
443 $capabilities[] = $row->capability;
444 $capability_ids[] = $row->capability_id;
445 }
446 }
447 }
448
449 }
450 }
451 Groups_Cache::set( self::CAPABILITIES . $this->user->ID, $capabilities, self::CACHE_GROUP );
452 Groups_Cache::set( self::CAPABILITY_IDS . $this->user->ID, $capability_ids, self::CACHE_GROUP );
453 Groups_Cache::set( self::GROUP_IDS . $this->user->ID, $group_ids, self::CACHE_GROUP );
454 }
455 }
456
457 }
458 Groups_User::init();
459