plugin_root = rtrim( $this->normalize_path( $root ), '/' ); } /** * Whether the plugin that owns a loaded class is currently active. * * @param string $class_name Fully qualified provider class name. */ public function is_class_owner_active( string $class_name ): bool { if ( '' === $this->plugin_root || ! class_exists( $class_name ) ) { return false; } try { $reflection = new ReflectionClass( $class_name ); $source_file = $reflection->getFileName(); } catch ( ReflectionException $exception ) { unset( $exception ); return false; } if ( false === $source_file ) { return false; } $relative_source = $this->get_relative_source_path( $source_file ); if ( '' === $relative_source ) { return false; } foreach ( $this->get_active_plugin_files() as $plugin_file ) { if ( $this->plugin_owns_source( $plugin_file, $relative_source ) ) { return true; } } return false; } /** * Get current site and network active plugin files without persistent caching. * * @return array */ private function get_active_plugin_files(): array { $active_plugins = function_exists( 'get_option' ) ? get_option( 'active_plugins', array() ) : array(); $network_plugins = function_exists( 'get_site_option' ) ? get_site_option( 'active_sitewide_plugins', array() ) : array(); $plugin_files = array(); if ( is_array( $active_plugins ) ) { foreach ( $active_plugins as $plugin_file ) { if ( is_string( $plugin_file ) ) { $plugin_files[] = $plugin_file; } } } if ( is_array( $network_plugins ) ) { foreach ( $network_plugins as $plugin_file => $activated_at ) { if ( is_string( $plugin_file ) ) { $plugin_files[] = $plugin_file; } elseif ( is_string( $activated_at ) ) { $plugin_files[] = $activated_at; } } } return array_values( array_unique( array_map( array( $this, 'normalize_plugin_file' ), $plugin_files ) ) ); } /** * Convert a reflected source file to a path relative to the plugin root. * * @param string $source_file Reflected source file. */ private function get_relative_source_path( string $source_file ): string { $source_file = $this->normalize_path( $source_file ); $root_prefix = strtolower( $this->plugin_root . '/' ); if ( 0 !== strpos( strtolower( $source_file ), $root_prefix ) ) { return ''; } return ltrim( substr( $source_file, strlen( $root_prefix ) ), '/' ); } /** * Whether an active plugin entry owns a reflected relative source path. * * @param string $plugin_file Active plugin file. * @param string $relative_source Relative source path. */ private function plugin_owns_source( string $plugin_file, string $relative_source ): bool { if ( '' === $plugin_file || '' === $relative_source ) { return false; } $plugin_file = strtolower( $plugin_file ); $relative_source = strtolower( $relative_source ); $plugin_dir = dirname( $plugin_file ); if ( '.' === $plugin_dir ) { return $plugin_file === $relative_source; } return 0 === strpos( $relative_source, rtrim( $plugin_dir, '/' ) . '/' ); } /** * Normalize a plugin option entry. * * @param string $plugin_file Plugin file. */ private function normalize_plugin_file( string $plugin_file ): string { $plugin_file = ltrim( $this->normalize_path( $plugin_file ), '/' ); if ( '' === $plugin_file || false !== strpos( $plugin_file, '../' ) ) { return ''; } return $plugin_file; } /** * Normalize filesystem separators. * * @param string $path Path. */ private function normalize_path( string $path ): string { return str_replace( '\\', '/', $path ); } }