/wp-content/plugins/really-simple-ssl/class-admin.php

https://bitbucket.org/carloskikea/helpet · PHP · 2582 lines · 1602 code · 427 blank · 553 comment · 387 complexity · 6e7a5d1bfff3eb272f501b92aecef16c MD5 · raw file

Large files are truncated click here to view the full file

  1. <?php
  2. defined('ABSPATH') or die("you do not have access to this page!");
  3. class rsssl_admin extends rsssl_front_end {
  4. private static $_this;
  5. public $wpconfig_siteurl_not_fixed = FALSE;
  6. public $no_server_variable = FALSE;
  7. public $errors = Array();
  8. public $do_wpconfig_loadbalancer_fix = FALSE;
  9. public $site_has_ssl = FALSE;
  10. public $ssl_enabled = FALSE;
  11. //multisite variables
  12. public $sites = Array(); //for multisite, list of all activated sites.
  13. //general settings
  14. public $capability = 'activate_plugins';
  15. public $ssl_test_page_error;
  16. public $htaccess_test_success = FALSE;
  17. public $plugin_version = rsssl_version; //deprecated, but used in pro plugin until 1.0.25
  18. public $plugin_dir = "really-simple-ssl";
  19. public $plugin_filename = "rlrsssl-really-simple-ssl.php";
  20. public $ABSpath;
  21. public $do_not_edit_htaccess = FALSE;
  22. public $htaccess_redirect = FALSE;
  23. public $htaccess_warning_shown = FALSE;
  24. public $ssl_success_message_shown = FALSE;
  25. public $hsts = FALSE;
  26. public $debug = TRUE;
  27. public $debug_log;
  28. public $plugin_conflict = ARRAY();
  29. public $plugin_db_version;
  30. public $plugin_upgraded;
  31. public $mixed_content_fixer_status = "OK";
  32. public $ssl_type = "NA";
  33. private $pro_url = "https://www.really-simple-ssl.com/pro";
  34. function __construct() {
  35. if ( isset( self::$_this ) )
  36. wp_die( sprintf( __( '%s is a singleton class and you cannot create a second instance.','really-simple-ssl' ), get_class( $this ) ) );
  37. self::$_this = $this;
  38. $this->ABSpath = $this->getABSPATH();
  39. $this->get_options();
  40. $this->get_admin_options();
  41. $this->get_plugin_upgraded(); //call always, otherwise db version will not match anymore.
  42. register_deactivation_hook(dirname( __FILE__ )."/".$this->plugin_filename, array($this,'deactivate') );
  43. }
  44. static function this() {
  45. return self::$_this;
  46. }
  47. /**
  48. * Initializes the admin class
  49. *
  50. * @since 2.2
  51. *
  52. * @access public
  53. *
  54. */
  55. public function init() {
  56. if (!current_user_can($this->capability)) return;
  57. $is_on_settings_page = $this->is_settings_page();
  58. /*
  59. Detect configuration when:
  60. - SSL activation just confirmed.
  61. - on settings page
  62. - No SSL detected
  63. */
  64. //when configuration should run again
  65. if ($this->clicked_activate_ssl() || !$this->ssl_enabled || !$this->site_has_ssl || $is_on_settings_page || is_network_admin()) {
  66. if (is_multisite()) $this->build_domain_list();//has to come after clicked_activate_ssl, otherwise this domain won't get counted.
  67. $this->detect_configuration();
  68. //flush caches when just activated ssl
  69. //flush the permalinks
  70. if ($this->clicked_activate_ssl()) {
  71. if (isset($_POST["rsssl_flush_rewrite_rules"])) {
  72. add_action( 'shutdown', 'flush_rewrite_rules');
  73. }
  74. add_action('admin_init', array(RSSSL()->rsssl_cache,'flush'),40);
  75. }
  76. if (!$this->wpconfig_ok()) {
  77. //if we were to activate ssl, this could result in a redirect loop. So warn first.
  78. add_action("admin_notices", array($this, 'show_notice_wpconfig_needs_fixes'));
  79. if (is_multisite()) add_action('network_admin_notices', array($this, 'show_notice_wpconfig_needs_fixes'), 10);
  80. $this->ssl_enabled = false;
  81. $this->save_options();
  82. } elseif ($this->ssl_enabled) {
  83. add_action('init',array($this,'configure_ssl'),20);
  84. }
  85. }
  86. //when SSL is enabled, and not enabled by user, ask for activation.
  87. add_action("admin_notices", array($this, 'show_notice_activate_ssl'),10);
  88. add_action('plugins_loaded', array($this,'check_plugin_conflicts'),30);
  89. //add the settings page for the plugin
  90. add_action('admin_enqueue_scripts', array($this, 'enqueue_assets'));
  91. add_action('admin_init', array($this, 'load_translation'),20);
  92. add_action('rsssl_configuration_page', array($this, 'configuration_page_more'),10);
  93. //settings page, form and settings link in the plugins page
  94. add_action('admin_menu', array($this, 'add_settings_page'),40);
  95. add_action('admin_init', array($this, 'create_form'),40);
  96. $plugin = rsssl_plugin;
  97. add_filter("plugin_action_links_$plugin", array($this,'plugin_settings_link'));
  98. //check if the uninstallfile is safely renamed to php.
  99. $this->check_for_uninstall_file();
  100. //callbacks for the ajax dismiss buttons
  101. add_action('wp_ajax_dismiss_htaccess_warning', array($this,'dismiss_htaccess_warning_callback') );
  102. add_action('wp_ajax_dismiss_success_message', array($this,'dismiss_success_message_callback') );
  103. //handle notices
  104. add_action('admin_notices', array($this,'show_notices'));
  105. }
  106. //change deprecated function depending on version.
  107. public function get_sites_bw_compatible(){
  108. global $wp_version;
  109. $sites = ($wp_version >= 4.6 ) ? get_sites() : wp_get_sites();
  110. return $sites;
  111. }
  112. /*
  113. The new get_sites function returns an object.
  114. */
  115. public function switch_to_blog_bw_compatible($site){
  116. global $wp_version;
  117. if ($wp_version >= 4.6 ) {
  118. switch_to_blog( $site->blog_id );
  119. } else {
  120. switch_to_blog( $site[ 'blog_id' ] );
  121. }
  122. }
  123. /*
  124. checks if the user just clicked the "activate SSL" button.
  125. */
  126. private function clicked_activate_ssl() {
  127. if (!current_user_can($this->capability)) return;
  128. //if (!isset( $_POST['rsssl_nonce'] ) || !wp_verify_nonce( $_POST['rsssl_nonce'], 'rsssl_nonce' )) return false;
  129. if (isset($_POST['rsssl_do_activate_ssl'])) {
  130. $this->activate_ssl();
  131. return true;
  132. }
  133. return false;
  134. }
  135. /*
  136. Activate the SSL for this site
  137. */
  138. public function activate_ssl(){
  139. $this->ssl_enabled = true;
  140. $this->wp_redirect = true;
  141. $this->set_siteurl_to_ssl();
  142. $this->save_options();
  143. }
  144. public function deactivate_ssl(){
  145. $this->ssl_enabled = false;
  146. $this->wp_redirect = false;
  147. $this->htaccess_redirect = false;
  148. $this->remove_ssl_from_siteurl();
  149. $this->save_options();
  150. }
  151. public function wpconfig_ok(){
  152. if (($this->do_wpconfig_loadbalancer_fix || $this->no_server_variable || $this->wpconfig_siteurl_not_fixed) && !$this->wpconfig_is_writable() ) {
  153. $result = false;
  154. } else {
  155. $result = true;
  156. }
  157. return apply_filters('rsssl_wpconfig_ok_check', $result);
  158. }
  159. /*
  160. This message is shown when no SSL is not enabled by the user yet
  161. */
  162. public function show_notice_activate_ssl(){
  163. if ($this->ssl_enabled) return;
  164. if (defined("RSSSL_DISMISS_ACTIVATE_SSL_NOTICE") && RSSSL_DISMISS_ACTIVATE_SSL_NOTICE) return;
  165. //for multisite, show only activate when a choice has been made to activate networkwide or per site.
  166. if (is_multisite() && !RSSSL()->rsssl_multisite->selected_networkwide_or_per_site) return;
  167. //on multistie, only show this message on the network admin. Per site activated sites have to go to the settings page.
  168. //otherwise sites that do not need SSL possibly get to see this message.
  169. if (is_multisite() && !is_network_admin()) return;
  170. if (!$this->wpconfig_ok()) return;
  171. if (!current_user_can($this->capability)) return;
  172. if (!$this->site_has_ssl) {
  173. global $wp;
  174. $current_url = "https://".$_SERVER["HTTP_HOST"].$_SERVER["REQUEST_URI"];
  175. ?>
  176. <div id="message" class="error fade notice activate-ssl">
  177. <p><?php _e("No SSL was detected. If you do have an SSL certificate, try to reload this page over https by clicking this link:","really-simple-ssl");?>&nbsp;<a href="<?php echo $current_url?>"><?php _e("reload over https.","really-simple-ssl");?></a>
  178. <?php _e("You can check your certificate on","really-simple-ssl");?>&nbsp;<a target="_blank" href="https://www.ssllabs.com/ssltest/">Qualys SSL Labs</a>
  179. </p>
  180. </div>
  181. <?php } ?>
  182. <div id="message" class="updated fade notice activate-ssl">
  183. <?php if ($this->site_has_ssl) { ?>
  184. <h1><?php _e("Almost ready to migrate to SSL!","really-simple-ssl");?></h1>
  185. <?php } ?>
  186. <?php _e("Some things can't be done automatically. Before you migrate, please check for: ",'really-simple-ssl');?>
  187. <p>
  188. <ul>
  189. <li><?php _e('Http references in your .css and .js files: change any http:// into //','really-simple-ssl');?></li>
  190. <li><?php _e('Images, stylesheets or scripts from a domain without an SSL certificate: remove them or move to your own server.','really-simple-ssl');?></li><?php
  191. $backup_link = "https://really-simple-ssl.com/knowledge-base/backing-up-your-site/";
  192. $link_open = '<a target="_blank" href="'.$backup_link.'">';
  193. $link_close = '</a>';
  194. ?> <li> <?php printf(__("It is recommended to take a %sbackup%s of your site before activating SSL", 'really-simple-ssl'), $link_open, $link_close); ?> </li>
  195. </ul>
  196. </p>
  197. <?php $this->show_pro(); ?>
  198. <?php RSSSL()->really_simple_ssl->show_enable_ssl_button();?>
  199. </div>
  200. <?php }
  201. /**
  202. * @since 2.3
  203. * Returns button to enable SSL.
  204. */
  205. public function show_enable_ssl_button(){
  206. if ($this->site_has_ssl || (defined('rsssl_force_activate') && rsssl_force_activate)) {
  207. ?>
  208. <p>
  209. <form action="" method="post">
  210. <?php wp_nonce_field( 'rsssl_nonce', 'rsssl_nonce' );?>
  211. <div>
  212. <input type="checkbox" name="rsssl_flush_rewrite_rules" checked><label><?php _e("Flush rewrite rules on activation (deselect when you encounter errors)","really-simple-ssl")?></label>
  213. </div>
  214. <input type="submit" class='button button-primary' value="<?php _e("Go ahead, activate SSL!","really-simple-ssl");?>" id="rsssl_do_activate_ssl" name="rsssl_do_activate_ssl">
  215. <br><?php _e("You may need to login in again.", "really-simple-ssl")?>
  216. </form>
  217. </p>
  218. <?php
  219. }
  220. }
  221. /**
  222. * @since 2.3
  223. * Shows option to buy pro
  224. */
  225. public function show_pro(){
  226. if ( !defined("rsssl_pro_version") ) {
  227. ?>
  228. <p><?php _e('You can also let the automatic scan of the pro version handle this for you, and get premium support, increased security with HSTS and more!','really-simple-ssl');?>&nbsp;<a target="_blank" href="<?php echo $this->pro_url;?>"><?php _e("Check out Really Simple SSL Premium","really-simple-ssl");?></a></p>
  229. <?php
  230. }
  231. }
  232. public function wpconfig_is_writable() {
  233. $wpconfig_path = $this->find_wp_config_path();
  234. if (is_writable($wpconfig_path))
  235. return true;
  236. else
  237. return false;
  238. }
  239. /*
  240. * Check if the uninstall file is renamed to .php
  241. */
  242. protected function check_for_uninstall_file() {
  243. if (file_exists(dirname( __FILE__ ) . '/force-deactivate.php')) {
  244. $this->errors["DEACTIVATE_FILE_NOT_RENAMED"] = true;
  245. }
  246. }
  247. /**
  248. * Get the options for this plugin
  249. *
  250. * @since 2.0
  251. *
  252. * @access public
  253. *
  254. */
  255. public function get_admin_options(){
  256. $options = get_option('rlrsssl_options');
  257. if (isset($options)) {
  258. $this->site_has_ssl = isset($options['site_has_ssl']) ? $options['site_has_ssl'] : FALSE;
  259. $this->hsts = isset($options['hsts']) ? $options['hsts'] : FALSE;
  260. $this->htaccess_warning_shown = isset($options['htaccess_warning_shown']) ? $options['htaccess_warning_shown'] : FALSE;
  261. $this->ssl_success_message_shown = isset($options['ssl_success_message_shown']) ? $options['ssl_success_message_shown'] : FALSE;
  262. $this->plugin_db_version = isset($options['plugin_db_version']) ? $options['plugin_db_version'] : "1.0";
  263. $this->debug = isset($options['debug']) ? $options['debug'] : FALSE;
  264. $this->do_not_edit_htaccess = isset($options['do_not_edit_htaccess']) ? $options['do_not_edit_htaccess'] : FALSE;
  265. $this->htaccess_redirect = isset($options['htaccess_redirect']) ? $options['htaccess_redirect'] : FALSE;
  266. $this->switch_mixed_content_fixer_hook = isset($options['switch_mixed_content_fixer_hook']) ? $options['switch_mixed_content_fixer_hook'] : FALSE;
  267. $this->debug_log = isset($options['debug_log']) ? $options['debug_log'] : $this->debug_log;
  268. }
  269. if (is_multisite()) {
  270. $network_options = get_site_option('rlrsssl_network_options');
  271. $network_htaccess_redirect = isset($network_options["htaccess_redirect"]) ? $network_options["htaccess_redirect"] : false;
  272. $network_do_not_edit_htaccess = isset($network_options["do_not_edit_htaccess"]) ? $network_options["do_not_edit_htaccess"] : false;
  273. /*
  274. If multiste, and networkwide, only the networkwide setting counts.
  275. if multisite, and per site, only the networkwide setting counts if it is true.
  276. */
  277. $ssl_enabled_networkwide = isset($network_options["ssl_enabled_networkwide"]) ? $network_options["ssl_enabled_networkwide"] : false;
  278. if ($ssl_enabled_networkwide) {
  279. $this->htaccess_redirect = $network_htaccess_redirect;
  280. $this->do_not_edit_htaccess = $network_do_not_edit_htaccess;
  281. } else {
  282. if ($network_do_not_edit_htaccess) $this->do_not_edit_htaccess = $network_do_not_edit_htaccess;
  283. if ($network_htaccess_redirect) $this->htaccess_redirect = $network_htaccess_redirect;
  284. }
  285. }
  286. //if the define is true, it overrides the db setting.
  287. if (defined( 'RLRSSSL_DO_NOT_EDIT_HTACCESS')) {
  288. $this->do_not_edit_htaccess = RLRSSSL_DO_NOT_EDIT_HTACCESS;
  289. }
  290. }
  291. /**
  292. * Creates an array of all domains where the plugin is active AND SSL is active, only used for multisite.
  293. *
  294. * @since 2.1
  295. *
  296. * @access public
  297. *
  298. */
  299. public function build_domain_list() {
  300. if (!is_multisite()) return;
  301. //create list of all activated sites with SSL
  302. $this->sites = array();
  303. $sites = $this->get_sites_bw_compatible();
  304. if ($this->debug) $this->trace_log("building domain list for multisite...");
  305. foreach ( $sites as $site ) {
  306. $this->switch_to_blog_bw_compatible($site);
  307. $options = get_option('rlrsssl_options');
  308. $ssl_enabled = FALSE;
  309. if (isset($options)) {
  310. $site_has_ssl = isset($options['site_has_ssl']) ? $options['site_has_ssl'] : FALSE;
  311. $ssl_enabled = isset($options['ssl_enabled']) ? $options['ssl_enabled'] : $site_has_ssl;
  312. }
  313. if (is_plugin_active(rsssl_plugin) && $ssl_enabled) {
  314. if ($this->debug) $this->trace_log("adding: ".home_url());
  315. $this->sites[] = home_url();
  316. }
  317. restore_current_blog(); //switches back to previous blog, not current, so we have to do it each loop
  318. }
  319. $this->save_options();
  320. }
  321. /**
  322. * check if the plugin was upgraded to a new version
  323. *
  324. * @since 2.1
  325. *
  326. * @access public
  327. *
  328. */
  329. public function get_plugin_upgraded() {
  330. if ($this->plugin_db_version!= rsssl_version) {
  331. $this->plugin_db_version = rsssl_version;
  332. $this->plugin_upgraded = true;
  333. $this->save_options();
  334. }
  335. $this->plugin_upgraded = false;
  336. }
  337. /**
  338. * Log events during plugin execution
  339. *
  340. * @since 2.1
  341. *
  342. * @access public
  343. *
  344. */
  345. public function trace_log($msg) {
  346. if (!$this->debug) return;
  347. $this->debug_log = $this->debug_log."<br>".$msg;
  348. $this->debug_log = strstr($this->debug_log,'** Detecting configuration **');
  349. error_log($msg);
  350. }
  351. /**
  352. * Configures the site for SSL
  353. *
  354. * @since 2.2
  355. *
  356. * @access public
  357. *
  358. */
  359. public function configure_ssl() {
  360. if (!current_user_can($this->capability)) return;
  361. $safe_mode = FALSE;
  362. if (defined('RSSSL_SAFE_MODE') && RSSSL_SAFE_MODE) $safe_mode = RSSSL_SAFE_MODE;
  363. if (!current_user_can($this->capability)) return;
  364. $this->trace_log("** Configuring SSL **");
  365. if ($this->site_has_ssl) {
  366. //when one of the used server variables was found, test if the redirect works
  367. if (RSSSL()->rsssl_server->uses_htaccess() && $this->ssl_type != "NA")
  368. $this->test_htaccess_redirect();
  369. //in a configuration reverse proxy without a set server variable https, add code to wpconfig
  370. if ($this->do_wpconfig_loadbalancer_fix){
  371. $this->wpconfig_loadbalancer_fix();
  372. }
  373. if ($this->no_server_variable)
  374. $this->wpconfig_server_variable_fix();
  375. if (!$safe_mode) {
  376. $this->editHtaccess();
  377. }
  378. if (!$safe_mode && $this->clicked_activate_ssl()) {
  379. $this->wp_redirect = TRUE;
  380. $this->save_options();
  381. }
  382. if (!$safe_mode && $this->wpconfig_siteurl_not_fixed)
  383. $this->fix_siteurl_defines_in_wpconfig();
  384. if (!$safe_mode) {
  385. $this->set_siteurl_to_ssl();
  386. }
  387. }
  388. }
  389. /**
  390. * Check to see if we are on the settings page, action hook independent
  391. *
  392. * @since 2.1
  393. *
  394. * @access public
  395. *
  396. */
  397. public function is_settings_page() {
  398. if (!isset($_SERVER['QUERY_STRING'])) return false;
  399. parse_str($_SERVER['QUERY_STRING'], $params);
  400. if (array_key_exists("page", $params) && ($params["page"]=="rlrsssl_really_simple_ssl")) {
  401. return true;
  402. }
  403. return false;
  404. }
  405. /**
  406. * Find the path to wp-config
  407. *
  408. * @since 2.1
  409. *
  410. * @access public
  411. *
  412. */
  413. public function find_wp_config_path() {
  414. //limit nr of iterations to 20
  415. $i=0;
  416. $maxiterations = 20;
  417. $dir = dirname(__FILE__);
  418. do {
  419. $i++;
  420. if( file_exists($dir."/wp-config.php") ) {
  421. return $dir."/wp-config.php";
  422. }
  423. } while( ($dir = realpath("$dir/..")) && ($i<$maxiterations) );
  424. return null;
  425. }
  426. /**
  427. * remove https from defined siteurl and homeurl in the wpconfig, if present
  428. *
  429. * @since 2.1
  430. *
  431. * @access public
  432. *
  433. */
  434. public function remove_ssl_from_siteurl_in_wpconfig() {
  435. if (!current_user_can($this->capability)) return;
  436. $wpconfig_path = $this->find_wp_config_path();
  437. if (!empty($wpconfig_path)) {
  438. $wpconfig = file_get_contents($wpconfig_path);
  439. $homeurl_pos = strpos($wpconfig, "define('WP_HOME','https://");
  440. $siteurl_pos = strpos($wpconfig, "define('WP_SITEURL','https://");
  441. if (($homeurl_pos !== false) || ($siteurl_pos !== false)) {
  442. if (is_writable($wpconfig_path)) {
  443. $search_array = array("define('WP_HOME','https://","define('WP_SITEURL','https://");
  444. $ssl_array = array("define('WP_HOME','http://","define('WP_SITEURL','http://");
  445. //now replace these urls
  446. $wpconfig = str_replace ($search_array , $ssl_array , $wpconfig);
  447. file_put_contents($wpconfig_path, $wpconfig);
  448. } else {
  449. $this->errors['wpconfig not writable'] = TRUE;
  450. }
  451. }
  452. }
  453. }
  454. /**
  455. *
  456. * Checks if the wp config contains any defined siteurl and homeurl
  457. *
  458. *
  459. */
  460. private function check_for_siteurl_in_wpconfig(){
  461. $wpconfig_path = $this->find_wp_config_path();
  462. if (empty($wpconfig_path)) return;
  463. $wpconfig = file_get_contents($wpconfig_path);
  464. $homeurl_pattern = '/(define\(\s*\'WP_HOME\'\s*,\s*\'http\:\/\/)/';
  465. $siteurl_pattern = '/(define\(\s*\'WP_SITEURL\'\s*,\s*\'http\:\/\/)/';
  466. $this->wpconfig_siteurl_not_fixed = FALSE;
  467. if (preg_match($homeurl_pattern, $wpconfig) || preg_match($siteurl_pattern, $wpconfig) ) {
  468. $this->wpconfig_siteurl_not_fixed = TRUE;
  469. $this->trace_log("siteurl or home url defines found in wpconfig");
  470. }
  471. }
  472. /**
  473. * Runs only when siteurl or homeurl define was found in the wpconfig, with the check_for_siteurl_in_wpconfig function
  474. * and only when wpconfig is writable.
  475. *
  476. * @since 2.1
  477. *
  478. * @access public
  479. *
  480. */
  481. private function fix_siteurl_defines_in_wpconfig() {
  482. $wpconfig_path = $this->find_wp_config_path();
  483. if (empty($wpconfig_path)) return;
  484. $wpconfig = file_get_contents($wpconfig_path);
  485. $homeurl_pattern = '/(define\(\s*\'WP_HOME\'\s*,\s*\'http\:\/\/)/';
  486. $siteurl_pattern = '/(define\(\s*\'WP_SITEURL\'\s*,\s*\'http\:\/\/)/';
  487. if (preg_match($homeurl_pattern, $wpconfig) || preg_match($siteurl_pattern, $wpconfig) ) {
  488. if (is_writable($wpconfig_path)) {
  489. $this->trace_log("wp config siteurl/homeurl edited.");
  490. $wpconfig = preg_replace($homeurl_pattern, "define('WP_HOME','https://", $wpconfig);
  491. $wpconfig = preg_replace($siteurl_pattern, "define('WP_SITEURL','https://", $wpconfig);
  492. file_put_contents($wpconfig_path, $wpconfig);
  493. }
  494. else {
  495. if ($this->debug) {$this->trace_log("not able to fix wpconfig siteurl/homeurl.");}
  496. //only when siteurl or homeurl is defined in wpconfig, and wpconfig is not writable is there a possible issue because we cannot edit the defined urls.
  497. $this->wpconfig_siteurl_not_fixed = TRUE;
  498. }
  499. } else {
  500. if ($this->debug) {$this->trace_log("no siteurl/homeurl defines in wpconfig");}
  501. }
  502. }
  503. /**
  504. * Check if the wpconfig is already fixed
  505. *
  506. * @since 2.2
  507. *
  508. * @access public
  509. *
  510. */
  511. public function wpconfig_has_fixes() {
  512. $wpconfig_path = $this->find_wp_config_path();
  513. if (empty($wpconfig_path)) return false;
  514. $wpconfig = file_get_contents($wpconfig_path);
  515. //only one of two fixes possible.
  516. if (strpos($wpconfig, "//Begin Really Simple SSL Load balancing fix")!==FALSE ) {
  517. return true;
  518. }
  519. if (strpos($wpconfig, "//Begin Really Simple SSL Server variable fix")!==FALSE ) {
  520. return true;
  521. }
  522. return false;
  523. }
  524. /**
  525. * In case of load balancer without server https on, add fix in wp-config
  526. *
  527. * @since 2.1
  528. *
  529. * @access public
  530. *
  531. */
  532. public function wpconfig_loadbalancer_fix() {
  533. if (!current_user_can($this->capability)) return;
  534. $wpconfig_path = $this->find_wp_config_path();
  535. if (empty($wpconfig_path)) return;
  536. $wpconfig = file_get_contents($wpconfig_path);
  537. $this->wpconfig_loadbalancer_fix_failed = FALSE;
  538. //only if loadbalancer AND NOT SERVER-HTTPS-ON should the following be added. (is_ssl = false)
  539. if (strpos($wpconfig, "//Begin Really Simple SSL Load balancing fix")===FALSE ) {
  540. if (is_writable($wpconfig_path)) {
  541. $rule = "\n"."//Begin Really Simple SSL Load balancing fix"."\n";
  542. $rule .= '$server_opts = array("HTTP_CLOUDFRONT_FORWARDED_PROTO" => "https", "HTTP_CF_VISITOR"=>"https", "HTTP_X_FORWARDED_PROTO"=>"https", "HTTP_X_FORWARDED_SSL"=>"on", "HTTP_X_FORWARDED_SSL"=>"1");'."\n";
  543. $rule .= 'foreach( $server_opts as $option => $value ) {'."\n";
  544. $rule .= 'if ( (isset($_ENV["HTTPS"]) && ( "on" == $_ENV["HTTPS"] )) || (isset( $_SERVER[ $option ] ) && ( strpos( $_SERVER[ $option ], $value ) !== false )) ) {'."\n";
  545. $rule .= '$_SERVER[ "HTTPS" ] = "on";'."\n";
  546. $rule .= 'break;'."\n";
  547. $rule .= '}'."\n";
  548. $rule .= '}'."\n";
  549. $rule .= "//END Really Simple SSL"."\n";
  550. $insert_after = "<?php";
  551. $pos = strpos($wpconfig, $insert_after);
  552. if ($pos !== false) {
  553. $wpconfig = substr_replace($wpconfig,$rule,$pos+1+strlen($insert_after),0);
  554. }
  555. file_put_contents($wpconfig_path, $wpconfig);
  556. if ($this->debug) {$this->trace_log("wp config loadbalancer fix inserted");}
  557. } else {
  558. if ($this->debug) {$this->trace_log("wp config loadbalancer fix FAILED");}
  559. $this->wpconfig_loadbalancer_fix_failed = TRUE;
  560. }
  561. } else {
  562. if ($this->debug) {$this->trace_log("wp config loadbalancer fix already in place, great!");}
  563. }
  564. $this->save_options();
  565. }
  566. /**
  567. * Getting WordPress to recognize setup as being SSL when no https server variable is available
  568. *
  569. * @since 2.1
  570. *
  571. * @access public
  572. *
  573. */
  574. public function wpconfig_server_variable_fix() {
  575. if (!current_user_can($this->capability)) return;
  576. $wpconfig_path = $this->find_wp_config_path();
  577. if (empty($wpconfig_path)) return;
  578. $wpconfig = file_get_contents($wpconfig_path);
  579. //check permissions
  580. if (!is_writable($wpconfig_path)) {
  581. if ($this->debug) $this->trace_log("wp-config.php not writable");
  582. return;
  583. }
  584. //when more than one blog, first remove what we have
  585. if (is_multisite() && !RSSSL()->rsssl_multisite->is_multisite_subfolder_install() && !RSSSL()->rsssl_multisite->ssl_enabled_networkwide && count($this->sites)>1) {
  586. $wpconfig = preg_replace("/\/\/Begin\s?Really\s?Simple\s?SSL.*?\/\/END\s?Really\s?Simple\s?SSL/s", "", $wpconfig);
  587. $wpconfig = preg_replace("/\n+/","\n", $wpconfig);
  588. file_put_contents($wpconfig_path, $wpconfig);
  589. }
  590. //now create new
  591. //check if the fix is already there
  592. if (strpos($wpconfig, "//Begin Really Simple SSL Server variable fix")!==FALSE ) {
  593. if ($this->debug) {$this->trace_log("wp config server variable fix already in place, great!");}
  594. return;
  595. }
  596. if ($this->debug) {$this->trace_log("Adding server variable to wpconfig");}
  597. $rule = $this->get_server_variable_fix_code();
  598. $insert_after = "<?php";
  599. $pos = strpos($wpconfig, $insert_after);
  600. if ($pos !== false) {
  601. $wpconfig = substr_replace($wpconfig,$rule,$pos+1+strlen($insert_after),0);
  602. }
  603. file_put_contents($wpconfig_path, $wpconfig);
  604. if ($this->debug) $this->trace_log("wp config server variable fix inserted");
  605. $this->save_options();
  606. }
  607. protected function get_server_variable_fix_code(){
  608. if (is_multisite() && !RSSSL()->rsssl_multisite->ssl_enabled_networkwide && RSSSL()->rsssl_multisite->is_multisite_subfolder_install()) {
  609. if ($this->debug) $this->trace_log("per site activation on subfolder install, wp config server variable fix skipped");
  610. return "";
  611. }
  612. if (is_multisite() && !RSSSL()->rsssl_multisite->ssl_enabled_networkwide && count($this->sites)==0) {
  613. if ($this->debug) $this->trace_log("no sites left with SSL, wp config server variable fix skipped");
  614. return "";
  615. }
  616. if (is_multisite() && !RSSSL()->rsssl_multisite->ssl_enabled_networkwide) {
  617. $rule = "\n"."//Begin Really Simple SSL Server variable fix"."\n";
  618. foreach ($this->sites as $domain ) {
  619. //remove http or https.
  620. if ($this->debug) {$this->trace_log("getting server variable rule for:".$domain);}
  621. $domain = preg_replace("/(http:\/\/|https:\/\/)/","",$domain);
  622. //we excluded subfolders, so treat as domain
  623. //check only for domain without www, as the www variant is found as well with the no www search.
  624. $domain_no_www = str_replace ( "www." , "" , $domain);
  625. $rule .= 'if ( strpos($_SERVER["HTTP_HOST"], "'.$domain_no_www.'")!==FALSE ) {'."\n";
  626. $rule .= ' $_SERVER["HTTPS"] = "on";'."\n";
  627. $rule .= '}'."\n";
  628. }
  629. $rule .= "//END Really Simple SSL"."\n";
  630. } else {
  631. $rule = "\n"."//Begin Really Simple SSL Server variable fix"."\n";
  632. $rule .= '$_SERVER["HTTPS"] = "on";'."\n";
  633. $rule .= "//END Really Simple SSL"."\n";
  634. }
  635. return $rule;
  636. }
  637. /**
  638. * Removing changes made to the wpconfig
  639. *
  640. * @since 2.1
  641. *
  642. * @access public
  643. *
  644. */
  645. public function remove_wpconfig_edit() {
  646. $wpconfig_path = $this->find_wp_config_path();
  647. if (empty($wpconfig_path)) return;
  648. $wpconfig = file_get_contents($wpconfig_path);
  649. //check for permissions
  650. if (!is_writable($wpconfig_path)) {
  651. if ($this->debug) $this->trace_log("could not remove wpconfig edits, wp-config.php not writable");
  652. $this->errors['wpconfig not writable'] = TRUE;
  653. return;
  654. }
  655. //remove edits
  656. $wpconfig = preg_replace("/\/\/Begin\s?Really\s?Simple\s?SSL.*?\/\/END\s?Really\s?Simple\s?SSL/s", "", $wpconfig);
  657. $wpconfig = preg_replace("/\n+/","\n", $wpconfig);
  658. file_put_contents($wpconfig_path, $wpconfig);
  659. //in multisite environment, with per site activation, re-add
  660. if (is_multisite() && ! RSSSL()->rsssl_multisite->ssl_enabled_networkwide) {
  661. if ($this->do_wpconfig_loadbalancer_fix)
  662. $this->wpconfig_loadbalancer_fix();
  663. if ($this->no_server_variable)
  664. $this->wpconfig_server_variable_fix();
  665. }
  666. }
  667. /**
  668. * Changes the siteurl and homeurl to https
  669. *
  670. * @since 2.0
  671. *
  672. * @access public
  673. *
  674. */
  675. public function set_siteurl_to_ssl() {
  676. if (!current_user_can($this->capability)) return;
  677. $this->trace_log("converting siteurl and homeurl to https");
  678. $siteurl_ssl = str_replace ( "http://" , "https://" , get_option('siteurl'));
  679. $homeurl_ssl = str_replace ( "http://" , "https://" , get_option('home'));
  680. update_option('siteurl',$siteurl_ssl);
  681. update_option('home',$homeurl_ssl);
  682. }
  683. /**
  684. * On de-activation, siteurl and homeurl are reset to http
  685. *
  686. * @since 2.0
  687. *
  688. * @access public
  689. *
  690. */
  691. public function remove_ssl_from_siteurl() {
  692. $siteurl_no_ssl = str_replace ( "https://" , "http://" , get_option('siteurl'));
  693. $homeurl_no_ssl = str_replace ( "https://" , "http://" , get_option('home'));
  694. update_option('siteurl',$siteurl_no_ssl);
  695. update_option('home',$homeurl_no_ssl);
  696. }
  697. /**
  698. * Save the plugin options
  699. *
  700. * @since 2.0
  701. *
  702. * @access public
  703. *
  704. */
  705. public function save_options() {
  706. if (!current_user_can($this->capability)) return;
  707. //any options added here should also be added to function options_validate()
  708. $options = array(
  709. 'site_has_ssl' => $this->site_has_ssl,
  710. 'hsts' => $this->hsts,
  711. 'htaccess_warning_shown' => $this->htaccess_warning_shown,
  712. 'ssl_success_message_shown' => $this->ssl_success_message_shown,
  713. 'autoreplace_insecure_links' => $this->autoreplace_insecure_links,
  714. 'plugin_db_version' => $this->plugin_db_version,
  715. 'debug' => $this->debug,
  716. 'do_not_edit_htaccess' => $this->do_not_edit_htaccess,
  717. 'htaccess_redirect' => $this->htaccess_redirect,
  718. 'ssl_enabled' => $this->ssl_enabled,
  719. 'javascript_redirect' => $this->javascript_redirect,
  720. 'wp_redirect' => $this->wp_redirect,
  721. 'switch_mixed_content_fixer_hook' => $this->switch_mixed_content_fixer_hook,
  722. );
  723. update_option('rlrsssl_options',$options);
  724. }
  725. /**
  726. * Load the translation files
  727. *
  728. * @since 1.0
  729. *
  730. * @access public
  731. *
  732. */
  733. public function load_translation()
  734. {
  735. load_plugin_textdomain('really-simple-ssl', FALSE, dirname(plugin_basename(__FILE__)).'/languages/');
  736. }
  737. /**
  738. * Handles deactivation of this plugin
  739. *
  740. * @since 2.0
  741. *
  742. * @access public
  743. *
  744. */
  745. public function deactivate($networkwide) {
  746. $this->remove_ssl_from_siteurl();
  747. $this->remove_ssl_from_siteurl_in_wpconfig();
  748. $this->site_has_ssl = FALSE;
  749. $this->hsts = FALSE;
  750. $this->htaccess_warning_shown = FALSE;
  751. $this->ssl_success_message_shown = FALSE;
  752. $this->autoreplace_insecure_links = TRUE;
  753. $this->do_not_edit_htaccess = FALSE;
  754. $this->htaccess_redirect = FALSE;
  755. $this->javascript_redirect = FALSE;
  756. $this->wp_redirect = FALSE;
  757. $this->ssl_enabled = FALSE;
  758. $this->switch_mixed_content_fixer_hook = FALSE;
  759. $this->save_options();
  760. //when on multisite, per site activation, recreate domain list for htaccess and wpconfig rewrite actions
  761. if (is_multisite()) {
  762. RSSSL()->rsssl_multisite->deactivate();
  763. if (!RSSSL()->rsssl_multisite->ssl_enabled_networkwide) $this->build_domain_list();
  764. }
  765. $this->remove_wpconfig_edit();
  766. $this->removeHtaccessEdit();
  767. }
  768. /**
  769. * Checks if we are currently on SSL protocol, but extends standard wp with loadbalancer check.
  770. *
  771. * @since 2.0
  772. *
  773. * @access public
  774. *
  775. */
  776. public function is_ssl_extended(){
  777. $server_var = FALSE;
  778. $server_opts = array(
  779. 'HTTP_X_FORWARDED_PROTO'=>'https',
  780. 'HTTP_CLOUDFRONT_FORWARDED_PROTO' => 'https',
  781. 'HTTP_CF_VISITOR'=>'https',
  782. 'HTTP_X_FORWARDED_SSL'=>'on',
  783. 'HTTP_X_FORWARDED_SSL'=>'1'
  784. );
  785. foreach( $server_opts as $option => $value ) {
  786. if ( (isset($_ENV['HTTPS']) && ( 'on' == $_ENV['HTTPS'] ))
  787. || (isset( $_SERVER[ $option ] ) && ( strpos( $_SERVER[ $option ], $value ) !== false ) )) {
  788. $server_var = TRUE;
  789. break;
  790. }
  791. }
  792. if (is_ssl() || $server_var){
  793. return true;
  794. } else {
  795. return false;
  796. }
  797. }
  798. /**
  799. * Checks for SSL by opening a test page in the plugin directory
  800. *
  801. * @since 2.0
  802. *
  803. * @access public
  804. *
  805. */
  806. public function detect_configuration() {
  807. $this->trace_log("** Detecting configuration **");
  808. $this->trace_log("plugin version: ".rsssl_version);
  809. $old_ssl_setting = $this->site_has_ssl;
  810. $filecontents = "";
  811. //if current page is on SSL, we can assume SSL is available, even when an errormsg was returned
  812. if($this->is_ssl_extended()){
  813. $this->trace_log("Already on SSL, start detecting configuration");
  814. $this->site_has_ssl = TRUE;
  815. } else {
  816. //we're not on SSL, or no server vars were returned, so test with the test-page.
  817. //plugin url: domain.com/wp-content/etc
  818. $testpage_url = trailingslashit($this->test_url())."ssl-test-page.php";
  819. $this->trace_log("Opening testpage to check for SSL: ".$testpage_url);
  820. $response = wp_remote_get( $testpage_url );
  821. if( is_array($response) ) {
  822. $status = wp_remote_retrieve_response_code( $response );
  823. $filecontents = wp_remote_retrieve_body($response);
  824. }
  825. $this->trace_log("test page url, enter in browser to check manually: ".$testpage_url);
  826. if(!is_wp_error( $response ) && (strpos($filecontents, "#SSL TEST PAGE#") !== false)) {
  827. $this->site_has_ssl = TRUE;
  828. $this->trace_log("SSL test page loaded successfully");
  829. } else {
  830. $this->site_has_ssl = FALSE;
  831. $error = "";
  832. if (is_wp_error( $response ) ) $error = $response->get_error_message();
  833. $this->trace_log("No SSL detected. No certificate, or the testpage is blocked by security settings. The SSL testpage returned the error: ".$error);
  834. }
  835. }
  836. if ($this->site_has_ssl) {
  837. //check the type of SSL, either by parsing the returned string, or by reading the server vars.
  838. if ((strpos($filecontents, "#CLOUDFRONT#") !== false) || (isset($_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO']) && ($_SERVER['HTTP_CLOUDFRONT_FORWARDED_PROTO'] == 'https'))) {
  839. $this->ssl_type = "CLOUDFRONT";
  840. } elseif ((strpos($filecontents, "#CLOUDFLARE#") !== false) || (isset($_SERVER['HTTP_CF_VISITOR']) && ($_SERVER['HTTP_CF_VISITOR'] == 'https'))) {
  841. $this->ssl_type = "CLOUDFLARE";
  842. } elseif ((strpos($filecontents, "#LOADBALANCER#") !== false) || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'))) {
  843. $this->ssl_type = "LOADBALANCER";
  844. } elseif ((strpos($filecontents, "#CDN#") !== false) || (isset($_SERVER['HTTP_X_FORWARDED_SSL']) && ($_SERVER['HTTP_X_FORWARDED_SSL'] == 'on' || $_SERVER['HTTP_X_FORWARDED_SSL'] == '1'))) {
  845. $this->ssl_type = "CDN";
  846. } elseif ((strpos($filecontents, "#SERVER-HTTPS-ON#") !== false) || (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on')) {
  847. $this->ssl_type = "SERVER-HTTPS-ON";
  848. } elseif ((strpos($filecontents, "#SERVER-HTTPS-1#") !== false) || (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == '1')) {
  849. $this->ssl_type = "SERVER-HTTPS-1";
  850. } elseif ((strpos($filecontents, "#SERVERPORT443#") !== false) || (isset($_SERVER['SERVER_PORT']) && ( '443' == $_SERVER['SERVER_PORT'] ))) {
  851. $this->ssl_type = "SERVERPORT443";
  852. } elseif ((strpos($filecontents, "#ENVHTTPS#") !== false) || (isset($_ENV['HTTPS']) && ( 'on' == $_ENV['HTTPS'] ))) {
  853. $this->ssl_type = "ENVHTTPS";
  854. } elseif ((strpos($filecontents, "#NO KNOWN SSL CONFIGURATION DETECTED#") !== false)) {
  855. //if we are here, SSL was detected, but without any known server variables set.
  856. //So we can use this info to set a server variable ourselfes.
  857. if (!$this->wpconfig_has_fixes()) {
  858. $this->no_server_variable = TRUE;
  859. }
  860. $this->trace_log("No server variable detected ");
  861. $this->ssl_type = "NA";
  862. } else {
  863. //no valid response, so set to NA
  864. $this->ssl_type = "NA";
  865. }
  866. //check for is_ssl()
  867. if ( (!$this->is_ssl_extended() &&
  868. (strpos($filecontents, "#SERVER-HTTPS-ON#") === false) &&
  869. (strpos($filecontents, "#SERVER-HTTPS-1#") === false) &&
  870. (strpos($filecontents, "#SERVERPORT443#") === false)) || (!is_ssl() && $this->is_ssl_extended())) {
  871. //when is_ssl would return false, we should add some code to wp-config.php
  872. if (!$this->wpconfig_has_fixes()) {
  873. $this->trace_log("is_ssl() will return false: wp-config fix needed");
  874. $this->do_wpconfig_loadbalancer_fix = TRUE;
  875. }
  876. }
  877. $this->trace_log("SSL type: ".$this->ssl_type);
  878. }
  879. $this->check_for_siteurl_in_wpconfig();
  880. $this->save_options();
  881. }
  882. /**
  883. * Test if the htaccess redirect will work
  884. * This way, no redirect loops should occur.
  885. *
  886. * @since 2.1
  887. *
  888. * @access public
  889. *
  890. */
  891. public function test_htaccess_redirect() {
  892. if (!current_user_can($this->capability)) return;
  893. if ($this->debug) {$this->trace_log("testing htaccess rules...");}
  894. $filecontents = "";
  895. $testpage_url = trailingslashit($this->test_url())."testssl/";
  896. switch ($this->ssl_type) {
  897. case "CLOUDFRONT":
  898. $testpage_url .= "cloudfront";
  899. break;
  900. case "CLOUDFLARE":
  901. $testpage_url .= "cloudflare";
  902. break;
  903. case "LOADBALANCER":
  904. $testpage_url .= "loadbalancer";
  905. break;
  906. case "CDN":
  907. $testpage_url .= "cdn";
  908. break;
  909. case "SERVER-HTTPS-ON":
  910. $testpage_url .= "serverhttpson";
  911. break;
  912. case "SERVER-HTTPS-1":
  913. $testpage_url .= "serverhttps1";
  914. break;
  915. case "SERVERPORT443":
  916. $testpage_url .= "serverport443";
  917. break;
  918. case "ENVHTTPS":
  919. $testpage_url .= "envhttps";
  920. break;
  921. }
  922. $testpage_url .= ("/ssl-test-page.html");
  923. $response = wp_remote_get( $testpage_url );
  924. if( is_array($response) ) {
  925. $status = wp_remote_retrieve_response_code( $response );
  926. $filecontents = wp_remote_retrieve_body($response);
  927. }
  928. $this->trace_log("test page url, enter in browser to check manually: ".$testpage_url);
  929. if (!is_wp_error( $response ) && (strpos($filecontents, "#SSL TEST PAGE#") !== false)) {
  930. $this->htaccess_test_success = TRUE;
  931. $this->trace_log("htaccess rules tested successfully.");
  932. } else {
  933. //.htaccess rewrite rule seems to be giving problems.
  934. $this->htaccess_test_success = FALSE;
  935. if (is_wp_error( $response )) {
  936. $this->trace_log("htaccess rules test failed with error: ".$response->get_error_message());
  937. } else {
  938. $this->trace_log("htaccess test rules failed. Set WordPress redirect in settings/SSL");
  939. }
  940. }
  941. }
  942. /**
  943. * Get an url with which we can test the SSL connection and htaccess redirect rules.
  944. *
  945. * @since 2.0
  946. *
  947. * @access public
  948. *
  949. */
  950. public function test_url(){
  951. $plugin_url = str_replace("http://", "https://", trailingslashit(rsssl_url) );;
  952. $https_home_url = str_replace("http://", "https://", home_url());
  953. //in some case we get a relative url here, so we check that.
  954. //we compare to urls replaced to https, in case one of them is still on http.
  955. if ( (strpos($plugin_url, "https://")===FALSE ) &&
  956. (strpos($plugin_url, $https_home_url)===FALSE)
  957. ) {
  958. //make sure we do not have a slash at the start
  959. $plugin_url = ltrim($plugin_url,"/");
  960. $plugin_url = trailingslashit(home_url()).$plugin_url;
  961. }
  962. //for subdomains or domain mapping situations, we have to convert the plugin_url from main site to the subdomain url.
  963. if (is_multisite() && ( !is_main_site(get_current_blog_id()) ) && (! RSSSL()->rsssl_multisite->is_multisite_subfolder_install()) ) {
  964. $mainsiteurl = trailingslashit(str_replace("http://","https://",network_site_url()));
  965. $home = trailingslashit($https_home_url);
  966. $plugin_url = str_replace($mainsiteurl, $home, $plugin_url);
  967. //return http link if original url is http.
  968. //if (strpos(home_url(), "https://")===FALSE) $plugin_url = str_replace("https://","http://",$plugin_url);
  969. }
  970. return $plugin_url;
  971. }
  972. /**
  973. * removes the added redirect to https rules to the .htaccess file.
  974. *
  975. * @since 2.0
  976. *
  977. * @access public
  978. *
  979. */
  980. public function removeHtaccessEdit() {
  981. if(file_exists($this->ABSpath.".htaccess") && is_writable($this->ABSpath.".htaccess")){
  982. $htaccess = file_get_contents($this->ABSpath.".htaccess");
  983. //if multisite, per site activation and more than one blog remaining on ssl, remove condition for this site only
  984. //the domain list has been rebuilt already, so current site is already removed.
  985. if (is_multisite() && ! RSSSL()->rsssl_multisite->ssl_enabled_networkwide && count($this->sites)>0) {
  986. //remove http or https.
  987. $domain = preg_replace("/(http:\/\/|https:\/\/)/","",home_url());
  988. $pattern = "/#wpmu\srewritecond\s?".preg_quote($domain, "/")."\n.*?#end\swpmu\srewritecond\s?".preg_quote($domain, "/")."\n/s";
  989. //only remove if the pattern is there at all
  990. if (preg_match($pattern, $htaccess)) $htaccess = preg_replace($pattern, "", $htaccess);
  991. //now replace any remaining "or" on the last condition.
  992. $pattern = "/(\[OR\])(?!.*(\[OR\]|#start).*?RewriteRule)/s";
  993. $htaccess = preg_replace($pattern, "", $htaccess,1);
  994. } else {
  995. // remove everything
  996. $pattern = "/#\s?BEGIN\s?rlrssslReallySimpleSSL.*?#\s?END\s?rlrssslReallySimpleSSL/s";
  997. //only remove if the pattern is there at all
  998. if (preg_match($pattern, $htaccess)) $htaccess = preg_replace($pattern, "", $htaccess);
  999. }
  1000. $htaccess = preg_replace("/\n+/","\n", $htaccess);
  1001. file_put_contents($this->ABSpath.".htaccess", $htaccess);
  1002. $this->save_options();
  1003. } else {
  1004. $this->errors['HTACCESS_NOT_WRITABLE'] = TRUE;
  1005. if ($this->debug) $this->trace_log("could not remove rules from htaccess, file not writable");
  1006. }
  1007. }
  1008. public function get_htaccess_version() {
  1009. if (!file_exists($this->ABSpath.".htaccess")) return false;
  1010. $htaccess = file_get_contents($this->ABSpath.".htaccess");
  1011. $versionpos = strpos($htaccess, "rsssl_version");
  1012. if ($versionpos===false) {
  1013. //no version found, so not .htaccess rules.
  1014. return false;
  1015. } else {
  1016. //find closing marker of version
  1017. $close = strpos($htaccess, "]", $versionpos);
  1018. $version = substr($htaccess, $versionpos+14, $close-($versionpos+14));
  1019. return $version;
  1020. }
  1021. }
  1022. /* deprecated */
  1023. function htaccess_redirect_allowed(){
  1024. if (is_multisite() && RSSSL()->rsssl_multisite->is_per_site_activated_multisite_subfolder_install()) {
  1025. return false;
  1026. } else {
  1027. return true;
  1028. }
  1029. }
  1030. /*
  1031. Checks if the htaccess contains redirect rules, either actual redirect or a rsssl marker.
  1032. */
  1033. public function htaccess_contains_redirect_rules() {
  1034. if (!file_exists($this->ABSpath.".htaccess")) {
  1035. return false;
  1036. }
  1037. $htaccess = file_get_contents($this->ABSpath.".htaccess");
  1038. $needle = "RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]";
  1039. if(strpos($htaccess, $needle) !== FALSE || $this->contains_rsssl_rules()){
  1040. return true;
  1041. } else {
  1042. $this->trace_log(".htaccess does not contain default Really Simple SSL redirect");
  1043. return false;
  1044. }
  1045. }
  1046. /*
  1047. * Checks if the htaccess contains the Really Simple SSL comment.
  1048. *
  1049. */
  1050. public function contains_rsssl_rules() {
  1051. if (!file_exists($this->ABSpath.".htaccess")) {
  1052. return false;
  1053. }
  1054. $htaccess = file_get_contents($this->ABSpath.".htaccess");
  1055. $check=null;
  1056. preg_match("/BEGIN rlrssslReallySimpleSSL/", $htaccess, $check);
  1057. if(count($check) === 0){
  1058. return false;
  1059. } else {
  1060. return true;
  1061. }
  1062. }
  1063. /*
  1064. * Checks if a 301 redirect is set
  1065. * this is the case if either the wp_redirect is set, or the htaccess redirect is set.
  1066. *
  1067. */
  1068. public function has_301_redirect() {
  1069. if ($this->wp_redirect) return true;
  1070. if (RSSSL()->rsssl_server->uses_htaccess() && $this->htaccess_contains_redirect_rules() ) {
  1071. return true;
  1072. }
  1073. return false;
  1074. }
  1075. /**
  1076. * Checks if the HSTS rule is already in the htaccess file
  1077. * Set the hsts variable in the db accordingly. applies to preload version as well.
  1078. *
  1079. * @since 2.1
  1080. *
  1081. * @access public
  1082. *
  1083. */
  1084. public function contains_hsts() {
  1085. if (!file_exists($this->ABSpath.".htaccess")) {
  1086. $this->trace_log(".htaccess not found in ".$this->ABSpath);
  1087. $result = $this->hsts; //just return the setting.
  1088. } else {
  1089. $htaccess = file_get_contents($this->ABSpath.".htaccess");
  1090. preg_match("/Strict-Transport-Security/", $htaccess, $check);
  1091. if(count($check) === 0){
  1092. $result = false;
  1093. } else {
  1094. $result = true;
  1095. }
  1096. }
  1097. return $result;
  1098. }
  1099. /**
  1100. * Adds redirect to https rules to the .htaccess file.
  1101. *
  1102. * @since 2.0
  1103. *
  1104. * @access public
  1105. *
  1106. */
  1107. public function editHtaccess(){
  1108. if (!current_user_can($this->capability)) return;
  1109. //check if htacces exists and if htaccess is writable
  1110. //update htaccess to redirect to ssl
  1111. $this->trace_log("checking if .htaccess can or should be edited...");
  1112. //does it exist?
  1113. if (!file_exists($this->ABSpath.".htaccess")) {
  1114. $this->trace_log(".htaccess not found.");
  1115. return;
  1116. }
  1117. //check if editing is blocked.
  1118. if ($this->do_not_edit_htaccess) {
  1119. $this->trace_log("Edit of .htaccess blocked by setting or define 'do not edit htaccess' in Really Simple SSL.");
  1120. return;
  1121. }
  1122. $htaccess = file_get_contents($this->ABSpath.".htaccess");
  1123. if(!$this->htaccess_contains_redirect_rules()){
  1124. if (!is_writable($this->ABSpath.".htaccess")) {
  1125. //set the wp redirect as fallback, because .htaccess couldn't be edited.
  1126. if ($this->clicked_activate_ssl()) $this->wp_redirect = true;
  1127. if (is_multisite()) {
  1128. RSSSL()->rsssl_multisite->wp_redirect = true;
  1129. RSSSL()->rsssl_multisite->save_options();
  1130. }
  1131. $this->save_options();
  1132. $this->trace_log(".htaccess not writable.");
  1133. return;
  1134. }
  1135. $rules = $this->get_redirect_rules();
  1136. //insert rules before wordpress part.
  1137. if (strlen($rules)>0) {
  1138. $wptag = "# BEGIN WordPress";
  1139. if (strpos($htaccess, $wptag)!==false) {
  1140. $htaccess = str_replace($wptag, $rules.$wptag, $htaccess);
  1141. } else {
  1142. $htaccess = $htaccess.$rules;
  1143. }
  1144. file_put_contents($this->ABSpath.".htaccess", $htaccess);
  1145. }
  1146. } elseif ($this->is_settings_page() || is_network_admin()) {
  1147. if ($this->debug) {$this->trace_log("settings page, or network admin, updating htaccess...");}
  1148. if (!is_writable($this->ABSpath.".htaccess")) {
  1149. if($this->debug) $this->trace_log(".htaccess not writable.");
  1150. return;
  1151. }
  1152. $htaccess = preg_replace("/#\s?BEGIN\s?rlrssslReallySimpleSSL.*?#\s?END\s?rlrssslReallySimpleSSL/s", "", $htaccess);
  1153. $htaccess = preg_replace("/\n+/","\n", $htaccess);
  1154. $rules = $this->get_redirect_rules();
  1155. //insert rules before WordPress part.
  1156. $wptag = "# BEGIN WordPress";
  1157. if (strpos($htaccess, $wptag)!==false) {
  1158. $htaccess = str_replace($wptag, $rules.$wptag, $htaccess);
  1159. } else {
  1160. $htaccess = $htaccess.$rules;
  1161. }
  1162. file_put_contents($this->ABSpath.".htaccess", $htaccess);
  1163. }
  1164. }
  1165. /**
  1166. *
  1167. * @since 2.2
  1168. * Check if the mixed content fixer is functioning on the front end, by scanning the source of the homepage for the fixer comment.
  1169. *
  1170. */
  1171. public function mixed_content_fixer_detected(){
  1172. $status = 0;
  1173. $web_source = "";
  1174. //check if the mixed content fixer is active
  1175. $response = wp_remote_get( home_url() );
  1176. if( is_array($response) ) {
  1177. $status = wp_remote_retrieve_response_code( $response );
  1178. $web_source = wp_remote_retrieve_body($response);
  1179. }
  1180. if ($status!=200 || (strpos($web_source, "data-rsssl=") === false)) {
  1181. $this->trace_log("Check for Mixed Content detection failed, http statuscode ".$status);
  1182. return false;
  1183. } else {
  1184. $this->trace_log("Mixed content fixer was successfully detected on the front end.");
  1185. return true;
  1186. }
  1187. }
  1188. /**
  1189. * Create redirect rules for the .htaccess.
  1190. *
  1191. *…