443 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			443 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace W3TC;
 | |
| 
 | |
| /**
 | |
|  * class Cdn_Environment
 | |
|  */
 | |
| class Cdn_Environment {
 | |
| 	public function __construct() {
 | |
| 		add_filter( 'w3tc_browsercache_rules_section_extensions',
 | |
| 			array( $this, 'w3tc_browsercache_rules_section_extensions' ),
 | |
| 			10, 3 );
 | |
| 
 | |
| 		add_filter( 'w3tc_browsercache_rules_section',
 | |
| 			array( $this, 'w3tc_browsercache_rules_section' ),
 | |
| 			10, 3 );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Fixes environment in each wp-admin request
 | |
| 	 *
 | |
| 	 * @param Config  $config
 | |
| 	 * @param bool    $force_all_checks
 | |
| 	 * @throws Util_Environment_Exceptions
 | |
| 	 */
 | |
| 	public function fix_on_wpadmin_request( $config, $force_all_checks ) {
 | |
| 		$exs = new Util_Environment_Exceptions();
 | |
| 
 | |
| 		if ( $config->get_boolean( 'config.check' ) || $force_all_checks ) {
 | |
| 			if ( $config->get_boolean( 'cdn.enabled' ) ) {
 | |
| 				$this->rules_add( $config, $exs );
 | |
| 			} else {
 | |
| 				$this->rules_remove( $exs );
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if ( count( $exs->exceptions() ) > 0 )
 | |
| 			throw $exs;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Fixes environment once event occurs
 | |
| 	 *
 | |
| 	 * @param Config  $config
 | |
| 	 * @param string  $event
 | |
| 	 * @param Config|null $old_config
 | |
| 	 * @throws Util_Environment_Exceptions
 | |
| 	 */
 | |
| 	public function fix_on_event( $config, $event, $old_config = null ) {
 | |
| 		if ( $config->get_boolean( 'cdn.enabled' ) &&
 | |
| 			!Cdn_Util::is_engine_mirror( $config->get_string( 'cdn.engine' ) ) ) {
 | |
| 			if ( $old_config != null &&
 | |
| 				$config->get_integer( 'cdn.queue.interval' ) !=
 | |
| 				$old_config->get_integer( 'cdn.queue.interval' ) ) {
 | |
| 				$this->unschedule_queue_process();
 | |
| 			}
 | |
| 
 | |
| 			if ( !wp_next_scheduled( 'w3_cdn_cron_queue_process' ) ) {
 | |
| 				wp_schedule_event( time(),
 | |
| 					'w3_cdn_cron_queue_process', 'w3_cdn_cron_queue_process' );
 | |
| 			}
 | |
| 		} else {
 | |
| 			$this->unschedule_queue_process();
 | |
| 		}
 | |
| 
 | |
| 		if ( $config->get_boolean( 'cdn.enabled' ) &&
 | |
| 			$config->get_boolean( 'cdn.autoupload.enabled' ) &&
 | |
| 			!Cdn_Util::is_engine_mirror( $config->get_string( 'cdn.engine' ) ) ) {
 | |
| 			if ( $old_config != null &&
 | |
| 				$config->get_integer( 'cdn.autoupload.interval' ) !=
 | |
| 				$old_config->get_integer( 'cdn.autoupload.interval' ) ) {
 | |
| 				$this->unschedule_upload();
 | |
| 			}
 | |
| 
 | |
| 			if ( !wp_next_scheduled( 'w3_cdn_cron_upload' ) ) {
 | |
| 				wp_schedule_event( time(),
 | |
| 					'w3_cdn_cron_upload', 'w3_cdn_cron_upload' );
 | |
| 			}
 | |
| 		} else {
 | |
| 			$this->unschedule_upload();
 | |
| 		}
 | |
| 
 | |
| 		$exs = new Util_Environment_Exceptions();
 | |
| 
 | |
| 		if ( $config->get_boolean( 'cdn.enabled' ) ) {
 | |
| 			try {
 | |
| 				$this->handle_tables(
 | |
| 					$event == 'activate' /* drop state on activation */,
 | |
| 					true );
 | |
| 			} catch ( \Exception $ex ) {
 | |
| 				$exs->push( $ex );
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if ( count( $exs->exceptions() ) > 0 )
 | |
| 			throw $exs;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Fixes environment after plugin deactivation
 | |
| 	 */
 | |
| 	public function fix_after_deactivation() {
 | |
| 		$exs = new Util_Environment_Exceptions();
 | |
| 
 | |
| 		$this->rules_remove( $exs );
 | |
| 		$this->handle_tables( true, false );
 | |
| 
 | |
| 		if ( count( $exs->exceptions() ) > 0 )
 | |
| 			throw $exs;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns required rules for module
 | |
| 	 *
 | |
| 	 * @param Config  $config
 | |
| 	 * @return array|null
 | |
| 	 */
 | |
| 	function get_required_rules( $config ) {
 | |
| 		if ( !$config->get_boolean( 'cdn.enabled' ) )
 | |
| 			return null;
 | |
| 
 | |
| 		$rewrite_rules = array();
 | |
| 		$rules = $this->rules_generate( $config );
 | |
| 
 | |
| 		if ( strlen( $rules ) > 0 ) {
 | |
| 			if ( $config->get_string( 'cdn.engine' ) == 'ftp' ) {
 | |
| 				$common = Dispatcher::component( 'Cdn_Core' );
 | |
| 				$domain = $common->get_cdn()->get_domain();
 | |
| 				$cdn_rules_path = sprintf( 'ftp://%s/%s', $domain,
 | |
| 					Util_Rule::get_cdn_rules_path() );
 | |
| 				$rewrite_rules[] = array(
 | |
| 					'filename' => $cdn_rules_path,
 | |
| 					'content' => $rules
 | |
| 				);
 | |
| 			}
 | |
| 
 | |
| 			$path = Util_Rule::get_browsercache_rules_cache_path();
 | |
| 			$rewrite_rules[] = array(
 | |
| 				'filename' => $path,
 | |
| 				'content' => $rules
 | |
| 			);
 | |
| 		}
 | |
| 		return $rewrite_rules;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 *
 | |
| 	 *
 | |
| 	 * @param Config  $config
 | |
| 	 * @return array|null
 | |
| 	 */
 | |
| 	function get_instructions( $config ) {
 | |
| 		if ( !$config->get_boolean( 'cdn.enabled' ) )
 | |
| 			return null;
 | |
| 
 | |
| 		$instructions = array();
 | |
| 		$instructions[] = array( 'title'=>__( 'CDN module: Required Database SQL', 'w3-total-cache' ),
 | |
| 			'content' => $this->generate_table_sql(), 'area' => 'database' );
 | |
| 
 | |
| 		return $instructions;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generate rules for FTP
 | |
| 	 */
 | |
| 	public function rules_generate_for_ftp( $config ) {
 | |
| 		return $this->rules_generate( $config, true );
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	/**
 | |
| 	 * Create tables
 | |
| 	 *
 | |
| 	 * @param bool    $drop
 | |
| 	 * @throws Util_Environment_Exception
 | |
| 	 */
 | |
| 	private function handle_tables( $drop, $create ) {
 | |
| 		global $wpdb;
 | |
| 
 | |
| 		$tablename_queue = $wpdb->base_prefix . W3TC_CDN_TABLE_QUEUE;
 | |
| 		$tablename_map = $wpdb->base_prefix . W3TC_CDN_TABLE_PATHMAP;
 | |
| 
 | |
| 		if ( $drop ) {
 | |
| 			$sql = "DROP TABLE IF EXISTS `$tablename_queue`;";
 | |
| 			$wpdb->query( $sql );
 | |
| 			$sql = "DROP TABLE IF EXISTS `$tablename_map`;";
 | |
| 			$wpdb->query( $sql );
 | |
| 		}
 | |
| 
 | |
| 		if ( !$create ) {
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		$charset_collate = '';
 | |
| 		if ( ! empty( $wpdb->charset ) )
 | |
| 			$charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
 | |
| 		if ( ! empty( $wpdb->collate ) )
 | |
| 			$charset_collate .= " COLLATE $wpdb->collate";
 | |
| 
 | |
| 		$sql = "CREATE TABLE IF NOT EXISTS `$tablename_queue` (
 | |
| 			`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 | |
| 			`local_path` varchar(500) NOT NULL DEFAULT '',
 | |
| 			`remote_path` varchar(500) NOT NULL DEFAULT '',
 | |
| 			`command` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '1 - Upload, 2 - Delete, 3 - Purge',
 | |
| 			`last_error` varchar(150) NOT NULL DEFAULT '',
 | |
| 			`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 | |
| 			PRIMARY KEY (`id`),
 | |
| 			KEY `date` (`date`)
 | |
| 		) $charset_collate;";
 | |
| 
 | |
| 		$wpdb->query( $sql );
 | |
| 		if ( !$wpdb->result )
 | |
| 			throw new Util_Environment_Exception( 'Can\'t create table ' .
 | |
| 				$tablename_queue );
 | |
| 
 | |
| 		$sql = "
 | |
| 			CREATE TABLE IF NOT EXISTS `$tablename_map` (
 | |
| 				-- Relative file path.
 | |
| 				-- For reference, not actually used for finding files.
 | |
| 				path TEXT NOT NULL,
 | |
| 				-- MD5 hash of remote path, used for finding files.
 | |
| 				path_hash VARCHAR(32) CHARACTER SET ascii NOT NULL,
 | |
| 				type tinyint(1) NOT NULL DEFAULT '0',
 | |
| 				-- Google Drive: document identifier
 | |
| 				remote_id VARCHAR(200) CHARACTER SET ascii,
 | |
| 				PRIMARY KEY (path_hash),
 | |
| 				KEY `remote_id` (`remote_id`)
 | |
| 			) $charset_collate";
 | |
| 
 | |
| 		$wpdb->query( $sql );
 | |
| 		if ( !$wpdb->result )
 | |
| 			throw new Util_Environment_Exception( 'Can\'t create table ' .
 | |
| 				$tablename_map );
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	private function generate_table_sql() {
 | |
| 		global $wpdb;
 | |
| 		$charset_collate = '';
 | |
| 
 | |
| 		if ( ! empty( $wpdb->charset ) )
 | |
| 			$charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
 | |
| 		if ( ! empty( $wpdb->collate ) )
 | |
| 			$charset_collate .= " COLLATE $wpdb->collate";
 | |
| 
 | |
| 		$sql = sprintf( 'DROP TABLE IF EXISTS `%s%s`;', $wpdb->base_prefix, W3TC_CDN_TABLE_QUEUE );
 | |
| 		$sql .= "\n" . sprintf( "CREATE TABLE IF NOT EXISTS `%s%s` (
 | |
| 			`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
 | |
| 			`local_path` varchar(500) NOT NULL DEFAULT '',
 | |
| 			`remote_path` varchar(500) NOT NULL DEFAULT '',
 | |
| 			`command` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '1 - Upload, 2 - Delete, 3 - Purge',
 | |
| 			`last_error` varchar(150) NOT NULL DEFAULT '',
 | |
| 			`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 | |
| 			PRIMARY KEY (`id`),
 | |
| 			KEY `date` (`date`)
 | |
| 		) $charset_collate;", $wpdb->base_prefix, W3TC_CDN_TABLE_QUEUE );
 | |
| 
 | |
| 		return $sql;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * schedules
 | |
| 	 */
 | |
| 
 | |
| 	/**
 | |
| 	 * Unschedules cron events
 | |
| 	 */
 | |
| 	private function unschedule_queue_process() {
 | |
| 		if ( wp_next_scheduled( 'w3_cdn_cron_queue_process' ) ) {
 | |
| 			wp_clear_scheduled_hook( 'w3_cdn_cron_queue_process' );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Unschedule upload event
 | |
| 	 */
 | |
| 	private function unschedule_upload() {
 | |
| 		if ( wp_next_scheduled( 'w3_cdn_cron_upload' ) ) {
 | |
| 			wp_clear_scheduled_hook( 'w3_cdn_cron_upload' );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	/*
 | |
| 	 * rules core modification
 | |
| 	 */
 | |
| 
 | |
| 	/**
 | |
| 	 * Writes directives to WP .htaccess
 | |
| 	 *
 | |
| 	 * @param Config  $config
 | |
| 	 * @param Util_Environment_Exceptions $exs
 | |
| 	 * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
 | |
| 	 */
 | |
| 	private function rules_add( $config, $exs ) {
 | |
| 		Util_Rule::add_rules( $exs, Util_Rule::get_browsercache_rules_cache_path(),
 | |
| 			$this->rules_generate( $config ),
 | |
| 			W3TC_MARKER_BEGIN_CDN,
 | |
| 			W3TC_MARKER_END_CDN,
 | |
| 			array(
 | |
| 				W3TC_MARKER_BEGIN_MINIFY_CORE => 0,
 | |
| 				W3TC_MARKER_BEGIN_PGCACHE_CORE => 0,
 | |
| 				W3TC_MARKER_BEGIN_BROWSERCACHE_CACHE => 0,
 | |
| 				W3TC_MARKER_BEGIN_WORDPRESS => 0,
 | |
| 				W3TC_MARKER_END_PGCACHE_CACHE => strlen( W3TC_MARKER_END_PGCACHE_CACHE ) + 1,
 | |
| 				W3TC_MARKER_END_MINIFY_CACHE => strlen( W3TC_MARKER_END_MINIFY_CACHE ) + 1
 | |
| 			)
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Removes Page Cache core directives
 | |
| 	 *
 | |
| 	 * @param Util_Environment_Exceptions $exs
 | |
| 	 * @throws Util_WpFile_FilesystemOperationException with S/FTP form if it can't get the required filesystem credentials
 | |
| 	 */
 | |
| 	private function rules_remove( $exs ) {
 | |
| 		Util_Rule::remove_rules( $exs,
 | |
| 			Util_Rule::get_browsercache_rules_cache_path(),
 | |
| 			W3TC_MARKER_BEGIN_CDN,
 | |
| 			W3TC_MARKER_END_CDN );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Generates rules for WP dir
 | |
| 	 *
 | |
| 	 * @param Config  $config
 | |
| 	 * @param bool    $cdnftp
 | |
| 	 * @return string
 | |
| 	 */
 | |
| 	private function rules_generate( $config, $cdnftp = false ) {
 | |
| 		if ( Util_Environment::is_nginx() ) {
 | |
| 			$o = new Cdn_Environment_Nginx( $config );
 | |
| 			return $o->generate( $cdnftp );
 | |
| 		} elseif ( Util_Environment::is_litespeed() ) {
 | |
| 			$o = new Cdn_Environment_LiteSpeed( $config );
 | |
| 			return $o->generate( $cdnftp );
 | |
| 		} else {
 | |
| 			return $this->rules_generate_apache( $config, $cdnftp );
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private function rules_generate_apache( $config, $cdnftp ) {
 | |
| 		$rules = '';
 | |
| 		if ( $config->get_boolean( 'cdn.canonical_header' ) ) {
 | |
| 			$rules .= $this->canonical( $cdnftp,
 | |
| 				$config->get_boolean( 'cdn.cors_header') );
 | |
| 		}
 | |
| 
 | |
| 		if ( $config->get_boolean( 'cdn.cors_header') ) {
 | |
| 			$rules .= $this->allow_origin( $cdnftp );
 | |
| 		}
 | |
| 
 | |
| 		if ( strlen( $rules ) > 0 ) {
 | |
| 			$rules =
 | |
| 				W3TC_MARKER_BEGIN_CDN . "\n" .
 | |
| 				$rules .
 | |
| 				W3TC_MARKER_END_CDN . "\n";
 | |
| 		}
 | |
| 
 | |
| 		return $rules;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	private function canonical( $cdnftp = false, $cors_header = true ) {
 | |
| 		$rules = '';
 | |
| 
 | |
| 		$mime_types = include W3TC_INC_DIR . '/mime/other.php';
 | |
| 		$extensions = array_keys( $mime_types );
 | |
| 
 | |
| 		$extensions_lowercase = array_map( 'strtolower', $extensions );
 | |
| 		$extensions_uppercase = array_map( 'strtoupper', $extensions );
 | |
| 		$rules .= "<FilesMatch \"\\.(" . implode( '|',
 | |
| 			array_merge( $extensions_lowercase, $extensions_uppercase ) ) . ")$\">\n";
 | |
| 
 | |
| 		$host = ( $cdnftp ? Util_Environment::home_url_host() : '%{HTTP_HOST}' );
 | |
| 		$rules .= "   <IfModule mod_rewrite.c>\n";
 | |
| 		$rules .= "      RewriteEngine On\n";
 | |
| 		$rules .= "      RewriteCond %{HTTPS} !=on\n";
 | |
| 		$rules .= "      RewriteRule .* - [E=CANONICAL:http://$host%{REQUEST_URI},NE]\n";
 | |
| 		$rules .= "      RewriteCond %{HTTPS} =on\n";
 | |
| 		$rules .= "      RewriteRule .* - [E=CANONICAL:https://$host%{REQUEST_URI},NE]\n";
 | |
| 		$rules .= "   </IfModule>\n";
 | |
| 		$rules .= "   <IfModule mod_headers.c>\n";
 | |
| 		$rules .= '      Header set Link "<%{CANONICAL}e>; rel=\"canonical\""' . "\n";
 | |
| 		$rules .= "   </IfModule>\n";
 | |
| 
 | |
| 		$rules .= "</FilesMatch>\n";
 | |
| 
 | |
| 		return $rules;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	/**
 | |
| 	 * Returns allow-origin rules
 | |
| 	 */
 | |
| 	private function allow_origin( $cdnftp = false ) {
 | |
| 		$r  = "<IfModule mod_headers.c>\n";
 | |
| 		$r .= "    Header set Access-Control-Allow-Origin \"*\"\n";
 | |
| 		$r .= "</IfModule>\n";
 | |
| 
 | |
| 		if ( !$cdnftp )
 | |
| 			return $r;
 | |
| 		else
 | |
| 			return
 | |
| 			"<FilesMatch \"\.(ttf|ttc|otf|eot|woff|woff2|font.css)$\">\n" .
 | |
| 				$r .
 | |
| 				"</FilesMatch>\n";
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public function w3tc_browsercache_rules_section_extensions(
 | |
| 			$extensions, $config, $section ) {
 | |
| 		if ( Util_Environment::is_nginx() ) {
 | |
| 			$o = new Cdn_Environment_Nginx( $config );
 | |
| 			$extensions = $o->w3tc_browsercache_rules_section_extensions(
 | |
| 				$extensions, $section );
 | |
| 		} elseif ( Util_Environment::is_litespeed() ) {
 | |
| 			$o = new Cdn_Environment_LiteSpeed( $config );
 | |
| 			$extensions = $o->w3tc_browsercache_rules_section_extensions(
 | |
| 				$extensions, $section );
 | |
| 		}
 | |
| 
 | |
| 		return $extensions;
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 
 | |
| 	public function w3tc_browsercache_rules_section( $section_rules, $config, $section ) {
 | |
| 		if ( Util_Environment::is_litespeed() ) {
 | |
| 			$o = new Cdn_Environment_LiteSpeed( $config );
 | |
| 			$section_rules = $o->w3tc_browsercache_rules_section(
 | |
| 				$section_rules, $section );
 | |
| 		}
 | |
| 		return $section_rules;
 | |
| 	}
 | |
| }
 |