Version Description
- Add : First Beta release
=
Download this release
Release Info
Developer | adeelkhan |
Plugin | Breeze – WordPress Cache Plugin |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- assets/css/style.css +97 -0
- assets/images/hdr-logo.png +0 -0
- assets/js/breeze-backend.js +130 -0
- assets/js/breeze-configuration.js +54 -0
- breeze.php +106 -0
- inc/breeze-admin.php +324 -0
- inc/breeze-configuration.php +541 -0
- inc/cache/Mobile-Detect-2.8.25/LICENSE.txt +48 -0
- inc/cache/Mobile-Detect-2.8.25/Mobile_Detect.json +1 -0
- inc/cache/Mobile-Detect-2.8.25/Mobile_Detect.php +1460 -0
- inc/cache/Mobile-Detect-2.8.25/README.md +283 -0
- inc/cache/Mobile-Detect-2.8.25/composer.json +28 -0
- inc/cache/Mobile-Detect-2.8.25/export/exportToJSON.php +67 -0
- inc/cache/Mobile-Detect-2.8.25/namespaced/Detection/MobileDetect.php +22 -0
- inc/cache/Mobile-Detect-2.8.25/ruleset.xml +187 -0
- inc/cache/config-cache.php +232 -0
- inc/cache/execute-cache.php +377 -0
- inc/cache/purge-cache.php +172 -0
- inc/cache/purge-per-time.php +116 -0
- inc/cache/purge-varnish.php +338 -0
- inc/cdn-integration/breeze-cdn-integration.php +58 -0
- inc/cdn-integration/breeze-cdn-rewrite.php +119 -0
- inc/minification/breeze-minification-base.php +320 -0
- inc/minification/breeze-minification-cache.php +256 -0
- inc/minification/breeze-minification-html.php +89 -0
- inc/minification/breeze-minification-scripts.php +504 -0
- inc/minification/breeze-minification-styles.php +809 -0
- inc/minification/breeze-minify-main.php +255 -0
- inc/minification/config/default.php +64 -0
- inc/minification/config/delayed.php +85 -0
- inc/minification/config/minificationFontRegex.php +8 -0
- inc/minification/minify/index.html +1 -0
- inc/minification/minify/jsmin-1.1.1.php +291 -0
- inc/minification/minify/minify-2.1.7-html.php +257 -0
- inc/minification/minify/minify-2.1.7-jsmin.php +447 -0
- inc/minification/minify/minify-css-compressor.php +250 -0
- inc/minification/minify/minify-html.php +268 -0
- inc/minification/minify/yui-php-cssmin-2.4.8-4.php +777 -0
- inc/minification/minify/yui-php-cssmin-2.4.8-4_fgo.php +789 -0
- languages/breeze-en_US.mo +0 -0
- languages/breeze-en_US.po +110 -0
- languages/breeze-fr_FR.mo +0 -0
- languages/breeze-fr_FR.po +87 -0
- languages/breeze.pot +111 -0
- readme.txt +132 -0
- views/breeze-setting-views.php +59 -0
- views/tabs/advanced.php +70 -0
- views/tabs/basic.php +106 -0
- views/tabs/cdn.php +63 -0
- views/tabs/database.php +69 -0
- views/tabs/varnish.php +43 -0
assets/css/style.css
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.breeze-notice {
|
2 |
+
background-color: #FFF;
|
3 |
+
padding:10px;
|
4 |
+
margin: 15px 0 15px 0;
|
5 |
+
border: 1px solid #CCC;
|
6 |
+
}
|
7 |
+
.breeze-header .breeze-logo{
|
8 |
+
background-image: url("../images/hdr-logo.png");
|
9 |
+
background-position: center -169px;
|
10 |
+
width: 60px;
|
11 |
+
height: 60px;
|
12 |
+
background-repeat: no-repeat;
|
13 |
+
float: left;
|
14 |
+
}
|
15 |
+
.breeze-header .breeze-logo-title{
|
16 |
+
float: left;
|
17 |
+
font-size: 16px;
|
18 |
+
font-weight:500;
|
19 |
+
line-height: 25px;
|
20 |
+
margin-top: 20px;
|
21 |
+
}
|
22 |
+
.breeze-header a{
|
23 |
+
text-decoration: none;
|
24 |
+
color: #000;
|
25 |
+
}
|
26 |
+
#breeze-tabs .nav-tab.active {
|
27 |
+
background-color: #FFF;
|
28 |
+
color: #464646;
|
29 |
+
}
|
30 |
+
|
31 |
+
.tab-child {
|
32 |
+
overflow: hidden;
|
33 |
+
background: #fff;
|
34 |
+
border-bottom: 1px solid #CCC;
|
35 |
+
border-left: 1px solid #CCC;
|
36 |
+
border-right: 1px solid #CCC;
|
37 |
+
padding: 10px 10px 30px 10px
|
38 |
+
}
|
39 |
+
|
40 |
+
#breeze-tabs-content .tab-pane {
|
41 |
+
display: none
|
42 |
+
}
|
43 |
+
|
44 |
+
#breeze-tabs-content .tab-pane.active {
|
45 |
+
display: block
|
46 |
+
}
|
47 |
+
|
48 |
+
.tab-content {
|
49 |
+
overflow: auto;
|
50 |
+
}
|
51 |
+
.tabs-below > .nav-tabs,
|
52 |
+
.tabs-right > .nav-tabs,
|
53 |
+
.tabs-left > .nav-tabs {
|
54 |
+
border-bottom: 0;
|
55 |
+
}
|
56 |
+
.tab-content > .tab-pane{
|
57 |
+
display: none;
|
58 |
+
}
|
59 |
+
.tab-content > .active{
|
60 |
+
display: block;
|
61 |
+
}
|
62 |
+
|
63 |
+
/*Table*/
|
64 |
+
#breeze-tabs-content table tr td:first-child{
|
65 |
+
width: 20%;
|
66 |
+
font-weight: bold;
|
67 |
+
}
|
68 |
+
#breeze-tabs-content table tr td.last-td{
|
69 |
+
font-weight: normal;
|
70 |
+
padding-top: 30px;
|
71 |
+
}
|
72 |
+
#breeze-tabs-content table tr td{
|
73 |
+
vertical-align: top;
|
74 |
+
padding: 3px;
|
75 |
+
}
|
76 |
+
|
77 |
+
#breeze-tabs-content table ul{
|
78 |
+
margin: 0 ;
|
79 |
+
}
|
80 |
+
#breeze-tabs-content table tr td label{
|
81 |
+
vertical-align: top;
|
82 |
+
}
|
83 |
+
#breeze-tabs-content table tr td.input-middle{
|
84 |
+
vertical-align: middle;
|
85 |
+
}
|
86 |
+
.breeze-top-notice{
|
87 |
+
margin: 10px 0 5px 0;
|
88 |
+
}
|
89 |
+
.breeze-top-notice label{
|
90 |
+
padding-left: 15px;
|
91 |
+
font-size: 15px;
|
92 |
+
font-weight: 400;
|
93 |
+
}
|
94 |
+
label.breeze_tool_tip{
|
95 |
+
vertical-align: middle !important;
|
96 |
+
}
|
97 |
+
|
assets/images/hdr-logo.png
ADDED
Binary file
|
assets/js/breeze-backend.js
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(document).ready(function ($) {
|
2 |
+
// Topbar action
|
3 |
+
$('#wp-admin-bar-breeze-purge-varnish-group').click(function(){
|
4 |
+
breeze_purgeVarnish_callAjax();
|
5 |
+
});
|
6 |
+
$('#wp-admin-bar-breeze-purge-file-group').click(function(){
|
7 |
+
breeze_purgeFile_callAjax();
|
8 |
+
});
|
9 |
+
$('#wp-admin-bar-breeze-purge-database-group').click(function(){
|
10 |
+
breeze_purgeDatabase_callAjax();
|
11 |
+
});
|
12 |
+
// Varnish clear button
|
13 |
+
$('#purge-varnish-button').click(function(){
|
14 |
+
breeze_purgeVarnish_callAjax();
|
15 |
+
});
|
16 |
+
|
17 |
+
//clear cache by button
|
18 |
+
function breeze_purgeVarnish_callAjax(){
|
19 |
+
$.ajax({
|
20 |
+
url:ajaxurl,
|
21 |
+
dataType:'json',
|
22 |
+
method:'POST',
|
23 |
+
data:{
|
24 |
+
action:'breeze_purge_varnish'
|
25 |
+
},
|
26 |
+
success : function(res){
|
27 |
+
current = location.href;
|
28 |
+
if(res.clear){
|
29 |
+
var div = '<div id="message" class="notice notice-success" style="margin-top:10px; margin-bottom:10px;padding: 10px;"><strong>OK! Purge Varnish Success</strong></div>';
|
30 |
+
//backend
|
31 |
+
$("#wpbody .wrap h1").after(div);
|
32 |
+
setTimeout(function(){
|
33 |
+
location.reload();
|
34 |
+
},2000);
|
35 |
+
}else{
|
36 |
+
window.location.href = current+ "breeze-msg=purge-fail";
|
37 |
+
location.reload();
|
38 |
+
}
|
39 |
+
}
|
40 |
+
});
|
41 |
+
}
|
42 |
+
|
43 |
+
function breeze_purgeFile_callAjax(){
|
44 |
+
$.ajax({
|
45 |
+
url:ajaxurl,
|
46 |
+
dataType:'json',
|
47 |
+
method:'POST',
|
48 |
+
data:{
|
49 |
+
action:'breeze_purge_file'
|
50 |
+
},
|
51 |
+
success : function(res){
|
52 |
+
current = location.href;
|
53 |
+
res = parseFloat(res) ;
|
54 |
+
if(current.indexOf("page=breeze_config") > 0){
|
55 |
+
window.location.href = current+ "#breeze-msg=success-cleancache&file="+res;
|
56 |
+
}else{
|
57 |
+
window.location.href = current+ "breeze-msg=success-cleancache&file="+res;
|
58 |
+
}
|
59 |
+
location.reload();
|
60 |
+
}
|
61 |
+
});
|
62 |
+
}
|
63 |
+
|
64 |
+
function breeze_purgeDatabase_callAjax(){
|
65 |
+
$.ajax({
|
66 |
+
url:ajaxurl,
|
67 |
+
dataType:'json',
|
68 |
+
method:'POST',
|
69 |
+
data:{
|
70 |
+
action:'breeze_purge_database'
|
71 |
+
},
|
72 |
+
success : function(res){
|
73 |
+
current = location.href;
|
74 |
+
if(res.clear){
|
75 |
+
var div = '<div id="message" class="notice notice-success" style="margin-top:10px; margin-bottom:10px;padding: 10px;"><strong>OK! Database cleanup successful</strong></div>';
|
76 |
+
//backend
|
77 |
+
$("#wpbody .wrap h1").after(div);
|
78 |
+
setTimeout(function(){
|
79 |
+
location.reload();
|
80 |
+
},2000);
|
81 |
+
}else{
|
82 |
+
window.location.href = current+ "breeze-msg=purge-fail";
|
83 |
+
location.reload();
|
84 |
+
}
|
85 |
+
}
|
86 |
+
});
|
87 |
+
}
|
88 |
+
|
89 |
+
function getParameterByName(name, url) {
|
90 |
+
if (!url) url = window.location.href;
|
91 |
+
name = name.replace(/[\[\]]/g, "\\$&");
|
92 |
+
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
|
93 |
+
results = regex.exec(url);
|
94 |
+
if (!results) return null;
|
95 |
+
if (!results[2]) return '';
|
96 |
+
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
97 |
+
}
|
98 |
+
|
99 |
+
var url = location.href;
|
100 |
+
var fileClean = parseFloat(getParameterByName('file',url) );
|
101 |
+
|
102 |
+
$( window ).load(function() {
|
103 |
+
var patt = /wp-admin/i;
|
104 |
+
if(patt.test(url)){
|
105 |
+
//backend
|
106 |
+
var div = '';
|
107 |
+
if(url.indexOf("msg=success-cleancache") > 0 && !isNaN(fileClean) ) {
|
108 |
+
if(fileClean > 0){
|
109 |
+
div = '<div id="message" class="notice notice-success" style="margin-top:10px; margin-bottom:10px;padding: 10px;"><strong>OK cache is clean: '+fileClean+'Kb cleaned</strong></div>';
|
110 |
+
}else{
|
111 |
+
div = '<div id="message" class="notice notice-success" style="margin-top:10px; margin-bottom:10px;padding: 10px;"><strong>OK ! Cache file cleaned successfully</strong></div>';
|
112 |
+
|
113 |
+
}
|
114 |
+
|
115 |
+
$("#wpbody .wrap h1").after(div);
|
116 |
+
|
117 |
+
var url_return = url.split('breeze-msg');
|
118 |
+
setTimeout(function(){
|
119 |
+
window.location = url_return[0];
|
120 |
+
location.reload();
|
121 |
+
},2000);
|
122 |
+
}
|
123 |
+
}else{
|
124 |
+
//frontend
|
125 |
+
}
|
126 |
+
|
127 |
+
});
|
128 |
+
|
129 |
+
|
130 |
+
});
|
assets/js/breeze-configuration.js
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(document).ready(function($){
|
2 |
+
// database clean tabs
|
3 |
+
$('input[name="all_control"]').click(function () {
|
4 |
+
var checked = $(this).is(':checked');
|
5 |
+
if (checked == true) {
|
6 |
+
$(".clean-data").prop("checked", true);
|
7 |
+
} else {
|
8 |
+
$(".clean-data").prop("checked", false);
|
9 |
+
}
|
10 |
+
});
|
11 |
+
|
12 |
+
$('.clean-data').click(function () {
|
13 |
+
var checked = $(this).is(':checked');
|
14 |
+
if (checked == false) {
|
15 |
+
$('input[name="all_control"]').prop('checked', false);
|
16 |
+
}
|
17 |
+
});
|
18 |
+
|
19 |
+
// Tab
|
20 |
+
$("#breeze-tabs .nav-tab").click(function (e) {
|
21 |
+
e.preventDefault();
|
22 |
+
$("#breeze-tabs .nav-tab").removeClass('active');
|
23 |
+
$(e.target).addClass('active');
|
24 |
+
id_tab = $(this).data('tab-id');
|
25 |
+
$("#tab-" + id_tab).addClass('active');
|
26 |
+
$("#breeze-tabs-content .tab-pane").removeClass('active');
|
27 |
+
$("#tab-content-" + id_tab).addClass('active');
|
28 |
+
document.cookie = 'breeze_active_tab=' + id_tab;
|
29 |
+
});
|
30 |
+
|
31 |
+
// Cookie do
|
32 |
+
function setTabFromCookie() {
|
33 |
+
active_tab = getCookie('breeze_active_tab');
|
34 |
+
if (!active_tab){
|
35 |
+
active_tab = 'basic';
|
36 |
+
}
|
37 |
+
$("#tab-" + active_tab).addClass('active');
|
38 |
+
$("#tab-content-" + active_tab).addClass('active');
|
39 |
+
}
|
40 |
+
|
41 |
+
function getCookie(cname) {
|
42 |
+
var name = cname + "=";
|
43 |
+
var ca = document.cookie.split(';');
|
44 |
+
for (var i = 0; i < ca.length; i++) {
|
45 |
+
var c = ca[i];
|
46 |
+
while (c.charAt(0) == ' ') c = c.substring(1);
|
47 |
+
if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
|
48 |
+
}
|
49 |
+
return "";
|
50 |
+
}
|
51 |
+
|
52 |
+
setTabFromCookie();
|
53 |
+
|
54 |
+
});
|
breeze.php
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: Breeze
|
4 |
+
* Description: Breeze is a WordPress cache plugin with extensive options to speed up your website. All the options including Varnish Cache are compatible with Cloudways hosting.
|
5 |
+
* Version: 1.0.0
|
6 |
+
* Text Domain: breeze
|
7 |
+
* Domain Path: /languages
|
8 |
+
* Author: Cloudways
|
9 |
+
* Author URI: https://www.cloudways.com
|
10 |
+
* License: GPL2
|
11 |
+
*/
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
15 |
+
*
|
16 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
17 |
+
*
|
18 |
+
* This program is free software; you can redistribute it and/or modify
|
19 |
+
* it under the terms of the GNU General Public License as published by
|
20 |
+
* the Free Software Foundation; either version 2 of the License, or
|
21 |
+
* (at your option) any later version.
|
22 |
+
*
|
23 |
+
* This program is distributed in the hope that it will be useful,
|
24 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
25 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
26 |
+
* GNU General Public License for more details.
|
27 |
+
*
|
28 |
+
* You should have received a copy of the GNU General Public License
|
29 |
+
* along with this program; if not, write to the Free Software
|
30 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
31 |
+
*/
|
32 |
+
|
33 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
34 |
+
|
35 |
+
if (!defined('BREEZE_PLUGIN_DIR'))
|
36 |
+
define('BREEZE_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
37 |
+
if (!defined('BREEZE_VERSION'))
|
38 |
+
define('BREEZE_VERSION','1.0.0');
|
39 |
+
if (!defined('BREEZE_SITEURL'))
|
40 |
+
define('BREEZE_SITEURL', get_site_url());
|
41 |
+
if (!defined('BREEZE_MINIFICATION_CACHE'))
|
42 |
+
define('BREEZE_MINIFICATION_CACHE', WP_CONTENT_DIR . '/cache/breeze-minification/');
|
43 |
+
if (!defined('BREEZE_CACHEFILE_PREFIX'))
|
44 |
+
define('BREEZE_CACHEFILE_PREFIX', 'breeze_');
|
45 |
+
if (!defined('BREEZE_CACHE_CHILD_DIR'))
|
46 |
+
define('BREEZE_CACHE_CHILD_DIR', '/cache/breeze-minification/');
|
47 |
+
if (!defined('BREEZE_WP_CONTENT_NAME'))
|
48 |
+
define('BREEZE_WP_CONTENT_NAME', '/' . wp_basename(WP_CONTENT_DIR));
|
49 |
+
if (!defined('BREEZE_BASENAME'))
|
50 |
+
define('BREEZE_BASENAME',plugin_basename(__FILE__));
|
51 |
+
|
52 |
+
define('BREEZE_CACHE_DELAY', true);
|
53 |
+
define('BREEZE_CACHE_NOGZIP', true);
|
54 |
+
define('BREEZE_ROOT_DIR', str_replace(BREEZE_WP_CONTENT_NAME, '', WP_CONTENT_DIR));
|
55 |
+
//action to purge cache
|
56 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/cache/purge-varnish.php');
|
57 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/cache/purge-cache.php');
|
58 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/cache/purge-per-time.php');
|
59 |
+
|
60 |
+
// Activate plugin hook
|
61 |
+
register_activation_hook(__FILE__,array('Breeze_Admin','plugin_active_hook'));
|
62 |
+
//Deactivate plugin hook
|
63 |
+
register_deactivation_hook(__FILE__,array('Breeze_Admin','plugin_deactive_hook'));
|
64 |
+
|
65 |
+
|
66 |
+
if(is_admin()){
|
67 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/breeze-admin.php');
|
68 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/breeze-configuration.php');
|
69 |
+
//config to cache
|
70 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/cache/config-cache.php');
|
71 |
+
}else{
|
72 |
+
$cdn_conf = get_option('breeze_cdn_integration');
|
73 |
+
$basic_conf = get_option('breeze_basic_settings');
|
74 |
+
|
75 |
+
if(!empty($cdn_conf['cdn-active']) || !empty($basic_conf['breeze-minify-js']) || !empty($basic_conf['breeze-minify-css']) || !empty($basic_conf['breeze-minify-html'])) {
|
76 |
+
// Call back ob start
|
77 |
+
ob_start('breeze_ob_start_callback');
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
// Call back ob start - stack
|
82 |
+
function breeze_ob_start_callback($buffer){
|
83 |
+
$conf = get_option('breeze_cdn_integration');
|
84 |
+
// Get buffer from minify
|
85 |
+
$buffer = apply_filters('breeze_minify_content_return',$buffer);
|
86 |
+
|
87 |
+
if(!empty($conf) || !empty($conf['cdn-active'])){
|
88 |
+
// Get buffer after remove query strings
|
89 |
+
$buffer = apply_filters('breeze_cdn_content_return',$buffer);
|
90 |
+
}
|
91 |
+
// Return content
|
92 |
+
return $buffer;
|
93 |
+
}
|
94 |
+
|
95 |
+
// Minify
|
96 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minify-main.php');
|
97 |
+
require_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-cache.php');
|
98 |
+
new Breeze_Minify();
|
99 |
+
// CDN Integration
|
100 |
+
if( !class_exists('Breeze_CDN_Integration')){
|
101 |
+
require_once ( BREEZE_PLUGIN_DIR. 'inc/cdn-integration/breeze-cdn-integration.php');
|
102 |
+
require_once ( BREEZE_PLUGIN_DIR. 'inc/cdn-integration/breeze-cdn-rewrite.php');
|
103 |
+
new Breeze_CDN_Integration();
|
104 |
+
}
|
105 |
+
|
106 |
+
|
inc/breeze-admin.php
ADDED
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_Admin {
|
24 |
+
public function __construct(){
|
25 |
+
add_action('init', function(){
|
26 |
+
load_plugin_textdomain('breeze', false, dirname(plugin_basename(__FILE__)) . '/languages/');
|
27 |
+
});
|
28 |
+
|
29 |
+
add_action('admin_init', array($this, 'admin_init'));
|
30 |
+
//register menu
|
31 |
+
add_action('admin_menu', array($this, 'register_menu_page'));
|
32 |
+
|
33 |
+
$config = get_option('breeze_basic_settings');
|
34 |
+
|
35 |
+
if(isset($config['breeze-display-clean']) && $config['breeze-display-clean']){
|
36 |
+
//register top bar menu
|
37 |
+
add_action('admin_bar_menu', array($this, 'register_admin_bar_menu'), 999);
|
38 |
+
}
|
39 |
+
|
40 |
+
/** Load admin js * */
|
41 |
+
add_action('admin_enqueue_scripts', array($this, 'loadAdminScripts'));
|
42 |
+
|
43 |
+
add_action('wp_head', array($this,'define_ajaxurl'));
|
44 |
+
$this->ajaxHandle();
|
45 |
+
|
46 |
+
add_filter( 'plugin_action_links_'.BREEZE_BASENAME, array($this,'breeze_add_action_links') );
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Admin Init
|
51 |
+
*
|
52 |
+
*/
|
53 |
+
public function admin_init()
|
54 |
+
{
|
55 |
+
//Check plugin requirements
|
56 |
+
if (version_compare(PHP_VERSION, '5.3', '<')) {
|
57 |
+
if (current_user_can('activate_plugins') && is_plugin_active(plugin_basename(__FILE__))) {
|
58 |
+
deactivate_plugins(__FILE__);
|
59 |
+
add_action('admin_notices', array($this, 'breeze_show_error'));
|
60 |
+
unset($_GET['activate']);
|
61 |
+
}
|
62 |
+
}
|
63 |
+
//Do not load anything more
|
64 |
+
return;
|
65 |
+
}
|
66 |
+
|
67 |
+
//define ajaxurl
|
68 |
+
function define_ajaxurl() {
|
69 |
+
if(current_user_can('manage_options')){
|
70 |
+
echo '<script type="text/javascript">
|
71 |
+
var ajaxurl = "' . admin_url('admin-ajax.php') . '";
|
72 |
+
</script>';
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
function loadAdminScripts() {
|
77 |
+
wp_enqueue_script('jquery');
|
78 |
+
wp_enqueue_script('breeze-backend', plugins_url('assets/js/breeze-backend.js', dirname(__FILE__)), array('jquery'), BREEZE_VERSION, true);
|
79 |
+
$current_screen = get_current_screen();
|
80 |
+
if($current_screen->base == 'settings_page_breeze'){
|
81 |
+
//add css
|
82 |
+
wp_enqueue_style('breeze-style', plugins_url('assets/css/style.css', dirname(__FILE__)));
|
83 |
+
//js
|
84 |
+
wp_enqueue_script('breeze-configuration', plugins_url('assets/js/breeze-configuration.js', dirname(__FILE__)), array('jquery'), BREEZE_VERSION, true);
|
85 |
+
}
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Register menu
|
90 |
+
*
|
91 |
+
*/
|
92 |
+
function register_menu_page()
|
93 |
+
{
|
94 |
+
//add submenu for cloudsway
|
95 |
+
add_submenu_page( 'options-general.php', __('Breeze', 'breeze'), __('Breeze', 'breeze'), 'manage_options', 'breeze', array($this, 'breeze_load_page') );
|
96 |
+
}
|
97 |
+
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Register bar menu
|
101 |
+
*
|
102 |
+
*/
|
103 |
+
function register_admin_bar_menu(WP_Admin_Bar $wp_admin_bar)
|
104 |
+
{
|
105 |
+
if (current_user_can('manage_options')) {
|
106 |
+
// add a parent item
|
107 |
+
$args = array(
|
108 |
+
'id' => 'breeze-topbar',
|
109 |
+
'title' => esc_html(__('Breeze', 'breeze')),
|
110 |
+
'meta' => array(
|
111 |
+
'classname' => 'breeze',
|
112 |
+
),
|
113 |
+
);
|
114 |
+
$wp_admin_bar->add_node( $args );
|
115 |
+
|
116 |
+
// add purge all item
|
117 |
+
$args = array(
|
118 |
+
'id' => 'breeze-purge-all',
|
119 |
+
'title' => esc_html(__('Purge All Cache', 'breeze')),
|
120 |
+
'href' => wp_nonce_url(add_query_arg('breeze_purge', 1), 'breeze_purge_cache'),
|
121 |
+
'parent' => 'breeze-topbar',
|
122 |
+
'meta' => array( 'class' => 'breeze-toolbar-group' ),
|
123 |
+
);
|
124 |
+
$wp_admin_bar->add_node( $args );
|
125 |
+
|
126 |
+
// add purge modules group
|
127 |
+
$args = array(
|
128 |
+
'id' => 'breeze-purge-modules',
|
129 |
+
'title' => esc_html(__('Purge Modules', 'breeze')),
|
130 |
+
'href' => '#',
|
131 |
+
'parent' => 'breeze-topbar',
|
132 |
+
'meta' => array( 'class' => 'breeze-toolbar-group' ),
|
133 |
+
);
|
134 |
+
$wp_admin_bar->add_node( $args );
|
135 |
+
|
136 |
+
|
137 |
+
// add child item (Purge Modules)
|
138 |
+
$args = array(
|
139 |
+
'id' => 'breeze-purge-varnish-group',
|
140 |
+
'title' => esc_html(__('Purge Varnish', 'breeze')),
|
141 |
+
'href' => '#',
|
142 |
+
'parent' => 'breeze-purge-modules',
|
143 |
+
);
|
144 |
+
$wp_admin_bar->add_node( $args );
|
145 |
+
|
146 |
+
// add child item (Purge Modules)
|
147 |
+
$args = array(
|
148 |
+
'id' => 'breeze-purge-file-group',
|
149 |
+
'title' => esc_html(__('Purge File', 'breeze')),
|
150 |
+
'href' => '#',
|
151 |
+
'parent' => 'breeze-purge-modules',
|
152 |
+
);
|
153 |
+
$wp_admin_bar->add_node( $args );
|
154 |
+
|
155 |
+
// add child item (Purge Modules)
|
156 |
+
$args = array(
|
157 |
+
'id' => 'breeze-purge-database-group',
|
158 |
+
'title' => esc_html(__('Purge Database', 'breeze')),
|
159 |
+
'href' => '#',
|
160 |
+
'parent' => 'breeze-purge-modules',
|
161 |
+
);
|
162 |
+
$wp_admin_bar->add_node( $args );
|
163 |
+
|
164 |
+
// add settings item
|
165 |
+
$args = array(
|
166 |
+
'id' => 'breeze-settings',
|
167 |
+
'title' => esc_html(__('Settings', 'breeze')),
|
168 |
+
'parent' => 'breeze-topbar',
|
169 |
+
'href' => 'options-general.php?page=breeze',
|
170 |
+
'meta' => array( 'class' => 'breeze-toolbar-group' ),
|
171 |
+
);
|
172 |
+
$wp_admin_bar->add_node( $args );
|
173 |
+
|
174 |
+
// add support item
|
175 |
+
$args = array(
|
176 |
+
'id' => 'breeze-support',
|
177 |
+
'title' => esc_html(__('Support', 'breeze')),
|
178 |
+
'href' => 'https://support.cloudways.com/breeze-wordpress-cache-configuration',
|
179 |
+
'parent' => 'breeze-topbar',
|
180 |
+
'meta' => array( 'class' => 'breeze-toolbar-group',
|
181 |
+
'target' => '_blank'),
|
182 |
+
);
|
183 |
+
$wp_admin_bar->add_node( $args );
|
184 |
+
|
185 |
+
}
|
186 |
+
}
|
187 |
+
|
188 |
+
function breeze_load_page()
|
189 |
+
{
|
190 |
+
if (isset($_GET['page']) && $_GET['page'] == 'breeze') {
|
191 |
+
require_once (BREEZE_PLUGIN_DIR . 'views/breeze-setting-views.php');
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
public function breeze_show_error()
|
196 |
+
{
|
197 |
+
echo '<div class="error"><p><strong>Breeze</strong> need at least PHP 5.3 version, please update php before installing the plugin.</p></div>';
|
198 |
+
}
|
199 |
+
//ajax admin
|
200 |
+
function ajaxHandle() {
|
201 |
+
add_action('wp_ajax_breeze_purge_varnish', array('Breeze_Configuration', 'purge_varnish_action'));
|
202 |
+
add_action('wp_ajax_breeze_purge_file', array('Breeze_Configuration', 'ajax_clean_cache'));
|
203 |
+
add_action('wp_ajax_breeze_purge_database', array('Breeze_Configuration', 'ajax_purge_database'));
|
204 |
+
}
|
205 |
+
/*
|
206 |
+
* Register active plugin hook
|
207 |
+
*/
|
208 |
+
public static function plugin_active_hook(){
|
209 |
+
WP_Filesystem();
|
210 |
+
// Default basic
|
211 |
+
$basic = get_option('breeze_basic_settings');
|
212 |
+
if(empty($basic)) $basic = array();
|
213 |
+
$default_basic = array(
|
214 |
+
'breeze-active' => '1',
|
215 |
+
'breeze-ttl' => '',
|
216 |
+
'breeze-minify-html' => '0',
|
217 |
+
'breeze-minify-css' => '0',
|
218 |
+
'breeze-minify-js' => '0',
|
219 |
+
'breeze-gzip-compression' => '1',
|
220 |
+
'breeze-desktop-cache' => '1',
|
221 |
+
'breeze-browser-cache' => '1',
|
222 |
+
'breeze-mobile-cache' => '1',
|
223 |
+
'breeze-disable-admin' => '1',
|
224 |
+
'breeze-display-clean' => '1',
|
225 |
+
);
|
226 |
+
$basic= array_merge($default_basic,$basic);
|
227 |
+
|
228 |
+
// Default Advanced
|
229 |
+
$advanced = get_option('breeze_advanced_settings');
|
230 |
+
if(empty($advanced)) $advanced = array();
|
231 |
+
$default_advanced = array(
|
232 |
+
'breeze-exclude-urls' => array(),
|
233 |
+
'breeze-group-css' => '0',
|
234 |
+
'breeze-group-js' => '0',
|
235 |
+
'breeze-exclude-css' => array(),
|
236 |
+
'breeze-exclude-js' => array()
|
237 |
+
);
|
238 |
+
$advanced= array_merge($default_advanced,$advanced);
|
239 |
+
|
240 |
+
//CDN default
|
241 |
+
$cdn = get_option('breeze_cdn_integration');
|
242 |
+
if(empty($cdn)) $cdn = array();
|
243 |
+
$wp_content = substr(WP_CONTENT_DIR,strlen(ABSPATH));
|
244 |
+
$default_cdn = array(
|
245 |
+
'cdn-active' => '0',
|
246 |
+
'cdn-url' =>'',
|
247 |
+
'cdn-content' => array('wp-includes',$wp_content),
|
248 |
+
'cdn-exclude-content' => array('.php'),
|
249 |
+
'cdn-relative-path' =>'1',
|
250 |
+
);
|
251 |
+
$cdn= array_merge($default_cdn,$cdn);
|
252 |
+
|
253 |
+
// Varnish default
|
254 |
+
$varnish = get_option('breeze_varnish_cache');
|
255 |
+
if(empty($varnish)) $varnish = array();
|
256 |
+
$default_varnish = array(
|
257 |
+
'auto-purge-varnish' => '1',
|
258 |
+
);
|
259 |
+
$varnish= array_merge($default_varnish,$varnish);
|
260 |
+
|
261 |
+
if(is_multisite()){
|
262 |
+
$blogs = get_sites();
|
263 |
+
foreach ($blogs as $blog){
|
264 |
+
update_blog_option((int)$blog->blog_id,'breeze_basic_settings', $basic);
|
265 |
+
update_blog_option((int)$blog->blog_id,'breeze_advanced_settings', $advanced);
|
266 |
+
update_blog_option((int)$blog->blog_id,'breeze_cdn_integration', $cdn);
|
267 |
+
update_blog_option((int)$blog->blog_id,'breeze_varnish_cache', $varnish);
|
268 |
+
}
|
269 |
+
}else{
|
270 |
+
update_option('breeze_basic_settings', $basic);
|
271 |
+
update_option('breeze_advanced_settings', $advanced);
|
272 |
+
update_option('breeze_cdn_integration', $cdn);
|
273 |
+
update_option('breeze_varnish_cache', $varnish);
|
274 |
+
}
|
275 |
+
|
276 |
+
//add header to htaccess by default
|
277 |
+
Breeze_Configuration::add_expires_header(TRUE);
|
278 |
+
Breeze_Configuration::add_gzip_htacess(TRUE);
|
279 |
+
//automatic config start cache
|
280 |
+
Breeze_ConfigCache::factory()->write();
|
281 |
+
Breeze_ConfigCache::factory()->write_config_cache();
|
282 |
+
|
283 |
+
if ( !empty($basic) && !empty($basic['breeze-active'] )) {
|
284 |
+
Breeze_ConfigCache::factory()->toggle_caching( true );
|
285 |
+
}
|
286 |
+
}
|
287 |
+
|
288 |
+
/*
|
289 |
+
* Register deactive plugin hook
|
290 |
+
*/
|
291 |
+
public static function plugin_deactive_hook(){
|
292 |
+
WP_Filesystem();
|
293 |
+
Breeze_ConfigCache::factory()->clean_up();
|
294 |
+
Breeze_ConfigCache::factory()->clean_config();
|
295 |
+
Breeze_ConfigCache::factory()->toggle_caching(false);
|
296 |
+
|
297 |
+
}
|
298 |
+
|
299 |
+
/*
|
300 |
+
* Render tab
|
301 |
+
*/
|
302 |
+
public static function render($tab){
|
303 |
+
require_once (BREEZE_PLUGIN_DIR . 'views/tabs/'.$tab.'.php');
|
304 |
+
}
|
305 |
+
|
306 |
+
// Check varnish cache exist
|
307 |
+
public static function check_varnish(){
|
308 |
+
if(isset($_SERVER['HTTP_X_VARNISH'])){
|
309 |
+
return true;
|
310 |
+
}
|
311 |
+
return false;
|
312 |
+
}
|
313 |
+
|
314 |
+
// Applied to the list of links to display on the plugins page
|
315 |
+
public function breeze_add_action_links($links){
|
316 |
+
|
317 |
+
$mylinks = array(
|
318 |
+
'<a href="' . admin_url( 'options-general.php?page=breeze' ) . '">Settings</a>',
|
319 |
+
);
|
320 |
+
return array_merge( $mylinks,$links );
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
$admin = new Breeze_Admin();
|
inc/breeze-configuration.php
ADDED
@@ -0,0 +1,541 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_Configuration{
|
24 |
+
public function __construct()
|
25 |
+
{
|
26 |
+
add_action( 'load-settings_page_breeze', array($this,'afterLoadConfigPage') );
|
27 |
+
}
|
28 |
+
|
29 |
+
|
30 |
+
/*
|
31 |
+
* function to save settings
|
32 |
+
*/
|
33 |
+
public function afterLoadConfigPage()
|
34 |
+
{
|
35 |
+
// Basic options tab
|
36 |
+
if (isset($_REQUEST['breeze_basic_action']) && $_REQUEST['breeze_basic_action'] == 'breeze_basic_settings') {
|
37 |
+
if (isset($_POST['breeze_settings_basic_nonce']) || wp_verify_nonce($_POST['breeze_settings_basic_nonce'], 'breeze_settings_basic')) {
|
38 |
+
WP_Filesystem();
|
39 |
+
|
40 |
+
$basic = array(
|
41 |
+
'breeze-active' =>(isset($_POST['cache-system']) ? '1' : '0'),
|
42 |
+
'breeze-ttl' => (int)$_POST['cache-ttl'],
|
43 |
+
'breeze-minify-html' => (isset($_POST['minification-html']) ? '1' : '0'),
|
44 |
+
'breeze-minify-css' => (isset($_POST['minification-css']) ? '1' : '0'),
|
45 |
+
'breeze-minify-js' => (isset($_POST['minification-js']) ? '1' : '0'),
|
46 |
+
'breeze-gzip-compression' => (isset($_POST['gzip-compression']) ? '1' : '0'),
|
47 |
+
'breeze-browser-cache' => (isset($_POST['browser-cache']) ? '1' : '0'),
|
48 |
+
'breeze-desktop-cache' => (int)$_POST['desktop-cache'],
|
49 |
+
'breeze-mobile-cache' => (int)$_POST['mobile-cache'],
|
50 |
+
'breeze-disable-admin' => '1',
|
51 |
+
'breeze-display-clean' => '1'
|
52 |
+
);
|
53 |
+
update_option('breeze_basic_settings',$basic);
|
54 |
+
|
55 |
+
// Storage infomation to cache pages
|
56 |
+
Breeze_ConfigCache::factory()->write();
|
57 |
+
Breeze_ConfigCache::factory()->write_config_cache();
|
58 |
+
|
59 |
+
// Turn on WP_CACHE to support advanced-cache file
|
60 |
+
if (isset($_POST['cache-system'])) {
|
61 |
+
Breeze_ConfigCache::factory()->toggle_caching(true);
|
62 |
+
} else {
|
63 |
+
Breeze_ConfigCache::factory()->toggle_caching(false);
|
64 |
+
}
|
65 |
+
|
66 |
+
// Reschedule cron events
|
67 |
+
if(isset($_POST['cache-system'])){
|
68 |
+
Breeze_PurgeCacheTime::factory()->unschedule_events();
|
69 |
+
Breeze_PurgeCacheTime::factory()->schedule_events();
|
70 |
+
}
|
71 |
+
// Add expires header
|
72 |
+
if(isset($_POST['gzip-compression'])){
|
73 |
+
self::add_gzip_htacess(true);
|
74 |
+
}else{
|
75 |
+
self::add_gzip_htacess(false);
|
76 |
+
}
|
77 |
+
// Add expires header
|
78 |
+
if(isset($_POST['browser-cache'])){
|
79 |
+
self::add_expires_header(true);
|
80 |
+
}else{
|
81 |
+
self::add_expires_header(false);
|
82 |
+
}
|
83 |
+
|
84 |
+
//delete minify
|
85 |
+
Breeze_MinificationCache::clear_minification();
|
86 |
+
Breeze_PurgeCache::breeze_cache_flush();
|
87 |
+
// Clear varnish cache after settings
|
88 |
+
$this->clear_varnish();
|
89 |
+
}
|
90 |
+
}
|
91 |
+
// Advanced options tab
|
92 |
+
if (isset($_REQUEST['breeze_advanced_action']) && $_REQUEST['breeze_advanced_action'] == 'breeze_advanced_settings') {
|
93 |
+
if (isset($_POST['breeze_settings_advanced_nonce']) || wp_verify_nonce($_POST['breeze_settings_advanced_nonce'], 'breeze_settings_advanced')) {
|
94 |
+
$exclude_urls = $this->string_convert_arr(sanitize_textarea_field($_POST['exclude-urls']));
|
95 |
+
$exclude_css = $this->string_convert_arr(sanitize_textarea_field($_POST['exclude-css']));
|
96 |
+
$exclude_js = $this->string_convert_arr(sanitize_textarea_field($_POST['exclude-js']));
|
97 |
+
$advanced = array(
|
98 |
+
'breeze-exclude-urls' => $exclude_urls,
|
99 |
+
'breeze-group-css' => (isset($_POST['group-css']) ? '1' : '0'),
|
100 |
+
'breeze-group-js' => (isset($_POST['group-js']) ? '1' : '0'),
|
101 |
+
'breeze-exclude-css' => $exclude_css,
|
102 |
+
'breeze-exclude-js' => $exclude_js
|
103 |
+
);
|
104 |
+
update_option('breeze_advanced_settings',$advanced);
|
105 |
+
|
106 |
+
WP_Filesystem();
|
107 |
+
// Storage infomation to cache pages
|
108 |
+
Breeze_ConfigCache::factory()->write_config_cache();
|
109 |
+
|
110 |
+
//delete minify
|
111 |
+
Breeze_MinificationCache::clear_minification();
|
112 |
+
Breeze_PurgeCache::breeze_cache_flush();
|
113 |
+
// Clear varnish cache after settings
|
114 |
+
$this->clear_varnish();
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
// Database option tab
|
119 |
+
if (isset($_REQUEST['breeze_database_action']) && $_REQUEST['breeze_database_action'] == 'breeze_database_settings') {
|
120 |
+
if (isset($_POST['breeze_settings_database_nonce']) || wp_verify_nonce($_POST['breeze_settings_database_nonce'], 'breeze_settings_database')) {
|
121 |
+
if(isset($_POST['clean'])){
|
122 |
+
foreach ($_POST['clean'] as $item){
|
123 |
+
$this->cleanSystem($item);
|
124 |
+
}
|
125 |
+
|
126 |
+
//return current page
|
127 |
+
if (!empty($_REQUEST['_wp_http_referer'])) {
|
128 |
+
wp_redirect($_REQUEST['_wp_http_referer'].'&database-cleanup=success');
|
129 |
+
exit;
|
130 |
+
}
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
// Cdn option tab
|
136 |
+
if (isset($_REQUEST['breeze_cdn_action']) && $_REQUEST['breeze_cdn_action'] == 'breeze_cdn_settings') {
|
137 |
+
if (isset($_POST['breeze_settings_cdn_nonce']) || wp_verify_nonce($_POST['breeze_settings_cdn_nonce'], 'breeze_settings_cdn')) {
|
138 |
+
$cdn_content = array();
|
139 |
+
$exclude_content = array();
|
140 |
+
if(!empty($_POST['cdn-content'])){
|
141 |
+
$cdn_content = explode(',',sanitize_text_field($_POST['cdn-content']));
|
142 |
+
$cdn_content = array_unique($cdn_content);
|
143 |
+
}
|
144 |
+
if(!empty($_POST['cdn-exclude-content'])){
|
145 |
+
$exclude_content = explode(',',sanitize_text_field($_POST['cdn-exclude-content']));
|
146 |
+
$exclude_content = array_unique($exclude_content);
|
147 |
+
}
|
148 |
+
|
149 |
+
$cdn = array(
|
150 |
+
'cdn-active' => (isset($_POST['activate-cdn']) ? '1' : '0'),
|
151 |
+
'cdn-url' =>(isset($_POST['cdn-url']) ? sanitize_text_field($_POST['cdn-url']) : ''),
|
152 |
+
'cdn-content' => $cdn_content,
|
153 |
+
'cdn-exclude-content' => $exclude_content,
|
154 |
+
'cdn-relative-path' =>(isset($_POST['cdn-relative-path']) ? '1' : '0'),
|
155 |
+
);
|
156 |
+
|
157 |
+
update_option('breeze_cdn_integration', $cdn);
|
158 |
+
|
159 |
+
//delete minify && normal cache
|
160 |
+
Breeze_MinificationCache::clear_minification();
|
161 |
+
Breeze_PurgeCache::breeze_cache_flush();
|
162 |
+
// Clear varnish cache after settings
|
163 |
+
$this->clear_varnish();
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
// Varnish option tab
|
168 |
+
if (isset($_REQUEST['breeze_varnish_action']) && $_REQUEST['breeze_varnish_action'] == 'breeze_varnish_settings') {
|
169 |
+
if (isset($_POST['breeze_settings_varnish_nonce']) || wp_verify_nonce($_POST['breeze_settings_varnish_nonce'], 'breeze_settings_varnish')) {
|
170 |
+
$varnish = array(
|
171 |
+
'auto-purge-varnish' => (isset($_POST['auto-purge-varnish']) ? '1' : '0'),
|
172 |
+
'breeze-varnish-server-ip' => preg_replace('/[^a-zA-Z0-9\-\_\.]*/','',$_POST['varnish-server-ip'])
|
173 |
+
);
|
174 |
+
update_option('breeze_varnish_cache',$varnish);
|
175 |
+
|
176 |
+
// Clear varnish cache after settings
|
177 |
+
$this->clear_varnish();
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
|
182 |
+
//return current page
|
183 |
+
if (!empty($_REQUEST['_wp_http_referer'])) {
|
184 |
+
wp_redirect($_REQUEST['_wp_http_referer'].'&save-settings=success');
|
185 |
+
exit;
|
186 |
+
}
|
187 |
+
|
188 |
+
return true;
|
189 |
+
}
|
190 |
+
|
191 |
+
/*
|
192 |
+
* function add expires header to .htaccess
|
193 |
+
*/
|
194 |
+
public static function add_expires_header($check) {
|
195 |
+
$expires = "#Expires headers configuration added by BREEZE WP CACHE plugin" . PHP_EOL .
|
196 |
+
"<IfModule mod_expires.c>" . PHP_EOL .
|
197 |
+
" ExpiresActive On" . PHP_EOL .
|
198 |
+
" ExpiresDefault A2592000" . PHP_EOL .
|
199 |
+
" ExpiresByType application/javascript \"access plus 7 days\"" . PHP_EOL .
|
200 |
+
" ExpiresByType text/javascript \"access plus 7 days\"" . PHP_EOL .
|
201 |
+
" ExpiresByType text/css \"access plus 7 days\"" . PHP_EOL .
|
202 |
+
" ExpiresByType image/jpeg \"access plus 7 days\"" . PHP_EOL .
|
203 |
+
" ExpiresByType image/png \"access plus 7 days\"" . PHP_EOL .
|
204 |
+
" ExpiresByType image/gif \"access plus 7 days\"" . PHP_EOL .
|
205 |
+
" ExpiresByType image/ico \"access plus 7 days\"" . PHP_EOL .
|
206 |
+
" ExpiresByType image/x-icon \"access plus 7 days\"" . PHP_EOL .
|
207 |
+
" ExpiresByType image/svg+xml \"access plus 7 days\"" . PHP_EOL .
|
208 |
+
" ExpiresByType image/bmp \"access plus 7 days\"" . PHP_EOL .
|
209 |
+
"</IfModule>" . PHP_EOL .
|
210 |
+
"#End of expires headers configuration" . PHP_EOL ;
|
211 |
+
|
212 |
+
if ($check) {
|
213 |
+
if (!is_super_admin()) {
|
214 |
+
return FALSE;
|
215 |
+
}
|
216 |
+
//open htaccess file
|
217 |
+
$htaccessContent = file_get_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess');
|
218 |
+
if (empty($htaccessContent)) {
|
219 |
+
return FALSE;
|
220 |
+
}
|
221 |
+
//if isset expires header in htacces
|
222 |
+
if (strpos($htaccessContent, 'mod_expires') !== false || strpos($htaccessContent, 'ExpiresActive') !== false || strpos($htaccessContent, 'ExpiresDefault') !== false || strpos($htaccessContent, 'ExpiresByType') !== false) {
|
223 |
+
return FALSE;
|
224 |
+
}
|
225 |
+
|
226 |
+
$htaccessContent = $expires.$htaccessContent;
|
227 |
+
file_put_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess', $htaccessContent);
|
228 |
+
return TRUE;
|
229 |
+
|
230 |
+
} else {
|
231 |
+
if (!is_super_admin()) {
|
232 |
+
return FALSE;
|
233 |
+
}
|
234 |
+
//open htaccess file
|
235 |
+
$htaccessContent = file_get_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess');
|
236 |
+
if (empty($htaccessContent)) {
|
237 |
+
return FALSE;
|
238 |
+
}
|
239 |
+
|
240 |
+
$htaccessContent = str_replace($expires,'',$htaccessContent);
|
241 |
+
file_put_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess', $htaccessContent);
|
242 |
+
return TRUE;
|
243 |
+
}
|
244 |
+
}
|
245 |
+
/*
|
246 |
+
* function add gzip header to .htaccess
|
247 |
+
*/
|
248 |
+
public static function add_gzip_htacess($check){
|
249 |
+
$data = "# Begin GzipofBreezeWPCache".PHP_EOL.
|
250 |
+
"<IfModule mod_deflate.c>".PHP_EOL.
|
251 |
+
"AddType x-font/woff .woff".PHP_EOL.
|
252 |
+
"AddOutputFilterByType DEFLATE image/svg+xml".PHP_EOL.
|
253 |
+
"AddOutputFilterByType DEFLATE text/plain".PHP_EOL.
|
254 |
+
"AddOutputFilterByType DEFLATE text/html".PHP_EOL.
|
255 |
+
"AddOutputFilterByType DEFLATE text/xml".PHP_EOL.
|
256 |
+
"AddOutputFilterByType DEFLATE text/css".PHP_EOL.
|
257 |
+
"AddOutputFilterByType DEFLATE text/javascript".PHP_EOL.
|
258 |
+
"AddOutputFilterByType DEFLATE application/xml".PHP_EOL.
|
259 |
+
"AddOutputFilterByType DEFLATE application/xhtml+xml".PHP_EOL.
|
260 |
+
"AddOutputFilterByType DEFLATE application/rss+xml".PHP_EOL.
|
261 |
+
"AddOutputFilterByType DEFLATE application/javascript".PHP_EOL.
|
262 |
+
"AddOutputFilterByType DEFLATE application/x-javascript".PHP_EOL.
|
263 |
+
"AddOutputFilterByType DEFLATE application/x-font-ttf".PHP_EOL.
|
264 |
+
"AddOutputFilterByType DEFLATE application/vnd.ms-fontobject".PHP_EOL.
|
265 |
+
"AddOutputFilterByType DEFLATE font/opentype font/ttf font/eot font/otf".PHP_EOL.
|
266 |
+
"</IfModule>".PHP_EOL.
|
267 |
+
"# End GzipofBreezeWPCache" . PHP_EOL ;
|
268 |
+
if ($check) {
|
269 |
+
if (!is_super_admin()) {
|
270 |
+
return FALSE;
|
271 |
+
}
|
272 |
+
//open htaccess file
|
273 |
+
$htaccessContent = file_get_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess');
|
274 |
+
if (empty($htaccessContent)) {
|
275 |
+
return FALSE;
|
276 |
+
}
|
277 |
+
//if isset Gzip access
|
278 |
+
if (strpos($htaccessContent, 'mod_deflate') !== false || strpos($htaccessContent, 'AddOutputFilterByType') !== false || strpos($htaccessContent, 'AddType') !== false || strpos($htaccessContent,'GzipofBreezeWPCache') !== false) {
|
279 |
+
return FALSE;
|
280 |
+
}
|
281 |
+
|
282 |
+
$htaccessContent = $data.$htaccessContent;
|
283 |
+
file_put_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess', $htaccessContent);
|
284 |
+
return TRUE;
|
285 |
+
|
286 |
+
} else {
|
287 |
+
if (!is_super_admin()) {
|
288 |
+
return FALSE;
|
289 |
+
}
|
290 |
+
//open htaccess file
|
291 |
+
$htaccessContent = file_get_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess');
|
292 |
+
if (empty($htaccessContent)) {
|
293 |
+
return FALSE;
|
294 |
+
}
|
295 |
+
|
296 |
+
$htaccessContent = str_replace($data,'',$htaccessContent);
|
297 |
+
file_put_contents(ABSPATH . DIRECTORY_SEPARATOR . '.htaccess', $htaccessContent);
|
298 |
+
return TRUE;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
/*
|
302 |
+
* Database clean tab
|
303 |
+
* funtion to clean in database
|
304 |
+
*/
|
305 |
+
public static function cleanSystem($type){
|
306 |
+
global $wpdb;
|
307 |
+
$clean = "";
|
308 |
+
|
309 |
+
switch ($type){
|
310 |
+
case "revisions":
|
311 |
+
$clean = "DELETE FROM `$wpdb->posts` WHERE post_type = 'revision';";
|
312 |
+
$revisions = $wpdb->query( $clean );
|
313 |
+
|
314 |
+
$message = "All post revisions";
|
315 |
+
break;
|
316 |
+
case "drafted":
|
317 |
+
$clean = "DELETE FROM `$wpdb->posts` WHERE post_status = 'auto-draft';";
|
318 |
+
$autodraft = $wpdb->query( $clean );
|
319 |
+
|
320 |
+
$message = "All auto drafted content";
|
321 |
+
break;
|
322 |
+
case "trash":
|
323 |
+
$clean = "DELETE FROM `$wpdb->posts` WHERE post_status = 'trash';";
|
324 |
+
$posttrash = $wpdb->query( $clean );
|
325 |
+
|
326 |
+
$message = "All trashed content";
|
327 |
+
break;
|
328 |
+
case "comments":
|
329 |
+
$clean = "DELETE FROM `$wpdb->comments` WHERE comment_approved = 'spam' OR comment_approved = 'trash' ;";
|
330 |
+
$comments = $wpdb->query( $clean );
|
331 |
+
|
332 |
+
$message = "Comments from trash & spam";
|
333 |
+
break;
|
334 |
+
case "trackbacks":
|
335 |
+
$clean = "DELETE FROM `$wpdb->comments` WHERE comment_type = 'trackback' OR comment_type = 'pingback' ;";
|
336 |
+
$comments = $wpdb->query( $clean );
|
337 |
+
|
338 |
+
$message = "Trackbacks and pingbacks";
|
339 |
+
break;
|
340 |
+
case "transient":
|
341 |
+
$clean = "DELETE FROM `$wpdb->options` WHERE option_name LIKE '%\_transient\_%' ;";
|
342 |
+
$comments = $wpdb->query( $clean );
|
343 |
+
|
344 |
+
$message = "Transient options";
|
345 |
+
break;
|
346 |
+
}
|
347 |
+
|
348 |
+
return true;
|
349 |
+
}
|
350 |
+
|
351 |
+
/*
|
352 |
+
* Database clean tab
|
353 |
+
* funtion to get number of element to clean in database
|
354 |
+
*/
|
355 |
+
public static function getElementToClean($type){
|
356 |
+
global $wpdb;
|
357 |
+
$return = 0;
|
358 |
+
switch ($type){
|
359 |
+
case "revisions":
|
360 |
+
$element = "SELECT ID FROM `$wpdb->posts` WHERE post_type = 'revision';";
|
361 |
+
$return = $wpdb->query( $element );
|
362 |
+
break;
|
363 |
+
case "drafted":
|
364 |
+
$element = "SELECT ID FROM `$wpdb->posts` WHERE post_status = 'auto-draft';";
|
365 |
+
$return = $wpdb->query( $element );
|
366 |
+
break;
|
367 |
+
case "trash":
|
368 |
+
$element = "SELECT ID FROM `$wpdb->posts` WHERE post_status = 'trash';";
|
369 |
+
$return = $wpdb->query( $element );
|
370 |
+
break;
|
371 |
+
case "comments":
|
372 |
+
$element = "SELECT comment_ID FROM `$wpdb->comments` WHERE comment_approved = 'spam' OR comment_approved = 'trash' ;";
|
373 |
+
$return = $wpdb->query( $element );
|
374 |
+
break;
|
375 |
+
case "trackbacks":
|
376 |
+
$element = "SELECT comment_ID FROM `$wpdb->comments` WHERE comment_type = 'trackback' OR comment_type = 'pingback' ;";
|
377 |
+
$return = $wpdb->query( $element );
|
378 |
+
break;
|
379 |
+
case "transient":
|
380 |
+
$element = "SELECT option_id FROM `$wpdb->options` WHERE option_name LIKE '%\_transient\_%' ;";
|
381 |
+
$return = $wpdb->query( $element );
|
382 |
+
break;
|
383 |
+
}
|
384 |
+
return $return;
|
385 |
+
}
|
386 |
+
|
387 |
+
// Convert string to array
|
388 |
+
protected function string_convert_arr($input){
|
389 |
+
$output = array();
|
390 |
+
if(!empty($input)){
|
391 |
+
$input = rawurldecode($input);
|
392 |
+
$input = trim($input);
|
393 |
+
$input = str_replace(' ', '', $input);
|
394 |
+
$input = explode("\n",$input);
|
395 |
+
|
396 |
+
foreach ($input as $k => $v){
|
397 |
+
$output[] = trim($v);
|
398 |
+
}
|
399 |
+
}
|
400 |
+
return $output;
|
401 |
+
}
|
402 |
+
//ajax clean cache
|
403 |
+
public static function ajax_clean_cache($check = false) {
|
404 |
+
$size_cache = 0;
|
405 |
+
$size_css_cache = 0;
|
406 |
+
$size_js_cache = 0;
|
407 |
+
$result = 0;
|
408 |
+
// analysis size cache
|
409 |
+
$cachepath = rtrim(WP_CONTENT_DIR, '/') . '/cache/breeze';
|
410 |
+
|
411 |
+
if (is_dir($cachepath))
|
412 |
+
$cachedirs = scandir($cachepath);
|
413 |
+
if (!empty($cachedirs)) {
|
414 |
+
foreach ($cachedirs as $cachedir) {
|
415 |
+
if ($cachedir != '.' && $cachedir != '..') {
|
416 |
+
$filepath = $cachepath . '/' . $cachedir;
|
417 |
+
if(is_dir($filepath))
|
418 |
+
$filedirs = scandir($filepath);
|
419 |
+
foreach($filedirs as $filedir){
|
420 |
+
if ($filedir != '.' && $filedir != '..') {
|
421 |
+
if (@file_exists($filepath)) {
|
422 |
+
$dir_path = $filepath.'/'.$filedir;
|
423 |
+
$size_cache += filesize($dir_path);
|
424 |
+
}
|
425 |
+
}
|
426 |
+
}
|
427 |
+
|
428 |
+
}
|
429 |
+
}
|
430 |
+
}
|
431 |
+
|
432 |
+
// analysis size css cache
|
433 |
+
if(is_multisite()){
|
434 |
+
$blog_id = get_current_blog_id();
|
435 |
+
$css_path = rtrim(WP_CONTENT_DIR, '/') . '/cache/breeze-minification/'.$blog_id.'/css';
|
436 |
+
}else{
|
437 |
+
$css_path = rtrim(WP_CONTENT_DIR, '/') . '/cache/breeze-minification/css';
|
438 |
+
}
|
439 |
+
if (is_dir($css_path))
|
440 |
+
$file_in_css = scandir($css_path);
|
441 |
+
if (!empty($file_in_css)) {
|
442 |
+
foreach ($file_in_css as $v) {
|
443 |
+
if ($v != '.' && $v != '..' && $v != 'index.html') {
|
444 |
+
$path = $css_path . '/' . $v;
|
445 |
+
$size_css_cache += filesize($path);
|
446 |
+
}
|
447 |
+
}
|
448 |
+
}
|
449 |
+
|
450 |
+
// analysis size js cache
|
451 |
+
if(is_multisite()){
|
452 |
+
$blog_id = get_current_blog_id();
|
453 |
+
$js_path = rtrim(WP_CONTENT_DIR, '/') . '/cache/breeze-minification/'.$blog_id.'/js';
|
454 |
+
}else{
|
455 |
+
$js_path = rtrim(WP_CONTENT_DIR, '/') . '/cache/breeze-minification/js';
|
456 |
+
}
|
457 |
+
if (is_dir($js_path))
|
458 |
+
;
|
459 |
+
$file_in_js = scandir($js_path);
|
460 |
+
if (!empty($file_in_js)) {
|
461 |
+
foreach ($file_in_js as $v) {
|
462 |
+
if ($v != '.' && $v != '..' && $v != 'index.html') {
|
463 |
+
$path = $js_path . '/' . $v;
|
464 |
+
$size_js_cache += filesize($path);
|
465 |
+
}
|
466 |
+
}
|
467 |
+
}
|
468 |
+
|
469 |
+
$total_size_cache = $size_cache + $size_css_cache + $size_js_cache;
|
470 |
+
|
471 |
+
$result = self::formatBytes($total_size_cache);
|
472 |
+
|
473 |
+
//delete minify file
|
474 |
+
Breeze_MinificationCache::clear_minification();
|
475 |
+
//delete all cache
|
476 |
+
Breeze_PurgeCache::breeze_cache_flush();
|
477 |
+
|
478 |
+
if($check){
|
479 |
+
return $result;
|
480 |
+
}
|
481 |
+
|
482 |
+
echo json_encode($result);
|
483 |
+
exit;
|
484 |
+
}
|
485 |
+
|
486 |
+
public static function purge_varnish_action(){
|
487 |
+
$homepage = home_url().'/?breeze';
|
488 |
+
$main = new Breeze_PurgeVarnish();
|
489 |
+
$main->purge_cache($homepage);
|
490 |
+
|
491 |
+
echo json_encode(array('clear' => true));
|
492 |
+
exit;
|
493 |
+
}
|
494 |
+
|
495 |
+
public static function ajax_purge_database(){
|
496 |
+
$type = array('revisions','drafted','trash','comments','trackbacks','transient');
|
497 |
+
foreach ($type as $item){
|
498 |
+
self::cleanSystem($item);
|
499 |
+
}
|
500 |
+
|
501 |
+
echo json_encode(array('clear' => true));
|
502 |
+
exit;
|
503 |
+
}
|
504 |
+
public static function formatBytes($bytes, $precision = 2) {
|
505 |
+
if ($bytes >= 1073741824) {
|
506 |
+
$bytes = number_format($bytes / 1073741824, 2);
|
507 |
+
} elseif ($bytes >= 1048576) {
|
508 |
+
$bytes = number_format($bytes / 1048576, 2);
|
509 |
+
} elseif ($bytes >= 1024) {
|
510 |
+
$bytes = number_format($bytes / 1024, 2);
|
511 |
+
} elseif ($bytes > 1) {
|
512 |
+
$bytes = $bytes;
|
513 |
+
} elseif ($bytes == 1) {
|
514 |
+
$bytes = $bytes;
|
515 |
+
} else {
|
516 |
+
$bytes = '0';
|
517 |
+
}
|
518 |
+
|
519 |
+
return $bytes;
|
520 |
+
}
|
521 |
+
|
522 |
+
/*
|
523 |
+
* Clear varnish after settings
|
524 |
+
*/
|
525 |
+
|
526 |
+
public function clear_varnish(){
|
527 |
+
// Clear varnish cache after settings
|
528 |
+
$varnish = get_option('breeze_varnish_cache');
|
529 |
+
if(!empty($varnish['auto-purge-varnish'])){
|
530 |
+
$homepage = home_url().'/?breeze';
|
531 |
+
$main = new Breeze_PurgeVarnish();
|
532 |
+
$main->purge_cache($homepage);
|
533 |
+
}
|
534 |
+
|
535 |
+
return true;
|
536 |
+
}
|
537 |
+
|
538 |
+
}
|
539 |
+
|
540 |
+
//init configuration object
|
541 |
+
new Breeze_Configuration();
|
inc/cache/Mobile-Detect-2.8.25/LICENSE.txt
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
MIT License
|
2 |
+
|
3 |
+
Copyright (c) <2011-2015> Serban Ghita, Nick Ilyin and contributors.
|
4 |
+
|
5 |
+
Permission is hereby granted, free of charge, to any person obtaining
|
6 |
+
a copy of this software and associated documentation files (the
|
7 |
+
"Software"), to deal in the Software without restriction, including
|
8 |
+
without limitation the rights to use, copy, modify, merge, publish,
|
9 |
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10 |
+
permit persons to whom the Software is furnished to do so, subject to
|
11 |
+
the following conditions:
|
12 |
+
|
13 |
+
The above copyright notice and this permission notice shall be included
|
14 |
+
in all copies or substantial portions of the Software.
|
15 |
+
|
16 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
17 |
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18 |
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19 |
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20 |
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21 |
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22 |
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23 |
+
|
24 |
+
Developer’s Certificate of Origin 1.1
|
25 |
+
|
26 |
+
By making a contribution to this project, I certify that:
|
27 |
+
|
28 |
+
(a) The contribution was created in whole or in part by me and I
|
29 |
+
have the right to submit it under the open source license
|
30 |
+
indicated in the file; or
|
31 |
+
|
32 |
+
(b) The contribution is based upon previous work that, to the best
|
33 |
+
of my knowledge, is covered under an appropriate open source
|
34 |
+
license and I have the right under that license to submit that
|
35 |
+
work with modifications, whether created in whole or in part
|
36 |
+
by me, under the same open source license (unless I am
|
37 |
+
permitted to submit under a different license), as indicated
|
38 |
+
in the file; or
|
39 |
+
|
40 |
+
(c) The contribution was provided directly to me by some other
|
41 |
+
person who certified (a), (b) or (c) and I have not modified
|
42 |
+
it.
|
43 |
+
|
44 |
+
(d) I understand and agree that this project and the contribution
|
45 |
+
are public and that a record of the contribution (including all
|
46 |
+
personal information I submit with it, including my sign-off) is
|
47 |
+
maintained indefinitely and may be redistributed consistent with
|
48 |
+
this project or the open source license(s) involved.
|
inc/cache/Mobile-Detect-2.8.25/Mobile_Detect.json
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
{"version":"2.8.25","headerMatch":{"HTTP_ACCEPT":{"matches":["application\/x-obml2d","application\/vnd.rim.html","text\/vnd.wap.wml","application\/vnd.wap.xhtml+xml"]},"HTTP_X_WAP_PROFILE":null,"HTTP_X_WAP_CLIENTID":null,"HTTP_WAP_CONNECTION":null,"HTTP_PROFILE":null,"HTTP_X_OPERAMINI_PHONE_UA":null,"HTTP_X_NOKIA_GATEWAY_ID":null,"HTTP_X_ORANGE_ID":null,"HTTP_X_VODAFONE_3GPDPCONTEXT":null,"HTTP_X_HUAWEI_USERID":null,"HTTP_UA_OS":null,"HTTP_X_MOBILE_GATEWAY":null,"HTTP_X_ATT_DEVICEID":null,"HTTP_UA_CPU":{"matches":["ARM"]}},"uaHttpHeaders":["HTTP_USER_AGENT","HTTP_X_OPERAMINI_PHONE_UA","HTTP_X_DEVICE_USER_AGENT","HTTP_X_ORIGINAL_USER_AGENT","HTTP_X_SKYFIRE_PHONE","HTTP_X_BOLT_PHONE_UA","HTTP_DEVICE_STOCK_UA","HTTP_X_UCBROWSER_DEVICE_UA"],"uaMatch":{"phones":{"iPhone":"\\biPhone\\b|\\biPod\\b","BlackBerry":"BlackBerry|\\bBB10\\b|rim[0-9]+","HTC":"HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\\bEVO\\b|T-Mobile G1|Z520m","Nexus":"Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6","Dell":"Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\\b001DL\\b|\\b101DL\\b|\\bGS01\\b","Motorola":"Motorola|DROIDX|DROID BIONIC|\\bDroid\\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\\bMoto E\\b","Samsung":"\\bSamsung\\b|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C","LG":"\\bLG\\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)","Sony":"SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533","Asus":"Asus.*Galaxy|PadFone.*Mobile","NokiaLumia":"Lumia [0-9]{3,4}","Micromax":"Micromax.*\\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\\b","Palm":"PalmSource|Palm","Vertu":"Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature","Pantech":"PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790","Fly":"IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250","Wiko":"KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM","iMobile":"i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)","SimValley":"\\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\\b","Wolfgang":"AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q","Alcatel":"Alcatel","Nintendo":"Nintendo 3DS","Amoi":"Amoi","INQ":"INQ","GenericPhone":"Tapatalk|PDA;|SAGEM|\\bmmp\\b|pocket|\\bpsp\\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\\bwap\\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser"},"tablets":{"iPad":"iPad|iPad.*Mobile","NexusTablet":"Android.*Nexus[\\s]+(7|9|10)","SamsungTablet":"SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587","Kindle":"Kindle|Silk.*Accelerated|Android.*\\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\\b|Android.*Silk\/[0-9.]+ like Chrome\/[0-9.]+ (?!Mobile)","SurfaceTablet":"Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)","HPTablet":"HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10","AsusTablet":"^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\\bK00F\\b|\\bK00C\\b|\\bK00E\\b|\\bK00L\\b|TX201LA|ME176C|ME102A|\\bM80TA\\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\\bME70C\\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z","BlackBerryTablet":"PlayBook|RIM Tablet","HTCtablet":"HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410","MotorolaTablet":"xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617","NookTablet":"Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2","AcerTablet":"Android.*; \\b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\\b|W3-810|\\bA3-A10\\b|\\bA3-A11\\b|\\bA3-A20\\b|\\bA3-A30","ToshibaTablet":"Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO","LGTablet":"\\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\\b","FujitsuTablet":"Android.*\\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\\b","PrestigioTablet":"PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002","LenovoTablet":"Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)","DellTablet":"Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7","YarvikTablet":"Android.*\\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\\b","MedionTablet":"Android.*\\bOYO\\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB","ArnovaTablet":"97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2","IntensoTablet":"INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004","IRUTablet":"M702pro","MegafonTablet":"MegaFon V9|\\bZTE V9\\b|Android.*\\bMT7A\\b","EbodaTablet":"E-Boda (Supreme|Impresspeed|Izzycomm|Essential)","AllViewTablet":"Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)","ArchosTablet":"\\b(101G9|80G9|A101IT)\\b|Qilive 97R|Archos5|\\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\\b","AinolTablet":"NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark","NokiaLumiaTablet":"Lumia 2520","SonyTablet":"Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31","PhilipsTablet":"\\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\\b","CubeTablet":"Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT","CobyTablet":"MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010","MIDTablet":"M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10","MSITablet":"MSI \\b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\\b","SMiTTablet":"Android.*(\\bMID\\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)","RockChipTablet":"Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A","FlyTablet":"IQ310|Fly Vision","bqTablet":"Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris [E|M]10)|Maxwell.*Lite|Maxwell.*Plus","HuaweiTablet":"MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim","NecTablet":"\\bN-06D|\\bN-08D","PantechTablet":"Pantech.*P4100","BronchoTablet":"Broncho.*(N701|N708|N802|a710)","VersusTablet":"TOUCHPAD.*[78910]|\\bTOUCHTAB\\b","ZyncTablet":"z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900","PositivoTablet":"TB07STA|TB10STA|TB07FTA|TB10FTA","NabiTablet":"Android.*\\bNabi","KoboTablet":"Kobo Touch|\\bK080\\b|\\bVox\\b Build|\\bArc\\b Build","DanewTablet":"DSlide.*\\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\\b","TexetTablet":"NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE","PlaystationTablet":"Playstation.*(Portable|Vita)","TrekstorTablet":"ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab","PyleAudioTablet":"\\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\\b","AdvanTablet":"Android.* \\b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\\b ","DanyTechTablet":"Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1","GalapadTablet":"Android.*\\bG1\\b","MicromaxTablet":"Funbook|Micromax.*\\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\\b","KarbonnTablet":"Android.*\\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\\b","AllFineTablet":"Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide","PROSCANTablet":"\\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\\b","YONESTablet":"BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026","ChangJiaTablet":"TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503","GUTablet":"TX-A1301|TX-M9002|Q702|kf026","PointOfViewTablet":"TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10","OvermaxTablet":"OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)","HCLTablet":"HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync","DPSTablet":"DPS Dream 9|DPS Dual 7","VistureTablet":"V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10","CrestaTablet":"CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989","MediatekTablet":"\\bMT8125|MT8389|MT8135|MT8377\\b","ConcordeTablet":"Concorde([ ]+)?Tab|ConCorde ReadMan","GoCleverTablet":"GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042","ModecomTablet":"FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003","VoninoTablet":"\\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\\bQ8\\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\\b","ECSTablet":"V07OT2|TM105A|S10OT1|TR10CS1","StorexTablet":"eZee[_']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab","VodafoneTablet":"SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497","EssentielBTablet":"Smart[ ']?TAB[ ]+?[0-9]+|Family[ ']?TAB2","RossMoorTablet":"RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711","iMobileTablet":"i-mobile i-note","TolinoTablet":"tolino tab [0-9.]+|tolino shine","AudioSonicTablet":"\\bC-22Q|T7-QC|T-17B|T-17P\\b","AMPETablet":"Android.* A78 ","SkkTablet":"Android.* (SKYPAD|PHOENIX|CYCLOPS)","TecnoTablet":"TECNO P9","JXDTablet":"Android.* \\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\\b","iJoyTablet":"Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)","FX2Tablet":"FX2 PAD7|FX2 PAD10","XoroTablet":"KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151","ViewsonicTablet":"ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a","OdysTablet":"LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\\bXELIO\\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10","CaptivaTablet":"CAPTIVA PAD","IconbitTablet":"NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S","TeclastTablet":"T98 4G|\\bP80\\b|\\bX90HD\\b|X98 Air|X98 Air 3G|\\bX89\\b|P80 3G|\\bX80h\\b|P98 Air|\\bX89HD\\b|P98 3G|\\bP90HD\\b|P89 3G|X98 3G|\\bP70h\\b|P79HD 3G|G18d 3G|\\bP79HD\\b|\\bP89s\\b|\\bA88\\b|\\bP10HD\\b|\\bP19HD\\b|G18 3G|\\bP78HD\\b|\\bA78\\b|\\bP75\\b|G17s 3G|G17h 3G|\\bP85t\\b|\\bP90\\b|\\bP11\\b|\\bP98t\\b|\\bP98HD\\b|\\bG18d\\b|\\bP85s\\b|\\bP11HD\\b|\\bP88s\\b|\\bA80HD\\b|\\bA80se\\b|\\bA10h\\b|\\bP89\\b|\\bP78s\\b|\\bG18\\b|\\bP85\\b|\\bA70h\\b|\\bA70\\b|\\bG17\\b|\\bP18\\b|\\bA80s\\b|\\bA11s\\b|\\bP88HD\\b|\\bA80h\\b|\\bP76s\\b|\\bP76h\\b|\\bP98\\b|\\bA10HD\\b|\\bP78\\b|\\bP88\\b|\\bA11\\b|\\bA10t\\b|\\bP76a\\b|\\bP76t\\b|\\bP76e\\b|\\bP85HD\\b|\\bP85a\\b|\\bP86\\b|\\bP75HD\\b|\\bP76v\\b|\\bA12\\b|\\bP75a\\b|\\bA15\\b|\\bP76Ti\\b|\\bP81HD\\b|\\bA10\\b|\\bT760VE\\b|\\bT720HD\\b|\\bP76\\b|\\bP73\\b|\\bP71\\b|\\bP72\\b|\\bT720SE\\b|\\bC520Ti\\b|\\bT760\\b|\\bT720VE\\b|T720-3GE|T720-WiFi","OndaTablet":"\\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\\b[\\s]+","JaytechTablet":"TPC-PA762","BlaupunktTablet":"Endeavour 800NG|Endeavour 1010","DigmaTablet":"\\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\\b","EvolioTablet":"ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\\bEvotab\\b|\\bNeura\\b","LavaTablet":"QPAD E704|\\bIvoryS\\b|E-TAB IVORY|\\bE-TAB\\b","AocTablet":"MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712","MpmanTablet":"MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\\bMPG7\\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010","CelkonTablet":"CT695|CT888|CT[\\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\\bCT-1\\b","WolderTablet":"miTab \\b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\\b","MiTablet":"\\bMI PAD\\b|\\bHM NOTE 1W\\b","NibiruTablet":"Nibiru M1|Nibiru Jupiter One","NexoTablet":"NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI","LeaderTablet":"TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100","UbislateTablet":"UbiSlate[\\s]?7C","PocketBookTablet":"Pocketbook","KocasoTablet":"\\b(TB-1207)\\b","HisenseTablet":"\\b(F5281|E2371)\\b","Hudl":"Hudl HT7S3|Hudl 2","TelstraTablet":"T-Hub2","GenericTablet":"Android.*\\b97D\\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\\bA7EB\\b|CatNova8|A1_07|CT704|CT1002|\\bM721\\b|rk30sdk|\\bEVOTAB\\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\\bM6pro\\b|CT1020W|arc 10HD|\\bTP750\\b"},"browsers":{"Chrome":"\\bCrMo\\b|CriOS|Android.*Chrome\/[.0-9]* (Mobile)?","Dolfin":"\\bDolfin\\b","Opera":"Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR\/[0-9.]+|Coast\/[0-9.]+","Skyfire":"Skyfire","Edge":"Mobile Safari\/[.0-9]* Edge","IE":"IEMobile|MSIEMobile","Firefox":"fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS","Bolt":"bolt","TeaShark":"teashark","Blazer":"Blazer","Safari":"Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari","UCBrowser":"UC.*Browser|UCWEB","baiduboxapp":"baiduboxapp","baidubrowser":"baidubrowser","DiigoBrowser":"DiigoBrowser","Puffin":"Puffin","Mercury":"\\bMercury\\b","ObigoBrowser":"Obigo","NetFront":"NF-Browser","GenericBrowser":"NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger","PaleMoon":"Android.*PaleMoon|Mobile.*PaleMoon"},"os":{"AndroidOS":"Android","BlackBerryOS":"blackberry|\\bBB10\\b|rim tablet os","PalmOS":"PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino","SymbianOS":"Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\\bS60\\b","WindowsMobileOS":"Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;","WindowsPhoneOS":"Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;","iOS":"\\biPhone.*Mobile|\\biPod|\\biPad","MeeGoOS":"MeeGo","MaemoOS":"Maemo","JavaOS":"J2ME\/|\\bMIDP\\b|\\bCLDC\\b","webOS":"webOS|hpwOS","badaOS":"\\bBada\\b","BREWOS":"BREW"},"utilities":{"Bot":"Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom","MobileBot":"Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker\/M1A1-R2D2","DesktopMode":"WPDesktop","TV":"SonyDTV|HbbTV","WebKit":"(webkit)[ \/]([\\w.]+)","Console":"\\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\\b","Watch":"SM-V700"}}}
|
inc/cache/Mobile-Detect-2.8.25/Mobile_Detect.php
ADDED
@@ -0,0 +1,1460 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
namespace Cloudways\Breeze\Mobile_Detect;
|
3 |
+
/**
|
4 |
+
* Mobile Detect Library
|
5 |
+
* =====================
|
6 |
+
*
|
7 |
+
* Motto: "Every business should have a mobile detection script to detect mobile readers"
|
8 |
+
*
|
9 |
+
* Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
|
10 |
+
* It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.
|
11 |
+
*
|
12 |
+
* @author Current authors: Serban Ghita <serbanghita@gmail.com>
|
13 |
+
* Nick Ilyin <nick.ilyin@gmail.com>
|
14 |
+
*
|
15 |
+
* Original author: Victor Stanciu <vic.stanciu@gmail.com>
|
16 |
+
*
|
17 |
+
* @license Code and contributions have 'MIT License'
|
18 |
+
* More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
|
19 |
+
*
|
20 |
+
* @link Homepage: http://mobiledetect.net
|
21 |
+
* GitHub Repo: https://github.com/serbanghita/Mobile-Detect
|
22 |
+
* Google Code: http://code.google.com/p/php-mobile-detect/
|
23 |
+
* README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md
|
24 |
+
* HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples
|
25 |
+
*
|
26 |
+
* @version 2.8.25
|
27 |
+
*/
|
28 |
+
|
29 |
+
class Mobile_Detect
|
30 |
+
{
|
31 |
+
/**
|
32 |
+
* Mobile detection type.
|
33 |
+
*
|
34 |
+
* @deprecated since version 2.6.9
|
35 |
+
*/
|
36 |
+
const DETECTION_TYPE_MOBILE = 'mobile';
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Extended detection type.
|
40 |
+
*
|
41 |
+
* @deprecated since version 2.6.9
|
42 |
+
*/
|
43 |
+
const DETECTION_TYPE_EXTENDED = 'extended';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* A frequently used regular expression to extract version #s.
|
47 |
+
*
|
48 |
+
* @deprecated since version 2.6.9
|
49 |
+
*/
|
50 |
+
const VER = '([\w._\+]+)';
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Top-level device.
|
54 |
+
*/
|
55 |
+
const MOBILE_GRADE_A = 'A';
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Mid-level device.
|
59 |
+
*/
|
60 |
+
const MOBILE_GRADE_B = 'B';
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Low-level device.
|
64 |
+
*/
|
65 |
+
const MOBILE_GRADE_C = 'C';
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Stores the version number of the current release.
|
69 |
+
*/
|
70 |
+
const VERSION = '2.8.25';
|
71 |
+
|
72 |
+
/**
|
73 |
+
* A type for the version() method indicating a string return value.
|
74 |
+
*/
|
75 |
+
const VERSION_TYPE_STRING = 'text';
|
76 |
+
|
77 |
+
/**
|
78 |
+
* A type for the version() method indicating a float return value.
|
79 |
+
*/
|
80 |
+
const VERSION_TYPE_FLOAT = 'float';
|
81 |
+
|
82 |
+
/**
|
83 |
+
* A cache for resolved matches
|
84 |
+
* @var array
|
85 |
+
*/
|
86 |
+
protected $cache = array();
|
87 |
+
|
88 |
+
/**
|
89 |
+
* The User-Agent HTTP header is stored in here.
|
90 |
+
* @var string
|
91 |
+
*/
|
92 |
+
protected $userAgent = null;
|
93 |
+
|
94 |
+
/**
|
95 |
+
* HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE.
|
96 |
+
* @var array
|
97 |
+
*/
|
98 |
+
protected $httpHeaders = array();
|
99 |
+
|
100 |
+
/**
|
101 |
+
* CloudFront headers. E.g. CloudFront-Is-Desktop-Viewer, CloudFront-Is-Mobile-Viewer & CloudFront-Is-Tablet-Viewer.
|
102 |
+
* @var array
|
103 |
+
*/
|
104 |
+
protected $cloudfrontHeaders = array();
|
105 |
+
|
106 |
+
/**
|
107 |
+
* The matching Regex.
|
108 |
+
* This is good for debug.
|
109 |
+
* @var string
|
110 |
+
*/
|
111 |
+
protected $matchingRegex = null;
|
112 |
+
|
113 |
+
/**
|
114 |
+
* The matches extracted from the regex expression.
|
115 |
+
* This is good for debug.
|
116 |
+
* @var string
|
117 |
+
*/
|
118 |
+
protected $matchesArray = null;
|
119 |
+
|
120 |
+
/**
|
121 |
+
* The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED.
|
122 |
+
*
|
123 |
+
* @deprecated since version 2.6.9
|
124 |
+
*
|
125 |
+
* @var string
|
126 |
+
*/
|
127 |
+
protected $detectionType = self::DETECTION_TYPE_MOBILE;
|
128 |
+
|
129 |
+
/**
|
130 |
+
* HTTP headers that trigger the 'isMobile' detection
|
131 |
+
* to be true.
|
132 |
+
*
|
133 |
+
* @var array
|
134 |
+
*/
|
135 |
+
protected static $mobileHeaders = array(
|
136 |
+
|
137 |
+
'HTTP_ACCEPT' => array('matches' => array(
|
138 |
+
// Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/
|
139 |
+
'application/x-obml2d',
|
140 |
+
// BlackBerry devices.
|
141 |
+
'application/vnd.rim.html',
|
142 |
+
'text/vnd.wap.wml',
|
143 |
+
'application/vnd.wap.xhtml+xml'
|
144 |
+
)),
|
145 |
+
'HTTP_X_WAP_PROFILE' => null,
|
146 |
+
'HTTP_X_WAP_CLIENTID' => null,
|
147 |
+
'HTTP_WAP_CONNECTION' => null,
|
148 |
+
'HTTP_PROFILE' => null,
|
149 |
+
// Reported by Opera on Nokia devices (eg. C3).
|
150 |
+
'HTTP_X_OPERAMINI_PHONE_UA' => null,
|
151 |
+
'HTTP_X_NOKIA_GATEWAY_ID' => null,
|
152 |
+
'HTTP_X_ORANGE_ID' => null,
|
153 |
+
'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
|
154 |
+
'HTTP_X_HUAWEI_USERID' => null,
|
155 |
+
// Reported by Windows Smartphones.
|
156 |
+
'HTTP_UA_OS' => null,
|
157 |
+
// Reported by Verizon, Vodafone proxy system.
|
158 |
+
'HTTP_X_MOBILE_GATEWAY' => null,
|
159 |
+
// Seen this on HTC Sensation. SensationXE_Beats_Z715e.
|
160 |
+
'HTTP_X_ATT_DEVICEID' => null,
|
161 |
+
// Seen this on a HTC.
|
162 |
+
'HTTP_UA_CPU' => array('matches' => array('ARM')),
|
163 |
+
);
|
164 |
+
|
165 |
+
/**
|
166 |
+
* List of mobile devices (phones).
|
167 |
+
*
|
168 |
+
* @var array
|
169 |
+
*/
|
170 |
+
protected static $phoneDevices = array(
|
171 |
+
'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes
|
172 |
+
'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+',
|
173 |
+
'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m',
|
174 |
+
'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6',
|
175 |
+
// @todo: Is 'Dell Streak' a tablet or a phone? ;)
|
176 |
+
'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b',
|
177 |
+
'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925|XT1021|\bMoto E\b',
|
178 |
+
'Samsung' => '\bSamsung\b|SM-G9250|GT-19300|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750|SM-G9006V|SM-G9008V|SM-G9009D|SM-G900A|SM-G900D|SM-G900F|SM-G900H|SM-G900I|SM-G900J|SM-G900K|SM-G900L|SM-G900M|SM-G900P|SM-G900R4|SM-G900S|SM-G900T|SM-G900V|SM-G900W8|SHV-E160K|SCH-P709|SCH-P729|SM-T2558|GT-I9205|SM-G9350|SM-J120F|SM-G920F|SM-G920V|SM-G930F|SM-N910C',
|
179 |
+
'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802|MS323)',
|
180 |
+
'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533',
|
181 |
+
'Asus' => 'Asus.*Galaxy|PadFone.*Mobile',
|
182 |
+
'NokiaLumia' => 'Lumia [0-9]{3,4}',
|
183 |
+
// http://www.micromaxinfo.com/mobiles/smartphones
|
184 |
+
// Added because the codes might conflict with Acer Tablets.
|
185 |
+
'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b',
|
186 |
+
// @todo Complete the regex.
|
187 |
+
'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ;
|
188 |
+
'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;)
|
189 |
+
// http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH)
|
190 |
+
// Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android.
|
191 |
+
'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790',
|
192 |
+
// http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones.
|
193 |
+
'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250',
|
194 |
+
// http://fr.wikomobile.com
|
195 |
+
'Wiko' => 'KITE 4G|HIGHWAY|GETAWAY|STAIRWAY|DARKSIDE|DARKFULL|DARKNIGHT|DARKMOON|SLIDE|WAX 4G|RAINBOW|BLOOM|SUNSET|GOA(?!nna)|LENNY|BARRY|IGGY|OZZY|CINK FIVE|CINK PEAX|CINK PEAX 2|CINK SLIM|CINK SLIM 2|CINK +|CINK KING|CINK PEAX|CINK SLIM|SUBLIM',
|
196 |
+
'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)',
|
197 |
+
// Added simvalley mobile just for fun. They have some interesting devices.
|
198 |
+
// http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html
|
199 |
+
'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b',
|
200 |
+
// Wolfgang - a brand that is sold by Aldi supermarkets.
|
201 |
+
// http://www.wolfgangmobile.com/
|
202 |
+
'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q',
|
203 |
+
'Alcatel' => 'Alcatel',
|
204 |
+
'Nintendo' => 'Nintendo 3DS',
|
205 |
+
// http://en.wikipedia.org/wiki/Amoi
|
206 |
+
'Amoi' => 'Amoi',
|
207 |
+
// http://en.wikipedia.org/wiki/INQ
|
208 |
+
'INQ' => 'INQ',
|
209 |
+
// @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039
|
210 |
+
'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser',
|
211 |
+
);
|
212 |
+
|
213 |
+
/**
|
214 |
+
* List of tablet devices.
|
215 |
+
*
|
216 |
+
* @var array
|
217 |
+
*/
|
218 |
+
protected static $tabletDevices = array(
|
219 |
+
// @todo: check for mobile friendly emails topic.
|
220 |
+
'iPad' => 'iPad|iPad.*Mobile',
|
221 |
+
// Removed |^.*Android.*Nexus(?!(?:Mobile).)*$
|
222 |
+
// @see #442
|
223 |
+
'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
|
224 |
+
'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587', // SCH-P709|SCH-P729|SM-T2558|GT-I9205 - Samsung Mega - treat them like a regular phone.
|
225 |
+
// http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html
|
226 |
+
'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)',
|
227 |
+
// Only the Surface tablets with Windows RT are considered mobile.
|
228 |
+
// http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx
|
229 |
+
'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
|
230 |
+
// http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT
|
231 |
+
'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
|
232 |
+
// Watch out for PadFone, see #132.
|
233 |
+
// http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/
|
234 |
+
'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z',
|
235 |
+
'BlackBerryTablet' => 'PlayBook|RIM Tablet',
|
236 |
+
'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
|
237 |
+
'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
|
238 |
+
'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
|
239 |
+
// http://www.acer.ro/ac/ro/RO/content/drivers
|
240 |
+
// http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer)
|
241 |
+
// http://us.acer.com/ac/en/US/content/group/tablets
|
242 |
+
// http://www.acer.de/ac/de/DE/content/models/tablets/
|
243 |
+
// Can conflict with Micromax and Motorola phones codes.
|
244 |
+
'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30',
|
245 |
+
// http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/
|
246 |
+
// http://us.toshiba.com/tablets/tablet-finder
|
247 |
+
// http://www.toshiba.co.jp/regza/tablet/
|
248 |
+
'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
|
249 |
+
// http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html
|
250 |
+
// http://www.lg.com/us/tablets
|
251 |
+
'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
|
252 |
+
'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
|
253 |
+
// Prestigio Tablets http://www.prestigio.com/support
|
254 |
+
'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
|
255 |
+
// http://support.lenovo.com/en_GB/downloads/default.page?#
|
256 |
+
'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)',
|
257 |
+
// http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets
|
258 |
+
'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
|
259 |
+
// http://www.yarvik.com/en/matrix/tablets/
|
260 |
+
'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
|
261 |
+
'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
|
262 |
+
'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
|
263 |
+
// http://www.intenso.de/kategorie_en.php?kategorie=33
|
264 |
+
// @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate
|
265 |
+
'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
|
266 |
+
// IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/
|
267 |
+
'IRUTablet' => 'M702pro',
|
268 |
+
'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
|
269 |
+
// http://www.e-boda.ro/tablete-pc.html
|
270 |
+
'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
|
271 |
+
// http://www.allview.ro/produse/droseries/lista-tablete-pc/
|
272 |
+
'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
|
273 |
+
// http://wiki.archosfans.com/index.php?title=Main_Page
|
274 |
+
// @note Rewrite the regex format after we add more UAs.
|
275 |
+
'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
|
276 |
+
// http://www.ainol.com/plugin.php?identifier=ainol&module=product
|
277 |
+
'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
|
278 |
+
'NokiaLumiaTablet' => 'Lumia 2520',
|
279 |
+
// @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER
|
280 |
+
// Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser
|
281 |
+
// http://www.sony.jp/support/tablet/
|
282 |
+
'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP612|SOT31',
|
283 |
+
// http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8
|
284 |
+
'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
|
285 |
+
// db + http://www.cube-tablet.com/buy-products.html
|
286 |
+
'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
|
287 |
+
// http://www.cobyusa.com/?p=pcat&pcat_id=3001
|
288 |
+
'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
|
289 |
+
// http://www.match.net.cn/products.asp
|
290 |
+
'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10',
|
291 |
+
// http://www.msi.com/support
|
292 |
+
// @todo Research the Windows Tablets.
|
293 |
+
'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
|
294 |
+
// @todo http://www.kyoceramobile.com/support/drivers/
|
295 |
+
// 'KyoceraTablet' => null,
|
296 |
+
// @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/
|
297 |
+
// 'IntextTablet' => null,
|
298 |
+
// http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets)
|
299 |
+
// http://www.imp3.net/14/show.php?itemid=20454
|
300 |
+
'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
|
301 |
+
// http://www.rock-chips.com/index.php?do=prod&pid=2
|
302 |
+
'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
|
303 |
+
// http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/
|
304 |
+
'FlyTablet' => 'IQ310|Fly Vision',
|
305 |
+
// http://www.bqreaders.com/gb/tablets-prices-sale.html
|
306 |
+
'bqTablet' => 'Android.*(bq)?.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris [E|M]10)|Maxwell.*Lite|Maxwell.*Plus',
|
307 |
+
// http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290
|
308 |
+
// http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets)
|
309 |
+
'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim',
|
310 |
+
// Nec or Medias Tab
|
311 |
+
'NecTablet' => '\bN-06D|\bN-08D',
|
312 |
+
// Pantech Tablets: http://www.pantechusa.com/phones/
|
313 |
+
'PantechTablet' => 'Pantech.*P4100',
|
314 |
+
// Broncho Tablets: http://www.broncho.cn/ (hard to find)
|
315 |
+
'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
|
316 |
+
// http://versusuk.com/support.html
|
317 |
+
'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
|
318 |
+
// http://www.zync.in/index.php/our-products/tablet-phablets
|
319 |
+
'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900',
|
320 |
+
// http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/
|
321 |
+
'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
|
322 |
+
// https://www.nabitablet.com/
|
323 |
+
'NabiTablet' => 'Android.*\bNabi',
|
324 |
+
'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
|
325 |
+
// French Danew Tablets http://www.danew.com/produits-tablette.php
|
326 |
+
'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
|
327 |
+
// Texet Tablets and Readers http://www.texet.ru/tablet/
|
328 |
+
'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
|
329 |
+
// Avoid detecting 'PLAYSTATION 3' as mobile.
|
330 |
+
'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
|
331 |
+
// http://www.trekstor.de/surftabs.html
|
332 |
+
'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
|
333 |
+
// http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets
|
334 |
+
'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
|
335 |
+
// http://www.advandigital.com/index.php?link=content-product&jns=JP001
|
336 |
+
// because of the short codenames we have to include whitespaces to reduce the possible conflicts.
|
337 |
+
'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
|
338 |
+
// http://www.danytech.com/category/tablet-pc
|
339 |
+
'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
|
340 |
+
// http://www.galapad.net/product.html
|
341 |
+
'GalapadTablet' => 'Android.*\bG1\b',
|
342 |
+
// http://www.micromaxinfo.com/tablet/funbook
|
343 |
+
'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
|
344 |
+
// http://www.karbonnmobiles.com/products_tablet.php
|
345 |
+
'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
|
346 |
+
// http://www.myallfine.com/Products.asp
|
347 |
+
'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
|
348 |
+
// http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr=
|
349 |
+
'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
|
350 |
+
// http://www.yonesnav.com/products/products.php
|
351 |
+
'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
|
352 |
+
// http://www.cjshowroom.com/eproducts.aspx?classcode=004001001
|
353 |
+
// China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html)
|
354 |
+
'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
|
355 |
+
// http://www.gloryunion.cn/products.asp
|
356 |
+
// http://www.allwinnertech.com/en/apply/mobile.html
|
357 |
+
// http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB)
|
358 |
+
// @todo: Softwiner tablets?
|
359 |
+
// aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions.
|
360 |
+
'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G
|
361 |
+
// http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118
|
362 |
+
'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
|
363 |
+
// http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/
|
364 |
+
// @todo: add more tests.
|
365 |
+
'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)',
|
366 |
+
// http://hclmetablet.com/India/index.php
|
367 |
+
'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
|
368 |
+
// http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html
|
369 |
+
'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
|
370 |
+
// http://www.visture.com/index.asp
|
371 |
+
'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
|
372 |
+
// http://www.mijncresta.nl/tablet
|
373 |
+
'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
|
374 |
+
// MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309
|
375 |
+
'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
|
376 |
+
// Concorde tab
|
377 |
+
'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
|
378 |
+
// GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/
|
379 |
+
'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
|
380 |
+
// Modecom Tablets - http://www.modecom.eu/tablets/portal/
|
381 |
+
'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
|
382 |
+
// Vonino Tablets - http://www.vonino.eu/tablets
|
383 |
+
'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
|
384 |
+
// ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0
|
385 |
+
'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
|
386 |
+
// Storex Tablets - http://storex.fr/espace_client/support.html
|
387 |
+
// @note: no need to add all the tablet codes since they are guided by the first regex.
|
388 |
+
'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
|
389 |
+
// Generic Vodafone tablets.
|
390 |
+
'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497',
|
391 |
+
// French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb
|
392 |
+
// Aka: http://www.essentielb.fr/
|
393 |
+
'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
|
394 |
+
// Ross & Moor - http://ross-moor.ru/
|
395 |
+
'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
|
396 |
+
// i-mobile http://product.i-mobilephone.com/Mobile_Device
|
397 |
+
'iMobileTablet' => 'i-mobile i-note',
|
398 |
+
// http://www.tolino.de/de/vergleichen/
|
399 |
+
'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
|
400 |
+
// AudioSonic - a Kmart brand
|
401 |
+
// http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1
|
402 |
+
'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
|
403 |
+
// AMPE Tablets - http://www.ampe.com.my/product-category/tablets/
|
404 |
+
// @todo: add them gradually to avoid conflicts.
|
405 |
+
'AMPETablet' => 'Android.* A78 ',
|
406 |
+
// Skk Mobile - http://skkmobile.com.ph/product_tablets.php
|
407 |
+
'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
|
408 |
+
// Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1
|
409 |
+
'TecnoTablet' => 'TECNO P9',
|
410 |
+
// JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3
|
411 |
+
'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
|
412 |
+
// i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/
|
413 |
+
'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
|
414 |
+
// http://www.intracon.eu/tablet
|
415 |
+
'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
|
416 |
+
// http://www.xoro.de/produkte/
|
417 |
+
// @note: Might be the same brand with 'Simply tablets'
|
418 |
+
'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
|
419 |
+
// http://www1.viewsonic.com/products/computing/tablets/
|
420 |
+
'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
|
421 |
+
// http://www.odys.de/web/internet-tablet_en.html
|
422 |
+
'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
|
423 |
+
// http://www.captiva-power.de/products.html#tablets-en
|
424 |
+
'CaptivaTablet' => 'CAPTIVA PAD',
|
425 |
+
// IconBIT - http://www.iconbit.com/products/tablets/
|
426 |
+
'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
|
427 |
+
// http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63
|
428 |
+
'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
|
429 |
+
// Onda - http://www.onda-tablet.com/buy-android-onda.html?dir=desc&limit=all&order=price
|
430 |
+
'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+',
|
431 |
+
'JaytechTablet' => 'TPC-PA762',
|
432 |
+
'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
|
433 |
+
// http://www.digma.ru/support/download/
|
434 |
+
// @todo: Ebooks also (if requested)
|
435 |
+
'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
|
436 |
+
// http://www.evolioshop.com/ro/tablete-pc.html
|
437 |
+
// http://www.evolio.ro/support/downloads_static.html?cat=2
|
438 |
+
// @todo: Research some more
|
439 |
+
'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
|
440 |
+
// @todo http://www.lavamobiles.com/tablets-data-cards
|
441 |
+
'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
|
442 |
+
// http://www.breezetablet.com/
|
443 |
+
'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712',
|
444 |
+
// http://www.mpmaneurope.com/en/products/internet-tablets-14/android-tablets-14/
|
445 |
+
'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010',
|
446 |
+
// https://www.celkonmobiles.com/?_a=categoryphones&sid=2
|
447 |
+
'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
|
448 |
+
// http://www.wolderelectronics.com/productos/manuales-y-guias-rapidas/categoria-2-miTab
|
449 |
+
'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
|
450 |
+
// http://www.mi.com/en
|
451 |
+
'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
|
452 |
+
// http://www.nbru.cn/index.html
|
453 |
+
'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
|
454 |
+
// http://navroad.com/products/produkty/tablety/
|
455 |
+
'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
|
456 |
+
// http://leader-online.com/new_site/product-category/tablets/
|
457 |
+
// http://www.leader-online.net.au/List/Tablet
|
458 |
+
'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
|
459 |
+
// http://www.datawind.com/ubislate/
|
460 |
+
'UbislateTablet' => 'UbiSlate[\s]?7C',
|
461 |
+
// http://www.pocketbook-int.com/ru/support
|
462 |
+
'PocketBookTablet' => 'Pocketbook',
|
463 |
+
// http://www.kocaso.com/product_tablet.html
|
464 |
+
'KocasoTablet' => '\b(TB-1207)\b',
|
465 |
+
// http://global.hisense.com/product/asia/tablet/Sero7/201412/t20141215_91832.htm
|
466 |
+
'HisenseTablet' => '\b(F5281|E2371)\b',
|
467 |
+
// http://www.tesco.com/direct/hudl/
|
468 |
+
'Hudl' => 'Hudl HT7S3|Hudl 2',
|
469 |
+
// http://www.telstra.com.au/home-phone/thub-2/
|
470 |
+
'TelstraTablet' => 'T-Hub2',
|
471 |
+
'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b'
|
472 |
+
);
|
473 |
+
|
474 |
+
/**
|
475 |
+
* List of mobile Operating Systems.
|
476 |
+
*
|
477 |
+
* @var array
|
478 |
+
*/
|
479 |
+
protected static $operatingSystems = array(
|
480 |
+
'AndroidOS' => 'Android',
|
481 |
+
'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os',
|
482 |
+
'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino',
|
483 |
+
'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b',
|
484 |
+
// @reference: http://en.wikipedia.org/wiki/Windows_Mobile
|
485 |
+
'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;',
|
486 |
+
// @reference: http://en.wikipedia.org/wiki/Windows_Phone
|
487 |
+
// http://wifeng.cn/?r=blog&a=view&id=106
|
488 |
+
// http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx
|
489 |
+
// http://msdn.microsoft.com/library/ms537503.aspx
|
490 |
+
// https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx
|
491 |
+
'WindowsPhoneOS' => 'Windows Phone 10.0|Windows Phone 8.1|Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;',
|
492 |
+
'iOS' => '\biPhone.*Mobile|\biPod|\biPad',
|
493 |
+
// http://en.wikipedia.org/wiki/MeeGo
|
494 |
+
// @todo: research MeeGo in UAs
|
495 |
+
'MeeGoOS' => 'MeeGo',
|
496 |
+
// http://en.wikipedia.org/wiki/Maemo
|
497 |
+
// @todo: research Maemo in UAs
|
498 |
+
'MaemoOS' => 'Maemo',
|
499 |
+
'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135
|
500 |
+
'webOS' => 'webOS|hpwOS',
|
501 |
+
'badaOS' => '\bBada\b',
|
502 |
+
'BREWOS' => 'BREW',
|
503 |
+
);
|
504 |
+
|
505 |
+
/**
|
506 |
+
* List of mobile User Agents.
|
507 |
+
*
|
508 |
+
* IMPORTANT: This is a list of only mobile browsers.
|
509 |
+
* Mobile Detect 2.x supports only mobile browsers,
|
510 |
+
* it was never designed to detect all browsers.
|
511 |
+
* The change will come in 2017 in the 3.x release for PHP7.
|
512 |
+
*
|
513 |
+
* @var array
|
514 |
+
*/
|
515 |
+
protected static $browsers = array(
|
516 |
+
//'Vivaldi' => 'Vivaldi',
|
517 |
+
// @reference: https://developers.google.com/chrome/mobile/docs/user-agent
|
518 |
+
'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?',
|
519 |
+
'Dolfin' => '\bDolfin\b',
|
520 |
+
'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+',
|
521 |
+
'Skyfire' => 'Skyfire',
|
522 |
+
'Edge' => 'Mobile Safari/[.0-9]* Edge',
|
523 |
+
'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+
|
524 |
+
'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile|FxiOS',
|
525 |
+
'Bolt' => 'bolt',
|
526 |
+
'TeaShark' => 'teashark',
|
527 |
+
'Blazer' => 'Blazer',
|
528 |
+
// @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3
|
529 |
+
'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari',
|
530 |
+
// http://en.wikipedia.org/wiki/Midori_(web_browser)
|
531 |
+
//'Midori' => 'midori',
|
532 |
+
//'Tizen' => 'Tizen',
|
533 |
+
'UCBrowser' => 'UC.*Browser|UCWEB',
|
534 |
+
'baiduboxapp' => 'baiduboxapp',
|
535 |
+
'baidubrowser' => 'baidubrowser',
|
536 |
+
// https://github.com/serbanghita/Mobile-Detect/issues/7
|
537 |
+
'DiigoBrowser' => 'DiigoBrowser',
|
538 |
+
// http://www.puffinbrowser.com/index.php
|
539 |
+
'Puffin' => 'Puffin',
|
540 |
+
// http://mercury-browser.com/index.html
|
541 |
+
'Mercury' => '\bMercury\b',
|
542 |
+
// http://en.wikipedia.org/wiki/Obigo_Browser
|
543 |
+
'ObigoBrowser' => 'Obigo',
|
544 |
+
// http://en.wikipedia.org/wiki/NetFront
|
545 |
+
'NetFront' => 'NF-Browser',
|
546 |
+
// @reference: http://en.wikipedia.org/wiki/Minimo
|
547 |
+
// http://en.wikipedia.org/wiki/Vision_Mobile_Browser
|
548 |
+
'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger',
|
549 |
+
// @reference: https://en.wikipedia.org/wiki/Pale_Moon_(web_browser)
|
550 |
+
'PaleMoon' => 'Android.*PaleMoon|Mobile.*PaleMoon',
|
551 |
+
);
|
552 |
+
|
553 |
+
/**
|
554 |
+
* Utilities.
|
555 |
+
*
|
556 |
+
* @var array
|
557 |
+
*/
|
558 |
+
protected static $utilities = array(
|
559 |
+
// Experimental. When a mobile device wants to switch to 'Desktop Mode'.
|
560 |
+
// http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/
|
561 |
+
// https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011
|
562 |
+
// https://developers.facebook.com/docs/sharing/best-practices
|
563 |
+
'Bot' => 'Googlebot|facebookexternalhit|AdsBot-Google|Google Keyword Suggestion|Facebot|YandexBot|YandexMobileBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|Exabot|MJ12bot|YandexImages|TurnitinBot|Pingdom',
|
564 |
+
'MobileBot' => 'Googlebot-Mobile|AdsBot-Google-Mobile|YahooSeeker/M1A1-R2D2',
|
565 |
+
'DesktopMode' => 'WPDesktop',
|
566 |
+
'TV' => 'SonyDTV|HbbTV', // experimental
|
567 |
+
'WebKit' => '(webkit)[ /]([\w.]+)',
|
568 |
+
// @todo: Include JXD consoles.
|
569 |
+
'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b',
|
570 |
+
'Watch' => 'SM-V700',
|
571 |
+
);
|
572 |
+
|
573 |
+
/**
|
574 |
+
* All possible HTTP headers that represent the
|
575 |
+
* User-Agent string.
|
576 |
+
*
|
577 |
+
* @var array
|
578 |
+
*/
|
579 |
+
protected static $uaHttpHeaders = array(
|
580 |
+
// The default User-Agent string.
|
581 |
+
'HTTP_USER_AGENT',
|
582 |
+
// Header can occur on devices using Opera Mini.
|
583 |
+
'HTTP_X_OPERAMINI_PHONE_UA',
|
584 |
+
// Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/
|
585 |
+
'HTTP_X_DEVICE_USER_AGENT',
|
586 |
+
'HTTP_X_ORIGINAL_USER_AGENT',
|
587 |
+
'HTTP_X_SKYFIRE_PHONE',
|
588 |
+
'HTTP_X_BOLT_PHONE_UA',
|
589 |
+
'HTTP_DEVICE_STOCK_UA',
|
590 |
+
'HTTP_X_UCBROWSER_DEVICE_UA'
|
591 |
+
);
|
592 |
+
|
593 |
+
/**
|
594 |
+
* The individual segments that could exist in a User-Agent string. VER refers to the regular
|
595 |
+
* expression defined in the constant self::VER.
|
596 |
+
*
|
597 |
+
* @var array
|
598 |
+
*/
|
599 |
+
protected static $properties = array(
|
600 |
+
|
601 |
+
// Build
|
602 |
+
'Mobile' => 'Mobile/[VER]',
|
603 |
+
'Build' => 'Build/[VER]',
|
604 |
+
'Version' => 'Version/[VER]',
|
605 |
+
'VendorID' => 'VendorID/[VER]',
|
606 |
+
|
607 |
+
// Devices
|
608 |
+
'iPad' => 'iPad.*CPU[a-z ]+[VER]',
|
609 |
+
'iPhone' => 'iPhone.*CPU[a-z ]+[VER]',
|
610 |
+
'iPod' => 'iPod.*CPU[a-z ]+[VER]',
|
611 |
+
//'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'),
|
612 |
+
'Kindle' => 'Kindle/[VER]',
|
613 |
+
|
614 |
+
// Browser
|
615 |
+
'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'),
|
616 |
+
'Coast' => array('Coast/[VER]'),
|
617 |
+
'Dolfin' => 'Dolfin/[VER]',
|
618 |
+
// @reference: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent/Firefox
|
619 |
+
'Firefox' => array('Firefox/[VER]', 'FxiOS/[VER]'),
|
620 |
+
'Fennec' => 'Fennec/[VER]',
|
621 |
+
// http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
|
622 |
+
// https://msdn.microsoft.com/en-us/library/ie/hh869301(v=vs.85).aspx
|
623 |
+
'Edge' => 'Edge/[VER]',
|
624 |
+
'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];', 'Trident/[0-9.]+;.*rv:[VER]'),
|
625 |
+
// http://en.wikipedia.org/wiki/NetFront
|
626 |
+
'NetFront' => 'NetFront/[VER]',
|
627 |
+
'NokiaBrowser' => 'NokiaBrowser/[VER]',
|
628 |
+
'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ),
|
629 |
+
'Opera Mini' => 'Opera Mini/[VER]',
|
630 |
+
'Opera Mobi' => 'Version/[VER]',
|
631 |
+
'UC Browser' => 'UC Browser[VER]',
|
632 |
+
'MQQBrowser' => 'MQQBrowser/[VER]',
|
633 |
+
'MicroMessenger' => 'MicroMessenger/[VER]',
|
634 |
+
'baiduboxapp' => 'baiduboxapp/[VER]',
|
635 |
+
'baidubrowser' => 'baidubrowser/[VER]',
|
636 |
+
'SamsungBrowser' => 'SamsungBrowser/[VER]',
|
637 |
+
'Iron' => 'Iron/[VER]',
|
638 |
+
// @note: Safari 7534.48.3 is actually Version 5.1.
|
639 |
+
// @note: On BlackBerry the Version is overwriten by the OS.
|
640 |
+
'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ),
|
641 |
+
'Skyfire' => 'Skyfire/[VER]',
|
642 |
+
'Tizen' => 'Tizen/[VER]',
|
643 |
+
'Webkit' => 'webkit[ /][VER]',
|
644 |
+
'PaleMoon' => 'PaleMoon/[VER]',
|
645 |
+
|
646 |
+
// Engine
|
647 |
+
'Gecko' => 'Gecko/[VER]',
|
648 |
+
'Trident' => 'Trident/[VER]',
|
649 |
+
'Presto' => 'Presto/[VER]',
|
650 |
+
'Goanna' => 'Goanna/[VER]',
|
651 |
+
|
652 |
+
// OS
|
653 |
+
'iOS' => ' \bi?OS\b [VER][ ;]{1}',
|
654 |
+
'Android' => 'Android [VER]',
|
655 |
+
'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'),
|
656 |
+
'BREW' => 'BREW [VER]',
|
657 |
+
'Java' => 'Java/[VER]',
|
658 |
+
// @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx
|
659 |
+
// @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases
|
660 |
+
'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'),
|
661 |
+
'Windows Phone' => 'Windows Phone [VER]',
|
662 |
+
'Windows CE' => 'Windows CE/[VER]',
|
663 |
+
// http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd
|
664 |
+
'Windows NT' => 'Windows NT [VER]',
|
665 |
+
'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'),
|
666 |
+
'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'),
|
667 |
+
);
|
668 |
+
|
669 |
+
/**
|
670 |
+
* Construct an instance of this class.
|
671 |
+
*
|
672 |
+
* @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored.
|
673 |
+
* If left empty, will use the global _SERVER['HTTP_*'] vars instead.
|
674 |
+
* @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT
|
675 |
+
* from the $headers array instead.
|
676 |
+
*/
|
677 |
+
public function __construct(
|
678 |
+
array $headers = null,
|
679 |
+
$userAgent = null
|
680 |
+
) {
|
681 |
+
$this->setHttpHeaders($headers);
|
682 |
+
$this->setUserAgent($userAgent);
|
683 |
+
}
|
684 |
+
|
685 |
+
/**
|
686 |
+
* Get the current script version.
|
687 |
+
* This is useful for the demo.php file,
|
688 |
+
* so people can check on what version they are testing
|
689 |
+
* for mobile devices.
|
690 |
+
*
|
691 |
+
* @return string The version number in semantic version format.
|
692 |
+
*/
|
693 |
+
public static function getScriptVersion()
|
694 |
+
{
|
695 |
+
return self::VERSION;
|
696 |
+
}
|
697 |
+
|
698 |
+
/**
|
699 |
+
* Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers.
|
700 |
+
*
|
701 |
+
* @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract
|
702 |
+
* the headers. The default null is left for backwards compatibility.
|
703 |
+
*/
|
704 |
+
public function setHttpHeaders($httpHeaders = null)
|
705 |
+
{
|
706 |
+
// use global _SERVER if $httpHeaders aren't defined
|
707 |
+
if (!is_array($httpHeaders) || !count($httpHeaders)) {
|
708 |
+
$httpHeaders = $_SERVER;
|
709 |
+
}
|
710 |
+
|
711 |
+
// clear existing headers
|
712 |
+
$this->httpHeaders = array();
|
713 |
+
|
714 |
+
// Only save HTTP headers. In PHP land, that means only _SERVER vars that
|
715 |
+
// start with HTTP_.
|
716 |
+
foreach ($httpHeaders as $key => $value) {
|
717 |
+
if (substr($key, 0, 5) === 'HTTP_') {
|
718 |
+
$this->httpHeaders[$key] = $value;
|
719 |
+
}
|
720 |
+
}
|
721 |
+
|
722 |
+
// In case we're dealing with CloudFront, we need to know.
|
723 |
+
$this->setCfHeaders($httpHeaders);
|
724 |
+
}
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Retrieves the HTTP headers.
|
728 |
+
*
|
729 |
+
* @return array
|
730 |
+
*/
|
731 |
+
public function getHttpHeaders()
|
732 |
+
{
|
733 |
+
return $this->httpHeaders;
|
734 |
+
}
|
735 |
+
|
736 |
+
/**
|
737 |
+
* Retrieves a particular header. If it doesn't exist, no exception/error is caused.
|
738 |
+
* Simply null is returned.
|
739 |
+
*
|
740 |
+
* @param string $header The name of the header to retrieve. Can be HTTP compliant such as
|
741 |
+
* "User-Agent" or "X-Device-User-Agent" or can be php-esque with the
|
742 |
+
* all-caps, HTTP_ prefixed, underscore seperated awesomeness.
|
743 |
+
*
|
744 |
+
* @return string|null The value of the header.
|
745 |
+
*/
|
746 |
+
public function getHttpHeader($header)
|
747 |
+
{
|
748 |
+
// are we using PHP-flavored headers?
|
749 |
+
if (strpos($header, '_') === false) {
|
750 |
+
$header = str_replace('-', '_', $header);
|
751 |
+
$header = strtoupper($header);
|
752 |
+
}
|
753 |
+
|
754 |
+
// test the alternate, too
|
755 |
+
$altHeader = 'HTTP_' . $header;
|
756 |
+
|
757 |
+
//Test both the regular and the HTTP_ prefix
|
758 |
+
if (isset($this->httpHeaders[$header])) {
|
759 |
+
return $this->httpHeaders[$header];
|
760 |
+
} elseif (isset($this->httpHeaders[$altHeader])) {
|
761 |
+
return $this->httpHeaders[$altHeader];
|
762 |
+
}
|
763 |
+
|
764 |
+
return null;
|
765 |
+
}
|
766 |
+
|
767 |
+
public function getMobileHeaders()
|
768 |
+
{
|
769 |
+
return self::$mobileHeaders;
|
770 |
+
}
|
771 |
+
|
772 |
+
/**
|
773 |
+
* Get all possible HTTP headers that
|
774 |
+
* can contain the User-Agent string.
|
775 |
+
*
|
776 |
+
* @return array List of HTTP headers.
|
777 |
+
*/
|
778 |
+
public function getUaHttpHeaders()
|
779 |
+
{
|
780 |
+
return self::$uaHttpHeaders;
|
781 |
+
}
|
782 |
+
|
783 |
+
|
784 |
+
/**
|
785 |
+
* Set CloudFront headers
|
786 |
+
* http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/header-caching.html#header-caching-web-device
|
787 |
+
*
|
788 |
+
* @param array $cfHeaders List of HTTP headers
|
789 |
+
*
|
790 |
+
* @return boolean If there were CloudFront headers to be set
|
791 |
+
*/
|
792 |
+
public function setCfHeaders($cfHeaders = null) {
|
793 |
+
// use global _SERVER if $cfHeaders aren't defined
|
794 |
+
if (!is_array($cfHeaders) || !count($cfHeaders)) {
|
795 |
+
$cfHeaders = $_SERVER;
|
796 |
+
}
|
797 |
+
|
798 |
+
// clear existing headers
|
799 |
+
$this->cloudfrontHeaders = array();
|
800 |
+
|
801 |
+
// Only save CLOUDFRONT headers. In PHP land, that means only _SERVER vars that
|
802 |
+
// start with cloudfront-.
|
803 |
+
$response = false;
|
804 |
+
foreach ($cfHeaders as $key => $value) {
|
805 |
+
if (substr(strtolower($key), 0, 16) === 'http_cloudfront_') {
|
806 |
+
$this->cloudfrontHeaders[strtoupper($key)] = $value;
|
807 |
+
$response = true;
|
808 |
+
}
|
809 |
+
}
|
810 |
+
|
811 |
+
return $response;
|
812 |
+
}
|
813 |
+
|
814 |
+
/**
|
815 |
+
* Retrieves the cloudfront headers.
|
816 |
+
*
|
817 |
+
* @return array
|
818 |
+
*/
|
819 |
+
public function getCfHeaders()
|
820 |
+
{
|
821 |
+
return $this->cloudfrontHeaders;
|
822 |
+
}
|
823 |
+
|
824 |
+
/**
|
825 |
+
* Set the User-Agent to be used.
|
826 |
+
*
|
827 |
+
* @param string $userAgent The user agent string to set.
|
828 |
+
*
|
829 |
+
* @return string|null
|
830 |
+
*/
|
831 |
+
public function setUserAgent($userAgent = null)
|
832 |
+
{
|
833 |
+
// Invalidate cache due to #375
|
834 |
+
$this->cache = array();
|
835 |
+
|
836 |
+
if (false === empty($userAgent)) {
|
837 |
+
return $this->userAgent = $userAgent;
|
838 |
+
} else {
|
839 |
+
$this->userAgent = null;
|
840 |
+
foreach ($this->getUaHttpHeaders() as $altHeader) {
|
841 |
+
if (false === empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban)
|
842 |
+
$this->userAgent .= $this->httpHeaders[$altHeader] . " ";
|
843 |
+
}
|
844 |
+
}
|
845 |
+
|
846 |
+
if (!empty($this->userAgent)) {
|
847 |
+
return $this->userAgent = trim($this->userAgent);
|
848 |
+
}
|
849 |
+
}
|
850 |
+
|
851 |
+
if (count($this->getCfHeaders()) > 0) {
|
852 |
+
return $this->userAgent = 'Amazon CloudFront';
|
853 |
+
}
|
854 |
+
return $this->userAgent = null;
|
855 |
+
}
|
856 |
+
|
857 |
+
/**
|
858 |
+
* Retrieve the User-Agent.
|
859 |
+
*
|
860 |
+
* @return string|null The user agent if it's set.
|
861 |
+
*/
|
862 |
+
public function getUserAgent()
|
863 |
+
{
|
864 |
+
return $this->userAgent;
|
865 |
+
}
|
866 |
+
|
867 |
+
/**
|
868 |
+
* Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or
|
869 |
+
* self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set.
|
870 |
+
*
|
871 |
+
* @deprecated since version 2.6.9
|
872 |
+
*
|
873 |
+
* @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default
|
874 |
+
* parameter is null which will default to self::DETECTION_TYPE_MOBILE.
|
875 |
+
*/
|
876 |
+
public function setDetectionType($type = null)
|
877 |
+
{
|
878 |
+
if ($type === null) {
|
879 |
+
$type = self::DETECTION_TYPE_MOBILE;
|
880 |
+
}
|
881 |
+
|
882 |
+
if ($type !== self::DETECTION_TYPE_MOBILE && $type !== self::DETECTION_TYPE_EXTENDED) {
|
883 |
+
return;
|
884 |
+
}
|
885 |
+
|
886 |
+
$this->detectionType = $type;
|
887 |
+
}
|
888 |
+
|
889 |
+
public function getMatchingRegex()
|
890 |
+
{
|
891 |
+
return $this->matchingRegex;
|
892 |
+
}
|
893 |
+
|
894 |
+
public function getMatchesArray()
|
895 |
+
{
|
896 |
+
return $this->matchesArray;
|
897 |
+
}
|
898 |
+
|
899 |
+
/**
|
900 |
+
* Retrieve the list of known phone devices.
|
901 |
+
*
|
902 |
+
* @return array List of phone devices.
|
903 |
+
*/
|
904 |
+
public static function getPhoneDevices()
|
905 |
+
{
|
906 |
+
return self::$phoneDevices;
|
907 |
+
}
|
908 |
+
|
909 |
+
/**
|
910 |
+
* Retrieve the list of known tablet devices.
|
911 |
+
*
|
912 |
+
* @return array List of tablet devices.
|
913 |
+
*/
|
914 |
+
public static function getTabletDevices()
|
915 |
+
{
|
916 |
+
return self::$tabletDevices;
|
917 |
+
}
|
918 |
+
|
919 |
+
/**
|
920 |
+
* Alias for getBrowsers() method.
|
921 |
+
*
|
922 |
+
* @return array List of user agents.
|
923 |
+
*/
|
924 |
+
public static function getUserAgents()
|
925 |
+
{
|
926 |
+
return self::getBrowsers();
|
927 |
+
}
|
928 |
+
|
929 |
+
/**
|
930 |
+
* Retrieve the list of known browsers. Specifically, the user agents.
|
931 |
+
*
|
932 |
+
* @return array List of browsers / user agents.
|
933 |
+
*/
|
934 |
+
public static function getBrowsers()
|
935 |
+
{
|
936 |
+
return self::$browsers;
|
937 |
+
}
|
938 |
+
|
939 |
+
/**
|
940 |
+
* Retrieve the list of known utilities.
|
941 |
+
*
|
942 |
+
* @return array List of utilities.
|
943 |
+
*/
|
944 |
+
public static function getUtilities()
|
945 |
+
{
|
946 |
+
return self::$utilities;
|
947 |
+
}
|
948 |
+
|
949 |
+
/**
|
950 |
+
* Method gets the mobile detection rules. This method is used for the magic methods $detect->is*().
|
951 |
+
*
|
952 |
+
* @deprecated since version 2.6.9
|
953 |
+
*
|
954 |
+
* @return array All the rules (but not extended).
|
955 |
+
*/
|
956 |
+
public static function getMobileDetectionRules()
|
957 |
+
{
|
958 |
+
static $rules;
|
959 |
+
|
960 |
+
if (!$rules) {
|
961 |
+
$rules = array_merge(
|
962 |
+
self::$phoneDevices,
|
963 |
+
self::$tabletDevices,
|
964 |
+
self::$operatingSystems,
|
965 |
+
self::$browsers
|
966 |
+
);
|
967 |
+
}
|
968 |
+
|
969 |
+
return $rules;
|
970 |
+
|
971 |
+
}
|
972 |
+
|
973 |
+
/**
|
974 |
+
* Method gets the mobile detection rules + utilities.
|
975 |
+
* The reason this is separate is because utilities rules
|
976 |
+
* don't necessary imply mobile. This method is used inside
|
977 |
+
* the new $detect->is('stuff') method.
|
978 |
+
*
|
979 |
+
* @deprecated since version 2.6.9
|
980 |
+
*
|
981 |
+
* @return array All the rules + extended.
|
982 |
+
*/
|
983 |
+
public function getMobileDetectionRulesExtended()
|
984 |
+
{
|
985 |
+
static $rules;
|
986 |
+
|
987 |
+
if (!$rules) {
|
988 |
+
// Merge all rules together.
|
989 |
+
$rules = array_merge(
|
990 |
+
self::$phoneDevices,
|
991 |
+
self::$tabletDevices,
|
992 |
+
self::$operatingSystems,
|
993 |
+
self::$browsers,
|
994 |
+
self::$utilities
|
995 |
+
);
|
996 |
+
}
|
997 |
+
|
998 |
+
return $rules;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
/**
|
1002 |
+
* Retrieve the current set of rules.
|
1003 |
+
*
|
1004 |
+
* @deprecated since version 2.6.9
|
1005 |
+
*
|
1006 |
+
* @return array
|
1007 |
+
*/
|
1008 |
+
public function getRules()
|
1009 |
+
{
|
1010 |
+
if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) {
|
1011 |
+
return self::getMobileDetectionRulesExtended();
|
1012 |
+
} else {
|
1013 |
+
return self::getMobileDetectionRules();
|
1014 |
+
}
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
/**
|
1018 |
+
* Retrieve the list of mobile operating systems.
|
1019 |
+
*
|
1020 |
+
* @return array The list of mobile operating systems.
|
1021 |
+
*/
|
1022 |
+
public static function getOperatingSystems()
|
1023 |
+
{
|
1024 |
+
return self::$operatingSystems;
|
1025 |
+
}
|
1026 |
+
|
1027 |
+
/**
|
1028 |
+
* Check the HTTP headers for signs of mobile.
|
1029 |
+
* This is the fastest mobile check possible; it's used
|
1030 |
+
* inside isMobile() method.
|
1031 |
+
*
|
1032 |
+
* @return bool
|
1033 |
+
*/
|
1034 |
+
public function checkHttpHeadersForMobile()
|
1035 |
+
{
|
1036 |
+
|
1037 |
+
foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) {
|
1038 |
+
if (isset($this->httpHeaders[$mobileHeader])) {
|
1039 |
+
if (is_array($matchType['matches'])) {
|
1040 |
+
foreach ($matchType['matches'] as $_match) {
|
1041 |
+
if (strpos($this->httpHeaders[$mobileHeader], $_match) !== false) {
|
1042 |
+
return true;
|
1043 |
+
}
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
return false;
|
1047 |
+
} else {
|
1048 |
+
return true;
|
1049 |
+
}
|
1050 |
+
}
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
return false;
|
1054 |
+
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
/**
|
1058 |
+
* Magic overloading method.
|
1059 |
+
*
|
1060 |
+
* @method boolean is[...]()
|
1061 |
+
* @param string $name
|
1062 |
+
* @param array $arguments
|
1063 |
+
* @return mixed
|
1064 |
+
* @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is'
|
1065 |
+
*/
|
1066 |
+
public function __call($name, $arguments)
|
1067 |
+
{
|
1068 |
+
// make sure the name starts with 'is', otherwise
|
1069 |
+
if (substr($name, 0, 2) !== 'is') {
|
1070 |
+
throw new BadMethodCallException("No such method exists: $name");
|
1071 |
+
}
|
1072 |
+
|
1073 |
+
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
|
1074 |
+
|
1075 |
+
$key = substr($name, 2);
|
1076 |
+
|
1077 |
+
return $this->matchUAAgainstKey($key);
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
/**
|
1081 |
+
* Find a detection rule that matches the current User-agent.
|
1082 |
+
*
|
1083 |
+
* @param null $userAgent deprecated
|
1084 |
+
* @return boolean
|
1085 |
+
*/
|
1086 |
+
protected function matchDetectionRulesAgainstUA($userAgent = null)
|
1087 |
+
{
|
1088 |
+
// Begin general search.
|
1089 |
+
foreach ($this->getRules() as $_regex) {
|
1090 |
+
if (empty($_regex)) {
|
1091 |
+
continue;
|
1092 |
+
}
|
1093 |
+
|
1094 |
+
if ($this->match($_regex, $userAgent)) {
|
1095 |
+
return true;
|
1096 |
+
}
|
1097 |
+
}
|
1098 |
+
|
1099 |
+
return false;
|
1100 |
+
}
|
1101 |
+
|
1102 |
+
/**
|
1103 |
+
* Search for a certain key in the rules array.
|
1104 |
+
* If the key is found then try to match the corresponding
|
1105 |
+
* regex against the User-Agent.
|
1106 |
+
*
|
1107 |
+
* @param string $key
|
1108 |
+
*
|
1109 |
+
* @return boolean
|
1110 |
+
*/
|
1111 |
+
protected function matchUAAgainstKey($key)
|
1112 |
+
{
|
1113 |
+
// Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc.
|
1114 |
+
$key = strtolower($key);
|
1115 |
+
if (false === isset($this->cache[$key])) {
|
1116 |
+
|
1117 |
+
// change the keys to lower case
|
1118 |
+
$_rules = array_change_key_case($this->getRules());
|
1119 |
+
|
1120 |
+
if (false === empty($_rules[$key])) {
|
1121 |
+
$this->cache[$key] = $this->match($_rules[$key]);
|
1122 |
+
}
|
1123 |
+
|
1124 |
+
if (false === isset($this->cache[$key])) {
|
1125 |
+
$this->cache[$key] = false;
|
1126 |
+
}
|
1127 |
+
}
|
1128 |
+
|
1129 |
+
return $this->cache[$key];
|
1130 |
+
}
|
1131 |
+
|
1132 |
+
/**
|
1133 |
+
* Check if the device is mobile.
|
1134 |
+
* Returns true if any type of mobile device detected, including special ones
|
1135 |
+
* @param null $userAgent deprecated
|
1136 |
+
* @param null $httpHeaders deprecated
|
1137 |
+
* @return bool
|
1138 |
+
*/
|
1139 |
+
public function isMobile($userAgent = null, $httpHeaders = null)
|
1140 |
+
{
|
1141 |
+
|
1142 |
+
if ($httpHeaders) {
|
1143 |
+
$this->setHttpHeaders($httpHeaders);
|
1144 |
+
}
|
1145 |
+
|
1146 |
+
if ($userAgent) {
|
1147 |
+
$this->setUserAgent($userAgent);
|
1148 |
+
}
|
1149 |
+
|
1150 |
+
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
|
1151 |
+
if ($this->getUserAgent() === 'Amazon CloudFront') {
|
1152 |
+
$cfHeaders = $this->getCfHeaders();
|
1153 |
+
if(array_key_exists('HTTP_CLOUDFRONT_IS_MOBILE_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_MOBILE_VIEWER'] === 'true') {
|
1154 |
+
return true;
|
1155 |
+
}
|
1156 |
+
}
|
1157 |
+
|
1158 |
+
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
|
1159 |
+
|
1160 |
+
if ($this->checkHttpHeadersForMobile()) {
|
1161 |
+
return true;
|
1162 |
+
} else {
|
1163 |
+
return $this->matchDetectionRulesAgainstUA();
|
1164 |
+
}
|
1165 |
+
|
1166 |
+
}
|
1167 |
+
|
1168 |
+
/**
|
1169 |
+
* Check if the device is a tablet.
|
1170 |
+
* Return true if any type of tablet device is detected.
|
1171 |
+
*
|
1172 |
+
* @param string $userAgent deprecated
|
1173 |
+
* @param array $httpHeaders deprecated
|
1174 |
+
* @return bool
|
1175 |
+
*/
|
1176 |
+
public function isTablet($userAgent = null, $httpHeaders = null)
|
1177 |
+
{
|
1178 |
+
// Check specifically for cloudfront headers if the useragent === 'Amazon CloudFront'
|
1179 |
+
if ($this->getUserAgent() === 'Amazon CloudFront') {
|
1180 |
+
$cfHeaders = $this->getCfHeaders();
|
1181 |
+
if(array_key_exists('HTTP_CLOUDFRONT_IS_TABLET_VIEWER', $cfHeaders) && $cfHeaders['HTTP_CLOUDFRONT_IS_TABLET_VIEWER'] === 'true') {
|
1182 |
+
return true;
|
1183 |
+
}
|
1184 |
+
}
|
1185 |
+
|
1186 |
+
$this->setDetectionType(self::DETECTION_TYPE_MOBILE);
|
1187 |
+
|
1188 |
+
foreach (self::$tabletDevices as $_regex) {
|
1189 |
+
if ($this->match($_regex, $userAgent)) {
|
1190 |
+
return true;
|
1191 |
+
}
|
1192 |
+
}
|
1193 |
+
|
1194 |
+
return false;
|
1195 |
+
}
|
1196 |
+
|
1197 |
+
/**
|
1198 |
+
* This method checks for a certain property in the
|
1199 |
+
* userAgent.
|
1200 |
+
* @todo: The httpHeaders part is not yet used.
|
1201 |
+
*
|
1202 |
+
* @param string $key
|
1203 |
+
* @param string $userAgent deprecated
|
1204 |
+
* @param string $httpHeaders deprecated
|
1205 |
+
* @return bool|int|null
|
1206 |
+
*/
|
1207 |
+
public function is($key, $userAgent = null, $httpHeaders = null)
|
1208 |
+
{
|
1209 |
+
// Set the UA and HTTP headers only if needed (eg. batch mode).
|
1210 |
+
if ($httpHeaders) {
|
1211 |
+
$this->setHttpHeaders($httpHeaders);
|
1212 |
+
}
|
1213 |
+
|
1214 |
+
if ($userAgent) {
|
1215 |
+
$this->setUserAgent($userAgent);
|
1216 |
+
}
|
1217 |
+
|
1218 |
+
$this->setDetectionType(self::DETECTION_TYPE_EXTENDED);
|
1219 |
+
|
1220 |
+
return $this->matchUAAgainstKey($key);
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
/**
|
1224 |
+
* Some detection rules are relative (not standard),
|
1225 |
+
* because of the diversity of devices, vendors and
|
1226 |
+
* their conventions in representing the User-Agent or
|
1227 |
+
* the HTTP headers.
|
1228 |
+
*
|
1229 |
+
* This method will be used to check custom regexes against
|
1230 |
+
* the User-Agent string.
|
1231 |
+
*
|
1232 |
+
* @param $regex
|
1233 |
+
* @param string $userAgent
|
1234 |
+
* @return bool
|
1235 |
+
*
|
1236 |
+
* @todo: search in the HTTP headers too.
|
1237 |
+
*/
|
1238 |
+
public function match($regex, $userAgent = null)
|
1239 |
+
{
|
1240 |
+
$match = (bool) preg_match(sprintf('#%s#is', $regex), (false === empty($userAgent) ? $userAgent : $this->userAgent), $matches);
|
1241 |
+
// If positive match is found, store the results for debug.
|
1242 |
+
if ($match) {
|
1243 |
+
$this->matchingRegex = $regex;
|
1244 |
+
$this->matchesArray = $matches;
|
1245 |
+
}
|
1246 |
+
|
1247 |
+
return $match;
|
1248 |
+
}
|
1249 |
+
|
1250 |
+
/**
|
1251 |
+
* Get the properties array.
|
1252 |
+
*
|
1253 |
+
* @return array
|
1254 |
+
*/
|
1255 |
+
public static function getProperties()
|
1256 |
+
{
|
1257 |
+
return self::$properties;
|
1258 |
+
}
|
1259 |
+
|
1260 |
+
/**
|
1261 |
+
* Prepare the version number.
|
1262 |
+
*
|
1263 |
+
* @todo Remove the error supression from str_replace() call.
|
1264 |
+
*
|
1265 |
+
* @param string $ver The string version, like "2.6.21.2152";
|
1266 |
+
*
|
1267 |
+
* @return float
|
1268 |
+
*/
|
1269 |
+
public function prepareVersionNo($ver)
|
1270 |
+
{
|
1271 |
+
$ver = str_replace(array('_', ' ', '/'), '.', $ver);
|
1272 |
+
$arrVer = explode('.', $ver, 2);
|
1273 |
+
|
1274 |
+
if (isset($arrVer[1])) {
|
1275 |
+
$arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions.
|
1276 |
+
}
|
1277 |
+
|
1278 |
+
return (float) implode('.', $arrVer);
|
1279 |
+
}
|
1280 |
+
|
1281 |
+
/**
|
1282 |
+
* Check the version of the given property in the User-Agent.
|
1283 |
+
* Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31)
|
1284 |
+
*
|
1285 |
+
* @param string $propertyName The name of the property. See self::getProperties() array
|
1286 |
+
* keys for all possible properties.
|
1287 |
+
* @param string $type Either self::VERSION_TYPE_STRING to get a string value or
|
1288 |
+
* self::VERSION_TYPE_FLOAT indicating a float value. This parameter
|
1289 |
+
* is optional and defaults to self::VERSION_TYPE_STRING. Passing an
|
1290 |
+
* invalid parameter will default to the this type as well.
|
1291 |
+
*
|
1292 |
+
* @return string|float The version of the property we are trying to extract.
|
1293 |
+
*/
|
1294 |
+
public function version($propertyName, $type = self::VERSION_TYPE_STRING)
|
1295 |
+
{
|
1296 |
+
if (empty($propertyName)) {
|
1297 |
+
return false;
|
1298 |
+
}
|
1299 |
+
|
1300 |
+
// set the $type to the default if we don't recognize the type
|
1301 |
+
if ($type !== self::VERSION_TYPE_STRING && $type !== self::VERSION_TYPE_FLOAT) {
|
1302 |
+
$type = self::VERSION_TYPE_STRING;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
$properties = self::getProperties();
|
1306 |
+
|
1307 |
+
// Check if the property exists in the properties array.
|
1308 |
+
if (true === isset($properties[$propertyName])) {
|
1309 |
+
|
1310 |
+
// Prepare the pattern to be matched.
|
1311 |
+
// Make sure we always deal with an array (string is converted).
|
1312 |
+
$properties[$propertyName] = (array) $properties[$propertyName];
|
1313 |
+
|
1314 |
+
foreach ($properties[$propertyName] as $propertyMatchString) {
|
1315 |
+
|
1316 |
+
$propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString);
|
1317 |
+
|
1318 |
+
// Identify and extract the version.
|
1319 |
+
preg_match(sprintf('#%s#is', $propertyPattern), $this->userAgent, $match);
|
1320 |
+
|
1321 |
+
if (false === empty($match[1])) {
|
1322 |
+
$version = ($type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1]);
|
1323 |
+
|
1324 |
+
return $version;
|
1325 |
+
}
|
1326 |
+
|
1327 |
+
}
|
1328 |
+
|
1329 |
+
}
|
1330 |
+
|
1331 |
+
return false;
|
1332 |
+
}
|
1333 |
+
|
1334 |
+
/**
|
1335 |
+
* Retrieve the mobile grading, using self::MOBILE_GRADE_* constants.
|
1336 |
+
*
|
1337 |
+
* @return string One of the self::MOBILE_GRADE_* constants.
|
1338 |
+
*/
|
1339 |
+
public function mobileGrade()
|
1340 |
+
{
|
1341 |
+
$isMobile = $this->isMobile();
|
1342 |
+
|
1343 |
+
if (
|
1344 |
+
// Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0)
|
1345 |
+
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) >= 4.3 ||
|
1346 |
+
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) >= 4.3 ||
|
1347 |
+
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) >= 4.3 ||
|
1348 |
+
|
1349 |
+
// Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5)
|
1350 |
+
// Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM
|
1351 |
+
// Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices
|
1352 |
+
// Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7
|
1353 |
+
( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) ||
|
1354 |
+
|
1355 |
+
// Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8)
|
1356 |
+
$this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT) >= 7.5 ||
|
1357 |
+
|
1358 |
+
// Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10)
|
1359 |
+
$this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 6.0 ||
|
1360 |
+
// Blackberry Playbook (1.0-2.0) - Tested on PlayBook
|
1361 |
+
$this->match('Playbook.*Tablet') ||
|
1362 |
+
|
1363 |
+
// Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0)
|
1364 |
+
( $this->version('webOS', self::VERSION_TYPE_FLOAT) >= 1.4 && $this->match('Palm|Pre|Pixi') ) ||
|
1365 |
+
// Palm WebOS 3.0 - Tested on HP TouchPad
|
1366 |
+
$this->match('hp.*TouchPad') ||
|
1367 |
+
|
1368 |
+
// Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices
|
1369 |
+
( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 18 ) ||
|
1370 |
+
|
1371 |
+
// Chrome for Android - Tested on Android 4.0, 4.1 device
|
1372 |
+
( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 4.0 ) ||
|
1373 |
+
|
1374 |
+
// Skyfire 4.1 - Tested on Android 2.3 device
|
1375 |
+
( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT) >= 4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
|
1376 |
+
|
1377 |
+
// Opera Mobile 11.5-12: Tested on Android 2.3
|
1378 |
+
( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11.5 && $this->is('AndroidOS') ) ||
|
1379 |
+
|
1380 |
+
// Meego 1.2 - Tested on Nokia 950 and N9
|
1381 |
+
$this->is('MeeGoOS') ||
|
1382 |
+
|
1383 |
+
// Tizen (pre-release) - Tested on early hardware
|
1384 |
+
$this->is('Tizen') ||
|
1385 |
+
|
1386 |
+
// Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser
|
1387 |
+
// @todo: more tests here!
|
1388 |
+
$this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT) >= 2.0 ||
|
1389 |
+
|
1390 |
+
// UC Browser - Tested on Android 2.3 device
|
1391 |
+
( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 ) ||
|
1392 |
+
|
1393 |
+
// Kindle 3 and Fire - Tested on the built-in WebKit browser for each
|
1394 |
+
( $this->match('Kindle Fire') ||
|
1395 |
+
$this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT) >= 3.0 ) ||
|
1396 |
+
|
1397 |
+
// Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet
|
1398 |
+
$this->is('AndroidOS') && $this->is('NookTablet') ||
|
1399 |
+
|
1400 |
+
// Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7
|
1401 |
+
$this->version('Chrome', self::VERSION_TYPE_FLOAT) >= 16 && !$isMobile ||
|
1402 |
+
|
1403 |
+
// Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7
|
1404 |
+
$this->version('Safari', self::VERSION_TYPE_FLOAT) >= 5.0 && !$isMobile ||
|
1405 |
+
|
1406 |
+
// Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7
|
1407 |
+
$this->version('Firefox', self::VERSION_TYPE_FLOAT) >= 10.0 && !$isMobile ||
|
1408 |
+
|
1409 |
+
// Internet Explorer 7-9 - Tested on Windows XP, Vista and 7
|
1410 |
+
$this->version('IE', self::VERSION_TYPE_FLOAT) >= 7.0 && !$isMobile ||
|
1411 |
+
|
1412 |
+
// Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7
|
1413 |
+
$this->version('Opera', self::VERSION_TYPE_FLOAT) >= 10 && !$isMobile
|
1414 |
+
){
|
1415 |
+
return self::MOBILE_GRADE_A;
|
1416 |
+
}
|
1417 |
+
|
1418 |
+
if (
|
1419 |
+
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 ||
|
1420 |
+
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 ||
|
1421 |
+
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 ||
|
1422 |
+
|
1423 |
+
// Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770
|
1424 |
+
$this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT) >= 5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 ||
|
1425 |
+
|
1426 |
+
//Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3
|
1427 |
+
($this->version('Opera Mini', self::VERSION_TYPE_FLOAT) >= 5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT) <= 7.0 &&
|
1428 |
+
($this->version('Android', self::VERSION_TYPE_FLOAT) >= 2.3 || $this->is('iOS')) ) ||
|
1429 |
+
|
1430 |
+
// Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1)
|
1431 |
+
$this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') ||
|
1432 |
+
|
1433 |
+
// @todo: report this (tested on Nokia N71)
|
1434 |
+
$this->version('Opera Mobi', self::VERSION_TYPE_FLOAT) >= 11 && $this->is('SymbianOS')
|
1435 |
+
){
|
1436 |
+
return self::MOBILE_GRADE_B;
|
1437 |
+
}
|
1438 |
+
|
1439 |
+
if (
|
1440 |
+
// Blackberry 4.x - Tested on the Curve 8330
|
1441 |
+
$this->version('BlackBerry', self::VERSION_TYPE_FLOAT) <= 5.0 ||
|
1442 |
+
// Windows Mobile - Tested on the HTC Leo (WinMo 5.2)
|
1443 |
+
$this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT) <= 5.2 ||
|
1444 |
+
|
1445 |
+
// Tested on original iPhone (3.1), iPhone 3 (3.2)
|
1446 |
+
$this->is('iOS') && $this->version('iPad', self::VERSION_TYPE_FLOAT) <= 3.2 ||
|
1447 |
+
$this->is('iOS') && $this->version('iPhone', self::VERSION_TYPE_FLOAT) <= 3.2 ||
|
1448 |
+
$this->is('iOS') && $this->version('iPod', self::VERSION_TYPE_FLOAT) <= 3.2 ||
|
1449 |
+
|
1450 |
+
// Internet Explorer 7 and older - Tested on Windows XP
|
1451 |
+
$this->version('IE', self::VERSION_TYPE_FLOAT) <= 7.0 && !$isMobile
|
1452 |
+
){
|
1453 |
+
return self::MOBILE_GRADE_C;
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
// All older smartphone platforms and featurephones - Any device that doesn't support media queries
|
1457 |
+
// will receive the basic, C grade experience.
|
1458 |
+
return self::MOBILE_GRADE_C;
|
1459 |
+
}
|
1460 |
+
}
|
inc/cache/Mobile-Detect-2.8.25/README.md
ADDED
@@ -0,0 +1,283 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
![Mobile Detect](http://demo.mobiledetect.net/logo-github.png)
|
2 |
+
|
3 |
+
> Motto: "Every business should have a mobile detection script to detect mobile readers."
|
4 |
+
|
5 |
+
[![Build Status](https://travis-ci.org/serbanghita/Mobile-Detect.svg?branch=devel)](https://travis-ci.org/serbanghita/Mobile-Detect)
|
6 |
+
[![Latest Stable Version](https://poser.pugx.org/mobiledetect/mobiledetectlib/v/stable.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
7 |
+
[![Total Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/downloads.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
8 |
+
[![Daily Downloads](https://poser.pugx.org/mobiledetect/mobiledetectlib/d/daily.png)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
9 |
+
[![License](https://poser.pugx.org/mobiledetect/mobiledetectlib/license.svg)](https://packagist.org/packages/mobiledetect/mobiledetectlib)
|
10 |
+
|
11 |
+
*Mobile_Detect is a lightweight PHP class for detecting mobile devices (including tablets).
|
12 |
+
It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.*
|
13 |
+
|
14 |
+
We're committed to make Mobile_Detect the best open-source mobile detection resource and this is why before
|
15 |
+
each release we're running [unit tests](./tests), we also research and update the detection rules on **daily**
|
16 |
+
and **weekly** basis.
|
17 |
+
|
18 |
+
Your website's _content strategy_ is important! You need a complete toolkit to deliver an experience that is _optimized_, _fast_ and _relevant_ to your users. Mobile_Detect class is a [server-side detection](http://www.w3.org/TR/mwabp/#bp-devcap-detection) tool that can help you with your RWD strategy, it is not a replacement for CSS3 media queries or other forms of client-side feature detection.
|
19 |
+
|
20 |
+
##### Announcements
|
21 |
+
|
22 |
+
For `2.x` branch we are no longer taking optimizations pull requests, but only new regexes and User-Agents for our tests.
|
23 |
+
On `2.x` releases we are focusing on **new tablets only**. All the pull requests about TVs, bots or optimizations will be closed and analyzed after `3.0.0-beta` is released.
|
24 |
+
|
25 |
+
Still working on `3.0.0` branch to provide you with device detection!
|
26 |
+
We're really excited on this one!
|
27 |
+
We would like to speed this up, but life and family gets in the way ;)
|
28 |
+
|
29 |
+
Special thanks to **JetBrains** for providing licenses for **PHPStorm**. In case you never heard or tried PHPStorm, you're
|
30 |
+
clearly missing out! [Check PHPStorm](https://www.jetbrains.com/phpstorm/) out!
|
31 |
+
|
32 |
+
##### Download and demo
|
33 |
+
|
34 |
+
|Download|Docs|Examples|
|
35 |
+
|-------------|-------------|-------------|
|
36 |
+
|[Go to releases](../../tags)|[Become a contributor](../../wiki/Become-a-contributor)|[Code examples](../../wiki/Code-examples)
|
37 |
+
|[Mobile_Detect.php](./Mobile_Detect.php)|[History](../../wiki/History)|[:iphone: Live demo!](http://is.gd/mobiletest)
|
38 |
+
|[Composer package](https://packagist.org/packages/mobiledetect/mobiledetectlib)|
|
39 |
+
|
40 |
+
#### Continuous updates
|
41 |
+
|
42 |
+
You can use [composer](https://getcomposer.org/doc/00-intro.md) in your release and update process to make sure you have the latest Mobile_Detect version.
|
43 |
+
|
44 |
+
```
|
45 |
+
composer require mobiledetect/mobiledetectlib
|
46 |
+
```
|
47 |
+
|
48 |
+
```json
|
49 |
+
{
|
50 |
+
"require": {
|
51 |
+
"mobiledetect/mobiledetectlib": "^2.8"
|
52 |
+
}
|
53 |
+
}
|
54 |
+
```
|
55 |
+
|
56 |
+
##### Help
|
57 |
+
|
58 |
+
|Pledgie|Paypal|
|
59 |
+
|-------|------|
|
60 |
+
|[Donate :+1:](https://pledgie.com/campaigns/21856)|[Donate :beer:](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=mobiledetectlib%40gmail%2ecom&lc=US&item_name=Mobile%20Detect¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)|
|
61 |
+
|
62 |
+
|
63 |
+
I'm currently paying for hosting and spend a lot of my family time to maintain the project and planning the future releases.
|
64 |
+
I would highly appreciate any money donations that will keep the research going.
|
65 |
+
|
66 |
+
Special thanks to the community :+1: for donations, [BrowserStack](https://www.browserstack.com/) - for providing access to their great platform, [Zend](http://www.zend.com/) - for donating licenses, [Dragos Gavrila](https://twitter.com/grafician) who contributed with the logo.
|
67 |
+
|
68 |
+
##### 3rd party modules / [Submit new](../../issues/new?title=New%203rd%20party%20module&body=Name, Link and Description of the module.)
|
69 |
+
|
70 |
+
:point_right: Keep `Mobile_Detect.php` class in a separate `module` and do NOT include it in your script core because of the high frequency of updates.
|
71 |
+
:point_right: When including the class into you `web application` or `module` always use `include_once '../path/to/Mobile_Detect.php` to prevent conflicts.
|
72 |
+
|
73 |
+
**JavaScript**
|
74 |
+
|
75 |
+
* mobile-detect.js - A [JavaScript port](https://github.com/hgoebl/mobile-detect.js) of Mobile-Detect class. Made by [Heinrich Goebl](https://github.com/hgoebl).
|
76 |
+
|
77 |
+
**Varnish Cache**
|
78 |
+
|
79 |
+
* [Varnish Mobile Detect](https://github.com/willemk/varnish-mobiletranslate) - Drop-in varnish solution to mobile user
|
80 |
+
detection based on the Mobile-Detect library. Made by [willemk](https://github.com/willemk).
|
81 |
+
* [mobiledetect2vcl](https://github.com/carlosabalde/mobiledetect2vcl) - Python script to transform the Mobile
|
82 |
+
Detect JSON database into an UA-based mobile detection VCL subroutine easily integrable in any Varnish Cache
|
83 |
+
configuration. Made by [Carlos Abalde](https://github.com/carlosabalde).
|
84 |
+
|
85 |
+
**LUA**
|
86 |
+
|
87 |
+
* [mobile-detect.lua](https://github.com/yourpalmark/mobile-detect.lua) is a port of Mobile-Detect to Lua for
|
88 |
+
NGINX HTTP servers. Follows closely to mobile-detect.js. Supports all methods that server-side
|
89 |
+
mobile-detect.js supports. Fully unit-tested and synced with Travis CI (Build Passing badge included).
|
90 |
+
Made by [Mark Walters](https://github.com/yourpalmark).
|
91 |
+
|
92 |
+
**PHP**
|
93 |
+
|
94 |
+
**WordPress**
|
95 |
+
|
96 |
+
* [WordPress Mobile Detect](https://wordpress.org/plugins/wp-mobile-detect/) - Gives you the ability to wrap that
|
97 |
+
infographic in a `[notdevice][/notdevice]` shortcode so at the server level WordPress will
|
98 |
+
decide to show that content only if the user is NOT on a phone or tablet.
|
99 |
+
Made by [Jesse Friedman](https://profiles.wordpress.org/professor44/).
|
100 |
+
|
101 |
+
* [mobble](https://wordpress.org/plugins/mobble/) - provides mobile related conditional functions for your site.
|
102 |
+
e.g. `is_iphone()`, `is_mobile()` and `is_tablet()`. Made by Scott Evans.
|
103 |
+
|
104 |
+
* [WordPress Responsage](https://github.com/iamspacehead/responsage) - A small WordPress theme plugin that allows
|
105 |
+
you to make your images responsive. Made by [Adrian Ciaschetti](https://github.com/iamspacehead).
|
106 |
+
|
107 |
+
* [WP247 Body Classes](https://wordpress.org/plugins/wp247-body-classes/) - Add unique classes to the `body` tag for
|
108 |
+
easy styling based on various attributes (archive, user, post, mobile) and various WordPress "is" functions.
|
109 |
+
Mobile attributes include type of device, Operating System, Browser, etc. Examples: .is-mobile, .is-not-mobile,
|
110 |
+
.is-tablet, .is-ios, .is-not-ios, .is-androidos, .is-chromebrowser.
|
111 |
+
Made by [wescleveland56](https://github.com/wescleveland56).
|
112 |
+
|
113 |
+
**Drupal**
|
114 |
+
|
115 |
+
* [Drupal Mobile Switch](https://www.drupal.org/project/mobile_switch) - The Mobile Switch Drupal module provides a
|
116 |
+
automatic theme switch functionality for mobile devices, detected by Browscap or Mobile Detect.
|
117 |
+
Made by [Siegfried Neumann](https://www.drupal.org/user/45267).
|
118 |
+
|
119 |
+
* [Drupal Context Mobile Detect](https://www.drupal.org/project/context_mobile_detect) - This is a Drupal context module
|
120 |
+
which integrates Context and PHP Mobile Detect library.
|
121 |
+
Created by [Artem Shymko](https://www.drupal.org/user/432492).
|
122 |
+
|
123 |
+
* [Drupal Mobile Detect](https://www.drupal.org/project/mobile_detect]) - Lightweight mobile detect module for Drupal
|
124 |
+
created by [Matthew Donadio](https://www.drupal.org/user/325244).
|
125 |
+
|
126 |
+
**Joomla**
|
127 |
+
|
128 |
+
* [yagendoo Joomla! Mobile Detection Plugin](http://www.yagendoo.com/en/blog/free-mobile-detection-plugin-for-joomla.html) - Lightweight PHP plugin for Joomla!
|
129 |
+
that detects a mobile browser using the Mobile Detect class.
|
130 |
+
Made by yagendoo media.
|
131 |
+
|
132 |
+
* [User Agent Detector plugin](https://github.com/renekreijveld/UserAgentDetector) - This system plugin detects the user
|
133 |
+
agent of your website visitor and sets a session variable accordingly. Based on the user agent, the plugin detects if the
|
134 |
+
site is running on a desktop pc, tablet or smartphone. It can also detect if the visitor is a spider bot (search engine).
|
135 |
+
Session variable that is set: `ualayout`. Possible values: desktop, tablet, mobile, bot.
|
136 |
+
Made by @ReneKreijveld.
|
137 |
+
|
138 |
+
**Magento**
|
139 |
+
|
140 |
+
* [Magento helper](http://www.magentocommerce.com/magento-connect/catalog/product/view/id/16835/) from Optimise Web enables
|
141 |
+
the use of all functions provided by Mobile Detect. Made by [Kathir Vel](http://www.kathirvel.com).
|
142 |
+
|
143 |
+
* [Magento 2 Mobile Detect Theme Change](https://github.com/EaDesgin/magento2-mobiledetect) is an extension for Magento 2
|
144 |
+
that will change the theme or redirect to a different URL. Also containing a helper to check for the device type.
|
145 |
+
|
146 |
+
**PrestaShop**
|
147 |
+
|
148 |
+
* [PrestaShop](https://www.prestashop.com) is a free, secure and open source shopping cart platform. Mobile_Detect
|
149 |
+
is included in the default package since 1.5.x.
|
150 |
+
|
151 |
+
**Laravel**
|
152 |
+
|
153 |
+
* [Agent](https://github.com/jenssegers/agent) is a user agent class for Laravel based on Mobile Detect with some
|
154 |
+
additional functionality.
|
155 |
+
Made by [Jens Segers](https://github.com/jenssegers).
|
156 |
+
|
157 |
+
* [BrowserDetect](https://github.com/hisorange/browser-detect) is a browser and mobile detection package, collects
|
158 |
+
and wrap together the best user-agent identifiers for Laravel.
|
159 |
+
Created by [Varga Zsolt](https://github.com/hisorange).
|
160 |
+
|
161 |
+
**Zend Framework**
|
162 |
+
|
163 |
+
* [ZF2 Mobile-Detect](https://github.com/neilime/zf2-mobile-detect.git) is a Zend Framework 2 module that provides
|
164 |
+
Mobile-Detect features (Mobile_Detect class as a service, helper for views and plugin controllers).
|
165 |
+
Made by [neilime](https://github.com/neilime).
|
166 |
+
|
167 |
+
* [ZF2 MobileDetectModule](https://github.com/nikolaposa/MobileDetectModule) facilitates integration of a PHP MobileDetect
|
168 |
+
class with some ZF2-based application. Has similar idea like the existing ZF2 Mobile-Detect module,
|
169 |
+
but differs in initialization and provision routine of the actual Mobile_Detect class.
|
170 |
+
Appropriate view helper and controller plugin also have different conceptions.
|
171 |
+
Made by [Nikola Posa](https://github.com/nikolaposa).
|
172 |
+
|
173 |
+
**Symfony**
|
174 |
+
|
175 |
+
* [Symfony2 Mobile Detect Bundle](https://github.com/suncat2000/MobileDetectBundle) is a bundle for detecting mobile devices,
|
176 |
+
manage mobile view and redirect to the mobile and tablet version.
|
177 |
+
Made by [Nikolay Ivlev](https://github.com/suncat2000).
|
178 |
+
|
179 |
+
* [Silex Mobile Detect Service Provider](https://github.com/jbinfo/MobileDetectServiceProvider) is a service provider to
|
180 |
+
interact with Mobile detect class methods.
|
181 |
+
Made by [Lhassan Baazzi](https://github.com/jbinfo).
|
182 |
+
|
183 |
+
**Slim Framework**
|
184 |
+
|
185 |
+
* [Slim_Mobile_Detect](https://github.com/zguillez/slim_mobile_detect) implements Mobile_Detect lib for different
|
186 |
+
responses write on Slim Framework App.
|
187 |
+
|
188 |
+
**ExpressionEngine**
|
189 |
+
|
190 |
+
* [EE2 Detect Mobile](https://github.com/garethtdavies/detect-mobile) is a lightweight PHP plugin for EE2 that detects
|
191 |
+
a mobile browser using the Mobile Detect class. Made by [Gareth Davies](https://github.com/garethtdavies).
|
192 |
+
|
193 |
+
**Yii Framework**
|
194 |
+
|
195 |
+
* [Yii Extension](https://github.com/iamsalnikov/MobileDetect) - Mobile detect plugin for Yii framework.
|
196 |
+
Made by [Alexey Salnikov](https://github.com/iamsalnikov).
|
197 |
+
|
198 |
+
* [Yii Extension](https://github.com/candasm/yii1-mobile-detect-component) - Mobile detect component for Yii framework
|
199 |
+
1.x version which supports composer package manager. Made by [Candas Minareci](https://github.com/candasm).
|
200 |
+
|
201 |
+
* [Yii2 Device Detect](https://github.com/alexandernst/yii2-device-detect/) - Yii2 extension for Mobile-Detect library.
|
202 |
+
Made by [Alexander Nestorov](https://github.com/alexandernst).
|
203 |
+
|
204 |
+
**CakePHP**
|
205 |
+
|
206 |
+
* [CakePHP MobileDetect](https://github.com/chronon/CakePHP-MobileDetectComponent-Plugin) is a plugin component for
|
207 |
+
CakePHP 2.x. Made by [Gregory Gaskill](https://github.com/chronon).
|
208 |
+
|
209 |
+
**FuelPHP**
|
210 |
+
|
211 |
+
* [Special Agent](https://github.com/rob-bar/special_agent) is a FuelPHP package which uses php-mobile-detect to
|
212 |
+
determine whether a device is mobile or not. It overrides the Fuelphp Agent class its methods.
|
213 |
+
Made by [Robbie Bardjin](https://github.com/rob-bar).
|
214 |
+
|
215 |
+
|
216 |
+
**TYPO3**
|
217 |
+
|
218 |
+
* [px_mobiledetect](https://typo3.org/extensions/repository/view/px_mobiledetect) is an extension that helps to detect
|
219 |
+
visitor's mobile device class (if that’s tablet or mobile device like smartphone). Made by Alexander Tretyak.
|
220 |
+
|
221 |
+
**Other**
|
222 |
+
|
223 |
+
* [PageCache](https://github.com/mmamedov/page-cache) is a lightweight PHP library for full page cache,
|
224 |
+
with built-in Mobile-Detect support. Made by [Muhammed Mamedov](https://github.com/mmamedov).
|
225 |
+
|
226 |
+
* [Statamic CMS Mobile Detect](https://github.com/haikulab/statamic-mobile-detect) is a plugin.
|
227 |
+
Made by [Sergei Filippov](https://github.com/haikulab/statamic-mobile-detect) of Haiku Lab.
|
228 |
+
|
229 |
+
* [Kohana Mobile Detect](https://github.com/madeinnordeste/kohana-mobile-detect) is an example of implementation of
|
230 |
+
Mobile_Detect class with Kohana framework.
|
231 |
+
Written by [Luiz Alberto S. Ribeiro](https://github.com/madeinnordeste).
|
232 |
+
|
233 |
+
* [MemHT](https://www.memht.com) is a Free PHP CMS and Blog that permit the creation and the management online
|
234 |
+
of websites with few and easy steps. Has the class included in the core.
|
235 |
+
|
236 |
+
* [concrete5](https://www.concrete5.org) is a CMS that is free and open source. The library is included in the core.
|
237 |
+
|
238 |
+
* [engine7](https://github.com/QOXCorp/exengine) is PHP Open Source Framework. The Mobile_Detect class is included in
|
239 |
+
the engine.
|
240 |
+
|
241 |
+
* [Zikula](http://zikula.org) is a free and open-source Content Management Framework, which allows you to run
|
242 |
+
impressive websites and build powerful online applications. The core uses Mobile-Detect to switch to a special
|
243 |
+
Mobile theme, using jQueryMobile.
|
244 |
+
|
245 |
+
* [UserAgentInfo](https://github.com/quentin389/UserAgentInfo) is a PHP class for parsing user agent strings
|
246 |
+
(HTTP_USER_AGENT). Includes mobile checks, bot checks, browser types/versions and more.
|
247 |
+
Based on browscap, Mobile_Detect and ua-parser. Created for high traffic websites and fast batch processing.
|
248 |
+
Made by [quentin389](https://github.com/quentin389).
|
249 |
+
|
250 |
+
* [LJ Mobile Detect](https://github.com/lewisjenkins/craft-lj-mobiledetect) is a simple implementation of Mobile Detect
|
251 |
+
for Craft CMS. Made by [Lewis Jenkins](https://github.com/lewisjenkins).
|
252 |
+
|
253 |
+
* [Grav Plugin Mobile Detect](https://github.com/dimitrilongo/grav-plugin-mobile-detect/) is a simple implementation
|
254 |
+
of Mobile Detect for Grav CMS. Made by [Dimitri Longo](https://github.com/dimitrilongo).
|
255 |
+
|
256 |
+
|
257 |
+
**Perl**
|
258 |
+
|
259 |
+
* [MobileDetect.pm](https://www.buzzerstar.com/development/) is a Perl module for Mobile Detect.
|
260 |
+
Made by [Sebastian Enger](https://devop.tools/).
|
261 |
+
|
262 |
+
**Python**
|
263 |
+
|
264 |
+
* [pymobiledetect](https://pypi.python.org/pypi/pymobiledetect) - Mobile detect python package.
|
265 |
+
Made by Bas van Oostveen.
|
266 |
+
|
267 |
+
**Ruby**
|
268 |
+
|
269 |
+
* [mobile_detect.rb](https://github.com/ktaragorn/mobile_detect) is a Ruby gem using the JSON data exposed by the
|
270 |
+
php project and implementing a basic subset of the API (as much as can be done by the exposed data).
|
271 |
+
Made by [Karthik T](https://github.com/ktaragorn).
|
272 |
+
|
273 |
+
**Go**
|
274 |
+
|
275 |
+
* [GoMobileDetect](https://github.com/Shaked/gomobiledetect) is a Go port of Mobile Detect class.
|
276 |
+
Made by [https://github.com/Shaked](Shaked).
|
277 |
+
|
278 |
+
|
279 |
+
**LUA**
|
280 |
+
|
281 |
+
* [ua-lua](https://github.com/robinef/ua-lua) is a small lib written in LUA providing device type detection.
|
282 |
+
ua-lua is detecting mobile or tablet devices based on user-agent inside nginx daemon.
|
283 |
+
Made by [Frédéric Robinet](https://github.com/robinef).
|
inc/cache/Mobile-Detect-2.8.25/composer.json
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "mobiledetect/mobiledetectlib",
|
3 |
+
"type": "library",
|
4 |
+
"description": "Mobile_Detect is a lightweight PHP class for detecting mobile devices. It uses the User-Agent string combined with specific HTTP headers to detect the mobile environment.",
|
5 |
+
"keywords": ["mobile", "mobile detect", "mobile detector", "php mobile detect", "detect mobile devices"],
|
6 |
+
"homepage": "https://github.com/serbanghita/Mobile-Detect",
|
7 |
+
"license": "MIT",
|
8 |
+
"authors": [
|
9 |
+
{
|
10 |
+
"name": "Serban Ghita",
|
11 |
+
"email": "serbanghita@gmail.com",
|
12 |
+
"homepage": "http://mobiledetect.net",
|
13 |
+
"role": "Developer"
|
14 |
+
}
|
15 |
+
],
|
16 |
+
"require": {
|
17 |
+
"php": ">=5.0.0"
|
18 |
+
},
|
19 |
+
"require-dev": {
|
20 |
+
"phpunit/phpunit": "*"
|
21 |
+
},
|
22 |
+
"autoload": {
|
23 |
+
"classmap": ["Mobile_Detect.php"],
|
24 |
+
"psr-0": {
|
25 |
+
"Detection": "namespaced/"
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
inc/cache/Mobile-Detect-2.8.25/export/exportToJSON.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Mobile Detect Library
|
4 |
+
* - export -
|
5 |
+
* =====================
|
6 |
+
*
|
7 |
+
* Use the resulting JSON export file in other languages
|
8 |
+
* other than PHP. Always check for 'version' key because
|
9 |
+
* new major versions can modify the structure of the JSON file.
|
10 |
+
*
|
11 |
+
* The result of running this script is the export.json file.
|
12 |
+
*
|
13 |
+
* @license Code and contributions have 'MIT License'
|
14 |
+
* More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt
|
15 |
+
*
|
16 |
+
*/
|
17 |
+
|
18 |
+
// Included nicejson function to beautify the result JSON file.
|
19 |
+
// This library is not mandatory.
|
20 |
+
if( file_exists(dirname(__FILE__).'/nicejson/nicejson.php') ) {
|
21 |
+
include_once dirname(__FILE__).'/nicejson/nicejson.php';
|
22 |
+
}
|
23 |
+
|
24 |
+
// Include Mobile Detect.
|
25 |
+
require_once dirname(__FILE__).'/../Mobile_Detect.php';
|
26 |
+
$detect = new Mobile_Detect;
|
27 |
+
|
28 |
+
$json = array(
|
29 |
+
// The current version of Mobile Detect class that
|
30 |
+
// is being exported.
|
31 |
+
'version' => $detect->getScriptVersion(),
|
32 |
+
|
33 |
+
// All headers that trigger 'isMobile' to be 'true',
|
34 |
+
// before reaching the User-Agent match detection.
|
35 |
+
'headerMatch' => $detect->getMobileHeaders(),
|
36 |
+
|
37 |
+
// All possible User-Agent headers.
|
38 |
+
'uaHttpHeaders' => $detect->getUaHttpHeaders(),
|
39 |
+
|
40 |
+
// All the regexes that trigger 'isMobile' or 'isTablet'
|
41 |
+
// to be true.
|
42 |
+
'uaMatch' => array(
|
43 |
+
// If match is found, triggers 'isMobile' to be true.
|
44 |
+
'phones' => $detect->getPhoneDevices(),
|
45 |
+
// Triggers 'isTablet' to be true.
|
46 |
+
'tablets' => $detect->getTabletDevices(),
|
47 |
+
// If match is found, triggers 'isMobile' to be true.
|
48 |
+
'browsers' => $detect->getBrowsers(),
|
49 |
+
// If match is found, triggers 'isMobile' to be true.
|
50 |
+
'os' => $detect->getOperatingSystems(),
|
51 |
+
// Various utilities. To be further discussed.
|
52 |
+
'utilities' => $detect->getUtilities()
|
53 |
+
)
|
54 |
+
);
|
55 |
+
|
56 |
+
$fileName = dirname(__FILE__).'/../Mobile_Detect.json';
|
57 |
+
// Write the JSON file to disk.11
|
58 |
+
// You can import this file in your app.
|
59 |
+
if (file_put_contents(
|
60 |
+
$fileName,
|
61 |
+
function_exists('json_format') ? json_format($json) : json_encode($json)
|
62 |
+
)) {
|
63 |
+
echo 'Done. Check '.realpath($fileName).' file.';
|
64 |
+
}
|
65 |
+
else {
|
66 |
+
echo 'Failed to write '.realpath($fileName).' to disk.';
|
67 |
+
}
|
inc/cache/Mobile-Detect-2.8.25/namespaced/Detection/MobileDetect.php
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Little piece of PHP to make Mobile_Detect auto-loadable in PSR-0 compatible PHP autoloaders like
|
4 |
+
* the Symfony Universal ClassLoader by Fabien Potencier. Since PSR-0 handles an underscore in
|
5 |
+
* classnames (on the filesystem) as a slash, "Mobile_Detect.php" autoloaders will try to convert
|
6 |
+
* the classname and path to "Mobile\Detect.php". This script will ensure autoloading with:
|
7 |
+
* - Namespace: Detection
|
8 |
+
* - Classname: MobileDetect
|
9 |
+
* - Namespased: \Detection\MobileDetect
|
10 |
+
* - Autoload path: ./namespaced
|
11 |
+
* - Converted path: ./namespaced/Detection/MobileDetect.php
|
12 |
+
*
|
13 |
+
* Don't forget to use MobileDetect (instead of Mobile_Detect) as class in code when autoloading.
|
14 |
+
*
|
15 |
+
* Thanks to @WietseWind.
|
16 |
+
* For details please check: https://github.com/serbanghita/Mobile-Detect/pull/120
|
17 |
+
*/
|
18 |
+
|
19 |
+
namespace Detection;
|
20 |
+
require_once dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Mobile_Detect.php';
|
21 |
+
|
22 |
+
class MobileDetect extends \Mobile_Detect {}
|
inc/cache/Mobile-Detect-2.8.25/ruleset.xml
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<ruleset name="PSR2">
|
3 |
+
<description>The PSR-2 coding standard.</description>
|
4 |
+
<arg name="tab-width" value="4"/>
|
5 |
+
|
6 |
+
<!-- 2. General -->
|
7 |
+
|
8 |
+
<!-- 2.1 Basic Coding Standard -->
|
9 |
+
|
10 |
+
<!-- Include the whole PSR-1 standard -->
|
11 |
+
<rule ref="PSR1"/>
|
12 |
+
|
13 |
+
<!-- 2.2 Files -->
|
14 |
+
|
15 |
+
<!-- All PHP files MUST use the Unix LF (linefeed) line ending. -->
|
16 |
+
<rule ref="Generic.Files.LineEndings">
|
17 |
+
<properties>
|
18 |
+
<property name="eolChar" value="\n"/>
|
19 |
+
</properties>
|
20 |
+
</rule>
|
21 |
+
|
22 |
+
<!-- All PHP files MUST end with a single blank line. -->
|
23 |
+
<!-- checked in Files/EndFileNewlineSniff -->
|
24 |
+
|
25 |
+
<!-- The closing ?> tag MUST be omitted from files containing only PHP. -->
|
26 |
+
<!-- checked in Files/ClosingTagSniff -->
|
27 |
+
|
28 |
+
<!-- 2.3 Lines -->
|
29 |
+
|
30 |
+
<!-- The soft limit on line length MUST be 120 characters; automated style checkers MUST warn but MUST NOT error at the soft limit. -->
|
31 |
+
<rule ref="Generic.Files.LineLength">
|
32 |
+
<properties>
|
33 |
+
<property name="lineLimit" value="0"/>
|
34 |
+
<property name="absoluteLineLimit" value="0"/>
|
35 |
+
</properties>
|
36 |
+
</rule>
|
37 |
+
|
38 |
+
<!-- There MUST NOT be trailing whitespace at the end of non-blank lines. -->
|
39 |
+
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace">
|
40 |
+
<properties>
|
41 |
+
<property name="ignoreBlankLines" value="true"/>
|
42 |
+
</properties>
|
43 |
+
</rule>
|
44 |
+
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.StartFile">
|
45 |
+
<severity>0</severity>
|
46 |
+
</rule>
|
47 |
+
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EndFile">
|
48 |
+
<severity>0</severity>
|
49 |
+
</rule>
|
50 |
+
<rule ref="Squiz.WhiteSpace.SuperfluousWhitespace.EmptyLines">
|
51 |
+
<severity>0</severity>
|
52 |
+
</rule>
|
53 |
+
|
54 |
+
<!-- There MUST NOT be more than one statement per line. -->
|
55 |
+
<rule ref="Generic.Formatting.DisallowMultipleStatements"/>
|
56 |
+
|
57 |
+
<!-- 2.4 Indenting -->
|
58 |
+
|
59 |
+
<!-- Code MUST use an indent of 4 spaces, and MUST NOT use tabs for indenting. -->
|
60 |
+
<rule ref="Generic.WhiteSpace.ScopeIndent">
|
61 |
+
<properties>
|
62 |
+
<property name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT_OPEN_TAG"/>
|
63 |
+
</properties>
|
64 |
+
</rule>
|
65 |
+
<rule ref="Generic.WhiteSpace.DisallowTabIndent"/>
|
66 |
+
|
67 |
+
<!-- 2.5 Keywords and True/False/Null -->
|
68 |
+
|
69 |
+
<!-- PHP keywords MUST be in lower case. -->
|
70 |
+
<rule ref="Generic.PHP.LowerCaseKeyword"/>
|
71 |
+
|
72 |
+
<!-- The PHP constants true, false, and null MUST be in lower case. -->
|
73 |
+
<rule ref="Generic.PHP.LowerCaseConstant"/>
|
74 |
+
|
75 |
+
<!-- 3. Namespace and Use Declarations -->
|
76 |
+
|
77 |
+
<!-- When present, there MUST be one blank line after the namespace declaration. -->
|
78 |
+
<!-- checked in Namespaces/NamespaceDeclarationSniff -->
|
79 |
+
|
80 |
+
<!-- When present, all use declarations MUST go after the namespace declaration.
|
81 |
+
There MUST be one use keyword per declaration.
|
82 |
+
There MUST be one blank line after the use block. -->
|
83 |
+
<!-- checked in Namespaces/UseDeclarationSniff -->
|
84 |
+
|
85 |
+
<!-- 4. Classes, Properties, and Methods -->
|
86 |
+
|
87 |
+
<!-- 4.1. Extends and Implements -->
|
88 |
+
|
89 |
+
<!-- The extends and implements keywords MUST be declared on the same line as the class name.
|
90 |
+
The opening brace for the class go MUST go on its own line; the closing brace for the class MUST go on the next line after the body.
|
91 |
+
Lists of implements MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line. -->
|
92 |
+
<!-- checked in Classes/ClassDeclarationSniff -->
|
93 |
+
|
94 |
+
<!-- 4.2. Properties -->
|
95 |
+
|
96 |
+
<!-- Visibility MUST be declared on all properties.
|
97 |
+
The var keyword MUST NOT be used to declare a property.
|
98 |
+
There MUST NOT be more than one property declared per statement.
|
99 |
+
Property names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility. -->
|
100 |
+
<!-- checked in Classes/PropertyDeclarationSniff -->
|
101 |
+
|
102 |
+
<!-- 4.3 Methods -->
|
103 |
+
|
104 |
+
<!-- Visibility MUST be declared on all methods. -->
|
105 |
+
<rule ref="Squiz.Scope.MethodScope"/>
|
106 |
+
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
|
107 |
+
|
108 |
+
<!-- Method names SHOULD NOT be prefixed with a single underscore to indicate protected or private visibility. -->
|
109 |
+
<!-- checked in Methods/MethodDeclarationSniff -->
|
110 |
+
|
111 |
+
<!-- Method names MUST NOT be declared with a space after the method name. The opening brace MUST go on its own line, and the closing brace MUST go on the next line following the body. There MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. -->
|
112 |
+
<rule ref="Squiz.Functions.FunctionDeclaration"/>
|
113 |
+
<rule ref="Squiz.Functions.LowercaseFunctionKeywords"/>
|
114 |
+
|
115 |
+
<!-- 4.4 Method Arguments -->
|
116 |
+
|
117 |
+
<!-- In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma. -->
|
118 |
+
<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing">
|
119 |
+
<properties>
|
120 |
+
<property name="equalsSpacing" value="1"/>
|
121 |
+
</properties>
|
122 |
+
</rule>
|
123 |
+
<rule ref="Squiz.Functions.FunctionDeclarationArgumentSpacing.SpacingAfterHint">
|
124 |
+
<severity>0</severity>
|
125 |
+
</rule>
|
126 |
+
|
127 |
+
<!-- Method arguments with default values MUST go at the end of the argument list. -->
|
128 |
+
<rule ref="PEAR.Functions.ValidDefaultValue"/>
|
129 |
+
|
130 |
+
<!-- Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. -->
|
131 |
+
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration"/>
|
132 |
+
|
133 |
+
<!-- 4.5 abstract, final, and static -->
|
134 |
+
|
135 |
+
<!-- When present, the abstract and final declarations MUST precede the visibility declaration.
|
136 |
+
When present, the static declaration MUST come after the visibility declaration. -->
|
137 |
+
<!-- checked in Methods/MethodDeclarationSniff -->
|
138 |
+
|
139 |
+
<!-- 4.6 Method and Function Calls -->
|
140 |
+
|
141 |
+
<!-- When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis, there MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.
|
142 |
+
Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line. -->
|
143 |
+
<rule ref="Generic.Functions.FunctionCallArgumentSpacing"/>
|
144 |
+
<rule ref="PSR2.Methods.FunctionCallSignature.SpaceAfterCloseBracket">
|
145 |
+
<severity>0</severity>
|
146 |
+
</rule>
|
147 |
+
|
148 |
+
<!-- 5. Control Structures -->
|
149 |
+
|
150 |
+
<!-- The general style rules for control structures are as follows:
|
151 |
+
There MUST be one space after the control structure keyword
|
152 |
+
There MUST NOT be a space after the opening parenthesis
|
153 |
+
There MUST NOT be a space before the closing parenthesis
|
154 |
+
There MUST be one space between the closing parenthesis and the opening brace
|
155 |
+
The structure body MUST be indented once
|
156 |
+
The closing brace MUST be on the next line after the body -->
|
157 |
+
<rule ref="Squiz.ControlStructures.ControlSignature"/>
|
158 |
+
<rule ref="Squiz.WhiteSpace.ScopeClosingBrace"/>
|
159 |
+
<rule ref="Squiz.ControlStructures.ForEachLoopDeclaration"/>
|
160 |
+
<rule ref="Squiz.ControlStructures.ForLoopDeclaration"/>
|
161 |
+
<rule ref="Squiz.ControlStructures.LowercaseDeclaration"/>
|
162 |
+
<!-- checked in ControlStructures/ControlStructureSpacingSniff -->
|
163 |
+
|
164 |
+
<!-- The body of each structure MUST be enclosed by braces. This standardizes how the structures look, and reduces the likelihood of introducing errors as new lines get added to the body. -->
|
165 |
+
<rule ref="Generic.ControlStructures.InlineControlStructure"/>
|
166 |
+
|
167 |
+
<!-- 5.1. if, elseif, else -->
|
168 |
+
|
169 |
+
<!-- The keyword elseif SHOULD be used instead of else if so that all control keywords look like single words. -->
|
170 |
+
<!-- checked in ControlStructures/ElseIfDeclarationSniff -->
|
171 |
+
|
172 |
+
<!-- 5.2. switch, case -->
|
173 |
+
|
174 |
+
<!-- The case statement MUST be indented once from switch, and the break keyword (or other terminating keyword) MUST be indented at the same level as the case body. There MUST be a comment such as // no break when fall-through is intentional in a non-empty case body. -->
|
175 |
+
<!-- checked in ControlStructures/SwitchDeclarationSniff -->
|
176 |
+
|
177 |
+
<!-- 6. Closures -->
|
178 |
+
|
179 |
+
<!-- Closures MUST be declared with a space after the function keyword, and a space before and after the use keyword.
|
180 |
+
The opening brace MUST go on the same line, and the closing brace MUST go on the next line following the body.
|
181 |
+
There MUST NOT be a space after the opening parenthesis of the argument list or variable list, and there MUST NOT be a space before the closing parenthesis of the argument list or variable list.
|
182 |
+
In the argument list and variable list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.
|
183 |
+
Closure arguments with default values MUST go at the end of the argument list.
|
184 |
+
Argument lists and variable lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument or variable per line.
|
185 |
+
When the ending list (whether or arguments or variables) is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them. -->
|
186 |
+
<!-- checked in Squiz.Functions.MultiLineFunctionDeclaration -->
|
187 |
+
</ruleset>
|
inc/cache/config-cache.php
ADDED
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
//Based on some work of simple-cache
|
22 |
+
if ( ! defined( 'ABSPATH' ) ) exit;
|
23 |
+
|
24 |
+
class Breeze_ConfigCache {
|
25 |
+
|
26 |
+
/*
|
27 |
+
* Create advanced-cache file
|
28 |
+
*/
|
29 |
+
public function write(){
|
30 |
+
global $wp_filesystem;
|
31 |
+
|
32 |
+
$file = untrailingslashit( WP_CONTENT_DIR ) . '/advanced-cache.php';
|
33 |
+
|
34 |
+
$config = get_option('breeze_basic_settings');
|
35 |
+
|
36 |
+
$file_string = '';
|
37 |
+
|
38 |
+
if (!empty($config) && !empty( $config['breeze-active'] ) ) {
|
39 |
+
|
40 |
+
$file_string = '<?php ' .
|
41 |
+
"\n\r" . "defined( 'ABSPATH' ) || exit;" .
|
42 |
+
"\n\r" . "define( 'BREEZE_ADVANCED_CACHE', true );" .
|
43 |
+
"\n\r" . 'if ( is_admin() ) { return; }' .
|
44 |
+
"\n\r" . "if ( ! @file_exists( '" . BREEZE_PLUGIN_DIR . "breeze.php' ) ) { return; }" .
|
45 |
+
"\n\r" . "if ( ! @file_exists( '". WP_CONTENT_DIR . "/breeze-config/breeze-config.php' ) ) { return; }" .
|
46 |
+
"\n\r" . "\$GLOBALS['breeze_config'] = include('". WP_CONTENT_DIR . "/breeze-config/breeze-config.php' );" .
|
47 |
+
"\n\r" . "if ( empty( \$GLOBALS['breeze_config'] ) || empty( \$GLOBALS['breeze_config']['cache_options']['breeze-active'] ) ) { return; }" .
|
48 |
+
"\n\r" . "if ( @file_exists( '". BREEZE_PLUGIN_DIR . "inc/cache/execute-cache.php' ) ) { include_once( '". BREEZE_PLUGIN_DIR . "inc/cache/execute-cache.php' ); }" . "\n\r";
|
49 |
+
|
50 |
+
}
|
51 |
+
|
52 |
+
if ( ! $wp_filesystem->put_contents( $file, $file_string ) ) {
|
53 |
+
return false;
|
54 |
+
}
|
55 |
+
|
56 |
+
return true;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Function write parameter to breeze-config
|
61 |
+
* @return breeze_Cache
|
62 |
+
*/
|
63 |
+
public static function write_config_cache(){
|
64 |
+
$settings = get_option('breeze_basic_settings');
|
65 |
+
$config = get_option('breeze_advanced_settings');
|
66 |
+
|
67 |
+
$storage = array(
|
68 |
+
'homepage' => get_site_url(),
|
69 |
+
'cache_options' => $settings,
|
70 |
+
'disable_per_adminuser' => 0,
|
71 |
+
'exclude_url' => array(),
|
72 |
+
);
|
73 |
+
|
74 |
+
if(!empty($settings['breeze-disable-admin'])){
|
75 |
+
$storage['disable_per_adminuser'] = $settings['breeze-disable-admin'];
|
76 |
+
}
|
77 |
+
if(!empty($config['breeze-exclude-urls'])){
|
78 |
+
$storage['exclude_url'] = $config['breeze-exclude-urls'];
|
79 |
+
}
|
80 |
+
|
81 |
+
if(! self::write_config($storage)){
|
82 |
+
return false;
|
83 |
+
}
|
84 |
+
return true;
|
85 |
+
}
|
86 |
+
|
87 |
+
/*
|
88 |
+
* create file config storage parameter used for cache
|
89 |
+
*/
|
90 |
+
public static function write_config( $config ) {
|
91 |
+
|
92 |
+
global $wp_filesystem;
|
93 |
+
|
94 |
+
$config_dir = WP_CONTENT_DIR . '/breeze-config';
|
95 |
+
|
96 |
+
$site_url_parts = parse_url( site_url() );
|
97 |
+
|
98 |
+
$config_file = $config_dir . '/breeze-config.php';
|
99 |
+
|
100 |
+
$wp_filesystem->mkdir( $config_dir );
|
101 |
+
|
102 |
+
$config_file_string = '<?php ' . "\n\r" . "defined( 'ABSPATH' ) || exit;" . "\n\r" . 'return ' . var_export( $config, true ) . '; ' . "\n\r";
|
103 |
+
if ( ! $wp_filesystem->put_contents( $config_file, $config_file_string ) ) {
|
104 |
+
return false;
|
105 |
+
}
|
106 |
+
|
107 |
+
return true;
|
108 |
+
}
|
109 |
+
//turn on / of wp cahe
|
110 |
+
public function toggle_caching( $status ) {
|
111 |
+
|
112 |
+
global $wp_filesystem;
|
113 |
+
if ( defined( 'WP_CACHE' ) && WP_CACHE === $status ) {
|
114 |
+
return;
|
115 |
+
}
|
116 |
+
|
117 |
+
// Lets look 4 levels deep for wp-config.php
|
118 |
+
$levels = 4;
|
119 |
+
|
120 |
+
$file = '/wp-config.php';
|
121 |
+
$config_path = false;
|
122 |
+
|
123 |
+
for ( $i = 1; $i <= 3; $i++ ) {
|
124 |
+
if ( $i > 1 ) {
|
125 |
+
$file = '/..' . $file;
|
126 |
+
}
|
127 |
+
|
128 |
+
if ( $wp_filesystem->exists( untrailingslashit( ABSPATH ) . $file ) ) {
|
129 |
+
$config_path = untrailingslashit( ABSPATH ) . $file;
|
130 |
+
break;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
// Couldn't find wp-config.php
|
135 |
+
if ( ! $config_path ) {
|
136 |
+
return false;
|
137 |
+
}
|
138 |
+
|
139 |
+
$config_file_string = $wp_filesystem->get_contents( $config_path );
|
140 |
+
|
141 |
+
// Config file is empty. Maybe couldn't read it?
|
142 |
+
if ( empty( $config_file_string ) ) {
|
143 |
+
return false;
|
144 |
+
}
|
145 |
+
|
146 |
+
$config_file = preg_split( "#(\n|\r)#", $config_file_string );
|
147 |
+
$line_key = false;
|
148 |
+
|
149 |
+
foreach ( $config_file as $key => $line ) {
|
150 |
+
if ( ! preg_match( '/^\s*define\(\s*(\'|")([A-Z_]+)(\'|")(.*)/', $line, $match ) ) {
|
151 |
+
continue;
|
152 |
+
}
|
153 |
+
|
154 |
+
if ( $match[2] == 'WP_CACHE' ) {
|
155 |
+
$line_key = $key;
|
156 |
+
}
|
157 |
+
}
|
158 |
+
|
159 |
+
if ( $line_key !== false ) {
|
160 |
+
unset( $config_file[ $line_key ] );
|
161 |
+
}
|
162 |
+
|
163 |
+
$status_string = ( $status ) ? 'true' : 'false';
|
164 |
+
|
165 |
+
array_shift( $config_file );
|
166 |
+
array_unshift( $config_file, '<?php', "define( 'WP_CACHE', $status_string ); " );
|
167 |
+
|
168 |
+
foreach ( $config_file as $key => $line ) {
|
169 |
+
if ( '' === $line ) {
|
170 |
+
unset( $config_file[$key] );
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
if ( ! $wp_filesystem->put_contents( $config_path, implode( PHP_EOL, $config_file ) ) ) {
|
175 |
+
return false;
|
176 |
+
}
|
177 |
+
|
178 |
+
return true;
|
179 |
+
}
|
180 |
+
//delete file for clean up
|
181 |
+
|
182 |
+
public function clean_up() {
|
183 |
+
|
184 |
+
global $wp_filesystem;
|
185 |
+
$file = untrailingslashit( WP_CONTENT_DIR ) . '/advanced-cache.php';
|
186 |
+
|
187 |
+
$ret = true;
|
188 |
+
|
189 |
+
if ( ! $wp_filesystem->delete( $file ) ) {
|
190 |
+
$ret = false;
|
191 |
+
}
|
192 |
+
|
193 |
+
$folder = untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze';
|
194 |
+
|
195 |
+
if ( ! $wp_filesystem->delete( $folder, true ) ) {
|
196 |
+
$ret = false;
|
197 |
+
}
|
198 |
+
|
199 |
+
$folder = untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze-minification';
|
200 |
+
|
201 |
+
if ( ! $wp_filesystem->delete( $folder, true ) ) {
|
202 |
+
$ret = false;
|
203 |
+
}
|
204 |
+
|
205 |
+
return $ret;
|
206 |
+
}
|
207 |
+
|
208 |
+
//delete config file
|
209 |
+
public function clean_config() {
|
210 |
+
|
211 |
+
global $wp_filesystem;
|
212 |
+
|
213 |
+
$folder = untrailingslashit( WP_CONTENT_DIR ) . '/breeze-config';
|
214 |
+
if ( ! $wp_filesystem->delete( $folder, true ) ) {
|
215 |
+
return false;
|
216 |
+
}
|
217 |
+
|
218 |
+
return true;
|
219 |
+
}
|
220 |
+
|
221 |
+
|
222 |
+
public static function factory() {
|
223 |
+
|
224 |
+
static $instance;
|
225 |
+
|
226 |
+
if ( ! $instance ) {
|
227 |
+
$instance = new self();
|
228 |
+
}
|
229 |
+
|
230 |
+
return $instance;
|
231 |
+
}
|
232 |
+
}
|
inc/cache/execute-cache.php
ADDED
@@ -0,0 +1,377 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Based on some work of https://github.com/tlovett1/simple-cache/blob/master/inc/dropins/file-based-page-cache.php
|
4 |
+
*/
|
5 |
+
defined('ABSPATH') || exit;
|
6 |
+
// Include and instantiate the class.
|
7 |
+
|
8 |
+
require_once 'Mobile-Detect-2.8.25/Mobile_Detect.php';
|
9 |
+
$detect = new \Cloudways\Breeze\Mobile_Detect\Mobile_Detect;
|
10 |
+
|
11 |
+
// Don't cache robots.txt or htacesss
|
12 |
+
if (strpos($_SERVER['REQUEST_URI'], 'robots.txt') !== false || strpos($_SERVER['REQUEST_URI'], '.htaccess') !== false) {
|
13 |
+
return;
|
14 |
+
}
|
15 |
+
|
16 |
+
// Don't cache non-GET requests
|
17 |
+
if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET') {
|
18 |
+
return;
|
19 |
+
}
|
20 |
+
|
21 |
+
$file_extension = $_SERVER['REQUEST_URI'];
|
22 |
+
$file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension);
|
23 |
+
$file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension));
|
24 |
+
|
25 |
+
// Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc.
|
26 |
+
if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) {
|
27 |
+
return;
|
28 |
+
}
|
29 |
+
|
30 |
+
$url_path = breeze_get_url_path();
|
31 |
+
$user_logged = false;
|
32 |
+
$filename = $url_path . 'guest';
|
33 |
+
// Don't cache
|
34 |
+
if (!empty($_COOKIE)) {
|
35 |
+
$wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_');
|
36 |
+
|
37 |
+
foreach ($_COOKIE as $key => $value) {
|
38 |
+
// Logged in!
|
39 |
+
if (strpos($key, 'wordpress_logged_in_') !== false) {
|
40 |
+
$user_logged = true;
|
41 |
+
}
|
42 |
+
|
43 |
+
}
|
44 |
+
|
45 |
+
if ($user_logged) {
|
46 |
+
foreach ($_COOKIE as $k => $v) {
|
47 |
+
if (strpos($k, 'wordpress_logged_in_') !== false) {
|
48 |
+
$nameuser = substr($v, 0, strpos($v, '|'));
|
49 |
+
$filename = $url_path . strtolower($nameuser);
|
50 |
+
}
|
51 |
+
}
|
52 |
+
}
|
53 |
+
if (!empty($_COOKIE['breeze_commented_posts'])) {
|
54 |
+
foreach ($_COOKIE['breeze_commented_posts'] as $path) {
|
55 |
+
if (rtrim($path, '/') === rtrim($_SERVER['REQUEST_URI'], '/')) {
|
56 |
+
// User commented on this post
|
57 |
+
return;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
//check disable cache for page
|
64 |
+
$domain = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || $_SERVER['SERVER_PORT'] == 443) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'];
|
65 |
+
//decode url with russian language
|
66 |
+
$current_url = $domain . rawurldecode($_SERVER['REQUEST_URI']);
|
67 |
+
$check_url = array();
|
68 |
+
$opts_config = $GLOBALS['breeze_config'];
|
69 |
+
if (!empty($opts_config['exclude_url'])) {
|
70 |
+
foreach ($opts_config['exclude_url'] as $v) {
|
71 |
+
if ($v && $v[0] == '/') {
|
72 |
+
//part url
|
73 |
+
if (preg_match('[\*]', $v) == 1) {
|
74 |
+
$v = substr($v, 0, strpos($v, "/(.*)"));
|
75 |
+
|
76 |
+
if (!empty($v)) {
|
77 |
+
if (strpos($current_url, $v) != false) {
|
78 |
+
$check_url[] = $current_url;
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
} else {
|
83 |
+
if (!empty($v)) {
|
84 |
+
if (strpos($current_url, $v) != false) {
|
85 |
+
$url = $current_url;
|
86 |
+
} else {
|
87 |
+
$homepage = $opts_config['homepage'];
|
88 |
+
$url = $homepage . $v;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
$check_url[] = $url;
|
93 |
+
}
|
94 |
+
} else {
|
95 |
+
if (preg_match('[\*]', $v) == 1) {
|
96 |
+
$v = substr($v, 0, strpos($v, "&(.*)"));
|
97 |
+
$v = substr($v, -10);
|
98 |
+
if (!empty($v)) {
|
99 |
+
if (strpos($current_url, $v) != false) {
|
100 |
+
$check_url[] = $current_url;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
} else {
|
104 |
+
//full url
|
105 |
+
$check_url[] = trim($v);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
}
|
109 |
+
}
|
110 |
+
//load cache
|
111 |
+
if (!in_array($current_url, $check_url)) {
|
112 |
+
$devices = $opts_config['cache_options'];
|
113 |
+
$X1 = '';
|
114 |
+
// Detect devices
|
115 |
+
if ($detect->isMobile() && !$detect->isTablet()) {
|
116 |
+
// The first X will be D for Desktop cache
|
117 |
+
// M for Mobile cache
|
118 |
+
// T for Tablet cache
|
119 |
+
if ((int)$devices['breeze-mobile-cache'] == 1) {
|
120 |
+
$X1 = 'D';
|
121 |
+
$filename .= '_breeze_cache_desktop';
|
122 |
+
}
|
123 |
+
if ((int)$devices['breeze-mobile-cache'] == 2) {
|
124 |
+
$X1 = 'M';
|
125 |
+
$filename .= '_breeze_cache_mobile';
|
126 |
+
}
|
127 |
+
|
128 |
+
} else {
|
129 |
+
if ((int)$devices['breeze-desktop-cache'] == 1) {
|
130 |
+
$X1 = 'D';
|
131 |
+
$filename .= '_breeze_cache_desktop';
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
breeze_serve_cache($filename, $url_path, $X1,$devices);
|
136 |
+
ob_start('breeze_cache');
|
137 |
+
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Cache output before it goes to the browser
|
142 |
+
*
|
143 |
+
* @param string $buffer
|
144 |
+
* @param int $flags
|
145 |
+
* @since 1.0
|
146 |
+
* @return string
|
147 |
+
*/
|
148 |
+
function breeze_cache($buffer, $flags)
|
149 |
+
{
|
150 |
+
|
151 |
+
require_once 'Mobile-Detect-2.8.25/Mobile_Detect.php';
|
152 |
+
$detect = new \Cloudways\Breeze\Mobile_Detect\Mobile_Detect;
|
153 |
+
//not cache per administrator if option disable optimization for admin users clicked
|
154 |
+
if (!empty($GLOBALS['breeze_config']) && (int)$GLOBALS['breeze_config']['disable_per_adminuser']) {
|
155 |
+
$current_user = wp_get_current_user();
|
156 |
+
if (in_array('administrator', $current_user->roles)) {
|
157 |
+
return $buffer;
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
if (strlen($buffer) < 255) {
|
162 |
+
return $buffer;
|
163 |
+
}
|
164 |
+
|
165 |
+
// Don't cache search, 404, or password protected
|
166 |
+
if (is_404() || is_search() || post_password_required()) {
|
167 |
+
return $buffer;
|
168 |
+
}
|
169 |
+
global $wp_filesystem;
|
170 |
+
if (empty($wp_filesystem)) {
|
171 |
+
require_once(ABSPATH . '/wp-admin/includes/file.php');
|
172 |
+
WP_Filesystem();
|
173 |
+
}
|
174 |
+
$url_path = breeze_get_url_path();
|
175 |
+
|
176 |
+
// Make sure we can read/write files and that proper folders exist
|
177 |
+
if (!$wp_filesystem->exists(untrailingslashit(WP_CONTENT_DIR) . '/cache')) {
|
178 |
+
if (!$wp_filesystem->mkdir(untrailingslashit(WP_CONTENT_DIR) . '/cache')) {
|
179 |
+
// Can not cache!
|
180 |
+
return $buffer;
|
181 |
+
}
|
182 |
+
}
|
183 |
+
|
184 |
+
if (!$wp_filesystem->exists(untrailingslashit(WP_CONTENT_DIR) . '/cache/breeze')) {
|
185 |
+
if (!$wp_filesystem->mkdir(untrailingslashit(WP_CONTENT_DIR) . '/cache/breeze')) {
|
186 |
+
// Can not cache!
|
187 |
+
return $buffer;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
if (!$wp_filesystem->exists(untrailingslashit(WP_CONTENT_DIR) . '/cache/breeze/' . md5($url_path))) {
|
192 |
+
if (!$wp_filesystem->mkdir(untrailingslashit(WP_CONTENT_DIR) . '/cache/breeze/' . md5($url_path))) {
|
193 |
+
// Can not cache!
|
194 |
+
return $buffer;
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
$path = untrailingslashit(WP_CONTENT_DIR) . '/cache/breeze/' . md5($url_path) . '/';
|
199 |
+
|
200 |
+
$modified_time = time(); // Make sure modified time is consistent
|
201 |
+
|
202 |
+
if (preg_match('#</html>#i', $buffer)) {
|
203 |
+
$buffer .= "\n<!-- Cache served by breeze CACHE - Last modified: " . gmdate('D, d M Y H:i:s', $modified_time) . " GMT -->\n";
|
204 |
+
}
|
205 |
+
$headers = array(
|
206 |
+
array(
|
207 |
+
'name' => 'Content-Length',
|
208 |
+
'value' => strlen($buffer)
|
209 |
+
),
|
210 |
+
array(
|
211 |
+
'name' => 'Content-Type',
|
212 |
+
'value' => 'text/html; charset=utf-8'
|
213 |
+
),
|
214 |
+
array(
|
215 |
+
'name' => 'Last-Modified',
|
216 |
+
'value' => gmdate('D, d M Y H:i:s', $modified_time) . ' GMT'
|
217 |
+
)
|
218 |
+
);
|
219 |
+
|
220 |
+
if(!isset($_SERVER['HTTP_X_VARNISH'])) {
|
221 |
+
$headers = array_merge(array(
|
222 |
+
array(
|
223 |
+
'name' => 'Expires',
|
224 |
+
'value' => 'Wed, 17 Aug 2005 00:00:00 GMT'
|
225 |
+
),
|
226 |
+
array(
|
227 |
+
'name' => 'Cache-Control',
|
228 |
+
'value' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0'
|
229 |
+
),
|
230 |
+
array(
|
231 |
+
'name' => 'Pragma',
|
232 |
+
'value' => 'no-cache'
|
233 |
+
)
|
234 |
+
));
|
235 |
+
}
|
236 |
+
|
237 |
+
$data = serialize(array('body' => $buffer, 'headers' => $headers));
|
238 |
+
//cache per users
|
239 |
+
if (is_user_logged_in()) {
|
240 |
+
$current_user = wp_get_current_user();
|
241 |
+
if ($current_user->user_login) {
|
242 |
+
$url_path .= $current_user->user_login;
|
243 |
+
}
|
244 |
+
} else {
|
245 |
+
$url_path .= 'guest';
|
246 |
+
}
|
247 |
+
$devices = $GLOBALS['breeze_config']['cache_options'];
|
248 |
+
// Detect devices
|
249 |
+
if ($detect->isMobile() && !$detect->isTablet()) {
|
250 |
+
if ($devices['breeze-mobile-cache'] == 1) {
|
251 |
+
$X1 = 'D';
|
252 |
+
$url_path .= '_breeze_cache_desktop';
|
253 |
+
}
|
254 |
+
if ($devices['breeze-mobile-cache'] == 2) {
|
255 |
+
$X1 = 'M';
|
256 |
+
$url_path .= '_breeze_cache_mobile';
|
257 |
+
}
|
258 |
+
} else {
|
259 |
+
if ($devices['breeze-desktop-cache'] == 1) {
|
260 |
+
$X1 = 'D';
|
261 |
+
$url_path .= '_breeze_cache_desktop';
|
262 |
+
}
|
263 |
+
}
|
264 |
+
|
265 |
+
if (strpos($url_path, '_breeze_cache_') !== false) {
|
266 |
+
if (!empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression']) && function_exists('gzencode')) {
|
267 |
+
$wp_filesystem->put_contents($path . md5($url_path . '/index.gzip.html') . '.php', $data);
|
268 |
+
$wp_filesystem->touch($path . md5($url_path . '/index.gzip.html') . '.php', $modified_time);
|
269 |
+
} else {
|
270 |
+
$wp_filesystem->put_contents($path . md5($url_path . '/index.html') . '.php', $data);
|
271 |
+
$wp_filesystem->touch($path . md5($url_path . '/index.html') . '.php', $modified_time);
|
272 |
+
}
|
273 |
+
} else {
|
274 |
+
return $buffer;
|
275 |
+
}
|
276 |
+
//set cache provider header if not exists cache file
|
277 |
+
header('Cache-Provider:CLOUDWAYS-CACHE-' . $X1 . 'C');
|
278 |
+
|
279 |
+
// Do not send this header in case we are behind a varnish proxy
|
280 |
+
if(!isset($_SERVER['HTTP_X_VARNISH'])) {
|
281 |
+
header('Cache-Control: no-cache'); // Check back every time to see if re-download is necessary
|
282 |
+
}
|
283 |
+
|
284 |
+
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $modified_time) . ' GMT');
|
285 |
+
|
286 |
+
if (function_exists('ob_gzhandler') && !empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'])) {
|
287 |
+
$ini_output_compression = ini_get('zlib.output_compression');
|
288 |
+
$array_values = array('1', 'On', 'on');
|
289 |
+
if (in_array($ini_output_compression, $array_values)) {
|
290 |
+
return $buffer;
|
291 |
+
} else {
|
292 |
+
return ob_gzhandler($buffer, $flags);
|
293 |
+
}
|
294 |
+
} else {
|
295 |
+
return $buffer;
|
296 |
+
}
|
297 |
+
}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Get URL path for caching
|
301 |
+
*
|
302 |
+
* @since 1.0
|
303 |
+
* @return string
|
304 |
+
*/
|
305 |
+
function breeze_get_url_path()
|
306 |
+
{
|
307 |
+
|
308 |
+
$host = (isset($_SERVER['HTTP_HOST'])) ? $_SERVER['HTTP_HOST'] : '';
|
309 |
+
|
310 |
+
return "http://" . rtrim($host, '/') . $_SERVER['REQUEST_URI'];
|
311 |
+
}
|
312 |
+
|
313 |
+
/**
|
314 |
+
* Optionally serve cache and exit
|
315 |
+
*
|
316 |
+
* @since 1.0
|
317 |
+
*/
|
318 |
+
function breeze_serve_cache($filename, $url_path, $X1,$opts)
|
319 |
+
{
|
320 |
+
if (strpos($filename, '_breeze_cache_') === false) {
|
321 |
+
return;
|
322 |
+
}
|
323 |
+
|
324 |
+
if (function_exists('gzencode') && !empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'])) {
|
325 |
+
$file_name = md5($filename . '/index.gzip.html') . '.php';
|
326 |
+
} else {
|
327 |
+
$file_name = md5($filename . '/index.html') . '.php';
|
328 |
+
}
|
329 |
+
|
330 |
+
|
331 |
+
$path = rtrim(WP_CONTENT_DIR, '/') . '/cache/breeze/' . md5($url_path) . '/' . $file_name;
|
332 |
+
|
333 |
+
$modified_time = (int)@filemtime($path);
|
334 |
+
|
335 |
+
if (!empty($opts['breeze-browser-cache']) &&!empty($modified_time) && !empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modified_time) {
|
336 |
+
header($_SERVER['SERVER_PROTOCOL'] . ' 304 Not Modified', true, 304);
|
337 |
+
exit;
|
338 |
+
}
|
339 |
+
|
340 |
+
if (@file_exists($path)) {
|
341 |
+
|
342 |
+
$cacheFile = file_get_contents($path);
|
343 |
+
|
344 |
+
|
345 |
+
if ($cacheFile != false) {
|
346 |
+
$datas = unserialize($cacheFile);
|
347 |
+
foreach ($datas['headers'] as $data) {
|
348 |
+
header($data['name'] . ': ' . $data['value']);
|
349 |
+
}
|
350 |
+
//set cache provider header
|
351 |
+
header('Cache-Provider:CLOUDWAYS-CACHE-' . $X1 . 'E');
|
352 |
+
|
353 |
+
$client_support_gzip = true;
|
354 |
+
|
355 |
+
//check gzip request from client
|
356 |
+
if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === false || strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate') === false)) {
|
357 |
+
$client_support_gzip = false;
|
358 |
+
}
|
359 |
+
|
360 |
+
if ($client_support_gzip && function_exists('gzdecode') && !empty($GLOBALS['breeze_config']['cache_options']['breeze-gzip-compression'])) {
|
361 |
+
//if file is zip
|
362 |
+
|
363 |
+
$content = gzencode($datas['body'], 9);
|
364 |
+
header('Content-Encoding: gzip');
|
365 |
+
header("cache-control: must-revalidate");
|
366 |
+
header('Content-Length: ' . strlen($content));
|
367 |
+
header('Vary: Accept-Encoding');
|
368 |
+
echo $content;
|
369 |
+
} else {
|
370 |
+
//render page cache
|
371 |
+
echo $datas['body'];
|
372 |
+
}
|
373 |
+
exit;
|
374 |
+
}
|
375 |
+
}
|
376 |
+
}
|
377 |
+
|
inc/cache/purge-cache.php
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
if ( ! defined( 'ABSPATH' ) ) exit;
|
22 |
+
class Breeze_PurgeCache {
|
23 |
+
|
24 |
+
public function set_action() {
|
25 |
+
add_action('pre_post_update', array($this, 'purge_post_on_update'), 10, 1);
|
26 |
+
add_action('save_post', array($this, 'purge_post_on_update'), 10, 1);
|
27 |
+
add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1);
|
28 |
+
add_action('comment_post', array($this, 'purge_post_on_new_comment'), 10, 3);
|
29 |
+
add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 2);
|
30 |
+
add_action('set_comment_cookies', array($this, 'set_comment_cookie_exceptions'), 10, 2);
|
31 |
+
}
|
32 |
+
|
33 |
+
/**
|
34 |
+
* When user posts a comment, set a cookie so we don't show them page cache
|
35 |
+
*
|
36 |
+
* @param WP_Comment $comment
|
37 |
+
* @param WP_User $user
|
38 |
+
* @since 1.3
|
39 |
+
*/
|
40 |
+
public function set_comment_cookie_exceptions($comment, $user) {
|
41 |
+
$config = get_option('breeze_basic_settings');
|
42 |
+
// File based caching only
|
43 |
+
if (!empty($config['breeze-active'])) {
|
44 |
+
|
45 |
+
$post_id = $comment->comment_post_ID;
|
46 |
+
|
47 |
+
setcookie('breeze_commented_posts[' . $post_id . ']', parse_url(get_permalink($post_id), PHP_URL_PATH), ( time() + HOUR_IN_SECONDS * 24 * 30));
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
// Automatically purge all file based page cache on post changes
|
52 |
+
public function purge_post_on_update($post_id) {
|
53 |
+
$post_type = get_post_type($post_id);
|
54 |
+
if (( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) || 'revision' === $post_type) {
|
55 |
+
return;
|
56 |
+
} elseif (!current_user_can('edit_post', $post_id) && (!defined('DOING_CRON') || !DOING_CRON )) {
|
57 |
+
return;
|
58 |
+
}
|
59 |
+
|
60 |
+
$config = get_option('breeze_basic_settings');
|
61 |
+
|
62 |
+
// File based caching only
|
63 |
+
if (!empty($config['breeze-active'])) {
|
64 |
+
self::breeze_cache_flush();
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
public function purge_post_on_new_comment($comment_ID, $approved, $commentdata) {
|
69 |
+
if (empty($approved)) {
|
70 |
+
return;
|
71 |
+
}
|
72 |
+
$config = get_option('breeze_basic_settings');
|
73 |
+
// File based caching only
|
74 |
+
if (!empty($config['breeze-active'])) {
|
75 |
+
$post_id = $commentdata['comment_post_ID'];
|
76 |
+
|
77 |
+
global $wp_filesystem;
|
78 |
+
|
79 |
+
if ( empty( $wp_filesystem ) ) {
|
80 |
+
require_once( ABSPATH . '/wp-admin/includes/file.php' );
|
81 |
+
WP_Filesystem();
|
82 |
+
}
|
83 |
+
|
84 |
+
$url_path = get_permalink($post_id);
|
85 |
+
if ( $wp_filesystem->exists( untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze/' . md5($url_path) ) ) {
|
86 |
+
$wp_filesystem->rmdir( untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze/' . md5($url_path), true );
|
87 |
+
}
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
// if a comments status changes, purge it's parent posts cache
|
92 |
+
public function purge_post_on_comment_status_change($comment_ID, $comment_status) {
|
93 |
+
$config = get_option('breeze_basic_settings');
|
94 |
+
|
95 |
+
// File based caching only
|
96 |
+
if (!empty($config['breeze-active'])) {
|
97 |
+
$comment = get_comment($comment_ID);
|
98 |
+
if(!empty($comment)){
|
99 |
+
$post_id = $comment->comment_post_ID;
|
100 |
+
|
101 |
+
global $wp_filesystem;
|
102 |
+
|
103 |
+
WP_Filesystem();
|
104 |
+
|
105 |
+
$url_path = get_permalink($post_id);
|
106 |
+
|
107 |
+
if ( $wp_filesystem->exists( untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze/' . md5($url_path) ) ) {
|
108 |
+
$wp_filesystem->rmdir( untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze/' . md5($url_path), true );
|
109 |
+
}
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
//clean cache
|
115 |
+
public static function breeze_cache_flush() {
|
116 |
+
global $wp_filesystem;
|
117 |
+
|
118 |
+
require_once( ABSPATH . 'wp-admin/includes/file.php');
|
119 |
+
|
120 |
+
WP_Filesystem();
|
121 |
+
|
122 |
+
$wp_filesystem->rmdir( untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze', true );
|
123 |
+
|
124 |
+
if ( function_exists( 'wp_cache_flush' ) ) {
|
125 |
+
wp_cache_flush();
|
126 |
+
}
|
127 |
+
}
|
128 |
+
|
129 |
+
//delete file for clean up
|
130 |
+
|
131 |
+
public function clean_up() {
|
132 |
+
|
133 |
+
global $wp_filesystem;
|
134 |
+
$file = untrailingslashit( WP_CONTENT_DIR ) . '/advanced-cache.php';
|
135 |
+
|
136 |
+
$ret = true;
|
137 |
+
|
138 |
+
if ( ! $wp_filesystem->delete( $file ) ) {
|
139 |
+
$ret = false;
|
140 |
+
}
|
141 |
+
|
142 |
+
$folder = untrailingslashit( WP_CONTENT_DIR ) . '/cache/breeze';
|
143 |
+
|
144 |
+
if ( ! $wp_filesystem->delete( $folder, true ) ) {
|
145 |
+
$ret = false;
|
146 |
+
}
|
147 |
+
|
148 |
+
return $ret;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Return an instance of the current class, create one if it doesn't exist
|
153 |
+
* @since 1.0
|
154 |
+
* @return object
|
155 |
+
*/
|
156 |
+
public static function factory() {
|
157 |
+
|
158 |
+
static $instance;
|
159 |
+
|
160 |
+
if (!$instance) {
|
161 |
+
$instance = new self();
|
162 |
+
$instance->set_action();
|
163 |
+
}
|
164 |
+
|
165 |
+
return $instance;
|
166 |
+
}
|
167 |
+
|
168 |
+
}
|
169 |
+
$settings = get_option('breeze_basic_settings');
|
170 |
+
if($settings['breeze-active']){
|
171 |
+
Breeze_PurgeCache::factory();
|
172 |
+
}
|
inc/cache/purge-per-time.php
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_PurgeCacheTime {
|
24 |
+
protected $timettl = false;
|
25 |
+
protected $normalcache = 0;
|
26 |
+
protected $varnishcache = 0;
|
27 |
+
public function __construct($settings = null)
|
28 |
+
{
|
29 |
+
$this->timettl = $settings['breeze-ttl'];
|
30 |
+
|
31 |
+
$this->normalcache = (int)$settings['breeze-active'];
|
32 |
+
|
33 |
+
$this->varnishcache = (int)$settings['breeze-varnish-purge'];
|
34 |
+
|
35 |
+
add_action( 'breeze_purge_cache', array( $this, 'schedule_varnish' ) );
|
36 |
+
add_action( 'init', array( $this, 'schedule_events' ) );
|
37 |
+
add_filter( 'cron_schedules', array( $this, 'filter_cron_schedules' ) );
|
38 |
+
|
39 |
+
}
|
40 |
+
// * Unschedule events
|
41 |
+
public function unschedule_events() {
|
42 |
+
$timestamp = wp_next_scheduled( 'breeze_purge_cache' );
|
43 |
+
|
44 |
+
wp_unschedule_event( $timestamp, 'breeze_purge_cache' );
|
45 |
+
}
|
46 |
+
// set up schedule_events
|
47 |
+
public function schedule_events() {
|
48 |
+
|
49 |
+
$timestamp = wp_next_scheduled( 'breeze_purge_cache' );
|
50 |
+
|
51 |
+
// Expire cache never
|
52 |
+
if ( isset( $this->timettl ) && (int)$this->timettl === 0 ) {
|
53 |
+
wp_unschedule_event( $timestamp, 'breeze_purge_cache' );
|
54 |
+
return;
|
55 |
+
}
|
56 |
+
|
57 |
+
if ( ! $timestamp ) {
|
58 |
+
wp_schedule_event( time(), 'breeze_varnish_time', 'breeze_purge_cache' );
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Add custom cron schedule
|
64 |
+
*/
|
65 |
+
public function filter_cron_schedules( $schedules ) {
|
66 |
+
if ( !empty( $this->timettl ) && is_numeric($this->timettl) && (int)$this->timettl > 0 ) {
|
67 |
+
$interval = $this->timettl * 60;
|
68 |
+
} else {
|
69 |
+
$interval = '86400'; // One day
|
70 |
+
}
|
71 |
+
|
72 |
+
$schedules['breeze_varnish_time'] = array(
|
73 |
+
'interval' => apply_filters( 'breeze_varnish_purge_interval', $interval ),
|
74 |
+
'display' => esc_html__( 'Cloudways Varnish Purge Interval', 'breeze' ),
|
75 |
+
);
|
76 |
+
|
77 |
+
return $schedules;
|
78 |
+
}
|
79 |
+
|
80 |
+
//execute purge varnish after time life
|
81 |
+
public function schedule_varnish(){
|
82 |
+
// Purge varnish cache
|
83 |
+
if($this->varnishcache){
|
84 |
+
$homepage = home_url().'/?breeze';
|
85 |
+
$main = new Breeze_PurgeVarnish();
|
86 |
+
$main->purge_cache($homepage);
|
87 |
+
}
|
88 |
+
// Purge normal cache
|
89 |
+
if($this->normalcache){
|
90 |
+
Breeze_PurgeCache::breeze_cache_flush();
|
91 |
+
}
|
92 |
+
|
93 |
+
}
|
94 |
+
|
95 |
+
public static function factory() {
|
96 |
+
static $instance;
|
97 |
+
if ( ! $instance ) {
|
98 |
+
$instance = new self();
|
99 |
+
}
|
100 |
+
return $instance;
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
$basic = get_option('breeze_basic_settings');
|
105 |
+
$varnish = get_option('breeze_varnish_cache');
|
106 |
+
//Enabled auto purge the varnish caching by time life
|
107 |
+
$params = array(
|
108 |
+
'breeze-active' => (isset($basic['breeze-active'])?(int)$basic['breeze-active']:0),
|
109 |
+
'breeze-ttl' => (isset($basic['breeze-ttl'])?(int)$basic['breeze-ttl']:0),
|
110 |
+
'breeze-varnish-purge' => (isset($varnish['auto-purge-varnish'])?(int)$varnish['auto-purge-varnish']:0),
|
111 |
+
);
|
112 |
+
|
113 |
+
if($params['breeze-active'] || $params['breeze-varnish-purge']){
|
114 |
+
$purgeTime = new Breeze_PurgeCacheTime($params);
|
115 |
+
}
|
116 |
+
|
inc/cache/purge-varnish.php
ADDED
@@ -0,0 +1,338 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_PurgeVarnish {
|
24 |
+
protected $blogId;
|
25 |
+
|
26 |
+
protected $urlsPurge = array();
|
27 |
+
|
28 |
+
protected $autoPurge = false;
|
29 |
+
|
30 |
+
protected $actions = array(
|
31 |
+
'switch_theme', // After a theme is changed
|
32 |
+
'save_post', // Save a post
|
33 |
+
'deleted_post', // Delete a post
|
34 |
+
'trashed_post', // Empty Trashed post
|
35 |
+
'edit_post', // Edit a post - includes leaving comments
|
36 |
+
'delete_attachment', // Delete an attachment - includes re-uploading
|
37 |
+
);
|
38 |
+
|
39 |
+
protected $actionsNoId = array('switch_theme');
|
40 |
+
|
41 |
+
public function __construct(){
|
42 |
+
global $blog_id;
|
43 |
+
$this->blogId = $blog_id;
|
44 |
+
$settings = get_option('breeze_varnish_cache');
|
45 |
+
//storage config
|
46 |
+
if(!empty($settings['auto-purge-varnish'])) $this->autoPurge = (int)$settings['auto-purge-varnish'];
|
47 |
+
|
48 |
+
add_action('init', array($this, 'init'));
|
49 |
+
}
|
50 |
+
|
51 |
+
public function init()
|
52 |
+
{
|
53 |
+
//Push urlsPurge
|
54 |
+
if($this->autoPurge){
|
55 |
+
if (!empty($this->actions)) {
|
56 |
+
//if enabled auto purge option , this action will start
|
57 |
+
foreach ($this->actions as $action) {
|
58 |
+
if (in_array($action, $this->actionsNoId)) {
|
59 |
+
add_action($action, function () {
|
60 |
+
array_push($this->urlsPurge, home_url() . '/?breeze');
|
61 |
+
});
|
62 |
+
} else {
|
63 |
+
add_action($action, array($this, 'purge_post'));
|
64 |
+
}
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
//Pust urlsPurge after comment
|
69 |
+
add_action('comment_post',array($this,'purge_post_on_comment'),10,3);
|
70 |
+
add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status'), 10, 2);
|
71 |
+
}
|
72 |
+
|
73 |
+
//Execute Purge
|
74 |
+
add_action('shutdown', array($this, 'breeze_execute_purge'));
|
75 |
+
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Execute Purge
|
80 |
+
*
|
81 |
+
*/
|
82 |
+
public function breeze_execute_purge()
|
83 |
+
{
|
84 |
+
$urlsPurge = array_unique($this->urlsPurge);
|
85 |
+
|
86 |
+
if (!empty($urlsPurge)) {
|
87 |
+
foreach ($urlsPurge as $url) {
|
88 |
+
$this->purge_cache($url);
|
89 |
+
}
|
90 |
+
} else {
|
91 |
+
$homepage = home_url().'/?breeze';
|
92 |
+
if (isset($_REQUEST['breeze_action']) && $_REQUEST['breeze_action'] == 'breeze_settings') {
|
93 |
+
if (isset($_POST['_breeze_nonce']) || wp_verify_nonce($_POST['_breeze_nonce'], 'breeze_settings')) {
|
94 |
+
//delete minify
|
95 |
+
Breeze_MinificationCache::clear_minification();
|
96 |
+
//clear normal cache
|
97 |
+
Breeze_PurgeCache::breeze_cache_flush();
|
98 |
+
//clear varnish cache
|
99 |
+
$this->purge_cache($homepage);
|
100 |
+
}
|
101 |
+
}
|
102 |
+
if(isset($_GET['breeze_purge']) && check_admin_referer('breeze_purge_cache')){
|
103 |
+
//clear varnish cache
|
104 |
+
$this->purge_cache($homepage);
|
105 |
+
//clear static cache
|
106 |
+
$size_cache = Breeze_Configuration::ajax_clean_cache($_GET['breeze_purge']);
|
107 |
+
|
108 |
+
if((int)$size_cache > 0){
|
109 |
+
echo '<div id="message-clear-cache-top" style="margin: 10px 0px 10px 0;padding: 10px;" class="notice notice-success" ><strong>'.__('OK ! Cache is cleaned: ','breeze') .$size_cache.__(' Kb static cache cleaned','breeze').'</strong></div>';
|
110 |
+
}else{
|
111 |
+
echo '<div id="message-clear-cache-top" style="margin: 10px 0px 10px 0;padding: 10px;" class="notice notice-success" ><strong>'.__('OK ! Cache file cleaned successfully','breeze').'</strong></div>';
|
112 |
+
}
|
113 |
+
}
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Purge varnish cache
|
119 |
+
*
|
120 |
+
*/
|
121 |
+
public function purge_cache($url)
|
122 |
+
{
|
123 |
+
$parseUrl = parse_url($url);
|
124 |
+
$pregex = '';
|
125 |
+
|
126 |
+
// Default method is URLPURGE to purge only one object, this method is specific to cloudways configuration
|
127 |
+
$purge_method = 'URLPURGE';
|
128 |
+
|
129 |
+
// Use PURGE method when purging all site
|
130 |
+
if (isset($parseUrl['query']) && ($parseUrl['query'] == 'breeze')) {
|
131 |
+
// The regex is not needed as cloudways configuration purge all the cache of the domain when a PURGE is done
|
132 |
+
$pregex = '.*';
|
133 |
+
$purge_method = 'PURGE';
|
134 |
+
}
|
135 |
+
|
136 |
+
// Determine the path
|
137 |
+
$path = '';
|
138 |
+
if (isset($parseUrl['path'])) {
|
139 |
+
$path = $parseUrl['path'];
|
140 |
+
}
|
141 |
+
|
142 |
+
// Determine the schema
|
143 |
+
$schema = 'http://';
|
144 |
+
if (isset($parseUrl['scheme'])) {
|
145 |
+
$schema = $parseUrl['scheme'] . '://';
|
146 |
+
}
|
147 |
+
|
148 |
+
// Determine the host
|
149 |
+
$host = $parseUrl['host'];
|
150 |
+
|
151 |
+
$config = get_option('breeze_varnish_cache');
|
152 |
+
$varnish_host = isset($config['breeze-varnish-server-ip'])?$config['breeze-varnish-server-ip']:'127.0.0.1';
|
153 |
+
|
154 |
+
$purgeme = $varnish_host . $path . $pregex;
|
155 |
+
|
156 |
+
if (!empty($parseUrl['query']) && $parseUrl['query'] != 'breeze') {
|
157 |
+
$purgeme .= '?' . $parseUrl['query'];
|
158 |
+
}
|
159 |
+
|
160 |
+
$request_args = array('method' => $purge_method, 'headers' => array('Host' => $host, 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'), 'sslverify' => false);
|
161 |
+
$response = wp_remote_request($schema . $purgeme, $request_args);
|
162 |
+
if(is_wp_error($response) || $response['response']['code']!='200') {
|
163 |
+
if($schema==='https://') {
|
164 |
+
$schema = 'http://';
|
165 |
+
}else{
|
166 |
+
$schema = 'https://';
|
167 |
+
}
|
168 |
+
$response = wp_remote_request($schema . $purgeme, $request_args);
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
//check permission
|
173 |
+
public function check_permission()
|
174 |
+
{
|
175 |
+
return (!is_multisite() && current_user_can('activate_plugins')) || current_user_can('manage_network') || (is_multisite() && !current_user_can('manage_network') && (SUBDOMAIN_INSTALL || (!SUBDOMAIN_INSTALL && (BLOG_ID_CURRENT_SITE != $this->blogId))));
|
176 |
+
}
|
177 |
+
/*
|
178 |
+
* Purge varnish cache with action if id post exists
|
179 |
+
*/
|
180 |
+
public function purge_post($postId)
|
181 |
+
{
|
182 |
+
$this->pushUrl($postId);
|
183 |
+
}
|
184 |
+
/*
|
185 |
+
* Purge varnish cache after comment
|
186 |
+
*/
|
187 |
+
public function purge_post_on_comment($comment_ID, $approved, $commentdata){
|
188 |
+
if (empty($approved)) {
|
189 |
+
return;
|
190 |
+
}
|
191 |
+
$postId = $commentdata['comment_post_ID'];
|
192 |
+
$this->pushUrl($postId);
|
193 |
+
}
|
194 |
+
/*
|
195 |
+
* if a comments status changes, purge varnish
|
196 |
+
*/
|
197 |
+
public function purge_post_on_comment_status($comment_ID, $comment_status){
|
198 |
+
$comment = get_comment($comment_ID);
|
199 |
+
if(!empty($comment)){
|
200 |
+
$postId = $comment->comment_post_ID;
|
201 |
+
$this->pushUrl($postId);
|
202 |
+
}
|
203 |
+
}
|
204 |
+
/*
|
205 |
+
* Push url from post ID
|
206 |
+
*/
|
207 |
+
public function pushUrl($postId){
|
208 |
+
// If this is a valid post we want to purge the post,
|
209 |
+
// the home page and any associated tags and categories
|
210 |
+
$valid_post_status = array('publish', 'private', 'trash');
|
211 |
+
$this_post_status = get_post_status($postId);
|
212 |
+
|
213 |
+
// Not all post types are created equal
|
214 |
+
$invalid_post_type = array('nav_menu_item', 'revision');
|
215 |
+
$noarchive_post_type = array('post', 'page');
|
216 |
+
$this_post_type = get_post_type($postId);
|
217 |
+
|
218 |
+
// Determine the route for the rest API
|
219 |
+
// This will need to be revisted if WP updates the version.
|
220 |
+
$rest_api_route = 'wp/v2';
|
221 |
+
|
222 |
+
// array to collect all our URLs
|
223 |
+
$listofurls = array();
|
224 |
+
|
225 |
+
// Verify we have a permalink and that we're a valid post status and a not an invalid post type
|
226 |
+
if (get_permalink($postId) == true && in_array($this_post_status, $valid_post_status) && !in_array($this_post_type, $invalid_post_type)) {
|
227 |
+
// Post URL
|
228 |
+
array_push($listofurls, get_permalink($postId));
|
229 |
+
|
230 |
+
// JSON API Permalink for the post based on type
|
231 |
+
// We only want to do this if the rest_base exists
|
232 |
+
$post_type_object = get_post_type_object($this_post_type);
|
233 |
+
if (isset($post_type_object->rest_base) && !empty($post_type_object->rest_base)) {
|
234 |
+
$rest_permalink = get_rest_url() . $rest_api_route . '/' . $post_type_object->rest_base . '/' . $postId . '/';
|
235 |
+
} elseif ($this_post_type == 'post') {
|
236 |
+
$rest_permalink = get_rest_url() . $rest_api_route . '/posts/' . $postId . '/';
|
237 |
+
} elseif ($this_post_type == 'page') {
|
238 |
+
$rest_permalink = get_rest_url() . $rest_api_route . '/views/' . $postId . '/';
|
239 |
+
}
|
240 |
+
if(isset($rest_permalink))
|
241 |
+
array_push($listofurls, $rest_permalink);
|
242 |
+
|
243 |
+
// Add in AMP permalink if Automattic's AMP is installed
|
244 |
+
if (function_exists('amp_get_permalink')) {
|
245 |
+
array_push($listofurls, amp_get_permalink($postId));
|
246 |
+
}
|
247 |
+
|
248 |
+
// Regular AMP url for posts
|
249 |
+
array_push($listofurls, get_permalink($postId) . 'amp/');
|
250 |
+
|
251 |
+
// Also clean URL for trashed post.
|
252 |
+
if ($this_post_status == 'trash') {
|
253 |
+
$trashpost = get_permalink($postId);
|
254 |
+
$trashpost = str_replace('__trashed', '', $trashpost);
|
255 |
+
array_push($listofurls, $trashpost, $trashpost . 'feed/');
|
256 |
+
}
|
257 |
+
|
258 |
+
// Category purge based on Donnacha's work in WP Super Cache
|
259 |
+
$categories = get_the_category($postId);
|
260 |
+
if ($categories) {
|
261 |
+
foreach ($categories as $cat) {
|
262 |
+
array_push($listofurls,
|
263 |
+
get_category_link($cat->term_id),
|
264 |
+
get_rest_url() . $rest_api_route . '/categories/' . $cat->term_id . '/'
|
265 |
+
);
|
266 |
+
}
|
267 |
+
}
|
268 |
+
// Tag purge based on Donnacha's work in WP Super Cache
|
269 |
+
$tags = get_the_tags($postId);
|
270 |
+
if ($tags) {
|
271 |
+
foreach ($tags as $tag) {
|
272 |
+
array_push($listofurls,
|
273 |
+
get_tag_link($tag->term_id),
|
274 |
+
get_rest_url() . $rest_api_route . '/tags/' . $tag->term_id . '/'
|
275 |
+
);
|
276 |
+
}
|
277 |
+
}
|
278 |
+
|
279 |
+
// Author URL
|
280 |
+
$author_id = get_post_field('post_author', $postId);
|
281 |
+
array_push($listofurls,
|
282 |
+
get_author_posts_url($author_id),
|
283 |
+
get_author_feed_link($author_id),
|
284 |
+
get_rest_url() . $rest_api_route . '/users/' . $author_id . '/'
|
285 |
+
);
|
286 |
+
|
287 |
+
|
288 |
+
// Archives and their feeds
|
289 |
+
if ($this_post_type && !in_array($this_post_type, $noarchive_post_type)) {
|
290 |
+
array_push($listofurls,
|
291 |
+
get_post_type_archive_link(get_post_type($postId)),
|
292 |
+
get_post_type_archive_feed_link(get_post_type($postId))
|
293 |
+
// Need to add in JSON?
|
294 |
+
);
|
295 |
+
}
|
296 |
+
|
297 |
+
|
298 |
+
// Feeds
|
299 |
+
array_push($listofurls,
|
300 |
+
get_bloginfo_rss('rdf_url'),
|
301 |
+
get_bloginfo_rss('rss_url'),
|
302 |
+
get_bloginfo_rss('rss2_url'),
|
303 |
+
get_bloginfo_rss('atom_url'),
|
304 |
+
get_bloginfo_rss('comments_rss2_url'),
|
305 |
+
get_post_comments_feed_link($postId)
|
306 |
+
);
|
307 |
+
|
308 |
+
// Home Pages and (if used) posts page
|
309 |
+
array_push($listofurls,
|
310 |
+
get_rest_url(),
|
311 |
+
home_url() . '/'
|
312 |
+
);
|
313 |
+
|
314 |
+
if (get_option('show_on_front') == 'page') {
|
315 |
+
// Ensure we have a page_for_posts setting to avoid empty URL
|
316 |
+
if (get_option('page_for_posts')) {
|
317 |
+
array_push($listofurls, get_permalink(get_option('page_for_posts')));
|
318 |
+
}
|
319 |
+
}
|
320 |
+
|
321 |
+
} else {
|
322 |
+
// Nothing
|
323 |
+
return;
|
324 |
+
}
|
325 |
+
|
326 |
+
// Now flush all the URLs we've collected provided the array isn't empty
|
327 |
+
if (!empty($listofurls)) {
|
328 |
+
$purgeurls = array_unique($listofurls, SORT_REGULAR);
|
329 |
+
|
330 |
+
foreach ($purgeurls as $url) {
|
331 |
+
array_push($this->urlsPurge, $url);
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
}
|
336 |
+
}
|
337 |
+
|
338 |
+
new Breeze_PurgeVarnish();
|
inc/cdn-integration/breeze-cdn-integration.php
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_CDN_Integration{
|
24 |
+
|
25 |
+
public function __construct(){
|
26 |
+
add_action('template_redirect', array($this,'handle_rewrite_cdn'));
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Execute rewrite cdn
|
31 |
+
*/
|
32 |
+
public function handle_rewrite_cdn(){
|
33 |
+
$cdn_integration = get_option('breeze_cdn_integration');
|
34 |
+
|
35 |
+
if(empty($cdn_integration) || empty($cdn_integration['cdn-active'])){
|
36 |
+
return;
|
37 |
+
}
|
38 |
+
|
39 |
+
if($cdn_integration['cdn-url'] == ''){
|
40 |
+
return;
|
41 |
+
}
|
42 |
+
|
43 |
+
if(get_option('home') == $cdn_integration['cdn-url']){
|
44 |
+
return;
|
45 |
+
}
|
46 |
+
|
47 |
+
$rewrite = new Breeze_CDN_Rewrite($cdn_integration);
|
48 |
+
|
49 |
+
//rewrite CDN Url to html raw
|
50 |
+
// ob_start(array(&$rewrite,'rewrite'));
|
51 |
+
add_filter('breeze_cdn_content_return',array(&$rewrite,'rewrite'));
|
52 |
+
|
53 |
+
}
|
54 |
+
|
55 |
+
public static function instance(){
|
56 |
+
new self();
|
57 |
+
}
|
58 |
+
}
|
inc/cdn-integration/breeze-cdn-rewrite.php
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_CDN_Rewrite {
|
24 |
+
private $blog_url = null;
|
25 |
+
private $cdn_url = null;
|
26 |
+
private $dirs = array();
|
27 |
+
private $excludes = array();
|
28 |
+
private $relative = false;
|
29 |
+
|
30 |
+
public function __construct(&$option){
|
31 |
+
//storage option
|
32 |
+
$this->blog_url = get_option('home');
|
33 |
+
$this->cdn_url = $option['cdn-url'];
|
34 |
+
$this->dirs = $option['cdn-content'];
|
35 |
+
$this->excludes = $option['cdn-exclude-content'];
|
36 |
+
$this->relative = $option['cdn-relative-path'];
|
37 |
+
}
|
38 |
+
/*
|
39 |
+
* Replace cdn on html raw
|
40 |
+
*/
|
41 |
+
public function rewrite($content){
|
42 |
+
|
43 |
+
$blog_url = quotemeta($this->blog_url);
|
44 |
+
|
45 |
+
// get dir scope in regex format
|
46 |
+
$dirs = $this->get_dir_scope();
|
47 |
+
|
48 |
+
// regex rule start
|
49 |
+
$regex_rule = '#(?<=[(\"\'])';
|
50 |
+
|
51 |
+
// check if relative paths
|
52 |
+
if ($this->relative) {
|
53 |
+
$regex_rule .= '(?:'.$blog_url.')?';
|
54 |
+
} else {
|
55 |
+
$regex_rule .= $blog_url;
|
56 |
+
}
|
57 |
+
|
58 |
+
// regex rule end
|
59 |
+
$regex_rule .= '/(?:((?:'.$dirs.')[^\"\')]+)|([^/\"\']+\.[^/\"\')]+))(?=[\"\')])#';
|
60 |
+
|
61 |
+
// call the cdn rewriter callback
|
62 |
+
$new_content = preg_replace_callback($regex_rule, array(&$this, 'replace_cdn_url'), $content);
|
63 |
+
|
64 |
+
return $new_content;
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* get directory scope
|
69 |
+
*/
|
70 |
+
|
71 |
+
protected function get_dir_scope() {
|
72 |
+
// default
|
73 |
+
if (empty($this->dirs) || count($this->dirs) < 1) {
|
74 |
+
return 'wp\-content|wp\-includes';
|
75 |
+
}
|
76 |
+
|
77 |
+
return implode('|', array_map('quotemeta', array_map('trim', $this->dirs)));
|
78 |
+
}
|
79 |
+
|
80 |
+
/*
|
81 |
+
* Replace cdn url to root url
|
82 |
+
*/
|
83 |
+
protected function replace_cdn_url($match){
|
84 |
+
//return file type or directories excluded
|
85 |
+
if($this->excludes_check($match[0])){
|
86 |
+
return $match[0];
|
87 |
+
}
|
88 |
+
|
89 |
+
$parseUrl = parse_url($this->blog_url);
|
90 |
+
$schema = 'http://';
|
91 |
+
if(isset($parseUrl['scheme'])){
|
92 |
+
$scheme = $parseUrl['scheme'].'://';
|
93 |
+
}
|
94 |
+
$host = $parseUrl['host'];
|
95 |
+
//get domain
|
96 |
+
$domain = $scheme.$host;
|
97 |
+
|
98 |
+
// check if not a relative path
|
99 |
+
if (!$this->relative || strstr($match[0], $this->blog_url)) {
|
100 |
+
return str_replace($domain, $this->cdn_url, $match[0]);
|
101 |
+
}
|
102 |
+
|
103 |
+
return $this->cdn_url . $match[0];
|
104 |
+
|
105 |
+
}
|
106 |
+
/*
|
107 |
+
* Check excludes assets
|
108 |
+
*/
|
109 |
+
protected function excludes_check($dir){
|
110 |
+
if(!empty($this->excludes)){
|
111 |
+
foreach ($this->excludes as $exclude){
|
112 |
+
if(stristr($dir, $exclude) != false){
|
113 |
+
return true;
|
114 |
+
}
|
115 |
+
}
|
116 |
+
}
|
117 |
+
return false;
|
118 |
+
}
|
119 |
+
}
|
inc/minification/breeze-minification-base.php
ADDED
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Based on some work of autoptimize plugin
|
4 |
+
*/
|
5 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
6 |
+
|
7 |
+
abstract class Breeze_MinificationBase {
|
8 |
+
protected $content = '';
|
9 |
+
protected $tagWarning = false;
|
10 |
+
|
11 |
+
public function __construct($content) {
|
12 |
+
$this->content = $content;
|
13 |
+
}
|
14 |
+
|
15 |
+
//Reads the page and collects tags
|
16 |
+
abstract public function read($justhead);
|
17 |
+
|
18 |
+
//Joins and optimizes collected things
|
19 |
+
abstract public function minify();
|
20 |
+
|
21 |
+
//Caches the things
|
22 |
+
abstract public function cache();
|
23 |
+
|
24 |
+
//Returns the content
|
25 |
+
abstract public function getcontent();
|
26 |
+
|
27 |
+
//Converts an URL to a full path
|
28 |
+
protected function getpath($url) {
|
29 |
+
$url=apply_filters( 'breeze_filter_cssjs_alter_url', $url);
|
30 |
+
|
31 |
+
if (strpos($url,'%')!==false) {
|
32 |
+
$url=urldecode($url);
|
33 |
+
}
|
34 |
+
|
35 |
+
// normalize
|
36 |
+
if (strpos($url,'//')===0) {
|
37 |
+
if (is_ssl()) {
|
38 |
+
$url = "https:".$url;
|
39 |
+
} else {
|
40 |
+
$url = "http:".$url;
|
41 |
+
}
|
42 |
+
} else if ((strpos($url,'//')===false) && (strpos($url,parse_url(breeze_WP_SITE_URL,PHP_URL_HOST))===false)) {
|
43 |
+
$url = breeze_WP_SITE_URL.$url;
|
44 |
+
}
|
45 |
+
|
46 |
+
// first check; hostname wp site should be hostname of url
|
47 |
+
$thisHost=@parse_url($url,PHP_URL_HOST);
|
48 |
+
if ($thisHost!==parse_url(breeze_WP_SITE_URL,PHP_URL_HOST)) {
|
49 |
+
/*
|
50 |
+
* first try to get all domains from WPML (if available)
|
51 |
+
* then explicitely declare $this->cdn_url as OK as well
|
52 |
+
* then apply own filter autoptimize_filter_cssjs_multidomain takes an array of hostnames
|
53 |
+
* each item in that array will be considered part of the same WP multisite installation
|
54 |
+
*/
|
55 |
+
$multidomains = array();
|
56 |
+
|
57 |
+
$multidomainsWPML = apply_filters('wpml_setting', array(), 'language_domains');
|
58 |
+
if (!empty($multidomainsWPML)) {
|
59 |
+
$multidomains = array_map(array($this,"ao_getDomain"),$multidomainsWPML);
|
60 |
+
}
|
61 |
+
|
62 |
+
if (!empty($this->cdn_url)) {
|
63 |
+
$multidomains[]=parse_url($this->cdn_url,PHP_URL_HOST);
|
64 |
+
}
|
65 |
+
|
66 |
+
$multidomains = apply_filters('breeze_filter_cssjs_multidomain', $multidomains);
|
67 |
+
|
68 |
+
if (!empty($multidomains)) {
|
69 |
+
if (in_array($thisHost,$multidomains)) {
|
70 |
+
$url=str_replace($thisHost, parse_url(breeze_WP_SITE_URL,PHP_URL_HOST), $url);
|
71 |
+
} else {
|
72 |
+
return false;
|
73 |
+
}
|
74 |
+
} else {
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
// try to remove "wp root url" from url while not minding http<>https
|
80 |
+
$tmp_ao_root = preg_replace('/https?/','',breeze_WP_ROOT_URL);
|
81 |
+
$tmp_url = preg_replace('/https?/','',$url);
|
82 |
+
$path = str_replace($tmp_ao_root,'',$tmp_url);
|
83 |
+
|
84 |
+
// final check; if path starts with :// or //, this is not a URL in the WP context and we have to assume we can't aggregate
|
85 |
+
if (preg_match('#^:?//#',$path)) {
|
86 |
+
/** External script/css (adsense, etc) */
|
87 |
+
return false;
|
88 |
+
}
|
89 |
+
|
90 |
+
$path = str_replace('//','/',BREEZE_ROOT_DIR.$path);
|
91 |
+
return $path;
|
92 |
+
}
|
93 |
+
|
94 |
+
// needed for WPML-filter
|
95 |
+
protected function ao_getDomain($in) {
|
96 |
+
// make sure the url starts with something vaguely resembling a protocol
|
97 |
+
if ((strpos($in,"http")!==0) && (strpos($in,"//")!==0)) {
|
98 |
+
$in="http://".$in;
|
99 |
+
}
|
100 |
+
|
101 |
+
// do the actual parse_url
|
102 |
+
$out = parse_url($in,PHP_URL_HOST);
|
103 |
+
|
104 |
+
// fallback if parse_url does not understand the url is in fact a url
|
105 |
+
if (empty($out)) $out=$in;
|
106 |
+
|
107 |
+
return $out;
|
108 |
+
}
|
109 |
+
|
110 |
+
|
111 |
+
// logger
|
112 |
+
protected function ao_logger($logmsg,$appendHTML=true) {
|
113 |
+
if ($appendHTML) {
|
114 |
+
$logmsg="<!--noptimize--><!-- ".$logmsg." --><!--/noptimize-->";
|
115 |
+
$this->content.=$logmsg;
|
116 |
+
} else {
|
117 |
+
error_log("Error: ".$logmsg);
|
118 |
+
}
|
119 |
+
}
|
120 |
+
|
121 |
+
// hide everything between noptimize-comment tags
|
122 |
+
protected function hide_noptimize($noptimize_in) {
|
123 |
+
if ( preg_match( '/<!--\s?noptimize\s?-->/', $noptimize_in ) ) {
|
124 |
+
$noptimize_out = preg_replace_callback(
|
125 |
+
'#<!--\s?noptimize\s?-->.*?<!--\s?/\s?noptimize\s?-->#is',
|
126 |
+
create_function(
|
127 |
+
'$matches',
|
128 |
+
'return "%%NOPTIMIZE".breeze_HASH."%%".base64_encode($matches[0])."%%NOPTIMIZE%%";'
|
129 |
+
),
|
130 |
+
$noptimize_in
|
131 |
+
);
|
132 |
+
} else {
|
133 |
+
$noptimize_out = $noptimize_in;
|
134 |
+
}
|
135 |
+
return $noptimize_out;
|
136 |
+
}
|
137 |
+
|
138 |
+
// unhide noptimize-tags
|
139 |
+
protected function restore_noptimize($noptimize_in) {
|
140 |
+
if ( strpos( $noptimize_in, '%%NOPTIMIZE%%' ) !== false ) {
|
141 |
+
$noptimize_out = preg_replace_callback(
|
142 |
+
'#%%NOPTIMIZE'.breeze_HASH.'%%(.*?)%%NOPTIMIZE%%#is',
|
143 |
+
create_function(
|
144 |
+
'$matches',
|
145 |
+
'return base64_decode($matches[1]);'
|
146 |
+
),
|
147 |
+
$noptimize_in
|
148 |
+
);
|
149 |
+
} else {
|
150 |
+
$noptimize_out = $noptimize_in;
|
151 |
+
}
|
152 |
+
return $noptimize_out;
|
153 |
+
}
|
154 |
+
|
155 |
+
protected function hide_iehacks($iehacks_in) {
|
156 |
+
if ( strpos( $iehacks_in, '<!--[if' ) !== false ) {
|
157 |
+
$iehacks_out = preg_replace_callback(
|
158 |
+
'#<!--\[if.*?\[endif\]-->#is',
|
159 |
+
create_function(
|
160 |
+
'$matches',
|
161 |
+
'return "%%IEHACK".breeze_HASH."%%".base64_encode($matches[0])."%%IEHACK%%";'
|
162 |
+
),
|
163 |
+
$iehacks_in
|
164 |
+
);
|
165 |
+
} else {
|
166 |
+
$iehacks_out = $iehacks_in;
|
167 |
+
}
|
168 |
+
return $iehacks_out;
|
169 |
+
}
|
170 |
+
|
171 |
+
protected function restore_iehacks($iehacks_in) {
|
172 |
+
if ( strpos( $iehacks_in, '%%IEHACK%%' ) !== false ) {
|
173 |
+
$iehacks_out = preg_replace_callback(
|
174 |
+
'#%%IEHACK'.breeze_HASH.'%%(.*?)%%IEHACK%%#is',
|
175 |
+
create_function(
|
176 |
+
'$matches',
|
177 |
+
'return base64_decode($matches[1]);'
|
178 |
+
),
|
179 |
+
$iehacks_in
|
180 |
+
);
|
181 |
+
} else {
|
182 |
+
$iehacks_out=$iehacks_in;
|
183 |
+
}
|
184 |
+
return $iehacks_out;
|
185 |
+
}
|
186 |
+
|
187 |
+
protected function hide_comments($comments_in) {
|
188 |
+
if ( strpos( $comments_in, '<!--' ) !== false ) {
|
189 |
+
$comments_out = preg_replace_callback(
|
190 |
+
'#<!--.*?-->#is',
|
191 |
+
create_function(
|
192 |
+
'$matches',
|
193 |
+
'return "%%COMMENTS".breeze_HASH."%%".base64_encode($matches[0])."%%COMMENTS%%";'
|
194 |
+
),
|
195 |
+
$comments_in
|
196 |
+
);
|
197 |
+
} else {
|
198 |
+
$comments_out = $comments_in;
|
199 |
+
}
|
200 |
+
return $comments_out;
|
201 |
+
}
|
202 |
+
|
203 |
+
protected function restore_comments($comments_in) {
|
204 |
+
if ( strpos( $comments_in, '%%COMMENTS%%' ) !== false ) {
|
205 |
+
$comments_out = preg_replace_callback(
|
206 |
+
'#%%COMMENTS'.breeze_HASH.'%%(.*?)%%COMMENTS%%#is',
|
207 |
+
create_function(
|
208 |
+
'$matches',
|
209 |
+
'return base64_decode($matches[1]);'
|
210 |
+
),
|
211 |
+
$comments_in
|
212 |
+
);
|
213 |
+
} else {
|
214 |
+
$comments_out=$comments_in;
|
215 |
+
}
|
216 |
+
return $comments_out;
|
217 |
+
}
|
218 |
+
|
219 |
+
protected function url_replace_cdn( $url ) {
|
220 |
+
$cdn_url = apply_filters( 'breeze_filter_base_cdnurl', $this->cdn_url );
|
221 |
+
if ( !empty($cdn_url) ) {
|
222 |
+
// secondly prepend domain-less absolute URL's
|
223 |
+
if ( ( substr( $url, 0, 1 ) === '/' ) && ( substr( $url, 1, 1 ) !== '/' ) ) {
|
224 |
+
$url = rtrim( $cdn_url, '/' ) . $url;
|
225 |
+
} else {
|
226 |
+
// get wordpress base URL
|
227 |
+
$WPSiteBreakdown = parse_url( breeze_WP_SITE_URL );
|
228 |
+
$WPBaseUrl = $WPSiteBreakdown['scheme'] . '://' . $WPSiteBreakdown['host'];
|
229 |
+
if ( ! empty( $WPSiteBreakdown['port'] ) ) {
|
230 |
+
$WPBaseUrl .= ":" . $WPSiteBreakdown['port'];
|
231 |
+
}
|
232 |
+
// three: replace full url's with scheme
|
233 |
+
$tmp_url = str_replace( $WPBaseUrl, rtrim( $cdn_url, '/' ), $url );
|
234 |
+
if ( $tmp_url === $url ) {
|
235 |
+
// last attempt; replace scheme-less URL's
|
236 |
+
$url = str_replace( preg_replace( '/https?:/', '', $WPBaseUrl ), rtrim( $cdn_url, '/' ), $url );
|
237 |
+
} else {
|
238 |
+
$url = $tmp_url;
|
239 |
+
}
|
240 |
+
}
|
241 |
+
}
|
242 |
+
|
243 |
+
// allow API filter to take alter after CDN replacement
|
244 |
+
$url = apply_filters( 'breeze_filter_base_replace_cdn', $url );
|
245 |
+
return $url;
|
246 |
+
}
|
247 |
+
|
248 |
+
protected function inject_in_html($payload,$replaceTag) {
|
249 |
+
if (strpos($this->content,$replaceTag[0])!== false) {
|
250 |
+
if ($replaceTag[1]==="after") {
|
251 |
+
$replaceBlock=$replaceTag[0].$payload;
|
252 |
+
} else if ($replaceTag[1]==="replace"){
|
253 |
+
$replaceBlock=$payload;
|
254 |
+
} else {
|
255 |
+
$replaceBlock=$payload.$replaceTag[0];
|
256 |
+
}
|
257 |
+
$this->content = substr_replace($this->content,$replaceBlock,strpos($this->content,$replaceTag[0]),strlen($replaceTag[0]));
|
258 |
+
} else {
|
259 |
+
$this->content .= $payload;
|
260 |
+
if (!$this->tagWarning) {
|
261 |
+
$this->content .= "<!--noptimize--><!-- breeze found a problem with the HTML in your Theme, tag ".$replaceTag[0]." missing --><!--/noptimize-->";
|
262 |
+
$this->tagWarning=true;
|
263 |
+
}
|
264 |
+
}
|
265 |
+
}
|
266 |
+
|
267 |
+
protected function isremovable($tag, $removables) {
|
268 |
+
foreach ($removables as $match) {
|
269 |
+
if (strpos($tag,$match)!==false) {
|
270 |
+
return true;
|
271 |
+
}
|
272 |
+
}
|
273 |
+
return false;
|
274 |
+
}
|
275 |
+
|
276 |
+
// inject already minified code in optimized JS/CSS
|
277 |
+
protected function inject_minified($in) {
|
278 |
+
if ( strpos( $in, '%%INJECTLATER%%' ) !== false ) {
|
279 |
+
$out = preg_replace_callback(
|
280 |
+
'#%%INJECTLATER'.breeze_HASH.'%%(.*?)%%INJECTLATER%%#is',
|
281 |
+
create_function(
|
282 |
+
'$matches',
|
283 |
+
'$filepath=base64_decode(strtok($matches[1],"|"));
|
284 |
+
$filecontent=file_get_contents($filepath);
|
285 |
+
|
286 |
+
// remove BOM
|
287 |
+
$filecontent = preg_replace("#\x{EF}\x{BB}\x{BF}#","",$filecontent);
|
288 |
+
|
289 |
+
// remove comments and blank lines
|
290 |
+
if (substr($filepath,-3,3)===".js") {
|
291 |
+
$filecontent=preg_replace("#^\s*\/\/.*$#Um","",$filecontent);
|
292 |
+
}
|
293 |
+
|
294 |
+
$filecontent=preg_replace("#^\s*\/\*[^!].*\*\/\s?#Us","",$filecontent);
|
295 |
+
$filecontent=preg_replace("#(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+#", "\n", $filecontent);
|
296 |
+
|
297 |
+
// specific stuff for JS-files
|
298 |
+
if (substr($filepath,-3,3)===".js") {
|
299 |
+
if ((substr($filecontent,-1,1)!==";")&&(substr($filecontent,-1,1)!=="}")) {
|
300 |
+
$filecontent.=";";
|
301 |
+
}
|
302 |
+
|
303 |
+
if (get_option("breeze_js_trycatch")==="on") {
|
304 |
+
$filecontent="try{".$filecontent."}catch(e){}";
|
305 |
+
}
|
306 |
+
} else if ((substr($filepath,-4,4)===".css")) {
|
307 |
+
$filecontent=Breeze_MinificationStyles::fixurls($filepath,$filecontent);
|
308 |
+
}
|
309 |
+
|
310 |
+
// return
|
311 |
+
return "\n".$filecontent;'
|
312 |
+
),
|
313 |
+
$in
|
314 |
+
);
|
315 |
+
} else {
|
316 |
+
$out = $in;
|
317 |
+
}
|
318 |
+
return $out;
|
319 |
+
}
|
320 |
+
}
|
inc/minification/breeze-minification-cache.php
ADDED
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
3 |
+
/*
|
4 |
+
* Based on some work of autoptimize plugin
|
5 |
+
*/
|
6 |
+
class Breeze_MinificationCache {
|
7 |
+
private $filename;
|
8 |
+
private $mime;
|
9 |
+
private $cachedir;
|
10 |
+
private $delayed;
|
11 |
+
|
12 |
+
public function __construct($md5,$ext='php') {
|
13 |
+
$this->cachedir = BREEZE_MINIFICATION_CACHE;
|
14 |
+
if(is_multisite()){
|
15 |
+
$blog_id = get_current_blog_id();
|
16 |
+
$this->cachedir = BREEZE_MINIFICATION_CACHE.$blog_id . '/';
|
17 |
+
}
|
18 |
+
$this->delayed = BREEZE_CACHE_DELAY;
|
19 |
+
$this->nogzip = BREEZE_CACHE_NOGZIP;
|
20 |
+
if($this->nogzip == false) {
|
21 |
+
$this->filename = BREEZE_CACHEFILE_PREFIX.$md5.'.php';
|
22 |
+
} else {
|
23 |
+
if (in_array($ext, array("js","css"))) {
|
24 |
+
$this->filename = $ext.'/'.BREEZE_CACHEFILE_PREFIX.$md5.'.'.$ext;
|
25 |
+
} else {
|
26 |
+
$this->filename = '/'.BREEZE_CACHEFILE_PREFIX.$md5.'.'.$ext;
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
|
31 |
+
}
|
32 |
+
|
33 |
+
public function check() {
|
34 |
+
if(!file_exists($this->cachedir.$this->filename)) {
|
35 |
+
// No cached file, sorry
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
// Cache exists!
|
39 |
+
return true;
|
40 |
+
}
|
41 |
+
public function retrieve() {
|
42 |
+
if($this->check()) {
|
43 |
+
if($this->nogzip == false) {
|
44 |
+
return file_get_contents($this->cachedir.$this->filename.'.none');
|
45 |
+
} else {
|
46 |
+
return file_get_contents($this->cachedir.$this->filename);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
return false;
|
50 |
+
}
|
51 |
+
public function cache($code,$mime) {
|
52 |
+
if($this->nogzip == false) {
|
53 |
+
$file = ($this->delayed ? 'delayed.php' : 'default.php');
|
54 |
+
$phpcode = file_get_contents(BREEZE_PLUGIN_DIR.'/inc/minification/config/'.$file);
|
55 |
+
$phpcode = str_replace(array('%%CONTENT%%','exit;'),array($mime,''),$phpcode);
|
56 |
+
file_put_contents($this->cachedir.$this->filename,$phpcode, LOCK_EX);
|
57 |
+
file_put_contents($this->cachedir.$this->filename.'.none',$code, LOCK_EX);
|
58 |
+
if(!$this->delayed) {
|
59 |
+
// Compress now!
|
60 |
+
file_put_contents($this->cachedir.$this->filename.'.deflate',gzencode($code,9,FORCE_DEFLATE), LOCK_EX);
|
61 |
+
file_put_contents($this->cachedir.$this->filename.'.gzip',gzencode($code,9,FORCE_GZIP), LOCK_EX);
|
62 |
+
}
|
63 |
+
} else {
|
64 |
+
// Write code to cache without doing anything else
|
65 |
+
file_put_contents($this->cachedir.$this->filename,$code, LOCK_EX);
|
66 |
+
}
|
67 |
+
}
|
68 |
+
public function getname() {
|
69 |
+
apply_filters('breeze_filter_cache_getname',breeze_CACHE_URL.$this->filename);
|
70 |
+
return $this->filename;
|
71 |
+
}
|
72 |
+
//create folder cache
|
73 |
+
public static function create_cache_minification_folder(){
|
74 |
+
if(!defined('BREEZE_MINIFICATION_CACHE')) {
|
75 |
+
// We didn't set a cache
|
76 |
+
return false;
|
77 |
+
}
|
78 |
+
if(is_multisite()){
|
79 |
+
$blog_id = get_current_blog_id();
|
80 |
+
foreach (array("","js","css") as $checkDir) {
|
81 |
+
if(!Breeze_MinificationCache::checkCacheDir(BREEZE_MINIFICATION_CACHE. $blog_id .'/'.$checkDir)) {
|
82 |
+
return false;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
/** write index.html here to avoid prying eyes */
|
87 |
+
$indexFile=BREEZE_MINIFICATION_CACHE . $blog_id .'/index.html';
|
88 |
+
if(!is_file($indexFile)) {
|
89 |
+
@file_put_contents($indexFile,'<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
|
90 |
+
}
|
91 |
+
|
92 |
+
/** write .htaccess here to overrule wp_super_cache */
|
93 |
+
$htAccess=BREEZE_MINIFICATION_CACHE. $blog_id .'/.htaccess';
|
94 |
+
}else{
|
95 |
+
foreach (array("","js","css") as $checkDir) {
|
96 |
+
if(!Breeze_MinificationCache::checkCacheDir(BREEZE_MINIFICATION_CACHE.$checkDir)) {
|
97 |
+
return false;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
/** write index.html here to avoid prying eyes */
|
101 |
+
$indexFile=BREEZE_MINIFICATION_CACHE.'/index.html';
|
102 |
+
if(!is_file($indexFile)) {
|
103 |
+
@file_put_contents($indexFile,'<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
|
104 |
+
}
|
105 |
+
|
106 |
+
/** write .htaccess here to overrule wp_super_cache */
|
107 |
+
$htAccess=BREEZE_MINIFICATION_CACHE.'/.htaccess';
|
108 |
+
}
|
109 |
+
|
110 |
+
if(!is_file($htAccess)) {
|
111 |
+
/**
|
112 |
+
* create wp-content/AO_htaccess_tmpl with
|
113 |
+
* whatever htaccess rules you might need
|
114 |
+
* if you want to override default AO htaccess
|
115 |
+
*/
|
116 |
+
$htaccess_tmpl=WP_CONTENT_DIR."/AO_htaccess_tmpl";
|
117 |
+
if (is_file($htaccess_tmpl)) {
|
118 |
+
$htAccessContent=file_get_contents($htaccess_tmpl);
|
119 |
+
} else if (is_multisite()) {
|
120 |
+
$htAccessContent='<IfModule mod_headers.c>
|
121 |
+
Header set Vary "Accept-Encoding"
|
122 |
+
Header set Cache-Control "max-age=10672000, must-revalidate"
|
123 |
+
</IfModule>
|
124 |
+
<IfModule mod_expires.c>
|
125 |
+
ExpiresActive On
|
126 |
+
ExpiresByType text/css A30672000
|
127 |
+
ExpiresByType text/javascript A30672000
|
128 |
+
ExpiresByType application/javascript A30672000
|
129 |
+
</IfModule>
|
130 |
+
<IfModule mod_deflate.c>
|
131 |
+
<FilesMatch "\.(js|css)$">
|
132 |
+
SetOutputFilter DEFLATE
|
133 |
+
</FilesMatch>
|
134 |
+
</IfModule>
|
135 |
+
<IfModule mod_authz_core.c>
|
136 |
+
<Files *.php>
|
137 |
+
Require all granted
|
138 |
+
</Files>
|
139 |
+
</IfModule>
|
140 |
+
<IfModule !mod_authz_core.c>
|
141 |
+
<Files *.php>
|
142 |
+
Order allow,deny
|
143 |
+
Allow from all
|
144 |
+
</Files>
|
145 |
+
</IfModule>';
|
146 |
+
} else {
|
147 |
+
$htAccessContent='<IfModule mod_headers.c>
|
148 |
+
Header set Vary "Accept-Encoding"
|
149 |
+
Header set Cache-Control "max-age=10672000, must-revalidate"
|
150 |
+
</IfModule>
|
151 |
+
<IfModule mod_expires.c>
|
152 |
+
ExpiresActive On
|
153 |
+
ExpiresByType text/css A30672000
|
154 |
+
ExpiresByType text/javascript A30672000
|
155 |
+
ExpiresByType application/javascript A30672000
|
156 |
+
</IfModule>
|
157 |
+
<IfModule mod_deflate.c>
|
158 |
+
<FilesMatch "\.(js|css)$">
|
159 |
+
SetOutputFilter DEFLATE
|
160 |
+
</FilesMatch>
|
161 |
+
</IfModule>
|
162 |
+
<IfModule mod_authz_core.c>
|
163 |
+
<Files *.php>
|
164 |
+
Require all denied
|
165 |
+
</Files>
|
166 |
+
</IfModule>
|
167 |
+
<IfModule !mod_authz_core.c>
|
168 |
+
<Files *.php>
|
169 |
+
Order deny,allow
|
170 |
+
Deny from all
|
171 |
+
</Files>
|
172 |
+
</IfModule>';
|
173 |
+
}
|
174 |
+
|
175 |
+
@file_put_contents($htAccess,$htAccessContent);
|
176 |
+
}
|
177 |
+
// All OK
|
178 |
+
return true;
|
179 |
+
|
180 |
+
}
|
181 |
+
// check dir cache
|
182 |
+
static function checkCacheDir($dir) {
|
183 |
+
// Check and create if not exists
|
184 |
+
if(!file_exists($dir)) {
|
185 |
+
@mkdir($dir,0775,true);
|
186 |
+
if(!file_exists($dir)) {
|
187 |
+
return false;
|
188 |
+
}
|
189 |
+
}
|
190 |
+
|
191 |
+
// check if we can now write
|
192 |
+
if(!is_writable($dir)) {
|
193 |
+
return false;
|
194 |
+
}
|
195 |
+
|
196 |
+
// and write index.html here to avoid prying eyes
|
197 |
+
$indexFile=$dir.'/index.html';
|
198 |
+
if(!is_file($indexFile)) {
|
199 |
+
@file_put_contents($indexFile,'<html><head><meta name="robots" content="noindex, nofollow"></head><body></body></html>');
|
200 |
+
}
|
201 |
+
|
202 |
+
return true;
|
203 |
+
}
|
204 |
+
public static function clear_minification() {
|
205 |
+
if(!Breeze_MinificationCache::create_cache_minification_folder()) {
|
206 |
+
return false;
|
207 |
+
}
|
208 |
+
if(is_multisite()){
|
209 |
+
$blog_id = get_current_blog_id();
|
210 |
+
// scan the cachedirs
|
211 |
+
foreach (array("","js","css") as $scandirName) {
|
212 |
+
$scan[$scandirName] = scandir(BREEZE_MINIFICATION_CACHE.$blog_id.'/'.$scandirName);
|
213 |
+
}
|
214 |
+
// clear the cachedirs
|
215 |
+
foreach ($scan as $scandirName=>$scanneddir) {
|
216 |
+
$thisAoCacheDir=rtrim(BREEZE_MINIFICATION_CACHE.$blog_id.'/'.$scandirName,"/")."/";
|
217 |
+
foreach($scanneddir as $file) {
|
218 |
+
if(!in_array($file,array('.','..')) && strpos($file,BREEZE_CACHEFILE_PREFIX) !== false && is_file($thisAoCacheDir.$file)) {
|
219 |
+
@unlink($thisAoCacheDir.$file);
|
220 |
+
}
|
221 |
+
}
|
222 |
+
}
|
223 |
+
@unlink(BREEZE_MINIFICATION_CACHE.$blog_id."/.htaccess");
|
224 |
+
}else{
|
225 |
+
// scan the cachedirs
|
226 |
+
foreach (array("","js","css") as $scandirName) {
|
227 |
+
$scan[$scandirName] = scandir(BREEZE_MINIFICATION_CACHE.$scandirName);
|
228 |
+
}
|
229 |
+
// clear the cachedirs
|
230 |
+
foreach ($scan as $scandirName=>$scanneddir) {
|
231 |
+
$thisAoCacheDir=rtrim(BREEZE_MINIFICATION_CACHE.$scandirName,"/")."/";
|
232 |
+
foreach($scanneddir as $file) {
|
233 |
+
if(!in_array($file,array('.','..')) && strpos($file,BREEZE_CACHEFILE_PREFIX) !== false && is_file($thisAoCacheDir.$file)) {
|
234 |
+
@unlink($thisAoCacheDir.$file);
|
235 |
+
}
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
@unlink(BREEZE_MINIFICATION_CACHE."/.htaccess");
|
240 |
+
}
|
241 |
+
return true;
|
242 |
+
}
|
243 |
+
|
244 |
+
public static function factory() {
|
245 |
+
|
246 |
+
static $instance;
|
247 |
+
|
248 |
+
if ( ! $instance ) {
|
249 |
+
$instance = new self();
|
250 |
+
$instance->set_action();
|
251 |
+
}
|
252 |
+
|
253 |
+
return $instance;
|
254 |
+
}
|
255 |
+
}
|
256 |
+
|
inc/minification/breeze-minification-html.php
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Based on some work of autoptimize plugin
|
4 |
+
*/
|
5 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
6 |
+
|
7 |
+
class Breeze_MinificationHtml extends Breeze_MinificationBase {
|
8 |
+
private $keepcomments = false;
|
9 |
+
private $exclude = array('<!-- ngg_resource_manager_marker -->');
|
10 |
+
|
11 |
+
public function read($options) {
|
12 |
+
// Remove the HTML comments?
|
13 |
+
$this->keepcomments = (bool) $options['keepcomments'];
|
14 |
+
|
15 |
+
// filter to force xhtml
|
16 |
+
$this->forcexhtml = (bool) apply_filters( 'breeze_filter_html_forcexhtml', false );
|
17 |
+
|
18 |
+
// filter to add strings to be excluded from HTML minification
|
19 |
+
$excludeHTML = apply_filters( 'breeze_filter_html_exclude','' );
|
20 |
+
if ($excludeHTML!=="") {
|
21 |
+
$exclHTMLArr = array_filter(array_map('trim',explode(",",$excludeHTML)));
|
22 |
+
$this->exclude = array_merge($exclHTMLArr,$this->exclude);
|
23 |
+
}
|
24 |
+
|
25 |
+
// Nothing else for HTML
|
26 |
+
return true;
|
27 |
+
}
|
28 |
+
|
29 |
+
//Joins and optimizes CSS
|
30 |
+
public function minify() {
|
31 |
+
$noptimizeHTML = apply_filters( 'breeze_filter_html_noptimize', false, $this->content );
|
32 |
+
if ($noptimizeHTML)
|
33 |
+
return false;
|
34 |
+
|
35 |
+
if(class_exists('Minify_HTML')) {
|
36 |
+
// wrap the to-be-excluded strings in noptimize tags
|
37 |
+
foreach ($this->exclude as $exclString) {
|
38 |
+
if (strpos($this->content,$exclString)!==false) {
|
39 |
+
$replString="<!--noptimize-->".$exclString."<!--/noptimize-->";
|
40 |
+
$this->content=str_replace($exclString,$replString,$this->content);
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
// noptimize me
|
45 |
+
$this->content = $this->hide_noptimize($this->content);
|
46 |
+
|
47 |
+
// Minify html
|
48 |
+
$options = array('keepComments' => $this->keepcomments);
|
49 |
+
if ($this->forcexhtml) {
|
50 |
+
$options['xhtml'] = true;
|
51 |
+
}
|
52 |
+
|
53 |
+
if (@is_callable(array(new Minify_HTML,"minify"))) {
|
54 |
+
$tmp_content = Minify_HTML::minify($this->content,$options);
|
55 |
+
if (!empty($tmp_content)) {
|
56 |
+
$this->content = $tmp_content;
|
57 |
+
unset($tmp_content);
|
58 |
+
}
|
59 |
+
}
|
60 |
+
|
61 |
+
// restore noptimize
|
62 |
+
$this->content = $this->restore_noptimize($this->content);
|
63 |
+
|
64 |
+
// remove the noptimize-wrapper from around the excluded strings
|
65 |
+
foreach ($this->exclude as $exclString) {
|
66 |
+
$replString="<!--noptimize-->".$exclString."<!--/noptimize-->";
|
67 |
+
if (strpos($this->content,$replString)!==false) {
|
68 |
+
$this->content=str_replace($replString,$exclString,$this->content);
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
return true;
|
73 |
+
}
|
74 |
+
|
75 |
+
// Didn't minify :(
|
76 |
+
return false;
|
77 |
+
}
|
78 |
+
|
79 |
+
// Does nothing
|
80 |
+
public function cache() {
|
81 |
+
//No cache for HTML
|
82 |
+
return true;
|
83 |
+
}
|
84 |
+
|
85 |
+
//Returns the content
|
86 |
+
public function getcontent() {
|
87 |
+
return $this->content;
|
88 |
+
}
|
89 |
+
}
|
inc/minification/breeze-minification-scripts.php
ADDED
@@ -0,0 +1,504 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Based on some work of autoptimize plugin
|
4 |
+
*/
|
5 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
6 |
+
|
7 |
+
class Breeze_MinificationScripts extends Breeze_MinificationBase {
|
8 |
+
private $scripts = array();
|
9 |
+
private $dontmove = array('document.write','html5.js','show_ads.js','google_ad','blogcatalog.com/w','tweetmeme.com/i','mybloglog.com/','histats.com/js','ads.smowtion.com/ad.js','statcounter.com/counter/counter.js','widgets.amung.us','ws.amazon.com/widgets','media.fastclick.net','/ads/','comment-form-quicktags/quicktags.php','edToolbar','intensedebate.com','scripts.chitika.net/','_gaq.push','jotform.com/','admin-bar.min.js','GoogleAnalyticsObject','plupload.full.min.js','syntaxhighlighter','adsbygoogle','gist.github.com','_stq','nonce','post_id','data-noptimize');
|
10 |
+
private $domove = array('gaJsHost','load_cmc','jd.gallery.transitions.js','swfobject.embedSWF(','tiny_mce.js','tinyMCEPreInit.go');
|
11 |
+
private $domovelast = array('addthis.com','/afsonline/show_afs_search.js','disqus.js','networkedblogs.com/getnetworkwidget','infolinks.com/js/','jd.gallery.js.php','jd.gallery.transitions.js','swfobject.embedSWF(','linkwithin.com/widget.js','tiny_mce.js','tinyMCEPreInit.go');
|
12 |
+
private $trycatch = false;
|
13 |
+
private $alreadyminified = false;
|
14 |
+
private $forcehead = true;
|
15 |
+
private $include_inline = false;
|
16 |
+
private $jscode = '';
|
17 |
+
private $url = '';
|
18 |
+
private $move = array('first' => array(), 'last' => array());
|
19 |
+
private $restofcontent = '';
|
20 |
+
private $md5hash = '';
|
21 |
+
private $whitelist = '';
|
22 |
+
private $jsremovables = array();
|
23 |
+
private $inject_min_late = '';
|
24 |
+
private $group_js = false;
|
25 |
+
private $custom_js_exclude = array();
|
26 |
+
private $js_group_val = array();
|
27 |
+
private $js_min_arr = array();
|
28 |
+
private $url_group_arr = array();
|
29 |
+
//Reads the page and collects script tags
|
30 |
+
public function read($options) {
|
31 |
+
$noptimizeJS = apply_filters( 'breeze_filter_js_noptimize', false, $this->content );
|
32 |
+
if ($noptimizeJS) return false;
|
33 |
+
|
34 |
+
// only optimize known good JS?
|
35 |
+
$whitelistJS = apply_filters( 'breeze_filter_js_whitelist', "" );
|
36 |
+
if (!empty($whitelistJS)) {
|
37 |
+
$this->whitelist = array_filter(array_map('trim',explode(",",$whitelistJS)));
|
38 |
+
}
|
39 |
+
|
40 |
+
// is there JS we should simply remove
|
41 |
+
$removableJS = apply_filters( 'breeze_filter_js_removables', '');
|
42 |
+
if (!empty($removableJS)) {
|
43 |
+
$this->jsremovables = array_filter(array_map('trim',explode(",",$removableJS)));
|
44 |
+
}
|
45 |
+
|
46 |
+
// only header?
|
47 |
+
if( apply_filters('breeze_filter_js_justhead',$options['justhead']) == true ) {
|
48 |
+
$content = explode('</head>',$this->content,2);
|
49 |
+
$this->content = $content[0].'</head>';
|
50 |
+
$this->restofcontent = $content[1];
|
51 |
+
}
|
52 |
+
|
53 |
+
// include inline?
|
54 |
+
if( apply_filters('breeze_js_include_inline',$options['include_inline']) == true ) {
|
55 |
+
$this->include_inline = true;
|
56 |
+
}
|
57 |
+
|
58 |
+
// group js?
|
59 |
+
if( apply_filters('breeze_js_group_js',$options['group_js']) == true ) {
|
60 |
+
$this->group_js = true;
|
61 |
+
}
|
62 |
+
|
63 |
+
//custom js exclude
|
64 |
+
if(!empty($options['custom_js_exclude'])){
|
65 |
+
$this->custom_js_exclude = $options['custom_js_exclude'];
|
66 |
+
}
|
67 |
+
|
68 |
+
// filter to "late inject minified JS", default to true for now (it is faster)
|
69 |
+
$this->inject_min_late = apply_filters('breeze_filter_js_inject_min_late',true);
|
70 |
+
|
71 |
+
// filters to override hardcoded do(nt)move(last) array contents (array in, array out!)
|
72 |
+
$this->dontmove = apply_filters( 'breeze_js_dontmove', $this->dontmove );
|
73 |
+
$this->domovelast = apply_filters( 'breeze_filter_js_movelast', $this->domovelast );
|
74 |
+
$this->domove = apply_filters( 'breeze_filter_js_domove', $this->domove );
|
75 |
+
|
76 |
+
// get extra exclusions settings or filter
|
77 |
+
$excludeJS = $options['js_exclude'];
|
78 |
+
$excludeJS = apply_filters( 'breeze_filter_js_exclude', $excludeJS );
|
79 |
+
if ($excludeJS!=="") {
|
80 |
+
$exclJSArr = array_filter(array_map('trim',explode(",",$excludeJS)));
|
81 |
+
$this->dontmove = array_merge($exclJSArr,$this->dontmove);
|
82 |
+
}
|
83 |
+
|
84 |
+
//Should we add try-catch?
|
85 |
+
if($options['trycatch'] == true)
|
86 |
+
$this->trycatch = true;
|
87 |
+
|
88 |
+
// force js in head?
|
89 |
+
if($options['forcehead'] == true) {
|
90 |
+
$this->forcehead = true;
|
91 |
+
} else {
|
92 |
+
$this->forcehead = false;
|
93 |
+
}
|
94 |
+
$this->forcehead = apply_filters( 'breeze_filter_js_forcehead', $this->forcehead );
|
95 |
+
|
96 |
+
// get cdn url
|
97 |
+
$this->cdn_url = $options['cdn_url'];
|
98 |
+
|
99 |
+
// noptimize me
|
100 |
+
$this->content = $this->hide_noptimize($this->content);
|
101 |
+
|
102 |
+
// Save IE hacks
|
103 |
+
$this->content = $this->hide_iehacks($this->content);
|
104 |
+
|
105 |
+
// comments
|
106 |
+
$this->content = $this->hide_comments($this->content);
|
107 |
+
|
108 |
+
//Get script files
|
109 |
+
if(preg_match_all('#<script.*</script>#Usmi',$this->content,$matches)) {
|
110 |
+
foreach($matches[0] as $tag) {
|
111 |
+
// only consider aggregation whitelisted in should_aggregate-function
|
112 |
+
if( !$this->should_aggregate($tag) ) {
|
113 |
+
$tag='';
|
114 |
+
continue;
|
115 |
+
}
|
116 |
+
if(preg_match('#src=("|\')(.*)("|\')#Usmi',$tag,$source)) {
|
117 |
+
if ($this->isremovable($tag,$this->jsremovables)) {
|
118 |
+
$this->content = str_replace($tag,'',$this->content);
|
119 |
+
continue;
|
120 |
+
}
|
121 |
+
// External script
|
122 |
+
$url = current(explode('?',$source[2],2));
|
123 |
+
//exclude js
|
124 |
+
if(in_array($url,$this->custom_js_exclude)){
|
125 |
+
continue;
|
126 |
+
}
|
127 |
+
|
128 |
+
$path = $this->getpath($url);
|
129 |
+
if($path !== false && preg_match('#\.js$#',$path)) {
|
130 |
+
//Inline
|
131 |
+
if($this->ismergeable($tag)) {
|
132 |
+
//We can merge it
|
133 |
+
$this->scripts[] = $path;
|
134 |
+
|
135 |
+
} else {
|
136 |
+
//No merge, but maybe we can move it
|
137 |
+
if($this->ismovable($tag)) {
|
138 |
+
//Yeah, move it
|
139 |
+
if($this->movetolast($tag)) {
|
140 |
+
$this->move['last'][] = $tag;
|
141 |
+
} else {
|
142 |
+
$this->move['first'][] = $tag;
|
143 |
+
}
|
144 |
+
} else {
|
145 |
+
//We shouldn't touch this
|
146 |
+
$tag = '';
|
147 |
+
}
|
148 |
+
}
|
149 |
+
} else {
|
150 |
+
//External script (example: google analytics)
|
151 |
+
//OR Script is dynamic (.php etc)
|
152 |
+
if($this->ismovable($tag)) {
|
153 |
+
if($this->movetolast($tag)) {
|
154 |
+
$this->move['last'][] = $tag;
|
155 |
+
} else {
|
156 |
+
$this->move['first'][] = $tag;
|
157 |
+
}
|
158 |
+
} else {
|
159 |
+
//We shouldn't touch this
|
160 |
+
$tag = '';
|
161 |
+
}
|
162 |
+
}
|
163 |
+
} else {
|
164 |
+
// Inline script
|
165 |
+
if ($this->isremovable($tag,$this->jsremovables)) {
|
166 |
+
$this->content = str_replace($tag,'',$this->content);
|
167 |
+
continue;
|
168 |
+
}
|
169 |
+
|
170 |
+
// unhide comments, as javascript may be wrapped in comment-tags for old times' sake
|
171 |
+
$tag = $this->restore_comments($tag);
|
172 |
+
if($this->ismergeable($tag) && ( $this->include_inline )) {
|
173 |
+
preg_match('#<script.*>(.*)</script>#Usmi',$tag,$code);
|
174 |
+
$code = preg_replace('#.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*#sm','$1',$code[1]);
|
175 |
+
$code = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/','',$code);
|
176 |
+
$this->scripts[] = 'INLINE;'.$code;
|
177 |
+
} else {
|
178 |
+
// Can we move this?
|
179 |
+
if($this->ismovable($tag)) {
|
180 |
+
if($this->movetolast($tag)) {
|
181 |
+
$this->move['last'][] = $tag;
|
182 |
+
} else {
|
183 |
+
$this->move['first'][] = $tag;
|
184 |
+
}
|
185 |
+
} else {
|
186 |
+
//We shouldn't touch this
|
187 |
+
$tag = '';
|
188 |
+
}
|
189 |
+
}
|
190 |
+
// re-hide comments to be able to do the removal based on tag from $this->content
|
191 |
+
$tag = $this->hide_comments($tag);
|
192 |
+
}
|
193 |
+
//Remove the original script tag
|
194 |
+
$this->content = str_replace($tag,'',$this->content);
|
195 |
+
}
|
196 |
+
|
197 |
+
return true;
|
198 |
+
}
|
199 |
+
|
200 |
+
// No script files, great ;-)
|
201 |
+
return false;
|
202 |
+
}
|
203 |
+
|
204 |
+
//Joins and optimizes JS
|
205 |
+
public function minify() {
|
206 |
+
foreach($this->scripts as $script) {
|
207 |
+
if(preg_match('#^INLINE;#',$script)) {
|
208 |
+
//Inline script
|
209 |
+
$script = preg_replace('#^INLINE;#','',$script);
|
210 |
+
$script = rtrim( $script, ";\n\t\r" ) . ';';
|
211 |
+
//Add try-catch?
|
212 |
+
if($this->trycatch) {
|
213 |
+
$script = 'try{'.$script.'}catch(e){}';
|
214 |
+
}
|
215 |
+
$tmpscript = apply_filters( 'breeze_js_individual_script', $script, "" );
|
216 |
+
if ( has_filter('breeze_js_individual_script') && !empty($tmpscript) ) {
|
217 |
+
$script=$tmpscript;
|
218 |
+
$this->alreadyminified=true;
|
219 |
+
}
|
220 |
+
if($this->group_js == true){
|
221 |
+
$this->jscode .= "\n" . $script;
|
222 |
+
}else{
|
223 |
+
$this->js_group_val[] = $script;
|
224 |
+
}
|
225 |
+
|
226 |
+
} else {
|
227 |
+
//External script
|
228 |
+
if($script !== false && file_exists($script) && is_readable($script)) {
|
229 |
+
$scriptsrc = file_get_contents($script);
|
230 |
+
$scriptsrc = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$scriptsrc);
|
231 |
+
$scriptsrc = rtrim($scriptsrc,";\n\t\r").';';
|
232 |
+
//Add try-catch?
|
233 |
+
if($this->trycatch) {
|
234 |
+
$scriptsrc = 'try{'.$scriptsrc.'}catch(e){}';
|
235 |
+
}
|
236 |
+
$tmpscriptsrc = apply_filters( 'breeze_js_individual_script', $scriptsrc, $script );
|
237 |
+
if ( has_filter('breeze_js_individual_script') && !empty($tmpscriptsrc) ) {
|
238 |
+
$scriptsrc=$tmpscriptsrc;
|
239 |
+
$this->alreadyminified=true;
|
240 |
+
} else if ((strpos($script,"min.js")!==false) && ($this->inject_min_late===true)) {
|
241 |
+
$scriptsrc="%%INJECTLATER".breeze_HASH."%%".base64_encode($script)."|".md5($scriptsrc)."%%INJECTLATER%%";
|
242 |
+
}
|
243 |
+
if($this->group_js == true){
|
244 |
+
$this->jscode .= "\n" . $scriptsrc;
|
245 |
+
}else{
|
246 |
+
$this->js_group_val[] = $scriptsrc;
|
247 |
+
}
|
248 |
+
|
249 |
+
}/*else{
|
250 |
+
//Couldn't read JS. Maybe getpath isn't working?
|
251 |
+
}*/
|
252 |
+
}
|
253 |
+
}
|
254 |
+
if($this->group_js == true){
|
255 |
+
//Check for already-minified code
|
256 |
+
$this->md5hash = md5($this->jscode);
|
257 |
+
$ccheck = new Breeze_MinificationCache($this->md5hash,'js');
|
258 |
+
if($ccheck->check()) {
|
259 |
+
$this->jscode = $ccheck->retrieve();
|
260 |
+
return true;
|
261 |
+
}
|
262 |
+
unset($ccheck);
|
263 |
+
|
264 |
+
//$this->jscode has all the uncompressed code now.
|
265 |
+
if ($this->alreadyminified!==true) {
|
266 |
+
if (class_exists('JSMin') && apply_filters( 'breeze_js_do_minify' , true)) {
|
267 |
+
if (@is_callable(array("JSMin","minify"))) {
|
268 |
+
$tmp_jscode = trim(JSMin::minify($this->jscode));
|
269 |
+
if (!empty($tmp_jscode)) {
|
270 |
+
$this->jscode = $tmp_jscode;
|
271 |
+
unset($tmp_jscode);
|
272 |
+
}
|
273 |
+
$this->jscode = $this->inject_minified($this->jscode);
|
274 |
+
$this->jscode = apply_filters( 'breeze_js_after_minify', $this->jscode );
|
275 |
+
return true;
|
276 |
+
} else {
|
277 |
+
$this->jscode = $this->inject_minified($this->jscode);
|
278 |
+
return false;
|
279 |
+
}
|
280 |
+
} else {
|
281 |
+
$this->jscode = $this->inject_minified($this->jscode);
|
282 |
+
return false;
|
283 |
+
}
|
284 |
+
}
|
285 |
+
}else{
|
286 |
+
foreach ($this->js_group_val as $jscode){
|
287 |
+
//Check for already-minified code
|
288 |
+
$this->md5hash = md5($jscode);
|
289 |
+
$ccheck = new Breeze_MinificationCache($this->md5hash,'js');
|
290 |
+
if($ccheck->check()) {
|
291 |
+
$js_exist = $ccheck->retrieve();
|
292 |
+
$this->js_min_arr[] = $this->md5hash .'_breezejsgroup_'.$js_exist;
|
293 |
+
continue;
|
294 |
+
}
|
295 |
+
unset($ccheck);
|
296 |
+
|
297 |
+
//$this->jscode has all the uncompressed code now.
|
298 |
+
|
299 |
+
if (class_exists('JSMin') && apply_filters( 'breeze_js_do_minify' , true)) {
|
300 |
+
if (@is_callable(array("JSMin","minify"))) {
|
301 |
+
$tmp_jscode = trim(JSMin::minify($jscode));
|
302 |
+
if (!empty($tmp_jscode)) {
|
303 |
+
$jscode = $tmp_jscode;
|
304 |
+
unset($tmp_jscode);
|
305 |
+
}
|
306 |
+
$jscode = $this->inject_minified($jscode);
|
307 |
+
$jscode = apply_filters( 'breeze_js_after_minify', $jscode );
|
308 |
+
$this->js_min_arr[] = $this->md5hash .'_breezejsgroup_'.$jscode;
|
309 |
+
} else {
|
310 |
+
$jscode = $this->inject_minified($jscode);
|
311 |
+
$this->js_min_arr[] = $this->md5hash .'_breezejsgroup_'.$jscode;
|
312 |
+
|
313 |
+
}
|
314 |
+
} else {
|
315 |
+
$jscode = $this->inject_minified($jscode);
|
316 |
+
$this->js_min_arr[] = $this->md5hash .'_breezejsgroup_'.$jscode;
|
317 |
+
}
|
318 |
+
|
319 |
+
}
|
320 |
+
}
|
321 |
+
return true;
|
322 |
+
}
|
323 |
+
|
324 |
+
//Caches the JS in uncompressed, deflated and gzipped form.
|
325 |
+
public function cache() {
|
326 |
+
if($this->group_js == true){
|
327 |
+
$cache = new Breeze_MinificationCache($this->md5hash,'js');
|
328 |
+
if(!$cache->check()) {
|
329 |
+
//Cache our code
|
330 |
+
$cache->cache($this->jscode,'text/javascript');
|
331 |
+
}
|
332 |
+
$this->url = breeze_CACHE_URL.$cache->getname();
|
333 |
+
$this->url = $this->url_replace_cdn($this->url);
|
334 |
+
}else{
|
335 |
+
foreach ($this->js_min_arr as $js_min){
|
336 |
+
$namehash = substr($js_min, 0 , strpos($js_min,'_breezejsgroup_'));
|
337 |
+
$js_code = substr($js_min,strpos($js_min,'_breezejsgroup_')+strlen('_breezejsgroup_'));
|
338 |
+
$cache = new Breeze_MinificationCache($namehash,'js');
|
339 |
+
if(!$cache->check()) {
|
340 |
+
//Cache our code
|
341 |
+
$cache->cache($js_code,'text/javascript');
|
342 |
+
}
|
343 |
+
$url = breeze_CACHE_URL.$cache->getname();
|
344 |
+
$this->url_group_arr[]= $this->url_replace_cdn($url);
|
345 |
+
}
|
346 |
+
}
|
347 |
+
}
|
348 |
+
|
349 |
+
// Returns the content
|
350 |
+
public function getcontent() {
|
351 |
+
// Restore the full content
|
352 |
+
if(!empty($this->restofcontent)) {
|
353 |
+
$this->content .= $this->restofcontent;
|
354 |
+
$this->restofcontent = '';
|
355 |
+
}
|
356 |
+
|
357 |
+
// Add the scripts taking forcehead/ deferred (default) into account
|
358 |
+
if($this->forcehead == true) {
|
359 |
+
$replaceTag=array("</head>","before");
|
360 |
+
$defer="";
|
361 |
+
} else {
|
362 |
+
$replaceTag=array("</body>","before");
|
363 |
+
$defer="defer ";
|
364 |
+
}
|
365 |
+
|
366 |
+
$defer = apply_filters( 'breeze_filter_js_defer', $defer );
|
367 |
+
if($this->group_js == true){
|
368 |
+
$bodyreplacementpayload = '<script type="text/javascript" '.$defer.'src="'.$this->url.'"></script>';
|
369 |
+
$bodyreplacementpayload = apply_filters('breeze_filter_js_bodyreplacementpayload',$bodyreplacementpayload);
|
370 |
+
}else{
|
371 |
+
$arrscript = array();
|
372 |
+
foreach ($this->url_group_arr as $url){
|
373 |
+
$arrscript[] = '<script type="text/javascript" '.$defer.'src="'.$url.'"></script>';
|
374 |
+
}
|
375 |
+
$bodyreplacementpayload = implode('',$arrscript);
|
376 |
+
}
|
377 |
+
$bodyreplacement = implode('',$this->move['first']);
|
378 |
+
$bodyreplacement .= $bodyreplacementpayload;
|
379 |
+
$bodyreplacement .= implode('',$this->move['last']);
|
380 |
+
$replaceTag = apply_filters( 'breeze_filter_js_replacetag', $replaceTag );
|
381 |
+
|
382 |
+
if($this->group_js == true){
|
383 |
+
if (strlen($this->jscode)>0) {
|
384 |
+
$this->inject_in_html($bodyreplacement,$replaceTag);
|
385 |
+
}
|
386 |
+
}else{
|
387 |
+
if(count($this->js_min_arr) > 0)
|
388 |
+
$this->inject_in_html($bodyreplacement,$replaceTag);
|
389 |
+
}
|
390 |
+
|
391 |
+
|
392 |
+
|
393 |
+
// restore comments
|
394 |
+
$this->content = $this->restore_comments($this->content);
|
395 |
+
|
396 |
+
// Restore IE hacks
|
397 |
+
$this->content = $this->restore_iehacks($this->content);
|
398 |
+
|
399 |
+
// Restore noptimize
|
400 |
+
$this->content = $this->restore_noptimize($this->content);
|
401 |
+
|
402 |
+
// Return the modified HTML
|
403 |
+
return $this->content;
|
404 |
+
}
|
405 |
+
|
406 |
+
// Checks against the white- and blacklists
|
407 |
+
private function ismergeable($tag) {
|
408 |
+
if (!empty($this->whitelist)) {
|
409 |
+
foreach ($this->whitelist as $match) {
|
410 |
+
if(strpos($tag,$match)!==false) {
|
411 |
+
return true;
|
412 |
+
}
|
413 |
+
}
|
414 |
+
// no match with whitelist
|
415 |
+
return false;
|
416 |
+
} else {
|
417 |
+
foreach($this->domove as $match) {
|
418 |
+
if(strpos($tag,$match)!==false) {
|
419 |
+
//Matched something
|
420 |
+
return false;
|
421 |
+
}
|
422 |
+
}
|
423 |
+
|
424 |
+
if ($this->movetolast($tag)) {
|
425 |
+
return false;
|
426 |
+
}
|
427 |
+
|
428 |
+
foreach($this->dontmove as $match) {
|
429 |
+
if(strpos($tag,$match)!==false) {
|
430 |
+
//Matched something
|
431 |
+
return false;
|
432 |
+
}
|
433 |
+
}
|
434 |
+
|
435 |
+
// If we're here it's safe to merge
|
436 |
+
return true;
|
437 |
+
}
|
438 |
+
}
|
439 |
+
|
440 |
+
//Checks agains the blacklist
|
441 |
+
private function ismovable($tag) {
|
442 |
+
if ($this->include_inline !== true || apply_filters('breeze_filter_js_unmovable',true)) {
|
443 |
+
return false;
|
444 |
+
}
|
445 |
+
|
446 |
+
foreach($this->domove as $match) {
|
447 |
+
if(strpos($tag,$match)!==false) {
|
448 |
+
//Matched something
|
449 |
+
return true;
|
450 |
+
}
|
451 |
+
}
|
452 |
+
|
453 |
+
if ($this->movetolast($tag)) {
|
454 |
+
return true;
|
455 |
+
}
|
456 |
+
|
457 |
+
foreach($this->dontmove as $match) {
|
458 |
+
if(strpos($tag,$match)!==false) {
|
459 |
+
//Matched something
|
460 |
+
return false;
|
461 |
+
}
|
462 |
+
}
|
463 |
+
|
464 |
+
//If we're here it's safe to move
|
465 |
+
return true;
|
466 |
+
}
|
467 |
+
|
468 |
+
private function movetolast($tag) {
|
469 |
+
foreach($this->domovelast as $match) {
|
470 |
+
if(strpos($tag,$match)!==false) {
|
471 |
+
//Matched, return true
|
472 |
+
return true;
|
473 |
+
}
|
474 |
+
}
|
475 |
+
|
476 |
+
//Should be in 'first'
|
477 |
+
return false;
|
478 |
+
}
|
479 |
+
/**
|
480 |
+
* Determines wheter a <script> $tag should be aggregated or not.
|
481 |
+
*
|
482 |
+
* We consider these as "aggregation-safe" currently:
|
483 |
+
* - script tags without a `type` attribute
|
484 |
+
* - script tags with an explicit `type` of `text/javascript`, 'text/ecmascript',
|
485 |
+
* 'application/javascript' or 'application/ecmascript'
|
486 |
+
*
|
487 |
+
* Everything else should return false.
|
488 |
+
*
|
489 |
+
* @param string $tag
|
490 |
+
* @return bool
|
491 |
+
*
|
492 |
+
* original function by https://github.com/zytzagoo/ on his AO fork, thanks Tomas!
|
493 |
+
*/
|
494 |
+
public function should_aggregate($tag) {
|
495 |
+
preg_match('#<(script[^>]*)>#i',$tag,$scripttag);
|
496 |
+
if ( strpos($scripttag[1], 'type=')===false ) {
|
497 |
+
return true;
|
498 |
+
} else if ( preg_match('/type=["\']?(?:text|application)\/(?:javascript|ecmascript)["\']?/i', $scripttag[1]) ) {
|
499 |
+
return true;
|
500 |
+
} else {
|
501 |
+
return false;
|
502 |
+
}
|
503 |
+
}
|
504 |
+
}
|
inc/minification/breeze-minification-styles.php
ADDED
@@ -0,0 +1,809 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
* Based on some work of autoptimize plugin
|
4 |
+
*/
|
5 |
+
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
6 |
+
|
7 |
+
class Breeze_MinificationStyles extends Breeze_MinificationBase {
|
8 |
+
private $css = array();
|
9 |
+
private $csscode = array();
|
10 |
+
private $url = array();
|
11 |
+
private $restofcontent = '';
|
12 |
+
private $mhtml = '';
|
13 |
+
private $datauris = false;
|
14 |
+
private $hashmap = array();
|
15 |
+
private $alreadyminified = false;
|
16 |
+
private $inline = false;
|
17 |
+
private $defer = false;
|
18 |
+
private $defer_inline = false;
|
19 |
+
private $whitelist = '';
|
20 |
+
private $cssinlinesize = '';
|
21 |
+
private $cssremovables = array();
|
22 |
+
private $include_inline = false;
|
23 |
+
private $inject_min_late = '';
|
24 |
+
private $group_css = false;
|
25 |
+
private $custom_css_exclude = array();
|
26 |
+
private $css_group_val = array();
|
27 |
+
private $css_min_arr = array();
|
28 |
+
private $issetminfile = false;
|
29 |
+
private $url_group_arr = array();
|
30 |
+
|
31 |
+
//Reads the page and collects style tags
|
32 |
+
public function read($options) {
|
33 |
+
$noptimizeCSS = apply_filters( 'breeze_filter_css_noptimize', false, $this->content );
|
34 |
+
if ($noptimizeCSS) return false;
|
35 |
+
|
36 |
+
$whitelistCSS = apply_filters( 'breeze_filter_css_whitelist', '' );
|
37 |
+
if (!empty($whitelistCSS)) {
|
38 |
+
$this->whitelist = array_filter(array_map('trim',explode(",",$whitelistCSS)));
|
39 |
+
}
|
40 |
+
|
41 |
+
if ($options['nogooglefont'] == true) {
|
42 |
+
$removableCSS = "fonts.googleapis.com";
|
43 |
+
} else {
|
44 |
+
$removableCSS = "";
|
45 |
+
}
|
46 |
+
$removableCSS = apply_filters( 'breeze_filter_css_removables', $removableCSS);
|
47 |
+
if (!empty($removableCSS)) {
|
48 |
+
$this->cssremovables = array_filter(array_map('trim',explode(",",$removableCSS)));
|
49 |
+
}
|
50 |
+
|
51 |
+
$this->cssinlinesize = apply_filters('breeze_filter_css_inlinesize',256);
|
52 |
+
|
53 |
+
// filter to "late inject minified CSS", default to true for now (it is faster)
|
54 |
+
$this->inject_min_late = apply_filters('breeze_filter_css_inject_min_late',true);
|
55 |
+
|
56 |
+
// Remove everything that's not the header
|
57 |
+
if ( apply_filters('breeze_filter_css_justhead',$options['justhead']) == true ) {
|
58 |
+
$content = explode('</head>',$this->content,2);
|
59 |
+
$this->content = $content[0].'</head>';
|
60 |
+
$this->restofcontent = $content[1];
|
61 |
+
}
|
62 |
+
|
63 |
+
// include inline?
|
64 |
+
if( apply_filters('breeze_css_include_inline',$options['include_inline']) == true ) {
|
65 |
+
$this->include_inline = true;
|
66 |
+
}
|
67 |
+
|
68 |
+
// group css?
|
69 |
+
if( apply_filters('breeze_css_include_inline',$options['groupcss']) == true ) {
|
70 |
+
$this->group_css = true;
|
71 |
+
}
|
72 |
+
//custom js exclude
|
73 |
+
if(!empty($options['custom_css_exclude'])){
|
74 |
+
$this->custom_css_exclude = $options['custom_css_exclude'];
|
75 |
+
}
|
76 |
+
// what CSS shouldn't be autoptimized
|
77 |
+
$excludeCSS = $options['css_exclude'];
|
78 |
+
$excludeCSS = apply_filters( 'breeze_filter_css_exclude', $excludeCSS );
|
79 |
+
if ($excludeCSS!=="") {
|
80 |
+
$this->dontmove = array_filter(array_map('trim',explode(",",$excludeCSS)));
|
81 |
+
} else {
|
82 |
+
$this->dontmove = "";
|
83 |
+
}
|
84 |
+
|
85 |
+
// should we defer css?
|
86 |
+
// value: true/ false
|
87 |
+
$this->defer = $options['defer'];
|
88 |
+
$this->defer = apply_filters( 'breeze_filter_css_defer', $this->defer );
|
89 |
+
|
90 |
+
// should we inline while deferring?
|
91 |
+
// value: inlined CSS
|
92 |
+
$this->defer_inline = $options['defer_inline'];
|
93 |
+
|
94 |
+
// should we inline?
|
95 |
+
// value: true/ false
|
96 |
+
$this->inline = $options['inline'];
|
97 |
+
$this->inline = apply_filters( 'breeze_filter_css_inline', $this->inline );
|
98 |
+
|
99 |
+
// get cdn url
|
100 |
+
$this->cdn_url = $options['cdn_url'];
|
101 |
+
|
102 |
+
// Store data: URIs setting for later use
|
103 |
+
$this->datauris = $options['datauris'];
|
104 |
+
|
105 |
+
// noptimize me
|
106 |
+
$this->content = $this->hide_noptimize($this->content);
|
107 |
+
|
108 |
+
// exclude (no)script, as those may contain CSS which should be left as is
|
109 |
+
if ( strpos( $this->content, '<script' ) !== false ) {
|
110 |
+
$this->content = preg_replace_callback(
|
111 |
+
'#<(?:no)?script.*?<\/(?:no)?script>#is',
|
112 |
+
create_function(
|
113 |
+
'$matches',
|
114 |
+
'return "%%SCRIPT".breeze_HASH."%%".base64_encode($matches[0])."%%SCRIPT%%";'
|
115 |
+
),
|
116 |
+
$this->content
|
117 |
+
);
|
118 |
+
}
|
119 |
+
|
120 |
+
// Save IE hacks
|
121 |
+
$this->content = $this->hide_iehacks($this->content);
|
122 |
+
|
123 |
+
// hide comments
|
124 |
+
$this->content = $this->hide_comments($this->content);
|
125 |
+
|
126 |
+
// Get <style> and <link>
|
127 |
+
if(preg_match_all('#(<style[^>]*>.*</style>)|(<link[^>]*stylesheet[^>]*>)#Usmi',$this->content,$matches)) {
|
128 |
+
foreach($matches[0] as $tag) {
|
129 |
+
if ($this->isremovable($tag,$this->cssremovables)) {
|
130 |
+
$this->content = str_replace($tag,'',$this->content);
|
131 |
+
} else if ($this->ismovable($tag)) {
|
132 |
+
// Get the media
|
133 |
+
if(strpos($tag,'media=')!==false) {
|
134 |
+
preg_match('#media=(?:"|\')([^>]*)(?:"|\')#Ui',$tag,$medias);
|
135 |
+
$medias = explode(',',$medias[1]);
|
136 |
+
$media = array();
|
137 |
+
foreach($medias as $elem) {
|
138 |
+
if (empty($elem)) { $elem="all"; }
|
139 |
+
$media[] = $elem;
|
140 |
+
}
|
141 |
+
} else {
|
142 |
+
// No media specified - applies to all
|
143 |
+
$media = array('all');
|
144 |
+
}
|
145 |
+
$media = apply_filters( 'breeze_filter_css_tagmedia',$media,$tag );
|
146 |
+
|
147 |
+
if(preg_match('#<link.*href=("|\')(.*)("|\')#Usmi',$tag,$source)) {
|
148 |
+
// <link>
|
149 |
+
$url = current(explode('?',$source[2],2));
|
150 |
+
//exclude css file
|
151 |
+
if(in_array($url,$this->custom_css_exclude)){
|
152 |
+
continue;
|
153 |
+
}
|
154 |
+
|
155 |
+
$path = $this->getpath($url);
|
156 |
+
|
157 |
+
if($path!==false && preg_match('#\.css$#',$path)) {
|
158 |
+
// Good link
|
159 |
+
$this->css[] = array($media,$path);
|
160 |
+
}else{
|
161 |
+
// Link is dynamic (.php etc)
|
162 |
+
$tag = '';
|
163 |
+
}
|
164 |
+
} else {
|
165 |
+
// inline css in style tags can be wrapped in comment tags, so restore comments
|
166 |
+
$tag = $this->restore_comments($tag);
|
167 |
+
preg_match('#<style.*>(.*)</style>#Usmi',$tag,$code);
|
168 |
+
|
169 |
+
// and re-hide them to be able to to the removal based on tag
|
170 |
+
$tag = $this->hide_comments($tag);
|
171 |
+
|
172 |
+
if ( $this->include_inline ) {
|
173 |
+
$code = preg_replace('#^.*<!\[CDATA\[(?:\s*\*/)?(.*)(?://|/\*)\s*?\]\]>.*$#sm','$1',$code[1]);
|
174 |
+
$this->css[] = array($media,'INLINE;'.$code);
|
175 |
+
} else {
|
176 |
+
$tag = '';
|
177 |
+
}
|
178 |
+
}
|
179 |
+
// Remove the original style tag
|
180 |
+
$this->content = str_replace($tag,'',$this->content);
|
181 |
+
}
|
182 |
+
}
|
183 |
+
return true;
|
184 |
+
}
|
185 |
+
// Really, no styles?
|
186 |
+
return false;
|
187 |
+
}
|
188 |
+
|
189 |
+
// Joins and optimizes CSS
|
190 |
+
public function minify() {
|
191 |
+
foreach($this->css as $group) {
|
192 |
+
list($media,$css) = $group;
|
193 |
+
if(preg_match('#^INLINE;#',$css)) {
|
194 |
+
// <style>
|
195 |
+
$css = preg_replace('#^INLINE;#','',$css);
|
196 |
+
$css = $this->fixurls(ABSPATH.'/index.php',$css);
|
197 |
+
$tmpstyle = apply_filters( 'breeze_css_individual_style', $css, "" );
|
198 |
+
if ( has_filter('breeze_css_individual_style') && !empty($tmpstyle) ) {
|
199 |
+
$css=$tmpstyle;
|
200 |
+
$this->alreadyminified=true;
|
201 |
+
}
|
202 |
+
} else {
|
203 |
+
//<link>
|
204 |
+
if($css !== false && file_exists($css) && is_readable($css)) {
|
205 |
+
$cssPath = $css;
|
206 |
+
$css = $this->fixurls($cssPath,file_get_contents($cssPath));
|
207 |
+
$css = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$css);
|
208 |
+
$tmpstyle = apply_filters( 'breeze_css_individual_style', $css, $cssPath );
|
209 |
+
if (has_filter('breeze_css_individual_style') && !empty($tmpstyle)) {
|
210 |
+
$css=$tmpstyle;
|
211 |
+
$this->alreadyminified=true;
|
212 |
+
} else if ($this->can_inject_late($cssPath,$css)) {
|
213 |
+
$css="%%INJECTLATER".breeze_HASH."%%".base64_encode($cssPath)."|".md5($css)."%%INJECTLATER%%";
|
214 |
+
}
|
215 |
+
} else {
|
216 |
+
// Couldn't read CSS. Maybe getpath isn't working?
|
217 |
+
$css = '';
|
218 |
+
}
|
219 |
+
}
|
220 |
+
if($this->group_css == true){
|
221 |
+
foreach($media as $elem) {
|
222 |
+
if(!isset($this->csscode[$elem]))
|
223 |
+
$this->csscode[$elem] = '';
|
224 |
+
$this->csscode[$elem] .= "\n/*FILESTART*/".$css;
|
225 |
+
}
|
226 |
+
}else{
|
227 |
+
foreach ($media as $elem){
|
228 |
+
$this->css_group_val[] = $elem."_breezecssgroup_".$css;
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
|
233 |
+
}
|
234 |
+
if($this->group_css == true){
|
235 |
+
// Check for duplicate code
|
236 |
+
$md5list = array();
|
237 |
+
$tmpcss = $this->csscode;
|
238 |
+
foreach($tmpcss as $media => $code) {
|
239 |
+
$md5sum = md5($code);
|
240 |
+
$medianame = $media;
|
241 |
+
foreach($md5list as $med => $sum) {
|
242 |
+
// If same code
|
243 |
+
if($sum === $md5sum) {
|
244 |
+
//Add the merged code
|
245 |
+
$medianame = $med.', '.$media;
|
246 |
+
$this->csscode[$medianame] = $code;
|
247 |
+
$md5list[$medianame] = $md5list[$med];
|
248 |
+
unset($this->csscode[$med], $this->csscode[$media]);
|
249 |
+
unset($md5list[$med]);
|
250 |
+
}
|
251 |
+
}
|
252 |
+
$md5list[$medianame] = $md5sum;
|
253 |
+
}
|
254 |
+
unset($tmpcss);
|
255 |
+
|
256 |
+
// Manage @imports, while is for recursive import management
|
257 |
+
foreach ($this->csscode as &$thiscss) {
|
258 |
+
// Flag to trigger import reconstitution and var to hold external imports
|
259 |
+
$fiximports = false;
|
260 |
+
$external_imports = "";
|
261 |
+
|
262 |
+
while(preg_match_all('#^(/*\s?)@import.*(?:;|$)#Um',$thiscss,$matches)) {
|
263 |
+
foreach($matches[0] as $import) {
|
264 |
+
if ($this->isremovable($import,$this->cssremovables)) {
|
265 |
+
$thiscss = str_replace($import,'',$thiscss);
|
266 |
+
$import_ok = true;
|
267 |
+
} else {
|
268 |
+
$url = trim(preg_replace('#^.*((?:https?:|ftp:)?//.*\.css).*$#','$1',trim($import))," \t\n\r\0\x0B\"'");
|
269 |
+
$path = $this->getpath($url);
|
270 |
+
$import_ok = false;
|
271 |
+
if (file_exists($path) && is_readable($path)) {
|
272 |
+
$code = addcslashes($this->fixurls($path,file_get_contents($path)),"\\");
|
273 |
+
$code = preg_replace('/\x{EF}\x{BB}\x{BF}/','',$code);
|
274 |
+
$tmpstyle = apply_filters( 'breeze_css_individual_style', $code, "" );
|
275 |
+
if ( has_filter('breeze_css_individual_style') && !empty($tmpstyle)) {
|
276 |
+
$code=$tmpstyle;
|
277 |
+
$this->alreadyminified=true;
|
278 |
+
} else if ($this->can_inject_late($path,$code)) {
|
279 |
+
$code="%%INJECTLATER".breeze_HASH."%%".base64_encode($path)."|".md5($code)."%%INJECTLATER%%";
|
280 |
+
}
|
281 |
+
|
282 |
+
if(!empty($code)) {
|
283 |
+
$tmp_thiscss = preg_replace('#(/\*FILESTART\*/.*)'.preg_quote($import,'#').'#Us','/*FILESTART2*/'.$code.'$1',$thiscss);
|
284 |
+
if (!empty($tmp_thiscss)) {
|
285 |
+
$thiscss = $tmp_thiscss;
|
286 |
+
$import_ok = true;
|
287 |
+
unset($tmp_thiscss);
|
288 |
+
}
|
289 |
+
unset($code);
|
290 |
+
}
|
291 |
+
}
|
292 |
+
}
|
293 |
+
|
294 |
+
if (!$import_ok) {
|
295 |
+
// external imports and general fall-back
|
296 |
+
$external_imports .= $import;
|
297 |
+
$thiscss = str_replace($import,'',$thiscss);
|
298 |
+
$fiximports = true;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
$thiscss = preg_replace('#/\*FILESTART\*/#','',$thiscss);
|
302 |
+
$thiscss = preg_replace('#/\*FILESTART2\*/#','/*FILESTART*/',$thiscss);
|
303 |
+
}
|
304 |
+
|
305 |
+
// add external imports to top of aggregated CSS
|
306 |
+
if($fiximports) {
|
307 |
+
$thiscss=$external_imports.$thiscss;
|
308 |
+
}
|
309 |
+
}
|
310 |
+
unset($thiscss);
|
311 |
+
|
312 |
+
// $this->csscode has all the uncompressed code now.
|
313 |
+
$mhtmlcount = 0;
|
314 |
+
foreach($this->csscode as &$code) {
|
315 |
+
// Check for already-minified code
|
316 |
+
$hash = md5($code);
|
317 |
+
$ccheck = new Breeze_MinificationCache($hash,'css');
|
318 |
+
if($ccheck->check()) {
|
319 |
+
$code = $ccheck->retrieve();
|
320 |
+
$this->hashmap[md5($code)] = $hash;
|
321 |
+
continue;
|
322 |
+
}
|
323 |
+
unset($ccheck);
|
324 |
+
|
325 |
+
// Do the imaging!
|
326 |
+
$imgreplace = array();
|
327 |
+
preg_match_all('#(background[^;}]*url\((?!\s?"?\s?data)(.*)\)[^;}]*)(?:;|$|})#Usm',$code,$matches);
|
328 |
+
|
329 |
+
if(($this->datauris == true) && (function_exists('base64_encode')) && (is_array($matches))) {
|
330 |
+
foreach($matches[2] as $count => $quotedurl) {
|
331 |
+
$iurl = trim($quotedurl," \t\n\r\0\x0B\"'");
|
332 |
+
|
333 |
+
// if querystring, remove it from url
|
334 |
+
if (strpos($iurl,'?') !== false) { $iurl = strtok($iurl,'?'); }
|
335 |
+
|
336 |
+
$ipath = $this->getpath($iurl);
|
337 |
+
|
338 |
+
$datauri_max_size = 4096;
|
339 |
+
$datauri_max_size = (int) apply_filters( 'breeze_filter_css_datauri_maxsize', $datauri_max_size );
|
340 |
+
$datauri_exclude = apply_filters( 'breeze_filter_css_datauri_exclude', "");
|
341 |
+
if (!empty($datauri_exclude)) {
|
342 |
+
$no_datauris=array_filter(array_map('trim',explode(",",$datauri_exclude)));
|
343 |
+
foreach ($no_datauris as $no_datauri) {
|
344 |
+
if (strpos($iurl,$no_datauri)!==false) {
|
345 |
+
$ipath=false;
|
346 |
+
break;
|
347 |
+
}
|
348 |
+
}
|
349 |
+
}
|
350 |
+
|
351 |
+
if($ipath != false && preg_match('#\.(jpe?g|png|gif|bmp)$#i',$ipath) && file_exists($ipath) && is_readable($ipath) && filesize($ipath) <= $datauri_max_size) {
|
352 |
+
$ihash=md5($ipath);
|
353 |
+
$icheck = new Breeze_MinificationCache($ihash,'img');
|
354 |
+
if($icheck->check()) {
|
355 |
+
// we have the base64 image in cache
|
356 |
+
$headAndData=$icheck->retrieve();
|
357 |
+
$_base64data=explode(";base64,",$headAndData);
|
358 |
+
$base64data=$_base64data[1];
|
359 |
+
} else {
|
360 |
+
// It's an image and we don't have it in cache, get the type
|
361 |
+
$explA=explode('.',$ipath);
|
362 |
+
$type=end($explA);
|
363 |
+
|
364 |
+
switch($type) {
|
365 |
+
case 'jpeg':
|
366 |
+
$dataurihead = 'data:image/jpeg;base64,';
|
367 |
+
break;
|
368 |
+
case 'jpg':
|
369 |
+
$dataurihead = 'data:image/jpeg;base64,';
|
370 |
+
break;
|
371 |
+
case 'gif':
|
372 |
+
$dataurihead = 'data:image/gif;base64,';
|
373 |
+
break;
|
374 |
+
case 'png':
|
375 |
+
$dataurihead = 'data:image/png;base64,';
|
376 |
+
break;
|
377 |
+
case 'bmp':
|
378 |
+
$dataurihead = 'data:image/bmp;base64,';
|
379 |
+
break;
|
380 |
+
default:
|
381 |
+
$dataurihead = 'data:application/octet-stream;base64,';
|
382 |
+
}
|
383 |
+
|
384 |
+
// Encode the data
|
385 |
+
$base64data = base64_encode(file_get_contents($ipath));
|
386 |
+
$headAndData=$dataurihead.$base64data;
|
387 |
+
|
388 |
+
// Save in cache
|
389 |
+
$icheck->cache($headAndData,"text/plain");
|
390 |
+
}
|
391 |
+
unset($icheck);
|
392 |
+
|
393 |
+
// Add it to the list for replacement
|
394 |
+
$imgreplace[$matches[1][$count]] = str_replace($quotedurl,$headAndData,$matches[1][$count]).";\n*".str_replace($quotedurl,'mhtml:%%MHTML%%!'.$mhtmlcount,$matches[1][$count]).";\n_".$matches[1][$count].';';
|
395 |
+
|
396 |
+
// Store image on the mhtml document
|
397 |
+
$this->mhtml .= "--_\r\nContent-Location:{$mhtmlcount}\r\nContent-Transfer-Encoding:base64\r\n\r\n{$base64data}\r\n";
|
398 |
+
$mhtmlcount++;
|
399 |
+
} else {
|
400 |
+
// just cdn the URL if applicable
|
401 |
+
if (!empty($this->cdn_url)) {
|
402 |
+
$url = trim($quotedurl," \t\n\r\0\x0B\"'");
|
403 |
+
$cdn_url=$this->url_replace_cdn($url);
|
404 |
+
$imgreplace[$matches[1][$count]] = str_replace($quotedurl,$cdn_url,$matches[1][$count]);
|
405 |
+
}
|
406 |
+
}
|
407 |
+
}
|
408 |
+
} else if ((is_array($matches)) && (!empty($this->cdn_url))) {
|
409 |
+
// change background image urls to cdn-url
|
410 |
+
foreach($matches[2] as $count => $quotedurl) {
|
411 |
+
$url = trim($quotedurl," \t\n\r\0\x0B\"'");
|
412 |
+
$cdn_url=$this->url_replace_cdn($url);
|
413 |
+
$imgreplace[$matches[1][$count]] = str_replace($quotedurl,$cdn_url,$matches[1][$count]);
|
414 |
+
}
|
415 |
+
}
|
416 |
+
|
417 |
+
if(!empty($imgreplace)) {
|
418 |
+
$code = str_replace(array_keys($imgreplace),array_values($imgreplace),$code);
|
419 |
+
}
|
420 |
+
|
421 |
+
// CDN the fonts!
|
422 |
+
if ( (!empty($this->cdn_url)) && (apply_filters('breeze_filter_css_fonts_cdn',false)) && (version_compare(PHP_VERSION, '5.3.0') >= 0) ) {
|
423 |
+
$fontreplace = array();
|
424 |
+
include_once(BREEZE_PLUGIN_DIR.'inc/minification/config/minificationFontRegex.php');
|
425 |
+
|
426 |
+
preg_match_all($fonturl_regex,$code,$matches);
|
427 |
+
if (is_array($matches)) {
|
428 |
+
foreach($matches[8] as $count => $quotedurl) {
|
429 |
+
$url = trim($quotedurl," \t\n\r\0\x0B\"'");
|
430 |
+
$cdn_url=$this->url_replace_cdn($url);
|
431 |
+
$fontreplace[$matches[8][$count]] = str_replace($quotedurl,$cdn_url,$matches[8][$count]);
|
432 |
+
}
|
433 |
+
if(!empty($fontreplace)) {
|
434 |
+
$code = str_replace(array_keys($fontreplace),array_values($fontreplace),$code);
|
435 |
+
}
|
436 |
+
}
|
437 |
+
}
|
438 |
+
|
439 |
+
// Minify
|
440 |
+
if (($this->alreadyminified!==true) && (apply_filters( "breeze_css_do_minify", true))) {
|
441 |
+
if (class_exists('Minify_CSS_Compressor')) {
|
442 |
+
$tmp_code = trim(Minify_CSS_Compressor::process($code));
|
443 |
+
} else if(class_exists('CSSmin')) {
|
444 |
+
$cssmin = new CSSmin();
|
445 |
+
if (method_exists($cssmin,"run")) {
|
446 |
+
$tmp_code = trim($cssmin->run($code));
|
447 |
+
} elseif (@is_callable(array($cssmin,"minify"))) {
|
448 |
+
$tmp_code = trim(CssMin::minify($code));
|
449 |
+
}
|
450 |
+
}
|
451 |
+
if (!empty($tmp_code)) {
|
452 |
+
$code = $tmp_code;
|
453 |
+
unset($tmp_code);
|
454 |
+
}
|
455 |
+
}
|
456 |
+
|
457 |
+
$code = $this->inject_minified($code);
|
458 |
+
|
459 |
+
$tmp_code = apply_filters( 'breeze_css_after_minify',$code );
|
460 |
+
if (!empty($tmp_code)) {
|
461 |
+
$code = $tmp_code;
|
462 |
+
unset($tmp_code);
|
463 |
+
}
|
464 |
+
|
465 |
+
$this->hashmap[md5($code)] = $hash;
|
466 |
+
}
|
467 |
+
unset($code);
|
468 |
+
}else{
|
469 |
+
foreach ($this->css_group_val as $value){
|
470 |
+
$media = substr($value, 0 , strpos($value,'_breezecssgroup_'));
|
471 |
+
$css = substr($value,strpos($value,'_breezecssgroup_')+strlen('_breezecssgroup_'));
|
472 |
+
|
473 |
+
$hash = md5($css);
|
474 |
+
$ccheck = new Breeze_MinificationCache($hash,'css');
|
475 |
+
if($ccheck->check()) {
|
476 |
+
$css_exist = $ccheck->retrieve();
|
477 |
+
$this->css_min_arr[] = $media."_breezemedia_".$hash."_breezekey_".$css_exist;
|
478 |
+
continue;
|
479 |
+
}
|
480 |
+
unset($ccheck);
|
481 |
+
|
482 |
+
// Minify
|
483 |
+
|
484 |
+
if (class_exists('Minify_CSS_Compressor')) {
|
485 |
+
$tmp_code = trim(Minify_CSS_Compressor::process($css));
|
486 |
+
} else if(class_exists('CSSmin')) {
|
487 |
+
$cssmin = new CSSmin();
|
488 |
+
if (method_exists($cssmin,"run")) {
|
489 |
+
$tmp_code = trim($cssmin->run($css));
|
490 |
+
} elseif (@is_callable(array($cssmin,"minify"))) {
|
491 |
+
$tmp_code = trim(CssMin::minify($css));
|
492 |
+
}
|
493 |
+
|
494 |
+
}
|
495 |
+
if (!empty($tmp_code)) {
|
496 |
+
$css = $tmp_code;
|
497 |
+
unset($tmp_code);
|
498 |
+
}
|
499 |
+
|
500 |
+
$css = $this->inject_minified($css);
|
501 |
+
$css = apply_filters( 'breeze_css_after_minify',$css );
|
502 |
+
$this->css_min_arr[] = $media."_breezemedia_".$hash."_breezekey_".$css;
|
503 |
+
}
|
504 |
+
unset($css);
|
505 |
+
|
506 |
+
}
|
507 |
+
return true;
|
508 |
+
}
|
509 |
+
|
510 |
+
//Caches the CSS in uncompressed, deflated and gzipped form.
|
511 |
+
public function cache() {
|
512 |
+
if($this->datauris) {
|
513 |
+
// MHTML Preparation
|
514 |
+
$this->mhtml = "/*\r\nContent-Type: multipart/related; boundary=\"_\"\r\n\r\n".$this->mhtml."*/\r\n";
|
515 |
+
$md5 = md5($this->mhtml);
|
516 |
+
$cache = new Breeze_MinificationCache($md5,'txt');
|
517 |
+
if(!$cache->check()) {
|
518 |
+
// Cache our images for IE
|
519 |
+
$cache->cache($this->mhtml,'text/plain');
|
520 |
+
}
|
521 |
+
$mhtml = breeze_CACHE_URL.$cache->getname();
|
522 |
+
}
|
523 |
+
if($this->group_css == true){
|
524 |
+
// CSS cache
|
525 |
+
foreach($this->csscode as $media => $code) {
|
526 |
+
$md5 = $this->hashmap[md5($code)];
|
527 |
+
|
528 |
+
if($this->datauris) {
|
529 |
+
// Images for ie! Get the right url
|
530 |
+
$code = str_replace('%%MHTML%%',$mhtml,$code);
|
531 |
+
}
|
532 |
+
|
533 |
+
$cache = new Breeze_MinificationCache($md5,'css');
|
534 |
+
if(!$cache->check()) {
|
535 |
+
// Cache our code
|
536 |
+
$cache->cache($code,'text/css');
|
537 |
+
}
|
538 |
+
$this->url[$media] = breeze_CACHE_URL.$cache->getname();
|
539 |
+
}
|
540 |
+
}else{
|
541 |
+
foreach ($this->css_min_arr as $value){
|
542 |
+
$media = substr($value,0,strpos($value,'_breezemedia_'));
|
543 |
+
$code = substr($value,strpos($value,'_breezemedia_')+strlen('_breezemedia_'));
|
544 |
+
$hash = substr($code,0,strpos($code,'_breezekey_'));
|
545 |
+
$css = substr($code,strpos($code,'_breezekey_')+strlen('_breezekey_'));
|
546 |
+
|
547 |
+
$cache = new Breeze_MinificationCache($hash,'css');
|
548 |
+
if(!$cache->check()) {
|
549 |
+
// Cache our code
|
550 |
+
$cache->cache($css,'text/css');
|
551 |
+
}
|
552 |
+
$this->url_group_arr[] = $media."_breezemedia_".$hash."_breezekey_".breeze_CACHE_URL.$cache->getname();
|
553 |
+
}
|
554 |
+
}
|
555 |
+
}
|
556 |
+
|
557 |
+
//Returns the content
|
558 |
+
public function getcontent() {
|
559 |
+
// restore IE hacks
|
560 |
+
$this->content = $this->restore_iehacks($this->content);
|
561 |
+
|
562 |
+
// restore comments
|
563 |
+
$this->content = $this->restore_comments($this->content);
|
564 |
+
|
565 |
+
// restore (no)script
|
566 |
+
if ( strpos( $this->content, '%%SCRIPT%%' ) !== false ) {
|
567 |
+
$this->content = preg_replace_callback(
|
568 |
+
'#%%SCRIPT'.breeze_HASH.'%%(.*?)%%SCRIPT%%#is',
|
569 |
+
create_function(
|
570 |
+
'$matches',
|
571 |
+
'return base64_decode($matches[1]);'
|
572 |
+
),
|
573 |
+
$this->content
|
574 |
+
);
|
575 |
+
}
|
576 |
+
|
577 |
+
// restore noptimize
|
578 |
+
$this->content = $this->restore_noptimize($this->content);
|
579 |
+
|
580 |
+
//Restore the full content
|
581 |
+
if(!empty($this->restofcontent)) {
|
582 |
+
$this->content .= $this->restofcontent;
|
583 |
+
$this->restofcontent = '';
|
584 |
+
}
|
585 |
+
|
586 |
+
// Inject the new stylesheets
|
587 |
+
$replaceTag = array("<title","before");
|
588 |
+
$replaceTag = apply_filters( 'breeze_filter_css_replacetag', $replaceTag );
|
589 |
+
if($this->group_css == true){
|
590 |
+
if ($this->inline == true) {
|
591 |
+
foreach($this->csscode as $media => $code) {
|
592 |
+
$this->inject_in_html('<style type="text/css" media="'.$media.'">'.$code.'</style>',$replaceTag);
|
593 |
+
}
|
594 |
+
} else {
|
595 |
+
if ($this->defer == true) {
|
596 |
+
$deferredCssBlock = "<script data-cfasync='false'>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media;aoin=d.getElementsByTagName('noscript')[0];aoin.parentNode.insertBefore(l,aoin.nextSibling);}function deferredCSS() {";
|
597 |
+
$noScriptCssBlock = "<noscript>";
|
598 |
+
$defer_inline_code=$this->defer_inline;
|
599 |
+
$defer_inline_code=apply_filters( 'breeze_filter_css_defer_inline', $defer_inline_code );
|
600 |
+
if(!empty($defer_inline_code)){
|
601 |
+
|
602 |
+
$iCssHash=md5($defer_inline_code);
|
603 |
+
$iCssCache = new Breeze_MinificationCache($iCssHash,'css');
|
604 |
+
if($iCssCache->check()) {
|
605 |
+
// we have the optimized inline CSS in cache
|
606 |
+
$defer_inline_code=$iCssCache->retrieve();
|
607 |
+
} else {
|
608 |
+
if (class_exists('Minify_CSS_Compressor')) {
|
609 |
+
$tmp_code = trim(Minify_CSS_Compressor::process($this->defer_inline));
|
610 |
+
} else if(class_exists('CSSmin')) {
|
611 |
+
$cssmin = new CSSmin();
|
612 |
+
$tmp_code = trim($cssmin->run($defer_inline_code));
|
613 |
+
}
|
614 |
+
|
615 |
+
if (!empty($tmp_code)) {
|
616 |
+
$defer_inline_code = $tmp_code;
|
617 |
+
$iCssCache->cache($defer_inline_code,"text/css");
|
618 |
+
unset($tmp_code);
|
619 |
+
}
|
620 |
+
}
|
621 |
+
$code_out='<style type="text/css" id="aoatfcss" media="all">'.$defer_inline_code.'</style>';
|
622 |
+
$this->inject_in_html($code_out,$replaceTag);
|
623 |
+
}
|
624 |
+
}
|
625 |
+
|
626 |
+
foreach($this->url as $media => $url) {
|
627 |
+
$url = $this->url_replace_cdn($url);
|
628 |
+
|
629 |
+
//Add the stylesheet either deferred (import at bottom) or normal links in head
|
630 |
+
if($this->defer == true) {
|
631 |
+
$deferredCssBlock .= "lCss('".$url."','".$media."');";
|
632 |
+
$noScriptCssBlock .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
|
633 |
+
} else {
|
634 |
+
if (strlen($this->csscode[$media]) > $this->cssinlinesize) {
|
635 |
+
$this->inject_in_html('<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />',$replaceTag);
|
636 |
+
} else if (strlen($this->csscode[$media])>0) {
|
637 |
+
$this->inject_in_html('<style type="text/css" media="'.$media.'">'.$this->csscode[$media].'</style>',$replaceTag);
|
638 |
+
}
|
639 |
+
}
|
640 |
+
}
|
641 |
+
|
642 |
+
if($this->defer == true) {
|
643 |
+
$deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
|
644 |
+
$noScriptCssBlock .= "</noscript>";
|
645 |
+
$this->inject_in_html($noScriptCssBlock,$replaceTag);
|
646 |
+
$this->inject_in_html($deferredCssBlock,array('</body>','before'));
|
647 |
+
}
|
648 |
+
}
|
649 |
+
}else{
|
650 |
+
|
651 |
+
if ($this->inline == true) {
|
652 |
+
foreach($this->csscode as $media => $code) {
|
653 |
+
$this->inject_in_html('<style type="text/css" media="'.$media.'">'.$code.'</style>',$replaceTag);
|
654 |
+
}
|
655 |
+
} else {
|
656 |
+
if ($this->defer == true) {
|
657 |
+
$deferredCssBlock = "<script data-cfasync='false'>function lCss(url,media) {var d=document;var l=d.createElement('link');l.rel='stylesheet';l.type='text/css';l.href=url;l.media=media;aoin=d.getElementsByTagName('noscript')[0];aoin.parentNode.insertBefore(l,aoin.nextSibling);}function deferredCSS() {";
|
658 |
+
$noScriptCssBlock = "<noscript>";
|
659 |
+
$defer_inline_code=$this->defer_inline;
|
660 |
+
$defer_inline_code=apply_filters( 'breeze_filter_css_defer_inline', $defer_inline_code );
|
661 |
+
if(!empty($defer_inline_code)){
|
662 |
+
|
663 |
+
$iCssHash=md5($defer_inline_code);
|
664 |
+
$iCssCache = new Breeze_MinificationCache($iCssHash,'css');
|
665 |
+
if($iCssCache->check()) {
|
666 |
+
// we have the optimized inline CSS in cache
|
667 |
+
$defer_inline_code=$iCssCache->retrieve();
|
668 |
+
} else {
|
669 |
+
if (class_exists('Minify_CSS_Compressor')) {
|
670 |
+
$tmp_code = trim(Minify_CSS_Compressor::process($this->defer_inline));
|
671 |
+
} else if(class_exists('CSSmin')) {
|
672 |
+
$cssmin = new CSSmin();
|
673 |
+
$tmp_code = trim($cssmin->run($defer_inline_code));
|
674 |
+
}
|
675 |
+
|
676 |
+
if (!empty($tmp_code)) {
|
677 |
+
$defer_inline_code = $tmp_code;
|
678 |
+
$iCssCache->cache($defer_inline_code,"text/css");
|
679 |
+
unset($tmp_code);
|
680 |
+
}
|
681 |
+
}
|
682 |
+
$code_out='<style type="text/css" id="aoatfcss" media="all">'.$defer_inline_code.'</style>';
|
683 |
+
$this->inject_in_html($code_out,$replaceTag);
|
684 |
+
}
|
685 |
+
}
|
686 |
+
|
687 |
+
foreach ($this->url_group_arr as $value){
|
688 |
+
$media = substr($value,0,strpos($value,'_breezemedia_'));
|
689 |
+
$code = substr($value,strpos($value,'_breezemedia_')+strlen('_breezemedia_'));
|
690 |
+
$hash = substr($code,0,strpos($code,'_breezekey_'));
|
691 |
+
$url = substr($code,strpos($code,'_breezekey_')+strlen('_breezekey_'));
|
692 |
+
|
693 |
+
$cache = new Breeze_MinificationCache($hash,'css');
|
694 |
+
if($cache->check()) {
|
695 |
+
$csscode = $cache->retrieve();
|
696 |
+
}
|
697 |
+
//Add the stylesheet either deferred (import at bottom) or normal links in head
|
698 |
+
if($this->defer == true) {
|
699 |
+
$deferredCssBlock .= "lCss('".$url."','".$media."');";
|
700 |
+
$noScriptCssBlock .= '<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />';
|
701 |
+
} else {
|
702 |
+
if (strlen($csscode) > $this->cssinlinesize) {
|
703 |
+
$url = $this->url_replace_cdn($url);
|
704 |
+
$this->inject_in_html('<link type="text/css" media="'.$media.'" href="'.$url.'" rel="stylesheet" />',$replaceTag);
|
705 |
+
} else if (strlen($csscode)>0) {
|
706 |
+
$this->inject_in_html('<style type="text/css" media="'.$media.'">'.$csscode.'</style>',$replaceTag);
|
707 |
+
}
|
708 |
+
}
|
709 |
+
}
|
710 |
+
|
711 |
+
if($this->defer == true) {
|
712 |
+
$deferredCssBlock .= "}if(window.addEventListener){window.addEventListener('DOMContentLoaded',deferredCSS,false);}else{window.onload = deferredCSS;}</script>";
|
713 |
+
$noScriptCssBlock .= "</noscript>";
|
714 |
+
$this->inject_in_html($noScriptCssBlock,$replaceTag);
|
715 |
+
$this->inject_in_html($deferredCssBlock,array('</body>','before'));
|
716 |
+
}
|
717 |
+
}
|
718 |
+
}
|
719 |
+
|
720 |
+
|
721 |
+
//Return the modified stylesheet
|
722 |
+
return $this->content;
|
723 |
+
}
|
724 |
+
|
725 |
+
static function fixurls($file,$code) {
|
726 |
+
$file = str_replace(BREEZE_ROOT_DIR,'/',$file);
|
727 |
+
$dir = dirname($file); //Like /wp-content
|
728 |
+
|
729 |
+
// quick fix for import-troubles in e.g. arras theme
|
730 |
+
$code=preg_replace('#@import ("|\')(.+?)\.css("|\')#','@import url("${2}.css")',$code);
|
731 |
+
|
732 |
+
if(preg_match_all('#url\((?!data)(?!\#)(?!"\#)(.*)\)#Usi',$code,$matches)) {
|
733 |
+
$replace = array();
|
734 |
+
foreach($matches[1] as $k => $url) {
|
735 |
+
// Remove quotes
|
736 |
+
$url = trim($url," \t\n\r\0\x0B\"'");
|
737 |
+
$noQurl = trim($url,"\"'");
|
738 |
+
if ($url!==$noQurl) {
|
739 |
+
$removedQuotes=true;
|
740 |
+
} else {
|
741 |
+
$removedQuotes=false;
|
742 |
+
}
|
743 |
+
$url=$noQurl;
|
744 |
+
if(substr($url,0,1)=='/' || preg_match('#^(https?://|ftp://|data:)#i',$url)) {
|
745 |
+
//URL is absolute
|
746 |
+
continue;
|
747 |
+
} else {
|
748 |
+
// relative URL
|
749 |
+
$newurl = preg_replace('/https?:/','',str_replace(" ","%20",breeze_WP_ROOT_URL.str_replace('//','/',$dir.'/'.$url)));
|
750 |
+
|
751 |
+
$hash = md5($url);
|
752 |
+
$code = str_replace($matches[0][$k],$hash,$code);
|
753 |
+
|
754 |
+
if (!empty($removedQuotes)) {
|
755 |
+
$replace[$hash] = 'url(\''.$newurl.'\')';
|
756 |
+
} else {
|
757 |
+
$replace[$hash] = 'url('.$newurl.')';
|
758 |
+
}
|
759 |
+
}
|
760 |
+
}
|
761 |
+
//Do the replacing here to avoid breaking URLs
|
762 |
+
$code = str_replace(array_keys($replace),array_values($replace),$code);
|
763 |
+
}
|
764 |
+
return $code;
|
765 |
+
}
|
766 |
+
|
767 |
+
private function ismovable($tag) {
|
768 |
+
if (!empty($this->whitelist)) {
|
769 |
+
foreach ($this->whitelist as $match) {
|
770 |
+
if(strpos($tag,$match)!==false) {
|
771 |
+
return true;
|
772 |
+
}
|
773 |
+
}
|
774 |
+
// no match with whitelist
|
775 |
+
return false;
|
776 |
+
} else {
|
777 |
+
if (is_array($this->dontmove)) {
|
778 |
+
foreach($this->dontmove as $match) {
|
779 |
+
if(strpos($tag,$match)!==false) {
|
780 |
+
//Matched something
|
781 |
+
return false;
|
782 |
+
}
|
783 |
+
}
|
784 |
+
}
|
785 |
+
|
786 |
+
//If we're here it's safe to move
|
787 |
+
return true;
|
788 |
+
}
|
789 |
+
}
|
790 |
+
|
791 |
+
private function can_inject_late($cssPath,$css) {
|
792 |
+
if ((strpos($cssPath,"min.css")===false) || ($this->inject_min_late!==true)) {
|
793 |
+
// late-inject turned off or file not minified based on filename
|
794 |
+
return false;
|
795 |
+
} else if (strpos($css,"@import")!==false) {
|
796 |
+
// can't late-inject files with imports as those need to be aggregated
|
797 |
+
return false;
|
798 |
+
} else if ( (strpos($css,"@font-face")!==false ) && ( apply_filters("breeze_filter_css_fonts_cdn",false)===true) && (!empty($this->cdn_url)) ) {
|
799 |
+
// don't late-inject CSS with font-src's if fonts are set to be CDN'ed
|
800 |
+
return false;
|
801 |
+
} else if ( (($this->datauris == true) || (!empty($this->cdn_url))) && preg_match("#background[^;}]*url\(#Ui",$css) ) {
|
802 |
+
// don't late-inject CSS with images if CDN is set OR is image inlining is on
|
803 |
+
return false;
|
804 |
+
} else {
|
805 |
+
// phew, all is safe, we can late-inject
|
806 |
+
return true;
|
807 |
+
}
|
808 |
+
}
|
809 |
+
}
|
inc/minification/breeze-minify-main.php
ADDED
@@ -0,0 +1,255 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @copyright 2017 Cloudways https://www.cloudways.com
|
4 |
+
*
|
5 |
+
* Original development of this plugin by JoomUnited https://www.joomunited.com/
|
6 |
+
*
|
7 |
+
* This program is free software; you can redistribute it and/or modify
|
8 |
+
* it under the terms of the GNU General Public License as published by
|
9 |
+
* the Free Software Foundation; either version 2 of the License, or
|
10 |
+
* (at your option) any later version.
|
11 |
+
*
|
12 |
+
* This program is distributed in the hope that it will be useful,
|
13 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
+
* GNU General Public License for more details.
|
16 |
+
*
|
17 |
+
* You should have received a copy of the GNU General Public License
|
18 |
+
* along with this program; if not, write to the Free Software
|
19 |
+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
+
*/
|
21 |
+
defined('ABSPATH') || die('No direct script access allowed!');
|
22 |
+
|
23 |
+
class Breeze_Minify {
|
24 |
+
|
25 |
+
public function __construct()
|
26 |
+
{
|
27 |
+
//check disable cache for page
|
28 |
+
$domain = (((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS']!=='off') || $_SERVER['SERVER_PORT']==443) ? 'https://':'http://' ).$_SERVER['HTTP_HOST'];
|
29 |
+
$current_url = $domain.$_SERVER['REQUEST_URI'];
|
30 |
+
|
31 |
+
$check_url = $this->check_exclude_url($current_url);
|
32 |
+
|
33 |
+
//load config file when redirect template
|
34 |
+
if (!in_array($current_url, $check_url)) {
|
35 |
+
//cache html
|
36 |
+
//cache minification
|
37 |
+
if (Breeze_MinificationCache::create_cache_minification_folder()) {
|
38 |
+
$conf = get_option('breeze_basic_settings');
|
39 |
+
if ( !empty($conf['breeze-minify-html']) || !empty($conf['breeze-minify-css']) || !empty($conf['breeze-minify-js']) ) {
|
40 |
+
if (defined('breeze_INIT_EARLIER')) {
|
41 |
+
add_action('init', array($this,'breeze_start_buffering'), -1);
|
42 |
+
} else {
|
43 |
+
add_action('template_redirect', array($this,'breeze_start_buffering'), 2);
|
44 |
+
}
|
45 |
+
}
|
46 |
+
}
|
47 |
+
}
|
48 |
+
|
49 |
+
}
|
50 |
+
/*
|
51 |
+
* Start buffer
|
52 |
+
*/
|
53 |
+
public function breeze_start_buffering(){
|
54 |
+
$ao_noptimize = false;
|
55 |
+
|
56 |
+
// check for DONOTMINIFY constant as used by e.g. WooCommerce POS
|
57 |
+
if (defined('DONOTMINIFY') && (constant('DONOTMINIFY') === true || constant('DONOTMINIFY') === "true")) {
|
58 |
+
$ao_noptimize = true;
|
59 |
+
}
|
60 |
+
// filter you can use to block autoptimization on your own terms
|
61 |
+
$ao_noptimize = (bool) apply_filters('breeze_filter_noptimize', $ao_noptimize);
|
62 |
+
if (!is_feed() && !$ao_noptimize && !is_admin()) {
|
63 |
+
// Config element
|
64 |
+
$conf = get_option('breeze_basic_settings');
|
65 |
+
// Load our base class
|
66 |
+
include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-base.php');
|
67 |
+
|
68 |
+
// Load extra classes and set some vars
|
69 |
+
if (!empty($conf['breeze-minify-html'])) {
|
70 |
+
include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-html.php');
|
71 |
+
// BUG: new minify-html does not support keeping HTML comments, skipping for now
|
72 |
+
if(!class_exists('Minify_HTML')){
|
73 |
+
@include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-html.php');
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
if (!empty($conf['breeze-minify-js'])) {
|
78 |
+
include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-scripts.php');
|
79 |
+
if (!class_exists('JSMin')) {
|
80 |
+
if (defined('breeze_LEGACY_MINIFIERS')) {
|
81 |
+
@include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/jsmin-1.1.1.php');
|
82 |
+
} else {
|
83 |
+
@include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-2.1.7-jsmin.php');
|
84 |
+
}
|
85 |
+
}
|
86 |
+
if (!defined('CONCATENATE_SCRIPTS')) {
|
87 |
+
define('CONCATENATE_SCRIPTS', false);
|
88 |
+
}
|
89 |
+
if (!defined('COMPRESS_SCRIPTS')) {
|
90 |
+
define('COMPRESS_SCRIPTS', false);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
if (!empty($conf['breeze-minify-css'])) {
|
94 |
+
include_once(BREEZE_PLUGIN_DIR . 'inc/minification/breeze-minification-styles.php');
|
95 |
+
if (defined('breeze_LEGACY_MINIFIERS')) {
|
96 |
+
if (!class_exists('Minify_CSS_Compressor')) {
|
97 |
+
@include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/minify-css-compressor.php');
|
98 |
+
}
|
99 |
+
} else {
|
100 |
+
if (!class_exists('CSSmin')) {
|
101 |
+
@include(BREEZE_PLUGIN_DIR . 'inc/minification/minify/yui-php-cssmin-2.4.8-4_fgo.php');
|
102 |
+
}
|
103 |
+
}
|
104 |
+
if (!defined('COMPRESS_CSS')) {
|
105 |
+
define('COMPRESS_CSS', false);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
// Now, start the real thing!
|
109 |
+
add_filter('breeze_minify_content_return',array($this,'breeze_end_buffering'));
|
110 |
+
}
|
111 |
+
}
|
112 |
+
|
113 |
+
/*
|
114 |
+
* Minify css , js and optimize html when start
|
115 |
+
*/
|
116 |
+
|
117 |
+
public function breeze_end_buffering($content) {
|
118 |
+
if (stripos($content, "<html") === false || stripos($content, "<html amp") !== false || stripos($content, "<html ⚡") !== false || stripos($content, "<xsl:stylesheet") !== false) {
|
119 |
+
return $content;
|
120 |
+
}
|
121 |
+
// load URL constants as late as possible to allow domain mapper to kick in
|
122 |
+
if (function_exists("domain_mapping_siteurl")) {
|
123 |
+
define('breeze_WP_SITE_URL', domain_mapping_siteurl(get_current_blog_id()));
|
124 |
+
define('breeze_WP_CONTENT_URL', str_replace(get_original_url(breeze_WP_SITE_URL), breeze_WP_SITE_URL, content_url()));
|
125 |
+
} else {
|
126 |
+
define('breeze_WP_SITE_URL', site_url());
|
127 |
+
define('breeze_WP_CONTENT_URL', content_url());
|
128 |
+
}
|
129 |
+
if (is_multisite() && apply_filters('breeze_separate_blog_caches', true)) {
|
130 |
+
$blog_id = get_current_blog_id();
|
131 |
+
define('breeze_CACHE_URL', breeze_WP_CONTENT_URL . BREEZE_CACHE_CHILD_DIR . $blog_id . '/');
|
132 |
+
} else {
|
133 |
+
define('breeze_CACHE_URL', breeze_WP_CONTENT_URL . BREEZE_CACHE_CHILD_DIR);
|
134 |
+
}
|
135 |
+
define('breeze_WP_ROOT_URL', str_replace(BREEZE_WP_CONTENT_NAME, '', breeze_WP_CONTENT_URL));
|
136 |
+
|
137 |
+
define('breeze_HASH',wp_hash(breeze_CACHE_URL));
|
138 |
+
// Config element
|
139 |
+
$conf = get_option('breeze_basic_settings');
|
140 |
+
$minify = get_option('breeze_advanced_settings');
|
141 |
+
|
142 |
+
// Choose the classes
|
143 |
+
$classes = array();
|
144 |
+
if (!empty($conf['breeze-minify-js']))
|
145 |
+
$classes[] = 'Breeze_MinificationScripts';
|
146 |
+
if (!empty($conf['breeze-minify-css']))
|
147 |
+
$classes[] = 'Breeze_MinificationStyles';
|
148 |
+
if (!empty($conf['breeze-minify-html']))
|
149 |
+
$classes[] = 'Breeze_MinificationHtml';
|
150 |
+
$groupcss = false;
|
151 |
+
$groupjs = false;
|
152 |
+
if (!empty($minify['breeze-group-css'])){
|
153 |
+
$groupcss = true;
|
154 |
+
}
|
155 |
+
if (!empty($minify['breeze-group-js'])){
|
156 |
+
$groupjs = true;
|
157 |
+
}
|
158 |
+
// Set some options
|
159 |
+
$classoptions = array(
|
160 |
+
'Breeze_MinificationScripts' => array(
|
161 |
+
'justhead' => false,
|
162 |
+
'forcehead' => false,
|
163 |
+
'trycatch' => false,
|
164 |
+
'js_exclude' => "s_sid, smowtion_size, sc_project, WAU_, wau_add, comment-form-quicktags, edToolbar, ch_client, seal.js",
|
165 |
+
'cdn_url' => "",
|
166 |
+
'include_inline' => true,
|
167 |
+
'group_js' => $groupjs,
|
168 |
+
'custom_js_exclude' => $minify['breeze-exclude-js']
|
169 |
+
),
|
170 |
+
'Breeze_MinificationStyles' => array(
|
171 |
+
'justhead' => false,
|
172 |
+
'datauris' => false,
|
173 |
+
'defer' => false,
|
174 |
+
'defer_inline' => false,
|
175 |
+
'inline' => false,
|
176 |
+
'css_exclude' => "admin-bar.min.css, dashicons.min.css",
|
177 |
+
'cdn_url' => "",
|
178 |
+
'include_inline' => true,
|
179 |
+
'nogooglefont' => false,
|
180 |
+
'groupcss' => $groupcss,
|
181 |
+
'custom_css_exclude' => $minify['breeze-exclude-css']
|
182 |
+
),
|
183 |
+
'Breeze_MinificationHtml' => array(
|
184 |
+
'keepcomments' => false
|
185 |
+
)
|
186 |
+
);
|
187 |
+
|
188 |
+
$content = apply_filters('breeze_filter_html_before_minify', $content);
|
189 |
+
|
190 |
+
if (!empty($conf) && $conf['breeze-disable-admin'] && current_user_can('manage_options')) {
|
191 |
+
$content = apply_filters('breeze_html_after_minify', $content);
|
192 |
+
}else{
|
193 |
+
// Run the classes
|
194 |
+
foreach ($classes as $name) {
|
195 |
+
$instance = new $name($content);
|
196 |
+
|
197 |
+
if ($instance->read($classoptions[$name])) {
|
198 |
+
$instance->minify();
|
199 |
+
$instance->cache();
|
200 |
+
$content = $instance->getcontent();
|
201 |
+
}
|
202 |
+
unset($instance);
|
203 |
+
}
|
204 |
+
$content = apply_filters('breeze_html_after_minify', $content);
|
205 |
+
}
|
206 |
+
return $content;
|
207 |
+
}
|
208 |
+
/*
|
209 |
+
* check url from Never cache the following pages area
|
210 |
+
*/
|
211 |
+
public function check_exclude_url($current_url){
|
212 |
+
|
213 |
+
$check_url = array();
|
214 |
+
$opts_config = get_option('breeze_advanced_settings');
|
215 |
+
if (!empty($opts_config['breeze-exclude-urls'])) {
|
216 |
+
foreach ($opts_config['breeze-exclude-urls'] as $v) {
|
217 |
+
if ($v && $v[0] == '/') {
|
218 |
+
//part url
|
219 |
+
if (preg_match('[\*]', $v) == 1) {
|
220 |
+
$v = substr($v, 0, strpos($v, "/(.*)"));
|
221 |
+
if(!empty($v)){
|
222 |
+
if(strpos($current_url,$v) != false){
|
223 |
+
$check_url[] = $current_url;
|
224 |
+
}
|
225 |
+
}
|
226 |
+
} else {
|
227 |
+
if(!empty($v)){
|
228 |
+
if(strpos($current_url,$v) != false){
|
229 |
+
$url = $current_url;
|
230 |
+
}else{
|
231 |
+
$url = BREEZE_SITEURL . $v;
|
232 |
+
}
|
233 |
+
}
|
234 |
+
$check_url[] = $url;
|
235 |
+
}
|
236 |
+
} else {
|
237 |
+
if(preg_match('[\*]', $v) == 1){
|
238 |
+
$v = substr($v, 0, strpos($v, "&(.*)"));
|
239 |
+
$v = substr($v, -10);
|
240 |
+
if(!empty($v)){
|
241 |
+
if(strpos($current_url,$v) != false){
|
242 |
+
$check_url[] = $current_url;
|
243 |
+
}
|
244 |
+
}
|
245 |
+
}else{
|
246 |
+
//full url
|
247 |
+
$check_url[] = $v;
|
248 |
+
}
|
249 |
+
}
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
return $check_url;
|
254 |
+
}
|
255 |
+
}
|
inc/minification/config/default.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php exit;
|
2 |
+
|
3 |
+
//Check everything exists before using it
|
4 |
+
if(!isset($_SERVER['HTTP_ACCEPT_ENCODING']))
|
5 |
+
$_SERVER['HTTP_ACCEPT_ENCODING'] = '';
|
6 |
+
if(!isset($_SERVER['HTTP_USER_AGENT']))
|
7 |
+
$_SERVER['HTTP_USER_AGENT'] = '';
|
8 |
+
|
9 |
+
// Determine supported compression method
|
10 |
+
$gzip = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
|
11 |
+
$deflate = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate');
|
12 |
+
|
13 |
+
// Determine used compression method
|
14 |
+
$encoding = $gzip ? 'gzip' : ($deflate ? 'deflate' : 'none');
|
15 |
+
|
16 |
+
// Check for buggy versions of Internet Explorer
|
17 |
+
if (!strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') &&
|
18 |
+
preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $matches))
|
19 |
+
{
|
20 |
+
$version = floatval($matches[1]);
|
21 |
+
|
22 |
+
if ($version < 6)
|
23 |
+
$encoding = 'none';
|
24 |
+
|
25 |
+
if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'EV1'))
|
26 |
+
$encoding = 'none';
|
27 |
+
}
|
28 |
+
|
29 |
+
//Some servers compress the output of PHP - Don't break in those cases
|
30 |
+
if(ini_get('output_handler') == 'ob_gzhandler' || ini_get('zlib.output_compression') == 1)
|
31 |
+
$encoding = 'none';
|
32 |
+
|
33 |
+
//Get data
|
34 |
+
$contents = file_get_contents(__FILE__.'.'.$encoding);
|
35 |
+
|
36 |
+
// first check if we have to send 304
|
37 |
+
$eTag=md5($contents);
|
38 |
+
$modTime=filemtime(__FILE__.'.none');
|
39 |
+
|
40 |
+
$eTagMatch = (isset($_SERVER['HTTP_IF_NONE_MATCH']) && strpos($_SERVER['HTTP_IF_NONE_MATCH'],$eTag));
|
41 |
+
$modTimeMatch = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modTime);
|
42 |
+
|
43 |
+
if (($modTimeMatch)||($eTagMatch)) {
|
44 |
+
header('HTTP/1.1 304 Not Modified');
|
45 |
+
header('Connection: close');
|
46 |
+
} else {
|
47 |
+
// send all sorts of headers
|
48 |
+
$expireTime=60*60*24*356; // 1y max according to RFC
|
49 |
+
|
50 |
+
if(isset($encoding) && $encoding != 'none')
|
51 |
+
{
|
52 |
+
header('Content-Encoding: '.$encoding);
|
53 |
+
}
|
54 |
+
header('Vary: Accept-Encoding');
|
55 |
+
header('Content-Length: '.strlen($contents));
|
56 |
+
header('Content-type: %%CONTENT%%; charset=utf-8');
|
57 |
+
header('Cache-Control: max-age='.$expireTime.', public, must-revalidate');
|
58 |
+
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expireTime).' GMT'); //10 years
|
59 |
+
header('ETag: ' . $eTag);
|
60 |
+
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modTime).' GMT');
|
61 |
+
|
62 |
+
// send output
|
63 |
+
echo $contents;
|
64 |
+
}
|
inc/minification/config/delayed.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php exit;
|
2 |
+
|
3 |
+
//Check everything exists before using it
|
4 |
+
if(!isset($_SERVER['HTTP_ACCEPT_ENCODING']))
|
5 |
+
$_SERVER['HTTP_ACCEPT_ENCODING'] = '';
|
6 |
+
if(!isset($_SERVER['HTTP_USER_AGENT']))
|
7 |
+
$_SERVER['HTTP_USER_AGENT'] = '';
|
8 |
+
|
9 |
+
// Determine supported compression method
|
10 |
+
$gzip = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
|
11 |
+
$deflate = strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'deflate');
|
12 |
+
|
13 |
+
// Determine used compression method
|
14 |
+
$encoding = $gzip ? 'gzip' : ($deflate ? 'deflate' : 'none');
|
15 |
+
|
16 |
+
// Check for buggy versions of Internet Explorer
|
17 |
+
if (!strstr($_SERVER['HTTP_USER_AGENT'], 'Opera') &&
|
18 |
+
preg_match('/^Mozilla\/4\.0 \(compatible; MSIE ([0-9]\.[0-9])/i', $_SERVER['HTTP_USER_AGENT'], $matches))
|
19 |
+
{
|
20 |
+
$version = floatval($matches[1]);
|
21 |
+
|
22 |
+
if ($version < 6)
|
23 |
+
$encoding = 'none';
|
24 |
+
|
25 |
+
if ($version == 6 && !strstr($_SERVER['HTTP_USER_AGENT'], 'EV1'))
|
26 |
+
$encoding = 'none';
|
27 |
+
}
|
28 |
+
|
29 |
+
//Some servers compress the output of PHP - Don't break in those cases
|
30 |
+
if(ini_get('output_handler') == 'ob_gzhandler' || ini_get('zlib.output_compression') == 1)
|
31 |
+
$encoding = 'none';
|
32 |
+
|
33 |
+
$iscompressed = file_exists(__FILE__.'.'.$encoding);
|
34 |
+
if($encoding != 'none' && $iscompressed == false)
|
35 |
+
{
|
36 |
+
$flag = ($encoding == 'gzip' ? FORCE_GZIP : FORCE_DEFLATE);
|
37 |
+
$code = file_get_contents(__FILE__.'.none');
|
38 |
+
$contents = gzencode($code,9,$flag);
|
39 |
+
}else{
|
40 |
+
//Get data
|
41 |
+
$contents = file_get_contents(__FILE__.'.'.$encoding);
|
42 |
+
}
|
43 |
+
|
44 |
+
// first check if we have to send 304
|
45 |
+
// inspired by http://www.jonasjohn.de/snippets/php/caching.htm
|
46 |
+
|
47 |
+
$eTag=md5($contents);
|
48 |
+
$modTime=filemtime(__FILE__.'.none');
|
49 |
+
|
50 |
+
$eTagMatch = (isset($_SERVER['HTTP_IF_NONE_MATCH']) && strpos($_SERVER['HTTP_IF_NONE_MATCH'],$eTag));
|
51 |
+
$modTimeMatch = (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) === $modTime);
|
52 |
+
|
53 |
+
if (($modTimeMatch)||($eTagMatch)) {
|
54 |
+
header('HTTP/1.1 304 Not Modified');
|
55 |
+
header('Connection: close');
|
56 |
+
} else {
|
57 |
+
// send all sorts of headers
|
58 |
+
$expireTime=60*60*24*355; // 1y max according to RFC
|
59 |
+
if ($encoding != 'none') {
|
60 |
+
header('Content-Encoding: '.$encoding);
|
61 |
+
}
|
62 |
+
header('Vary: Accept-Encoding');
|
63 |
+
header('Content-Length: '.strlen($contents));
|
64 |
+
header('Content-type: %%CONTENT%%; charset=utf-8');
|
65 |
+
header('Cache-Control: max-age='.$expireTime.', public, must-revalidate');
|
66 |
+
header('Expires: '.gmdate('D, d M Y H:i:s', time() + $expireTime).' GMT');
|
67 |
+
header('ETag: ' . $eTag);
|
68 |
+
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $modTime).' GMT');
|
69 |
+
|
70 |
+
// send output
|
71 |
+
echo $contents;
|
72 |
+
|
73 |
+
//And write to filesystem cache if not done yet
|
74 |
+
if($encoding != 'none' && $iscompressed == false)
|
75 |
+
{
|
76 |
+
//Write the content we sent
|
77 |
+
file_put_contents(__FILE__.'.'.$encoding,$contents);
|
78 |
+
|
79 |
+
//And write the new content
|
80 |
+
$flag = ($encoding == 'gzip' ? FORCE_DEFLATE : FORCE_GZIP);
|
81 |
+
$ext = ($encoding == 'gzip' ? 'deflate' : 'gzip');
|
82 |
+
$contents = gzencode($code,9,$flag);
|
83 |
+
file_put_contents(__FILE__.'.'.$ext,$contents);
|
84 |
+
}
|
85 |
+
}
|
inc/minification/config/minificationFontRegex.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// regex to find fonts, externalised to avoid nasty errors for php<5.3
|
3 |
+
|
4 |
+
$fonturl_regex = <<<'LOD'
|
5 |
+
~(?(DEFINE)(?<quoted_content>(["']) (?>[^"'\\]++ | \\{2} | \\. | (?!\g{-1})["'] )*+ \g{-1})(?<comment> /\* .*? \*/ ) (?<url_skip>(?: data: ) [^"'\s)}]*+ ) (?<other_content>(?> [^u}/"']++ | \g<quoted_content> | \g<comment> | \Bu | u(?!rl\s*+\() | /(?!\*) | \g<url_start> \g<url_skip> ["']?+ )++ ) (?<anchor> \G(?<!^) ["']?+ | @font-face \s*+ { ) (?<url_start> url\( \s*+ ["']?+ ) ) \g<comment> (*SKIP)(*FAIL) | \g<anchor> \g<other_content>?+ \g<url_start> \K ((?:(?:https?:)?(?://[[:alnum:]\-\.]+)(?::[0-9]+)?)?\/[^"'\s)}]*+) ~xs
|
6 |
+
LOD;
|
7 |
+
|
8 |
+
?>
|
inc/minification/minify/index.html
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<html><head><meta name="robots" content="noindex, nofollow"></head><body>Generated by <a href="http://wordpress.org/extend/plugins/autoptimize/" rel="nofollow">Autoptimize</a></body></html>
|
inc/minification/minify/jsmin-1.1.1.php
ADDED
@@ -0,0 +1,291 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* jsmin.php - PHP implementation of Douglas Crockford's JSMin.
|
4 |
+
*
|
5 |
+
* This is pretty much a direct port of jsmin.c to PHP with just a few
|
6 |
+
* PHP-specific performance tweaks. Also, whereas jsmin.c reads from stdin and
|
7 |
+
* outputs to stdout, this library accepts a string as input and returns another
|
8 |
+
* string as output.
|
9 |
+
*
|
10 |
+
* PHP 5 or higher is required.
|
11 |
+
*
|
12 |
+
* Permission is hereby granted to use this version of the library under the
|
13 |
+
* same terms as jsmin.c, which has the following license:
|
14 |
+
*
|
15 |
+
* --
|
16 |
+
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
17 |
+
*
|
18 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
19 |
+
* this software and associated documentation files (the "Software"), to deal in
|
20 |
+
* the Software without restriction, including without limitation the rights to
|
21 |
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
22 |
+
* of the Software, and to permit persons to whom the Software is furnished to do
|
23 |
+
* so, subject to the following conditions:
|
24 |
+
*
|
25 |
+
* The above copyright notice and this permission notice shall be included in all
|
26 |
+
* copies or substantial portions of the Software.
|
27 |
+
*
|
28 |
+
* The Software shall be used for Good, not Evil.
|
29 |
+
*
|
30 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
31 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
32 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
33 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
34 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
35 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
36 |
+
* SOFTWARE.
|
37 |
+
* --
|
38 |
+
*
|
39 |
+
* @package JSMin
|
40 |
+
* @author Ryan Grove <ryan@wonko.com>
|
41 |
+
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
42 |
+
* @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
|
43 |
+
* @license http://opensource.org/licenses/mit-license.php MIT License
|
44 |
+
* @version 1.1.1 (2008-03-02)
|
45 |
+
* @link http://code.google.com/p/jsmin-php/
|
46 |
+
*/
|
47 |
+
|
48 |
+
class JSMin {
|
49 |
+
const ORD_LF = 10;
|
50 |
+
const ORD_SPACE = 32;
|
51 |
+
|
52 |
+
protected $a = '';
|
53 |
+
protected $b = '';
|
54 |
+
protected $input = '';
|
55 |
+
protected $inputIndex = 0;
|
56 |
+
protected $inputLength = 0;
|
57 |
+
protected $lookAhead = null;
|
58 |
+
protected $output = '';
|
59 |
+
|
60 |
+
// -- Public Static Methods --------------------------------------------------
|
61 |
+
|
62 |
+
public static function minify($js) {
|
63 |
+
$jsmin = new JSMin($js);
|
64 |
+
return $jsmin->min();
|
65 |
+
}
|
66 |
+
|
67 |
+
// -- Public Instance Methods ------------------------------------------------
|
68 |
+
|
69 |
+
public function __construct($input) {
|
70 |
+
$this->input = str_replace("\r\n", "\n", $input);
|
71 |
+
$this->inputLength = strlen($this->input);
|
72 |
+
}
|
73 |
+
|
74 |
+
// -- Protected Instance Methods ---------------------------------------------
|
75 |
+
|
76 |
+
protected function action($d) {
|
77 |
+
switch($d) {
|
78 |
+
case 1:
|
79 |
+
$this->output .= $this->a;
|
80 |
+
|
81 |
+
case 2:
|
82 |
+
$this->a = $this->b;
|
83 |
+
|
84 |
+
if ($this->a === "'" || $this->a === '"') {
|
85 |
+
for (;;) {
|
86 |
+
$this->output .= $this->a;
|
87 |
+
$this->a = $this->get();
|
88 |
+
|
89 |
+
if ($this->a === $this->b) {
|
90 |
+
break;
|
91 |
+
}
|
92 |
+
|
93 |
+
if (ord($this->a) <= self::ORD_LF) {
|
94 |
+
throw new JSMinException('Unterminated string literal.');
|
95 |
+
}
|
96 |
+
|
97 |
+
if ($this->a === '\\') {
|
98 |
+
$this->output .= $this->a;
|
99 |
+
$this->a = $this->get();
|
100 |
+
}
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
case 3:
|
105 |
+
$this->b = $this->next();
|
106 |
+
|
107 |
+
if ($this->b === '/' && (
|
108 |
+
$this->a === '(' || $this->a === ',' || $this->a === '=' ||
|
109 |
+
$this->a === ':' || $this->a === '[' || $this->a === '!' ||
|
110 |
+
$this->a === '&' || $this->a === '|' || $this->a === '?')) {
|
111 |
+
|
112 |
+
$this->output .= $this->a . $this->b;
|
113 |
+
|
114 |
+
for (;;) {
|
115 |
+
$this->a = $this->get();
|
116 |
+
|
117 |
+
if ($this->a === '/') {
|
118 |
+
break;
|
119 |
+
} elseif ($this->a === '\\') {
|
120 |
+
$this->output .= $this->a;
|
121 |
+
$this->a = $this->get();
|
122 |
+
} elseif (ord($this->a) <= self::ORD_LF) {
|
123 |
+
throw new JSMinException('Unterminated regular expression '.
|
124 |
+
'literal.');
|
125 |
+
}
|
126 |
+
|
127 |
+
$this->output .= $this->a;
|
128 |
+
}
|
129 |
+
|
130 |
+
$this->b = $this->next();
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
protected function get() {
|
136 |
+
$c = $this->lookAhead;
|
137 |
+
$this->lookAhead = null;
|
138 |
+
|
139 |
+
if ($c === null) {
|
140 |
+
if ($this->inputIndex < $this->inputLength) {
|
141 |
+
$c = $this->input[$this->inputIndex];
|
142 |
+
$this->inputIndex += 1;
|
143 |
+
} else {
|
144 |
+
$c = null;
|
145 |
+
}
|
146 |
+
}
|
147 |
+
|
148 |
+
if ($c === "\r") {
|
149 |
+
return "\n";
|
150 |
+
}
|
151 |
+
|
152 |
+
if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
|
153 |
+
return $c;
|
154 |
+
}
|
155 |
+
|
156 |
+
return ' ';
|
157 |
+
}
|
158 |
+
|
159 |
+
protected function isAlphaNum($c) {
|
160 |
+
return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
|
161 |
+
}
|
162 |
+
|
163 |
+
protected function min() {
|
164 |
+
$this->a = "\n";
|
165 |
+
$this->action(3);
|
166 |
+
|
167 |
+
while ($this->a !== null) {
|
168 |
+
switch ($this->a) {
|
169 |
+
case ' ':
|
170 |
+
if ($this->isAlphaNum($this->b)) {
|
171 |
+
$this->action(1);
|
172 |
+
} else {
|
173 |
+
$this->action(2);
|
174 |
+
}
|
175 |
+
break;
|
176 |
+
|
177 |
+
case "\n":
|
178 |
+
switch ($this->b) {
|
179 |
+
case '{':
|
180 |
+
case '[':
|
181 |
+
case '(':
|
182 |
+
case '+':
|
183 |
+
case '-':
|
184 |
+
$this->action(1);
|
185 |
+
break;
|
186 |
+
|
187 |
+
case ' ':
|
188 |
+
$this->action(3);
|
189 |
+
break;
|
190 |
+
|
191 |
+
default:
|
192 |
+
if ($this->isAlphaNum($this->b)) {
|
193 |
+
$this->action(1);
|
194 |
+
}
|
195 |
+
else {
|
196 |
+
$this->action(2);
|
197 |
+
}
|
198 |
+
}
|
199 |
+
break;
|
200 |
+
|
201 |
+
default:
|
202 |
+
switch ($this->b) {
|
203 |
+
case ' ':
|
204 |
+
if ($this->isAlphaNum($this->a)) {
|
205 |
+
$this->action(1);
|
206 |
+
break;
|
207 |
+
}
|
208 |
+
|
209 |
+
$this->action(3);
|
210 |
+
break;
|
211 |
+
|
212 |
+
case "\n":
|
213 |
+
switch ($this->a) {
|
214 |
+
case '}':
|
215 |
+
case ']':
|
216 |
+
case ')':
|
217 |
+
case '+':
|
218 |
+
case '-':
|
219 |
+
case '"':
|
220 |
+
case "'":
|
221 |
+
$this->action(1);
|
222 |
+
break;
|
223 |
+
|
224 |
+
default:
|
225 |
+
if ($this->isAlphaNum($this->a)) {
|
226 |
+
$this->action(1);
|
227 |
+
}
|
228 |
+
else {
|
229 |
+
$this->action(3);
|
230 |
+
}
|
231 |
+
}
|
232 |
+
break;
|
233 |
+
|
234 |
+
default:
|
235 |
+
$this->action(1);
|
236 |
+
break;
|
237 |
+
}
|
238 |
+
}
|
239 |
+
}
|
240 |
+
|
241 |
+
return $this->output;
|
242 |
+
}
|
243 |
+
|
244 |
+
protected function next() {
|
245 |
+
$c = $this->get();
|
246 |
+
|
247 |
+
if ($c === '/') {
|
248 |
+
switch($this->peek()) {
|
249 |
+
case '/':
|
250 |
+
for (;;) {
|
251 |
+
$c = $this->get();
|
252 |
+
|
253 |
+
if (ord($c) <= self::ORD_LF) {
|
254 |
+
return $c;
|
255 |
+
}
|
256 |
+
}
|
257 |
+
|
258 |
+
case '*':
|
259 |
+
$this->get();
|
260 |
+
|
261 |
+
for (;;) {
|
262 |
+
switch($this->get()) {
|
263 |
+
case '*':
|
264 |
+
if ($this->peek() === '/') {
|
265 |
+
$this->get();
|
266 |
+
return ' ';
|
267 |
+
}
|
268 |
+
break;
|
269 |
+
|
270 |
+
case null:
|
271 |
+
throw new JSMinException('Unterminated comment.');
|
272 |
+
}
|
273 |
+
}
|
274 |
+
|
275 |
+
default:
|
276 |
+
return $c;
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
return $c;
|
281 |
+
}
|
282 |
+
|
283 |
+
protected function peek() {
|
284 |
+
$this->lookAhead = $this->get();
|
285 |
+
return $this->lookAhead;
|
286 |
+
}
|
287 |
+
}
|
288 |
+
|
289 |
+
// -- Exceptions ---------------------------------------------------------------
|
290 |
+
class JSMinException extends Exception {}
|
291 |
+
?>
|
inc/minification/minify/minify-2.1.7-html.php
ADDED
@@ -0,0 +1,257 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_HTML
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Compress HTML
|
9 |
+
*
|
10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
11 |
+
* tokens. IE conditional comments are preserved. There are also options to have
|
12 |
+
* STYLE and SCRIPT blocks compressed by callback functions.
|
13 |
+
*
|
14 |
+
* A test suite is available.
|
15 |
+
*
|
16 |
+
* @package Minify
|
17 |
+
* @author Stephen Clay <steve@mrclay.org>
|
18 |
+
*/
|
19 |
+
class Minify_HTML {
|
20 |
+
/**
|
21 |
+
* @var boolean
|
22 |
+
*/
|
23 |
+
protected $_jsCleanComments = true;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* "Minify" an HTML page
|
27 |
+
*
|
28 |
+
* @param string $html
|
29 |
+
*
|
30 |
+
* @param array $options
|
31 |
+
*
|
32 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
33 |
+
* elements.
|
34 |
+
*
|
35 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
36 |
+
* elements. Note: the type attribute is ignored.
|
37 |
+
*
|
38 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
39 |
+
* unset, minify will sniff for an XHTML doctype.
|
40 |
+
*
|
41 |
+
* @return string
|
42 |
+
*/
|
43 |
+
public static function minify($html, $options = array()) {
|
44 |
+
$min = new self($html, $options);
|
45 |
+
return $min->process();
|
46 |
+
}
|
47 |
+
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Create a minifier object
|
51 |
+
*
|
52 |
+
* @param string $html
|
53 |
+
*
|
54 |
+
* @param array $options
|
55 |
+
*
|
56 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
57 |
+
* elements.
|
58 |
+
*
|
59 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
60 |
+
* elements. Note: the type attribute is ignored.
|
61 |
+
*
|
62 |
+
* 'jsCleanComments' : (optional) whether to remove HTML comments beginning and end of script block
|
63 |
+
*
|
64 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
65 |
+
* unset, minify will sniff for an XHTML doctype.
|
66 |
+
*
|
67 |
+
* @return null
|
68 |
+
*/
|
69 |
+
public function __construct($html, $options = array())
|
70 |
+
{
|
71 |
+
$this->_html = str_replace("\r\n", "\n", trim($html));
|
72 |
+
if (isset($options['xhtml'])) {
|
73 |
+
$this->_isXhtml = (bool)$options['xhtml'];
|
74 |
+
}
|
75 |
+
if (isset($options['cssMinifier'])) {
|
76 |
+
$this->_cssMinifier = $options['cssMinifier'];
|
77 |
+
}
|
78 |
+
if (isset($options['jsMinifier'])) {
|
79 |
+
$this->_jsMinifier = $options['jsMinifier'];
|
80 |
+
}
|
81 |
+
if (isset($options['jsCleanComments'])) {
|
82 |
+
$this->_jsCleanComments = (bool)$options['jsCleanComments'];
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Minify the markeup given in the constructor
|
89 |
+
*
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
public function process()
|
93 |
+
{
|
94 |
+
if ($this->_isXhtml === null) {
|
95 |
+
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
96 |
+
}
|
97 |
+
|
98 |
+
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
|
99 |
+
$this->_placeholders = array();
|
100 |
+
|
101 |
+
// replace SCRIPTs (and minify) with placeholders
|
102 |
+
$this->_html = preg_replace_callback(
|
103 |
+
'/(\\s*)<script(\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
|
104 |
+
,array($this, '_removeScriptCB')
|
105 |
+
,$this->_html);
|
106 |
+
|
107 |
+
// replace STYLEs (and minify) with placeholders
|
108 |
+
$this->_html = preg_replace_callback(
|
109 |
+
'/\\s*<style(\\b[^>]*>)([\\s\\S]*?)<\\/style>\\s*/i'
|
110 |
+
,array($this, '_removeStyleCB')
|
111 |
+
,$this->_html);
|
112 |
+
|
113 |
+
// remove HTML comments (not containing IE conditional comments).
|
114 |
+
$this->_html = preg_replace_callback(
|
115 |
+
'/<!--([\\s\\S]*?)-->/'
|
116 |
+
,array($this, '_commentCB')
|
117 |
+
,$this->_html);
|
118 |
+
|
119 |
+
// replace PREs with placeholders
|
120 |
+
$this->_html = preg_replace_callback('/\\s*<pre(\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
121 |
+
,array($this, '_removePreCB')
|
122 |
+
,$this->_html);
|
123 |
+
|
124 |
+
// replace TEXTAREAs with placeholders
|
125 |
+
$this->_html = preg_replace_callback(
|
126 |
+
'/\\s*<textarea(\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
127 |
+
,array($this, '_removeTextareaCB')
|
128 |
+
,$this->_html);
|
129 |
+
|
130 |
+
// trim each line.
|
131 |
+
// @todo take into account attribute values that span multiple lines.
|
132 |
+
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
|
133 |
+
|
134 |
+
// remove ws around block/undisplayed elements
|
135 |
+
$this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body'
|
136 |
+
.'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form'
|
137 |
+
.'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta'
|
138 |
+
.'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)'
|
139 |
+
.'|ul)\\b[^>]*>)/i', '$1', $this->_html);
|
140 |
+
|
141 |
+
// remove ws outside of all elements
|
142 |
+
$this->_html = preg_replace(
|
143 |
+
'/>(\\s(?:\\s*))?([^<]+)(\\s(?:\s*))?</'
|
144 |
+
,'>$1$2$3<'
|
145 |
+
,$this->_html);
|
146 |
+
|
147 |
+
// use newlines before 1st attribute in open tags (to limit line lengths)
|
148 |
+
$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
|
149 |
+
|
150 |
+
// fill placeholders
|
151 |
+
$this->_html = str_replace(
|
152 |
+
array_keys($this->_placeholders)
|
153 |
+
,array_values($this->_placeholders)
|
154 |
+
,$this->_html
|
155 |
+
);
|
156 |
+
// issue 229: multi-pass to catch scripts that didn't get replaced in textareas
|
157 |
+
$this->_html = str_replace(
|
158 |
+
array_keys($this->_placeholders)
|
159 |
+
,array_values($this->_placeholders)
|
160 |
+
,$this->_html
|
161 |
+
);
|
162 |
+
return $this->_html;
|
163 |
+
}
|
164 |
+
|
165 |
+
protected function _commentCB($m)
|
166 |
+
{
|
167 |
+
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
|
168 |
+
? $m[0]
|
169 |
+
: '';
|
170 |
+
}
|
171 |
+
|
172 |
+
protected function _reservePlace($content)
|
173 |
+
{
|
174 |
+
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
|
175 |
+
$this->_placeholders[$placeholder] = $content;
|
176 |
+
return $placeholder;
|
177 |
+
}
|
178 |
+
|
179 |
+
protected $_isXhtml = null;
|
180 |
+
protected $_replacementHash = null;
|
181 |
+
protected $_placeholders = array();
|
182 |
+
protected $_cssMinifier = null;
|
183 |
+
protected $_jsMinifier = null;
|
184 |
+
|
185 |
+
protected function _removePreCB($m)
|
186 |
+
{
|
187 |
+
return $this->_reservePlace("<pre{$m[1]}");
|
188 |
+
}
|
189 |
+
|
190 |
+
protected function _removeTextareaCB($m)
|
191 |
+
{
|
192 |
+
return $this->_reservePlace("<textarea{$m[1]}");
|
193 |
+
}
|
194 |
+
|
195 |
+
protected function _removeStyleCB($m)
|
196 |
+
{
|
197 |
+
$openStyle = "<style{$m[1]}";
|
198 |
+
$css = $m[2];
|
199 |
+
// remove HTML comments
|
200 |
+
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
201 |
+
|
202 |
+
// remove CDATA section markers
|
203 |
+
$css = $this->_removeCdata($css);
|
204 |
+
|
205 |
+
// minify
|
206 |
+
$minifier = $this->_cssMinifier
|
207 |
+
? $this->_cssMinifier
|
208 |
+
: 'trim';
|
209 |
+
$css = call_user_func($minifier, $css);
|
210 |
+
|
211 |
+
return $this->_reservePlace($this->_needsCdata($css)
|
212 |
+
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
213 |
+
: "{$openStyle}{$css}</style>"
|
214 |
+
);
|
215 |
+
}
|
216 |
+
|
217 |
+
protected function _removeScriptCB($m)
|
218 |
+
{
|
219 |
+
$openScript = "<script{$m[2]}";
|
220 |
+
$js = $m[3];
|
221 |
+
|
222 |
+
// whitespace surrounding? preserve at least one space
|
223 |
+
$ws1 = ($m[1] === '') ? '' : ' ';
|
224 |
+
$ws2 = ($m[4] === '') ? '' : ' ';
|
225 |
+
|
226 |
+
// remove HTML comments (and ending "//" if present)
|
227 |
+
if ($this->_jsCleanComments) {
|
228 |
+
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
229 |
+
}
|
230 |
+
|
231 |
+
// remove CDATA section markers
|
232 |
+
$js = $this->_removeCdata($js);
|
233 |
+
|
234 |
+
// minify
|
235 |
+
$minifier = $this->_jsMinifier
|
236 |
+
? $this->_jsMinifier
|
237 |
+
: 'trim';
|
238 |
+
$js = call_user_func($minifier, $js);
|
239 |
+
|
240 |
+
return $this->_reservePlace($this->_needsCdata($js)
|
241 |
+
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
|
242 |
+
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
|
243 |
+
);
|
244 |
+
}
|
245 |
+
|
246 |
+
protected function _removeCdata($str)
|
247 |
+
{
|
248 |
+
return (false !== strpos($str, '<![CDATA['))
|
249 |
+
? str_replace(array('<![CDATA[', ']]>'), '', $str)
|
250 |
+
: $str;
|
251 |
+
}
|
252 |
+
|
253 |
+
protected function _needsCdata($str)
|
254 |
+
{
|
255 |
+
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
256 |
+
}
|
257 |
+
}
|
inc/minification/minify/minify-2.1.7-jsmin.php
ADDED
@@ -0,0 +1,447 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* JSMin.php - modified PHP implementation of Douglas Crockford's JSMin.
|
4 |
+
*
|
5 |
+
* <code>
|
6 |
+
* $minifiedJs = JSMin::minify($js);
|
7 |
+
* </code>
|
8 |
+
*
|
9 |
+
* This is a modified port of jsmin.c. Improvements:
|
10 |
+
*
|
11 |
+
* Does not choke on some regexp literals containing quote characters. E.g. /'/
|
12 |
+
*
|
13 |
+
* Spaces are preserved after some add/sub operators, so they are not mistakenly
|
14 |
+
* converted to post-inc/dec. E.g. a + ++b -> a+ ++b
|
15 |
+
*
|
16 |
+
* Preserves multi-line comments that begin with /*!
|
17 |
+
*
|
18 |
+
* PHP 5 or higher is required.
|
19 |
+
*
|
20 |
+
* Permission is hereby granted to use this version of the library under the
|
21 |
+
* same terms as jsmin.c, which has the following license:
|
22 |
+
*
|
23 |
+
* --
|
24 |
+
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
25 |
+
*
|
26 |
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
27 |
+
* this software and associated documentation files (the "Software"), to deal in
|
28 |
+
* the Software without restriction, including without limitation the rights to
|
29 |
+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
30 |
+
* of the Software, and to permit persons to whom the Software is furnished to do
|
31 |
+
* so, subject to the following conditions:
|
32 |
+
*
|
33 |
+
* The above copyright notice and this permission notice shall be included in all
|
34 |
+
* copies or substantial portions of the Software.
|
35 |
+
*
|
36 |
+
* The Software shall be used for Good, not Evil.
|
37 |
+
*
|
38 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
39 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
40 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
41 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
42 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
43 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
44 |
+
* SOFTWARE.
|
45 |
+
* --
|
46 |
+
*
|
47 |
+
* @package JSMin
|
48 |
+
* @author Ryan Grove <ryan@wonko.com> (PHP port)
|
49 |
+
* @author Steve Clay <steve@mrclay.org> (modifications + cleanup)
|
50 |
+
* @author Andrea Giammarchi <http://www.3site.eu> (spaceBeforeRegExp)
|
51 |
+
* @copyright 2002 Douglas Crockford <douglas@crockford.com> (jsmin.c)
|
52 |
+
* @copyright 2008 Ryan Grove <ryan@wonko.com> (PHP port)
|
53 |
+
* @license http://opensource.org/licenses/mit-license.php MIT License
|
54 |
+
* @link http://code.google.com/p/jsmin-php/
|
55 |
+
*/
|
56 |
+
|
57 |
+
class JSMin {
|
58 |
+
const ORD_LF = 10;
|
59 |
+
const ORD_SPACE = 32;
|
60 |
+
const ACTION_KEEP_A = 1;
|
61 |
+
const ACTION_DELETE_A = 2;
|
62 |
+
const ACTION_DELETE_A_B = 3;
|
63 |
+
|
64 |
+
protected $a = "\n";
|
65 |
+
protected $b = '';
|
66 |
+
protected $input = '';
|
67 |
+
protected $inputIndex = 0;
|
68 |
+
protected $inputLength = 0;
|
69 |
+
protected $lookAhead = null;
|
70 |
+
protected $output = '';
|
71 |
+
protected $lastByteOut = '';
|
72 |
+
protected $keptComment = '';
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Minify Javascript.
|
76 |
+
*
|
77 |
+
* @param string $js Javascript to be minified
|
78 |
+
*
|
79 |
+
* @return string
|
80 |
+
*/
|
81 |
+
public static function minify($js)
|
82 |
+
{
|
83 |
+
$jsmin = new JSMin($js);
|
84 |
+
return $jsmin->min();
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @param string $input
|
89 |
+
*/
|
90 |
+
public function __construct($input)
|
91 |
+
{
|
92 |
+
$this->input = $input;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Perform minification, return result
|
97 |
+
*
|
98 |
+
* @return string
|
99 |
+
*/
|
100 |
+
public function min()
|
101 |
+
{
|
102 |
+
if ($this->output !== '') { // min already run
|
103 |
+
return $this->output;
|
104 |
+
}
|
105 |
+
|
106 |
+
$mbIntEnc = null;
|
107 |
+
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
108 |
+
$mbIntEnc = mb_internal_encoding();
|
109 |
+
mb_internal_encoding('8bit');
|
110 |
+
}
|
111 |
+
$this->input = str_replace("\r\n", "\n", $this->input);
|
112 |
+
$this->inputLength = strlen($this->input);
|
113 |
+
|
114 |
+
$this->action(self::ACTION_DELETE_A_B);
|
115 |
+
|
116 |
+
while ($this->a !== null) {
|
117 |
+
// determine next command
|
118 |
+
$command = self::ACTION_KEEP_A; // default
|
119 |
+
if ($this->a === ' ') {
|
120 |
+
if (($this->lastByteOut === '+' || $this->lastByteOut === '-')
|
121 |
+
&& ($this->b === $this->lastByteOut)) {
|
122 |
+
// Don't delete this space. If we do, the addition/subtraction
|
123 |
+
// could be parsed as a post-increment
|
124 |
+
} elseif (! $this->isAlphaNum($this->b)) {
|
125 |
+
$command = self::ACTION_DELETE_A;
|
126 |
+
}
|
127 |
+
} elseif ($this->a === "\n") {
|
128 |
+
if ($this->b === ' ') {
|
129 |
+
$command = self::ACTION_DELETE_A_B;
|
130 |
+
|
131 |
+
// in case of mbstring.func_overload & 2, must check for null b,
|
132 |
+
// otherwise mb_strpos will give WARNING
|
133 |
+
} elseif ($this->b === null
|
134 |
+
|| (false === strpos('{[(+-!~', $this->b)
|
135 |
+
&& ! $this->isAlphaNum($this->b))) {
|
136 |
+
$command = self::ACTION_DELETE_A;
|
137 |
+
}
|
138 |
+
} elseif (! $this->isAlphaNum($this->a)) {
|
139 |
+
if ($this->b === ' '
|
140 |
+
|| ($this->b === "\n"
|
141 |
+
&& (false === strpos('}])+-"\'', $this->a)))) {
|
142 |
+
$command = self::ACTION_DELETE_A_B;
|
143 |
+
}
|
144 |
+
}
|
145 |
+
$this->action($command);
|
146 |
+
}
|
147 |
+
$this->output = trim($this->output);
|
148 |
+
|
149 |
+
if ($mbIntEnc !== null) {
|
150 |
+
mb_internal_encoding($mbIntEnc);
|
151 |
+
}
|
152 |
+
return $this->output;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* ACTION_KEEP_A = Output A. Copy B to A. Get the next B.
|
157 |
+
* ACTION_DELETE_A = Copy B to A. Get the next B.
|
158 |
+
* ACTION_DELETE_A_B = Get the next B.
|
159 |
+
*
|
160 |
+
* @param int $command
|
161 |
+
* @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException
|
162 |
+
*/
|
163 |
+
protected function action($command)
|
164 |
+
{
|
165 |
+
// make sure we don't compress "a + ++b" to "a+++b", etc.
|
166 |
+
if ($command === self::ACTION_DELETE_A_B
|
167 |
+
&& $this->b === ' '
|
168 |
+
&& ($this->a === '+' || $this->a === '-')) {
|
169 |
+
// Note: we're at an addition/substraction operator; the inputIndex
|
170 |
+
// will certainly be a valid index
|
171 |
+
if ($this->input[$this->inputIndex] === $this->a) {
|
172 |
+
// This is "+ +" or "- -". Don't delete the space.
|
173 |
+
$command = self::ACTION_KEEP_A;
|
174 |
+
}
|
175 |
+
}
|
176 |
+
|
177 |
+
switch ($command) {
|
178 |
+
case self::ACTION_KEEP_A: // 1
|
179 |
+
$this->output .= $this->a;
|
180 |
+
|
181 |
+
if ($this->keptComment) {
|
182 |
+
$this->output = rtrim($this->output, "\n");
|
183 |
+
$this->output .= $this->keptComment;
|
184 |
+
$this->keptComment = '';
|
185 |
+
}
|
186 |
+
|
187 |
+
$this->lastByteOut = $this->a;
|
188 |
+
|
189 |
+
// fallthrough intentional
|
190 |
+
case self::ACTION_DELETE_A: // 2
|
191 |
+
$this->a = $this->b;
|
192 |
+
if ($this->a === "'" || $this->a === '"') { // string literal
|
193 |
+
$str = $this->a; // in case needed for exception
|
194 |
+
for(;;) {
|
195 |
+
$this->output .= $this->a;
|
196 |
+
$this->lastByteOut = $this->a;
|
197 |
+
|
198 |
+
$this->a = $this->get();
|
199 |
+
if ($this->a === $this->b) { // end quote
|
200 |
+
break;
|
201 |
+
}
|
202 |
+
if ($this->isEOF($this->a)) {
|
203 |
+
throw new JSMin_UnterminatedStringException(
|
204 |
+
"JSMin: Unterminated String at byte {$this->inputIndex}: {$str}");
|
205 |
+
}
|
206 |
+
$str .= $this->a;
|
207 |
+
if ($this->a === '\\') {
|
208 |
+
$this->output .= $this->a;
|
209 |
+
$this->lastByteOut = $this->a;
|
210 |
+
|
211 |
+
$this->a = $this->get();
|
212 |
+
$str .= $this->a;
|
213 |
+
}
|
214 |
+
}
|
215 |
+
}
|
216 |
+
|
217 |
+
// fallthrough intentional
|
218 |
+
case self::ACTION_DELETE_A_B: // 3
|
219 |
+
$this->b = $this->next();
|
220 |
+
if ($this->b === '/' && $this->isRegexpLiteral()) {
|
221 |
+
$this->output .= $this->a . $this->b;
|
222 |
+
$pattern = '/'; // keep entire pattern in case we need to report it in the exception
|
223 |
+
for(;;) {
|
224 |
+
$this->a = $this->get();
|
225 |
+
$pattern .= $this->a;
|
226 |
+
if ($this->a === '[') {
|
227 |
+
for(;;) {
|
228 |
+
$this->output .= $this->a;
|
229 |
+
$this->a = $this->get();
|
230 |
+
$pattern .= $this->a;
|
231 |
+
if ($this->a === ']') {
|
232 |
+
break;
|
233 |
+
}
|
234 |
+
if ($this->a === '\\') {
|
235 |
+
$this->output .= $this->a;
|
236 |
+
$this->a = $this->get();
|
237 |
+
$pattern .= $this->a;
|
238 |
+
}
|
239 |
+
if ($this->isEOF($this->a)) {
|
240 |
+
throw new JSMin_UnterminatedRegExpException(
|
241 |
+
"JSMin: Unterminated set in RegExp at byte "
|
242 |
+
. $this->inputIndex .": {$pattern}");
|
243 |
+
}
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
if ($this->a === '/') { // end pattern
|
248 |
+
break; // while (true)
|
249 |
+
} elseif ($this->a === '\\') {
|
250 |
+
$this->output .= $this->a;
|
251 |
+
$this->a = $this->get();
|
252 |
+
$pattern .= $this->a;
|
253 |
+
} elseif ($this->isEOF($this->a)) {
|
254 |
+
throw new JSMin_UnterminatedRegExpException(
|
255 |
+
"JSMin: Unterminated RegExp at byte {$this->inputIndex}: {$pattern}");
|
256 |
+
}
|
257 |
+
$this->output .= $this->a;
|
258 |
+
$this->lastByteOut = $this->a;
|
259 |
+
}
|
260 |
+
$this->b = $this->next();
|
261 |
+
}
|
262 |
+
// end case ACTION_DELETE_A_B
|
263 |
+
}
|
264 |
+
}
|
265 |
+
|
266 |
+
/**
|
267 |
+
* @return bool
|
268 |
+
*/
|
269 |
+
protected function isRegexpLiteral()
|
270 |
+
{
|
271 |
+
if (false !== strpos("(,=:[!&|?+-~*{;", $this->a)) {
|
272 |
+
// we obviously aren't dividing
|
273 |
+
return true;
|
274 |
+
}
|
275 |
+
|
276 |
+
// we have to check for a preceding keyword, and we don't need to pattern
|
277 |
+
// match over the whole output.
|
278 |
+
$recentOutput = substr($this->output, -10);
|
279 |
+
|
280 |
+
// check if return/typeof directly precede a pattern without a space
|
281 |
+
foreach (array('return', 'typeof') as $keyword) {
|
282 |
+
if ($this->a !== substr($keyword, -1)) {
|
283 |
+
// certainly wasn't keyword
|
284 |
+
continue;
|
285 |
+
}
|
286 |
+
if (preg_match("~(^|[\\s\\S])" . substr($keyword, 0, -1) . "$~", $recentOutput, $m)) {
|
287 |
+
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
288 |
+
return true;
|
289 |
+
}
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
// check all keywords
|
294 |
+
if ($this->a === ' ' || $this->a === "\n") {
|
295 |
+
if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) {
|
296 |
+
if ($m[1] === '' || !$this->isAlphaNum($m[1])) {
|
297 |
+
return true;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
}
|
301 |
+
|
302 |
+
return false;
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* Return the next character from stdin. Watch out for lookahead. If the character is a control character,
|
307 |
+
* translate it to a space or linefeed.
|
308 |
+
*
|
309 |
+
* @return string
|
310 |
+
*/
|
311 |
+
protected function get()
|
312 |
+
{
|
313 |
+
$c = $this->lookAhead;
|
314 |
+
$this->lookAhead = null;
|
315 |
+
if ($c === null) {
|
316 |
+
// getc(stdin)
|
317 |
+
if ($this->inputIndex < $this->inputLength) {
|
318 |
+
$c = $this->input[$this->inputIndex];
|
319 |
+
$this->inputIndex += 1;
|
320 |
+
} else {
|
321 |
+
$c = null;
|
322 |
+
}
|
323 |
+
}
|
324 |
+
if (ord($c) >= self::ORD_SPACE || $c === "\n" || $c === null) {
|
325 |
+
return $c;
|
326 |
+
}
|
327 |
+
if ($c === "\r") {
|
328 |
+
return "\n";
|
329 |
+
}
|
330 |
+
return ' ';
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Does $a indicate end of input?
|
335 |
+
*
|
336 |
+
* @param string $a
|
337 |
+
* @return bool
|
338 |
+
*/
|
339 |
+
protected function isEOF($a)
|
340 |
+
{
|
341 |
+
return ord($a) <= self::ORD_LF;
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Get next char (without getting it). If is ctrl character, translate to a space or newline.
|
346 |
+
*
|
347 |
+
* @return string
|
348 |
+
*/
|
349 |
+
protected function peek()
|
350 |
+
{
|
351 |
+
$this->lookAhead = $this->get();
|
352 |
+
return $this->lookAhead;
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Return true if the character is a letter, digit, underscore, dollar sign, or non-ASCII character.
|
357 |
+
*
|
358 |
+
* @param string $c
|
359 |
+
*
|
360 |
+
* @return bool
|
361 |
+
*/
|
362 |
+
protected function isAlphaNum($c)
|
363 |
+
{
|
364 |
+
return (preg_match('/^[a-z0-9A-Z_\\$\\\\]$/', $c) || ord($c) > 126);
|
365 |
+
}
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Consume a single line comment from input (possibly retaining it)
|
369 |
+
*/
|
370 |
+
protected function consumeSingleLineComment()
|
371 |
+
{
|
372 |
+
$comment = '';
|
373 |
+
while (true) {
|
374 |
+
$get = $this->get();
|
375 |
+
$comment .= $get;
|
376 |
+
if (ord($get) <= self::ORD_LF) { // end of line reached
|
377 |
+
// if IE conditional comment
|
378 |
+
if (preg_match('/^\\/@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
379 |
+
$this->keptComment .= "/{$comment}";
|
380 |
+
}
|
381 |
+
return;
|
382 |
+
}
|
383 |
+
}
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Consume a multiple line comment from input (possibly retaining it)
|
388 |
+
*
|
389 |
+
* @throws JSMin_UnterminatedCommentException
|
390 |
+
*/
|
391 |
+
protected function consumeMultipleLineComment()
|
392 |
+
{
|
393 |
+
$this->get();
|
394 |
+
$comment = '';
|
395 |
+
for(;;) {
|
396 |
+
$get = $this->get();
|
397 |
+
if ($get === '*') {
|
398 |
+
if ($this->peek() === '/') { // end of comment reached
|
399 |
+
$this->get();
|
400 |
+
if (0 === strpos($comment, '!')) {
|
401 |
+
// preserved by YUI Compressor
|
402 |
+
if (!$this->keptComment) {
|
403 |
+
// don't prepend a newline if two comments right after one another
|
404 |
+
$this->keptComment = "\n";
|
405 |
+
}
|
406 |
+
$this->keptComment .= "/*!" . substr($comment, 1) . "*/\n";
|
407 |
+
} else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) {
|
408 |
+
// IE conditional
|
409 |
+
$this->keptComment .= "/*{$comment}*/";
|
410 |
+
}
|
411 |
+
return;
|
412 |
+
}
|
413 |
+
} elseif ($get === null) {
|
414 |
+
throw new JSMin_UnterminatedCommentException(
|
415 |
+
"JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}");
|
416 |
+
}
|
417 |
+
$comment .= $get;
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Get the next character, skipping over comments. Some comments may be preserved.
|
423 |
+
*
|
424 |
+
* @return string
|
425 |
+
*/
|
426 |
+
protected function next()
|
427 |
+
{
|
428 |
+
$get = $this->get();
|
429 |
+
if ($get === '/') {
|
430 |
+
switch ($this->peek()) {
|
431 |
+
case '/':
|
432 |
+
$this->consumeSingleLineComment();
|
433 |
+
$get = "\n";
|
434 |
+
break;
|
435 |
+
case '*':
|
436 |
+
$this->consumeMultipleLineComment();
|
437 |
+
$get = ' ';
|
438 |
+
break;
|
439 |
+
}
|
440 |
+
}
|
441 |
+
return $get;
|
442 |
+
}
|
443 |
+
}
|
444 |
+
|
445 |
+
class JSMin_UnterminatedStringException extends Exception {}
|
446 |
+
class JSMin_UnterminatedCommentException extends Exception {}
|
447 |
+
class JSMin_UnterminatedRegExpException extends Exception {}
|
inc/minification/minify/minify-css-compressor.php
ADDED
@@ -0,0 +1,250 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_CSS_Compressor
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Compress CSS
|
9 |
+
*
|
10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary
|
11 |
+
* comments and tokens, and some CSS value minimization, where practical.
|
12 |
+
* Many steps have been taken to avoid breaking comment-based hacks,
|
13 |
+
* including the ie5/mac filter (and its inversion), but expect tricky
|
14 |
+
* hacks involving comment tokens in 'content' value strings to break
|
15 |
+
* minimization badly. A test suite is available.
|
16 |
+
*
|
17 |
+
* @package Minify
|
18 |
+
* @author Stephen Clay <steve@mrclay.org>
|
19 |
+
* @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
|
20 |
+
*/
|
21 |
+
class Minify_CSS_Compressor {
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Minify a CSS string
|
25 |
+
*
|
26 |
+
* @param string $css
|
27 |
+
*
|
28 |
+
* @param array $options (currently ignored)
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public static function process($css, $options = array())
|
33 |
+
{
|
34 |
+
$obj = new Minify_CSS_Compressor($options);
|
35 |
+
return $obj->_process($css);
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @var array options
|
40 |
+
*/
|
41 |
+
protected $_options = null;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @var bool Are we "in" a hack?
|
45 |
+
*
|
46 |
+
* I.e. are some browsers targetted until the next comment?
|
47 |
+
*/
|
48 |
+
protected $_inHack = false;
|
49 |
+
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Constructor
|
53 |
+
*
|
54 |
+
* @param array $options (currently ignored)
|
55 |
+
*
|
56 |
+
* @return null
|
57 |
+
*/
|
58 |
+
private function __construct($options) {
|
59 |
+
$this->_options = $options;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Minify a CSS string
|
64 |
+
*
|
65 |
+
* @param string $css
|
66 |
+
*
|
67 |
+
* @return string
|
68 |
+
*/
|
69 |
+
protected function _process($css)
|
70 |
+
{
|
71 |
+
$css = str_replace("\r\n", "\n", $css);
|
72 |
+
|
73 |
+
// preserve empty comment after '>'
|
74 |
+
// http://www.webdevout.net/css-hacks#in_css-selectors
|
75 |
+
$css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
|
76 |
+
|
77 |
+
// preserve empty comment between property and value
|
78 |
+
// http://css-discuss.incutio.com/?page=BoxModelHack
|
79 |
+
$css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
|
80 |
+
$css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
|
81 |
+
|
82 |
+
// apply callback to all valid comments (and strip out surrounding ws
|
83 |
+
$css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
|
84 |
+
,array($this, '_commentCB'), $css);
|
85 |
+
|
86 |
+
// remove ws around { } and last semicolon in declaration block
|
87 |
+
$css = preg_replace('/\\s*{\\s*/', '{', $css);
|
88 |
+
$css = preg_replace('/;?\\s*}\\s*/', '}', $css);
|
89 |
+
|
90 |
+
// remove ws surrounding semicolons
|
91 |
+
$css = preg_replace('/\\s*;\\s*/', ';', $css);
|
92 |
+
|
93 |
+
// remove ws around urls
|
94 |
+
$css = preg_replace('/
|
95 |
+
url\\( # url(
|
96 |
+
\\s*
|
97 |
+
([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
|
98 |
+
\\s*
|
99 |
+
\\) # )
|
100 |
+
/x', 'url($1)', $css);
|
101 |
+
|
102 |
+
// remove ws between rules and colons
|
103 |
+
$css = preg_replace('/
|
104 |
+
\\s*
|
105 |
+
([{;]) # 1 = beginning of block or rule separator
|
106 |
+
\\s*
|
107 |
+
([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
|
108 |
+
\\s*
|
109 |
+
:
|
110 |
+
\\s*
|
111 |
+
(\\b|[#\'"]) # 3 = first character of a value
|
112 |
+
/x', '$1$2:$3', $css);
|
113 |
+
|
114 |
+
// remove ws in selectors
|
115 |
+
$css = preg_replace_callback('/
|
116 |
+
(?: # non-capture
|
117 |
+
\\s*
|
118 |
+
[^~>+,\\s]+ # selector part
|
119 |
+
\\s*
|
120 |
+
[,>+~] # combinators
|
121 |
+
)+
|
122 |
+
\\s*
|
123 |
+
[^~>+,\\s]+ # selector part
|
124 |
+
{ # open declaration block
|
125 |
+
/x'
|
126 |
+
,array($this, '_selectorsCB'), $css);
|
127 |
+
|
128 |
+
// minimize hex colors
|
129 |
+
$css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
|
130 |
+
, '$1#$2$3$4$5', $css);
|
131 |
+
|
132 |
+
// remove spaces between font families
|
133 |
+
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
|
134 |
+
,array($this, '_fontFamilyCB'), $css);
|
135 |
+
|
136 |
+
$css = preg_replace('/@import\\s+url/', '@import url', $css);
|
137 |
+
|
138 |
+
// replace any ws involving newlines with a single newline
|
139 |
+
$css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
|
140 |
+
|
141 |
+
// separate common descendent selectors w/ newlines (to limit line lengths)
|
142 |
+
$css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
|
143 |
+
|
144 |
+
// Use newline after 1st numeric value (to limit line lengths).
|
145 |
+
$css = preg_replace('/
|
146 |
+
((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
|
147 |
+
\\s+
|
148 |
+
/x'
|
149 |
+
,"$1\n", $css);
|
150 |
+
|
151 |
+
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
152 |
+
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
153 |
+
|
154 |
+
return trim($css);
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Replace what looks like a set of selectors
|
159 |
+
*
|
160 |
+
* @param array $m regex matches
|
161 |
+
*
|
162 |
+
* @return string
|
163 |
+
*/
|
164 |
+
protected function _selectorsCB($m)
|
165 |
+
{
|
166 |
+
// remove ws around the combinators
|
167 |
+
return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Process a comment and return a replacement
|
172 |
+
*
|
173 |
+
* @param array $m regex matches
|
174 |
+
*
|
175 |
+
* @return string
|
176 |
+
*/
|
177 |
+
protected function _commentCB($m)
|
178 |
+
{
|
179 |
+
$hasSurroundingWs = (trim($m[0]) !== $m[1]);
|
180 |
+
$m = $m[1];
|
181 |
+
// $m is the comment content w/o the surrounding tokens,
|
182 |
+
// but the return value will replace the entire comment.
|
183 |
+
if ($m === 'keep') {
|
184 |
+
return '/**/';
|
185 |
+
}
|
186 |
+
if ($m === '" "') {
|
187 |
+
// component of http://tantek.com/CSS/Examples/midpass.html
|
188 |
+
return '/*" "*/';
|
189 |
+
}
|
190 |
+
if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
|
191 |
+
// component of http://tantek.com/CSS/Examples/midpass.html
|
192 |
+
return '/*";}}/* */';
|
193 |
+
}
|
194 |
+
if ($this->_inHack) {
|
195 |
+
// inversion: feeding only to one browser
|
196 |
+
if (preg_match('@
|
197 |
+
^/ # comment started like /*/
|
198 |
+
\\s*
|
199 |
+
(\\S[\\s\\S]+?) # has at least some non-ws content
|
200 |
+
\\s*
|
201 |
+
/\\* # ends like /*/ or /**/
|
202 |
+
@x', $m, $n)) {
|
203 |
+
// end hack mode after this comment, but preserve the hack and comment content
|
204 |
+
$this->_inHack = false;
|
205 |
+
return "/*/{$n[1]}/**/";
|
206 |
+
}
|
207 |
+
}
|
208 |
+
if (substr($m, -1) === '\\') { // comment ends like \*/
|
209 |
+
// begin hack mode and preserve hack
|
210 |
+
$this->_inHack = true;
|
211 |
+
return '/*\\*/';
|
212 |
+
}
|
213 |
+
if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
|
214 |
+
// begin hack mode and preserve hack
|
215 |
+
$this->_inHack = true;
|
216 |
+
return '/*/*/';
|
217 |
+
}
|
218 |
+
if ($this->_inHack) {
|
219 |
+
// a regular comment ends hack mode but should be preserved
|
220 |
+
$this->_inHack = false;
|
221 |
+
return '/**/';
|
222 |
+
}
|
223 |
+
// Issue 107: if there's any surrounding whitespace, it may be important, so
|
224 |
+
// replace the comment with a single space
|
225 |
+
return $hasSurroundingWs // remove all other comments
|
226 |
+
? ' '
|
227 |
+
: '';
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Process a font-family listing and return a replacement
|
232 |
+
*
|
233 |
+
* @param array $m regex matches
|
234 |
+
*
|
235 |
+
* @return string
|
236 |
+
*/
|
237 |
+
protected function _fontFamilyCB($m)
|
238 |
+
{
|
239 |
+
$m[1] = preg_replace('/
|
240 |
+
\\s*
|
241 |
+
(
|
242 |
+
"[^"]+" # 1 = family in double qutoes
|
243 |
+
|\'[^\']+\' # or 1 = family in single quotes
|
244 |
+
|[\\w\\-]+ # or 1 = unquoted family
|
245 |
+
)
|
246 |
+
\\s*
|
247 |
+
/x', '$1', $m[1]);
|
248 |
+
return 'font-family:' . $m[1] . $m[2];
|
249 |
+
}
|
250 |
+
}
|
inc/minification/minify/minify-html.php
ADDED
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Minify_HTML
|
4 |
+
* @package Minify
|
5 |
+
*/
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Compress HTML
|
9 |
+
*
|
10 |
+
* This is a heavy regex-based removal of whitespace, unnecessary comments and
|
11 |
+
* tokens. IE conditional comments are preserved. There are also options to have
|
12 |
+
* STYLE and SCRIPT blocks compressed by callback functions.
|
13 |
+
*
|
14 |
+
* A test suite is available.
|
15 |
+
*
|
16 |
+
* @package Minify
|
17 |
+
* @author Stephen Clay <steve@mrclay.org>
|
18 |
+
*/
|
19 |
+
class Minify_HTML {
|
20 |
+
|
21 |
+
/**
|
22 |
+
* "Minify" an HTML page
|
23 |
+
*
|
24 |
+
* @param string $html
|
25 |
+
*
|
26 |
+
* @param array $options
|
27 |
+
*
|
28 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
29 |
+
* elements.
|
30 |
+
*
|
31 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
32 |
+
* elements. Note: the type attribute is ignored.
|
33 |
+
*
|
34 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
35 |
+
* unset, minify will sniff for an XHTML doctype.
|
36 |
+
*
|
37 |
+
* 'keepComments' : (optional boolean) should the HTML comments be kept
|
38 |
+
* in the HTML Code?
|
39 |
+
*
|
40 |
+
* @return string
|
41 |
+
*/
|
42 |
+
public static function minify($html, $options = array()) {
|
43 |
+
$min = new Minify_HTML($html, $options);
|
44 |
+
return $min->process();
|
45 |
+
}
|
46 |
+
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Create a minifier object
|
50 |
+
*
|
51 |
+
* @param string $html
|
52 |
+
*
|
53 |
+
* @param array $options
|
54 |
+
*
|
55 |
+
* 'cssMinifier' : (optional) callback function to process content of STYLE
|
56 |
+
* elements.
|
57 |
+
*
|
58 |
+
* 'jsMinifier' : (optional) callback function to process content of SCRIPT
|
59 |
+
* elements. Note: the type attribute is ignored.
|
60 |
+
*
|
61 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
62 |
+
* unset, minify will sniff for an XHTML doctype.
|
63 |
+
*
|
64 |
+
* 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If
|
65 |
+
* unset, minify will sniff for an XHTML doctype.
|
66 |
+
*
|
67 |
+
* @return null
|
68 |
+
*/
|
69 |
+
public function __construct($html, $options = array())
|
70 |
+
{
|
71 |
+
$this->_html = str_replace("\r\n", "\n", trim($html));
|
72 |
+
if (isset($options['xhtml'])) {
|
73 |
+
$this->_isXhtml = (bool)$options['xhtml'];
|
74 |
+
}
|
75 |
+
if (isset($options['cssMinifier'])) {
|
76 |
+
$this->_cssMinifier = $options['cssMinifier'];
|
77 |
+
}
|
78 |
+
if (isset($options['jsMinifier'])) {
|
79 |
+
$this->_jsMinifier = $options['jsMinifier'];
|
80 |
+
}
|
81 |
+
if (isset($options['keepComments'])) {
|
82 |
+
$this->_keepComments = $options['keepComments'];
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Minify the markeup given in the constructor
|
89 |
+
*
|
90 |
+
* @return string
|
91 |
+
*/
|
92 |
+
public function process()
|
93 |
+
{
|
94 |
+
if ($this->_isXhtml === null) {
|
95 |
+
$this->_isXhtml = (false !== strpos($this->_html, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML'));
|
96 |
+
}
|
97 |
+
|
98 |
+
$this->_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']);
|
99 |
+
$this->_placeholders = array();
|
100 |
+
|
101 |
+
// replace SCRIPTs (and minify) with placeholders
|
102 |
+
$this->_html = preg_replace_callback(
|
103 |
+
'/(\\s*)(<script\\b[^>]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i'
|
104 |
+
,array($this, '_removeScriptCB')
|
105 |
+
,$this->_html);
|
106 |
+
|
107 |
+
// replace STYLEs (and minify) with placeholders
|
108 |
+
$this->_html = preg_replace_callback(
|
109 |
+
'/\\s*(<style\\b[^>]*?>)([\\s\\S]*?)<\\/style>\\s*/i'
|
110 |
+
,array($this, '_removeStyleCB')
|
111 |
+
,$this->_html);
|
112 |
+
|
113 |
+
// remove HTML comments (not containing IE conditional comments).
|
114 |
+
if ($this->_keepComments == false) {
|
115 |
+
$this->_html = preg_replace_callback(
|
116 |
+
'/<!--([\\s\\S]*?)-->/'
|
117 |
+
,array($this, '_commentCB')
|
118 |
+
,$this->_html);
|
119 |
+
}
|
120 |
+
|
121 |
+
// replace PREs with placeholders
|
122 |
+
$this->_html = preg_replace_callback('/\\s*(<pre\\b[^>]*?>[\\s\\S]*?<\\/pre>)\\s*/i'
|
123 |
+
,array($this, '_removePreCB')
|
124 |
+
,$this->_html);
|
125 |
+
|
126 |
+
// replace TEXTAREAs with placeholders
|
127 |
+
$this->_html = preg_replace_callback(
|
128 |
+
'/\\s*(<textarea\\b[^>]*?>[\\s\\S]*?<\\/textarea>)\\s*/i'
|
129 |
+
,array($this, '_removeTextareaCB')
|
130 |
+
,$this->_html);
|
131 |
+
|
132 |
+
// replace data: URIs with placeholders
|
133 |
+
$this->_html = preg_replace_callback(
|
134 |
+
'/(=("|\')data:.*\\2)/Ui'
|
135 |
+
,array($this, '_removeDataURICB')
|
136 |
+
,$this->_html);
|
137 |
+
|
138 |
+
// trim each line.
|
139 |
+
// @todo take into account attribute values that span multiple lines.
|
140 |
+
$this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html);
|
141 |
+
|
142 |
+
// remove ws around block/undisplayed elements
|
143 |
+
$this->_html = preg_replace('/\\s+(<\\/?(?:area|article|aside|base(?:font)?|blockquote|body'
|
144 |
+
.'|canvas|caption|center|col(?:group)?|dd|dir|div|dl|dt|fieldset|figcaption|figure|footer|form'
|
145 |
+
.'|frame(?:set)?|h[1-6]|head|header|hgroup|hr|html|legend|li|link|main|map|menu|meta|nav'
|
146 |
+
.'|ol|opt(?:group|ion)|output|p|param|section|t(?:able|body|head|d|h||r|foot|itle)'
|
147 |
+
.'|ul|video)\\b[^>]*>)/i', '$1', $this->_html);
|
148 |
+
|
149 |
+
// remove ws outside of all elements
|
150 |
+
$this->_html = preg_replace_callback(
|
151 |
+
'/>([^<]+)</'
|
152 |
+
,array($this, '_outsideTagCB')
|
153 |
+
,$this->_html);
|
154 |
+
|
155 |
+
// use newlines before 1st attribute in open tags (to limit line lengths)
|
156 |
+
//$this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html);
|
157 |
+
|
158 |
+
// fill placeholders
|
159 |
+
$this->_html = str_replace(
|
160 |
+
array_keys($this->_placeholders)
|
161 |
+
,array_values($this->_placeholders)
|
162 |
+
,$this->_html
|
163 |
+
);
|
164 |
+
return $this->_html;
|
165 |
+
}
|
166 |
+
|
167 |
+
protected function _commentCB($m)
|
168 |
+
{
|
169 |
+
return (0 === strpos($m[1], '[') || false !== strpos($m[1], '<!['))
|
170 |
+
? $m[0]
|
171 |
+
: '';
|
172 |
+
}
|
173 |
+
|
174 |
+
protected function _reservePlace($content)
|
175 |
+
{
|
176 |
+
$placeholder = '%' . $this->_replacementHash . count($this->_placeholders) . '%';
|
177 |
+
$this->_placeholders[$placeholder] = $content;
|
178 |
+
return $placeholder;
|
179 |
+
}
|
180 |
+
|
181 |
+
protected $_isXhtml = null;
|
182 |
+
protected $_replacementHash = null;
|
183 |
+
protected $_placeholders = array();
|
184 |
+
protected $_cssMinifier = null;
|
185 |
+
protected $_jsMinifier = null;
|
186 |
+
protected $_keepComments = false;
|
187 |
+
|
188 |
+
protected function _outsideTagCB($m)
|
189 |
+
{
|
190 |
+
return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<';
|
191 |
+
}
|
192 |
+
|
193 |
+
protected function _removePreCB($m)
|
194 |
+
{
|
195 |
+
return $this->_reservePlace($m[1]);
|
196 |
+
}
|
197 |
+
|
198 |
+
protected function _removeTextareaCB($m)
|
199 |
+
{
|
200 |
+
return $this->_reservePlace($m[1]);
|
201 |
+
}
|
202 |
+
|
203 |
+
protected function _removeDataURICB($m)
|
204 |
+
{
|
205 |
+
return $this->_reservePlace($m[1]);
|
206 |
+
}
|
207 |
+
|
208 |
+
protected function _removeStyleCB($m)
|
209 |
+
{
|
210 |
+
$openStyle = $m[1];
|
211 |
+
$css = $m[2];
|
212 |
+
// remove HTML comments
|
213 |
+
$css = preg_replace('/(?:^\\s*<!--|-->\\s*$)/', '', $css);
|
214 |
+
|
215 |
+
// remove CDATA section markers
|
216 |
+
$css = $this->_removeCdata($css);
|
217 |
+
|
218 |
+
// minify
|
219 |
+
$minifier = $this->_cssMinifier
|
220 |
+
? $this->_cssMinifier
|
221 |
+
: 'trim';
|
222 |
+
$css = call_user_func($minifier, $css);
|
223 |
+
|
224 |
+
return $this->_reservePlace($this->_needsCdata($css)
|
225 |
+
? "{$openStyle}/*<![CDATA[*/{$css}/*]]>*/</style>"
|
226 |
+
: "{$openStyle}{$css}</style>"
|
227 |
+
);
|
228 |
+
}
|
229 |
+
|
230 |
+
protected function _removeScriptCB($m)
|
231 |
+
{
|
232 |
+
$openScript = $m[2];
|
233 |
+
$js = $m[3];
|
234 |
+
|
235 |
+
// whitespace surrounding? preserve at least one space
|
236 |
+
$ws1 = ($m[1] === '') ? '' : ' ';
|
237 |
+
$ws2 = ($m[4] === '') ? '' : ' ';
|
238 |
+
|
239 |
+
// remove HTML comments (and ending "//" if present)
|
240 |
+
$js = preg_replace('/(?:^\\s*<!--\\s*|\\s*(?:\\/\\/)?\\s*-->\\s*$)/', '', $js);
|
241 |
+
|
242 |
+
// remove CDATA section markers
|
243 |
+
$js = $this->_removeCdata($js);
|
244 |
+
|
245 |
+
// minify
|
246 |
+
$minifier = $this->_jsMinifier
|
247 |
+
? $this->_jsMinifier
|
248 |
+
: 'trim';
|
249 |
+
$js = call_user_func($minifier, $js);
|
250 |
+
|
251 |
+
return $this->_reservePlace($this->_needsCdata($js)
|
252 |
+
? "{$ws1}{$openScript}/*<![CDATA[*/{$js}/*]]>*/</script>{$ws2}"
|
253 |
+
: "{$ws1}{$openScript}{$js}</script>{$ws2}"
|
254 |
+
);
|
255 |
+
}
|
256 |
+
|
257 |
+
protected function _removeCdata($str)
|
258 |
+
{
|
259 |
+
return (false !== strpos($str, '<![CDATA['))
|
260 |
+
? str_replace(array('/*<![CDATA[*/','/*]]>*/','<![CDATA[', ']]>'), '', $str)
|
261 |
+
: $str;
|
262 |
+
}
|
263 |
+
|
264 |
+
protected function _needsCdata($str)
|
265 |
+
{
|
266 |
+
return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str));
|
267 |
+
}
|
268 |
+
}
|
inc/minification/minify/yui-php-cssmin-2.4.8-4.php
ADDED
@@ -0,0 +1,777 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*!
|
4 |
+
* cssmin.php v2.4.8-4
|
5 |
+
* Author: Tubal Martin - http://tubalmartin.me/
|
6 |
+
* Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
|
7 |
+
*
|
8 |
+
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
|
9 |
+
* itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
|
10 |
+
* Permission is hereby granted to use the PHP version under the same
|
11 |
+
* conditions as the YUICompressor.
|
12 |
+
*/
|
13 |
+
|
14 |
+
/*!
|
15 |
+
* YUI Compressor
|
16 |
+
* http://developer.yahoo.com/yui/compressor/
|
17 |
+
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
18 |
+
* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
|
19 |
+
* The copyrights embodied in the content of this file are licensed
|
20 |
+
* by Yahoo! Inc. under the BSD (revised) open source license.
|
21 |
+
*/
|
22 |
+
|
23 |
+
class CSSmin
|
24 |
+
{
|
25 |
+
const NL = '___YUICSSMIN_PRESERVED_NL___';
|
26 |
+
const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
|
27 |
+
const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
|
28 |
+
const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
|
29 |
+
const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
|
30 |
+
|
31 |
+
private $comments;
|
32 |
+
private $preserved_tokens;
|
33 |
+
private $memory_limit;
|
34 |
+
private $max_execution_time;
|
35 |
+
private $pcre_backtrack_limit;
|
36 |
+
private $pcre_recursion_limit;
|
37 |
+
private $raise_php_limits;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* @param bool|int $raise_php_limits
|
41 |
+
* If true, PHP settings will be raised if needed
|
42 |
+
*/
|
43 |
+
public function __construct($raise_php_limits = TRUE)
|
44 |
+
{
|
45 |
+
// Set suggested PHP limits
|
46 |
+
$this->memory_limit = 128 * 1048576; // 128MB in bytes
|
47 |
+
$this->max_execution_time = 60; // 1 min
|
48 |
+
$this->pcre_backtrack_limit = 1000 * 1000;
|
49 |
+
$this->pcre_recursion_limit = 500 * 1000;
|
50 |
+
|
51 |
+
$this->raise_php_limits = (bool) $raise_php_limits;
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Minify a string of CSS
|
56 |
+
* @param string $css
|
57 |
+
* @param int|bool $linebreak_pos
|
58 |
+
* @return string
|
59 |
+
*/
|
60 |
+
public function run($css = '', $linebreak_pos = FALSE)
|
61 |
+
{
|
62 |
+
if (empty($css)) {
|
63 |
+
return '';
|
64 |
+
}
|
65 |
+
|
66 |
+
if ($this->raise_php_limits) {
|
67 |
+
$this->do_raise_php_limits();
|
68 |
+
}
|
69 |
+
|
70 |
+
$this->comments = array();
|
71 |
+
$this->preserved_tokens = array();
|
72 |
+
|
73 |
+
$start_index = 0;
|
74 |
+
$length = strlen($css);
|
75 |
+
|
76 |
+
$css = $this->extract_data_urls($css);
|
77 |
+
|
78 |
+
// collect all comment blocks...
|
79 |
+
while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) {
|
80 |
+
$end_index = $this->index_of($css, '*/', $start_index + 2);
|
81 |
+
if ($end_index < 0) {
|
82 |
+
$end_index = $length;
|
83 |
+
}
|
84 |
+
$comment_found = $this->str_slice($css, $start_index + 2, $end_index);
|
85 |
+
$this->comments[] = $comment_found;
|
86 |
+
$comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___';
|
87 |
+
$css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index);
|
88 |
+
// Set correct start_index: Fixes issue #2528130
|
89 |
+
$start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found);
|
90 |
+
}
|
91 |
+
|
92 |
+
// preserve strings so their content doesn't get accidentally minified
|
93 |
+
$css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);
|
94 |
+
|
95 |
+
// Let's divide css code in chunks of 5.000 chars aprox.
|
96 |
+
// Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
|
97 |
+
// of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
|
98 |
+
// long strings and a (sub)pattern matches a number of chars greater than
|
99 |
+
// the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
|
100 |
+
// returning NULL and $css would be empty.
|
101 |
+
$charset = '';
|
102 |
+
$charset_regexp = '/(@charset)( [^;]+;)/i';
|
103 |
+
$css_chunks = array();
|
104 |
+
$css_chunk_length = 5000; // aprox size, not exact
|
105 |
+
$start_index = 0;
|
106 |
+
$i = $css_chunk_length; // save initial iterations
|
107 |
+
$l = strlen($css);
|
108 |
+
|
109 |
+
|
110 |
+
// if the number of characters is 5000 or less, do not chunk
|
111 |
+
if ($l <= $css_chunk_length) {
|
112 |
+
$css_chunks[] = $css;
|
113 |
+
} else {
|
114 |
+
// chunk css code securely
|
115 |
+
while ($i < $l) {
|
116 |
+
$i += 50; // save iterations
|
117 |
+
if ($l - $start_index <= $css_chunk_length || $i >= $l) {
|
118 |
+
$css_chunks[] = $this->str_slice($css, $start_index);
|
119 |
+
break;
|
120 |
+
}
|
121 |
+
if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) {
|
122 |
+
// If there are two ending curly braces }} separated or not by spaces,
|
123 |
+
// join them in the same chunk (i.e. @media blocks)
|
124 |
+
$next_chunk = substr($css, $i);
|
125 |
+
if (preg_match('/^\s*\}/', $next_chunk)) {
|
126 |
+
$i = $i + $this->index_of($next_chunk, '}') + 1;
|
127 |
+
}
|
128 |
+
|
129 |
+
$css_chunks[] = $this->str_slice($css, $start_index, $i);
|
130 |
+
$start_index = $i;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
// Minify each chunk
|
136 |
+
for ($i = 0, $n = count($css_chunks); $i < $n; $i++) {
|
137 |
+
$css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos);
|
138 |
+
// Keep the first @charset at-rule found
|
139 |
+
if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) {
|
140 |
+
$charset = strtolower($matches[1]) . $matches[2];
|
141 |
+
}
|
142 |
+
// Delete all @charset at-rules
|
143 |
+
$css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]);
|
144 |
+
}
|
145 |
+
|
146 |
+
// Update the first chunk and push the charset to the top of the file.
|
147 |
+
$css_chunks[0] = $charset . $css_chunks[0];
|
148 |
+
|
149 |
+
return implode('', $css_chunks);
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Sets the memory limit for this script
|
154 |
+
* @param int|string $limit
|
155 |
+
*/
|
156 |
+
public function set_memory_limit($limit)
|
157 |
+
{
|
158 |
+
$this->memory_limit = $this->normalize_int($limit);
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Sets the maximum execution time for this script
|
163 |
+
* @param int|string $seconds
|
164 |
+
*/
|
165 |
+
public function set_max_execution_time($seconds)
|
166 |
+
{
|
167 |
+
$this->max_execution_time = (int) $seconds;
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Sets the PCRE backtrack limit for this script
|
172 |
+
* @param int $limit
|
173 |
+
*/
|
174 |
+
public function set_pcre_backtrack_limit($limit)
|
175 |
+
{
|
176 |
+
$this->pcre_backtrack_limit = (int) $limit;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Sets the PCRE recursion limit for this script
|
181 |
+
* @param int $limit
|
182 |
+
*/
|
183 |
+
public function set_pcre_recursion_limit($limit)
|
184 |
+
{
|
185 |
+
$this->pcre_recursion_limit = (int) $limit;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Try to configure PHP to use at least the suggested minimum settings
|
190 |
+
*/
|
191 |
+
private function do_raise_php_limits()
|
192 |
+
{
|
193 |
+
$php_limits = array(
|
194 |
+
'memory_limit' => $this->memory_limit,
|
195 |
+
'max_execution_time' => $this->max_execution_time,
|
196 |
+
'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
|
197 |
+
'pcre.recursion_limit' => $this->pcre_recursion_limit
|
198 |
+
);
|
199 |
+
|
200 |
+
// If current settings are higher respect them.
|
201 |
+
foreach ($php_limits as $name => $suggested) {
|
202 |
+
$current = $this->normalize_int(ini_get($name));
|
203 |
+
// memory_limit exception: allow -1 for "no memory limit".
|
204 |
+
if ($current > -1 && ($suggested == -1 || $current < $suggested)) {
|
205 |
+
ini_set($name, $suggested);
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Does bulk of the minification
|
212 |
+
* @param string $css
|
213 |
+
* @param int|bool $linebreak_pos
|
214 |
+
* @return string
|
215 |
+
*/
|
216 |
+
private function minify($css, $linebreak_pos)
|
217 |
+
{
|
218 |
+
// strings are safe, now wrestle the comments
|
219 |
+
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
220 |
+
|
221 |
+
$token = $this->comments[$i];
|
222 |
+
$placeholder = '/' . self::COMMENT . $i . '___/';
|
223 |
+
|
224 |
+
// ! in the first position of the comment means preserve
|
225 |
+
// so push to the preserved tokens keeping the !
|
226 |
+
if (substr($token, 0, 1) === '!') {
|
227 |
+
$this->preserved_tokens[] = $token;
|
228 |
+
$token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
|
229 |
+
$css = preg_replace($placeholder, $token_tring, $css, 1);
|
230 |
+
// Preserve new lines for /*! important comments
|
231 |
+
$css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css);
|
232 |
+
$css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css);
|
233 |
+
continue;
|
234 |
+
}
|
235 |
+
|
236 |
+
// \ in the last position looks like hack for Mac/IE5
|
237 |
+
// shorten that to /*\*/ and the next one to /**/
|
238 |
+
if (substr($token, (strlen($token) - 1), 1) === '\\') {
|
239 |
+
$this->preserved_tokens[] = '\\';
|
240 |
+
$css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
241 |
+
$i = $i + 1; // attn: advancing the loop
|
242 |
+
$this->preserved_tokens[] = '';
|
243 |
+
$css = preg_replace('/' . self::COMMENT . $i . '___/', self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
244 |
+
continue;
|
245 |
+
}
|
246 |
+
|
247 |
+
// keep empty comments after child selectors (IE7 hack)
|
248 |
+
// e.g. html >/**/ body
|
249 |
+
if (strlen($token) === 0) {
|
250 |
+
$start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1));
|
251 |
+
if ($start_index > 2) {
|
252 |
+
if (substr($css, $start_index - 3, 1) === '>') {
|
253 |
+
$this->preserved_tokens[] = '';
|
254 |
+
$css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
255 |
+
}
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
// in all other cases kill the comment
|
260 |
+
$css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1);
|
261 |
+
}
|
262 |
+
|
263 |
+
|
264 |
+
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
265 |
+
$css = preg_replace('/\s+/', ' ', $css);
|
266 |
+
|
267 |
+
// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
|
268 |
+
$css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);
|
269 |
+
|
270 |
+
// Shorten & preserve calculations calc(...) since spaces are important
|
271 |
+
$css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);
|
272 |
+
|
273 |
+
// Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
|
274 |
+
// +1.2em to 1.2em, +.8px to .8px, +2% to 2%
|
275 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css);
|
276 |
+
|
277 |
+
// Remove leading zeros from integer and float numbers preceded by : or a white-space
|
278 |
+
// 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
|
279 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css);
|
280 |
+
|
281 |
+
// Remove trailing zeros from float numbers preceded by : or a white-space
|
282 |
+
// -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
|
283 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
|
284 |
+
|
285 |
+
// Remove trailing .0 -> -9.0 to -9
|
286 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css);
|
287 |
+
|
288 |
+
// Replace 0 length numbers with 0
|
289 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css);
|
290 |
+
|
291 |
+
// Remove the spaces before the things that should not have spaces before them.
|
292 |
+
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
293 |
+
// Swap out any pseudo-class colons with the token, and then swap back.
|
294 |
+
$css = preg_replace_callback('/(?:^|\})[^\{]*\s+\:/', array($this, 'replace_colon'), $css);
|
295 |
+
|
296 |
+
// Remove spaces before the things that should not have spaces before them.
|
297 |
+
$css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);
|
298 |
+
|
299 |
+
// Restore spaces for !important
|
300 |
+
$css = preg_replace('/\!important/i', ' !important', $css);
|
301 |
+
|
302 |
+
// bring back the colon
|
303 |
+
$css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css);
|
304 |
+
|
305 |
+
// retain space for special IE6 cases
|
306 |
+
$css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css);
|
307 |
+
|
308 |
+
// no space after the end of a preserved comment
|
309 |
+
$css = preg_replace('/\*\/ /', '*/', $css);
|
310 |
+
|
311 |
+
// lowercase some popular @directives
|
312 |
+
$css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css);
|
313 |
+
|
314 |
+
// lowercase some more common pseudo-elements
|
315 |
+
$css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css);
|
316 |
+
|
317 |
+
// lowercase some more common functions
|
318 |
+
$css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css);
|
319 |
+
|
320 |
+
// lower case some common function that can be values
|
321 |
+
// NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
|
322 |
+
$css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);
|
323 |
+
|
324 |
+
// Put the space back in some cases, to support stuff like
|
325 |
+
// @media screen and (-webkit-min-device-pixel-ratio:0){
|
326 |
+
$css = preg_replace('/\band\(/i', 'and (', $css);
|
327 |
+
|
328 |
+
// Remove the spaces after the things that should not have spaces after them.
|
329 |
+
$css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
|
330 |
+
|
331 |
+
// remove unnecessary semicolons
|
332 |
+
$css = preg_replace('/;+\}/', '}', $css);
|
333 |
+
|
334 |
+
// Fix for issue: #2528146
|
335 |
+
// Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
|
336 |
+
// to avoid issues on Symbian S60 3.x browsers.
|
337 |
+
$css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
|
338 |
+
|
339 |
+
// Replace 0 <length> and 0 <percentage> values with 0.
|
340 |
+
// <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
|
341 |
+
// <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
|
342 |
+
$css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
|
343 |
+
|
344 |
+
// 0% step in a keyframe? restore the % unit
|
345 |
+
$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
|
346 |
+
|
347 |
+
// Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
|
348 |
+
$css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
|
349 |
+
|
350 |
+
// Fix for issue: #2528142
|
351 |
+
// Replace text-shadow:0; with text-shadow:0 0 0;
|
352 |
+
$css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
|
353 |
+
|
354 |
+
// Replace background-position:0; with background-position:0 0;
|
355 |
+
// same for transform-origin
|
356 |
+
// Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
|
357 |
+
$css = preg_replace('/(background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
|
358 |
+
|
359 |
+
// Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
|
360 |
+
// Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
|
361 |
+
// This makes it more likely that it'll get further compressed in the next step.
|
362 |
+
$css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
|
363 |
+
$css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
|
364 |
+
|
365 |
+
// Shorten colors from #AABBCC to #ABC or short color name.
|
366 |
+
$css = $this->compress_hex_colors($css);
|
367 |
+
|
368 |
+
// border: none to border:0, outline: none to outline:0
|
369 |
+
$css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
|
370 |
+
|
371 |
+
// shorter opacity IE filter
|
372 |
+
$css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
|
373 |
+
|
374 |
+
// Find a fraction that is used for Opera's -o-device-pixel-ratio query
|
375 |
+
// Add token to add the "\" back in later
|
376 |
+
$css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
|
377 |
+
|
378 |
+
// Remove empty rules.
|
379 |
+
$css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
|
380 |
+
|
381 |
+
// Add "/" back to fix Opera -o-device-pixel-ratio query
|
382 |
+
$css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
|
383 |
+
|
384 |
+
// Replace multiple semi-colons in a row by a single one
|
385 |
+
// See SF bug #1980989
|
386 |
+
$css = preg_replace('/;;+/', ';', $css);
|
387 |
+
|
388 |
+
// Restore new lines for /*! important comments
|
389 |
+
$css = preg_replace('/'. self::NL .'/', "\n", $css);
|
390 |
+
|
391 |
+
// Lowercase all uppercase properties
|
392 |
+
$css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
|
393 |
+
|
394 |
+
// Some source control tools don't like it when files containing lines longer
|
395 |
+
// than, say 8000 characters, are checked in. The linebreak option is used in
|
396 |
+
// that case to split long lines after a specific column.
|
397 |
+
if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
|
398 |
+
$linebreak_pos = (int) $linebreak_pos;
|
399 |
+
$start_index = $i = 0;
|
400 |
+
while ($i < strlen($css)) {
|
401 |
+
$i++;
|
402 |
+
if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
|
403 |
+
$css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
|
404 |
+
$start_index = $i;
|
405 |
+
}
|
406 |
+
}
|
407 |
+
}
|
408 |
+
|
409 |
+
// restore preserved comments and strings in reverse order
|
410 |
+
for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
|
411 |
+
$css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
|
412 |
+
}
|
413 |
+
|
414 |
+
// Trim the final string (for any leading or trailing white spaces)
|
415 |
+
return trim($css);
|
416 |
+
}
|
417 |
+
|
418 |
+
/**
|
419 |
+
* Utility method to replace all data urls with tokens before we start
|
420 |
+
* compressing, to avoid performance issues running some of the subsequent
|
421 |
+
* regexes against large strings chunks.
|
422 |
+
*
|
423 |
+
* @param string $css
|
424 |
+
* @return string
|
425 |
+
*/
|
426 |
+
private function extract_data_urls($css)
|
427 |
+
{
|
428 |
+
// Leave data urls alone to increase parse performance.
|
429 |
+
$max_index = strlen($css) - 1;
|
430 |
+
$append_index = $index = $last_index = $offset = 0;
|
431 |
+
$sb = array();
|
432 |
+
$pattern = '/url\(\s*(["\']?)data\:/i';
|
433 |
+
|
434 |
+
// Since we need to account for non-base64 data urls, we need to handle
|
435 |
+
// ' and ) being part of the data string. Hence switching to indexOf,
|
436 |
+
// to determine whether or not we have matching string terminators and
|
437 |
+
// handling sb appends directly, instead of using matcher.append* methods.
|
438 |
+
|
439 |
+
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
440 |
+
$index = $this->index_of($css, $m[0], $offset);
|
441 |
+
$last_index = $index + strlen($m[0]);
|
442 |
+
$start_index = $index + 4; // "url(".length()
|
443 |
+
$end_index = $last_index - 1;
|
444 |
+
$terminator = $m[1]; // ', " or empty (not quoted)
|
445 |
+
$found_terminator = FALSE;
|
446 |
+
|
447 |
+
if (strlen($terminator) === 0) {
|
448 |
+
$terminator = ')';
|
449 |
+
}
|
450 |
+
|
451 |
+
while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
|
452 |
+
$end_index = $this->index_of($css, $terminator, $end_index + 1);
|
453 |
+
|
454 |
+
// endIndex == 0 doesn't really apply here
|
455 |
+
if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
|
456 |
+
$found_terminator = TRUE;
|
457 |
+
if (')' != $terminator) {
|
458 |
+
$end_index = $this->index_of($css, ')', $end_index);
|
459 |
+
}
|
460 |
+
}
|
461 |
+
}
|
462 |
+
|
463 |
+
// Enough searching, start moving stuff over to the buffer
|
464 |
+
$sb[] = $this->str_slice($css, $append_index, $index);
|
465 |
+
|
466 |
+
if ($found_terminator) {
|
467 |
+
$token = $this->str_slice($css, $start_index, $end_index);
|
468 |
+
$token = preg_replace('/\s+/', '', $token);
|
469 |
+
$this->preserved_tokens[] = $token;
|
470 |
+
|
471 |
+
$preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
|
472 |
+
$sb[] = $preserver;
|
473 |
+
|
474 |
+
$append_index = $end_index + 1;
|
475 |
+
} else {
|
476 |
+
// No end terminator found, re-add the whole match. Should we throw/warn here?
|
477 |
+
$sb[] = $this->str_slice($css, $index, $last_index);
|
478 |
+
$append_index = $last_index;
|
479 |
+
}
|
480 |
+
|
481 |
+
$offset = $last_index;
|
482 |
+
}
|
483 |
+
|
484 |
+
$sb[] = $this->str_slice($css, $append_index);
|
485 |
+
|
486 |
+
return implode('', $sb);
|
487 |
+
}
|
488 |
+
|
489 |
+
/**
|
490 |
+
* Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
|
491 |
+
*
|
492 |
+
* DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
|
493 |
+
* e.g. #AddressForm { ... }
|
494 |
+
*
|
495 |
+
* DOES NOT compress IE filters, which have hex color values (which would break things).
|
496 |
+
* e.g. filter: chroma(color="#FFFFFF");
|
497 |
+
*
|
498 |
+
* DOES NOT compress invalid hex values.
|
499 |
+
* e.g. background-color: #aabbccdd
|
500 |
+
*
|
501 |
+
* @param string $css
|
502 |
+
* @return string
|
503 |
+
*/
|
504 |
+
private function compress_hex_colors($css)
|
505 |
+
{
|
506 |
+
// Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
|
507 |
+
$pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
|
508 |
+
$_index = $index = $last_index = $offset = 0;
|
509 |
+
$sb = array();
|
510 |
+
// See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
|
511 |
+
$short_safe = array(
|
512 |
+
'#808080' => 'gray',
|
513 |
+
'#008000' => 'green',
|
514 |
+
'#800000' => 'maroon',
|
515 |
+
'#000080' => 'navy',
|
516 |
+
'#808000' => 'olive',
|
517 |
+
'#ffa500' => 'orange',
|
518 |
+
'#800080' => 'purple',
|
519 |
+
'#c0c0c0' => 'silver',
|
520 |
+
'#008080' => 'teal',
|
521 |
+
'#f00' => 'red'
|
522 |
+
);
|
523 |
+
|
524 |
+
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
525 |
+
$index = $this->index_of($css, $m[0], $offset);
|
526 |
+
$last_index = $index + strlen($m[0]);
|
527 |
+
$is_filter = $m[1] !== null && $m[1] !== '';
|
528 |
+
|
529 |
+
$sb[] = $this->str_slice($css, $_index, $index);
|
530 |
+
|
531 |
+
if ($is_filter) {
|
532 |
+
// Restore, maintain case, otherwise filter will break
|
533 |
+
$sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
|
534 |
+
} else {
|
535 |
+
if (strtolower($m[2]) == strtolower($m[3]) &&
|
536 |
+
strtolower($m[4]) == strtolower($m[5]) &&
|
537 |
+
strtolower($m[6]) == strtolower($m[7])) {
|
538 |
+
// Compress.
|
539 |
+
$hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
|
540 |
+
} else {
|
541 |
+
// Non compressible color, restore but lower case.
|
542 |
+
$hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
|
543 |
+
}
|
544 |
+
// replace Hex colors to short safe color names
|
545 |
+
$sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
|
546 |
+
}
|
547 |
+
|
548 |
+
$_index = $offset = $last_index - strlen($m[8]);
|
549 |
+
}
|
550 |
+
|
551 |
+
$sb[] = $this->str_slice($css, $_index);
|
552 |
+
|
553 |
+
return implode('', $sb);
|
554 |
+
}
|
555 |
+
|
556 |
+
/* CALLBACKS
|
557 |
+
* ---------------------------------------------------------------------------------------------
|
558 |
+
*/
|
559 |
+
|
560 |
+
private function replace_string($matches)
|
561 |
+
{
|
562 |
+
$match = $matches[0];
|
563 |
+
$quote = substr($match, 0, 1);
|
564 |
+
// Must use addcslashes in PHP to avoid parsing of backslashes
|
565 |
+
$match = addcslashes($this->str_slice($match, 1, -1), '\\');
|
566 |
+
|
567 |
+
// maybe the string contains a comment-like substring?
|
568 |
+
// one, maybe more? put'em back then
|
569 |
+
if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
|
570 |
+
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
571 |
+
$match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
|
572 |
+
}
|
573 |
+
}
|
574 |
+
|
575 |
+
// minify alpha opacity in filter strings
|
576 |
+
$match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
|
577 |
+
|
578 |
+
$this->preserved_tokens[] = $match;
|
579 |
+
return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
|
580 |
+
}
|
581 |
+
|
582 |
+
private function replace_colon($matches)
|
583 |
+
{
|
584 |
+
return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
|
585 |
+
}
|
586 |
+
|
587 |
+
private function replace_calc($matches)
|
588 |
+
{
|
589 |
+
$this->preserved_tokens[] = trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2]));
|
590 |
+
return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
591 |
+
}
|
592 |
+
|
593 |
+
private function preserve_old_IE_specific_matrix_definition($matches)
|
594 |
+
{
|
595 |
+
$this->preserved_tokens[] = $matches[1];
|
596 |
+
return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
597 |
+
}
|
598 |
+
|
599 |
+
private function replace_keyframe_zero($matches)
|
600 |
+
{
|
601 |
+
return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
|
602 |
+
}
|
603 |
+
|
604 |
+
private function rgb_to_hex($matches)
|
605 |
+
{
|
606 |
+
// Support for percentage values rgb(100%, 0%, 45%);
|
607 |
+
if ($this->index_of($matches[1], '%') >= 0){
|
608 |
+
$rgbcolors = explode(',', str_replace('%', '', $matches[1]));
|
609 |
+
for ($i = 0; $i < count($rgbcolors); $i++) {
|
610 |
+
$rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
|
611 |
+
}
|
612 |
+
} else {
|
613 |
+
$rgbcolors = explode(',', $matches[1]);
|
614 |
+
}
|
615 |
+
|
616 |
+
// Values outside the sRGB color space should be clipped (0-255)
|
617 |
+
for ($i = 0; $i < count($rgbcolors); $i++) {
|
618 |
+
$rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
|
619 |
+
$rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
|
620 |
+
}
|
621 |
+
|
622 |
+
// Fix for issue #2528093
|
623 |
+
if (!preg_match('/[\s\,\);\}]/', $matches[2])){
|
624 |
+
$matches[2] = ' ' . $matches[2];
|
625 |
+
}
|
626 |
+
|
627 |
+
return '#' . implode('', $rgbcolors) . $matches[2];
|
628 |
+
}
|
629 |
+
|
630 |
+
private function hsl_to_hex($matches)
|
631 |
+
{
|
632 |
+
$values = explode(',', str_replace('%', '', $matches[1]));
|
633 |
+
$h = floatval($values[0]);
|
634 |
+
$s = floatval($values[1]);
|
635 |
+
$l = floatval($values[2]);
|
636 |
+
|
637 |
+
// Wrap and clamp, then fraction!
|
638 |
+
$h = ((($h % 360) + 360) % 360) / 360;
|
639 |
+
$s = $this->clamp_number($s, 0, 100) / 100;
|
640 |
+
$l = $this->clamp_number($l, 0, 100) / 100;
|
641 |
+
|
642 |
+
if ($s == 0) {
|
643 |
+
$r = $g = $b = $this->round_number(255 * $l);
|
644 |
+
} else {
|
645 |
+
$v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
|
646 |
+
$v1 = (2 * $l) - $v2;
|
647 |
+
$r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
|
648 |
+
$g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
|
649 |
+
$b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
|
650 |
+
}
|
651 |
+
|
652 |
+
return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
|
653 |
+
}
|
654 |
+
|
655 |
+
private function lowercase_pseudo_first($matches)
|
656 |
+
{
|
657 |
+
return ':first-'. strtolower($matches[1]) .' '. $matches[2];
|
658 |
+
}
|
659 |
+
|
660 |
+
private function lowercase_directives($matches)
|
661 |
+
{
|
662 |
+
return '@'. strtolower($matches[1]);
|
663 |
+
}
|
664 |
+
|
665 |
+
private function lowercase_pseudo_elements($matches)
|
666 |
+
{
|
667 |
+
return ':'. strtolower($matches[1]);
|
668 |
+
}
|
669 |
+
|
670 |
+
private function lowercase_common_functions($matches)
|
671 |
+
{
|
672 |
+
return ':'. strtolower($matches[1]) .'(';
|
673 |
+
}
|
674 |
+
|
675 |
+
private function lowercase_common_functions_values($matches)
|
676 |
+
{
|
677 |
+
return $matches[1] . strtolower($matches[2]);
|
678 |
+
}
|
679 |
+
|
680 |
+
private function lowercase_properties($matches)
|
681 |
+
{
|
682 |
+
return $matches[1].strtolower($matches[2]).$matches[3];
|
683 |
+
}
|
684 |
+
|
685 |
+
/* HELPERS
|
686 |
+
* ---------------------------------------------------------------------------------------------
|
687 |
+
*/
|
688 |
+
|
689 |
+
private function hue_to_rgb($v1, $v2, $vh)
|
690 |
+
{
|
691 |
+
$vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
|
692 |
+
if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
|
693 |
+
if ($vh * 2 < 1) return $v2;
|
694 |
+
if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
|
695 |
+
return $v1;
|
696 |
+
}
|
697 |
+
|
698 |
+
private function round_number($n)
|
699 |
+
{
|
700 |
+
return intval(floor(floatval($n) + 0.5), 10);
|
701 |
+
}
|
702 |
+
|
703 |
+
private function clamp_number($n, $min, $max)
|
704 |
+
{
|
705 |
+
return min(max($n, $min), $max);
|
706 |
+
}
|
707 |
+
|
708 |
+
/**
|
709 |
+
* PHP port of Javascript's "indexOf" function for strings only
|
710 |
+
* Author: Tubal Martin http://blog.margenn.com
|
711 |
+
*
|
712 |
+
* @param string $haystack
|
713 |
+
* @param string $needle
|
714 |
+
* @param int $offset index (optional)
|
715 |
+
* @return int
|
716 |
+
*/
|
717 |
+
private function index_of($haystack, $needle, $offset = 0)
|
718 |
+
{
|
719 |
+
$index = strpos($haystack, $needle, $offset);
|
720 |
+
|
721 |
+
return ($index !== FALSE) ? $index : -1;
|
722 |
+
}
|
723 |
+
|
724 |
+
/**
|
725 |
+
* PHP port of Javascript's "slice" function for strings only
|
726 |
+
* Author: Tubal Martin http://blog.margenn.com
|
727 |
+
* Tests: http://margenn.com/tubal/str_slice/
|
728 |
+
*
|
729 |
+
* @param string $str
|
730 |
+
* @param int $start index
|
731 |
+
* @param int|bool $end index (optional)
|
732 |
+
* @return string
|
733 |
+
*/
|
734 |
+
private function str_slice($str, $start = 0, $end = FALSE)
|
735 |
+
{
|
736 |
+
if ($end !== FALSE && ($start < 0 || $end <= 0)) {
|
737 |
+
$max = strlen($str);
|
738 |
+
|
739 |
+
if ($start < 0) {
|
740 |
+
if (($start = $max + $start) < 0) {
|
741 |
+
return '';
|
742 |
+
}
|
743 |
+
}
|
744 |
+
|
745 |
+
if ($end < 0) {
|
746 |
+
if (($end = $max + $end) < 0) {
|
747 |
+
return '';
|
748 |
+
}
|
749 |
+
}
|
750 |
+
|
751 |
+
if ($end <= $start) {
|
752 |
+
return '';
|
753 |
+
}
|
754 |
+
}
|
755 |
+
|
756 |
+
$slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
|
757 |
+
return ($slice === FALSE) ? '' : $slice;
|
758 |
+
}
|
759 |
+
|
760 |
+
/**
|
761 |
+
* Convert strings like "64M" or "30" to int values
|
762 |
+
* @param mixed $size
|
763 |
+
* @return int
|
764 |
+
*/
|
765 |
+
private function normalize_int($size)
|
766 |
+
{
|
767 |
+
if (is_string($size)) {
|
768 |
+
switch (substr($size, -1)) {
|
769 |
+
case 'M': case 'm': return $size * 1048576;
|
770 |
+
case 'K': case 'k': return $size * 1024;
|
771 |
+
case 'G': case 'g': return $size * 1073741824;
|
772 |
+
}
|
773 |
+
}
|
774 |
+
|
775 |
+
return (int) $size;
|
776 |
+
}
|
777 |
+
}
|
inc/minification/minify/yui-php-cssmin-2.4.8-4_fgo.php
ADDED
@@ -0,0 +1,789 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*!
|
4 |
+
* cssmin.php v2.4.8-4
|
5 |
+
* Author: Tubal Martin - http://tubalmartin.me/
|
6 |
+
* Repo: https://github.com/tubalmartin/YUI-CSS-compressor-PHP-port
|
7 |
+
*
|
8 |
+
* This is a PHP port of the CSS minification tool distributed with YUICompressor,
|
9 |
+
* itself a port of the cssmin utility by Isaac Schlueter - http://foohack.com/
|
10 |
+
* Permission is hereby granted to use the PHP version under the same
|
11 |
+
* conditions as the YUICompressor.
|
12 |
+
*/
|
13 |
+
|
14 |
+
/*!
|
15 |
+
* YUI Compressor
|
16 |
+
* http://developer.yahoo.com/yui/compressor/
|
17 |
+
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
18 |
+
* Copyright (c) 2013 Yahoo! Inc. All rights reserved.
|
19 |
+
* The copyrights embodied in the content of this file are licensed
|
20 |
+
* by Yahoo! Inc. under the BSD (revised) open source license.
|
21 |
+
*/
|
22 |
+
|
23 |
+
class CSSmin
|
24 |
+
{
|
25 |
+
const NL = '___YUICSSMIN_PRESERVED_NL___';
|
26 |
+
const TOKEN = '___YUICSSMIN_PRESERVED_TOKEN_';
|
27 |
+
const COMMENT = '___YUICSSMIN_PRESERVE_CANDIDATE_COMMENT_';
|
28 |
+
const CLASSCOLON = '___YUICSSMIN_PSEUDOCLASSCOLON___';
|
29 |
+
const QUERY_FRACTION = '___YUICSSMIN_QUERY_FRACTION___';
|
30 |
+
|
31 |
+
private $comments;
|
32 |
+
private $preserved_tokens;
|
33 |
+
private $memory_limit;
|
34 |
+
private $max_execution_time;
|
35 |
+
private $pcre_backtrack_limit;
|
36 |
+
private $pcre_recursion_limit;
|
37 |
+
private $raise_php_limits;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* @param bool|int $raise_php_limits
|
41 |
+
* If true, PHP settings will be raised if needed
|
42 |
+
*/
|
43 |
+
public function __construct($raise_php_limits = TRUE)
|
44 |
+
{
|
45 |
+
// Set suggested PHP limits
|
46 |
+
$this->memory_limit = 128 * 1048576; // 128MB in bytes
|
47 |
+
$this->max_execution_time = 60; // 1 min
|
48 |
+
$this->pcre_backtrack_limit = 1000 * 1000;
|
49 |
+
$this->pcre_recursion_limit = 500 * 1000;
|
50 |
+
|
51 |
+
$this->raise_php_limits = (bool) $raise_php_limits;
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Minify a string of CSS
|
56 |
+
* @param string $css
|
57 |
+
* @param int|bool $linebreak_pos
|
58 |
+
* @return string
|
59 |
+
*/
|
60 |
+
public function run($css = '', $linebreak_pos = FALSE)
|
61 |
+
{
|
62 |
+
if (empty($css)) {
|
63 |
+
return '';
|
64 |
+
}
|
65 |
+
|
66 |
+
if ($this->raise_php_limits) {
|
67 |
+
$this->do_raise_php_limits();
|
68 |
+
}
|
69 |
+
|
70 |
+
$this->comments = array();
|
71 |
+
$this->preserved_tokens = array();
|
72 |
+
|
73 |
+
$start_index = 0;
|
74 |
+
$length = strlen($css);
|
75 |
+
|
76 |
+
$css = $this->extract_data_urls($css);
|
77 |
+
|
78 |
+
// collect all comment blocks...
|
79 |
+
while (($start_index = $this->index_of($css, '/*', $start_index)) >= 0) {
|
80 |
+
$end_index = $this->index_of($css, '*/', $start_index + 2);
|
81 |
+
if ($end_index < 0) {
|
82 |
+
$end_index = $length;
|
83 |
+
}
|
84 |
+
$comment_found = $this->str_slice($css, $start_index + 2, $end_index);
|
85 |
+
$this->comments[] = $comment_found;
|
86 |
+
$comment_preserve_string = self::COMMENT . (count($this->comments) - 1) . '___';
|
87 |
+
$css = $this->str_slice($css, 0, $start_index + 2) . $comment_preserve_string . $this->str_slice($css, $end_index);
|
88 |
+
// Set correct start_index: Fixes issue #2528130
|
89 |
+
$start_index = $end_index + 2 + strlen($comment_preserve_string) - strlen($comment_found);
|
90 |
+
}
|
91 |
+
|
92 |
+
// preserve strings so their content doesn't get accidentally minified
|
93 |
+
$css = preg_replace_callback('/(?:"(?:[^\\\\"]|\\\\.|\\\\)*")|'."(?:'(?:[^\\\\']|\\\\.|\\\\)*')/S", array($this, 'replace_string'), $css);
|
94 |
+
|
95 |
+
// Let's divide css code in chunks of 5.000 chars aprox.
|
96 |
+
// Reason: PHP's PCRE functions like preg_replace have a "backtrack limit"
|
97 |
+
// of 100.000 chars by default (php < 5.3.7) so if we're dealing with really
|
98 |
+
// long strings and a (sub)pattern matches a number of chars greater than
|
99 |
+
// the backtrack limit number (i.e. /(.*)/s) PCRE functions may fail silently
|
100 |
+
// returning NULL and $css would be empty.
|
101 |
+
$charset = '';
|
102 |
+
$charset_regexp = '/(@charset)( [^;]+;)/i';
|
103 |
+
$css_chunks = array();
|
104 |
+
$css_chunk_length = 5000; // aprox size, not exact
|
105 |
+
$start_index = 0;
|
106 |
+
$i = $css_chunk_length; // save initial iterations
|
107 |
+
$l = strlen($css);
|
108 |
+
|
109 |
+
|
110 |
+
// if the number of characters is 5000 or less, do not chunk
|
111 |
+
if ($l <= $css_chunk_length) {
|
112 |
+
$css_chunks[] = $css;
|
113 |
+
} else {
|
114 |
+
// chunk css code securely
|
115 |
+
while ($i < $l) {
|
116 |
+
$i += 50; // save iterations
|
117 |
+
if ($l - $start_index <= $css_chunk_length || $i >= $l) {
|
118 |
+
$css_chunks[] = $this->str_slice($css, $start_index);
|
119 |
+
break;
|
120 |
+
}
|
121 |
+
if ($css[$i - 1] === '}' && $i - $start_index > $css_chunk_length) {
|
122 |
+
// If there are two ending curly braces }} separated or not by spaces,
|
123 |
+
// join them in the same chunk (i.e. @media blocks)
|
124 |
+
$next_chunk = substr($css, $i);
|
125 |
+
if (preg_match('/^\s*\}/', $next_chunk)) {
|
126 |
+
$i = $i + $this->index_of($next_chunk, '}') + 1;
|
127 |
+
}
|
128 |
+
|
129 |
+
$css_chunks[] = $this->str_slice($css, $start_index, $i);
|
130 |
+
$start_index = $i;
|
131 |
+
}
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
// Minify each chunk
|
136 |
+
for ($i = 0, $n = count($css_chunks); $i < $n; $i++) {
|
137 |
+
$css_chunks[$i] = $this->minify($css_chunks[$i], $linebreak_pos);
|
138 |
+
// Keep the first @charset at-rule found
|
139 |
+
if (empty($charset) && preg_match($charset_regexp, $css_chunks[$i], $matches)) {
|
140 |
+
$charset = strtolower($matches[1]) . $matches[2];
|
141 |
+
}
|
142 |
+
// Delete all @charset at-rules
|
143 |
+
$css_chunks[$i] = preg_replace($charset_regexp, '', $css_chunks[$i]);
|
144 |
+
}
|
145 |
+
|
146 |
+
// Update the first chunk and push the charset to the top of the file.
|
147 |
+
$css_chunks[0] = $charset . $css_chunks[0];
|
148 |
+
|
149 |
+
return implode('', $css_chunks);
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Sets the memory limit for this script
|
154 |
+
* @param int|string $limit
|
155 |
+
*/
|
156 |
+
public function set_memory_limit($limit)
|
157 |
+
{
|
158 |
+
$this->memory_limit = $this->normalize_int($limit);
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Sets the maximum execution time for this script
|
163 |
+
* @param int|string $seconds
|
164 |
+
*/
|
165 |
+
public function set_max_execution_time($seconds)
|
166 |
+
{
|
167 |
+
$this->max_execution_time = (int) $seconds;
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Sets the PCRE backtrack limit for this script
|
172 |
+
* @param int $limit
|
173 |
+
*/
|
174 |
+
public function set_pcre_backtrack_limit($limit)
|
175 |
+
{
|
176 |
+
$this->pcre_backtrack_limit = (int) $limit;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Sets the PCRE recursion limit for this script
|
181 |
+
* @param int $limit
|
182 |
+
*/
|
183 |
+
public function set_pcre_recursion_limit($limit)
|
184 |
+
{
|
185 |
+
$this->pcre_recursion_limit = (int) $limit;
|
186 |
+
}
|
187 |
+
|
188 |
+
/**
|
189 |
+
* Try to configure PHP to use at least the suggested minimum settings
|
190 |
+
*/
|
191 |
+
private function do_raise_php_limits()
|
192 |
+
{
|
193 |
+
$php_limits = array(
|
194 |
+
'memory_limit' => $this->memory_limit,
|
195 |
+
'max_execution_time' => $this->max_execution_time,
|
196 |
+
'pcre.backtrack_limit' => $this->pcre_backtrack_limit,
|
197 |
+
'pcre.recursion_limit' => $this->pcre_recursion_limit
|
198 |
+
);
|
199 |
+
|
200 |
+
// If current settings are higher respect them.
|
201 |
+
foreach ($php_limits as $name => $suggested) {
|
202 |
+
$current = $this->normalize_int(ini_get($name));
|
203 |
+
// memory_limit exception: allow -1 for "no memory limit".
|
204 |
+
if ($current > -1 && ($suggested == -1 || $current < $suggested)) {
|
205 |
+
ini_set($name, $suggested);
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Does bulk of the minification
|
212 |
+
* @param string $css
|
213 |
+
* @param int|bool $linebreak_pos
|
214 |
+
* @return string
|
215 |
+
*/
|
216 |
+
private function minify($css, $linebreak_pos)
|
217 |
+
{
|
218 |
+
// strings are safe, now wrestle the comments
|
219 |
+
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
220 |
+
|
221 |
+
$token = $this->comments[$i];
|
222 |
+
$placeholder = '/' . self::COMMENT . $i . '___/';
|
223 |
+
|
224 |
+
// ! in the first position of the comment means preserve
|
225 |
+
// so push to the preserved tokens keeping the !
|
226 |
+
if (substr($token, 0, 1) === '!') {
|
227 |
+
$this->preserved_tokens[] = $token;
|
228 |
+
$token_tring = self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
|
229 |
+
$css = preg_replace($placeholder, $token_tring, $css, 1);
|
230 |
+
// Preserve new lines for /*! important comments
|
231 |
+
$css = preg_replace('/\s*[\n\r\f]+\s*(\/\*'. $token_tring .')/S', self::NL.'$1', $css);
|
232 |
+
$css = preg_replace('/('. $token_tring .'\*\/)\s*[\n\r\f]+\s*/', '$1'.self::NL, $css);
|
233 |
+
continue;
|
234 |
+
}
|
235 |
+
|
236 |
+
// \ in the last position looks like hack for Mac/IE5
|
237 |
+
// shorten that to /*\*/ and the next one to /**/
|
238 |
+
if (substr($token, (strlen($token) - 1), 1) === '\\') {
|
239 |
+
$this->preserved_tokens[] = '\\';
|
240 |
+
$css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
241 |
+
$i = $i + 1; // attn: advancing the loop
|
242 |
+
$this->preserved_tokens[] = '';
|
243 |
+
$css = preg_replace('/' . self::COMMENT . $i . '___/', self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
244 |
+
continue;
|
245 |
+
}
|
246 |
+
|
247 |
+
// keep empty comments after child selectors (IE7 hack)
|
248 |
+
// e.g. html >/**/ body
|
249 |
+
if (strlen($token) === 0) {
|
250 |
+
$start_index = $this->index_of($css, $this->str_slice($placeholder, 1, -1));
|
251 |
+
if ($start_index > 2) {
|
252 |
+
if (substr($css, $start_index - 3, 1) === '>') {
|
253 |
+
$this->preserved_tokens[] = '';
|
254 |
+
$css = preg_replace($placeholder, self::TOKEN . (count($this->preserved_tokens) - 1) . '___', $css, 1);
|
255 |
+
}
|
256 |
+
}
|
257 |
+
}
|
258 |
+
|
259 |
+
// in all other cases kill the comment
|
260 |
+
$css = preg_replace('/\/\*' . $this->str_slice($placeholder, 1, -1) . '\*\//', '', $css, 1);
|
261 |
+
}
|
262 |
+
|
263 |
+
|
264 |
+
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
265 |
+
$css = preg_replace('/\s+/', ' ', $css);
|
266 |
+
|
267 |
+
// preserve flex, keeping percentage even if 0
|
268 |
+
$css = preg_replace_callback('/flex\s?:\s?((?:[0-9 ]*)\s?(?:px|em|auto|%)?(?:calc\(.*\))?)/i',array($this, 'replace_flex'),$css);
|
269 |
+
|
270 |
+
// Fix IE7 issue on matrix filters which browser accept whitespaces between Matrix parameters
|
271 |
+
$css = preg_replace_callback('/\s*filter\:\s*progid:DXImageTransform\.Microsoft\.Matrix\(([^\)]+)\)/', array($this, 'preserve_old_IE_specific_matrix_definition'), $css);
|
272 |
+
|
273 |
+
// Shorten & preserve calculations calc(...) since spaces are important
|
274 |
+
$css = preg_replace_callback('/calc(\(((?:[^\(\)]+|(?1))*)\))/i', array($this, 'replace_calc'), $css);
|
275 |
+
|
276 |
+
// Replace positive sign from numbers preceded by : or a white-space before the leading space is removed
|
277 |
+
// +1.2em to 1.2em, +.8px to .8px, +2% to 2%
|
278 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)\+(\.?\d+)/S', '$1$2', $css);
|
279 |
+
|
280 |
+
// Remove leading zeros from integer and float numbers preceded by : or a white-space
|
281 |
+
// 000.6 to .6, -0.8 to -.8, 0050 to 50, -01.05 to -1.05
|
282 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?)0+(\.?\d+)/S', '$1$2$3', $css);
|
283 |
+
|
284 |
+
// Remove trailing zeros from float numbers preceded by : or a white-space
|
285 |
+
// -6.0100em to -6.01em, .0100 to .01, 1.200px to 1.2px
|
286 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?)(\d?\.\d+?)0+([^\d])/S', '$1$2$3$4', $css);
|
287 |
+
|
288 |
+
// Remove trailing .0 -> -9.0 to -9
|
289 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)(\-?\d+)\.0([^\d])/S', '$1$2$3', $css);
|
290 |
+
|
291 |
+
// Replace 0 length numbers with 0
|
292 |
+
$css = preg_replace('/((?<!\\\\)\:|\s)\-?\.?0+([^\d])/S', '${1}0$2', $css);
|
293 |
+
|
294 |
+
// Remove the spaces before the things that should not have spaces before them.
|
295 |
+
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
296 |
+
// Swap out any pseudo-class colons with the token, and then swap back.
|
297 |
+
$css = preg_replace_callback('/(?:^|\})[^\{]*\s+\:/', array($this, 'replace_colon'), $css);
|
298 |
+
|
299 |
+
// Remove spaces before the things that should not have spaces before them.
|
300 |
+
$css = preg_replace('/\s+([\!\{\}\;\:\>\+\(\)\]\~\=,])/', '$1', $css);
|
301 |
+
|
302 |
+
// Restore spaces for !important
|
303 |
+
$css = preg_replace('/\!important/i', ' !important', $css);
|
304 |
+
|
305 |
+
// bring back the colon
|
306 |
+
$css = preg_replace('/' . self::CLASSCOLON . '/', ':', $css);
|
307 |
+
|
308 |
+
// retain space for special IE6 cases
|
309 |
+
$css = preg_replace_callback('/\:first\-(line|letter)(\{|,)/i', array($this, 'lowercase_pseudo_first'), $css);
|
310 |
+
|
311 |
+
// no space after the end of a preserved comment
|
312 |
+
$css = preg_replace('/\*\/ /', '*/', $css);
|
313 |
+
|
314 |
+
// lowercase some popular @directives
|
315 |
+
$css = preg_replace_callback('/@(font-face|import|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?keyframe|media|page|namespace)/i', array($this, 'lowercase_directives'), $css);
|
316 |
+
|
317 |
+
// lowercase some more common pseudo-elements
|
318 |
+
$css = preg_replace_callback('/:(active|after|before|checked|disabled|empty|enabled|first-(?:child|of-type)|focus|hover|last-(?:child|of-type)|link|only-(?:child|of-type)|root|:selection|target|visited)/i', array($this, 'lowercase_pseudo_elements'), $css);
|
319 |
+
|
320 |
+
// lowercase some more common functions
|
321 |
+
$css = preg_replace_callback('/:(lang|not|nth-child|nth-last-child|nth-last-of-type|nth-of-type|(?:-(?:moz|webkit)-)?any)\(/i', array($this, 'lowercase_common_functions'), $css);
|
322 |
+
|
323 |
+
// lower case some common function that can be values
|
324 |
+
// NOTE: rgb() isn't useful as we replace with #hex later, as well as and() is already done for us
|
325 |
+
$css = preg_replace_callback('/([:,\( ]\s*)(attr|color-stop|from|rgba|to|url|(?:-(?:atsc|khtml|moz|ms|o|wap|webkit)-)?(?:calc|max|min|(?:repeating-)?(?:linear|radial)-gradient)|-webkit-gradient)/iS', array($this, 'lowercase_common_functions_values'), $css);
|
326 |
+
|
327 |
+
// Put the space back in some cases, to support stuff like
|
328 |
+
// @media screen and (-webkit-min-device-pixel-ratio:0){
|
329 |
+
$css = preg_replace('/\band\(/i', 'and (', $css);
|
330 |
+
|
331 |
+
// Remove the spaces after the things that should not have spaces after them.
|
332 |
+
$css = preg_replace('/([\!\{\}\:;\>\+\(\[\~\=,])\s+/S', '$1', $css);
|
333 |
+
|
334 |
+
// remove unnecessary semicolons
|
335 |
+
$css = preg_replace('/;+\}/', '}', $css);
|
336 |
+
|
337 |
+
// Fix for issue: #2528146
|
338 |
+
// Restore semicolon if the last property is prefixed with a `*` (lte IE7 hack)
|
339 |
+
// to avoid issues on Symbian S60 3.x browsers.
|
340 |
+
$css = preg_replace('/(\*[a-z0-9\-]+\s*\:[^;\}]+)(\})/', '$1;$2', $css);
|
341 |
+
|
342 |
+
// Replace 0 <length> and 0 <percentage> values with 0.
|
343 |
+
// <length> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/length
|
344 |
+
// <percentage> data type: https://developer.mozilla.org/en-US/docs/Web/CSS/percentage
|
345 |
+
$css = preg_replace('/([^\\\\]\:|\s)0(?:em|ex|ch|rem|vw|vh|vm|vmin|cm|mm|in|px|pt|pc|%)/iS', '${1}0', $css);
|
346 |
+
|
347 |
+
// 0% step in a keyframe? restore the % unit
|
348 |
+
$css = preg_replace_callback('/(@[a-z\-]*?keyframes[^\{]+\{)(.*?)(\}\})/iS', array($this, 'replace_keyframe_zero'), $css);
|
349 |
+
|
350 |
+
// Replace 0 0; or 0 0 0; or 0 0 0 0; with 0.
|
351 |
+
$css = preg_replace('/\:0(?: 0){1,3}(;|\}| \!)/', ':0$1', $css);
|
352 |
+
|
353 |
+
// Fix for issue: #2528142
|
354 |
+
// Replace text-shadow:0; with text-shadow:0 0 0;
|
355 |
+
$css = preg_replace('/(text-shadow\:0)(;|\}| \!)/i', '$1 0 0$2', $css);
|
356 |
+
|
357 |
+
// Replace background-position:0; with background-position:0 0;
|
358 |
+
// same for transform-origin
|
359 |
+
// Changing -webkit-mask-position: 0 0 to just a single 0 will result in the second parameter defaulting to 50% (center)
|
360 |
+
$css = preg_replace('/(background|background\-position|webkit-mask-position|(?:webkit|moz|o|ms|)\-?transform\-origin)\:0(;|\}| \!)/iS', '$1:0 0$2', $css);
|
361 |
+
|
362 |
+
// Shorten colors from rgb(51,102,153) to #336699, rgb(100%,0%,0%) to #ff0000 (sRGB color space)
|
363 |
+
// Shorten colors from hsl(0, 100%, 50%) to #ff0000 (sRGB color space)
|
364 |
+
// This makes it more likely that it'll get further compressed in the next step.
|
365 |
+
$css = preg_replace_callback('/rgb\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'rgb_to_hex'), $css);
|
366 |
+
$css = preg_replace_callback('/hsl\s*\(\s*([0-9,\s\-\.\%]+)\s*\)(.{1})/i', array($this, 'hsl_to_hex'), $css);
|
367 |
+
|
368 |
+
// Shorten colors from #AABBCC to #ABC or short color name.
|
369 |
+
$css = $this->compress_hex_colors($css);
|
370 |
+
|
371 |
+
// border: none to border:0, outline: none to outline:0
|
372 |
+
$css = preg_replace('/(border\-?(?:top|right|bottom|left|)|outline)\:none(;|\}| \!)/iS', '$1:0$2', $css);
|
373 |
+
|
374 |
+
// shorter opacity IE filter
|
375 |
+
$css = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $css);
|
376 |
+
|
377 |
+
// Find a fraction that is used for Opera's -o-device-pixel-ratio query
|
378 |
+
// Add token to add the "\" back in later
|
379 |
+
$css = preg_replace('/\(([a-z\-]+):([0-9]+)\/([0-9]+)\)/i', '($1:$2'. self::QUERY_FRACTION .'$3)', $css);
|
380 |
+
|
381 |
+
// Remove empty rules.
|
382 |
+
$css = preg_replace('/[^\};\{\/]+\{\}/S', '', $css);
|
383 |
+
|
384 |
+
// Add "/" back to fix Opera -o-device-pixel-ratio query
|
385 |
+
$css = preg_replace('/'. self::QUERY_FRACTION .'/', '/', $css);
|
386 |
+
|
387 |
+
// Replace multiple semi-colons in a row by a single one
|
388 |
+
// See SF bug #1980989
|
389 |
+
$css = preg_replace('/;;+/', ';', $css);
|
390 |
+
|
391 |
+
// Restore new lines for /*! important comments
|
392 |
+
$css = preg_replace('/'. self::NL .'/', "\n", $css);
|
393 |
+
|
394 |
+
// Lowercase all uppercase properties
|
395 |
+
$css = preg_replace_callback('/(\{|\;)([A-Z\-]+)(\:)/', array($this, 'lowercase_properties'), $css);
|
396 |
+
|
397 |
+
// Some source control tools don't like it when files containing lines longer
|
398 |
+
// than, say 8000 characters, are checked in. The linebreak option is used in
|
399 |
+
// that case to split long lines after a specific column.
|
400 |
+
if ($linebreak_pos !== FALSE && (int) $linebreak_pos >= 0) {
|
401 |
+
$linebreak_pos = (int) $linebreak_pos;
|
402 |
+
$start_index = $i = 0;
|
403 |
+
while ($i < strlen($css)) {
|
404 |
+
$i++;
|
405 |
+
if ($css[$i - 1] === '}' && $i - $start_index > $linebreak_pos) {
|
406 |
+
$css = $this->str_slice($css, 0, $i) . "\n" . $this->str_slice($css, $i);
|
407 |
+
$start_index = $i;
|
408 |
+
}
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
+
// restore preserved comments and strings in reverse order
|
413 |
+
for ($i = count($this->preserved_tokens) - 1; $i >= 0; $i--) {
|
414 |
+
$css = preg_replace('/' . self::TOKEN . $i . '___/', $this->preserved_tokens[$i], $css, 1);
|
415 |
+
// $css.=$this->preserved_tokens[$i];
|
416 |
+
}
|
417 |
+
|
418 |
+
// Trim the final string (for any leading or trailing white spaces)
|
419 |
+
return trim($css);
|
420 |
+
}
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Utility method to replace all data urls with tokens before we start
|
424 |
+
* compressing, to avoid performance issues running some of the subsequent
|
425 |
+
* regexes against large strings chunks.
|
426 |
+
*
|
427 |
+
* @param string $css
|
428 |
+
* @return string
|
429 |
+
*/
|
430 |
+
private function extract_data_urls($css)
|
431 |
+
{
|
432 |
+
// Leave data urls alone to increase parse performance.
|
433 |
+
$max_index = strlen($css) - 1;
|
434 |
+
$append_index = $index = $last_index = $offset = 0;
|
435 |
+
$sb = array();
|
436 |
+
$pattern = '/url\(\s*(["\']?)data\:/i';
|
437 |
+
|
438 |
+
// Since we need to account for non-base64 data urls, we need to handle
|
439 |
+
// ' and ) being part of the data string. Hence switching to indexOf,
|
440 |
+
// to determine whether or not we have matching string terminators and
|
441 |
+
// handling sb appends directly, instead of using matcher.append* methods.
|
442 |
+
|
443 |
+
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
444 |
+
$index = $this->index_of($css, $m[0], $offset);
|
445 |
+
$last_index = $index + strlen($m[0]);
|
446 |
+
$start_index = $index + 4; // "url(".length()
|
447 |
+
$end_index = $last_index - 1;
|
448 |
+
$terminator = $m[1]; // ', " or empty (not quoted)
|
449 |
+
$found_terminator = FALSE;
|
450 |
+
|
451 |
+
if (strlen($terminator) === 0) {
|
452 |
+
$terminator = ')';
|
453 |
+
}
|
454 |
+
|
455 |
+
while ($found_terminator === FALSE && $end_index+1 <= $max_index) {
|
456 |
+
$end_index = $this->index_of($css, $terminator, $end_index + 1);
|
457 |
+
|
458 |
+
// endIndex == 0 doesn't really apply here
|
459 |
+
if ($end_index > 0 && substr($css, $end_index - 1, 1) !== '\\') {
|
460 |
+
$found_terminator = TRUE;
|
461 |
+
if (')' != $terminator) {
|
462 |
+
$end_index = $this->index_of($css, ')', $end_index);
|
463 |
+
}
|
464 |
+
}
|
465 |
+
}
|
466 |
+
|
467 |
+
// Enough searching, start moving stuff over to the buffer
|
468 |
+
$sb[] = $this->str_slice($css, $append_index, $index);
|
469 |
+
|
470 |
+
if ($found_terminator) {
|
471 |
+
$token = $this->str_slice($css, $start_index, $end_index);
|
472 |
+
if (strpos($token,"<svg")===false && strpos($token,'svg+xml')===false) {
|
473 |
+
$token = preg_replace('/\s+/', '', $token);
|
474 |
+
}
|
475 |
+
$this->preserved_tokens[] = $token;
|
476 |
+
|
477 |
+
$preserver = 'url(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___)';
|
478 |
+
$sb[] = $preserver;
|
479 |
+
|
480 |
+
$append_index = $end_index + 1;
|
481 |
+
} else {
|
482 |
+
// No end terminator found, re-add the whole match. Should we throw/warn here?
|
483 |
+
$sb[] = $this->str_slice($css, $index, $last_index);
|
484 |
+
$append_index = $last_index;
|
485 |
+
}
|
486 |
+
|
487 |
+
$offset = $last_index;
|
488 |
+
}
|
489 |
+
|
490 |
+
$sb[] = $this->str_slice($css, $append_index);
|
491 |
+
|
492 |
+
return implode('', $sb);
|
493 |
+
}
|
494 |
+
|
495 |
+
/**
|
496 |
+
* Utility method to compress hex color values of the form #AABBCC to #ABC or short color name.
|
497 |
+
*
|
498 |
+
* DOES NOT compress CSS ID selectors which match the above pattern (which would break things).
|
499 |
+
* e.g. #AddressForm { ... }
|
500 |
+
*
|
501 |
+
* DOES NOT compress IE filters, which have hex color values (which would break things).
|
502 |
+
* e.g. filter: chroma(color="#FFFFFF");
|
503 |
+
*
|
504 |
+
* DOES NOT compress invalid hex values.
|
505 |
+
* e.g. background-color: #aabbccdd
|
506 |
+
*
|
507 |
+
* @param string $css
|
508 |
+
* @return string
|
509 |
+
*/
|
510 |
+
private function compress_hex_colors($css)
|
511 |
+
{
|
512 |
+
// Look for hex colors inside { ... } (to avoid IDs) and which don't have a =, or a " in front of them (to avoid filters)
|
513 |
+
$pattern = '/(\=\s*?["\']?)?#([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])(\}|[^0-9a-f{][^{]*?\})/iS';
|
514 |
+
$_index = $index = $last_index = $offset = 0;
|
515 |
+
$sb = array();
|
516 |
+
// See: http://ajaxmin.codeplex.com/wikipage?title=CSS%20Colors
|
517 |
+
$short_safe = array(
|
518 |
+
'#808080' => 'gray',
|
519 |
+
'#008000' => 'green',
|
520 |
+
'#800000' => 'maroon',
|
521 |
+
'#000080' => 'navy',
|
522 |
+
'#808000' => 'olive',
|
523 |
+
'#ffa500' => 'orange',
|
524 |
+
'#800080' => 'purple',
|
525 |
+
'#c0c0c0' => 'silver',
|
526 |
+
'#008080' => 'teal',
|
527 |
+
'#f00' => 'red'
|
528 |
+
);
|
529 |
+
|
530 |
+
while (preg_match($pattern, $css, $m, 0, $offset)) {
|
531 |
+
$index = $this->index_of($css, $m[0], $offset);
|
532 |
+
$last_index = $index + strlen($m[0]);
|
533 |
+
$is_filter = $m[1] !== null && $m[1] !== '';
|
534 |
+
|
535 |
+
$sb[] = $this->str_slice($css, $_index, $index);
|
536 |
+
|
537 |
+
if ($is_filter) {
|
538 |
+
// Restore, maintain case, otherwise filter will break
|
539 |
+
$sb[] = $m[1] . '#' . $m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7];
|
540 |
+
} else {
|
541 |
+
if (strtolower($m[2]) == strtolower($m[3]) &&
|
542 |
+
strtolower($m[4]) == strtolower($m[5]) &&
|
543 |
+
strtolower($m[6]) == strtolower($m[7])) {
|
544 |
+
// Compress.
|
545 |
+
$hex = '#' . strtolower($m[3] . $m[5] . $m[7]);
|
546 |
+
} else {
|
547 |
+
// Non compressible color, restore but lower case.
|
548 |
+
$hex = '#' . strtolower($m[2] . $m[3] . $m[4] . $m[5] . $m[6] . $m[7]);
|
549 |
+
}
|
550 |
+
// replace Hex colors to short safe color names
|
551 |
+
$sb[] = array_key_exists($hex, $short_safe) ? $short_safe[$hex] : $hex;
|
552 |
+
}
|
553 |
+
|
554 |
+
$_index = $offset = $last_index - strlen($m[8]);
|
555 |
+
}
|
556 |
+
|
557 |
+
$sb[] = $this->str_slice($css, $_index);
|
558 |
+
|
559 |
+
return implode('', $sb);
|
560 |
+
}
|
561 |
+
|
562 |
+
/* CALLBACKS
|
563 |
+
* ---------------------------------------------------------------------------------------------
|
564 |
+
*/
|
565 |
+
|
566 |
+
private function replace_string($matches)
|
567 |
+
{
|
568 |
+
$match = $matches[0];
|
569 |
+
$quote = substr($match, 0, 1);
|
570 |
+
// Must use addcslashes in PHP to avoid parsing of backslashes
|
571 |
+
$match = addcslashes($this->str_slice($match, 1, -1), '\\');
|
572 |
+
|
573 |
+
// maybe the string contains a comment-like substring?
|
574 |
+
// one, maybe more? put'em back then
|
575 |
+
if (($pos = $this->index_of($match, self::COMMENT)) >= 0) {
|
576 |
+
for ($i = 0, $max = count($this->comments); $i < $max; $i++) {
|
577 |
+
$match = preg_replace('/' . self::COMMENT . $i . '___/', $this->comments[$i], $match, 1);
|
578 |
+
}
|
579 |
+
}
|
580 |
+
|
581 |
+
// minify alpha opacity in filter strings
|
582 |
+
$match = preg_replace('/progid\:DXImageTransform\.Microsoft\.Alpha\(Opacity\=/i', 'alpha(opacity=', $match);
|
583 |
+
|
584 |
+
$this->preserved_tokens[] = $match;
|
585 |
+
return $quote . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . $quote;
|
586 |
+
}
|
587 |
+
|
588 |
+
private function replace_colon($matches)
|
589 |
+
{
|
590 |
+
return preg_replace('/\:/', self::CLASSCOLON, $matches[0]);
|
591 |
+
}
|
592 |
+
|
593 |
+
private function replace_calc($matches)
|
594 |
+
{
|
595 |
+
$this->preserved_tokens[] = preg_replace('/([\+\-]{1})\(/','$1 (',trim(preg_replace('/\s*([\*\/\(\),])\s*/', '$1', $matches[2])));
|
596 |
+
return 'calc('. self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
597 |
+
}
|
598 |
+
|
599 |
+
private function replace_flex($matches)
|
600 |
+
{
|
601 |
+
$this->preserved_tokens[] = trim($matches[1]);
|
602 |
+
return 'flex:'.self::TOKEN . (count($this->preserved_tokens) - 1) . '___';
|
603 |
+
}
|
604 |
+
|
605 |
+
private function preserve_old_IE_specific_matrix_definition($matches)
|
606 |
+
{
|
607 |
+
$this->preserved_tokens[] = $matches[1];
|
608 |
+
return 'filter:progid:DXImageTransform.Microsoft.Matrix(' . self::TOKEN . (count($this->preserved_tokens) - 1) . '___' . ')';
|
609 |
+
}
|
610 |
+
|
611 |
+
private function replace_keyframe_zero($matches)
|
612 |
+
{
|
613 |
+
return $matches[1] . preg_replace('/0(\{|,[^\)\{]+\{)/', '0%$1', $matches[2]) . $matches[3];
|
614 |
+
}
|
615 |
+
|
616 |
+
private function rgb_to_hex($matches)
|
617 |
+
{
|
618 |
+
// Support for percentage values rgb(100%, 0%, 45%);
|
619 |
+
if ($this->index_of($matches[1], '%') >= 0){
|
620 |
+
$rgbcolors = explode(',', str_replace('%', '', $matches[1]));
|
621 |
+
for ($i = 0; $i < count($rgbcolors); $i++) {
|
622 |
+
$rgbcolors[$i] = $this->round_number(floatval($rgbcolors[$i]) * 2.55);
|
623 |
+
}
|
624 |
+
} else {
|
625 |
+
$rgbcolors = explode(',', $matches[1]);
|
626 |
+
}
|
627 |
+
|
628 |
+
// Values outside the sRGB color space should be clipped (0-255)
|
629 |
+
for ($i = 0; $i < count($rgbcolors); $i++) {
|
630 |
+
$rgbcolors[$i] = $this->clamp_number(intval($rgbcolors[$i], 10), 0, 255);
|
631 |
+
$rgbcolors[$i] = sprintf("%02x", $rgbcolors[$i]);
|
632 |
+
}
|
633 |
+
|
634 |
+
// Fix for issue #2528093
|
635 |
+
if (!preg_match('/[\s\,\);\}]/', $matches[2])){
|
636 |
+
$matches[2] = ' ' . $matches[2];
|
637 |
+
}
|
638 |
+
|
639 |
+
return '#' . implode('', $rgbcolors) . $matches[2];
|
640 |
+
}
|
641 |
+
|
642 |
+
private function hsl_to_hex($matches)
|
643 |
+
{
|
644 |
+
$values = explode(',', str_replace('%', '', $matches[1]));
|
645 |
+
$h = floatval($values[0]);
|
646 |
+
$s = floatval($values[1]);
|
647 |
+
$l = floatval($values[2]);
|
648 |
+
|
649 |
+
// Wrap and clamp, then fraction!
|
650 |
+
$h = ((($h % 360) + 360) % 360) / 360;
|
651 |
+
$s = $this->clamp_number($s, 0, 100) / 100;
|
652 |
+
$l = $this->clamp_number($l, 0, 100) / 100;
|
653 |
+
|
654 |
+
if ($s == 0) {
|
655 |
+
$r = $g = $b = $this->round_number(255 * $l);
|
656 |
+
} else {
|
657 |
+
$v2 = $l < 0.5 ? $l * (1 + $s) : ($l + $s) - ($s * $l);
|
658 |
+
$v1 = (2 * $l) - $v2;
|
659 |
+
$r = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h + (1/3)));
|
660 |
+
$g = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h));
|
661 |
+
$b = $this->round_number(255 * $this->hue_to_rgb($v1, $v2, $h - (1/3)));
|
662 |
+
}
|
663 |
+
|
664 |
+
return $this->rgb_to_hex(array('', $r.','.$g.','.$b, $matches[2]));
|
665 |
+
}
|
666 |
+
|
667 |
+
private function lowercase_pseudo_first($matches)
|
668 |
+
{
|
669 |
+
return ':first-'. strtolower($matches[1]) .' '. $matches[2];
|
670 |
+
}
|
671 |
+
|
672 |
+
private function lowercase_directives($matches)
|
673 |
+
{
|
674 |
+
return '@'. strtolower($matches[1]);
|
675 |
+
}
|
676 |
+
|
677 |
+
private function lowercase_pseudo_elements($matches)
|
678 |
+
{
|
679 |
+
return ':'. strtolower($matches[1]);
|
680 |
+
}
|
681 |
+
|
682 |
+
private function lowercase_common_functions($matches)
|
683 |
+
{
|
684 |
+
return ':'. strtolower($matches[1]) .'(';
|
685 |
+
}
|
686 |
+
|
687 |
+
private function lowercase_common_functions_values($matches)
|
688 |
+
{
|
689 |
+
return $matches[1] . strtolower($matches[2]);
|
690 |
+
}
|
691 |
+
|
692 |
+
private function lowercase_properties($matches)
|
693 |
+
{
|
694 |
+
return $matches[1].strtolower($matches[2]).$matches[3];
|
695 |
+
}
|
696 |
+
|
697 |
+
/* HELPERS
|
698 |
+
* ---------------------------------------------------------------------------------------------
|
699 |
+
*/
|
700 |
+
|
701 |
+
private function hue_to_rgb($v1, $v2, $vh)
|
702 |
+
{
|
703 |
+
$vh = $vh < 0 ? $vh + 1 : ($vh > 1 ? $vh - 1 : $vh);
|
704 |
+
if ($vh * 6 < 1) return $v1 + ($v2 - $v1) * 6 * $vh;
|
705 |
+
if ($vh * 2 < 1) return $v2;
|
706 |
+
if ($vh * 3 < 2) return $v1 + ($v2 - $v1) * ((2/3) - $vh) * 6;
|
707 |
+
return $v1;
|
708 |
+
}
|
709 |
+
|
710 |
+
private function round_number($n)
|
711 |
+
{
|
712 |
+
return intval(floor(floatval($n) + 0.5), 10);
|
713 |
+
}
|
714 |
+
|
715 |
+
private function clamp_number($n, $min, $max)
|
716 |
+
{
|
717 |
+
return min(max($n, $min), $max);
|
718 |
+
}
|
719 |
+
|
720 |
+
/**
|
721 |
+
* PHP port of Javascript's "indexOf" function for strings only
|
722 |
+
* Author: Tubal Martin http://blog.margenn.com
|
723 |
+
*
|
724 |
+
* @param string $haystack
|
725 |
+
* @param string $needle
|
726 |
+
* @param int $offset index (optional)
|
727 |
+
* @return int
|
728 |
+
*/
|
729 |
+
private function index_of($haystack, $needle, $offset = 0)
|
730 |
+
{
|
731 |
+
$index = strpos($haystack, $needle, $offset);
|
732 |
+
|
733 |
+
return ($index !== FALSE) ? $index : -1;
|
734 |
+
}
|
735 |
+
|
736 |
+
/**
|
737 |
+
* PHP port of Javascript's "slice" function for strings only
|
738 |
+
* Author: Tubal Martin http://blog.margenn.com
|
739 |
+
* Tests: http://margenn.com/tubal/str_slice/
|
740 |
+
*
|
741 |
+
* @param string $str
|
742 |
+
* @param int $start index
|
743 |
+
* @param int|bool $end index (optional)
|
744 |
+
* @return string
|
745 |
+
*/
|
746 |
+
private function str_slice($str, $start = 0, $end = FALSE)
|
747 |
+
{
|
748 |
+
if ($end !== FALSE && ($start < 0 || $end <= 0)) {
|
749 |
+
$max = strlen($str);
|
750 |
+
|
751 |
+
if ($start < 0) {
|
752 |
+
if (($start = $max + $start) < 0) {
|
753 |
+
return '';
|
754 |
+
}
|
755 |
+
}
|
756 |
+
|
757 |
+
if ($end < 0) {
|
758 |
+
if (($end = $max + $end) < 0) {
|
759 |
+
return '';
|
760 |
+
}
|
761 |
+
}
|
762 |
+
|
763 |
+
if ($end <= $start) {
|
764 |
+
return '';
|
765 |
+
}
|
766 |
+
}
|
767 |
+
|
768 |
+
$slice = ($end === FALSE) ? substr($str, $start) : substr($str, $start, $end - $start);
|
769 |
+
return ($slice === FALSE) ? '' : $slice;
|
770 |
+
}
|
771 |
+
|
772 |
+
/**
|
773 |
+
* Convert strings like "64M" or "30" to int values
|
774 |
+
* @param mixed $size
|
775 |
+
* @return int
|
776 |
+
*/
|
777 |
+
private function normalize_int($size)
|
778 |
+
{
|
779 |
+
if (is_string($size)) {
|
780 |
+
switch (substr($size, -1)) {
|
781 |
+
case 'M': case 'm': return $size * 1048576;
|
782 |
+
case 'K': case 'k': return $size * 1024;
|
783 |
+
case 'G': case 'g': return $size * 1073741824;
|
784 |
+
}
|
785 |
+
}
|
786 |
+
|
787 |
+
return (int) $size;
|
788 |
+
}
|
789 |
+
}
|
languages/breeze-en_US.mo
ADDED
Binary file
|
languages/breeze-en_US.po
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
msgid ""
|
2 |
+
msgstr ""
|
3 |
+
"Project-Id-Version: Cloudways Wordpress Cache 1.0\n"
|
4 |
+
"POT-Creation-Date: \n"
|
5 |
+
"PO-Revision-Date: \n"
|
6 |
+
"Last-Translator: \n"
|
7 |
+
"Language-Team: \n"
|
8 |
+
"Language: en_US\n"
|
9 |
+
"MIME-Version: 1.0\n"
|
10 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
+
"Content-Transfer-Encoding: 8bit\n"
|
12 |
+
"X-Generator: Poedit 1.8.9\n"
|
13 |
+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
14 |
+
|
15 |
+
msgid "Cloudways WP Cache"
|
16 |
+
msgstr ""
|
17 |
+
|
18 |
+
msgid "Cloudways Purge Cache"
|
19 |
+
msgstr ""
|
20 |
+
|
21 |
+
msgid "Please set the IPs for Purge Cache!"
|
22 |
+
msgstr ""
|
23 |
+
|
24 |
+
msgid "Cloudways Varnish Purge Interval"
|
25 |
+
msgstr ""
|
26 |
+
|
27 |
+
msgid "Purge cache after"
|
28 |
+
msgstr ""
|
29 |
+
|
30 |
+
msgid "Set IPs"
|
31 |
+
msgstr ""
|
32 |
+
|
33 |
+
msgid "Save setting"
|
34 |
+
msgstr ""
|
35 |
+
|
36 |
+
msgid ""
|
37 |
+
msgstr ""
|
38 |
+
|
39 |
+
msgid ""
|
40 |
+
msgstr ""
|
41 |
+
|
42 |
+
msgid ""
|
43 |
+
msgstr ""
|
44 |
+
|
45 |
+
msgid ""
|
46 |
+
msgstr ""
|
47 |
+
|
48 |
+
msgid ""
|
49 |
+
msgstr ""
|
50 |
+
|
51 |
+
msgid ""
|
52 |
+
msgstr ""
|
53 |
+
|
54 |
+
msgid ""
|
55 |
+
msgstr ""
|
56 |
+
|
57 |
+
msgid ""
|
58 |
+
msgstr ""
|
59 |
+
|
60 |
+
msgid ""
|
61 |
+
msgstr ""
|
62 |
+
|
63 |
+
msgid ""
|
64 |
+
msgstr ""
|
65 |
+
|
66 |
+
msgid ""
|
67 |
+
msgstr ""
|
68 |
+
|
69 |
+
msgid ""
|
70 |
+
msgstr ""
|
71 |
+
|
72 |
+
msgid ""
|
73 |
+
msgstr ""
|
74 |
+
|
75 |
+
msgid ""
|
76 |
+
msgstr ""
|
77 |
+
|
78 |
+
msgid ""
|
79 |
+
msgstr ""
|
80 |
+
|
81 |
+
msgid ""
|
82 |
+
msgstr ""
|
83 |
+
|
84 |
+
msgid ""
|
85 |
+
msgstr ""
|
86 |
+
|
87 |
+
msgid ""
|
88 |
+
msgstr ""
|
89 |
+
|
90 |
+
msgid ""
|
91 |
+
msgstr ""
|
92 |
+
|
93 |
+
msgid ""
|
94 |
+
msgstr ""
|
95 |
+
|
96 |
+
msgid ""
|
97 |
+
msgstr ""
|
98 |
+
|
99 |
+
msgid ""
|
100 |
+
msgstr ""
|
101 |
+
|
102 |
+
msgid ""
|
103 |
+
msgstr ""
|
104 |
+
|
105 |
+
msgid ""
|
106 |
+
msgstr ""
|
107 |
+
|
108 |
+
msgid ""
|
109 |
+
msgstr ""
|
110 |
+
|
languages/breeze-fr_FR.mo
ADDED
Binary file
|
languages/breeze-fr_FR.po
ADDED
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
msgid ""
|
2 |
+
msgstr ""
|
3 |
+
"Project-Id-Version: Cloudways Wordpress Cache 1.0\n"
|
4 |
+
"POT-Creation-Date: \n"
|
5 |
+
"PO-Revision-Date: \n"
|
6 |
+
"Last-Translator: \n"
|
7 |
+
"Language-Team: \n"
|
8 |
+
"Language: fr_FR\n"
|
9 |
+
"MIME-Version: 1.0\n"
|
10 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
+
"Content-Transfer-Encoding: 8bit\n"
|
12 |
+
"X-Generator: Poedit 1.8.9\n"
|
13 |
+
|
14 |
+
msgid "Cloudways WP Cache"
|
15 |
+
msgstr ""
|
16 |
+
|
17 |
+
msgid "Cloudways Purge Cache"
|
18 |
+
msgstr ""
|
19 |
+
|
20 |
+
msgid "Please set the IPs for Purge Cache!"
|
21 |
+
msgstr ""
|
22 |
+
|
23 |
+
msgid "Cloudways Varnish Purge Interval"
|
24 |
+
msgstr ""
|
25 |
+
|
26 |
+
msgid "Purge cache after"
|
27 |
+
msgstr ""
|
28 |
+
|
29 |
+
msgid "Set IPs"
|
30 |
+
msgstr ""
|
31 |
+
|
32 |
+
msgid "Save setting"
|
33 |
+
msgstr ""
|
34 |
+
|
35 |
+
msgid ""
|
36 |
+
msgstr ""
|
37 |
+
|
38 |
+
msgid ""
|
39 |
+
msgstr ""
|
40 |
+
|
41 |
+
msgid ""
|
42 |
+
msgstr ""
|
43 |
+
|
44 |
+
msgid ""
|
45 |
+
msgstr ""
|
46 |
+
|
47 |
+
msgid ""
|
48 |
+
msgstr ""
|
49 |
+
|
50 |
+
msgid ""
|
51 |
+
msgstr ""
|
52 |
+
|
53 |
+
msgid ""
|
54 |
+
msgstr ""
|
55 |
+
|
56 |
+
msgid ""
|
57 |
+
msgstr ""
|
58 |
+
|
59 |
+
msgid ""
|
60 |
+
msgstr ""
|
61 |
+
|
62 |
+
msgid ""
|
63 |
+
msgstr ""
|
64 |
+
|
65 |
+
msgid ""
|
66 |
+
msgstr ""
|
67 |
+
|
68 |
+
msgid ""
|
69 |
+
msgstr ""
|
70 |
+
|
71 |
+
msgid ""
|
72 |
+
msgstr ""
|
73 |
+
|
74 |
+
msgid ""
|
75 |
+
msgstr ""
|
76 |
+
|
77 |
+
msgid ""
|
78 |
+
msgstr ""
|
79 |
+
|
80 |
+
msgid ""
|
81 |
+
msgstr ""
|
82 |
+
|
83 |
+
msgid ""
|
84 |
+
msgstr ""
|
85 |
+
|
86 |
+
msgid ""
|
87 |
+
msgstr ""
|
languages/breeze.pot
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#, fuzzy
|
2 |
+
msgid ""
|
3 |
+
msgstr ""
|
4 |
+
"Project-Id-Version: Cloudways Wordpress Cache\n"
|
5 |
+
"POT-Creation-Date: \n"
|
6 |
+
"PO-Revision-Date: \n"
|
7 |
+
"Last-Translator: \n"
|
8 |
+
"Language-Team: \n"
|
9 |
+
"MIME-Version: 1.0\n"
|
10 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
+
"Content-Transfer-Encoding: 8bit\n"
|
12 |
+
"Language: en_GB\n"
|
13 |
+
"X-Generator: Poedit 1.8.5\n"
|
14 |
+
"X-Poedit-SourceCharset: UTF-8\n"
|
15 |
+
|
16 |
+
msgid "Cloudways WP Cache"
|
17 |
+
msgstr "1"
|
18 |
+
|
19 |
+
msgid "Cloudways Purge Cache"
|
20 |
+
msgstr ""
|
21 |
+
|
22 |
+
msgid "Please set the IPs for Purge Cache!"
|
23 |
+
msgstr ""
|
24 |
+
|
25 |
+
msgid "Cloudways Varnish Purge Interval"
|
26 |
+
msgstr ""
|
27 |
+
|
28 |
+
msgid "Purge cache after"
|
29 |
+
msgstr ""
|
30 |
+
|
31 |
+
msgid "Set IPs"
|
32 |
+
msgstr ""
|
33 |
+
|
34 |
+
msgid "Save setting"
|
35 |
+
msgstr ""
|
36 |
+
|
37 |
+
msgid ""
|
38 |
+
msgstr ""
|
39 |
+
|
40 |
+
msgid ""
|
41 |
+
msgstr ""
|
42 |
+
|
43 |
+
msgid ""
|
44 |
+
msgstr ""
|
45 |
+
|
46 |
+
msgid ""
|
47 |
+
msgstr ""
|
48 |
+
|
49 |
+
msgid ""
|
50 |
+
msgstr ""
|
51 |
+
|
52 |
+
msgid ""
|
53 |
+
msgstr ""
|
54 |
+
|
55 |
+
msgid ""
|
56 |
+
msgstr ""
|
57 |
+
|
58 |
+
msgid ""
|
59 |
+
msgstr ""
|
60 |
+
|
61 |
+
msgid ""
|
62 |
+
msgstr ""
|
63 |
+
|
64 |
+
msgid ""
|
65 |
+
msgstr ""
|
66 |
+
|
67 |
+
msgid ""
|
68 |
+
msgstr ""
|
69 |
+
|
70 |
+
msgid ""
|
71 |
+
msgstr ""
|
72 |
+
|
73 |
+
msgid ""
|
74 |
+
msgstr ""
|
75 |
+
|
76 |
+
msgid ""
|
77 |
+
msgstr ""
|
78 |
+
|
79 |
+
msgid ""
|
80 |
+
msgstr ""
|
81 |
+
|
82 |
+
msgid ""
|
83 |
+
msgstr ""
|
84 |
+
|
85 |
+
msgid ""
|
86 |
+
msgstr ""
|
87 |
+
|
88 |
+
msgid ""
|
89 |
+
msgstr ""
|
90 |
+
|
91 |
+
msgid ""
|
92 |
+
msgstr ""
|
93 |
+
|
94 |
+
msgid ""
|
95 |
+
msgstr ""
|
96 |
+
|
97 |
+
msgid ""
|
98 |
+
msgstr ""
|
99 |
+
|
100 |
+
msgid ""
|
101 |
+
msgstr ""
|
102 |
+
|
103 |
+
msgid ""
|
104 |
+
msgstr ""
|
105 |
+
|
106 |
+
msgid ""
|
107 |
+
msgstr ""
|
108 |
+
|
109 |
+
msgid ""
|
110 |
+
msgstr ""
|
111 |
+
|
readme.txt
ADDED
@@ -0,0 +1,132 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Breeze - WordPress Cache Plugin ===
|
2 |
+
Contributors: Cloudways
|
3 |
+
Tags: cache, caching, performance, wp-cache, cdn, combine, compress, speed plugin, database cache,gzip, http compression, js cache, minify, optimize, page cache, performance, speed, expire headers
|
4 |
+
Requires at least: 4.5
|
5 |
+
Tested up to: 4.8
|
6 |
+
Stable tag: 1.0.0
|
7 |
+
License: GPLv2 or later
|
8 |
+
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
+
|
10 |
+
Breeze is a WordPress Caching Plugin developed by Cloudways. Breeze uses advance caching systems to improve WordPress loading times exponentially.
|
11 |
+
|
12 |
+
== Description ==
|
13 |
+
|
14 |
+
Breeze is a free, simple (yet powerful) and user-friendly WordPress Caching Plugin developed by the Cloudways team. It offers various options to optimize WordPress performance at various levels. It works equally great with WordPress, WordPress with WooCommerce and WordPress Multisite.
|
15 |
+
|
16 |
+
Breeze excels in the following areas:
|
17 |
+
|
18 |
+
* **Performance:** Breeze improves website speed and resource optimization. Other features include file level cache system, database cleanup, minification, support for Varnish cache and simplified CDN integration options.
|
19 |
+
|
20 |
+
* **Convenience:** Breeze is easy to install and configure directly from WordPress. Configuring Breeze is easy and most of the default options work well right out of the box. The recommended settings should work on all your WordPress websites seamlessly.
|
21 |
+
|
22 |
+
* **Simplicity:** Breeze is designed to be simple for all users. Just install and activate the plugin and you'll see the results instantaneously.
|
23 |
+
|
24 |
+
What makes Breeze WordPress Cache Plugin awesome is that it comes with builtin support for Varnish. If Varnish is not installed on your servers, Breeze will utilize its internal cache mechanism to boost up your WordPress site performance.
|
25 |
+
|
26 |
+
**Support:** We love to provide support! Post your questions on the WordPress.org support forums, or if you are a Cloudways Customer you may ask questions on the <a href="https://community.cloudways.com/">Cloudways Community Forum</a>.
|
27 |
+
|
28 |
+
**Note:** This plugin is still in Beta phase and this plugin is tested on Cloudways WordPress hosting servers.
|
29 |
+
|
30 |
+
|
31 |
+
|
32 |
+
== Installation ==
|
33 |
+
|
34 |
+
= To install the plugin via WordPress Dashboard: =
|
35 |
+
* In the WordPress admin panel, navigate to Plugin > Add new
|
36 |
+
* Search for Breeze
|
37 |
+
* Click install and wait for the installation to finish. Next, click the activate link
|
38 |
+
|
39 |
+
= To install the plugin manually: =
|
40 |
+
* Download and unzip the plugin package - breeze.1.0.0.zip
|
41 |
+
* Upload the breeze to /wp-content/plugins/
|
42 |
+
* Activate the plugin through the 'Plugins' menu in WordPress
|
43 |
+
* Access Breeze from WordPress Admin > Settings > Breeze
|
44 |
+
|
45 |
+
== Frequently Asked Questions ==
|
46 |
+
|
47 |
+
= Installation Instructions
|
48 |
+
|
49 |
+
To install the plugin via WordPress Dashboard
|
50 |
+
1. In the WordPress admin panel, Menu > Plugin > Add new
|
51 |
+
2. Search for Breeze
|
52 |
+
3. Click on install and wait for the installation to finish. Next, then click on the activate link
|
53 |
+
|
54 |
+
To install the plugin manually
|
55 |
+
1. Download and unzip the plugin package - breeze.1.0.0.zip
|
56 |
+
2. Upload the /breeze to /wp-content/plugins/
|
57 |
+
3. Activate the plugin through the 'Plugins' menu in WordPress
|
58 |
+
4. Access Breeze from WordPress Admin > Settings > Breeze
|
59 |
+
|
60 |
+
= Does Breeze support Varnish and to what extent? =
|
61 |
+
|
62 |
+
Breeze, by default, supports Varnish. It has been tested to be fully compatible with Cloudways Servers that come with Varnish pre-installed. If you are using hosting providers other than Cloudways, we suggest you confirm Varnish support with your hosting provider
|
63 |
+
|
64 |
+
= Does Breeze support WooCommerce? =
|
65 |
+
|
66 |
+
Breeze is fully compatible with WooCommerce, out of the box. It does not require any special configurations.
|
67 |
+
|
68 |
+
= Does Breeze support WordPress Multisite? =
|
69 |
+
|
70 |
+
Breeze is fully compatible with WordPress Multisite without the need for any extra configuration.
|
71 |
+
|
72 |
+
= Is Breeze compatible with other WordPress Cache plugins? =
|
73 |
+
|
74 |
+
We DO NOT recommend using two WordPress cache plugins at the same time on any WordPress website.
|
75 |
+
We strongly recommend that you use Breeze as the only cache plugin for your website. If there are any other cache plugins installed, please ensure that you have disabled them prior to proceeding with the Breeze installation.
|
76 |
+
|
77 |
+
|
78 |
+
= Is Breeze compatible with HTTPS? =
|
79 |
+
|
80 |
+
Breeze does not require any special configuration to work with HTTP or HTTPS pages.
|
81 |
+
|
82 |
+
= Does Breeze have compatibility issues with other known plugins? =
|
83 |
+
|
84 |
+
Breeze has been tested with popular plugins available on WordPress.org. Please feel free to report any incompatibilities on the WordPress Support Forums or on <a href="https://community.cloudways.com/">Cloudways Community Forum</a>.
|
85 |
+
|
86 |
+
= Does Breeze support CDN? =
|
87 |
+
|
88 |
+
Breeze supports CDN integration. It allows all static assets (such as images, CSS and JS files) to be served via CDN.
|
89 |
+
|
90 |
+
= What does Breeze's Database Optimization feature do? =
|
91 |
+
|
92 |
+
WordPress databases are notorious for storing information like post revisions, spam comments and much more. Over time, databases l become bloated and it is a good practice to clear out unwanted information to reduce database size and improve optimization.
|
93 |
+
|
94 |
+
Breeze's database optimization cleans out unwanted information in a single click.
|
95 |
+
|
96 |
+
= Will comments and other dynamic parts of my blog appear immediately? =
|
97 |
+
|
98 |
+
Comments will appear upon moderation as per the comment system (or policy) set in place by the blog owner. Other dynamic changes such as any modifications in files will require a full cache purge.
|
99 |
+
|
100 |
+
= Can I exclude URLs of individual files and pages from cache? =
|
101 |
+
|
102 |
+
You can exclude a file by mentioning its URL or file type (by mentioning file extension) in the exclude fields (available in the Breeze settings). Exclude will not let the cache impact that URL or file type.
|
103 |
+
|
104 |
+
If Varnish is active, you will need to exclude URLs and file type(s) in the Varnish configuration. If you are hosting WordPress websites on Cloudways servers, follow <a href="https://support.cloudways.com/how-to-exclude-url-from-varnish/">this KB to exclude URLs from the Varnish cache</a>.
|
105 |
+
|
106 |
+
|
107 |
+
= Does it work with all hosting providers? =
|
108 |
+
|
109 |
+
Breeze is in Beta phase and has not yet been tested on hosting providers other than Cloudways.
|
110 |
+
However, major Breeze options such as Gzip, browser cache, minification, grouping, database optimization. CDN integration will work as expected on other hosting providers.
|
111 |
+
|
112 |
+
|
113 |
+
= Where can I get support for Breeze? =
|
114 |
+
|
115 |
+
You can get your questions answered on the WordPress support forums. If you are a Cloudways customer, please feel free to start a discussion at <a href="https://community.cloudways.com/">Cloudways Community Forum</a>.
|
116 |
+
|
117 |
+
== Changelog ==
|
118 |
+
|
119 |
+
= 1.0.0 =
|
120 |
+
* Add : First Beta release
|
121 |
+
|
122 |
+
|
123 |
+
== Upgrade Notice ==
|
124 |
+
|
125 |
+
Update Breeze through WordPress Admin > Dashboard >Updates. The settings will remain intact after the update.
|
126 |
+
|
127 |
+
== Screenshots ==
|
128 |
+
|
129 |
+
|
130 |
+
== Requirements ==
|
131 |
+
|
132 |
+
PHP 5.3+, PHP7 or 7.1 recommended for better performance, WordPress 4.5+
|
views/breeze-setting-views.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$tabs = array(
|
3 |
+
'basic' => __('Basic options', 'breeze'),
|
4 |
+
'advanced' => __('Advanced options', 'breeze'),
|
5 |
+
'database' => __('Database', 'breeze'),
|
6 |
+
'cdn' => __('CDN', 'breeze'),
|
7 |
+
'varnish' => __('Varnish', 'breeze'),
|
8 |
+
);
|
9 |
+
?>
|
10 |
+
<?php if (isset($_REQUEST['database-cleanup']) && $_REQUEST['database-cleanup'] == 'success'): ?>
|
11 |
+
<div id="message-save-settings" class="notice notice-success" style="margin: 10px 0px 10px 0;padding: 10px;"><strong><?php _e('Database cleanup successful', 'breeze'); ?></strong></div>
|
12 |
+
<?php endif; ?>
|
13 |
+
<!--save settings successfull message-->
|
14 |
+
<?php if (isset($_REQUEST['save-settings']) && $_REQUEST['save-settings'] == 'success'): ?>
|
15 |
+
<div id="message-save-settings" class="notice notice-success" style="margin: 10px 0px 10px 0;padding: 10px;"><strong><?php _e('Configuration settings saved', 'breeze'); ?></strong></div>
|
16 |
+
<?php endif; ?>
|
17 |
+
<div class="wrap breeze-main">
|
18 |
+
<div class="breeze-header" style="display: none"><a href="https://www.cloudways.com" target="_blank">
|
19 |
+
<div class="breeze-logo"></div>
|
20 |
+
<label class="breeze-logo-title"><?php _e('CLOUDWAYS', 'breeze'); ?></label>
|
21 |
+
</a>
|
22 |
+
</div>
|
23 |
+
<div style="clear: both"></div>
|
24 |
+
<h1 style="padding: 0;font-size: 30px"><?php _e("Breeze - WordPress Cache Settings", 'breeze'); ?></h1>
|
25 |
+
|
26 |
+
<ul id="breeze-tabs" class="nav-tab-wrapper">
|
27 |
+
<?php
|
28 |
+
foreach ($tabs as $key => $name) {
|
29 |
+
echo '<a id="tab-' . $key . '" class="nav-tab" href="#tab-' . $key . '" data-tab-id="' . $key . '"> ' . $name . ' </a> ';
|
30 |
+
}
|
31 |
+
?>
|
32 |
+
</ul>
|
33 |
+
|
34 |
+
<div id="breeze-tabs-content" class="tab-content">
|
35 |
+
<?php
|
36 |
+
foreach ($tabs as $key => $name) {
|
37 |
+
echo '<div id="tab-content-' . $key . '" class="tab-pane">';
|
38 |
+
echo '<form class="breeze-form" method="post" action="">';
|
39 |
+
echo '<div class="tab-child">';
|
40 |
+
echo '<input type="hidden" name="breeze_'.$key.'_action" value="breeze_'.$key.'_settings">';
|
41 |
+
wp_nonce_field('breeze_settings_' . $key, 'breeze_settings_' . $key . '_nonce');
|
42 |
+
Breeze_Admin::render($key);
|
43 |
+
echo '</div>';
|
44 |
+
if ($key == 'database'){
|
45 |
+
echo '<p class="submit">
|
46 |
+
<input type="submit" class="button button-primary" value="Optimize"/>
|
47 |
+
</p>';
|
48 |
+
}else{
|
49 |
+
echo '<p class="submit">
|
50 |
+
<input type="submit" class="button button-primary" value="Save Changes"/>
|
51 |
+
</p>';
|
52 |
+
}
|
53 |
+
echo '</form>';
|
54 |
+
echo '</div>';
|
55 |
+
|
56 |
+
}
|
57 |
+
?>
|
58 |
+
</div>
|
59 |
+
</div>
|
views/tabs/advanced.php
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$advanced = get_option('breeze_advanced_settings');
|
3 |
+
?>
|
4 |
+
<table cellspacing="15">
|
5 |
+
<tr>
|
6 |
+
<td>
|
7 |
+
<label for="exclude-urls" class="breeze_tool_tip"><?php _e('Never Cache these URLs', 'breeze'); ?></label>
|
8 |
+
</td>
|
9 |
+
<td>
|
10 |
+
<textarea cols="100" rows="7" id="exclude-urls"
|
11 |
+
name="exclude-urls"><?php if (!empty($advanced['breeze-exclude-urls'])) {
|
12 |
+
$output = implode("\n", $advanced['breeze-exclude-urls']);
|
13 |
+
echo esc_textarea($output);
|
14 |
+
} ?></textarea>
|
15 |
+
<br>
|
16 |
+
<label class="breeze_tool_tip"><b>Note: </b><?php _e('Add URLs per line of pages that you want to exclude from the WordPress internal cache. To exclude URLs from Varnish cache, please refer to ', 'breeze') ?><a href="https://support.cloudways.com/how-to-exclude-url-from-varnish/" target="_blank"><?php _e('this KB','breeze')?></a></a> </label>
|
17 |
+
</td>
|
18 |
+
</tr>
|
19 |
+
<tr>
|
20 |
+
<td>
|
21 |
+
<label class="breeze_tool_tip"><?php _e('Group Files', 'breeze'); ?></label>
|
22 |
+
</td>
|
23 |
+
<td>
|
24 |
+
<ul>
|
25 |
+
<li>
|
26 |
+
<input type="checkbox" name="group-css" value="1" <?php checked($advanced['breeze-group-css'],'1')?>/>
|
27 |
+
<label class="breeze_tool_tip"><?php _e('CSS','breeze')?></label>
|
28 |
+
</li>
|
29 |
+
<li>
|
30 |
+
<input type="checkbox" name="group-js" value="1" <?php checked($advanced['breeze-group-js'],'1')?>/>
|
31 |
+
<label class="breeze_tool_tip"><?php _e('JS','breeze')?></label>
|
32 |
+
</li>
|
33 |
+
<li>
|
34 |
+
<label class="breeze_tool_tip">
|
35 |
+
<b>Note: </b><?php _e('Group CSS, JS files to combine them into single file. This will reduce the number of HTTP requests to your server.', 'breeze') ?><br>
|
36 |
+
<b><?php _e('Enable Minification to be able to use Group option','breeze')?></b>
|
37 |
+
</label>
|
38 |
+
</li>
|
39 |
+
</ul>
|
40 |
+
</td>
|
41 |
+
</tr>
|
42 |
+
<tr>
|
43 |
+
<td>
|
44 |
+
<label for="exclude-css" class="breeze_tool_tip"><?php _e('Exclude CSS', 'breeze') ?></label>
|
45 |
+
</td>
|
46 |
+
<td>
|
47 |
+
<textarea cols="100" rows="7" id="exclude-css"
|
48 |
+
name="exclude-css"><?php if (!empty($advanced['breeze-exclude-css'])) {
|
49 |
+
$output = implode("\n", $advanced['breeze-exclude-css']);
|
50 |
+
echo esc_textarea($output);
|
51 |
+
} ?></textarea>
|
52 |
+
<br>
|
53 |
+
<label class="breeze_tool_tip"><b>Note: </b><?php _e('Use this option to exclude CSS files from Minification and Grouping. Enter the URLs of CSS files on each line.', 'breeze') ?></label>
|
54 |
+
</td>
|
55 |
+
</tr>
|
56 |
+
<tr>
|
57 |
+
<td>
|
58 |
+
<label for="exclude-js" class="breeze_tool_tip"><?php _e('Exclude JS', 'breeze') ?></label>
|
59 |
+
</td>
|
60 |
+
<td>
|
61 |
+
<textarea cols="100" rows="7" id="exclude-js"
|
62 |
+
name="exclude-js"><?php if (!empty($advanced['breeze-exclude-js'])) {
|
63 |
+
$output = implode("\n", $advanced['breeze-exclude-js']);
|
64 |
+
echo esc_textarea($output);
|
65 |
+
} ?></textarea>
|
66 |
+
<br>
|
67 |
+
<label class="breeze_tool_tip"><b>Note: </b><?php _e('Use this option to exclude JS files from Minification and Grouping. Enter the URLs of JS files on each line.', 'breeze') ?></label>
|
68 |
+
</td>
|
69 |
+
</tr>
|
70 |
+
</table>
|
views/tabs/basic.php
ADDED
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$basic = get_option('breeze_basic_settings');
|
3 |
+
?>
|
4 |
+
<table cellspacing="15">
|
5 |
+
<tr>
|
6 |
+
<td>
|
7 |
+
<label for="cache-system"><?php _e('Cache System', 'breeze'); ?></label>
|
8 |
+
</td>
|
9 |
+
<td>
|
10 |
+
<input type="checkbox" id="cache-system" name="cache-system"
|
11 |
+
value='1' <?php checked($basic['breeze-active'], '1') ?>/>
|
12 |
+
<label class="breeze_tool_tip">
|
13 |
+
<?php _e('This is the basic cache that we recommend should be kept enabled in all cases. Basic cache will build the internal and static caches for the WordPress websites.', 'breeze') ?>
|
14 |
+
</label>
|
15 |
+
</td>
|
16 |
+
</tr>
|
17 |
+
<tr>
|
18 |
+
<td>
|
19 |
+
<label for="cache-ttl"><?php _e('Purge cache after', 'breeze'); ?></label>
|
20 |
+
</td>
|
21 |
+
<td>
|
22 |
+
<input type="text" id="cache-ttl" size="5" name="cache-ttl"
|
23 |
+
value='<?php echo(!empty($basic['breeze-ttl']) ? (int)$basic['breeze-ttl'] : '1440'); ?>'/>
|
24 |
+
<label class="breeze_tool_tip" style="vertical-align: baseline">
|
25 |
+
<?php _e('Automatically purge internal cache after X minutes. By default this is set to 1440 minutes', 'breeze') ?>
|
26 |
+
</label>
|
27 |
+
</td>
|
28 |
+
</tr>
|
29 |
+
<tr>
|
30 |
+
<td>
|
31 |
+
<label class="breeze_tool_tip"><?php _e('Minification', 'breeze'); ?></label>
|
32 |
+
</td>
|
33 |
+
<td>
|
34 |
+
<ul>
|
35 |
+
<li>
|
36 |
+
<input type="checkbox" name="minification-html"
|
37 |
+
value="1" <?php checked($basic['breeze-minify-html'], '1') ?>/>
|
38 |
+
<label class="breeze_tool_tip"><?php _e('HTML', 'breeze') ?></label>
|
39 |
+
</li>
|
40 |
+
<li>
|
41 |
+
<input type="checkbox" name="minification-css"
|
42 |
+
value="1" <?php checked($basic['breeze-minify-css'], '1') ?>/>
|
43 |
+
<label class="breeze_tool_tip"><?php _e('CSS', 'breeze') ?></label>
|
44 |
+
</li>
|
45 |
+
<li>
|
46 |
+
<input type="checkbox" name="minification-js"
|
47 |
+
value="1" <?php checked($basic['breeze-minify-js'], '1') ?>/>
|
48 |
+
<label class="breeze_tool_tip"><?php _e('JS', 'breeze') ?></label>
|
49 |
+
</li>
|
50 |
+
<li>
|
51 |
+
<label><?php _e('Use the above options to minify HTML, CSS, or JS files.', 'breeze') ?></label>
|
52 |
+
<br>
|
53 |
+
<label><b>Note: </b>
|
54 |
+
<span style="color: #ff0000"><?php _e('We recommend testing minification on a staging website before deploying it on a live website. Minification is known to cause issues on the frontend.', 'breeze') ?></span>
|
55 |
+
</label>
|
56 |
+
</li>
|
57 |
+
</ul>
|
58 |
+
|
59 |
+
</td>
|
60 |
+
</tr>
|
61 |
+
<tr>
|
62 |
+
<td>
|
63 |
+
<label for="gzip-compression"><?php _e('Gzip Compression', 'breeze') ?></label>
|
64 |
+
</td>
|
65 |
+
<td>
|
66 |
+
<input type="checkbox" id="gzip-compression" name="gzip-compression"
|
67 |
+
value='1' <?php checked($basic['breeze-gzip-compression'], '1') ?>/>
|
68 |
+
<label class="breeze_tool_tip"><?php _e('Enable this to compress your files making HTTP requests fewer and faster.', 'breeze') ?></label>
|
69 |
+
</td>
|
70 |
+
</tr>
|
71 |
+
<tr>
|
72 |
+
<td style="vertical-align: middle">
|
73 |
+
<label for="browser-cache"><?php _e('Browser Cache', 'breeze') ?></label>
|
74 |
+
</td>
|
75 |
+
<td>
|
76 |
+
<input type="checkbox" id="browser-cache" name="browser-cache"
|
77 |
+
value='1' <?php checked($basic['breeze-browser-cache'], '1') ?>/>
|
78 |
+
<label class="breeze_tool_tip"><?php _e('Enable this to add expires headers to static files. This will ask browsers to either request a file from server or fetch from the browser’s cache.', 'breeze') ?></label>
|
79 |
+
</td>
|
80 |
+
</tr>
|
81 |
+
|
82 |
+
<tr style="display: none;">
|
83 |
+
<td style="vertical-align: middle">
|
84 |
+
<label for="desktop-cache" class="breeze_tool_tip"> <?php _e('Desktop Cache', 'breeze') ?></label>
|
85 |
+
</td>
|
86 |
+
<td>
|
87 |
+
<select id="desktop-cache" name="desktop-cache">
|
88 |
+
<option value="1" <?php echo ($basic['breeze-desktop-cache'] == '1') ? 'selected="selected"' : '' ?>><?php _e('Activated', 'breeze') ?></option>
|
89 |
+
<option value="2" <?php echo ($basic['breeze-desktop-cache'] == '2') ? 'selected="selected"' : '' ?>><?php _e('No cache for desktop', 'breeze') ?></option>
|
90 |
+
</select>
|
91 |
+
</td>
|
92 |
+
</tr>
|
93 |
+
|
94 |
+
<tr style="display: none;">
|
95 |
+
<td style="vertical-align: middle">
|
96 |
+
<label for="mobile-cache" class="breeze_tool_tip"> <?php _e('Mobile Cache', 'breeze') ?></label>
|
97 |
+
</td>
|
98 |
+
<td>
|
99 |
+
<select id="mobile-cache" name="mobile-cache">
|
100 |
+
<option value="1" <?php echo ($basic['breeze-mobile-cache'] == '1') ? 'selected="selected"' : '' ?>><?php _e('Automatic (same as desktop)', 'breeze') ?></option>
|
101 |
+
<option value="2" <?php echo ($basic['breeze-mobile-cache'] == '2') ? 'selected="selected"' : '' ?>><?php _e('Specific mobile cache', 'breeze') ?></option>
|
102 |
+
<option value="3" <?php echo ($basic['breeze-mobile-cache'] == '3') ? 'selected="selected"' : '' ?>><?php _e('No cache for mobile', 'breeze') ?></option>
|
103 |
+
</select>
|
104 |
+
</td>
|
105 |
+
</tr>
|
106 |
+
</table>
|
views/tabs/cdn.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$cdn_integration = get_option('breeze_cdn_integration');
|
3 |
+
|
4 |
+
$cdn_content_value = '';
|
5 |
+
$cdn_exclude_content_value = '';
|
6 |
+
if(!empty($cdn_integration['cdn-content'])){
|
7 |
+
$cdn_content_value = implode(',',$cdn_integration['cdn-content']);
|
8 |
+
}
|
9 |
+
if(!empty($cdn_integration['cdn-exclude-content'])){
|
10 |
+
$cdn_exclude_content_value = implode(',',$cdn_integration['cdn-exclude-content']);
|
11 |
+
}
|
12 |
+
?>
|
13 |
+
<table cellspacing="15">
|
14 |
+
<tr>
|
15 |
+
<td>
|
16 |
+
<label for="activate-cdn" class="breeze_tool_tip"><?php _e('Activate CDN', 'breeze')?></label>
|
17 |
+
</td>
|
18 |
+
<td>
|
19 |
+
<input type="checkbox" id="activate-cdn" name="activate-cdn" value="1" <?php checked($cdn_integration['cdn-active'],'1')?>/>
|
20 |
+
<label class="breeze_tool_tip"><?php _e('Enable to make CDN effective on your website.', 'breeze')?></label>
|
21 |
+
</td>
|
22 |
+
</tr>
|
23 |
+
<tr>
|
24 |
+
<td>
|
25 |
+
<label for="cdn-url" class="breeze_tool_tip"><?php _e('CDN Root URL', 'breeze')?></label>
|
26 |
+
</td>
|
27 |
+
<td>
|
28 |
+
<input type="text" id="cdn-url" name="cdn-url" size="50" placeholder="<?php _e('https://www.domain.com','breeze')?>" value="<?php echo (($cdn_integration['cdn-url'])?esc_html($cdn_integration['cdn-url']):''); ?>"/>
|
29 |
+
<label style="vertical-align: baseline" class="breeze_tool_tip"><?php _e('Enter the URL of CDN.', 'breeze')?></label>
|
30 |
+
<br>
|
31 |
+
<label class="breeze_tool_tip"><b>Note: </b><?php _e('Use double slash ‘//’ at the start or url, if you have some pages on HTTP and some are on HTTPS.', 'breeze') ?></label>
|
32 |
+
</td>
|
33 |
+
</tr>
|
34 |
+
<tr>
|
35 |
+
<td>
|
36 |
+
<label for="cdn-content" class="breeze_tool_tip" ><?php _e('CDN Content', 'breeze')?></label>
|
37 |
+
</td>
|
38 |
+
<td>
|
39 |
+
<input type="text" id="cdn-content" name="cdn-content" size="50" value="<?php echo (($cdn_content_value)?esc_html($cdn_content_value):''); ?>"/>
|
40 |
+
<br>
|
41 |
+
<label class="breeze_tool_tip"><b>Note: </b><?php _e('Enter the directories (comma separated) of which you want the CDN to serve the content.', 'breeze') ?></label>
|
42 |
+
</td>
|
43 |
+
</tr>
|
44 |
+
<tr>
|
45 |
+
<td>
|
46 |
+
<label for="cdn-exclude-content" class="breeze_tool_tip" ><?php _e('Exclude Content', 'breeze')?></label>
|
47 |
+
</td>
|
48 |
+
<td>
|
49 |
+
<input type="text" id="cdn-exclude-content" name="cdn-exclude-content" size="50" value="<?php echo (($cdn_exclude_content_value)?esc_html($cdn_exclude_content_value):''); ?>" />
|
50 |
+
<br>
|
51 |
+
<label class="breeze_tool_tip"><b>Note: </b><?php _e('Exclude file types or directories from CDN. Example, enter .css to exclude the CSS files.', 'breeze') ?></label>
|
52 |
+
</td>
|
53 |
+
</tr>
|
54 |
+
<tr>
|
55 |
+
<td>
|
56 |
+
<label for="cdn-relative-path" class="breeze_tool_tip" ><?php _e('Relative path', 'breeze')?></label>
|
57 |
+
</td>
|
58 |
+
<td>
|
59 |
+
<input type="checkbox" id="cdn-relative-path" name="cdn-relative-path" value="1" <?php checked($cdn_integration['cdn-relative-path'], '1')?>/>
|
60 |
+
<label class="breeze_tool_tip"><?php _e('Keep this option enabled. Use this option to enable relative path for your CDN on your WordPress site.', 'breeze')?></label>
|
61 |
+
</td>
|
62 |
+
</tr>
|
63 |
+
</table>
|
views/tabs/database.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="breeze-top-notice">
|
2 |
+
<label class="breeze_tool_tip"><?php _e('It is recommended to backup your Database before using the following options.','breeze')?></label>
|
3 |
+
</div>
|
4 |
+
<table cellspacing="15">
|
5 |
+
<tr>
|
6 |
+
<td>
|
7 |
+
<label for="data0" class="breeze_tool_tip"><?php _e('Select all','breeze')?></label>
|
8 |
+
</td>
|
9 |
+
<td>
|
10 |
+
<input type="checkbox" id="data0" name="all_control" value="all_data"/>
|
11 |
+
<label class="breeze_tool_tip"><?php _e('Select all following options. Click Optimize to perform actions.','breeze')?></label>
|
12 |
+
</td>
|
13 |
+
</tr>
|
14 |
+
<tr>
|
15 |
+
<td>
|
16 |
+
<label for="data1" class="breeze_tool_tip"><?php _e('Post revisions','breeze')?><?php echo " (".(int)Breeze_Configuration::getElementToClean('revisions').")"; ?></label>
|
17 |
+
</td>
|
18 |
+
<td>
|
19 |
+
<input type="checkbox" id="data1" name="clean[]" class="clean-data" value="revisions"/>
|
20 |
+
<label class="breeze_tool_tip"><?php _e('Use this option to clear out post revisions from your WordPress database.','breeze')?></label>
|
21 |
+
</td>
|
22 |
+
</tr>
|
23 |
+
<tr>
|
24 |
+
<td>
|
25 |
+
<label for="data2" class="breeze_tool_tip" ><?php _e('Auto drafted content','breeze')?><?php echo " (".(int)Breeze_Configuration::getElementToClean('drafted').")"; ?></label>
|
26 |
+
</td>
|
27 |
+
<td>
|
28 |
+
<input type="checkbox" id="data2" name="clean[]" class="clean-data" value="drafted"/>
|
29 |
+
<label class="breeze_tool_tip"><?php _e('Use this option to delete the auto saved drafts from WordPress database.','breeze')?></label>
|
30 |
+
</td>
|
31 |
+
</tr>
|
32 |
+
<tr>
|
33 |
+
<td>
|
34 |
+
<label for="data3" class="breeze_tool_tip" ><?php _e('All trashed content','breeze')?><?php echo " (".(int)Breeze_Configuration::getElementToClean('trash').")"; ?></label>
|
35 |
+
</td>
|
36 |
+
<td>
|
37 |
+
<input type="checkbox" id="data3" name="clean[]" class="clean-data" value="trash"/>
|
38 |
+
<label class="breeze_tool_tip"><?php _e('Use this option to delete the trashed content from WordPress database.','breeze')?></label>
|
39 |
+
|
40 |
+
</td>
|
41 |
+
</tr>
|
42 |
+
<tr>
|
43 |
+
<td>
|
44 |
+
<label for="data4" class="breeze_tool_tip" ><?php _e('Comments from trash & spam','breeze')?><?php echo " (".(int)Breeze_Configuration::getElementToClean('comments').")"; ?></label>
|
45 |
+
</td>
|
46 |
+
<td>
|
47 |
+
<input type="checkbox" id="data4" name="clean[]" class="clean-data" value="comments"/>
|
48 |
+
<label class="breeze_tool_tip"><?php _e('Use this option to cleanup trash and spam comments from WordPress database.','breeze')?></label>
|
49 |
+
</td>
|
50 |
+
</tr>
|
51 |
+
<tr>
|
52 |
+
<td>
|
53 |
+
<label for="data5" class="breeze_tool_tip" ><?php _e('Trackbacks and pingbacks','breeze')?><?php echo " (".(int)Breeze_Configuration::getElementToClean('trackbacks').")"; ?></label>
|
54 |
+
</td>
|
55 |
+
<td>
|
56 |
+
<input type="checkbox" id="data5" name="clean[]" class="clean-data" value="trackbacks"/>
|
57 |
+
<label class="breeze_tool_tip"><?php _e('Cleanup Transients and Pingbacks from the WordPress database.','breeze')?></label>
|
58 |
+
</td>
|
59 |
+
</tr>
|
60 |
+
<tr>
|
61 |
+
<td>
|
62 |
+
<label for="data6" class="breeze_tool_tip" ><?php _e('Transient options','breeze')?><?php echo " (".(int)Breeze_Configuration::getElementToClean('transient').")"; ?></label>
|
63 |
+
</td>
|
64 |
+
<td>
|
65 |
+
<input type="checkbox" id="data6" name="clean[]" class="clean-data" value="transient"/>
|
66 |
+
<label class="breeze_tool_tip"><?php _e('Cleanup expired and active Transients from WordPress.','breeze')?></label>
|
67 |
+
</td>
|
68 |
+
</tr>
|
69 |
+
</table>
|
views/tabs/varnish.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
$varnish = get_option('breeze_varnish_cache');
|
3 |
+
$check_varnish = Breeze_Admin::check_varnish();
|
4 |
+
?>
|
5 |
+
<div class="breeze-top-notice">
|
6 |
+
<label class="breeze_tool_tip"><?php _e('By default Varnish is enabled on all WordPress websites hosted on Cloudways.','breeze')?></label>
|
7 |
+
</div>
|
8 |
+
<table cellspacing="15">
|
9 |
+
<tr>
|
10 |
+
<td>
|
11 |
+
<label for="auto-purge-varnish" class="breeze_tool_tip"><?php _e('Auto Purge Varnish', 'breeze'); ?></label>
|
12 |
+
</td>
|
13 |
+
<td>
|
14 |
+
<input type="checkbox" id="auto-purge-varnish" name="auto-purge-varnish" value="1" <?php checked($varnish['auto-purge-varnish'], '1')?>/>
|
15 |
+
<label class="breeze_tool_tip" ><?php _e('Keep this option enabled to automatically purge Varnish cache on actions like publishing new blog posts, pages and comments.','breeze')?></label>
|
16 |
+
<br>
|
17 |
+
<?php if( !$check_varnish): ?>
|
18 |
+
<label><b>Note: </b>
|
19 |
+
<span style="color: #ff0000"><?php _e('Seems Varnish is disabled on your Application. Please refer to ', 'breeze') ?><a href="https://support.cloudways.com/most-common-varnish-issues-and-queries/" target="_blank">this KB</a><?php _e(' and learn how to enable it.','breeze') ?> </span>
|
20 |
+
</label>
|
21 |
+
<?php endif; ?>
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
<tr>
|
25 |
+
<td>
|
26 |
+
<label for="varnish-server-ip" class="breeze_tool_tip"><?php _e('Varnish server', 'breeze'); ?></label>
|
27 |
+
</td>
|
28 |
+
<td>
|
29 |
+
<input type="text" id="varnish-server-ip" size="20" name="varnish-server-ip"
|
30 |
+
value='<?php echo(!empty($varnish['breeze-varnish-server-ip']) ? esc_html($varnish['breeze-varnish-server-ip']) : '127.0.0.1'); ?>'/>
|
31 |
+
<br/><span class="breeze_tool_tip" ><strong><?php _e('Note: Keep this default if you are a Cloudways customer. Otherwise ask your hosting provider on what to set here.','breeze')?></strong></span>
|
32 |
+
</td>
|
33 |
+
</tr>
|
34 |
+
<tr>
|
35 |
+
<td style="vertical-align: middle">
|
36 |
+
<label class="breeze_tool_tip"><?php _e('Purge Varnish Cache', 'breeze'); ?></label>
|
37 |
+
</td>
|
38 |
+
<td>
|
39 |
+
<input type="button" id="purge-varnish-button" class="button" value="<?php _e('Purge','breeze')?>" />
|
40 |
+
<label style="vertical-align: bottom"><?php _e('Use this option to instantly Purge Varnish Cache on entire website. ', 'breeze') ?></label>
|
41 |
+
</td>
|
42 |
+
</tr>
|
43 |
+
</table>
|