| @@ -22,41 +22,77 @@ | ||
| 22 | 22 | if ( !defined( 'ABSPATH' ) ) { |
| 23 | 23 | exit; |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | +// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange | |
| 27 | + | |
| 26 | 28 | /** |
| 27 | 29 | * Plugin controller |
| 28 | 30 | */ |
| 29 | 31 | class Groups_Controller { |
| 30 | - | |
| 32 | + | |
| 31 | 33 | /** |
| 34 | + * Version 2.0.0 number | |
| 35 | + * | |
| 36 | + * @var string | |
| 37 | + */ | |
| 38 | + const GROUPS_200 = '2.0.0'; | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * Holds mofile when determined. | |
| 42 | + * | |
| 43 | + * @since 3.10.0 | |
| 44 | + * | |
| 45 | + * @var string | |
| 46 | + */ | |
| 47 | + private static $mofile = null; | |
| 48 | + | |
| 49 | + /** | |
| 32 | 50 | * Cache-safe switching in case any multi-site hiccups might occur. |
| 51 | + * | |
| 33 | 52 | * Clears the cache after switching to the given blog to avoid using |
| 34 | 53 | * another blog's cached values. |
| 35 | - * See wp_cache_reset() in wp-includes/cache.php | |
| 54 | + * | |
| 55 | + * Some implementations don't have wp_cache_switch_to_blog() nor the deprecated | |
| 56 | + * wp_cache_reset(), e.g. WP Engine's object-cache.php which has wp_cache_flush(). | |
| 57 | + * Cache plugins are responsible for acting accordingly when switch_to_blog() or | |
| 58 | + * restore_current_blog() is invoked. In 4.0.0 we dropped any additional calls | |
| 59 | + * other than those to switch_to_blog() and restore_current_blog(). | |
| 60 | + * | |
| 61 | + * @since 2.10.0 giving preference to call wp_cache_init() since it will reset the blog_id | |
| 62 | + * @since 2.10.0 removed alternative call to wp_cache_reset() | |
| 63 | + * @since 4.0.0 multisite guard added; not calling functions already called within switch_to_blog; cache plugins should act appropriately | |
| 64 | + * | |
| 65 | + * @see wp_cache_switch_to_blog() | |
| 66 | + * @see wp_cache_init() | |
| 67 | + * @see wp_cache_flush() | |
| 36 | 68 | * @see wp_cache_reset() |
| 69 | + * @see self::restore_current_blog() | |
| 70 | + * | |
| 37 | 71 | * @link http://core.trac.wordpress.org/ticket/14941 |
| 38 | 72 | * |
| 39 | 73 | * @param int $blog_id |
| 40 | 74 | */ |
| 41 | 75 | public static function switch_to_blog( $blog_id ) { |
| 42 | - switch_to_blog( $blog_id ); | |
| 43 | - if ( function_exists( 'wp_cache_switch_to_blog' ) ) { | |
| 44 | - wp_cache_switch_to_blog( $blog_id ); // introduced in WP 3.5.0 | |
| 45 | - } else { | |
| 46 | - wp_cache_reset(); // deprecated in WP 3.5.0 | |
| 76 | + if ( is_multisite() ) { | |
| 77 | + switch_to_blog( $blog_id ); | |
| 47 | 78 | } |
| 48 | 79 | } |
| 49 | - | |
| 80 | + | |
| 50 | 81 | /** |
| 51 | 82 | * Switch back to previous blog. |
| 83 | + * | |
| 84 | + * @see self::switch_to_blog() | |
| 52 | 85 | */ |
| 53 | 86 | public static function restore_current_blog() { |
| 54 | - restore_current_blog(); | |
| 87 | + if ( is_multisite() ) { | |
| 88 | + restore_current_blog(); | |
| 89 | + } | |
| 55 | 90 | } |
| 56 | - | |
| 91 | + | |
| 57 | 92 | /** |
| 58 | 93 | * Boot the plugin. |
| 94 | + * | |
| 59 | 95 | * @see Groups_Registered::wpmu_new_blog() |
| 60 | 96 | */ |
| 61 | 97 | public static function boot() { |
| 62 | 98 | register_activation_hook( GROUPS_FILE, array( __CLASS__, 'activate' ) ); |
| @@ -61,18 +97,21 @@ | ||
| 61 | 97 | public static function boot() { |
| 62 | 98 | register_activation_hook( GROUPS_FILE, array( __CLASS__, 'activate' ) ); |
| 63 | 99 | register_deactivation_hook( GROUPS_FILE, array( __CLASS__, 'deactivate' ) ); |
| 64 | 100 | add_action( 'init', array( __CLASS__, 'init' ) ); |
| 65 | - | |
| 101 | + add_filter( 'load_textdomain_mofile', array( __CLASS__, 'load_textdomain_mofile' ), 10, 2 ); // as of 3.10.0 this filter is removed within its function while processing, any changes made here should be reflected there, too | |
| 102 | + add_filter( 'load_script_translation_file', array( __CLASS__, 'load_script_translation_file' ), 10, 3 ); // @since 3.10.0 | |
| 66 | 103 | // priority 9 because it needs to be called before Groups_Registered's |
| 67 | 104 | // wpmu_new_blog kicks in |
| 68 | 105 | add_action( 'wpmu_new_blog', array( __CLASS__, 'wpmu_new_blog' ), 9, 2 ); |
| 69 | 106 | add_action( 'delete_blog', array( __CLASS__, 'delete_blog' ), 10, 2 ); |
| 107 | + add_action( 'wp_loaded', array( __CLASS__, 'wp_loaded' ) ); // @since 2.16.0 | |
| 108 | + add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_enqueue_scripts' ) ); // @since 2.16.0 | |
| 70 | 109 | } |
| 71 | - | |
| 110 | + | |
| 72 | 111 | /** |
| 73 | 112 | * Run activation for a newly created blog in a multisite environment. |
| 74 | - * | |
| 113 | + * | |
| 75 | 114 | * @param int $blog_id |
| 76 | 115 | */ |
| 77 | 116 | public static function wpmu_new_blog( $blog_id, $user_id ) { |
| 78 | 117 | if ( is_multisite() ) { |
| @@ -83,13 +122,13 @@ | ||
| 83 | 122 | self::restore_current_blog(); |
| 84 | 123 | } |
| 85 | 124 | } |
| 86 | 125 | } |
| 87 | - | |
| 126 | + | |
| 88 | 127 | /** |
| 89 | 128 | * Run deactivation for a blog that is about to be deleted in a multisite |
| 90 | 129 | * environment. |
| 91 | - * | |
| 130 | + * | |
| 92 | 131 | * @param int $blog_id |
| 93 | 132 | */ |
| 94 | 133 | public static function delete_blog( $blog_id, $drop = false ) { |
| 95 | 134 | if ( is_multisite() ) { |
| @@ -100,41 +139,200 @@ | ||
| 100 | 139 | self::restore_current_blog(); |
| 101 | 140 | } |
| 102 | 141 | } |
| 103 | 142 | } |
| 104 | - | |
| 143 | + | |
| 105 | 144 | /** |
| 106 | 145 | * Initialize. |
| 107 | 146 | * Loads the plugin's translations. |
| 147 | + * Invokes version check. | |
| 108 | 148 | */ |
| 109 | 149 | public static function init() { |
| 110 | - load_plugin_textdomain( GROUPS_PLUGIN_DOMAIN, null, 'groups/languages' ); | |
| 150 | + | |
| 151 | + unload_textdomain( 'groups' ); | |
| 152 | + | |
| 153 | + // Load our current translations first ... | |
| 154 | + $mofile = self::get_mofile(); | |
| 155 | + load_textdomain( 'groups', $mofile ); | |
| 156 | + | |
| 157 | + // ... otherwise load_plugin_textdomain will simply get those in WP's languages | |
| 158 | + // and we won't have our up-to-date translations. | |
| 159 | + //load_plugin_textdomain( 'groups', null, 'groups/languages' ); | |
| 111 | 160 | self::version_check(); |
| 161 | + | |
| 162 | + // load the notice class | |
| 163 | + if ( is_admin() ) { | |
| 164 | + if ( Groups_User::current_user_can( 'activate_plugins' ) ) { // important: after init hook | |
| 165 | + require_once GROUPS_ADMIN_LIB . '/class-groups-admin-notice.php'; | |
| 166 | + } | |
| 167 | + } | |
| 112 | 168 | } |
| 113 | - | |
| 169 | + | |
| 114 | 170 | /** |
| 171 | + * Register the menu style. | |
| 172 | + * | |
| 173 | + * @since 2.16.0 | |
| 174 | + */ | |
| 175 | + public static function wp_loaded() { | |
| 176 | + global $groups_version; | |
| 177 | + if ( !wp_style_is( 'groups-menu', 'registered' ) ) { | |
| 178 | + wp_register_style( 'groups-menu', GROUPS_PLUGIN_URL . 'css/groups-menu.css', array(), $groups_version ); | |
| 179 | + } | |
| 180 | + } | |
| 181 | + | |
| 182 | + /** | |
| 183 | + * Enqueue the menu style. | |
| 184 | + * | |
| 185 | + * @since 2.16.0 | |
| 186 | + */ | |
| 187 | + public static function admin_enqueue_scripts() { | |
| 188 | + wp_enqueue_style( 'groups-menu' ); | |
| 189 | + } | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * Builds the mofile string for our own translations. | |
| 193 | + * | |
| 194 | + * @return string mofile | |
| 195 | + */ | |
| 196 | + private static function get_mofile() { | |
| 197 | + | |
| 198 | + // @since 3.10.0 determine the file only once and avoid redundant work | |
| 199 | + if ( self::$mofile !== null ) { | |
| 200 | + return self::$mofile; | |
| 201 | + } | |
| 202 | + | |
| 203 | + $locale = get_locale(); | |
| 204 | + if ( function_exists( 'get_user_locale' ) ) { | |
| 205 | + $locale = get_user_locale(); | |
| 206 | + } | |
| 207 | + $locale = apply_filters( 'plugin_locale', $locale, 'groups' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound | |
| 208 | + $mofile = GROUPS_CORE_DIR . '/languages/groups-' . $locale . '.mo'; | |
| 209 | + // @since 3.3.0 load language-generic translation if available | |
| 210 | + if ( !file_exists( $mofile ) ) { | |
| 211 | + $parts = explode( '_', $locale ); | |
| 212 | + $language = $parts[0]; | |
| 213 | + $country = isset( $parts[1] ) ? $parts[1] : ''; | |
| 214 | + $form = isset( $parts[2] ) ? $parts[2] : ''; | |
| 215 | + switch ( $country ) { | |
| 216 | + case 'CH': | |
| 217 | + switch ( $form ) { | |
| 218 | + case 'informal': | |
| 219 | + $form = ''; | |
| 220 | + break; | |
| 221 | + case '': | |
| 222 | + $form = 'formal'; | |
| 223 | + break; | |
| 224 | + } | |
| 225 | + break; | |
| 226 | + } | |
| 227 | + $the_mofile = null; | |
| 228 | + if ( $form !== '' ) { | |
| 229 | + $the_mofile = GROUPS_CORE_DIR . '/languages/groups' . '-' . $language . '_' . $form . '.mo'; | |
| 230 | + if ( !file_exists( $the_mofile ) ) { | |
| 231 | + $the_mofile = null; | |
| 232 | + } | |
| 233 | + } | |
| 234 | + if ( $the_mofile === null ) { | |
| 235 | + $the_mofile = GROUPS_CORE_DIR . '/languages/groups' . '-' . $language . '.mo'; | |
| 236 | + if ( !file_exists( $the_mofile ) ) { | |
| 237 | + $the_mofile = null; | |
| 238 | + } | |
| 239 | + } | |
| 240 | + if ( $the_mofile !== null ) { | |
| 241 | + $mofile = $the_mofile; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + self::$mofile = $mofile; | |
| 246 | + | |
| 247 | + return $mofile; | |
| 248 | + } | |
| 249 | + | |
| 250 | + /** | |
| 251 | + * Makes sure that our own translation file is loaded first. | |
| 252 | + * | |
| 253 | + * @param string $mofile | |
| 254 | + * @param string $domain | |
| 255 | + * | |
| 256 | + * @return string mofile | |
| 257 | + */ | |
| 258 | + public static function load_textdomain_mofile( $mofile, $domain ) { | |
| 259 | + if ( $domain === 'groups' ) { | |
| 260 | + // @since 3.10.0 remove the filter while processing and avoid potential infinite recursion during processing | |
| 261 | + remove_filter( 'load_textdomain_mofile', array( __CLASS__, 'load_textdomain_mofile' ), 10 ); | |
| 262 | + $own_mofile = self::get_mofile(); | |
| 263 | + if ( $own_mofile != $mofile ) { | |
| 264 | + if ( !is_textdomain_loaded( $domain ) ) { | |
| 265 | + if ( is_readable( $own_mofile ) ) { | |
| 266 | + $mofile = $own_mofile; | |
| 267 | + } | |
| 268 | + } | |
| 269 | + } | |
| 270 | + add_filter( 'load_textdomain_mofile', array( __CLASS__, 'load_textdomain_mofile' ), 10, 2 ); // see self::boot() where this filter is originally added | |
| 271 | + } | |
| 272 | + return $mofile; | |
| 273 | + } | |
| 274 | + | |
| 275 | + /** | |
| 276 | + * Load our script translations. | |
| 277 | + * | |
| 278 | + * @since 3.10.0 | |
| 279 | + * | |
| 280 | + * @param string $file | |
| 281 | + * @param string $handle | |
| 282 | + * @param string $domain | |
| 283 | + * | |
| 284 | + * @return string | |
| 285 | + */ | |
| 286 | + public static function load_script_translation_file( $file, $handle, $domain ) { | |
| 287 | + if ( $domain === 'groups' ) { | |
| 288 | + $mofile = self::get_mofile(); | |
| 289 | + if ( $mofile !== null ) { | |
| 290 | + $base = basename( $mofile, '.mo' ); | |
| 291 | + $path = GROUPS_CORE_DIR . '/languages/js/' . $base . '.json'; | |
| 292 | + if ( file_exists( $path ) ) { | |
| 293 | + $file = $path; | |
| 294 | + } | |
| 295 | + } | |
| 296 | + } | |
| 297 | + return $file; | |
| 298 | + } | |
| 299 | + | |
| 300 | + /** | |
| 115 | 301 | * Plugin activation. |
| 302 | + * | |
| 116 | 303 | * @param boolean $network_wide |
| 117 | 304 | */ |
| 118 | 305 | public static function activate( $network_wide = false ) { |
| 119 | - if ( is_multisite() && $network_wide ) { | |
| 120 | - $blog_ids = Groups_Utility::get_blogs(); | |
| 121 | - foreach ( $blog_ids as $blog_id ) { | |
| 122 | - self::switch_to_blog( $blog_id ); | |
| 306 | + $sem_id = self::sem_get( self::get_sem_key() ); | |
| 307 | + if ( ( $sem_id === false ) || self::sem_acquire( $sem_id ) ) { | |
| 308 | + if ( is_multisite() && $network_wide ) { | |
| 309 | + $blog_ids = Groups_Utility::get_blogs(); | |
| 310 | + foreach ( $blog_ids as $blog_id ) { | |
| 311 | + self::switch_to_blog( $blog_id ); | |
| 312 | + self::setup(); | |
| 313 | + self::restore_current_blog(); | |
| 314 | + } | |
| 315 | + } else { | |
| 123 | 316 | self::setup(); |
| 124 | - self::restore_current_blog(); | |
| 317 | + // @since 3.3.1 Check here already if it is a single activation of Groups and only then set the transient | |
| 318 | + if ( self::is_single_activate() ) { | |
| 319 | + set_transient( 'groups_plugin_activated', true, 60 ); | |
| 320 | + } | |
| 125 | 321 | } |
| 126 | - } else { | |
| 127 | - self::setup(); | |
| 322 | + if ( $sem_id !== false ) { | |
| 323 | + self::sem_release( $sem_id ); | |
| 324 | + self::sem_remove( $sem_id ); | |
| 325 | + } | |
| 128 | 326 | } |
| 129 | 327 | } |
| 130 | - | |
| 328 | + | |
| 131 | 329 | /** |
| 132 | 330 | * Plugin activation work. |
| 133 | 331 | */ |
| 134 | 332 | private static function setup() { |
| 135 | 333 | global $wpdb, $wp_roles; |
| 136 | - | |
| 334 | + | |
| 137 | 335 | // create WP capabilities |
| 138 | 336 | Groups_Controller::set_default_capabilities(); |
| 139 | 337 | |
| 140 | 338 | $charset_collate = ''; |
| @@ -144,12 +342,13 @@ | ||
| 144 | 342 | if ( ! empty( $wpdb->collate ) ) { |
| 145 | 343 | $charset_collate .= " COLLATE $wpdb->collate"; |
| 146 | 344 | } |
| 147 | 345 | |
| 148 | - // create tables | |
| 346 | + // create tables | |
| 149 | 347 | $group_table = _groups_get_tablename( 'group' ); |
| 348 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 150 | 349 | if ( $wpdb->get_var( "SHOW TABLES LIKE '$group_table'" ) != $group_table ) { |
| 151 | - $queries[] = "CREATE TABLE $group_table ( | |
| 350 | + $queries[] = "CREATE TABLE IF NOT EXISTS $group_table ( | |
| 152 | 351 | group_id BIGINT(20) UNSIGNED NOT NULL auto_increment, |
| 153 | 352 | parent_id BIGINT(20) DEFAULT NULL, |
| 154 | 353 | creator_id BIGINT(20) DEFAULT NULL, |
| 155 | 354 | datetime DATETIME DEFAULT NULL, |
| @@ -159,10 +358,11 @@ | ||
| 159 | 358 | UNIQUE INDEX group_n (name) |
| 160 | 359 | ) $charset_collate;"; |
| 161 | 360 | } |
| 162 | 361 | $capability_table = _groups_get_tablename( 'capability' ); |
| 362 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 163 | 363 | if ( $wpdb->get_var( "SHOW TABLES LIKE '$capability_table'" ) != $capability_table ) { |
| 164 | - $queries[] = "CREATE TABLE $capability_table ( | |
| 364 | + $queries[] = "CREATE TABLE IF NOT EXISTS $capability_table ( | |
| 165 | 365 | capability_id BIGINT(20) UNSIGNED NOT NULL auto_increment, |
| 166 | 366 | capability VARCHAR(255) NOT NULL, |
| 167 | 367 | class VARCHAR(255) DEFAULT NULL, |
| 168 | 368 | object VARCHAR(255) DEFAULT NULL, |
| @@ -173,10 +373,11 @@ | ||
| 173 | 373 | INDEX capability_kco (capability(20),class(20),object(20)) |
| 174 | 374 | ) $charset_collate;"; |
| 175 | 375 | } |
| 176 | 376 | $user_group_table = _groups_get_tablename( 'user_group' ); |
| 377 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 177 | 378 | if ( $wpdb->get_var( "SHOW TABLES LIKE '$user_group_table'" ) != $user_group_table ) { |
| 178 | - $queries[] = "CREATE TABLE $user_group_table ( | |
| 379 | + $queries[] = "CREATE TABLE IF NOT EXISTS $user_group_table ( | |
| 179 | 380 | user_id bigint(20) unsigned NOT NULL, |
| 180 | 381 | group_id bigint(20) unsigned NOT NULL, |
| 181 | 382 | PRIMARY KEY (user_id, group_id), |
| 182 | 383 | INDEX user_group_gu (group_id,user_id) |
| @@ -182,11 +383,12 @@ | ||
| 182 | 383 | INDEX user_group_gu (group_id,user_id) |
| 183 | 384 | ) $charset_collate;"; |
| 184 | 385 | } |
| 185 | 386 | $user_capability_table = _groups_get_tablename( 'user_capability' ); |
| 387 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 186 | 388 | if ( $wpdb->get_var( "SHOW TABLES LIKE '$user_capability_table'" ) != $user_capability_table ) { |
| 187 | - $queries[] = "CREATE TABLE $user_capability_table ( | |
| 188 | - user_id bigint(20) unsigned NOT NULL, | |
| 389 | + $queries[] = "CREATE TABLE IF NOT EXISTS $user_capability_table ( | |
| 390 | + user_id bigint(20) unsigned NOT NULL, | |
| 189 | 391 | capability_id bigint(20) unsigned NOT NULL, |
| 190 | 392 | PRIMARY KEY (user_id, capability_id), |
| 191 | 393 | INDEX user_capability_cu (capability_id,user_id) |
| 192 | 394 | ) $charset_collate;"; |
| @@ -191,10 +393,11 @@ | ||
| 191 | 393 | INDEX user_capability_cu (capability_id,user_id) |
| 192 | 394 | ) $charset_collate;"; |
| 193 | 395 | } |
| 194 | 396 | $group_capability_table = _groups_get_tablename( 'group_capability' ); |
| 397 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 195 | 398 | if ( $wpdb->get_var( "SHOW TABLES LIKE '$group_capability_table'" ) != $group_capability_table ) { |
| 196 | - $queries[] = "CREATE TABLE $group_capability_table ( | |
| 399 | + $queries[] = "CREATE TABLE IF NOT EXISTS $group_capability_table ( | |
| 197 | 400 | group_id bigint(20) unsigned NOT NULL, |
| 198 | 401 | capability_id bigint(20) unsigned NOT NULL, |
| 199 | 402 | PRIMARY KEY (group_id, capability_id), |
| 200 | 403 | INDEX group_capability_cg (capability_id,group_id) |
| @@ -200,10 +403,16 @@ | ||
| 200 | 403 | INDEX group_capability_cg (capability_id,group_id) |
| 201 | 404 | ) $charset_collate;"; |
| 202 | 405 | } |
| 203 | 406 | if ( !empty( $queries ) ) { |
| 204 | - require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); | |
| 205 | - dbDelta( $queries ); | |
| 407 | + // For the record ... (and https://core.trac.wordpress.org/ticket/12773 should not be closed) | |
| 408 | + // dbDelta() fails to handle queries "CREATE TABLE IF NOT EXISTS ..." | |
| 409 | + // (a regex results in "IF" used as array index holding only last query to create table). | |
| 410 | + //require_once ABSPATH . 'wp-admin/includes/upgrade.php'; | |
| 411 | + //dbDelta( $queries ); | |
| 412 | + foreach ( $queries as $query ) { | |
| 413 | + $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 414 | + } | |
| 206 | 415 | } |
| 207 | 416 | // needs to be called to create its capabilities |
| 208 | 417 | Groups_Post_Access::activate(); |
| 209 | 418 | // same thing to created groups for registered users |
| @@ -211,108 +420,149 @@ | ||
| 211 | 420 | // add WordPress capabilities |
| 212 | 421 | Groups_WordPress::activate(); |
| 213 | 422 | // ... end of plugin activation work. |
| 214 | 423 | } |
| 215 | - | |
| 424 | + | |
| 216 | 425 | /** |
| 217 | 426 | * Checks current version and triggers update if needed. |
| 218 | 427 | */ |
| 219 | 428 | public static function version_check() { |
| 220 | 429 | global $groups_version, $groups_admin_messages; |
| 221 | - $previous_version = get_option( 'groups_plugin_version', null ); | |
| 430 | + $previous_version = get_option( 'groups_plugin_version', '' ); | |
| 222 | 431 | $groups_version = GROUPS_CORE_VERSION; |
| 223 | - if ( version_compare( $previous_version, $groups_version ) < 0 ) { | |
| 224 | - if ( self::update( $previous_version ) ) { | |
| 225 | - update_option( 'groups_plugin_version', $groups_version ); | |
| 226 | - } else { | |
| 227 | - $groups_admin_messages[] = '<div class="error">Updating Groups plugin core <em>failed</em>.</div>'; | |
| 432 | + // auto-enable legacy support on upgrade from Groups previous to 2.0.0 | |
| 433 | + if ( $previous_version ) { | |
| 434 | + if ( version_compare( $previous_version, self::GROUPS_200 ) < 0 ) { | |
| 435 | + if ( Groups_Options::get_option( GROUPS_LEGACY_ENABLE ) === null ) { | |
| 436 | + Groups_Options::update_option( GROUPS_LEGACY_ENABLE, true ); | |
| 437 | + } | |
| 438 | + set_transient( 'groups_plugin_updated_legacy', true, 60 ); | |
| 228 | 439 | } |
| 229 | 440 | } |
| 441 | + | |
| 442 | + // disable legacy support on new installations | |
| 443 | + if ( Groups_Options::get_option( GROUPS_LEGACY_ENABLE ) === null ) { | |
| 444 | + Groups_Options::update_option( GROUPS_LEGACY_ENABLE, false ); | |
| 445 | + } | |
| 446 | + | |
| 447 | + // run update procedure if newer version is installed | |
| 448 | + if ( $previous_version ) { | |
| 449 | + if ( version_compare( $previous_version, $groups_version ) < 0 ) { | |
| 450 | + if ( self::update( $previous_version ) ) { | |
| 451 | + if ( update_option( 'groups_plugin_version', $groups_version ) ) { | |
| 452 | + set_transient( 'groups_plugin_updated', true, 60 ); | |
| 453 | + } | |
| 454 | + } else { | |
| 455 | + $groups_admin_messages[] = '<div class="error">Updating Groups plugin core <em>failed</em>.</div>'; | |
| 456 | + } | |
| 457 | + } | |
| 458 | + } | |
| 230 | 459 | } |
| 231 | - | |
| 460 | + | |
| 232 | 461 | /** |
| 233 | 462 | * Update maintenance. |
| 234 | 463 | */ |
| 235 | 464 | public static function update( $previous_version ) { |
| 465 | + | |
| 236 | 466 | global $wpdb, $groups_admin_messages; |
| 467 | + | |
| 237 | 468 | $result = true; |
| 238 | - $queries = array(); | |
| 239 | - switch ( $previous_version ) { | |
| 240 | - case '1.0.0' : | |
| 241 | - $capability_table = _groups_get_tablename( 'capability' ); | |
| 242 | - if ( $wpdb->get_var( "SHOW TABLES LIKE '$capability_table'" ) == $capability_table ) { | |
| 243 | - // increase column sizes | |
| 244 | - $queries[] = "ALTER TABLE $capability_table MODIFY capability VARCHAR(255) UNIQUE NOT NULL;"; | |
| 245 | - $queries[] = "ALTER TABLE $capability_table MODIFY class VARCHAR(255) DEFAULT NULL;"; | |
| 246 | - $queries[] = "ALTER TABLE $capability_table MODIFY object VARCHAR(255) DEFAULT NULL;"; | |
| 247 | - // correct capabilities | |
| 248 | - $queries[] = "UPDATE $capability_table SET capability='delete_published_pages' WHERE capability='delete_published_pag';"; | |
| 249 | - $queries[] = "UPDATE $capability_table SET capability='delete_published_posts' WHERE capability='delete_published_pos';"; | |
| 250 | - // fix hideously big index | |
| 251 | - $queries[] = "ALTER TABLE $capability_table DROP INDEX capability_kco;"; | |
| 252 | - $queries[] = "ALTER TABLE $capability_table ADD INDEX capability_kco (capability(20),class(20),object(20));"; | |
| 253 | - } | |
| 254 | - break; | |
| 255 | - case '1.0.0-beta-3d' : | |
| 256 | - $capability_table = _groups_get_tablename( 'capability' ); | |
| 257 | - if ( $wpdb->get_var( "SHOW TABLES LIKE '$capability_table'" ) == $capability_table ) { | |
| 258 | - // increase column sizes | |
| 259 | - $queries[] = "ALTER TABLE $capability_table MODIFY capability VARCHAR(255) UNIQUE NOT NULL;"; | |
| 260 | - $queries[] = "ALTER TABLE $capability_table MODIFY class VARCHAR(255) DEFAULT NULL;"; | |
| 261 | - $queries[] = "ALTER TABLE $capability_table MODIFY object VARCHAR(255) DEFAULT NULL;"; | |
| 262 | - // correct capabilities | |
| 263 | - $queries[] = "UPDATE $capability_table SET capability='delete_published_pages' WHERE capability='delete_published_pag';"; | |
| 264 | - $queries[] = "UPDATE $capability_table SET capability='delete_published_posts' WHERE capability='delete_published_pos';"; | |
| 265 | - } | |
| 266 | - break; | |
| 267 | - default : | |
| 268 | - if ( !empty( $previous_version ) ) { | |
| 269 | - if ( version_compare( $previous_version, '1.1.6' ) < 0 ) { | |
| 270 | - Groups_Options::update_option( Groups_Post_Access::READ_POST_CAPABILITIES, array( Groups_Post_Access::READ_POST_CAPABILITY ) ); | |
| 271 | - $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = %s WHERE meta_key = %s", Groups_Post_Access::READ_POST_CAPABILITY, Groups_Post_Access::POSTMETA_PREFIX . Groups_Post_Access::READ_POST_CAPABILITY ) ); | |
| 469 | + | |
| 470 | + $sem_id = self::sem_get( self::get_sem_key() ); | |
| 471 | + if ( ( $sem_id === false ) || self::sem_acquire( $sem_id ) ) { | |
| 472 | + $queries = array(); | |
| 473 | + switch ( $previous_version ) { | |
| 474 | + case '1.0.0' : | |
| 475 | + $capability_table = _groups_get_tablename( 'capability' ); | |
| 476 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 477 | + if ( $wpdb->get_var( "SHOW TABLES LIKE '$capability_table'" ) == $capability_table ) { | |
| 478 | + // increase column sizes | |
| 479 | + $queries[] = "ALTER TABLE $capability_table MODIFY capability VARCHAR(255) UNIQUE NOT NULL;"; | |
| 480 | + $queries[] = "ALTER TABLE $capability_table MODIFY class VARCHAR(255) DEFAULT NULL;"; | |
| 481 | + $queries[] = "ALTER TABLE $capability_table MODIFY object VARCHAR(255) DEFAULT NULL;"; | |
| 482 | + // correct capabilities | |
| 483 | + $queries[] = "UPDATE $capability_table SET capability='delete_published_pages' WHERE capability='delete_published_pag';"; | |
| 484 | + $queries[] = "UPDATE $capability_table SET capability='delete_published_posts' WHERE capability='delete_published_pos';"; | |
| 485 | + // fix hideously big index | |
| 486 | + $queries[] = "ALTER TABLE $capability_table DROP INDEX capability_kco;"; | |
| 487 | + $queries[] = "ALTER TABLE $capability_table ADD INDEX capability_kco (capability(20),class(20),object(20));"; | |
| 272 | 488 | } |
| 273 | - if ( version_compare( $previous_version, '1.5.1' ) < 0 ) { | |
| 274 | - $capability_table = _groups_get_tablename( 'capability' ); | |
| 275 | - $queries[] = "ALTER TABLE $capability_table DROP INDEX capability, ADD UNIQUE INDEX capability(capability(100));"; | |
| 489 | + break; | |
| 490 | + case '1.0.0-beta-3d' : | |
| 491 | + $capability_table = _groups_get_tablename( 'capability' ); | |
| 492 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 493 | + if ( $wpdb->get_var( "SHOW TABLES LIKE '$capability_table'" ) == $capability_table ) { | |
| 494 | + // increase column sizes | |
| 495 | + $queries[] = "ALTER TABLE $capability_table MODIFY capability VARCHAR(255) UNIQUE NOT NULL;"; | |
| 496 | + $queries[] = "ALTER TABLE $capability_table MODIFY class VARCHAR(255) DEFAULT NULL;"; | |
| 497 | + $queries[] = "ALTER TABLE $capability_table MODIFY object VARCHAR(255) DEFAULT NULL;"; | |
| 498 | + // correct capabilities | |
| 499 | + $queries[] = "UPDATE $capability_table SET capability='delete_published_pages' WHERE capability='delete_published_pag';"; | |
| 500 | + $queries[] = "UPDATE $capability_table SET capability='delete_published_posts' WHERE capability='delete_published_pos';"; | |
| 276 | 501 | } |
| 502 | + break; | |
| 503 | + default : | |
| 504 | + if ( !empty( $previous_version ) ) { | |
| 505 | + if ( version_compare( $previous_version, '1.1.6' ) < 0 ) { | |
| 506 | + Groups_Options::update_option( Groups_Post_Access::READ_POST_CAPABILITIES, array( Groups_Post_Access::READ_POST_CAPABILITY ) ); | |
| 507 | + $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = %s WHERE meta_key = %s", Groups_Post_Access::READ_POST_CAPABILITY, Groups_Post_Access::POSTMETA_PREFIX . Groups_Post_Access::READ_POST_CAPABILITY ) ); | |
| 508 | + } | |
| 509 | + if ( version_compare( $previous_version, '1.5.1' ) < 0 ) { | |
| 510 | + $capability_table = _groups_get_tablename( 'capability' ); | |
| 511 | + $queries[] = "ALTER TABLE $capability_table DROP INDEX capability, ADD UNIQUE INDEX capability(capability(100));"; | |
| 512 | + } | |
| 513 | + } | |
| 514 | + } // switch | |
| 515 | + if ( !empty( $previous_version ) && version_compare( $previous_version, '2.0.0' ) < 0 ) { | |
| 516 | + self::set_default_capabilities(); | |
| 517 | + Groups_WordPress::refresh_capabilities(); | |
| 518 | + } | |
| 519 | + foreach ( $queries as $query ) { | |
| 520 | + if ( $wpdb->query( $query ) === false ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 521 | + $result = false; | |
| 277 | 522 | } |
| 278 | - } // switch | |
| 279 | - foreach ( $queries as $query ) { | |
| 280 | - if ( $wpdb->query( $query ) === false ) { | |
| 281 | - $result = false; | |
| 282 | 523 | } |
| 283 | 524 | } |
| 284 | 525 | return $result; |
| 285 | 526 | } |
| 286 | - | |
| 527 | + | |
| 287 | 528 | /** |
| 288 | 529 | * Drop tables and clear data if the plugin is deactivated. |
| 289 | 530 | * This will happen only if the user chooses to delete data upon deactivation. |
| 531 | + * | |
| 290 | 532 | * @param boolean $network_wide |
| 291 | 533 | */ |
| 292 | 534 | public static function deactivate( $network_wide = false ) { |
| 293 | - if ( is_multisite() && $network_wide ) { | |
| 294 | - if ( Groups_Options::get_option( 'groups_network_delete_data', false ) ) { | |
| 295 | - $blog_ids = Groups_Utility::get_blogs(); | |
| 296 | - foreach ( $blog_ids as $blog_id ) { | |
| 297 | - self::switch_to_blog( $blog_id ); | |
| 298 | - self::cleanup( true ); | |
| 299 | - self::restore_current_blog(); | |
| 535 | + $sem_id = self::sem_get( self::get_sem_key() ); | |
| 536 | + if ( ( $sem_id === false ) || self::sem_acquire( $sem_id ) ) { | |
| 537 | + if ( is_multisite() && $network_wide ) { | |
| 538 | + if ( Groups_Options::get_option( 'groups_network_delete_data', false ) ) { | |
| 539 | + $blog_ids = Groups_Utility::get_blogs(); | |
| 540 | + foreach ( $blog_ids as $blog_id ) { | |
| 541 | + self::switch_to_blog( $blog_id ); | |
| 542 | + self::cleanup( true ); | |
| 543 | + self::restore_current_blog(); | |
| 544 | + } | |
| 300 | 545 | } |
| 546 | + } else { | |
| 547 | + self::cleanup(); | |
| 301 | 548 | } |
| 302 | - } else { | |
| 303 | - self::cleanup(); | |
| 549 | + if ( $sem_id !== false ) { | |
| 550 | + self::sem_release( $sem_id ); | |
| 551 | + self::sem_remove( $sem_id ); | |
| 552 | + } | |
| 304 | 553 | } |
| 305 | 554 | } |
| 306 | - | |
| 555 | + | |
| 307 | 556 | /** |
| 308 | 557 | * Plugin deactivation cleanup. |
| 309 | - * @param $drop overrides the groups_delete_data option, default is false | |
| 558 | + * | |
| 559 | + * @param $drop boolean overrides the groups_delete_data option, default is false | |
| 310 | 560 | */ |
| 311 | 561 | private static function cleanup( $drop = false ) { |
| 312 | - | |
| 562 | + | |
| 313 | 563 | global $wpdb, $wp_roles; |
| 314 | - | |
| 564 | + | |
| 315 | 565 | $delete_data = Groups_Options::get_option( 'groups_delete_data', false ); |
| 316 | 566 | if ( $delete_data || $drop ) { |
| 317 | 567 | foreach ( $wp_roles->role_objects as $role ) { |
| 318 | 568 | $role->remove_cap( GROUPS_ACCESS_GROUPS ); |
| @@ -317,22 +567,63 @@ | ||
| 317 | 567 | foreach ( $wp_roles->role_objects as $role ) { |
| 318 | 568 | $role->remove_cap( GROUPS_ACCESS_GROUPS ); |
| 319 | 569 | $role->remove_cap( GROUPS_ADMINISTER_GROUPS ); |
| 320 | 570 | $role->remove_cap( GROUPS_ADMINISTER_OPTIONS ); |
| 571 | + $role->remove_cap( GROUPS_RESTRICT_ACCESS ); | |
| 321 | 572 | } |
| 322 | - $wpdb->query('DROP TABLE IF EXISTS ' . _groups_get_tablename( 'group' ) ); | |
| 323 | - $wpdb->query('DROP TABLE IF EXISTS ' . _groups_get_tablename( 'capability' ) ); | |
| 324 | - $wpdb->query('DROP TABLE IF EXISTS ' . _groups_get_tablename( 'user_group' ) ); | |
| 325 | - $wpdb->query('DROP TABLE IF EXISTS ' . _groups_get_tablename( 'user_capability' ) ); | |
| 326 | - $wpdb->query('DROP TABLE IF EXISTS ' . _groups_get_tablename( 'group_capability' ) ); | |
| 573 | + $wpdb->query( 'DROP TABLE IF EXISTS ' . _groups_get_tablename( 'group' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 574 | + $wpdb->query( 'DROP TABLE IF EXISTS ' . _groups_get_tablename( 'capability' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 575 | + $wpdb->query( 'DROP TABLE IF EXISTS ' . _groups_get_tablename( 'user_group' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 576 | + $wpdb->query( 'DROP TABLE IF EXISTS ' . _groups_get_tablename( 'user_capability' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 577 | + $wpdb->query( 'DROP TABLE IF EXISTS ' . _groups_get_tablename( 'group_capability' ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared | |
| 327 | 578 | Groups_Options::flush_options(); |
| 328 | - delete_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE ); | |
| 579 | + if ( class_exists( 'Groups_Admin_Notice' ) ) { | |
| 580 | + delete_metadata( 'user', null, Groups_Admin_Notice::HIDE_REVIEW_NOTICE, null, true ); | |
| 581 | + delete_site_option( Groups_Admin_Notice::INIT_TIME ); | |
| 582 | + } | |
| 583 | + delete_option( GROUPS_ADMINISTRATOR_ACCESS_OVERRIDE ); // keep this to delete the deprecated option @since 2.1.1 | |
| 329 | 584 | delete_option( 'groups_plugin_version' ); |
| 330 | 585 | delete_option( 'groups_delete_data' ); |
| 331 | 586 | } |
| 332 | 587 | } |
| 333 | - | |
| 588 | + | |
| 334 | 589 | /** |
| 590 | + * Whether this is an individual activation of the plugin. | |
| 591 | + * | |
| 592 | + * @since 3.3.1 | |
| 593 | + * | |
| 594 | + * @return boolean | |
| 595 | + */ | |
| 596 | + private static function is_single_activate() { | |
| 597 | + $is = false; | |
| 598 | + $groups_basename = plugin_basename( GROUPS_FILE ); | |
| 599 | + $action = groups_sanitize_request( 'action' ); | |
| 600 | + if ( is_string( $action ) ) { | |
| 601 | + switch ( $action ) { | |
| 602 | + case 'activate': | |
| 603 | + // Single plugin activation of Groups: | |
| 604 | + $slug = groups_sanitize_request( 'plugin' ); | |
| 605 | + if ( $slug === $groups_basename ) { | |
| 606 | + $is = true; | |
| 607 | + } | |
| 608 | + break; | |
| 609 | + case 'activate-selected': | |
| 610 | + // Bulk plugin activation of Groups but it is the only plugin being activated: | |
| 611 | + $slugs = groups_sanitize_request( 'checked' ); | |
| 612 | + if ( is_array( $slugs ) && count( $slugs ) === 1 ) { | |
| 613 | + $slug = array_pop( $slugs ); | |
| 614 | + if ( $slug === $groups_basename ) { | |
| 615 | + $is = true; | |
| 616 | + break; | |
| 617 | + } | |
| 618 | + } | |
| 619 | + break; | |
| 620 | + } | |
| 621 | + } | |
| 622 | + return $is; | |
| 623 | + } | |
| 624 | + | |
| 625 | + /** | |
| 335 | 626 | * Determines the default capabilities for the administrator role. |
| 336 | 627 | * In lack of an administrator role, these capabilities are assigned |
| 337 | 628 | * to any role that can manage_options. |
| 338 | 629 | * This is also used to assure a minimum set of capabilities is |
| @@ -339,9 +630,9 @@ | ||
| 339 | 630 | * assigned to an appropriate role, so that it's not possible |
| 340 | 631 | * to lock yourself out (although deactivating and then activating |
| 341 | 632 | * the plugin would have the same effect but with the danger of |
| 342 | 633 | * deleting all plugin data). |
| 343 | - * @param boolean $activate defaults to true, when this function is called upon plugin activation | |
| 634 | + * | |
| 344 | 635 | * @access private |
| 345 | 636 | */ |
| 346 | 637 | public static function set_default_capabilities() { |
| 347 | 638 | global $wp_roles; |
| @@ -350,8 +641,9 @@ | ||
| 350 | 641 | if ( $administrator_role = $wp_roles->get_role( 'administrator' ) ) { |
| 351 | 642 | $administrator_role->add_cap( GROUPS_ACCESS_GROUPS ); |
| 352 | 643 | $administrator_role->add_cap( GROUPS_ADMINISTER_GROUPS ); |
| 353 | 644 | $administrator_role->add_cap( GROUPS_ADMINISTER_OPTIONS ); |
| 645 | + $administrator_role->add_cap( GROUPS_RESTRICT_ACCESS ); | |
| 354 | 646 | } else { |
| 355 | 647 | foreach ( $wp_roles->role_objects as $role ) { |
| 356 | 648 | if ($role->has_cap( 'manage_options' ) ) { |
| 357 | 649 | $role->add_cap( GROUPS_ACCESS_GROUPS ); |
| @@ -356,13 +648,14 @@ | ||
| 356 | 648 | if ($role->has_cap( 'manage_options' ) ) { |
| 357 | 649 | $role->add_cap( GROUPS_ACCESS_GROUPS ); |
| 358 | 650 | $role->add_cap( GROUPS_ADMINISTER_GROUPS ); |
| 359 | 651 | $role->add_cap( GROUPS_ADMINISTER_OPTIONS ); |
| 652 | + $role->add_cap( GROUPS_RESTRICT_ACCESS ); | |
| 360 | 653 | } |
| 361 | 654 | } |
| 362 | 655 | } |
| 363 | 656 | } |
| 364 | - | |
| 657 | + | |
| 365 | 658 | /** |
| 366 | 659 | * There must be at least one role with the minimum set of capabilities |
| 367 | 660 | * to access and manage the Groups plugin's options. |
| 368 | 661 | * If this condition is not met, the minimum set of capabilities is |
| @@ -371,9 +664,9 @@ | ||
| 371 | 664 | public static function assure_capabilities() { |
| 372 | 665 | global $wp_roles; |
| 373 | 666 | $complies = false; |
| 374 | 667 | $roles = $wp_roles->role_objects; |
| 375 | - foreach( $roles as $role ) { | |
| 668 | + foreach ( $roles as $role ) { | |
| 376 | 669 | if ( $role->has_cap( GROUPS_ACCESS_GROUPS ) && ( $role->has_cap( GROUPS_ADMINISTER_OPTIONS ) ) ) { |
| 377 | 670 | $complies = true; |
| 378 | 671 | break; |
| 379 | 672 | } |
| @@ -382,6 +675,104 @@ | ||
| 382 | 675 | self::set_default_capabilities(); |
| 383 | 676 | } |
| 384 | 677 | } |
| 385 | 678 | |
| 679 | + /** | |
| 680 | + * Guarded sem_get() wrapper. | |
| 681 | + * | |
| 682 | + * @see sem_get() | |
| 683 | + * | |
| 684 | + * @param int $key | |
| 685 | + * @param number $max_acquire | |
| 686 | + * @param number $perm | |
| 687 | + * @param number $auto_release | |
| 688 | + * | |
| 689 | + * @return boolean|resource | |
| 690 | + */ | |
| 691 | + private static function sem_get( $key, $max_acquire = 1, $perm = 0666, $auto_release = 1 ) { | |
| 692 | + $result = false; | |
| 693 | + if ( function_exists( 'sem_get' ) ) { | |
| 694 | + $result = sem_get( $key, $max_acquire, $perm, $auto_release ); | |
| 695 | + } | |
| 696 | + return $result; | |
| 697 | + } | |
| 698 | + | |
| 699 | + /** | |
| 700 | + * Guarded sem_acquire() wrapper. | |
| 701 | + * | |
| 702 | + * To maintain backwards-compatibility with servers running PHP < 5.6 where | |
| 703 | + * the second parameter to sem_acquire() is not supported, we use sem_remove() | |
| 704 | + * and have any calls waiting on sem_acquire() fail silently (achieving that | |
| 705 | + * the activation, update or deactivation routines are not run for those | |
| 706 | + * processes that have been waiting and which would have duplicated execution | |
| 707 | + * unnecessarily). | |
| 708 | + * | |
| 709 | + * @see sem_acquire() | |
| 710 | + * | |
| 711 | + * @param resource $sem_identifier | |
| 712 | + * @param boolean $nowait (only taken into account and effective on PHP >= 5.6.1) | |
| 713 | + * | |
| 714 | + * @return boolean | |
| 715 | + */ | |
| 716 | + private static function sem_acquire( $sem_identifier, $nowait = false ) { | |
| 717 | + $result = false; | |
| 718 | + if ( function_exists( 'sem_acquire' ) ) { | |
| 719 | + if ( version_compare( phpversion(), '5.6.1' ) >= 0 ) { | |
| 720 | + $result = @sem_acquire( $sem_identifier, $nowait ); | |
| 721 | + } else { | |
| 722 | + $result = @sem_acquire( $sem_identifier ); | |
| 723 | + } | |
| 724 | + } | |
| 725 | + return $result; | |
| 726 | + } | |
| 727 | + | |
| 728 | + /** | |
| 729 | + * Guarded sem_release() wrapper. | |
| 730 | + * | |
| 731 | + * @see sem_release() | |
| 732 | + * | |
| 733 | + * @param resource $sem_identifier | |
| 734 | + * | |
| 735 | + * @return boolean | |
| 736 | + */ | |
| 737 | + private static function sem_release( $sem_identifier ) { | |
| 738 | + $result = false; | |
| 739 | + if ( function_exists( 'sem_release' ) ) { | |
| 740 | + $result = @sem_release( $sem_identifier ); | |
| 741 | + } | |
| 742 | + return $result; | |
| 743 | + } | |
| 744 | + | |
| 745 | + /** | |
| 746 | + * Guarded sem_remove() wrapper. | |
| 747 | + * | |
| 748 | + * @see sem_remove() | |
| 749 | + * | |
| 750 | + * @param resource $sem_identifier | |
| 751 | + * | |
| 752 | + * @return boolean | |
| 753 | + */ | |
| 754 | + private static function sem_remove( $sem_identifier ) { | |
| 755 | + $result = false; | |
| 756 | + if ( function_exists( 'sem_remove' ) ) { | |
| 757 | + $result = @sem_remove( $sem_identifier ); | |
| 758 | + } | |
| 759 | + return $result; | |
| 760 | + } | |
| 761 | + | |
| 762 | + /** | |
| 763 | + * Produces a file-based key for use with sem_get(). | |
| 764 | + * | |
| 765 | + * @return number | |
| 766 | + */ | |
| 767 | + private static function get_sem_key() { | |
| 768 | + $key = -1; | |
| 769 | + if ( function_exists( 'ftok' ) ) { | |
| 770 | + $key = ftok( __FILE__, 'g' ); | |
| 771 | + } | |
| 772 | + if ( $key == -1 ) { | |
| 773 | + $key = fileinode( __FILE__ ); | |
| 774 | + } | |
| 775 | + return $key; | |
| 776 | + } | |
| 386 | 777 | } |
| 387 | 778 | Groups_Controller::boot(); |