version adapted from WP 4.8.2 (unchanged since 4.5.0) * * @param string $path Path to normalize. * * @return string Normalized path. */ public static function normalizePath( $path ) { if ( function_exists( 'wp_normalize_path' ) ) { return wp_normalize_path( $path ); } $path = str_replace( '\\', '/', $path ); $path = preg_replace( '|(?<=.)/+|', '/', $path ); if ( substr( $path, 1, 1 ) === ':' ) { $path = ucfirst( $path ); } return $path; } /** * Check if the path points to a plugin file. * * @param string $absolutePath Normalized path. * * @return bool */ protected static function isPluginFile( $absolutePath ) { //Is the file inside the "plugins" or "mu-plugins" directory? $pluginDir = self::normalizePath( WP_PLUGIN_DIR ); $muPluginDir = self::normalizePath( WPMU_PLUGIN_DIR ); if ( ( strpos( $absolutePath, $pluginDir ) === 0 ) || ( strpos( $absolutePath, $muPluginDir ) === 0 ) ) { return true; } //Is it a file at all? Caution: is_file() can fail if the parent dir. doesn't have the +x permission set. if ( ! is_file( $absolutePath ) ) { return false; } //Does it have a valid plugin header? //This is a last-ditch check for plugins symlinked from outside the WP root. if ( function_exists( 'get_file_data' ) ) { $headers = get_file_data( $absolutePath, array( 'Name' => 'Plugin Name' ), 'plugin' ); return ! empty( $headers['Name'] ); } return false; } /** * Get the name of the theme's directory from a full path to a file inside that directory. * E.g. "/abc/public_html/wp-content/themes/foo/whatever.php" => "foo". * * Note that subdirectories are currently not supported. For example, * "/xyz/wp-content/themes/my-theme/includes/whatever.php" => NULL. * * @param string $absolutePath Normalized path. * * @return string|null Directory name, or NULL if the path doesn't point to a theme. */ protected static function getThemeDirectoryName( $absolutePath ) { if ( is_file( $absolutePath ) ) { $absolutePath = dirname( $absolutePath ); } if ( file_exists( $absolutePath . '/style.css' ) ) { return basename( $absolutePath ); } return null; } /** * Get the name of the hosting service that the URL points to. * * @param string $metadataUrl * * @return string|null */ private static function getVcsService( $metadataUrl ) { $service = null; //Which hosting service does the URL point to? $host = @parse_url( $metadataUrl, PHP_URL_HOST ); $path = @parse_url( $metadataUrl, PHP_URL_PATH ); //Check if the path looks like "/user-name/repository". $usernameRepoRegex = '@^/?([^/]+?)/([^/#?&]+?)/?$@'; if ( preg_match( $usernameRepoRegex, $path ) ) { $knownServices = array( 'github.com' => 'GitHub', 'bitbucket.org' => 'BitBucket', 'gitlab.com' => 'GitLab', ); if ( isset( $knownServices[ $host ] ) ) { $service = $knownServices[ $host ]; } } return $service; } /** * Get the latest version of the specified class that has the same major version number * as this factory class. * * @param string $class Partial class name. * * @return string|null Full class name. */ protected static function getCompatibleClassVersion( $class ) { if ( isset( self::$classVersions[ $class ][ self::$latestCompatibleVersion ] ) ) { return self::$classVersions[ $class ][ self::$latestCompatibleVersion ]; } return null; } /** * Get the specific class name for the latest available version of a class. * * @param string $class * * @return null|string */ public static function getLatestClassVersion( $class ) { if ( ! self::$sorted ) { self::sortVersions(); } if ( isset( self::$classVersions[ $class ] ) ) { return reset( self::$classVersions[ $class ] ); } else { return null; } } /** * Sort available class versions in descending order (i.e. newest first). */ protected static function sortVersions() { foreach ( self::$classVersions as $class => $versions ) { uksort( $versions, array( __CLASS__, 'compareVersions' ) ); self::$classVersions[ $class ] = $versions; } self::$sorted = true; } protected static function compareVersions( $a, $b ) { return - version_compare( $a, $b ); } /** * Register a version of a class. * * @access private This method is only for internal use by the library. * * @param string $generalClass Class name without version numbers, e.g. 'PluginUpdateChecker'. * @param string $versionedClass Actual class name, e.g. 'PluginUpdateChecker_1_2'. * @param string $version Version number, e.g. '1.2'. */ public static function addVersion( $generalClass, $versionedClass, $version ) { if ( empty( self::$myMajorVersion ) ) { $nameParts = explode( '_', __CLASS__, 3 ); self::$myMajorVersion = substr( ltrim( $nameParts[1], 'v' ), 0, 1 ); } //Store the greatest version number that matches our major version. $components = explode( '.', $version ); if ( $components[0] === self::$myMajorVersion ) { if ( empty( self::$latestCompatibleVersion ) || version_compare( $version, self::$latestCompatibleVersion, '>' ) ) { self::$latestCompatibleVersion = $version; } } if ( ! isset( self::$classVersions[ $generalClass ] ) ) { self::$classVersions[ $generalClass ] = array(); } self::$classVersions[ $generalClass ][ $version ] = $versionedClass; self::$sorted = false; } } endif;