PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.3
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.3
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / includes / class-wp-optimize-htaccess.php

class-wp-optimize-htaccess.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.3, at includes/class-wp-optimize-htaccess.php

337 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('WPO_VERSION')) die('No direct access allowed');
4
5 class WP_Optimize_Htaccess {
6
7 /**
8 * Full path to .htaccess file.
9 *
10 * @var string
11 */
12 private $_htaccess_file = '';
13
14 /**
15 * Structured content of .htaccess file.
16 *
17 * @var array
18 */
19 private $_file_tree = array();
20
21 /**
22 * WP_Optimize_Htaccess constructor.
23 *
24 * @param string $htaccess_file Full path to .htaccess file.
25 */
26 public function __construct($htaccess_file = '') {
27 $this->_htaccess_file = ('' != $htaccess_file) ? $htaccess_file : $this->get_home_path() . '.htaccess';
28 // read .htaccess content into $_file_tree.
29 $this->read_file();
30 }
31
32 /**
33 * Returns .htaccess filename.
34 *
35 * @return string
36 */
37 public function get_filename() {
38 return $this->_htaccess_file;
39 }
40
41 /**
42 * Checks if .htaccess file exists.
43 *
44 * @return bool
45 */
46 public function is_exists() {
47 return is_file($this->_htaccess_file);
48 }
49
50 /**
51 * Checks if .htaccess file is readaable.
52 *
53 * @return bool
54 */
55 public function is_readable() {
56 return is_readable($this->_htaccess_file);
57 }
58
59 /**
60 * Checks if .htaccess file is writable.
61 *
62 * @return bool
63 */
64 public function is_writable() {
65 return is_writable($this->_htaccess_file);
66 }
67
68 /**
69 * Read content of .htaccess file and store it as a tree in $_file_tree variable.
70 * For ex.
71 * [0] => '# BEGIN WordPress',
72 * [1] => [
73 * [0] => '<IfModule mod_rewrite.c>',
74 * [1] => 'RewriteEngine On',
75 * [2] => 'RewriteBase /',
76 * [3] => 'RewriteRule ^index\.php$ - [L]',
77 * [4] => 'RewriteCond %{REQUEST_FILENAME} !-f',
78 * [5] => 'RewriteCond %{REQUEST_FILENAME} !-d',
79 * [6] => 'RewriteRule . /index.php [L]',
80 * [7] => '</IfModule>',
81 * [2] => '# END WordPress'
82 *
83 * @return void
84 */
85 public function read_file() {
86 if (false == $this->is_exists() || false == $this->is_readable()) return;
87
88 $content = file_get_contents($this->_htaccess_file);
89
90 $content = explode("\n", $content);
91
92 $content_tree = array();
93
94 $section = array();
95 $sections = array();
96
97 foreach ($content as $line) {
98 $line = trim($line);
99
100 if (preg_match("/^\<\/(.+)(\s.*)?\>/", $line, $matches)) {
101 $section[] = $line;
102
103 // close section
104 if (!empty($sections)) {
105 $_section = $section;
106 $section = array_pop($sections);
107 $section[] = $_section;
108 } else {
109 $content_tree[] = $section;
110 $section = array();
111 }
112 } elseif (preg_match('/^\<(.+)>/', $line, $matches)) {
113 // open section
114 if (!empty($section)) {
115 $sections[] = $section;
116 }
117
118 $section = array();
119 $section[] = $line;
120 } elseif (!empty($section)) {
121 $section[] = $line;
122 } else {
123 $content_tree[] = $line;
124 }
125 }
126
127 $this->_file_tree = $content_tree;
128 }
129
130 /**
131 * Write current $_file_tree content into .htaccess file.
132 */
133 public function write_file() {
134 $content = implode(PHP_EOL, $this->get_flat_array($this->_file_tree));
135 file_put_contents($this->_htaccess_file, $content);
136 }
137
138 /**
139 * Recursive function used to prepare data for output - build flat array from $_file_tree.
140 *
141 * @param array $array
142 * @param string $prefix
143 *
144 * @return array
145 */
146 public function get_flat_array($array, $prefix = '') {
147 $flat_array = array();
148
149 if (!empty($array)) {
150 foreach ($array as $item) {
151 if (is_array($item)) {
152 $item = $this->get_flat_array($item, "\t");
153 $flat_array = array_merge($flat_array, $item);
154 } else {
155 $flat_array[] = $item;
156 }
157 }
158 }
159
160 reset($flat_array);
161 $first = key($flat_array);
162 end($flat_array);
163 $last = key($flat_array);
164
165 foreach ($flat_array as $key => $value) {
166 if ('' != $value && '#' == $value[0]) {
167 // never add prefix for comment lines.
168 $flat_array[$key] = $value;
169 } else {
170 $flat_array[$key] = ($key == $first || $key == $last) ? $value : $prefix . $value;
171 }
172 }
173
174 return $flat_array;
175 }
176
177 /**
178 * Update commented section in array $_file_tree, i.e. section wrapped with comments
179 * # BEGIN WP-Optimize Browser Cache
180 * ...
181 * # END WP-Optimize Browser Cache
182 *
183 * @param array $content
184 * @param string $section
185 */
186 public function update_commented_section($content, $section = 'WP-Optimize Browser Cache') {
187 $section_begin = $this->get_section_begin_comment($section);
188 $section_end = $this->get_section_end_comment($section);
189
190 // add begin-end section comments.
191 array_unshift($content, $section_begin);
192 array_push($content, $section_end);
193
194 $section_index = $this->search_commented_section($section);
195
196 // check if section with cache settings already in the file.
197 if (false === $section_index) {
198 // no section in file then add it to the end of file.
199 $this->_file_tree = array_merge($this->_file_tree, $content);
200 } else {
201 $remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
202 array_splice($this->_file_tree, $section_index['begin'], $remove_length, $content);
203 }
204 }
205
206 /**
207 * Removes commented section in $_file_tree, i.e. section wrapped with comments
208 * # BEGIN WP-Optimize Browser Cache
209 * ...
210 * # END WP-Optimize Browser Cache
211 *
212 * @param string $comment
213 *
214 * @return bool
215 */
216 public function remove_commented_section($comment = 'WP-Optimize Browser Cache') {
217 $section_index = $this->search_commented_section($comment);
218
219 if (false === $section_index) return false;
220
221 $remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
222 array_splice($this->_file_tree, $section_index['begin'], $remove_length);
223
224 $this->_file_tree = array_values($this->_file_tree);
225
226 return true;
227 }
228
229 /**
230 * Check if section exists wrapped by comments like
231 *
232 * # BEGIN WP-Optimize Browser Cache
233 * ...
234 * # END WP-Optimize Browser Cache
235 *
236 * @param string $section
237 * @return bool
238 */
239 public function is_commented_section_exists($section = 'WP-Optimize Browser Cache') {
240 $search = $this->search_commented_section($section);
241
242 return (false === $search) ? false : true;
243 }
244
245 /**
246 * Search section in $_file_tree array wrapped by begin and end comments.
247 *
248 * @param string $section
249 * @return array|bool
250 */
251 private function search_commented_section($section) {
252 $section_begin = $this->get_section_begin_comment($section);
253 $section_end = $this->get_section_end_comment($section);
254
255 $section_begin_index = $section_end_index = false;
256
257 $section_begin_normalized = $this->normalize_string($section_begin);
258 $section_end_normalized = $this->normalize_string($section_end);
259
260 foreach ($this->_file_tree as $i => $value) {
261 // if it is subsection then we don't go in deep.
262 if (is_array($value)) continue;
263
264 $value = $this->normalize_string($value);
265
266 if ($value == $section_begin_normalized) $section_begin_index = $i;
267 if ($value == $section_end_normalized) $section_end_index = $i;
268 }
269
270 if (false == $section_begin_index) {
271 return false;
272 } else {
273 return array(
274 'begin' => $section_begin_index,
275 'end' => $section_end_index,
276 );
277 }
278 }
279
280 /**
281 * Generate begin cache section comment.
282 *
283 * @param string $section
284 * @return string
285 */
286 public function get_section_begin_comment($section = 'WP-Optimize Browser Cache') {
287 return '# BEGIN ' . $section;
288 }
289
290 /**
291 * Generate end cache section comment.
292 *
293 * @param string $section
294 * @return string
295 */
296 public function get_section_end_comment($section = 'WP-Optimize Browser Cache') {
297 return '# END ' . $section;
298 }
299
300 /**
301 * Normalize string - make all letters lowercase and remove spaces.
302 *
303 * @param string $string
304 * @return string
305 */
306 private function normalize_string($string) {
307 return strtolower(str_replace(array("\n", "\r", ' '), '', $string));
308 }
309
310 /**
311 * Get the absolute filesystem path to the root of the WordPress installation.
312 * WP_Core function from wp-admin/includes/file.php.
313 *
314 * @since 1.5.0
315 *
316 * @return string Full filesystem path to the root of the WordPress installation
317 */
318 private function get_home_path() {
319 if (function_exists('get_home_path')) {
320 return get_home_path();
321 }
322
323 $home = set_url_scheme(get_option('home'), 'http');
324 $siteurl = set_url_scheme(get_option('siteurl'), 'http');
325 if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) {
326 $wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
327 $pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home));
328 $home_path = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
329 $home_path = trailingslashit($home_path);
330 } else {
331 $home_path = ABSPATH;
332 }
333
334 return str_replace('\\', '/', $home_path);
335 }
336 }
337