*/ class Wp_Database_Tools_Matching { /** * The information of the plugins formatted * * @since 1.0.0 * @access protected * @var array $plugins The plugins data. */ protected $plugins; /** * The information of the themes formatted * * @since 1.0.0 * @access protected * @var array $themes The themes data. */ protected $themes; /** * Constructor * * Create the instance of a Matching. * * @access public * @since 1.0.0 * * @param Wp_Database_Tools_Plugins $plugins Plugin Obj. * @param Wp_Database_Tools_Themes $themes Theme Obj. */ public function __construct( $plugins, $themes ) { $this->plugins = $plugins->get_plugins(); $this->themes = $themes->get_themes(); } /** * Searches for possible matches of origins and returns matches * sorted by the level of probability of a match. * * @access public * @since 1.0.0 * * @param String $type Values plugin|theme. * @param String $source_name Name of the source. * @param String $source_value Value of the source. * * @return Array match found. */ public function find_match( $type, $source_name, $source_value ) { $MATCHING_LVL = 100; if ( 'plugin' === $type ) { $search_origin = $this->plugins; $search_text_domain = true; } if ( 'theme' === $type ) { $search_origin = $this->themes; $search_text_domain = false; } $concidences_slugs = array(); // We go through all possible sources (plugins or themes) looking for matches. foreach ( $search_origin as $key => $origin ) { // Porcent match. $match_results = array(); // Text Domain. if ( $search_text_domain === true ) { $text_domain = $origin['text_domain']; $match = $this->search_by_text_domain( $text_domain, $source_name ); array_push( $match_results, $match ); } // Slugs. $slug = $origin['slug']; $name = $origin['name']; if ( $source_value !== null ) { if ( str_contains( $source_name, 'edd_' ) ) { $match = $this->search_by_value( $slug, $name, $source_value ); array_push( $match_results, $match ); } } $match = $this->search_by_text_slug( $slug, $source_name ); array_push( $match_results, $match ); // Initials. $initials = $origin['initials']; if ( strlen( $initials ) >= 3 && strlen( $initials ) <= 5 ) { $match = $this->search_by_starts_initials( $initials, $source_name ); array_push( $match_results, $match ); if ( str_contains( $slug, 'premium' ) || str_contains( $slug, 'pro' ) ) { if ( substr( $initials, -1 ) == 'p' ) { $match = $this->search_by_starts_initials_without_last( $initials, $source_name ); array_push( $match_results, $match ); } } $match = $this->search_by_starts_initials_similar( $initials, $source_name ); array_push( $match_results, $match ); } $match = $this->search_by_similar_slug( $slug, $source_name ); array_push( $match_results, $match ); // Search main file. if ( isset( $origin['path'] ) ) { $path = $origin['path']; $match = $this->search_main_file( $path, $source_name, $initials ); array_push( $match_results, $match ); } // Order array. asort( $match_results ); $concidences_slugs[ $slug ] = end( $match_results ); unset( $origin ); } // Order array. asort( $concidences_slugs ); // Get value if the match if hightest. if ( end( $concidences_slugs ) >= $MATCHING_LVL ) { $data_return = array( 'slug' => array_key_last( $concidences_slugs ), 'match' => end( $concidences_slugs ), ); return $data_return; } return null; } /** * Return longest char match between two strings * * @access protected * @since 1.0.0 * * @param String $str1 First string to compare. * @param String $str2 Second string to compare. * * @return int longest match. */ protected function get_longest_matching_substring( $str1, $str2 ) { $len_1 = strlen( $str1 ); $longest = ''; for ( $i = 0; $i < $len_1; $i++ ) { for ( $j = $len_1 - $i; $j > 0; $j-- ) { $sub = substr( $str1, $i, $j ); if ( strpos( $str2, $sub ) !== false && strlen( $sub ) > strlen( $longest ) ) { $longest = $sub; break; } } } return strlen( $longest ); } /** * Compare the slug of the plugin or theme with the name of the source * (options, cronjobs...) to find a match. * * The comparison is done by looking for an exact match of the same string * at its beginning. * * @access protected * @since 1.0.0 * * @param String $slug Slug of origin. * @param String $source_name Name of the source. * * @return int longest match. */ protected function search_by_similar_slug( $slug, $source_name ) { $slug_name = preg_split( '/-|_/', $slug ); $source_name = str_replace( array( '_', '-' ), '_', $source_name ); $match = 0; foreach ( $slug_name as $key => $slug ) { if ( $key == 0 ) { $slug_search = $slug_name[0] . '_'; } if ( $key == 1 ) { $slug_search = $slug_name[0] . '_' . $slug_name[1] . '_'; } if ( $key == 2 ) { $slug_search = $slug_name[0] . '_' . $slug_name[1] . '_' . $slug_name[2] . '_'; } $slug_length = strlen( $slug_search ); if ( str_starts_with( $source_name, $slug_search ) && $slug_length > 3 ) { $match += $slug_length + 100; } } return $match; } /** * Compare the slug of the plugin or theme with the name of the source * (options, cronjobs...) to find a match. * * The comparison is made on the basis of the highest coincidence between * the achievement of their chars. * * @access protected * @since 1.0.0 * * @param String $slug Slug of origin. * @param String $source_name Name of the source. * * @return int longest match. */ protected function search_by_text_slug( $slug, $source_name ) { $slug = str_replace( array( '_', '-' ), '', $slug ); $source_name = str_replace( array( '_', '-' ), '', $source_name ); $slug = strtolower( $slug ); $source_name = strtolower( $source_name ); $slug_length = strlen( $slug ); $result = $this->get_longest_matching_substring( $slug, $source_name ); $match = ( $result * 100 ) / $slug_length; $match += $slug_length; return $match; } /** * Compare text_domain slug of the plugin or theme with the name of the source * (options, cronjobs...) to find a match. * * The comparison is made on the basis of the highest coincidence between * the achievement of their chars. * * @access protected * @since 1.0.0 * * @param String $text_domain Slug of origin. * @param String $source_name Name of the source. * * @return int match. */ protected function search_by_text_domain( $text_domain, $source_name ) { $text_domain = str_replace( array( '_', '-' ), '', $text_domain ); $source_name = str_replace( array( '_', '-' ), '', $source_name ); $text_domain = strtolower( $text_domain ); $source_name = strtolower( $source_name ); $text_domain_length = strlen( $text_domain ); $result = $this->get_longest_matching_substring( $text_domain, $source_name ); $match = ( $result * 100 ) / $text_domain_length; $match += $text_domain_length; return $match; } /** * Compare initials of the plugin or theme with the name of the source * (options, cronjobs...) to find a match. * * @access protected * @since 1.0.0 * * @param String $initials Initials of origin. * @param String $source_name Name of the source. * * @return int match. */ protected function search_by_starts_initials( $initials, $source_name ) { $source_name = preg_split( '/-|_/', $source_name ); if ( count( $source_name ) > 1 ) { $start_name = $source_name[0]; $match = ( $start_name === $initials ) ? 100 : 0; return $match; } return 0; } /** * Compare initials of the plugin or theme with the name of the source * (options, cronjobs...) to find a match. * * We search by initials omitting the last character. * This is checked to avoid comparisons with words * like "pro" or "lite" at the end. * * @access protected * @since 1.0.0 * * @param String $initials Initials of origin. * @param String $source_name Name of the source. * * @return int match. */ protected function search_by_starts_initials_without_last( $initials, $source_name ) { $source_name = preg_split( '/-|_/', $source_name ); if ( count( $source_name ) > 1 ) { $start_name = $source_name[0]; $match = ( $start_name == substr_replace( $initials, '', -1 ) ) ? 100 : 0; return $match; } return 0; } /** * Compare initials of the plugin or theme with the name of the source * (options, cronjobs...) to find a match. * * We compare the similarity of the initials * * @access protected * @since 1.0.0 * * @param String $initials Initials of origin. * @param String $source_name Name of the source. * * @return int match. */ protected function search_by_starts_initials_similar( $initials, $source_name ) { $initials = strtolower( $initials ); $source_name = strtolower( $source_name ); $source_name = preg_split( '/-|_/', $source_name ); if ( count( $source_name ) > 1 ) { $start_name = $source_name[0]; similar_text( $initials, $start_name, $match ); return $match; } return 0; } /** * We look for matches in the value of the origins (options,tables,cronjobs) * by comparing with the slug and name of the source (themes,plugins). * * @access protected * @since 1.0.0 * * @param String $slug Initials of origin. * @param String $name Name of the source. * @param String $source_value Name of the source. * * @return int match. */ protected function search_by_value( $slug, $name, $source_value ) { $content = strtolower( $source_value ); if ( str_contains( $content, strtolower( $slug ) ) ) { return 100; } if ( str_contains( $content, strtolower( $name ) ) ) { return 100; } return 0; } /** * We look for matches in the origins file (themes,plugins) * comparing with the value of the sources (cronjobs,options,tables). * * @access protected * @since 1.0.0 * * @param String $path The file path. * @param String $source_name Name of the source. * @param String $initials Initials of the source. * * @return int match. */ protected function search_main_file( $path, $source_name, $initials ) { $prefix_source = preg_split( '/-|_/', $source_name ); if ( count( $prefix_source ) > 1 ) { if ( $prefix_source[0] != 'edd' ) { if ( strlen( $prefix_source[0] ) >= 3 ) { $content = strtolower( file_get_contents( WP_PLUGIN_DIR . '/' . $path ) ); $regex = '/("|\')' . $prefix_source[0] . '(_|-)/i'; // Search on main file. preg_match( $regex, $content, $concidences ); if ( count( $concidences ) > 0 ) { similar_text( $concidences[0], $prefix_source[0], $percent ); if ( $percent >= 80 ) { return intval( $percent ); } similar_text( $concidences[0], $initials, $percent ); if ( $percent >= 80 ) { return intval( $percent ); } return 0; } } } } return 0; } }