PluginProbe
Squeeze – Image Optimization & Compression, WEBP Conversion / 1.7.8
Squeeze – Image Optimization & Compression, WEBP Conversion v1.7.8
1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 trunk 1.0 1.1 1.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5 1.5.1 1.5.2 1.6 All 42 releases
squeeze / inc / helpers.php

helpers.php in Squeeze – Image Optimization & Compression, WEBP Conversion 1.7.8, at inc/helpers.php

623 lines 21.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace SqueezeFree;
3
4 // Exit if accessed directly.
5 if (!defined('ABSPATH')) {
6 exit;
7 }
8
9 class SqueezeHelpers extends SqueezeInit {
10 // Cache squeeze_options array per request to avoid repeated database queries
11 private static $cached_squeeze_options = null;
12
13 public function __construct() {
14 //parent::__construct(); // will cause infinite loop in SquuezeInit
15
16 add_filter( 'posts_where', [$this, 'get_images_from_last_id'], 10, 2 );
17 }
18
19 public function get_upload_path($attach_id, $filename, $url) {
20 if ($attach_id > 0) {
21 $upload_dir = str_replace($filename, "", wp_get_original_image_path($attach_id));
22 } else {
23 $upload_url = str_replace($filename, "", $url);
24 $upload_dir = str_replace(home_url('/'), ABSPATH, $upload_url);
25 }
26 return str_replace('/', DIRECTORY_SEPARATOR, $upload_dir);
27 }
28
29 public function create_backup_filename($filename) {
30 $backup_filename = preg_replace("/(\.(?!.*\.))/", '.bak.', $filename);
31 return $backup_filename;
32 }
33
34 public function backup_original_image($upload_path, $filename, $original_file = null) {
35 if ( ! function_exists( 'WP_Filesystem' ) ) {
36 require_once ABSPATH . 'wp-admin/includes/file.php';
37 }
38
39 global $wp_filesystem;
40
41 // Initialize the filesystem (this populates $wp_filesystem)
42 WP_Filesystem();
43
44 if ( ! $wp_filesystem || ! method_exists( $wp_filesystem, 'copy' ) ) {
45 return new \WP_Error( 'squeeze_filesystem_api_error', 'Filesystem API is not available or failed to initialize.' );
46 }
47
48 $backup_filename = $this->create_backup_filename($filename);
49 if (!file_exists($upload_path . $backup_filename)) {
50 try {
51 if (!$original_file) {
52 $upload_backup_file = $wp_filesystem->copy($upload_path . $filename, $upload_path . $backup_filename, true);
53 } else {
54 $upload_backup_file = move_uploaded_file($original_file, $upload_path . $backup_filename);
55 }
56 } catch (\Exception $e) {
57 return new \WP_Error('squeeze_backup_original_image_failed', ''.esc_html__('Backup original image failed', 'squeeze') . ': '. $upload_path . $backup_filename);
58 }
59 }
60
61 return true;
62 }
63
64 public function decode_base64_image($base64, $file_format) {
65 $img = str_replace('data:image/'.$file_format.';base64,', '', $base64);
66 $img = str_replace(' ', '+', $img);
67 return base64_decode($img);
68 }
69
70 public function upload_image($upload_path, $filename, $decoded_image, $is_file = false) {
71 if ( ! function_exists( 'WP_Filesystem' ) ) {
72 require_once ABSPATH . 'wp-admin/includes/file.php';
73 }
74
75 global $wp_filesystem;
76
77 // Initialize the filesystem (this populates $wp_filesystem)
78 WP_Filesystem();
79
80 if ( ! $wp_filesystem || ! method_exists( $wp_filesystem, 'copy' ) ) {
81 return new \WP_Error('squeeze_filesystem_api_error', 'Filesystem API is not available or failed to initialize.');
82 }
83
84 if ($is_file) {
85 $upload_file = move_uploaded_file($decoded_image, $upload_path . $filename);
86 } else {
87 $upload_file = $wp_filesystem->put_contents($upload_path . $filename, $decoded_image);
88 }
89 if (!$upload_file) {
90 return new \WP_Error('squeeze_upload_image_failed', ''.esc_html__('Upload image failed', 'squeeze') . ': <br>upload_path: ' . $upload_path . '<br>filename: ' . $filename);
91 }
92
93 return $upload_file;
94 }
95
96 public function upload_image_thumbs($upload_path, $sizes, $file_format, $filename = '') {
97 if (!is_array($sizes) || empty($sizes)) {
98 return new \WP_Error('squeeze_upload_image_thumbs_failed', ''.esc_html__('No image data found', 'squeeze'));
99 }
100
101 if ( ! function_exists( 'WP_Filesystem' ) ) {
102 require_once ABSPATH . 'wp-admin/includes/file.php';
103 }
104
105 global $wp_filesystem;
106
107 // Initialize the filesystem (this populates $wp_filesystem)
108 WP_Filesystem();
109
110 if ( ! $wp_filesystem || ! method_exists( $wp_filesystem, 'copy' ) ) {
111 return new \WP_Error('squeeze_filesystem_api_error', 'Filesystem API is not available or failed to initialize.');
112 }
113
114 $is_direct_webp = $this->get_option('direct_webp');
115 foreach ($sizes as $size_name => $size_data) {
116 if ($size_name === 'original') {
117 continue;
118 }
119 $new_size_url = '';
120 if ($file_format === 'webp' && $is_direct_webp && $filename) {
121 //$size_data['url'] = preg_replace('/\.[^.]+$/', '.webp', $size_data['url']);
122
123 // remove extension from filename if it exists
124 //$origin_filename = $filename;
125 $new_filename = pathinfo($filename, PATHINFO_FILENAME); // DO NOT appennd to the $filename, causes bug with complex filenames
126
127
128 // replace the filename in the URL before the last dash
129 // e.g. 'http://localhost/test/wp-content/uploads/2025/08/image-thumbxsize.jpg' becomes
130 // 'http://localhost/test/wp-content/uploads/2025/08/$new_filename-thumbxsize.webp'
131
132 // 1. Match and capture path, base filename, suffix, and extension
133 //if (preg_match('/^(.*\/)(.+)-([^-\/]+)\.((?:jpe?g|png))$/i', $size_data['url'], $m)) {
134 if (preg_match('#^(?P<path>.*/wp-content/uploads/.*/)(?P<base>[^/]+?)(?P<suffix>-(?:\d+x\d+|scaled|rotated))?\.(?P<ext>jpe?g|png)$#i', $size_data['url'], $m)) {
135 // $m[1] = the full path including trailing slash
136 // $m[2] = the base filename (before the dash)
137 // $m[3] = the suffix (between dash and extension)
138 // $m[4] = the original extension
139
140 $path = $m[1];
141 //$new_filename = $m[2]; // <-- this is your variable
142 $suffix = $m[3];
143
144 // 2. Rebuild URL with .webp
145 $new_size_url = "{$path}{$new_filename}{$suffix}.webp";
146 }
147 }
148 $size_base64 = sanitize_text_field($size_data['base64']);
149 $size_decoded = $this->decode_base64_image($size_base64, $file_format);
150 $size_filename = basename(sanitize_url($new_size_url ? $new_size_url : $size_data['url']));
151 if ($size_name === 'full') {
152 $size_name = 'scaled';
153 unset($sizes['full']);
154 }
155 $original_size = file_exists($upload_path . $size_filename) ? wp_filesize($upload_path . $size_filename) : 0;
156 $compressed_size = strlen($size_decoded);
157 $sizes[$size_name]['original_size'] = $original_size;
158
159 // if compressed size is larger than original, skip uploading and keep original
160 if ($original_size > 0 && $compressed_size > $original_size) {
161 $sizes[$size_name]['compressed_size'] = $original_size;
162 continue;
163 }
164 $upload_size_file = $wp_filesystem->put_contents($upload_path . $size_filename, $size_decoded);
165 if (!$upload_size_file) {
166 return new \WP_Error('squeeze_upload_image_thumbs_failed', ''.esc_html__('Upload image failed', 'squeeze') . ': <br>upload_path: ' . $upload_path . '<br>filename: ' . $size_filename);
167 } else {
168 $sizes[$size_name]['compressed_size'] = $compressed_size;
169 }
170 }
171 return $sizes;
172 }
173
174 public function upload_webp($upload_path, $base64_webp, $filename, $is_file = false) {
175 if (!$base64_webp) {
176 return new \WP_Error('squeeze_upload_webp_failed', ''.esc_html__('No WebP data found', 'squeeze'));
177 }
178
179 $upload_webp_path = $this->convert_image_path_to_webp_path($upload_path);
180 if (!file_exists($upload_webp_path)) {
181 wp_mkdir_p($upload_webp_path);
182 }
183 $decoded_webp = $is_file ? $base64_webp : $this->decode_base64_image($base64_webp, 'webp');
184 $filename_webp = $filename.'.webp';
185 $upload_file_webp = $this->upload_image($upload_webp_path, $filename_webp, $decoded_webp, $is_file);
186
187 return $upload_file_webp;
188 }
189
190 public function upload_webp_thumbs($upload_path, $sizes_webp) {
191 if (!is_array($sizes_webp) || empty($sizes_webp)) {
192 return new \WP_Error('squeeze_upload_webp_thumbs_failed', ''.esc_html__('No WebP data found', 'squeeze'));
193 }
194
195 $upload_webp_path = $this->convert_image_path_to_webp_path($upload_path);
196 if (!file_exists($upload_webp_path)) {
197 wp_mkdir_p($upload_webp_path);
198 }
199 foreach ($sizes_webp as $size_name => $size_data) {
200 if ($size_name === 'original') {
201 continue;
202 }
203 $size_base64 = sanitize_text_field($size_data['base64']);
204 $size_decoded = $this->decode_base64_image($size_base64, 'webp');
205 $size_filename = basename(sanitize_url($size_data['url']));
206 $size_filename = $size_filename.'.webp';
207 $upload_size_file = $this->upload_image($upload_webp_path, $size_filename, $size_decoded);
208 }
209 return $sizes_webp;
210 }
211
212 public function convert_image_path_to_webp_path($image_path) {
213 //$webp_path = preg_replace('/wp-content[\/\\\\]/', 'wp-content/squeeze-webp/', $image_path, 1);
214 //return str_replace(['/', '\\'], '/', $webp_path);
215
216 // Grab your actual content folder name (e.g. "wp-content" or custom)
217 $content_folder = basename( WP_CONTENT_DIR );
218
219 // Build a regex to match that folder plus a slash or backslash
220 $pattern = sprintf(
221 '#%s[\\/\\\\]#',
222 preg_quote( $content_folder, '#' )
223 );
224 // Replace with "{folder}/squeeze-webp/"
225 $replacement = $content_folder . '/squeeze-webp/';
226
227 // Do the one-time replacement…
228 $webp_path = preg_replace( $pattern, $replacement, $image_path, 1 );
229
230 // Normalize backslashes to forward slashes and return
231 return str_replace( '\\', '/', $webp_path );
232 }
233
234 public function can_restore($attach_id) {
235 $original_img_path = wp_get_original_image_path((int) $attach_id);
236 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
237 $can_restore = file_exists($backup_img_path);
238
239 return $can_restore;
240 }
241
242 public function restore_attachment($attach_id, $is_bulk = false) {
243 if ( ! function_exists( 'WP_Filesystem' ) ) {
244 require_once ABSPATH . 'wp-admin/includes/file.php';
245 }
246
247 global $wp_filesystem;
248
249 // Initialize the filesystem (this populates $wp_filesystem)
250 WP_Filesystem();
251
252 if ( ! $wp_filesystem || ! method_exists( $wp_filesystem, 'copy' ) ) {
253 if ($is_bulk) {
254 wp_die( 'Filesystem API is not available or failed to initialize.' );
255 } else {
256 return new \WP_Error('squeeze_filesystem_api_error', 'Filesystem API is not available or failed to initialize.');
257 }
258 }
259
260 $original_img_path = wp_get_original_image_path($attach_id);
261 $backup_img_path = preg_replace("/(\.(?!.*\.))/", '.bak.', $original_img_path);
262
263 if (!file_exists($backup_img_path)) {
264 $error_message = '' . esc_html__('Backup image not found', 'squeeze');
265 if ($is_bulk) {
266 wp_die(esc_html($error_message));
267 } else {
268 return new \WP_Error('squeeze_restore_attachment_failed', $error_message);
269 }
270 return false;
271 }
272
273 $backup_img = $wp_filesystem->copy($backup_img_path, $original_img_path, true);
274 if (!$backup_img) {
275 $error_message = '' . esc_html__('Restore original image failed', 'squeeze');
276 if ($is_bulk) {
277 wp_die(esc_html($error_message));
278 } else {
279 return new \WP_Error('squeeze_restore_attachment_failed', $error_message);
280 }
281 return false;
282 }
283
284 $attachment_data = wp_create_image_subsizes($original_img_path, $attach_id);
285 if (!delete_post_meta($attach_id, "squeeze_is_compressed")) {
286 return false;
287 }
288
289 wp_delete_file($backup_img_path);
290 $this->delete_webp_images($original_img_path, $attachment_data);
291
292 $uncompressed_images = $this->get_stats_option('uncompressed_images');
293 update_option('squeeze_stats', array('uncompressed_images' => ++$uncompressed_images));
294 return true;
295 }
296
297 public function delete_webp_images($original_img_path, $attachment_data) {
298 $result = false;
299
300 if (!is_array($attachment_data) || empty($attachment_data)) {
301 return $result;
302 }
303
304 $original_filename = pathinfo($original_img_path, PATHINFO_BASENAME);
305
306 $webp_path = $this->convert_image_path_to_webp_path($original_img_path);
307 $result = wp_delete_file($webp_path . '.webp');
308
309 foreach ($attachment_data['sizes'] as $size_data) {
310 $webp_thumb_path = str_replace($original_filename, $size_data['file'] . '.webp', $original_img_path);
311 $result = wp_delete_file($this->convert_image_path_to_webp_path($webp_thumb_path));
312 }
313
314 $webp_scaled_filename = pathinfo($attachment_data['file'], PATHINFO_BASENAME);
315 $webp_scaled_path = $this->convert_image_path_to_webp_path(str_replace($original_filename, $webp_scaled_filename . '.webp', $original_img_path));
316
317 if (file_exists($webp_scaled_path)) {
318 $result = wp_delete_file($webp_scaled_path);
319 }
320
321 return $result;
322 }
323
324 public function get_stats_option($option) {
325 $stats = get_option('squeeze_stats');
326 $option_value = isset($stats[$option]) ? $stats[$option] : 0;
327
328 return $option_value;
329 }
330
331 public function get_option($option) {
332 // Cache squeeze_options array per request to avoid repeated database queries
333 // This prevents hundreds of get_option('squeeze_options') calls during bulk operations
334 if (self::$cached_squeeze_options === null) {
335 self::$cached_squeeze_options = get_option('squeeze_options');
336 }
337
338 $options = self::$cached_squeeze_options;
339 $option_value = isset($options[$option]) ? $options[$option] : $this->get_default_value($option);
340
341 return $option_value;
342 }
343
344 public function set_options($options) {
345 $default_options = $this->get_default_value('all', true);
346 $options = wp_parse_args($options, $default_options);
347 $result = update_option('squeeze_options', $options);
348
349 // Clear the cache when options are updated
350 if ($result) {
351 self::$cached_squeeze_options = $options;
352 }
353
354 return $result;
355 }
356
357 public function get_comparison_table($sizes) {
358 if (!is_array($sizes) || empty($sizes)) {
359 return '';
360 }
361
362 //$table = print_r($sizes, true);
363 $table = '<div class="squeeze-comparison-table">';
364 $table .= '<table class="wp-list-table widefat striped">';
365 $table .= '<thead><tr><th>'.esc_html__('Size Name', 'squeeze').'</th><th>'.esc_html__('Original Size', 'squeeze').'</th><th>'.esc_html__('Squeezed Size', 'squeeze').'</th><th>'.esc_html__('Savings', 'squeeze').' (%)</th></tr></thead>';
366 $table .= '<tbody>';
367
368 foreach ($sizes as $size_name => $size_data) {
369 /*if (!isset($size_data['url'])) {
370 continue;
371 }*/
372 //$size_filename = basename(sanitize_url($size_data['url']));
373 $original_size = $size_data['original_size'];
374 $compressed_size = $size_data['compressed_size'];
375 $savings = $original_size - $compressed_size;
376 $savings_percent = round(($savings / $original_size) * 100, 2);
377 $savings_class = $savings > 0 ? 'squeeze-savings-positive' : 'squeeze-savings-negative';
378
379 $table .= '<tr>';
380 $table .= '<td><strong>'.$size_name.'</strong></td>';
381 $table .= '<td>'.size_format($original_size, 0).'</td>';
382 $table .= '<td>'.size_format($compressed_size, 0).'</td>';
383 $table .= '<td><span class="squeeze-savings-label '.$savings_class.'">'.$savings_percent.'%</span></td>';
384 $table .= '</tr>';
385 }
386
387 $table .= '</tbody></table></div>';
388
389 return $table;
390 }
391
392 public function is_webp_replace_urls() {
393 $is_auto_webp = $this->get_option('auto_webp');
394 $is_webp_replace_urls = $this->get_option('webp_replace_urls');
395
396 if (!$is_auto_webp || !$is_webp_replace_urls) {
397 return false;
398 }
399
400 return true;
401 }
402
403 public function get_image_formats($return_mimes = false, $custom_formats = []) {
404 $allowed_image_formats = empty($custom_formats) ? $this->get_option('compress_formats') : $custom_formats;
405 $allowed_image_formats = array_keys($allowed_image_formats);
406
407 // make values the same as keys
408 $allowed_image_formats = array_combine($allowed_image_formats, $allowed_image_formats);
409
410 if ($return_mimes) {
411 $allowed_image_formats = array_map(function($format) {
412 $format = $format === 'jpg' ? 'jpeg' : $format; // handle jpg/jpeg mime type
413 return 'image/'.$format;
414 }, $allowed_image_formats);
415 }
416
417 return $allowed_image_formats;
418 }
419
420 public function get_total_images_count() {
421 $total_images = $this->get_stats_option('total_images');
422
423 if ($total_images > 0) {
424 return $total_images;
425 }
426
427 $query_all = new \WP_Query(array(
428 'post_type' => 'attachment',
429 'post_status' => 'inherit',
430 'post_mime_type' => $this->get_image_formats(true),
431 'posts_per_page' => -1,
432 'fields' => 'ids',
433 ));
434
435 $total_images = $query_all->found_posts;
436
437 $stats['total_images'] = $total_images;
438 update_option('squeeze_stats', $stats);
439
440 return $total_images;
441 }
442
443 public function get_uncompressed_images_count() {
444 $uncompressed_images = $this->get_stats_option('uncompressed_images');
445
446 if ($uncompressed_images > 0) {
447 return $uncompressed_images;
448 }
449
450 $query_uncompressed = new \WP_Query(array(
451 'post_type' => 'attachment',
452 'post_status' => 'inherit',
453 'post_mime_type' => $this->get_image_formats(true),
454 'posts_per_page' => -1,
455 'fields' => 'ids',
456 'meta_query' => array(
457 'relation' => 'OR',
458 array(
459 'key' => 'squeeze_is_compressed',
460 'compare' => 'NOT EXISTS',
461 ),
462 array(
463 'key' => 'squeeze_is_compressed',
464 'compare' => '!=',
465 'value' => '1',
466 ),
467 ),
468 ));
469
470 $uncompressed_images = $query_uncompressed->found_posts;
471
472 $stats['uncompressed_images'] = $uncompressed_images;
473 update_option('squeeze_stats', $stats);
474
475 return $uncompressed_images;
476 }
477
478 public function get_images_from_last_id($where, $wp_query) {
479 if ( $wp_query->get( 'squeeze_last_id' ) !== null && $wp_query->get( 'squeeze_last_id' ) > 0 ) {
480 global $wpdb;
481 $last = intval( $wp_query->get( 'squeeze_last_id' ) );
482 $where .= $wpdb->prepare( " AND {$wpdb->posts}.ID < %d", $last );
483 }
484 return $where;
485 }
486
487 public function get_uncompressed_images($last_id = 0) {
488
489 $query_uncompressed = new \WP_Query(array(
490 'post_type' => 'attachment',
491 'post_status' => 'inherit',
492 'post_mime_type' => $this->get_image_formats(true),
493 'posts_per_page' => self::$MEDIA_PER_PAGE,
494 'fields' => 'ids',
495 'orderby' => 'ID',
496 'order' => 'DESC',
497 'meta_query' => array(
498 'relation' => 'OR',
499 array(
500 'key' => 'squeeze_is_compressed',
501 'compare' => 'NOT EXISTS',
502 ),
503 array(
504 'key' => 'squeeze_is_compressed',
505 'compare' => '!=',
506 'value' => '1',
507 ),
508 ),
509 'squeeze_last_id' => $last_id,
510 ));
511
512 return $query_uncompressed->posts;
513 }
514
515 public function get_total_images($paged = 1) {
516 $args = array(
517 'post_type' => 'attachment',
518 'post_status' => 'inherit',
519 'post_mime_type' => $this->get_image_formats(true),
520 'posts_per_page' => self::$MEDIA_PER_PAGE,
521 'paged' => $paged,
522 'fields' => 'ids',
523 );
524
525 $query_all = new \WP_Query($args);
526
527 return $query_all->posts;
528 }
529
530 public function get_hint($hint, $class = 'squeeze-hint') {
531 return '<span class="' . esc_attr($class) . '">' . esc_html($hint) . '</span>';
532 }
533
534 public function get_default_value ( $option, $all = false ) {
535 $options_defaults = apply_filters('squeeze_options_default',
536 array(
537 // JPEG settings
538 'jpeg_quality' => 80,
539 'jpeg_baseline' => false,
540 //'jpeg_arithmetic' => false,
541 'jpeg_progressive' => true,
542 'jpeg_optimize_coding' => true,
543 'jpeg_smoothing' => 0,
544 'jpeg_color_space' => 3,
545 'jpeg_quant_table' => 3,
546 'jpeg_trellis_multipass' => false,
547 'jpeg_trellis_opt_zero' => false,
548 'jpeg_trellis_opt_table' => false,
549 'jpeg_trellis_loops' => 1,
550 'jpeg_auto_subsample' => true,
551 'jpeg_chroma_subsample' => 2,
552 'jpeg_separate_chroma_quality' => false,
553 'jpeg_chroma_quality' => 75,
554
555 // PNG settings
556 'png_level' => 2,
557 'png_interlace' => false,
558 'png_quality' => 0.7,
559
560 // WEBP settings
561 'webp_method' => 4,
562 'webp_quality' => 80,
563 'webp_lossless' => false,
564 'webp_near_lossless' => 100,
565
566 // AVIF settings
567 'avif_cqLevel' => 70,
568
569 // General settings
570 'auto_compress' => true,
571 'auto_webp' => false, // needs to be false by default, because user has to save settings first in order to flush rewrite rules
572 'webp_replace_urls' => false,
573 'direct_webp' => true,
574 'cdn_url' => '',
575 'backup_original' => true,
576 'compress_formats' => self::ALLOWED_IMAGE_FORMATS,
577 'compress_thumbs' => array('large' => 'on', 'full' => 'on'),
578 'max_width' => '',
579 'max_height' => '',
580 'excluded_images' => '',
581 'timeout' => 60,
582 'restore_defaults' => false, // special option to trigger restore defaults
583 )
584 );
585 if ($all) {
586 return $options_defaults;
587 }
588 return in_array($option, array_keys($options_defaults)) ? $options_defaults[ $option ] : false;
589 }
590
591 public function get_thumb_sizes() {
592 $sizes = wp_get_registered_image_subsizes();
593 if ( !empty( $sizes ) && is_array( $sizes ) ) {
594 // Add the scaled image size option if it fits the image dimensions
595 $big_image_size_threshold = apply_filters('big_image_size_threshold', 2560);
596 if ( $big_image_size_threshold ) {
597 $sizes['full'] = array(
598 'width' => $big_image_size_threshold,
599 'height' => $big_image_size_threshold,
600 'crop' => false,
601 );
602 }
603 }
604 return $sizes;
605 }
606
607 public function is_rest_enabled() {
608 // Check if REST API is enabled
609 if ( !function_exists( 'rest_get_server' ) || !rest_get_server() ) {
610 return false;
611 }
612
613 return (bool) apply_filters( 'rest_enabled', true );
614 }
615
616 public function apache_get_modules() {
617 if (!function_exists('apache_get_modules') || !in_array('mod_rewrite', apache_get_modules())) {
618 return false;
619 }
620 return apache_get_modules();
621 }
622 }
623