PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.9
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.9
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.9, at includes/class-wp-optimize-htaccess.php

336 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 if (false === $section_index) return false;
219
220 $remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
221 array_splice($this->_file_tree, $section_index['begin'], $remove_length);
222
223 $this->_file_tree = array_values($this->_file_tree);
224
225 return true;
226 }
227
228 /**
229 * Check if section exists wrapped by comments like
230 *
231 * # BEGIN WP-Optimize Browser Cache
232 * ...
233 * # END WP-Optimize Browser Cache
234 *
235 * @param string $section
236 * @return bool
237 */
238 public function is_commented_section_exists($section = 'WP-Optimize Browser Cache') {
239 $search = $this->search_commented_section($section);
240
241 return (false === $search) ? false : true;
242 }
243
244 /**
245 * Search section in $_file_tree array wrapped by begin and end comments.
246 *
247 * @param string $section
248 * @return array|bool
249 */
250 private function search_commented_section($section) {
251 $section_begin = $this->get_section_begin_comment($section);
252 $section_end = $this->get_section_end_comment($section);
253
254 $section_begin_index = $section_end_index = false;
255
256 $section_begin_normalized = $this->normalize_string($section_begin);
257 $section_end_normalized = $this->normalize_string($section_end);
258
259 foreach ($this->_file_tree as $i => $value) {
260 // if it is subsection then we don't go in deep.
261 if (is_array($value)) continue;
262
263 $value = $this->normalize_string($value);
264
265 if ($value == $section_begin_normalized) $section_begin_index = $i;
266 if ($value == $section_end_normalized) $section_end_index = $i;
267 }
268
269 if (false == $section_begin_index) {
270 return false;
271 } else {
272 return array(
273 'begin' => $section_begin_index,
274 'end' => $section_end_index,
275 );
276 }
277 }
278
279 /**
280 * Generate begin cache section comment.
281 *
282 * @param string $section
283 * @return string
284 */
285 public function get_section_begin_comment($section = 'WP-Optimize Browser Cache') {
286 return '# BEGIN ' . $section;
287 }
288
289 /**
290 * Generate end cache section comment.
291 *
292 * @param string $section
293 * @return string
294 */
295 public function get_section_end_comment($section = 'WP-Optimize Browser Cache') {
296 return '# END ' . $section;
297 }
298
299 /**
300 * Normalize string - make all letters lowercase and remove spaces.
301 *
302 * @param string $string
303 * @return string
304 */
305 private function normalize_string($string) {
306 return strtolower(str_replace(array("\n", "\r", ' '), '', $string));
307 }
308
309 /**
310 * Get the absolute filesystem path to the root of the WordPress installation.
311 * WP_Core function from wp-admin/includes/file.php.
312 *
313 * @since 1.5.0
314 *
315 * @return string Full filesystem path to the root of the WordPress installation
316 */
317 private function get_home_path() {
318 if (function_exists('get_home_path')) {
319 return get_home_path();
320 }
321
322 $home = set_url_scheme(get_option('home'), 'http');
323 $siteurl = set_url_scheme(get_option('siteurl'), 'http');
324 if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) {
325 $wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
326 $pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home));
327 $home_path = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
328 $home_path = trailingslashit($home_path);
329 } else {
330 $home_path = ABSPATH;
331 }
332
333 return str_replace('\\', '/', $home_path);
334 }
335 }
336