![]() Server : Apache System : Linux pod-100823:apache2_74:v0.5.9 5.4.0-1138-gcp #147~18.04.1-Ubuntu SMP Mon Oct 7 21:46:26 UTC 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.33.9 Disable Function : apache_child_terminate,apache_get_modules,apache_get_version,apache_getenv,apache_note,apache_setenv,disk_free_space,disk_total_space,diskfreespace,dl,exec,fastcgi_finish_request,link,opcache_compile_file,opcache_get_configuration,opcache_invalidate,opcache_is_script_cached,opcache_reset,passthru,pclose,pcntl_exec,popen,posix_getpid,posix_getppid,posix_getpwuid,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_uname,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,realpath_cache_get,shell_exec,show_source,symlink,system Directory : /nas/content/live/attorneyexperi/wp-content/plugins/diva/src/Support/ |
<?php /** * Class to prepare and send support data to insights server. * * @package AmpProject\AmpWP */ namespace AmpProject\AmpWP\Support; use AMP_Options_Manager; use AMP_Validated_URL_Post_Type; use AMP_Validation_Manager; use WP_Error; use WP_Post; use WP_Query; use WP_Site_Health; use WP_Term; use WP_Theme; /** * Class SupportData * To prepare and send support data to insights server. * * @internal * @since 2.2 */ class SupportData { /** * Endpoint to send diagnostic data. * * @since 2.2 * * @var string */ const SUPPORT_ENDPOINT = 'https://insights.amp-wp.org'; /** * Args for AMP send data. * * @since 2.2 * * @var array [ * @type string[] $urls Optional * @type int[] $term_ids Optional * @type int[] $post_ids Optional * @type int[] $amp_validated_post_ids Optional * ] */ public $args = []; /** * List of URL to send data. * * @since 2.2 * * @var string[] */ public $urls = []; /** * Support Data. * * @var array */ private $data = []; /** * Constructor method. * * @since 2.2 * * @param array $args Arguments for AMP Send data. */ public function __construct( $args = [] ) { $this->args = ( ! empty( $args ) && is_array( $args ) ) ? $args : []; $this->parse_args(); $this->data = []; } /** * To parse args for AMP data that will send. * * @since 2.2 * * @return void */ public function parse_args() { if ( ! empty( $this->args['urls'] ) && is_array( $this->args['urls'] ) ) { $this->urls = array_merge( $this->urls, $this->args['urls'] ); } if ( ! empty( $this->args['term_ids'] ) && is_array( $this->args['term_ids'] ) ) { $this->args['term_ids'] = array_map( 'intval', $this->args['term_ids'] ); $this->args['term_ids'] = array_filter( $this->args['term_ids'] ); foreach ( $this->args['term_ids'] as $term_id ) { $url = get_term_link( $term_id ); if ( ! empty( $url ) && ! is_wp_error( $url ) ) { $this->urls[] = $url; } } } if ( ! empty( $this->args['post_ids'] ) && is_array( $this->args['post_ids'] ) ) { $this->args['post_ids'] = array_map( 'intval', $this->args['post_ids'] ); $this->args['post_ids'] = array_filter( $this->args['post_ids'] ); foreach ( $this->args['post_ids'] as $post_id ) { $url = get_permalink( $post_id ); if ( ! empty( $url ) && ! is_wp_error( $url ) ) { $this->urls[] = $url; } } } if ( ! empty( $this->args['amp_validated_post_ids'] ) && is_array( $this->args['amp_validated_post_ids'] ) ) { $this->args['amp_validated_post_ids'] = array_map( 'intval', $this->args['amp_validated_post_ids'] ); $this->args['amp_validated_post_ids'] = array_filter( $this->args['amp_validated_post_ids'] ); foreach ( $this->args['amp_validated_post_ids'] as $post_id ) { $post = get_post( $post_id ); if ( ! empty( $post->post_title ) ) { $this->urls[] = $post->post_title; } } } $this->urls = array_map( static function ( $url ) { if ( filter_var( $url, FILTER_VALIDATE_URL ) ) { return AMP_Validated_URL_Post_Type::normalize_url_for_storage( $url ); } return false; }, $this->urls ); $this->urls = array_values( array_unique( array_filter( $this->urls ) ) ); } /** * To send support data to insight server. * * @return array|WP_Error WP_Error on fail, Otherwise server response. */ public function send_data() { $data = ( ! empty( $this->data ) ) ? $this->data : $this->get_data(); $endpoint = ( ! empty( $this->args['endpoint'] ) ) ? $this->args['endpoint'] : self::SUPPORT_ENDPOINT; $endpoint = untrailingslashit( $endpoint ); // Send data to server. $response = wp_remote_post( sprintf( '%s/api/v1/support/', $endpoint ), [ // We need long timeout here, in case the data being sent is large or the network connection is slow. 'timeout' => 30, // phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout 'body' => $data, 'compress' => true, ] ); if ( ! is_wp_error( $response ) ) { $response_body = wp_remote_retrieve_body( $response ); $response = json_decode( $response_body, true ); $json_last_error = json_last_error(); if ( JSON_ERROR_NONE !== $json_last_error ) { return new WP_Error( 'malformed_json_amp_insight_endpoint', json_last_error_msg() ); } } return $response; } /** * To get amp data to send it to compatibility server. * * @since 2.2 * * @return array */ public function get_data() { $amp_urls = $this->get_amp_urls(); $request_data = [ 'site_url' => static::get_home_url(), 'site_info' => $this->get_site_info(), 'plugins' => $this->get_plugin_info(), 'themes' => $this->get_theme_info(), 'errors' => array_values( $amp_urls['errors'] ), 'error_sources' => array_values( $amp_urls['error_sources'] ), 'urls' => array_values( $amp_urls['urls'] ), 'error_log' => $this->get_error_log(), ]; if ( ! empty( $this->args['is_synthetic'] ) ) { $request_data['site_info']['is_synthetic_data'] = true; } $this->data = $request_data; return $request_data; } /** * To get site info. * * @since 2.2 * * @return array Site information. */ public function get_site_info() { global $wpdb; $wp_type = 'single'; if ( is_multisite() && ( defined( 'SUBDOMAIN_INSTALL' ) && SUBDOMAIN_INSTALL ) ) { $wp_type = 'subdomain'; } elseif ( is_multisite() ) { $wp_type = 'subdir'; } $active_theme = wp_get_theme(); $active_theme = static::normalize_theme_info( $active_theme ); $amp_settings = AMP_Options_Manager::get_options(); $amp_settings = ( ! empty( $amp_settings ) && is_array( $amp_settings ) ) ? $amp_settings : []; $loopback_status = ''; if ( class_exists( 'WP_Site_Health' ) ) { $loopback_status = ( new WP_Site_Health() )->can_perform_loopback(); $loopback_status = ( ! empty( $loopback_status->status ) ) ? $loopback_status->status : ''; } if ( function_exists( 'wp_get_https_detection_errors' ) ) { $https_errors = wp_get_https_detection_errors(); $is_ssl = empty( $https_errors ); } elseif ( function_exists( 'wp_is_https_supported' ) ) { $is_ssl = wp_is_https_supported(); } else { $is_ssl = is_ssl(); } $site_info = [ 'site_url' => static::get_home_url(), 'site_title' => get_bloginfo( 'site_title' ), 'php_version' => phpversion(), 'mysql_version' => $wpdb->db_version(), 'wp_version' => get_bloginfo( 'version' ), 'wp_language' => get_bloginfo( 'language' ), 'wp_https_status' => $is_ssl, 'wp_multisite' => $wp_type, 'wp_active_theme' => $active_theme, 'object_cache_status' => wp_using_ext_object_cache(), 'libxml_version' => ( defined( 'LIBXML_VERSION' ) ) ? LIBXML_VERSION : '', 'is_defined_curl_multi' => ( function_exists( 'curl_multi_init' ) ), 'loopback_requests' => $loopback_status, 'amp_mode' => ( ! empty( $amp_settings['theme_support'] ) ) ? $amp_settings['theme_support'] : '', 'amp_version' => ( ! empty( $amp_settings['version'] ) ) ? $amp_settings['version'] : '', 'amp_plugin_configured' => ( ! empty( $amp_settings['plugin_configured'] ) ) ? true : false, 'amp_all_templates_supported' => ( ! empty( $amp_settings['all_templates_supported'] ) ) ? true : false, 'amp_supported_post_types' => ( ! empty( $amp_settings['supported_post_types'] ) && is_array( $amp_settings['supported_post_types'] ) ) ? $amp_settings['supported_post_types'] : [], 'amp_supported_templates' => ( ! empty( $amp_settings['supported_templates'] ) && is_array( $amp_settings['supported_templates'] ) ) ? $amp_settings['supported_templates'] : [], 'amp_mobile_redirect' => ( ! empty( $amp_settings['mobile_redirect'] ) ) ? true : false, 'amp_reader_theme' => ( ! empty( $amp_settings['reader_theme'] ) ) ? $amp_settings['reader_theme'] : '', ]; return $site_info; } /** * To get list of active plugin's information. * * @since 2.2 * * @return array List of plugin detail. */ public function get_plugin_info() { $active_plugins = get_option( 'active_plugins' ); if ( is_multisite() ) { $network_wide_activate_plugins = get_site_option( 'active_sitewide_plugins' ); $active_plugins = array_merge( $active_plugins, $network_wide_activate_plugins ); } $active_plugins = array_values( array_unique( $active_plugins ) ); $plugin_info = array_map( static function ( $active_plugin ) { return self::normalize_plugin_info( $active_plugin ); }, $active_plugins ); $plugin_info = array_filter( $plugin_info ); return array_values( $plugin_info ); } /** * To get active theme info. * * @since 2.2 * * @return array List of theme information. */ public function get_theme_info() { $themes = [ wp_get_theme(), ]; if ( wp_get_theme()->parent() ) { $themes[] = wp_get_theme()->parent(); } $themes = array_filter( $themes, static function ( WP_Theme $theme ) { return ! $theme->errors(); } ); $response = array_map( static function( WP_Theme $theme ) { return self::normalize_theme_info( $theme ); }, $themes ); return array_values( $response ); } /** * To get error log. * * @since 2.2 * * @return array Error log contents and log_errors ini setting. */ public function get_error_log() { $error_log_path = ini_get( 'error_log' ); // $error_log_path might be a relative path/filename. // In this case, we would have to iterate many directories to find them. if ( empty( $error_log_path ) || ! file_exists( $error_log_path ) ) { return [ 'log_errors' => ini_get( 'log_errors' ), 'contents' => '', ]; } $max_lines = 200; // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen $file = @fopen( $error_log_path, 'r' ); $lines = []; $current_line = ''; $position = 0; if ( is_resource( $file ) ) { while ( -1 !== fseek( $file, $position, SEEK_END ) ) { $char = fgetc( $file ); if ( PHP_EOL === $char ) { $lines[] = $current_line; $current_line = ''; if ( count( $lines ) > $max_lines ) { break; } } else { $current_line = $char . $current_line; } $position--; } $lines[] = $current_line; fclose( $file ); } $lines = array_filter( $lines ); $lines = array_reverse( $lines ); return [ 'log_errors' => ini_get( 'log_errors' ), 'contents' => implode( "\n", $lines ), ]; } /** * To get plugin information by plugin file. * * @since 2.2 * * @param string $plugin_file Plugin file. * * @return array Plugin detail. */ public static function normalize_plugin_info( $plugin_file ) { $absolute_plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file; if ( 0 !== validate_file( $absolute_plugin_file ) || ! file_exists( $absolute_plugin_file ) ) { return []; } require_once ABSPATH . '/wp-admin/includes/plugin.php'; /** @var array */ $plugin_data = get_plugin_data( $absolute_plugin_file ); $slug = explode( '/', $plugin_file ); $slug = $slug[0]; $amp_options = get_option( 'amp-options' ); $suppressed_plugins = ( ! empty( $amp_options['suppressed_plugins'] ) && is_array( $amp_options['suppressed_plugins'] ) ) ? $amp_options['suppressed_plugins'] : []; $suppressed_plugin_list = array_keys( $suppressed_plugins ); if ( empty( $plugin_data['Name'] ) ) { return []; } return [ 'name' => $plugin_data['Name'], 'slug' => $slug, 'plugin_url' => array_key_exists( 'PluginURI', $plugin_data ) ? $plugin_data['PluginURI'] : '', 'version' => array_key_exists( 'Version', $plugin_data ) ? $plugin_data['Version'] : '', 'author' => array_key_exists( 'AuthorName', $plugin_data ) ? $plugin_data['AuthorName'] : '', 'author_url' => array_key_exists( 'AuthorURI', $plugin_data ) ? $plugin_data['AuthorURI'] : '', 'requires_wp' => array_key_exists( 'RequiresWP', $plugin_data ) ? $plugin_data['RequiresWP'] : '', 'requires_php' => array_key_exists( 'RequiresPHP', $plugin_data ) ? $plugin_data['RequiresPHP'] : '', 'is_active' => is_plugin_active( $plugin_file ), 'is_network_active' => is_plugin_active_for_network( $plugin_file ), 'is_suppressed' => in_array( $slug, $suppressed_plugin_list, true ) ? $suppressed_plugins[ $slug ]['last_version'] : '', ]; } /** * To normalize theme information. * * @since 2.2 * * @param WP_Theme $theme_object Theme object. * * @return array Normalize theme information. */ public static function normalize_theme_info( WP_Theme $theme_object ) { $active_theme = wp_get_theme(); $tags = $theme_object->get( 'Tags' ); $tags = ( ! empty( $tags ) && is_array( $tags ) ) ? $tags : []; $theme_data = [ 'name' => $theme_object->get( 'Name' ), 'slug' => $theme_object->get_stylesheet(), 'version' => $theme_object->get( 'Version' ), 'status' => $theme_object->get( 'Status' ), 'tags' => $tags, 'text_domain' => $theme_object->get( 'TextDomain' ), 'requires_wp' => $theme_object->get( 'RequiresWP' ), 'requires_php' => $theme_object->get( 'RequiresPHP' ), 'theme_url' => $theme_object->get( 'ThemeURI' ), 'author' => $theme_object->get( 'Author' ), 'author_url' => $theme_object->get( 'AuthorURI' ), 'is_active' => ( $theme_object->get_stylesheet() === $active_theme->get_stylesheet() ), 'parent_theme' => $theme_object->parent() ? $theme_object->get_template() : null, ]; return $theme_data; } /** * Normalize error data. * * @since 2.2 * * @param array $error_data Error data array. * * @return array */ public static function normalize_error( $error_data ) { if ( empty( $error_data ) || ! is_array( $error_data ) ) { return []; } unset( $error_data['sources'] ); $error_data['text'] = ( ! empty( $error_data['text'] ) ) ? trim( $error_data['text'] ) : ''; $error_data = static::remove_domain( $error_data ); /** * Generate new slug after removing site specific data. */ $error_data['error_slug'] = static::generate_hash( $error_data ); return $error_data; } /** * To normalize the error source data. * * @since 2.2 * * @param array $source Error source detail. * * @return array Normalized error source data. */ public static function normalize_error_source( $source ) { if ( empty( $source ) || ! is_array( $source ) ) { return []; } static $plugin_versions = []; /** * All plugin info */ if ( empty( $plugin_versions ) || ! is_array( $plugin_versions ) ) { $plugin_list = get_plugins(); $plugin_list = array_keys( $plugin_list ); $plugin_list = array_values( array_unique( $plugin_list ) ); $plugin_list = array_map( static function ( $plugin ) { return self::normalize_plugin_info( $plugin ); }, $plugin_list ); foreach ( $plugin_list as $plugin ) { $plugin_versions[ $plugin['slug'] ] = $plugin['version']; } } /** * Normalize error source. */ $allowed_types = [ 'plugin', 'theme' ]; $source['type'] = ( ! empty( $source['type'] ) ) ? strtolower( trim( $source['type'] ) ) : ''; if ( ! empty( $source['sources'] ) && is_array( $source['sources'] ) ) { foreach ( $source['sources'] as $index => $inner_source ) { $source['sources'][ $index ] = self::normalize_error_source( $inner_source ); } $source['sources'] = array_values( array_filter( $source['sources'] ) ); } /** * Do not include wp-core sources. * But allow if source have sub sources. */ if ( ( empty( $source['type'] ) || ! in_array( $source['type'], $allowed_types, true ) ) && empty( $source['sources'] ) ) { return []; } if ( ! empty( $source['type'] ) ) { if ( 'plugin' === $source['type'] ) { $source['version'] = isset( $plugin_versions[ $source['name'] ] ) ? $plugin_versions[ $source['name'] ] : 'n/a'; } elseif ( 'theme' === $source['type'] ) { $theme = wp_get_theme( $source['name'] ); $source['version'] = ! $theme->errors() ? $theme->get( 'Version' ) : 'n/a'; } } if ( ! empty( $source['text'] ) ) { $source['text'] = trim( $source['text'] ); $source['text'] = static::remove_domain( $source['text'] ); } // Generate error source slug. $error_source_slug = self::generate_hash( $source ); // Update source information. Add error_slug and source_slug. $source['error_source_slug'] = $error_source_slug; ksort( $source ); return $source; } /** * To get amp validated URLs. * * @since 2.2 * * @return array [ * List amp validated URLs. * @type array $errors List of error for given instance of Validated post. * @type array $error_sources List of error sources for given instance of Validated post. * @type string[] $urls List of front-end URL. * ] */ public function get_amp_urls() { /** * List of invalid AMP URLs. * * @var string[] */ $amp_invalid_urls = []; /** * Error Information * * @var array */ $errors = []; /** * Error Source information. * * @var array */ $error_sources = []; if ( empty( $this->urls ) ) { /** * If argument provided and we don't have URL data. * then return empty values. */ if ( ! empty( $this->args['post_ids'] ) || ! empty( $this->args['term_ids'] ) || ! empty( $this->args['urls'] ) || ! empty( $this->args['amp_validated_post_ids'] ) ) { return [ 'errors' => [], 'error_sources' => [], 'urls' => [], ]; } // If no specific URL requested. $query_args = [ 'post_type' => AMP_Validated_URL_Post_Type::POST_TYPE_SLUG, 'posts_per_page' => 100, 'post_status' => 'publish', 'meta_key' => AMP_Validated_URL_Post_Type::VALIDATED_ENVIRONMENT_POST_META_KEY, 'meta_value' => maybe_serialize( AMP_Validated_URL_Post_Type::get_validated_environment() ), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 's' => 'term_slug', ]; $query = new WP_Query( $query_args ); $amp_validated_posts = $query->get_posts(); foreach ( $amp_validated_posts as $amp_validated_post ) { $validation_data = $this->process_raw_post_errors( $amp_validated_post ); if ( ! empty( $validation_data['errors'] ) && ! empty( $validation_data['error_sources'] ) && ! empty( $validation_data['url'] ) ) { $errors = array_merge( $errors, $validation_data['errors'] ); $error_sources = array_merge( $error_sources, $validation_data['error_sources'] ); $amp_invalid_urls[] = $validation_data['url']; } } } else { // If we have specific URL requested. foreach ( $this->urls as $url ) { // Check request URL have validated data if not then validate URL. $amp_validated_post = AMP_Validated_URL_Post_Type::get_invalid_url_post( $url ); if ( ! $amp_validated_post ) { $validity = AMP_Validation_Manager::validate_url_and_store( $url ); if ( is_wp_error( $validity ) || ! is_array( $validity ) ) { continue; } $amp_validated_post = get_post( $validity['post_id'] ); } // If validation data is exists for URL then check if it is stale or not. If it is stale, then revalidate. $is_stale = ! empty( AMP_Validated_URL_Post_Type::get_post_staleness( $amp_validated_post ) ); if ( $is_stale ) { AMP_Validation_Manager::validate_url_and_store( $url, $amp_validated_post ); } $validation_data = $this->process_raw_post_errors( $amp_validated_post ); if ( ! empty( $validation_data['errors'] ) && ! empty( $validation_data['error_sources'] ) && ! empty( $validation_data['url'] ) ) { $errors = array_merge( $errors, $validation_data['errors'] ); $error_sources = array_merge( $error_sources, $validation_data['error_sources'] ); $amp_invalid_urls[] = $validation_data['url']; } } } return [ 'errors' => $errors, 'error_sources' => $error_sources, 'urls' => $amp_invalid_urls, ]; } /** * Process AMP errors for single AMP validated post. * * @param WP_Post $amp_validated_post Instance of AMP Validated Post. * * @return array [ * @type array $errors List of error for given instance of Validated post. * @type array $error_sources List of error sources for given instance of Validated post. * @type string $url Front-end URL. * ] */ protected function process_raw_post_errors( WP_Post $amp_validated_post ) { if ( AMP_Validated_URL_Post_Type::POST_TYPE_SLUG !== $amp_validated_post->post_type ) { return []; } // Empty array for post staleness means post is NOT stale. if ( ! empty( AMP_Validated_URL_Post_Type::get_post_staleness( $amp_validated_post ) ) ) { return []; } /** * Error Information * * @var array */ $error_list = []; /** * Error Source information. * * @var array */ $error_source_list = []; $validation_errors_raw = json_decode( $amp_validated_post->post_content, true ); if ( ! is_array( $validation_errors_raw ) ) { $validation_errors_raw = []; } /** * Error loop. * * @var array */ $validation_errors = []; foreach ( $validation_errors_raw as $validation_error ) { $error_data = ( ! empty( $validation_error['data'] ) && is_array( $validation_error['data'] ) ) ? $validation_error['data'] : []; $error_sources = ( ! empty( $error_data['sources'] ) && is_array( $error_data['sources'] ) ) ? $error_data['sources'] : []; if ( empty( $error_data ) || empty( $error_sources ) ) { continue; } unset( $error_data['sources'] ); $error_data = static::normalize_error( $error_data ); /** * Store error data in all error list. */ if ( ! empty( $error_data ) && is_array( $error_data ) ) { $error_list[ $error_data['error_slug'] ] = $error_data; } /** * Source loop. */ foreach ( $error_sources as $index => $source ) { $source['error_slug'] = $error_data['error_slug']; $error_sources[ $index ] = static::normalize_error_source( $source ); /** * Store error source in all error_source list. */ if ( ! empty( $error_sources[ $index ] ) && is_array( $error_sources[ $index ] ) ) { $error_source_list[ $error_sources[ $index ]['error_source_slug'] ] = $error_sources[ $index ]; } } $error_sources = array_filter( $error_sources ); $error_source_slugs = wp_list_pluck( $error_sources, 'error_source_slug' ); $error_source_slugs = array_values( array_unique( $error_source_slugs ) ); if ( ! empty( $error_source_slugs ) ) { $validation_errors[] = [ 'error_slug' => $error_data['error_slug'], 'sources' => $error_source_slugs, ]; } } // Object information. $amp_queried_object = get_post_meta( $amp_validated_post->ID, '_amp_queried_object', true ); $object_type = ( ! empty( $amp_queried_object['type'] ) ) ? $amp_queried_object['type'] : ''; $object_subtype = ''; if ( empty( $object_type ) ) { $amp_validated_post_url = AMP_Validated_URL_Post_Type::get_url_from_post( $amp_validated_post ); if ( false !== strpos( $amp_validated_post_url, '?s=' ) ) { $object_type = 'search'; } } switch ( $object_type ) { case 'post': $post_object = get_post( $amp_queried_object['id'] ); $object_subtype = ( ! empty( $post_object ) && $post_object instanceof WP_Post ) ? $post_object->post_type : ''; break; case 'term': $term_object = get_term( $amp_queried_object['id'] ); $object_subtype = ( ! empty( $term_object ) && $term_object instanceof WP_Term ) ? $term_object->taxonomy : ''; break; case 'user': break; } // Stylesheet info. $stylesheet_info = static::get_stylesheet_info( $amp_validated_post->ID ); $css_budget_percentage = ( ! empty( $stylesheet_info['css_budget_percentage'] ) ) ? $stylesheet_info['css_budget_percentage'] : 0; $css_budget_percentage = intval( $css_budget_percentage ); if ( empty( $validation_errors ) && $css_budget_percentage < 100 ) { return []; } $amp_invalid_url = [ 'url' => AMP_Validated_URL_Post_Type::get_url_from_post( $amp_validated_post ), 'object_type' => $object_type, 'object_subtype' => $object_subtype, 'css_size_before' => ( ! empty( $stylesheet_info['css_size_before'] ) ) ? $stylesheet_info['css_size_before'] : '', 'css_size_after' => ( ! empty( $stylesheet_info['css_size_after'] ) ) ? $stylesheet_info['css_size_after'] : '', 'css_size_excluded' => ( ! empty( $stylesheet_info['css_size_excluded'] ) ) ? $stylesheet_info['css_size_excluded'] : '', 'css_budget_percentage' => $css_budget_percentage, 'errors' => $validation_errors, ]; return [ 'errors' => $error_list, 'error_sources' => $error_source_list, 'url' => $amp_invalid_url, ]; } /** * Get style sheet info of the post. * * @since 2.2 * * Reference: AMP_Validated_URL_Post_Type::print_stylesheets_meta_box() * * @param int $post_id Post ID. * * @return array AMP stylesheet used info. */ public static function get_stylesheet_info( $post_id ) { $stylesheets = get_post_meta( $post_id, AMP_Validated_URL_Post_Type::STYLESHEETS_POST_META_KEY, true ); if ( empty( $stylesheets ) ) { return []; } $stylesheets = json_decode( $stylesheets, true ); $style_custom_cdata_spec = null; foreach ( \AMP_Allowed_Tags_Generated::get_allowed_tag( 'style' ) as $spec_rule ) { if ( isset( $spec_rule[ \AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) && \AMP_Style_Sanitizer::STYLE_AMP_CUSTOM_SPEC_NAME === $spec_rule[ \AMP_Rule_Spec::TAG_SPEC ]['spec_name'] ) { $style_custom_cdata_spec = $spec_rule[ \AMP_Rule_Spec::CDATA ]; } } $included_final_size = 0; $included_original_size = 0; $excluded_final_size = 0; $excluded_original_size = 0; $excluded_stylesheets = 0; $max_final_size = 0; $included_status = 1; $excessive_status = 2; $excluded_status = 3; // Determine which stylesheets are included based on their priorities. $pending_stylesheet_indices = array_keys( $stylesheets ); usort( $pending_stylesheet_indices, static function ( $a, $b ) use ( $stylesheets ) { return $stylesheets[ $a ]['priority'] - $stylesheets[ $b ]['priority']; } ); foreach ( $pending_stylesheet_indices as $i ) { if ( ! isset( $stylesheets[ $i ]['group'] ) || 'amp-custom' !== $stylesheets[ $i ]['group'] || ! empty( $stylesheets[ $i ]['duplicate'] ) ) { continue; } $max_final_size = max( $max_final_size, $stylesheets[ $i ]['final_size'] ); if ( $stylesheets[ $i ]['included'] ) { $included_final_size += $stylesheets[ $i ]['final_size']; $included_original_size += $stylesheets[ $i ]['original_size']; if ( $included_final_size >= $style_custom_cdata_spec['max_bytes'] ) { $stylesheets[ $i ]['status'] = $excessive_status; } else { $stylesheets[ $i ]['status'] = $included_status; } } else { $excluded_final_size += $stylesheets[ $i ]['final_size']; $excluded_original_size += $stylesheets[ $i ]['original_size']; $excluded_stylesheets ++; $stylesheets[ $i ]['status'] = $excluded_status; } } $percentage_budget_used = ( ( $included_final_size + $excluded_final_size ) / $style_custom_cdata_spec['max_bytes'] ) * 100; $response = [ 'css_size_before' => intval( $included_original_size + $excluded_original_size ), 'css_size_after' => intval( $included_final_size + $excluded_final_size ), 'css_size_excluded' => intval( $excluded_stylesheets ), 'css_budget_percentage' => round( $percentage_budget_used, 1 ), ]; return $response; } /** * To get home url of the site. * Note: It will give home url without protocol. * * @since 2.2 * * @return string Home URL. */ public static function get_home_url() { $home_url = home_url(); $home_url = strtolower( trim( $home_url ) ); $http_protocol = wp_parse_url( $home_url, PHP_URL_SCHEME ); $home_url = str_replace( "$http_protocol://", '', $home_url ); $home_url = untrailingslashit( $home_url ); return $home_url; } /** * To remove home url from the content. * * @since 2.2 * * @param mixed $content Content from home_url need to remove. * * @return string|array Content after removing home_url. */ public static function remove_domain( $content ) { if ( empty( $content ) ) { return ''; } elseif ( is_numeric( $content ) ) { return $content; } $home_url = static::get_home_url(); $home_url = str_replace( [ '.', '/' ], [ '\.', '\\\\{1,5}\/' ], $home_url ); /** * Reference: https://regex101.com/r/c25pNF/1 */ $regex = "/http[s]?:\\\\{0,5}\/\\\\{0,5}\/$home_url/mU"; if ( is_string( $content ) ) { return preg_replace( $regex, '', $content ); } if ( is_object( $content ) ) { $content = (array) $content; } if ( is_array( $content ) ) { return array_map( static function ( $item ) { return self::remove_domain( $item ); }, $content ); } return $content; } /** * To generate hash of object. * * @since 2.2 * * @param string|array|object $object Object for that hash need to generate. * * @return string Hash value of provided object. */ public static function generate_hash( $object ) { if ( empty( $object ) ) { return ''; } if ( is_object( $object ) ) { $object = (array) $object; } if ( is_array( $object ) ) { ksort( $object ); $object = wp_json_encode( $object ); } $object = trim( $object ); $hash = hash( 'sha256', $object ); return $hash; } }