File: /home/hubdkrco/6wgame.pk/wp-content/plugins/colibri-page-builder/src/GoogleFontsLocalLoader.php
<?php
namespace ColibriWP\PageBuilder;
use function ExtendBuilder\array_get_value;
use function ExtendBuilder\array_set_value;
class GoogleFontsLocalLoader {
private static $instance = null;
private $queries_transient = 'colibri_local_google_queries_transient';
private $font_file_action = 'colibri_get_google_font_file';
private $fonts_css_action = 'colibri_get_google_font_css';
private $uploads_dir = 'colibri-google-fonts-cache';
private $google_css_url = 'https://fonts.googleapis.com/css';
private $google_font_url = 'https://fonts.gstatic.com/s';
private $user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0';
private $local_fonts_dir;
private $local_fonts_url;
/**
*
* @return GoogleFontsLocalLoader
*/
public static function getInstance() {
if ( ! static::$instance ) {
static::$instance = new static();
}
return static::$instance;
}
public function __construct() {
$upload_dir = wp_upload_dir();
$upload_path = untrailingslashit( $upload_dir['basedir'] );
$this->local_fonts_dir = "{$upload_path}/{$this->uploads_dir}";
$this->local_fonts_url = "{$upload_dir['baseurl']}/{$this->uploads_dir}";
if ( ! file_exists( $this->local_fonts_dir ) ) {
//phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
mkdir( $this->local_fonts_dir, 0777, true );
}
}
public function resolveFontsCSS() {
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
$action = array_get_value( $_REQUEST, 'action' );
if ( $action !== $this->fonts_css_action ) {
return;
}
header( 'Content-type: text/css' );
header( 'Cache-control: public' );
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
$key = sanitize_text_field(array_get_value( $_REQUEST, 'key', '' ));
$cached = $this->getCachedDataByKey( $key );
if ( ! $cached ) {
die( '' );
}
$query = array_get_value( $cached, 'query' );
$css = array_get_value( $cached, 'css' );
if ( ! $css ) {
$css = $this->getCSS( $query );
$this->cacheQueryCSS( $query, $css );
}
$css = $this->replacePlaceholdersWithLocalCSS( $css );
// if ( Utils::isDebug() ) {
// $css = "/* {$this->google_css_url}?family={$query} */\n\n{$css}";
// }
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
die( $css );
}
private function getCSS( $query, $replace_urls = true ) {
$fonts_url = add_query_arg(
array(
'family' => urlencode( $query ),
'display' => 'swap',
),
$this->google_css_url
);
$response = wp_remote_get(
$fonts_url,
array(
'user-agent' => $this->user_agent,
)
);
if ( is_wp_error( $response ) ) {
return null;
}
if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
return null;
}
$css = wp_remote_retrieve_body( $response );
if ( $replace_urls ) {
$css = $this->replaceGoogleURLS( $css );
}
return $css;
}
private function replaceGoogleURLS( $css ) {
$google_font_url = $this->google_font_url;
$css = preg_replace_callback(
'#url\((.*?)\)#',
function( $matches ) use ( $google_font_url ) {
$url = str_replace( $google_font_url, '', array_get_value( $matches, 1, '' ) );
return "url({{{{$url}}}})";
},
$css
);
return $css;
}
public function getLocalFontFilePath( $font_file ) {
$file_key = md5( $font_file );
return "{$this->local_fonts_dir}/{$file_key}.woff2";
}
public function getLocalFontFileURL( $font_file ) {
$file_key = md5( $font_file );
return "{$this->local_fonts_url}/{$file_key}.woff2";
}
public function saveFontContentToLocalFile( $font_file, $content ) {
$path = $this->getLocalFontFilePath( $font_file );
return file_put_contents( $path, $content );
}
public function localFontFileExists( $font_file ) {
return file_exists( $this->getLocalFontFilePath( $font_file ) );
}
private function replacePlaceholdersWithLocalCSS( $css ) {
$self = $this;
$action = $this->font_file_action;
$css = preg_replace_callback(
'#url\(\{\{\{(.*?)\}\}\}\)#',
function( $matches ) use ( $self, $action ) {
$font_file = array_get_value( $matches, 1, '' );
if ( $self->localFontFileExists( $font_file ) ) {
$url = $self->getLocalFontFileURL( $font_file );
} else {
$url = add_query_arg(
array(
'font' => urlencode( $font_file ),
'action' => $action,
'security' => $self->createSecurityKey( "{$action}_{$font_file}" ),
),
admin_url( 'admin-ajax.php' )
);
}
return "url({$url})";
},
$css
);
return $css;
}
public function getCachedDataByKey( $key ) {
$transient = get_transient( $this->queries_transient );
if ( ! is_array( $transient ) ) {
return null;
}
return array_get_value( $transient, $key );
}
public function getCachedQueryData( $query ) {
return $this->getCachedDataByKey( md5( $query ) );
}
public function cacheQueryCSS( $query, $css ) {
$transient = get_transient( $this->queries_transient );
if ( ! is_array( $transient ) ) {
$transient = array();
}
array_set_value(
$transient,
md5( $query ),
array(
'query' => $query,
'css' => $css,
)
);
set_transient( $this->queries_transient, $transient );
}
public function addQueryToCache( $query ) {
$transient = get_transient( $this->queries_transient );
if ( ! is_array( $transient ) ) {
$transient = array();
}
$key = md5( $query );
if ( isset( $transient[ $key ] ) ) {
return;
}
array_set_value(
$transient,
$key,
array(
'query' => $query,
)
);
set_transient( $this->queries_transient, $transient );
}
public function enqueueFonts( $query ) {
$cached = $this->getCachedQueryData( $query );
if ( ! $cached ) {
$this->addQueryToCache(
$query,
array(
'query' => $query,
)
);
}
wp_enqueue_style(
'colibri-local-google-fonts',
add_query_arg(
array(
'action' => $this->fonts_css_action,
'key' => md5( $query ),
),
site_url()
)
);
}
public function getFontsMap( $query, $subset = 'latin' ) {
$css = $this->getCSS( $query, false );
// prepare subset
$css = preg_replace( '#/\*\s+?(' . $subset . ")\s+?\*/(.*\n?)@font-face#", 'is_subset_match', $css );
// remove comments
$css = preg_replace( '#/\*(.*?)\*/#', '', $css );
$css = preg_replace( '#format\((.*?)\)#', '', $css );
$css = preg_replace( '#url\(https://(.*?)\)#', '$1', $css );
$re = '/is_subset_match.*{\K[^}]*(?=})/';
preg_match_all( $re, $css, $matches, PREG_SET_ORDER );
$parsed = array();
$keys = array( 'font-family', 'src', 'font-style', 'font-weight', 'unicode-range' );
if ( $matches ) {
foreach ( $matches as $k => $ff ) {
$css = $ff[0];
$attrs = explode( ';', $css );
$props = array();
foreach ( $attrs as $attr ) {
if ( strlen( trim( $attr ) ) > 0 ) {
$pair = explode( ':', trim( $attr ) );
if ( in_array( $pair[0], $keys ) ) {
$value = trim( $pair[1] );
if ( $pair[0] === 'font-family' ) {
$value = str_replace( "'", '', $value );
}
if ( $pair[0] === 'font-weight' ) {
$value = intval( $value );
}
if ( $pair[0] === 'src' ) {
$value = "https://{$value}";
}
$props[ trim( $pair[0] ) ] = $value;
}
}
}
$props['subset'] = $subset;
$parsed[ $k ] = $props;
}
}
return $parsed;
}
public function resolveFont() {
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
$font_file = sanitize_text_field( array_get_value( $_REQUEST, 'font', '' ) );
//phpcs:ignore WordPress.Security.NonceVerification.Recommended
$security_key = sanitize_text_field( array_get_value( $_REQUEST, 'security', '' ) );
$valid_nonce = $this->verifySecurityKey( $security_key, "{$this->font_file_action}_{$font_file}" );
if ( ! $valid_nonce ) {
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
wp_die( __( 'Frobidden', 'colibri-page-builder' ), 403 );
}
$content = $this->resolveFontFileContent( $font_file );
if ( is_wp_error( $content ) ) {
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
wp_die( $content, 404 );
}
//phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
$this_year = strtotime( date( 'Y' ) . '-01-01' );
header( 'Content-type: font/woff2' );
header( 'Cache-control: public' );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', $this_year ) . ' GMT' );
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', $this_year + YEAR_IN_SECONDS ) . ' GMT' );
header( 'Etag: ' . md5( base64_encode( $content ) ) );
//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
die( $content );
}
private function resolveFontFileContent( $font_file ) {
if ( $this->localFontFileExists( $font_file ) ) {
return file_get_contents( $this->getLocalFontFilePath( $font_file ) );
}
//phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable
if ( ! is_writable( $this->local_fonts_dir ) ) {
return new \WP_Error( 'folder_not_writable' );
}
$google_font_url = "{$this->google_font_url}/{$font_file}";
$reponse = wp_remote_get( $google_font_url );
if ( is_wp_error( $reponse ) ) {
return new \WP_Error( 'could_not_retrieve_url' );
}
$content = wp_remote_retrieve_body( $reponse );
$this->saveFontContentToLocalFile( $font_file, $content );
return $content;
}
private function getSecuritySalt() {
if ( defined( 'NONCE_KEY' ) ) {
return NONCE_KEY;
}
if ( defined( 'SECURE_AUTH_KEY' ) ) {
return SECURE_AUTH_KEY;
}
if ( defined( 'AUTH_KEY' ) ) {
return AUTH_KEY;
}
if ( defined( 'SECURE_AUTH_SALT' ) ) {
return SECURE_AUTH_SALT;
}
if ( defined( 'AUTH_SALT' ) ) {
return AUTH_SALT;
}
// $pro_activation_time = Flags::get( 'colibri_pro_activation_time' );
//
// if ( $pro_activation_time ) {
// return $pro_activation_time;
// }
//
// $activation_time = Flags::get( 'colibri_activation_time' );
//
// if ( $activation_time ) {
// return $activation_time;
// }
return uniqid( time() );
}
public function createSecurityKey( $action ) {
return wp_hash( $this->getSecuritySalt() . '|' . $action );
}
public function verifySecurityKey( $nonce, $action ) {
return $nonce === $this->createSecurityKey( $action );
}
public function addAdminAjaxActions() {
add_action( "wp_ajax_{$this->font_file_action}", array( $this, 'resolveFont' ) );
add_action( "wp_ajax_nopriv_{$this->font_file_action}", array( $this, 'resolveFont' ) );
add_action( 'plugins_loaded', array( $this, 'resolveFontsCSS' ) );
}
public static function enqueuLocalGoogleFonts( $fonts_query ) {
return GoogleFontsLocalLoader::getInstance()->enqueueFonts( $fonts_query );
}
public static function registerFontResolver() {
return GoogleFontsLocalLoader::getInstance()->addAdminAjaxActions();
}
}