/** * URL file filter * * @param string $file * @return bool */ public function is_file_for_minification($file) { static $external; if (!isset($external)) { $external = $this->config->get_array('minify.cache.files'); } foreach ($external as $ext) { if (preg_match('#' . Util_Environment::get_url_regexp($ext) . '#', $file)) { if ($this->debug) { Minify_Core::log('is_file_for_minification: whilelisted ' . $file); } return true; } } $file_normalized = Util_Environment::remove_query_all($file); $ext = strrchr($file_normalized, '.'); if ($ext != '.js' && $ext != '.css') { if ($this->debug) { Minify_Core::log('is_file_for_minification: unknown extension ' . $ext . ' for ' . $file); } return false; } if (Util_Environment::is_url($file_normalized)) { if ($this->debug) { Minify_Core::log('is_file_for_minification: its url ' . $file); } return false; } $path = Util_Environment::document_root() . '/' . $file; if (!file_exists($path)) { if ($this->debug) { Minify_Core::log('is_file_for_minification: file doesnt exists ' . $path); } return false; } if ($this->debug) { Minify_Core::log('is_file_for_minification: true for file ' . $file . ' path ' . $path); } return true; }
/** * Generates directives for file cache dir * * @param Config $config * @return string */ private function rules_cache_generate_nginx($config) { $cache_root = Util_Environment::normalize_path(W3TC_CACHE_PAGE_ENHANCED_DIR); $cache_dir = rtrim(str_replace(Util_Environment::document_root(), '', $cache_root), '/'); if (Util_Environment::is_wpmu()) { $cache_dir = preg_replace('~/w3tc.*?/~', '/w3tc.*?/', $cache_dir, 1); } $browsercache = $config->get_boolean('browsercache.enabled'); $compression = $browsercache && $config->get_boolean('browsercache.html.compression'); $expires = $browsercache && $config->get_boolean('browsercache.html.expires'); $lifetime = $browsercache ? $config->get_integer('browsercache.html.lifetime') : 0; $cache_control = $browsercache && $config->get_boolean('browsercache.html.cache.control'); $w3tc = $browsercache && $config->get_integer('browsercache.html.w3tc'); $common_rules = ''; if ($expires) { $common_rules .= " expires modified " . $lifetime . "s;\n"; } if ($w3tc) { $common_rules .= " add_header X-Powered-By \"" . Util_Environment::w3tc_header($config) . "\";\n"; } if ($expires) { $common_rules .= " add_header Vary \"Accept-Encoding, Cookie\";\n"; } if ($cache_control) { $cache_policy = $config->get_string('browsercache.html.cache.policy'); switch ($cache_policy) { case 'cache': $common_rules .= " add_header Pragma \"public\";\n"; $common_rules .= " add_header Cache-Control \"public\";\n"; break; case 'cache_public_maxage': $common_rules .= " add_header Pragma \"public\";\n"; $common_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public\";\n"; break; case 'cache_validation': $common_rules .= " add_header Pragma \"public\";\n"; $common_rules .= " add_header Cache-Control \"public, must-revalidate, proxy-revalidate\";\n"; break; case 'cache_noproxy': $common_rules .= " add_header Pragma \"public\";\n"; $common_rules .= " add_header Cache-Control \"private, must-revalidate\";\n"; break; case 'cache_maxage': $common_rules .= " add_header Pragma \"public\";\n"; $common_rules .= " add_header Cache-Control \"max-age=" . $lifetime . ", public, must-revalidate, proxy-revalidate\";\n"; break; case 'no_cache': $common_rules .= " add_header Pragma \"no-cache\";\n"; $common_rules .= " add_header Cache-Control \"max-age=0, private, no-store, no-cache, must-revalidate\";\n"; break; } } $rules = ''; $rules .= W3TC_MARKER_BEGIN_PGCACHE_CACHE . "\n"; $rules .= "location ~ " . $cache_dir . ".*html\$ {\n"; $rules .= $common_rules; $rules .= "}\n"; if ($compression) { $rules .= "location ~ " . $cache_dir . ".*gzip\$ {\n"; $rules .= " gzip off;\n"; $rules .= " types {}\n"; $rules .= " default_type text/html;\n"; $rules .= $common_rules; $rules .= " add_header Content-Encoding gzip;\n"; $rules .= "}\n"; } $rules .= W3TC_MARKER_END_PGCACHE_CACHE . "\n"; return $rules; }
/** * Returns custom files * * @param string $hash * @param string $type * @return array */ function minify_filename_to_filenames_for_minification($hash, $type) { // if bad data passed as get parameter - it shouldn't fire internal errors try { $files = Minify_Core::minify_filename_to_urls_for_minification($hash, $type); } catch (Exception $e) { $files = array(); } $result = array(); if (is_array($files) && count($files) > 0) { foreach ($files as $file) { $file = Util_Environment::url_to_docroot_filename($file); if (Util_Environment::is_url($file)) { $precached_file = $this->_precache_file($file, $type); if ($precached_file) { $result[] = $precached_file; } else { Minify_Core::debug_error(sprintf('Unable to cache remote file: "%s"', $file)); } } else { $path = Util_Environment::document_root() . '/' . $file; if (file_exists($path)) { $result[] = $file; } else { Minify_Core::debug_error(sprintf('File "%s" doesn\'t exist', $path)); } } } } else { Minify_Core::debug_error(sprintf('Unable to fetch custom files list: "%s.%s"', $hash, $type), false, 404); } return $result; }
/** * CDN Test action * * @return void */ function w3tc_cdn_test() { $engine = Util_Request::get_string('engine'); $config = Util_Request::get_array('config'); //TODO: Workaround to support test case cdn/a04 if ($engine == 'ftp' && !isset($config['host'])) { $config = Util_Request::get_string('config'); $config = json_decode($config, true); } $config = array_merge($config, array('debug' => false)); if (isset($config['domain']) && !is_array($config['domain'])) { $config['domain'] = explode(',', $config['domain']); } if (Cdn_Util::is_engine($engine)) { $result = true; $error = null; } else { $result = false; $error = __('Incorrect engine ' . $engine, 'w3-total-cache'); } if (!isset($config['docroot'])) { $config['docroot'] = Util_Environment::document_root(); } if ($result) { if ($engine == 'google_drive' || $engine == 'highwinds' || $engine == 'rackspace_cdn' || $engine == 'rscf' || $engine == 's3_compatible') { // those use already stored w3tc config $w3_cdn = Dispatcher::component('Cdn_Core')->get_cdn(); } else { // those use dynamic config from the page $w3_cdn = CdnEngine::instance($engine, $config); } @set_time_limit($this->_config->get_integer('timelimit.cdn_test')); if ($w3_cdn->test($error)) { $result = true; $error = __('Test passed', 'w3-total-cache'); } else { $result = false; $error = sprintf(__('Error: %s', 'w3-total-cache'), $error); } } $response = array('result' => $result, 'error' => $error); echo json_encode($response); }
/** * Imports library * * @param integer $limit * @param integer $offset * @param integer $count * @param integer $total * @param array $results * @return boolean */ function import_library($limit, $offset, &$count, &$total, &$results) { global $wpdb; $count = 0; $total = 0; $results = array(); $upload_info = Util_Http::upload_info(); $uploads_use_yearmonth_folders = get_option('uploads_use_yearmonth_folders'); $document_root = Util_Environment::document_root(); @set_time_limit($this->_config->get_integer('timelimit.cdn_import')); if ($upload_info) { /** * Search for posts with links or images */ $sql = sprintf('SELECT ID, post_content, post_date FROM %sposts WHERE post_status = "publish" AND (post_type = "post" OR post_type = "page") AND (post_content LIKE "%%src=%%" OR post_content LIKE "%%href=%%") ', $wpdb->prefix); if ($limit) { $sql .= sprintf(' LIMIT %d', $limit); if ($offset) { $sql .= sprintf(' OFFSET %d', $offset); } } $posts = $wpdb->get_results($sql); if ($posts) { $count = count($posts); $total = $this->get_import_posts_count(); $regexp = '~(' . $this->get_regexp_by_mask($this->_config->get_string('cdn.import.files')) . ')$~'; $config_state = Dispatcher::config_state(); $import_external = $config_state->get_boolean('cdn.import.external'); foreach ($posts as $post) { $matches = null; $replaced = array(); $attachments = array(); $post_content = $post->post_content; /** * Search for all link and image sources */ if (preg_match_all('~(href|src)=[\'"]?([^\'"<>\\s]+)[\'"]?~', $post_content, $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { list($search, $attribute, $origin) = $match; /** * Check if $search is already replaced */ if (isset($replaced[$search])) { continue; } $error = ''; $result = false; $src = Util_Environment::normalize_file_minify($origin); $dst = ''; /** * Check if file exists in the library */ if (stristr($origin, $upload_info['baseurl']) === false) { /** * Check file extension */ $check_src = $src; if (Util_Environment::is_url($check_src)) { $qpos = strpos($check_src, '?'); if ($qpos !== false) { $check_src = substr($check_src, 0, $qpos); } } if (preg_match($regexp, $check_src)) { /** * Check for already uploaded attachment */ if (isset($attachments[$src])) { list($dst, $dst_url) = $attachments[$src]; $result = true; } else { if ($uploads_use_yearmonth_folders) { $upload_subdir = date('Y/m', strtotime($post->post_date)); $upload_dir = sprintf('%s/%s', $upload_info['basedir'], $upload_subdir); $upload_url = sprintf('%s/%s', $upload_info['baseurl'], $upload_subdir); } else { $upload_subdir = ''; $upload_dir = $upload_info['basedir']; $upload_url = $upload_info['baseurl']; } $src_filename = pathinfo($src, PATHINFO_FILENAME); $src_extension = pathinfo($src, PATHINFO_EXTENSION); /** * Get available filename */ for ($i = 0;; $i++) { $dst = sprintf('%s/%s%s%s', $upload_dir, $src_filename, $i ? $i : '', $src_extension ? '.' . $src_extension : ''); if (!file_exists($dst)) { break; } } $dst_basename = basename($dst); $dst_url = sprintf('%s/%s', $upload_url, $dst_basename); $dst_path = ltrim(str_replace($document_root, '', Util_Environment::normalize_path($dst)), '/'); if ($upload_subdir) { Util_File::mkdir($upload_subdir, 0777, $upload_info['basedir']); } $download_result = false; /** * Check if file is remote URL */ if (Util_Environment::is_url($src)) { /** * Download file */ if ($import_external) { $download_result = Util_Http::download($src, $dst); if (!$download_result) { $error = 'Unable to download file'; } } else { $error = 'External file import is disabled'; } } else { /** * Otherwise copy file from local path */ $src_path = $document_root . '/' . urldecode($src); if (file_exists($src_path)) { $download_result = @copy($src_path, $dst); if (!$download_result) { $error = 'Unable to copy file'; } } else { $error = 'Source file doesn\'t exists'; } } /** * Check if download or copy was successful */ if ($download_result) { $title = $dst_basename; $guid = ltrim($upload_info['baseurlpath'] . $title, ','); $mime_type = Util_Mime::get_mime_type($dst); $GLOBALS['wp_rewrite'] = new WP_Rewrite(); /** * Insert attachment */ $id = wp_insert_attachment(array('post_mime_type' => $mime_type, 'guid' => $guid, 'post_title' => $title, 'post_content' => '', 'post_parent' => $post->ID), $dst); if (!is_wp_error($id)) { /** * Generate attachment metadata and upload to CDN */ require_once ABSPATH . 'wp-admin/includes/image.php'; wp_update_attachment_metadata($id, wp_generate_attachment_metadata($id, $dst)); $attachments[$src] = array($dst, $dst_url); $result = true; } else { $error = 'Unable to insert attachment'; } } } /** * If attachment was successfully created then replace links */ if ($result) { $replace = sprintf('%s="%s"', $attribute, $dst_url); // replace $search with $replace $post_content = str_replace($search, $replace, $post_content); $replaced[$search] = $replace; $error = 'OK'; } } else { $error = 'File type rejected'; } } else { $error = 'File already exists in the media library'; } /** * Add new entry to the log file */ $results[] = array('src' => $src, 'dst' => $dst_path, 'result' => $result, 'error' => $error); } } /** * If post content was chenged then update DB */ if ($post_content != $post->post_content) { wp_update_post(array('ID' => $post->ID, 'post_content' => $post_content)); } } } } }
/** * Taks an absolute path and converts to a relative path to root * * @param unknown $path * @return mixed */ function abspath_to_relative_path($path) { return str_replace(Util_Environment::document_root(), '', $path); }
/** * Returns server info * * @return array */ private function get_server_info() { global $wp_version, $wp_db_version, $wpdb; $wordpress_plugins = get_plugins(); $wordpress_plugins_active = array(); foreach ($wordpress_plugins as $wordpress_plugin_file => $wordpress_plugin) { if (is_plugin_active($wordpress_plugin_file)) { $wordpress_plugins_active[$wordpress_plugin_file] = $wordpress_plugin; } } $mysql_version = $wpdb->get_var('SELECT VERSION()'); $mysql_variables_result = (array) $wpdb->get_results('SHOW VARIABLES', ARRAY_N); $mysql_variables = array(); foreach ($mysql_variables_result as $mysql_variables_row) { $mysql_variables[$mysql_variables_row[0]] = $mysql_variables_row[1]; } $server_info = array('w3tc' => array('version' => W3TC_VERSION, 'server' => !empty($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'Unknown', 'dir' => W3TC_DIR, 'cache_dir' => W3TC_CACHE_DIR, 'blog_id' => Util_Environment::blog_id(), 'home_domain_root_url' => Util_Environment::home_domain_root_url(), 'home_url_maybe_https' => Util_Environment::home_url_maybe_https(), 'site_path' => Util_Environment::site_path(), 'document_root' => Util_Environment::document_root(), 'site_root' => Util_Environment::site_root(), 'site_url_uri' => Util_Environment::site_url_uri(), 'home_url_host' => Util_Environment::home_url_host(), 'home_url_uri' => Util_Environment::home_url_uri(), 'network_home_url_uri' => Util_Environment::network_home_url_uri(), 'host_port' => Util_Environment::host_port(), 'host' => Util_Environment::host(), 'wp_config_path' => Util_Environment::wp_config_path()), 'wp' => array('version' => $wp_version, 'db_version' => $wp_db_version, 'abspath' => ABSPATH, 'home' => get_option('home'), 'siteurl' => get_option('siteurl'), 'email' => get_option('admin_email'), 'upload_info' => (array) Util_Http::upload_info(), 'theme' => Util_Theme::get_current_theme(), 'wp_cache' => defined('WP_CACHE') && WP_CACHE ? 'true' : 'false', 'plugins' => $wordpress_plugins_active), 'mysql' => array('version' => $mysql_version, 'variables' => $mysql_variables)); return $server_info; }
/** * Exports custom files to CDN * * @return array */ function get_files_custom() { $files = array(); $document_root = Util_Environment::document_root(); $custom_files = $this->_config->get_array('cdn.custom.files'); $custom_files = array_map(array('\\W3TC\\Util_Environment', 'parse_path'), $custom_files); $site_root = Util_Environment::site_root(); $path = Util_Environment::site_url_uri(); $site_root_dir = str_replace($document_root, '', $site_root); if (strstr(WP_CONTENT_DIR, Util_Environment::site_root()) === false) { $site_root = Util_Environment::document_root(); $path = ''; } $content_path = trim(str_replace(WP_CONTENT_DIR, '', $site_root), '/\\'); foreach ($custom_files as $custom_file) { if ($custom_file != '') { $custom_file = Cdn_Util::replace_folder_placeholders($custom_file); $custom_file = Util_Environment::normalize_file($custom_file); if (!Util_Environment::is_wpmu()) { $dir = trim(dirname($custom_file), '/\\'); $rel_path = trim(dirname($custom_file), '/\\'); } else { $rel_path = $dir = trim(dirname($custom_file), '/\\'); } if (strpos($dir, '<currentblog>') != false) { $rel_path = $dir = str_replace('<currentblog>', 'blogs.dir/' . Util_Environment::blog_id(), $dir); } if ($dir == '.') { $rel_path = $dir = ''; } $mask = basename($custom_file); $files = array_merge($files, Cdn_Util::search_files($document_root . '/' . $dir, $rel_path, $mask)); } } return $files; }
/** * Normalizes file name for minify * Relative to document root! * * @param string $file * @return string */ public static function url_to_docroot_filename($url) { $data = array('home_url' => get_home_url(), 'url' => $url); $data = apply_filters('w3tc_url_to_docroot_filename', $data); $home_url = $data['home_url']; $normalized_url = $data['url']; $normalized_url = Util_Environment::remove_query_all($normalized_url); // cut protocol $normalized_url = preg_replace('~^http(s)?://~', '//', $normalized_url); $home_url = preg_replace('~^http(s)?://~', '//', $home_url); if (substr($normalized_url, 0, strlen($home_url)) != $home_url) { // not a home url, return unchanged since cant be // converted to filename return $url; } else { $path_relative_to_home = str_replace($home_url, '', $normalized_url); $home = set_url_scheme(get_option('home'), 'http'); $siteurl = set_url_scheme(get_option('siteurl'), 'http'); $home_path = rtrim(Util_Environment::site_path(), '/'); // adjust home_path if site is not is home if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) { // $siteurl - $home $wp_path_rel_to_home = rtrim(str_ireplace($home, '', $siteurl), '/'); if (substr($home_path, -strlen($wp_path_rel_to_home)) == $wp_path_rel_to_home) { $home_path = substr($home_path, 0, -strlen($wp_path_rel_to_home)); } } // common encoded characters $path_relative_to_home = str_replace('%20', ' ', $path_relative_to_home); $full_filename = $home_path . DIRECTORY_SEPARATOR . trim($path_relative_to_home, DIRECTORY_SEPARATOR); $docroot = Util_Environment::document_root(); if (substr($full_filename, 0, strlen($docroot)) == $docroot) { $docroot_filename = substr($full_filename, strlen($docroot)); } else { $docroot_filename = $path_relative_to_home; } } // sometimes urls (coming from other plugins/themes) // contain multiple "/" like "my-folder//myfile.js" which // fails to recognize by filesystem, while url is accessible $docroot_filename = str_replace('//', DIRECTORY_SEPARATOR, $docroot_filename); return ltrim($docroot_filename, DIRECTORY_SEPARATOR); }
static function replace_folder_placeholders($file) { static $content_dir, $plugin_dir, $upload_dir; if (empty($content_dir)) { $content_dir = str_replace(Util_Environment::document_root(), '', WP_CONTENT_DIR); $content_dir = substr($content_dir, strlen(Util_Environment::site_url_uri())); $content_dir = trim($content_dir, '/'); if (defined('WP_PLUGIN_DIR')) { $plugin_dir = str_replace(Util_Environment::document_root(), '', WP_PLUGIN_DIR); $plugin_dir = trim($plugin_dir, '/'); } else { $plugin_dir = str_replace(Util_Environment::document_root(), '', WP_CONTENT_DIR . '/plugins'); $plugin_dir = trim($plugin_dir, '/'); } $upload_dir = Util_Environment::wp_upload_dir(); $upload_dir = str_replace(Util_Environment::document_root(), '', $upload_dir['basedir']); $upload_dir = trim($upload_dir, '/'); } $file = str_replace('{wp_content_dir}', $content_dir, $file); $file = str_replace('{plugins_dir}', $plugin_dir, $file); $file = str_replace('{uploads_dir}', $upload_dir, $file); return $file; }