PluginProbe
Vigilant – 100% Free Security Suite: Firewall, 2FA, Login, Headers, Scanner… / 2.9.5
Vigilant – 100% Free Security Suite: Firewall, 2FA, Login, Headers, Scanner… v2.9.5
3.0.0 2.11.12 2.11.11 2.11.10 2.11.9 2.11.7 2.11.8 2.11.6 2.11.5 2.11.4 2.11.3 2.11.1 2.11.2 2.11.0 2.10.5 2.10.4 2.10.3 2.10.2 2.10.1 2.10.0 2.9.9 2.9.8 2.9.6 2.9.7 2.9.5 All 88 releases
vigilante / includes / class-wpconfig-security.php

class-wpconfig-security.php in Vigilant – 100% Free Security Suite: Firewall, 2FA, Login, Headers, Scanner… 2.9.5, at includes/class-wpconfig-security.php

714 lines 25.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WP-Config Security Class
4 *
5 * Manages wp-config.php security constants with MULTIPLE safety checks
6 * Uses comment/uncomment strategy to handle existing constants
7 *
8 * @package Vigilante
9 */
10
11 // Prevent direct access
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Class Vigilante_Wpconfig_Security
18 *
19 * Applies security constants to wp-config.php
20 */
21 class Vigilante_Wpconfig_Security {
22
23 /**
24 * Settings instance
25 *
26 * @var Vigilante_Settings
27 */
28 private $settings;
29
30 /**
31 * Security options
32 *
33 * @var array
34 */
35 private $options;
36
37 /**
38 * Path to wp-config.php
39 *
40 * @var string
41 */
42 private $wpconfig_path;
43
44 /**
45 * Marker for our constants
46 */
47 const MARKER_START = '/* BEGIN Vigilante Security Constants */';
48 const MARKER_END = '/* END Vigilante Security Constants */';
49
50 /**
51 * Marker for commented original lines
52 */
53 const ORIGINAL_MARKER = '// [VIGILANTE_ORIGINAL] ';
54
55 /**
56 * Old plugin markers to clean
57 */
58 const OLD_MARKER_START = '/* BEGIN AyudaWP Security Constants */';
59 const OLD_MARKER_END = '/* END AyudaWP Security Constants */';
60
61 /**
62 * Minimum valid wp-config.php size in bytes
63 */
64 const MIN_CONFIG_SIZE = 1000;
65
66 /**
67 * Constants managed by this plugin
68 *
69 * @var array
70 */
71 private $managed_constants = array(
72 'DISALLOW_FILE_EDIT',
73 'DISALLOW_FILE_MODS',
74 'FORCE_SSL_ADMIN',
75 'FORCE_SSL_LOGIN',
76 'WP_DEBUG',
77 'WP_DEBUG_LOG',
78 'WP_DEBUG_DISPLAY',
79 'SCRIPT_DEBUG',
80 'DISABLE_WP_CRON',
81 );
82
83 /**
84 * Constructor
85 *
86 * @param Vigilante_Settings $settings Settings instance.
87 */
88 public function __construct( $settings ) {
89 $this->settings = $settings;
90 $this->options = $settings->get_section( 'wp_hardening' );
91 $this->wpconfig_path = ABSPATH . 'wp-config.php';
92 }
93
94 /**
95 * Apply security constants to wp-config.php
96 *
97 * @return bool|WP_Error
98 */
99 public function apply_security_constants() {
100 // Safety check 1: File must exist and be writable
101 if ( ! $this->is_wpconfig_writable() ) {
102 return new WP_Error( 'not_writable', __( 'wp-config.php is not writable', 'vigilante' ) );
103 }
104
105 // Safety check 2: Create backup BEFORE any modification
106 $backup_result = $this->create_backup();
107 if ( is_wp_error( $backup_result ) ) {
108 return $backup_result;
109 }
110
111 // First clean up old plugin constants
112 $this->remove_old_constants();
113
114 // Restore any previously commented constants (clean slate for upgrades)
115 // This ensures constants no longer managed by current version get uncommented
116 $this->uncomment_original_constants();
117
118 // Comment out existing managed constants
119 $comment_result = $this->comment_existing_constants();
120 if ( is_wp_error( $comment_result ) ) {
121 return $comment_result;
122 }
123
124 // Generate and write our constants block
125 $constants = $this->generate_constants();
126 $result = $this->write_constants( $constants );
127
128 // Regenerate critical file baseline so the integrity scan does not
129 // flag our own modifications as unauthorized changes.
130 if ( true === $result ) {
131 /**
132 * Fires after Vigilante successfully writes to wp-config.php.
133 * Used by the file integrity module to update the baseline hash.
134 */
135 do_action( 'vigilante_critical_file_written', 'wp-config.php' );
136 }
137
138 return $result;
139 }
140
141 /**
142 * Create a backup of wp-config.php before modification
143 *
144 * @return bool|WP_Error
145 */
146 private function create_backup() {
147 if ( ! file_exists( $this->wpconfig_path ) ) {
148 return new WP_Error( 'no_config', __( 'wp-config.php does not exist', 'vigilante' ) );
149 }
150
151 $content = $this->read_file_directly( $this->wpconfig_path );
152
153 if ( false === $content || strlen( $content ) < self::MIN_CONFIG_SIZE ) {
154 return new WP_Error( 'invalid_config', __( 'wp-config.php appears invalid or too small', 'vigilante' ) );
155 }
156
157 // Validate it looks like a real wp-config.php
158 if ( ! $this->validate_wpconfig_content( $content ) ) {
159 return new WP_Error( 'invalid_config', __( 'wp-config.php does not appear to be a valid WordPress configuration file', 'vigilante' ) );
160 }
161
162 // Store the backup in a private database option, never as a file under
163 // the web root. wp-config.php holds DB credentials and salts; a file in
164 // wp-content could be served by a misconfigured server. The option is
165 // not reachable over HTTP and is not autoloaded.
166 $stored = update_option(
167 'vigilante_wpconfig_backup',
168 array(
169 'content' => $content,
170 'time' => time(),
171 ),
172 false
173 );
174
175 // update_option() returns false both on failure and when the value is
176 // unchanged; only treat it as an error if the content was not stored.
177 if ( false === $stored && $content !== $this->get_wpconfig_backup_content() ) {
178 return new WP_Error( 'backup_failed', __( 'Could not create wp-config.php backup', 'vigilante' ) );
179 }
180
181 return true;
182 }
183
184 /**
185 * Get the stored wp-config.php backup content, or '' if none.
186 *
187 * @return string
188 */
189 private function get_wpconfig_backup_content() {
190 $backup = get_option( 'vigilante_wpconfig_backup' );
191 return ( is_array( $backup ) && isset( $backup['content'] ) ) ? (string) $backup['content'] : '';
192 }
193
194 /**
195 * Read file directly without WP_Filesystem (more reliable)
196 *
197 * @param string $path File path.
198 * @return string|false
199 */
200 private function read_file_directly( $path ) {
201 if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
202 return false;
203 }
204 return file_get_contents( $path ); // phpcs:ignore
205 }
206
207 /**
208 * Validate that content looks like a real wp-config.php
209 *
210 * @param string $content File content.
211 * @return bool
212 */
213 private function validate_wpconfig_content( $content ) {
214 // Must contain PHP opening tag
215 if ( strpos( $content, '<?php' ) === false ) {
216 return false;
217 }
218
219 // Must contain database configuration
220 if ( strpos( $content, 'DB_NAME' ) === false ) {
221 return false;
222 }
223
224 if ( strpos( $content, 'DB_USER' ) === false ) {
225 return false;
226 }
227
228 if ( strpos( $content, 'DB_PASSWORD' ) === false ) {
229 return false;
230 }
231
232 // Must contain table prefix
233 if ( strpos( $content, '$table_prefix' ) === false ) {
234 return false;
235 }
236
237 return true;
238 }
239
240 /**
241 * Comment out existing managed constants in wp-config.php
242 *
243 * @return bool|WP_Error
244 */
245 private function comment_existing_constants() {
246 $content = $this->read_file_directly( $this->wpconfig_path );
247
248 if ( false === $content || ! $this->validate_wpconfig_content( $content ) ) {
249 return new WP_Error( 'read_failed', __( 'Could not read wp-config.php', 'vigilante' ) );
250 }
251
252 $modified = false;
253
254 foreach ( $this->managed_constants as $constant ) {
255 // Pattern to match define statements for this constant
256 // Matches: define( 'CONSTANT', value ); or define('CONSTANT', value);
257 // Does NOT match already commented lines (commented lines have // prefix before define)
258 $pattern = '/^(\s*)(define\s*\(\s*[\'"]' . preg_quote( $constant, '/' ) . '[\'"]\s*,\s*[^)]+\)\s*;)/m';
259
260 // Loop to comment ALL occurrences, not just the first
261 // wp-config.php files may have duplicate defines (e.g. multiple WP_DEBUG)
262 $safety = 0;
263 while ( preg_match( $pattern, $content, $matches ) && $safety < 20 ) {
264 $safety++;
265 $full_line = $matches[0];
266
267 // Already commented by us — no more uncommented matches possible
268 if ( strpos( $full_line, self::ORIGINAL_MARKER ) !== false ) {
269 break;
270 }
271
272 // Check if this line is inside our Vigilante block (skip it)
273 $marker_pos = strpos( $content, self::MARKER_START );
274 if ( $marker_pos !== false ) {
275 $line_pos = strpos( $content, $full_line );
276 $end_marker_pos = strpos( $content, self::MARKER_END );
277 if ( $line_pos > $marker_pos && $line_pos < $end_marker_pos ) {
278 break; // Inside our block, stop processing this constant
279 }
280 }
281
282 // Comment out this occurrence
283 $replacement = $matches[1] . self::ORIGINAL_MARKER . $matches[2];
284 $content = preg_replace( $pattern, $replacement, $content, 1 );
285 $modified = true;
286 }
287 }
288
289 if ( $modified ) {
290 // Validate BEFORE writing
291 if ( ! $this->validate_wpconfig_content( $content ) ) {
292 return new WP_Error( 'invalid_after_comment', __( 'wp-config.php would be invalid after commenting constants', 'vigilante' ) );
293 }
294
295 if ( ! $this->write_file_directly( $this->wpconfig_path, $content ) ) {
296 return new WP_Error( 'write_failed', __( 'Could not write to wp-config.php', 'vigilante' ) );
297 }
298 }
299
300 return true;
301 }
302
303 /**
304 * Uncomment original constants that were commented by us
305 *
306 * @return bool
307 */
308 private function uncomment_original_constants() {
309 $content = $this->read_file_directly( $this->wpconfig_path );
310
311 if ( false === $content ) {
312 return false;
313 }
314
315 // Find and uncomment lines marked with our original marker
316 $pattern = '/^(\s*)' . preg_quote( self::ORIGINAL_MARKER, '/' ) . '(.+)$/m';
317
318 if ( preg_match( $pattern, $content ) ) {
319 $content = preg_replace( $pattern, '$1$2', $content );
320
321 // Validate BEFORE writing
322 if ( ! $this->validate_wpconfig_content( $content ) ) {
323 return false;
324 }
325
326 return $this->write_file_directly( $this->wpconfig_path, $content );
327 }
328
329 return true;
330 }
331
332 /**
333 * Remove old Easy Vigilante constants from wp-config.php
334 *
335 * @return bool
336 */
337 public function remove_old_constants() {
338 $content = $this->read_file_directly( $this->wpconfig_path );
339
340 if ( false === $content || ! $this->validate_wpconfig_content( $content ) ) {
341 return false;
342 }
343
344 $modified = false;
345
346 // Remove old AyudaWP Security Constants block
347 $pattern = '/' . preg_quote( self::OLD_MARKER_START, '/' ) . '.*?' . preg_quote( self::OLD_MARKER_END, '/' ) . '\s*/s';
348 if ( preg_match( $pattern, $content ) ) {
349 $content = preg_replace( $pattern, '', $content );
350 $modified = true;
351 }
352
353 if ( $modified ) {
354 // Validate BEFORE writing
355 if ( ! $this->validate_wpconfig_content( $content ) ) {
356 return false;
357 }
358 return $this->write_file_directly( $this->wpconfig_path, $content );
359 }
360
361 return true;
362 }
363
364 /**
365 * Remove our security constants from wp-config.php and restore originals
366 *
367 * @return bool
368 */
369 public function remove_constants() {
370 if ( ! file_exists( $this->wpconfig_path ) ) {
371 return true;
372 }
373
374 $content = $this->read_file_directly( $this->wpconfig_path );
375
376 if ( false === $content ) {
377 return false;
378 }
379
380 // If our markers don't exist, just try to uncomment originals
381 if ( strpos( $content, self::MARKER_START ) === false ) {
382 return $this->uncomment_original_constants();
383 }
384
385 // Validate before modification
386 if ( ! $this->validate_wpconfig_content( $content ) ) {
387 return false;
388 }
389
390 // Remove our section
391 $pattern = '/' . preg_quote( self::MARKER_START, '/' ) . '.*?' . preg_quote( self::MARKER_END, '/' ) . '\s*/s';
392 $new_content = preg_replace( $pattern, '', $content );
393
394 // CRITICAL: Validate result BEFORE writing
395 if ( ! $this->validate_wpconfig_content( $new_content ) ) {
396 // Something went wrong, don't write
397 return false;
398 }
399
400 // Clean up multiple empty lines
401 $new_content = preg_replace( '/\n{3,}/', "\n\n", $new_content );
402
403 // Write the file without our block
404 if ( ! $this->write_file_directly( $this->wpconfig_path, $new_content ) ) {
405 return false;
406 }
407
408 // Now uncomment the original constants
409 return $this->uncomment_original_constants();
410 }
411
412 /**
413 * Generate security constants block (without conditional checks)
414 *
415 * @return string
416 */
417 public function generate_constants() {
418 $constants = array();
419
420 $constants[] = self::MARKER_START;
421 $constants[] = '// Vigilante for WordPress - v' . VIGILANTE_VERSION;
422 $constants[] = '// Generated: ' . gmdate( 'Y-m-d H:i:s' ) . ' UTC';
423 $constants[] = '// Note: Original constants (if any) are commented with [VIGILANTE_ORIGINAL] marker';
424 $constants[] = '// Each define() is wrapped in "if ( ! defined() )" so the block is safe on';
425 $constants[] = '// non-standard setups that pre-define WordPress constants before wp-config.php';
426 $constants[] = '// is parsed (would otherwise trigger a "Constant already defined" fatal).';
427 $constants[] = '';
428
429 // File editing/modification
430 if ( ! empty( $this->options['disallow_file_edit'] ) ) {
431 $constants[] = "// Disable file editing in admin";
432 $constants[] = "if ( ! defined( 'DISALLOW_FILE_EDIT' ) ) { define( 'DISALLOW_FILE_EDIT', true ); }";
433 $constants[] = '';
434 }
435
436 if ( ! empty( $this->options['disallow_file_mods'] ) ) {
437 $constants[] = "// Disable file modifications (plugins/themes install/update)";
438 $constants[] = "if ( ! defined( 'DISALLOW_FILE_MODS' ) ) { define( 'DISALLOW_FILE_MODS', true ); }";
439 $constants[] = '';
440 }
441
442 // SSL settings
443 if ( ! empty( $this->options['force_ssl_admin'] ) ) {
444 $constants[] = "// Force SSL for admin";
445 $constants[] = "if ( ! defined( 'FORCE_SSL_ADMIN' ) ) { define( 'FORCE_SSL_ADMIN', true ); }";
446 $constants[] = '';
447 }
448
449 if ( ! empty( $this->options['force_ssl_login'] ) ) {
450 $constants[] = "// Force SSL for login";
451 $constants[] = "if ( ! defined( 'FORCE_SSL_LOGIN' ) ) { define( 'FORCE_SSL_LOGIN', true ); }";
452 $constants[] = '';
453 }
454
455 // Debug settings - generate when "Hide PHP errors from visitors" is unchecked (development mode)
456 if ( empty( $this->options['wp_debug'] ) ) {
457 $constants[] = "// Debug settings (enabled for development)";
458 $constants[] = "if ( ! defined( 'WP_DEBUG' ) ) { define( 'WP_DEBUG', true ); }";
459 $constants[] = "if ( ! defined( 'WP_DEBUG_LOG' ) ) { define( 'WP_DEBUG_LOG', true ); }";
460 $constants[] = "if ( ! defined( 'WP_DEBUG_DISPLAY' ) ) { define( 'WP_DEBUG_DISPLAY', false ); }";
461 $constants[] = "if ( ! defined( 'SCRIPT_DEBUG' ) ) { define( 'SCRIPT_DEBUG', false ); }";
462 $constants[] = '';
463 } else {
464 $constants[] = "// Debug disabled (production)";
465 $constants[] = "if ( ! defined( 'WP_DEBUG' ) ) { define( 'WP_DEBUG', false ); }";
466 $constants[] = '';
467 }
468
469 // Disable WordPress's built-in pseudo-cron (page-view trigger). Pairs with the
470 // .htaccess block from firewall.protect_wp_cron — this constant alone does NOT
471 // block external HTTP access to wp-cron.php, only the auto-spawn from front-end
472 // page views. Both pieces are needed for full coverage; both require a real
473 // server-side cron job calling wp-cron.php from CLI.
474 if ( ! empty( $this->options['disable_wp_cron'] ) ) {
475 $constants[] = "// Disable WordPress pseudo-cron (use real server-side cron instead)";
476 $constants[] = "if ( ! defined( 'DISABLE_WP_CRON' ) ) { define( 'DISABLE_WP_CRON', true ); }";
477 $constants[] = '';
478 }
479
480 $constants[] = self::MARKER_END;
481 $constants[] = '';
482
483 return implode( "\n", $constants );
484 }
485
486 /**
487 * Write constants to wp-config.php with multiple safety checks
488 *
489 * @param string $constants Constants block to write.
490 * @return bool|WP_Error
491 */
492 private function write_constants( $constants ) {
493 // SAFETY CHECK 1: Read file directly (not via WP_Filesystem which can fail)
494 $content = $this->read_file_directly( $this->wpconfig_path );
495
496 // SAFETY CHECK 2: Verify we got valid content
497 if ( false === $content || strlen( $content ) < self::MIN_CONFIG_SIZE ) {
498 return new WP_Error( 'read_failed', __( 'Could not read wp-config.php or file is too small', 'vigilante' ) );
499 }
500
501 // SAFETY CHECK 3: Validate it's a real wp-config.php
502 if ( ! $this->validate_wpconfig_content( $content ) ) {
503 return new WP_Error( 'invalid_config', __( 'wp-config.php does not appear to be valid', 'vigilante' ) );
504 }
505
506 // Store original for comparison
507 $original_content = $content;
508
509 // Remove existing Vigilante constants block
510 $pattern = '/' . preg_quote( self::MARKER_START, '/' ) . '.*?' . preg_quote( self::MARKER_END, '/' ) . '\s*/s';
511 $content = preg_replace( $pattern, '', $content );
512
513 // Remove old plugin constants block
514 $old_pattern = '/' . preg_quote( self::OLD_MARKER_START, '/' ) . '.*?' . preg_quote( self::OLD_MARKER_END, '/' ) . '\s*/s';
515 $content = preg_replace( $old_pattern, '', $content );
516
517 // Clean up multiple empty lines
518 $content = preg_replace( '/\n{3,}/', "\n\n", $content );
519
520 // SAFETY CHECK 4: Content should still be valid after removal
521 if ( ! $this->validate_wpconfig_content( $content ) ) {
522 return new WP_Error( 'invalid_after_clean', __( 'wp-config.php became invalid after cleanup', 'vigilante' ) );
523 }
524
525 // Find the best place to insert constants
526 $inserted = false;
527
528 // Method 1: Before "That's all, stop editing" comment
529 // This comment may be translated in localized wp-config files, so we use a broad pattern
530 // that matches the block comment immediately before the ABSPATH section.
531 // Known variants: "That's all, stop editing!", "C'est tout, ne touchez plus à ce qui suit",
532 // "Das war's, Schluss mit dem Editieren!", "Ya está. ¡Deja de editar!", etc.
533 $stop_editing_patterns = array(
534 // English (default)
535 "/(\/\*[^*]*That's all,?\s*stop editing[^*]*\*\/)/i",
536 // Broad match: any block comment on its own line(s) immediately before "Absolute path"
537 // This catches translated versions without needing every language
538 '/(\n\/\*[^\n*]{5,80}\*\/)\s*\n+\s*\/\*\*\s*Absolute path/i',
539 );
540
541 foreach ( $stop_editing_patterns as $pattern ) {
542 if ( preg_match( $pattern, $content, $matches ) ) {
543 $content = str_replace(
544 $matches[1],
545 $constants . "\n\n" . $matches[1],
546 $content
547 );
548 $inserted = true;
549 break;
550 }
551 }
552
553 // Method 2: Before "/** Absolute path to the WordPress directory" PHPDoc comment
554 // This is a code comment in wp-config-sample.php and is NOT translatable
555 if ( ! $inserted && preg_match( '/(\/\*\*\s*Absolute path to the WordPress directory)/i', $content, $matches ) ) {
556 $content = str_replace(
557 $matches[1],
558 $constants . "\n\n" . $matches[1],
559 $content
560 );
561 $inserted = true;
562 }
563
564 // Method 3: Before ABSPATH definition (language-independent)
565 if ( ! $inserted && preg_match( '/(if\s*\(\s*!\s*defined\s*\(\s*[\'"]ABSPATH[\'"]\s*\)\s*\))/i', $content, $matches ) ) {
566 $content = str_replace(
567 $matches[1],
568 $constants . "\n\n" . $matches[1],
569 $content
570 );
571 $inserted = true;
572 }
573
574 // Method 4: Before require_once wp-settings.php (language-independent)
575 if ( ! $inserted && preg_match( '/(require[_once\s\(]+[\'"]?.*wp-settings\.php[\'"]?\s*\)?;)/i', $content, $matches ) ) {
576 $content = str_replace(
577 $matches[1],
578 $constants . "\n\n" . $matches[1],
579 $content
580 );
581 $inserted = true;
582 }
583
584 // Method 5: After $table_prefix (safest fallback)
585 if ( ! $inserted && preg_match( '/(\$table_prefix\s*=\s*[\'"][^\'"]+[\'"]\s*;)/i', $content, $matches ) ) {
586 $content = str_replace(
587 $matches[1],
588 $matches[1] . "\n\n" . $constants,
589 $content
590 );
591 $inserted = true;
592 }
593
594 if ( ! $inserted ) {
595 return new WP_Error( 'insert_failed', __( 'Could not find a safe place to insert constants', 'vigilante' ) );
596 }
597
598 // SAFETY CHECK 5: Final content must still be valid
599 if ( ! $this->validate_wpconfig_content( $content ) ) {
600 return new WP_Error( 'invalid_final', __( 'Final wp-config.php would be invalid, aborting', 'vigilante' ) );
601 }
602
603 // SAFETY CHECK 6: Final content should be at least as big as original (minus our old block)
604 if ( strlen( $content ) < strlen( $original_content ) * 0.5 ) {
605 return new WP_Error( 'size_check_failed', __( 'Final wp-config.php would be too small, aborting', 'vigilante' ) );
606 }
607
608 // All checks passed, write the file
609 if ( $this->write_file_directly( $this->wpconfig_path, $content ) ) {
610 return true;
611 }
612
613 return new WP_Error( 'write_failed', __( 'Failed to write wp-config.php', 'vigilante' ) );
614 }
615
616 /**
617 * Write file directly (more reliable than WP_Filesystem)
618 *
619 * @param string $path File path.
620 * @param string $content Content to write.
621 * @return bool
622 */
623 private function write_file_directly( $path, $content ) {
624 return false !== file_put_contents( $path, $content ); // phpcs:ignore
625 }
626
627 /**
628 * Check if wp-config.php is writable
629 *
630 * @return bool
631 */
632 public function is_wpconfig_writable() {
633 if ( ! file_exists( $this->wpconfig_path ) ) {
634 return false;
635 }
636
637 // Initialize WP_Filesystem
638 global $wp_filesystem;
639 if ( ! function_exists( 'WP_Filesystem' ) ) {
640 require_once ABSPATH . 'wp-admin/includes/file.php';
641 }
642 WP_Filesystem();
643
644 if ( ! $wp_filesystem ) {
645 return false;
646 }
647
648 return $wp_filesystem->is_writable( $this->wpconfig_path );
649 }
650
651 /**
652 * Verify if our constants are currently active
653 *
654 * @return bool
655 */
656 public function are_constants_active() {
657 $content = $this->read_file_directly( $this->wpconfig_path );
658 if ( false === $content ) {
659 return false;
660 }
661 return strpos( $content, self::MARKER_START ) !== false;
662 }
663
664 /**
665 * Get current defined constants status
666 *
667 * @return array
668 */
669 public function get_constants_status() {
670 return array(
671 'DISALLOW_FILE_EDIT' => defined( 'DISALLOW_FILE_EDIT' ) ? DISALLOW_FILE_EDIT : null,
672 'DISALLOW_FILE_MODS' => defined( 'DISALLOW_FILE_MODS' ) ? DISALLOW_FILE_MODS : null,
673 'FORCE_SSL_ADMIN' => defined( 'FORCE_SSL_ADMIN' ) ? FORCE_SSL_ADMIN : null,
674 'FORCE_SSL_LOGIN' => defined( 'FORCE_SSL_LOGIN' ) ? FORCE_SSL_LOGIN : null,
675 'WP_DEBUG' => defined( 'WP_DEBUG' ) ? WP_DEBUG : null,
676 'WP_DEBUG_LOG' => defined( 'WP_DEBUG_LOG' ) ? WP_DEBUG_LOG : null,
677 'WP_DEBUG_DISPLAY' => defined( 'WP_DEBUG_DISPLAY' ) ? WP_DEBUG_DISPLAY : null,
678 );
679 }
680
681 /**
682 * Check if there are commented original constants
683 *
684 * @return bool
685 */
686 public function has_commented_originals() {
687 $content = $this->read_file_directly( $this->wpconfig_path );
688 if ( false === $content ) {
689 return false;
690 }
691 return strpos( $content, self::ORIGINAL_MARKER ) !== false;
692 }
693
694 /**
695 * Get list of commented original constants
696 *
697 * @return array
698 */
699 public function get_commented_originals() {
700 $content = $this->read_file_directly( $this->wpconfig_path );
701 if ( false === $content ) {
702 return array();
703 }
704
705 $originals = array();
706 $pattern = '/' . preg_quote( self::ORIGINAL_MARKER, '/' ) . '(.+)$/m';
707
708 if ( preg_match_all( $pattern, $content, $matches ) ) {
709 $originals = $matches[1];
710 }
711
712 return $originals;
713 }
714 }