PluginProbe
HTTP Headers / 1.13.2
HTTP Headers v1.13.2
1.19.5 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.12.0 1.12.1 1.12.2 1.13.0 1.13.1 1.13.2 1.13.3 1.13.4 1.14.0 1.14.1 1.14.2 1.15.0 All 60 releases
http-headers / http-headers.php

http-headers.php in HTTP Headers 1.13.2, at http-headers.php

1,357 lines 48.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: HTTP Headers
4 Plugin URI: https://zinoui.com/blog/http-headers-for-wordpress
5 Description: A plugin for HTTP headers management including security, access-control (CORS), caching, compression, and authentication.
6 Version: 1.13.2
7 Author: Dimitar Ivanov
8 Author URI: https://zinoui.com
9 License: GPLv2 or later
10 Text Domain: http-headers
11 */
12
13 /*
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License
16 as published by the Free Software Foundation; either version 2
17 of the License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/copyleft/gpl.html>.
26
27 Copyright (c) 2017-2019 Zino UI
28 */
29
30 if (!defined('ABSPATH')) {
31 exit;
32 }
33
34 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
35 foreach ($options as $option) {
36 if (get_option($option[0]) === false) {
37 add_option($option[0], $option[1], null, 'yes');
38 }
39 }
40
41 function build_csp_value($value) {
42 $csp = array();
43 foreach ($value as $key => $val)
44 {
45 if (is_array($val))
46 {
47 $source = NULL;
48 if (isset($val['source']))
49 {
50 $source = $val['source'];
51 unset($val['source']);
52 }
53 if (!empty($val))
54 {
55 $val = join(" ", array_keys($val));
56 if ($source)
57 {
58 $val .= " " . $source;
59 }
60 $csp[] = sprintf("%s %s", $key, $val);
61 } elseif ($source) {
62 $csp[] = sprintf("%s %s", $key, $source);
63 }
64 } else {
65 if (in_array($key, array('block-all-mixed-content', 'upgrade-insecure-requests')))
66 {
67 $csp[] = $key;
68 }
69 if (in_array($key, array('plugin-types', 'report-to')) && !empty($val))
70 {
71 $csp[] = sprintf("%s %s", $key, $val);
72 }
73 }
74 }
75
76 if (!$csp)
77 {
78 return NULL;
79 }
80
81 return join('; ', $csp);
82 }
83
84 function get_http_headers() {
85 $statuses = array();
86 $unset = array();
87 $headers = array();
88 $append = array();
89 if (get_option('hh_x_frame_options') == 1) {
90 $x_frame_options_value = strtoupper(get_option('hh_x_frame_options_value'));
91 if ($x_frame_options_value == 'ALLOW-FROM') {
92 $x_frame_options_value .= ' ' . get_option('hh_x_frame_options_domain');
93 }
94 $headers['X-Frame-Options'] = $x_frame_options_value;
95 }
96 if (get_option('hh_x_powered_by') == 1) {
97 if (get_option('hh_x_powered_by_option') == 'set') {
98 $headers['X-Powered-By'] = get_option('hh_x_powered_by_value');
99 } else {
100 $unset[] = 'X-Powered-By';
101 }
102 }
103 if (get_option('hh_x_xxs_protection') == 1) {
104 $headers['X-XSS-Protection'] = get_option('hh_x_xxs_protection_value');
105 if ($headers['X-XSS-Protection'] == '1; report=') {
106 $headers['X-XSS-Protection'] .= get_option('hh_x_xxs_protection_uri');
107 }
108 }
109 if (get_option('hh_x_content_type_options') == 1) {
110 $headers['X-Content-Type-Options'] = get_option('hh_x_content_type_options_value');
111 }
112 if (get_option('hh_x_download_options') == 1) {
113 $headers['X-Download-Options'] = get_option('hh_x_download_options_value');
114 }
115 if (get_option('hh_x_permitted_cross_domain_policies') == 1) {
116 $headers['X-Permitted-Cross-Domain-Policies'] = get_option('hh_x_permitted_cross_domain_policies_value');
117 }
118 if (get_option('hh_x_dns_prefetch_control') == 1) {
119 $headers['X-DNS-Prefetch-Control'] = get_option('hh_x_dns_prefetch_control_value');
120 }
121 if (get_option('hh_connection') == 1) {
122 $headers['Connection'] = get_option('hh_connection_value');
123 }
124 if (get_option('hh_pragma') == 1) {
125 $headers['Pragma'] = get_option('hh_pragma_value');
126 }
127 if (get_option('hh_age') == 1) {
128 $headers['Age'] = sprintf("%u", get_option('hh_age_value'));
129 }
130 if (get_option('hh_cache_control') == 1) {
131 $hh_cache_control_value = get_option('hh_cache_control_value', array());
132 $tmp = array();
133 foreach ($hh_cache_control_value as $k => $v) {
134 if (in_array($k, array('max-age', 's-maxage'))) {
135 if (strlen($v) > 0) {
136 $tmp[] = sprintf("%s=%u", $k, $v);
137 }
138 } else {
139 $tmp[] = $k;
140 }
141 }
142 $hh_cache_control_value = join(', ', $tmp);
143 $headers['Cache-Control'] = $hh_cache_control_value;
144 }
145 if (get_option('hh_strict_transport_security') == 1) {
146 $hh_strict_transport_security = array();
147
148 $hh_strict_transport_security_max_age = get_option('hh_strict_transport_security_max_age');
149 if ($hh_strict_transport_security_max_age !== false)
150 {
151 $hh_strict_transport_security[] = sprintf('max-age=%u', get_option('hh_strict_transport_security_max_age'));
152 if (get_option('hh_strict_transport_security_sub_domains'))
153 {
154 $hh_strict_transport_security[] = 'includeSubDomains';
155 }
156 if (get_option('hh_strict_transport_security_preload'))
157 {
158 $hh_strict_transport_security[] = 'preload';
159 }
160 } else {
161 $hh_strict_transport_security = array(get_option('hh_strict_transport_security_value'));
162 }
163 $headers['Strict-Transport-Security'] = join('; ', $hh_strict_transport_security);
164 }
165 if (get_option('hh_x_ua_compatible') == 1) {
166 $headers['X-UA-Compatible'] = get_option('hh_x_ua_compatible_value');
167 }
168 if (get_option('hh_public_key_pins') == 1) {
169 $public_key_pins_sha256_1 = get_option('hh_public_key_pins_sha256_1');
170 $public_key_pins_sha256_2 = get_option('hh_public_key_pins_sha256_2');
171 $public_key_pins_max_age = get_option('hh_public_key_pins_max_age');
172 $public_key_pins_sub_domains = get_option('hh_public_key_pins_sub_domains');
173 $public_key_pins_report_uri = get_option('hh_public_key_pins_report_uri');
174 $public_key_pins_report_only = get_option('hh_public_key_pins_report_only');
175 if (!empty($public_key_pins_sha256_1) && !empty($public_key_pins_sha256_2) && !empty($public_key_pins_max_age)) {
176
177 $public_key_pins = array();
178 $public_key_pins[] = sprintf('pin-sha256="%s"', $public_key_pins_sha256_1);
179 $public_key_pins[] = sprintf('pin-sha256="%s"', $public_key_pins_sha256_2);
180 $public_key_pins[] = sprintf("max-age=%u", $public_key_pins_max_age);
181 if ($public_key_pins_sub_domains) {
182 $public_key_pins[] = "includeSubDomains";
183 }
184 if (!empty($public_key_pins_report_uri)) {
185 $public_key_pins[] = sprintf('report-uri="%s"', $public_key_pins_report_uri);
186 }
187 $headers['Public-Key-Pins'.($public_key_pins_report_only ? '-Report-Only' : NULL)] = join('; ', $public_key_pins);
188 }
189 }
190
191 if (get_option('hh_content_security_policy') == 1)
192 {
193 $value = get_option('hh_content_security_policy_value');
194 $csp = build_csp_value($value);
195 if ($csp)
196 {
197 $csp_report_only = get_option('hh_content_security_policy_report_only');
198 $headers['Content-Security-Policy'.($csp_report_only ? '-Report-Only' : NULL)] = $csp;
199 }
200 }
201
202 if (get_option('hh_access_control_allow_origin') == 1)
203 {
204 $value = get_option('hh_access_control_allow_origin_value');
205 switch ($value)
206 {
207 case 'origin':
208 $value = get_option('hh_access_control_allow_origin_url', array());
209 if (is_scalar($value))
210 {
211 $value = array($value);
212 }
213 break;
214 }
215 if (!empty($value))
216 {
217 $headers['Access-Control-Allow-Origin'] = $value;
218 }
219 }
220 if (get_option('hh_access_control_allow_credentials') == 1)
221 {
222 $headers['Access-Control-Allow-Credentials'] = get_option('hh_access_control_allow_credentials_value');
223 }
224 if (get_option('hh_access_control_max_age') == 1)
225 {
226 $value = get_option('hh_access_control_max_age_value');
227 if (!empty($value))
228 {
229 $headers['Access-Control-Max-Age'] = intval($value);
230 }
231 }
232 if (get_option('hh_access_control_allow_methods') == 1)
233 {
234 $value = get_option('hh_access_control_allow_methods_value');
235 if (!empty($value))
236 {
237 $headers['Access-Control-Allow-Methods'] = join(', ', array_keys($value));
238 }
239 }
240 if (get_option('hh_access_control_allow_headers') == 1)
241 {
242 $value = get_option('hh_access_control_allow_headers_value');
243 if (!empty($value))
244 {
245 $headers['Access-Control-Allow-Headers'] = join(', ', array_keys($value));
246 }
247 }
248 if (get_option('hh_access_control_expose_headers') == 1)
249 {
250 $value = get_option('hh_access_control_expose_headers_value');
251 if (!empty($value))
252 {
253 $headers['Access-Control-Expose-Headers'] = join(', ', array_keys($value));
254 }
255 }
256 if (get_option('hh_p3p') == 1)
257 {
258 $value = get_option('hh_p3p_value');
259 if (!empty($value))
260 {
261 $headers['P3P'] = 'CP="' . join(' ', array_keys($value)) . '"';
262 }
263 }
264 if (get_option('hh_referrer_policy') == 1) {
265 $headers['Referrer-Policy'] = get_option('hh_referrer_policy_value');
266 }
267 if (get_option('hh_www_authenticate') == 1) {
268
269 switch (get_option('hh_www_authenticate_type')) {
270 case 'Basic':
271 if (!(isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])
272 && $_SERVER['PHP_AUTH_USER'] == get_option('hh_www_authenticate_user')
273 && $_SERVER['PHP_AUTH_PW'] == get_option('hh_www_authenticate_pswd'))) {
274 $headers['WWW-Authenticate'] = sprintf("Basic realm='%s'", get_option('hh_www_authenticate_realm'));
275 $statuses['HTTP/1.1'] = '401 Unauthorized';
276 }
277 break;
278 case 'Digest':
279 if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
280 $realm = get_option('hh_www_authenticate_realm');
281 $headers['WWW-Authenticate'] = sprintf("Digest realm='%s',qop='auth',nonce='%s',opaque='%s'",
282 $realm, uniqid(), md5($realm));
283 $statuses['HTTP/1.1'] = '401 Unauthorized';
284 }
285 break;
286 }
287 }
288 if (get_option('hh_vary') == 1)
289 {
290 $value = get_option('hh_vary_value');
291 if (!empty($value))
292 {
293 $append['Vary'] = join(', ', array_keys($value));
294 }
295 }
296
297 if (get_option('hh_expect_ct') == 1) {
298 $expect_ct_max_age = get_option('hh_expect_ct_max_age');
299 $expect_ct_report_uri = get_option('hh_expect_ct_report_uri');
300 if (!empty($expect_ct_report_uri) && !empty($expect_ct_max_age)) {
301
302 $expect_ct = array();
303 $expect_ct[] = sprintf("max-age=%u", $expect_ct_max_age);
304 if (get_option('hh_expect_ct_enforce') == 1) {
305 $expect_ct[] = "enforce";
306 }
307 $expect_ct[] = sprintf('report-uri="%s"', $expect_ct_report_uri);
308 $headers['Expect-CT'] = join(', ', $expect_ct);
309 }
310 }
311 if (get_option('hh_custom_headers') == 1) {
312 $custom_headers = get_option('hh_custom_headers_value');
313 if (isset($custom_headers['name'], $custom_headers['value']) && !empty($custom_headers['name'])) {
314 foreach ($custom_headers['name'] as $key => $name) {
315 $name = trim($name);
316 $value = trim($custom_headers['value'][$key]);
317 if (empty($name) || empty($value)) {
318 continue;
319 }
320 $headers[$name] = $value;
321 }
322 }
323 }
324 if (get_option('hh_report_to') == 1) {
325 $report_to = get_option('hh_report_to_value');
326 $tmp = array();
327 foreach ($report_to as $item)
328 {
329 $tmp[] = sprintf('{"url": "%s", "group": "%s", "max-age": %u%s}',
330 $item['url'], $item['group'], $item['max-age'], isset($item['includeSubDomains']) ? ', includeSubDomains' : NULL);
331 }
332 if ($tmp)
333 {
334 $headers['Report-To'] = join(', ', $tmp);
335 }
336 }
337 if (get_option('hh_feature_policy') == 1) {
338 $feature_policy_feature = get_option('hh_feature_policy_feature');
339 $feature_policy_value = get_option('hh_feature_policy_value');
340 $feature_policy_origin = get_option('hh_feature_policy_origin');
341 $tmp = array();
342 $feature_policy_feature = is_array($feature_policy_feature) ? $feature_policy_feature : array();
343 foreach (array_keys($feature_policy_feature) as $feature)
344 {
345 $value = NULL;
346 switch ($feature_policy_value[$feature])
347 {
348 case '*':
349 case "'none'":
350 $value = $feature_policy_value[$feature];
351 break;
352 case "'self'":
353 $value = $feature_policy_value[$feature];
354 if (!empty($feature_policy_origin[$feature]))
355 {
356 $value .= " " . $feature_policy_origin[$feature];
357 }
358 break;
359 case 'origin(s)':
360 $value = $feature_policy_origin[$feature];
361 break;
362 }
363
364 $tmp[] = sprintf("%s %s", $feature, $value);
365 }
366 if ($tmp)
367 {
368 $headers['Feature-Policy'] = join('; ', $tmp);
369 }
370 }
371
372 return array($headers, $statuses, $unset, $append);
373 }
374
375 function http_digest_parse($txt) {
376 $txt = stripslashes($txt);
377
378 $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
379 $data = array();
380 $keys = implode('|', array_keys($needed_parts));
381
382 preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
383
384 foreach ($matches as $m) {
385 $data[$m[1]] = $m[3] ? $m[3] : $m[4];
386 unset($needed_parts[$m[1]]);
387 }
388
389 return $needed_parts ? false : $data;
390 }
391
392 function php_auth_digest() {
393 if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || get_option('hh_www_authenticate_user') != $data['username']) {
394 die('Wrong Credentials!');
395 }
396
397 $A1 = md5($data['username'] . ':' . get_option('hh_www_authenticate_realm') . ':' . get_option('hh_www_authenticate_pswd'));
398 $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
399 $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
400 if ($data['response'] != $valid_response) {
401 die('Wrong Credentials!');
402 }
403 }
404
405 function php_content_encoding() {
406 if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
407 ob_start('ob_gzhandler');
408 } else {
409 ob_start();
410 }
411 }
412
413 function php_cookie_security_directives() {
414 $lines = array();
415 if (get_option('hh_cookie_security') == 1) {
416 $value = get_option('hh_cookie_security_value', array());
417 if (isset($value['HttpOnly'])) {
418 $lines[] = 'session.cookie_httponly = on';
419 }
420 if (isset($value['Secure'])) {
421 $lines[] = 'session.cookie_secure = on';
422 }
423 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
424 $lines[] = sprintf('session.cookie_samesite = "%s"', $value['SameSite']);
425 }
426 }
427
428 return $lines;
429 }
430
431 function http_headers() {
432 if (get_option('hh_method') !== 'php') {
433 return;
434 }
435 // PHP method below
436 list($headers, $statuses, $unset, $append) = get_http_headers();
437 $isCors = false;
438 foreach ($headers as $key => $value) {
439 if ($key == 'Access-Control-Allow-Origin') {
440 if (isset($_SERVER['HTTP_ORIGIN'])) {
441 if ($value == '*') {
442 $isCors = true;
443 header(sprintf("%s: *", $key));
444 }
445
446 if (is_array($value) && in_array($_SERVER['HTTP_ORIGIN'], $value)) {
447 $isCors = true;
448 header(sprintf("%s: %s", $key, $_SERVER['HTTP_ORIGIN']));
449 }
450 }
451 continue;
452 }
453 if (in_array($key, array('Access-Control-Allow-Headers', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Credentials', 'Access-Control-Max-Age', 'Access-Control-Expose-Headers'))) {
454 if ($isCors) {
455 header(sprintf("%s: %s", $key, $value));
456 }
457 continue;
458 }
459 header(sprintf("%s: %s", $key, $value));
460 }
461 foreach ($append as $key => $value) {
462 header(sprintf("%s: %s", $key, $value), false);
463 }
464 foreach ($unset as $header) {
465 if (function_exists('header_remove')) {
466 header_remove($header);
467 } else {
468 header("$header:");
469 }
470 }
471 foreach ($statuses as $key => $value) {
472 header(sprintf("%s %s", $key, $value));
473 exit;
474 }
475
476 if (get_option('hh_www_authenticate') == 1) {
477 php_auth_digest();
478 }
479
480 if (get_option('hh_content_encoding') == 1) {
481 php_content_encoding();
482 }
483 }
484
485 function http_headers_admin_add_page() {
486 add_options_page('HTTP Headers', 'HTTP Headers', 'manage_options', 'http-headers', 'http_headers_admin_page');
487 }
488
489 function http_headers_admin() {
490 register_setting('http-headers-mtd', 'hh_method');
491 register_setting('http-headers-xfo', 'hh_x_frame_options');
492 register_setting('http-headers-xfo', 'hh_x_frame_options_value');
493 register_setting('http-headers-xfo', 'hh_x_frame_options_domain');
494 register_setting('http-headers-xss', 'hh_x_xxs_protection');
495 register_setting('http-headers-xss', 'hh_x_xxs_protection_value');
496 register_setting('http-headers-xss', 'hh_x_xxs_protection_uri');
497 register_setting('http-headers-cto', 'hh_x_content_type_options');
498 register_setting('http-headers-cto', 'hh_x_content_type_options_value');
499 register_setting('http-headers-sts', 'hh_strict_transport_security');
500 register_setting('http-headers-sts', 'hh_strict_transport_security_value'); //obsolete
501 register_setting('http-headers-sts', 'hh_strict_transport_security_max_age');
502 register_setting('http-headers-sts', 'hh_strict_transport_security_sub_domains');
503 register_setting('http-headers-sts', 'hh_strict_transport_security_preload');
504 register_setting('http-headers-pkp', 'hh_public_key_pins');
505 register_setting('http-headers-pkp', 'hh_public_key_pins_sha256_1');
506 register_setting('http-headers-pkp', 'hh_public_key_pins_sha256_2');
507 register_setting('http-headers-pkp', 'hh_public_key_pins_max_age');
508 register_setting('http-headers-pkp', 'hh_public_key_pins_sub_domains');
509 register_setting('http-headers-pkp', 'hh_public_key_pins_report_uri');
510 register_setting('http-headers-pkp', 'hh_public_key_pins_report_only');
511 register_setting('http-headers-uac', 'hh_x_ua_compatible');
512 register_setting('http-headers-uac', 'hh_x_ua_compatible_value');
513 register_setting('http-headers-p3p', 'hh_p3p');
514 register_setting('http-headers-p3p', 'hh_p3p_value');
515 register_setting('http-headers-rp', 'hh_referrer_policy');
516 register_setting('http-headers-rp', 'hh_referrer_policy_value');
517 register_setting('http-headers-csp', 'hh_content_security_policy');
518 register_setting('http-headers-csp', 'hh_content_security_policy_value');
519 register_setting('http-headers-csp', 'hh_content_security_policy_report_only');
520 register_setting('http-headers-acao', 'hh_access_control_allow_origin');
521 register_setting('http-headers-acao', 'hh_access_control_allow_origin_value');
522 register_setting('http-headers-acao', 'hh_access_control_allow_origin_url');
523 register_setting('http-headers-acac', 'hh_access_control_allow_credentials');
524 register_setting('http-headers-acac', 'hh_access_control_allow_credentials_value');
525 register_setting('http-headers-acam', 'hh_access_control_allow_methods');
526 register_setting('http-headers-acam', 'hh_access_control_allow_methods_value');
527 register_setting('http-headers-acah', 'hh_access_control_allow_headers');
528 register_setting('http-headers-acah', 'hh_access_control_allow_headers_value');
529 register_setting('http-headers-aceh', 'hh_access_control_expose_headers');
530 register_setting('http-headers-aceh', 'hh_access_control_expose_headers_value');
531 register_setting('http-headers-acma', 'hh_access_control_max_age');
532 register_setting('http-headers-acma', 'hh_access_control_max_age_value');
533 register_setting('http-headers-ce', 'hh_content_encoding');
534 register_setting('http-headers-ce', 'hh_content_encoding_module');
535 register_setting('http-headers-ce', 'hh_content_encoding_value');
536 register_setting('http-headers-ce', 'hh_content_encoding_ext');
537 register_setting('http-headers-vary', 'hh_vary');
538 register_setting('http-headers-vary', 'hh_vary_value');
539 register_setting('http-headers-xpb', 'hh_x_powered_by');
540 register_setting('http-headers-xpb', 'hh_x_powered_by_option');
541 register_setting('http-headers-xpb', 'hh_x_powered_by_value');
542 register_setting('http-headers-wwa', 'hh_www_authenticate');
543 register_setting('http-headers-wwa', 'hh_www_authenticate_type');
544 register_setting('http-headers-wwa', 'hh_www_authenticate_realm');
545 register_setting('http-headers-wwa', 'hh_www_authenticate_user');
546 register_setting('http-headers-wwa', 'hh_www_authenticate_pswd');
547 register_setting('http-headers-cc', 'hh_cache_control');
548 register_setting('http-headers-cc', 'hh_cache_control_value');
549 register_setting('http-headers-age', 'hh_age');
550 register_setting('http-headers-age', 'hh_age_value');
551 register_setting('http-headers-pra', 'hh_pragma');
552 register_setting('http-headers-pra', 'hh_pragma_value');
553 register_setting('http-headers-exp', 'hh_expires');
554 register_setting('http-headers-exp', 'hh_expires_value');
555 register_setting('http-headers-exp', 'hh_expires_type');
556 register_setting('http-headers-con', 'hh_connection');
557 register_setting('http-headers-con', 'hh_connection_value');
558 register_setting('http-headers-cose', 'hh_cookie_security');
559 register_setting('http-headers-cose', 'hh_cookie_security_value');
560 register_setting('http-headers-ect', 'hh_expect_ct');
561 register_setting('http-headers-ect', 'hh_expect_ct_max_age');
562 register_setting('http-headers-ect', 'hh_expect_ct_report_uri');
563 register_setting('http-headers-ect', 'hh_expect_ct_enforce');
564 register_setting('http-headers-tao', 'hh_timing_allow_origin');
565 register_setting('http-headers-tao', 'hh_timing_allow_origin_value');
566 register_setting('http-headers-tao', 'hh_timing_allow_origin_url');
567 register_setting('http-headers-che', 'hh_custom_headers');
568 register_setting('http-headers-che', 'hh_custom_headers_value');
569 register_setting('http-headers-xdo', 'hh_x_download_options');
570 register_setting('http-headers-xdo', 'hh_x_download_options_value');
571 register_setting('http-headers-xpcd', 'hh_x_permitted_cross_domain_policies');
572 register_setting('http-headers-xpcd', 'hh_x_permitted_cross_domain_policies_value');
573 register_setting('http-headers-xdpc', 'hh_x_dns_prefetch_control');
574 register_setting('http-headers-xdpc', 'hh_x_dns_prefetch_control_value');
575 register_setting('http-headers-rt', 'hh_report_to');
576 register_setting('http-headers-rt', 'hh_report_to_value');
577 register_setting('http-headers-fp', 'hh_feature_policy');
578 register_setting('http-headers-fp', 'hh_feature_policy_value');
579 register_setting('http-headers-fp', 'hh_feature_policy_feature');
580 register_setting('http-headers-fp', 'hh_feature_policy_origin');
581 register_setting('http-headers-csd', 'hh_clear_site_data');
582 register_setting('http-headers-csd', 'hh_clear_site_data_value');
583 }
584
585 function http_headers_option($option) {
586
587 include_once ABSPATH . 'wp-admin/includes/admin.php';
588
589 if (isset($_POST['hh_method']))
590 {
591 check_admin_referer('http-headers-mtd-options');
592 # When method is changed
593 http_headers_activate();
594
595 } elseif (get_option('hh_method') == 'htaccess') {
596 # When particular header is changed
597 switch (true) {
598 case array_key_exists('hh_www_authenticate', $_POST):
599 check_admin_referer('http-headers-wwa-options');
600 update_auth_credentials();
601 update_auth_directives();
602 break;
603 case array_key_exists('hh_content_encoding', $_POST):
604 check_admin_referer('http-headers-ce-options');
605 update_content_encoding_directives();
606 break;
607 case array_key_exists('hh_expires', $_POST):
608 check_admin_referer('http-headers-exp-options');
609 update_expires_directives();
610 break;
611 case array_key_exists('hh_cookie_security', $_POST):
612 check_admin_referer('http-headers-cose-options');
613 update_cookie_security_directives();
614 break;
615 case array_key_exists('hh_timing_allow_origin', $_POST):
616 check_admin_referer('http-headers-tao-options');
617 update_timing_directives();
618 break;
619 case array_key_exists('option_page', $_POST) && strpos($_POST['option_page'], 'http-headers-') === 0:
620 check_admin_referer($_POST['option_page'].'-options');
621 update_headers_directives();
622 break;
623 }
624 }
625 }
626
627 function nginx_headers_directives() {
628 $lines = array();
629 list($headers, $statuses, $unset, $append) = get_http_headers();
630
631 foreach ($unset as $header) {
632 $lines[] = sprintf(' more_clear_headers "%s";', $header);
633 }
634 $cors = $cors_header = $cors_inner = $cors_footer = array();
635 $all = array();
636 foreach ($headers as $key => $value) {
637 if (in_array($key, array('WWW-Authenticate'))) {
638 continue;
639 }
640 if (in_array($key, array('X-Content-Type-Options'))) {
641 $all[] = sprintf('add_header %s %s always;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
642 continue;
643 }
644 if ($key == 'Access-Control-Allow-Origin' && is_array($value)) {
645 $cors_header[] = sprintf('if ($http_origin ~* ^(%s)$) {', str_replace('.', '\.', join('|', $value)));
646 $cors_footer[] = '}';
647 $cors_inner[] = ' add_header Access-Control-Allow-Origin "$http_origin";';
648 continue;
649 }
650 if (in_array($key, array('Access-Control-Allow-Headers', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Credentials', 'Access-Control-Max-Age', 'Access-Control-Expose-Headers'))) {
651 $cors_inner[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
652 continue;
653 }
654 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
655 }
656 foreach ($append as $key => $value) {
657 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
658 }
659 if (!empty($cors_inner))
660 {
661 $cors = array_merge(
662 $cors_header,
663 $cors_inner,
664 $cors_footer
665 );
666 }
667 if (!empty($lines)) {
668 $lines = array_merge(
669 $all,
670 $cors,
671 array('location ~* \.(php|html)$ {'),
672 $lines,
673 array('}')
674 );
675 }
676 return $lines;
677 }
678
679 function nginx_content_encoding_directives() {
680 $lines = array();
681 if (get_option('hh_content_encoding') == 1) {
682
683 $lines[] = 'gzip on;';
684
685 $content_encoding_value = get_option('hh_content_encoding_value');
686 if (!$content_encoding_value) {
687 $content_encoding_value = array();
688 }
689
690 $content_encoding_ext = get_option('hh_content_encoding_ext');
691 if (!$content_encoding_ext) {
692 $content_encoding_ext = array();
693 }
694 if (!empty($content_encoding_ext)) {
695 //$lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
696 }
697 if (!empty($content_encoding_value)) {
698 $lines[] = sprintf('gzip_types %s;', join(' ', array_keys($content_encoding_value)));
699 }
700 }
701 return $lines;
702 }
703
704 function nginx_expires_directives() {
705 $lines = array();
706 if (get_option('hh_expires') == 1) {
707
708 $types = get_option('hh_expires_type', array());
709 $values = get_option('hh_expires_value', array());
710
711 $lines[] = 'map $sent_http_content_type $expires {';
712 foreach ($types as $type => $whatever) {
713 list($base, $period, $suffix) = explode('_', $values[$type]);
714 if (in_array($base, array('access', 'modification'))) {
715 $lines[] = $type != 'default'
716 ? sprintf(' %s %u%s;', $type, $period, $suffix[0])
717 : sprintf(' default %u%s;', $period, $suffix[0]);
718 } elseif ($base == 'invalid') {
719 $lines[] = $type != 'default'
720 ? sprintf(' %s 0;', $type)
721 : sprintf(' default 0;');
722 }
723 }
724 $lines[] = '}';
725
726 $lines[] = 'expires $expires;';
727 }
728 return $lines;
729 }
730
731 function nginx_timing_directives() {
732 $lines = array();
733 if (get_option('hh_timing_allow_origin') == 1) {
734 $value = get_option('hh_timing_allow_origin_value');
735 switch ($value)
736 {
737 case 'origin':
738 $value = get_option('hh_timing_allow_origin_url');
739 break;
740 }
741 if (!empty($value))
742 {
743 $lines[] = 'location ~* \.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$ {';
744 $lines[] = sprintf(' add_header Timing-Allow-Origin "%s";', $value);
745 $lines[] = '}';
746 }
747 }
748 return $lines;
749 }
750
751 function nginx_auth_directives() {
752 $lines = array();
753 if (get_option('hh_www_authenticate') == 1) {
754
755 $type = get_option('hh_www_authenticate_type');
756
757 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
758
759 $lines[] = 'location ~ ^\.hh-ht(digest|passwd)$ {';
760 $lines[] = ' deny all;';
761 $lines[] = '}';
762
763 $lines[] = sprintf('location %s {', get_home_path());
764 if ($type == 'Basic') {
765 $lines[] = sprintf(' auth_basic "%s";', get_option('hh_www_authenticate_realm'));
766 $lines[] = sprintf(' auth_basic_user_file %s%s;', get_home_path(), $file);
767 } else {
768 $lines[] = sprintf(' auth_digest "%s";', get_option('hh_www_authenticate_realm'));
769 $lines[] = sprintf(' auth_digest_user_file %s%s;', get_home_path(), $file);
770 }
771 $lines[] = '}';
772 }
773 return $lines;
774 }
775
776 function nginx_auth_credentials() {
777 return apache_auth_credentials();
778 }
779
780 function nginx_cookie_security_directives() {
781 $lines = array();
782
783 //TODO
784
785 return $lines;
786 }
787
788 function nginx_check_requirements() {
789 //TODO scheduled for v2.0.0
790 return true;
791 }
792
793 function iis_headers_directives() {
794 //TODO scheduled for v2.0.0
795 }
796
797 function iis_content_encoding_directives() {
798 //TODO scheduled for v2.0.0
799 }
800
801 function iis_expires_directives() {
802 //TODO scheduled for v2.0.0
803 }
804
805 function iis_timing_directives() {
806 //TODO scheduled for v2.0.0
807 }
808
809 function iis_auth_directives() {
810 //TODO scheduled for v2.0.0
811 }
812
813 function iis_auth_credentials() {
814 //TODO scheduled for v2.0.0
815 }
816
817 function iis_cookie_security_directives() {
818 //TODO scheduled for v2.0.0
819 }
820
821 function iis_check_requirements() {
822 //TODO scheduled for v2.0.0
823 return true;
824 }
825
826 function apache_headers_directives() {
827 $lines = array();
828 list($headers, $statuses, $unset, $append) = get_http_headers();
829
830 foreach ($unset as $header) {
831 $lines[] = sprintf(' Header unset %s', $header);
832 }
833 $all = array();
834 foreach ($headers as $key => $value) {
835 if (in_array($key, array('WWW-Authenticate'))) {
836 continue;
837 }
838 if (in_array($key, array('X-Content-Type-Options'))) {
839 $all[] = sprintf(' Header always set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
840 continue;
841 }
842 if ($key == 'Strict-Transport-Security') {
843 $lines[] = sprintf(' Header set %s %s env=HTTPS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
844 continue;
845 }
846 if ($key == 'Access-Control-Allow-Origin') {
847 $all[] = ' <IfModule mod_setenvif.c>';
848 if (!is_array($value)) {
849 if ($value) {
850 $value = array($value);
851 } else {
852 $value = array();
853 }
854 }
855 $value[] = 'null';
856 if (is_array($value))
857 {
858 $all[] = sprintf(' SetEnvIf Origin "^(%s)$" CORS=$0', str_replace('.', '\.', join('|', $value)));
859 } else {
860 $all[] = ' SetEnvIf Origin "^(.+)$" CORS=$0';
861 }
862 $all[] = ' </IfModule>';
863 $all[] = ' Header set Access-Control-Allow-Origin %{CORS}e env=CORS';
864 continue;
865 }
866 if (in_array($key, array('Access-Control-Allow-Headers', 'Access-Control-Allow-Methods', 'Access-Control-Allow-Credentials', 'Access-Control-Max-Age', 'Access-Control-Expose-Headers'))) {
867 $all[] = sprintf(' Header set %s %s env=CORS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
868 continue;
869 }
870 $lines[] = sprintf(' Header set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
871 }
872 foreach ($append as $key => $value) {
873 $lines[] = sprintf(' Header append %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
874 }
875 if (!empty($lines)) {
876 $lines = array_merge(
877 array('<IfModule mod_headers.c>'),
878 $all,
879 array(' <FilesMatch "\.(php|html)$">'),
880 $lines,
881 array(' </FilesMatch>', '</IfModule>')
882 );
883 }
884 return $lines;
885 }
886
887 function apache_content_encoding_directives() {
888 $lines = array();
889 if (get_option('hh_content_encoding') == 1) {
890
891 $content_encoding_module = get_option('hh_content_encoding_module');
892 switch ($content_encoding_module) {
893 case 'brotli':
894 $module = 'mod_brotli.c';
895 $module_end = '';
896 $filter = 'BROTLI_COMPRESS';
897 break;
898 case 'brotli_deflate':
899 $module = "mod_brotli.c>\n<IfModule mod_deflate.c";
900 $module_end = "\n</IfModule>";
901 $filter = 'BROTLI_COMPRESS;DEFLATE';
902 break;
903 case 'deflate':
904 default:
905 $module = 'mod_deflate.c';
906 $module_end = '';
907 $filter = 'DEFLATE';
908 break;
909 }
910
911 $content_encoding_value = get_option('hh_content_encoding_value');
912 if (!$content_encoding_value) {
913 $content_encoding_value = array();
914 }
915
916 $content_encoding_ext = get_option('hh_content_encoding_ext');
917 if (!$content_encoding_ext) {
918 $content_encoding_ext = array();
919 }
920 if (!empty($content_encoding_ext)) {
921 $lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
922 $lines[] = sprintf(' <IfModule %s>', $module);
923 $lines[] = sprintf(' SetOutputFilter %s', $filter);
924 $lines[] = sprintf(' </IfModule>%s', $module_end);
925 $lines[] = '</FilesMatch>';
926 }
927 if (!empty($content_encoding_value)) {
928 if (!empty($lines)) {
929 $lines[] = '';
930 }
931 $lines[] = sprintf('<IfModule %s>', $module);
932 foreach (array_keys($content_encoding_value) as $item) {
933 $lines[] = sprintf(' AddOutputFilterByType %s %s', $filter, $item);
934 }
935 $lines[] = sprintf('</IfModule>%s', $module_end);
936 }
937 }
938
939 return $lines;
940 }
941
942 function apache_expires_directives() {
943 $lines = array();
944 if (get_option('hh_expires') == 1) {
945
946 $types = get_option('hh_expires_type', array());
947 $values = get_option('hh_expires_value', array());
948
949 $lines[] = '<IfModule mod_expires.c>';
950 $lines[] = ' ExpiresActive On';
951 foreach ($types as $type => $whatever) {
952 list($base, $period, $suffix) = explode('_', $values[$type]);
953 if (in_array($base, array('access', 'modification'))) {
954 $lines[] = $type != 'default'
955 ? sprintf(' ExpiresByType %s "%s plus %u %s"', $type, $base, $period, $suffix)
956 : sprintf(' ExpiresDefault "%s plus %u %s"', $base, $period, $suffix);
957 } elseif ($base == 'invalid') {
958 $lines[] = $type != 'default'
959 ? sprintf(' ExpiresByType %s A0', $type)
960 : sprintf(' ExpiresDefault A0');
961 }
962 }
963 $lines[] = '</IfModule>';
964 }
965
966 return $lines;
967 }
968
969 function apache_timing_directives() {
970 $lines = array();
971 if (get_option('hh_timing_allow_origin') == 1) {
972 $value = get_option('hh_timing_allow_origin_value');
973 switch ($value)
974 {
975 case 'origin':
976 $value = get_option('hh_timing_allow_origin_url');
977 break;
978 }
979 if (!empty($value))
980 {
981 $lines[] = '<IfModule mod_headers.c>';
982 $lines[] = ' <FilesMatch "\\.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$">';
983 $lines[] = sprintf(' Header set Timing-Allow-Origin "%s"', $value);
984 $lines[] = ' </FilesMatch>';
985 $lines[] = '</IfModule>';
986 }
987 }
988
989 return $lines;
990 }
991
992 function apache_auth_directives() {
993 $lines = array();
994 if (get_option('hh_www_authenticate') == 1) {
995
996 $type = get_option('hh_www_authenticate_type');
997
998 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
999
1000 $lines[] = '<FilesMatch "^\.hh-ht(digest|passwd)$">';
1001 $lines[] = ' Order deny,allow';
1002 $lines[] = ' Deny from all';
1003 $lines[] = '</FilesMatch>';
1004
1005 $lines[] = sprintf('<IfModule mod_auth_%s.c>', strtolower($type));
1006 $lines[] = sprintf(' AuthType %s', get_option('hh_www_authenticate_type'));
1007 $lines[] = sprintf(' AuthName "%s"', get_option('hh_www_authenticate_realm'));
1008 $lines[] = sprintf(' AuthUserFile "%s%s"', get_home_path(), $file);
1009 $lines[] = ' Require valid-user';
1010 $lines[] = '</IfModule>';
1011 }
1012
1013 return $lines;
1014 }
1015
1016 function apache_auth_credentials() {
1017 if (get_option('hh_www_authenticate') == 1) {
1018 $type = get_option('hh_www_authenticate_type');
1019 $usernames = get_option('hh_www_authenticate_user', array());
1020 $passwords = get_option('hh_www_authenticate_pswd', array());
1021 if (!is_array($usernames)) {
1022 $usernames = array($usernames);
1023 }
1024 if (!is_array($passwords)) {
1025 $passwords = array($passwords);
1026 }
1027 $realm = get_option('hh_www_authenticate_realm');
1028 $auth = array();
1029 switch ($type) {
1030 case 'Basic':
1031 $ht_file = get_home_path().'.hh-htpasswd';
1032 foreach ($usernames as $k => $user) {
1033 $auth[] = sprintf('%s:{SHA}%s', $user, base64_encode(sha1($passwords[$k], true)));
1034 }
1035 break;
1036 case 'Digest':
1037 $ht_file = get_home_path().'.hh-htdigest';
1038 foreach ($usernames as $k => $user) {
1039 $auth[] = sprintf('%s:%s:%s', $user, $realm, md5($user.':'.$realm.':'.$passwords[$k]));
1040 }
1041 break;
1042 }
1043 $auth = join("\n", $auth);
1044
1045 return compact('ht_file', 'auth');
1046 }
1047 return false;
1048 }
1049
1050 function apache_cookie_security_directives() {
1051 $lines = array();
1052 if (get_option('hh_cookie_security') == 1) {
1053 $value = get_option('hh_cookie_security_value', array());
1054 if (isset($value['HttpOnly'])) {
1055 $lines[] = 'php_flag session.cookie_httponly on';
1056 }
1057 if (isset($value['Secure'])) {
1058 $lines[] = 'php_flag session.cookie_secure on';
1059 }
1060 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
1061 $lines[] = sprintf('php_value session.cookie_samesite "%s"', $value['SameSite']);
1062 }
1063 }
1064
1065 return $lines;
1066 }
1067
1068 function apache_check_requirements() {
1069 return check_filename(get_home_path().'.htaccess');
1070 }
1071
1072 function update_headers_directives() {
1073 $lines = array();
1074 if (get_option('hh_method') == 'htaccess') {
1075 $lines = apache_headers_directives();
1076 }
1077
1078 return insert_with_markers(get_home_path().'.htaccess', "HttpHeaders", $lines);
1079 }
1080
1081 function update_content_encoding_directives() {
1082 $lines = array();
1083 if (get_option('hh_method') == 'htaccess') {
1084 $lines = apache_content_encoding_directives();
1085 }
1086
1087 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersCompression", $lines);
1088 }
1089
1090 function update_expires_directives() {
1091 $lines = array();
1092 if (get_option('hh_method') == 'htaccess') {
1093 $lines = apache_expires_directives();
1094 }
1095
1096 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersExpires", $lines);
1097 }
1098
1099 function update_timing_directives() {
1100 $lines = array();
1101 if (get_option('hh_method') == 'htaccess') {
1102 $lines = apache_timing_directives();
1103 }
1104
1105 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersTiming", $lines);
1106 }
1107
1108 function update_auth_directives() {
1109 $lines = array();
1110 if (get_option('hh_method') == 'htaccess') {
1111 $lines = apache_auth_directives();
1112 }
1113
1114 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersAuth", $lines);
1115 }
1116
1117 function update_auth_credentials() {
1118 if (get_option('hh_method') == 'htaccess') {
1119 $credentials = apache_auth_credentials();
1120
1121 return @file_put_contents($credentials['ht_file'], $credentials['auth']);
1122 }
1123
1124 return false;
1125 }
1126
1127 function update_cookie_security_directives() {
1128 $lines = array();
1129 $is_apache = get_option('hh_method') == 'htaccess';
1130 $htaccess = get_home_path().'.htaccess';
1131 if (strpos(PHP_SAPI, 'cgi') !== false) {
1132 $filename = get_home_path().ini_get('user_ini.filename');
1133 $lines = php_cookie_security_directives();
1134 } elseif ($is_apache) {
1135 $filename = $htaccess;
1136 $lines = apache_cookie_security_directives();
1137 }
1138
1139 if (!$is_apache) {
1140 insert_with_markers($htaccess, "HttpHeadersCookieSecurity", array());
1141 }
1142
1143 return insert_with_markers($filename, "HttpHeadersCookieSecurity", $lines);
1144 }
1145
1146 function is_samesite_supported() {
1147 return version_compare(PHP_VERSION, '7.3.0', '>=');
1148 }
1149
1150 function http_headers_text_domain() {
1151 load_plugin_textdomain('http-headers', false, basename( dirname( __FILE__ ) ) . '/languages/');
1152 }
1153
1154 function http_headers_settings_link( $links ) {
1155 $url = get_admin_url() . 'options-general.php?page=http-headers';
1156 $settings_link = '<a href="' . $url . '">' . __('Settings', 'http-headers') . '</a>';
1157 array_unshift( $links, $settings_link );
1158 return $links;
1159 }
1160
1161 function http_headers_after_setup_theme() {
1162 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'http_headers_settings_link');
1163 }
1164
1165 function http_headers_enqueue($hook) {
1166 if ( 'http-headers.php' != $hook ) {
1167 # FIXME
1168 //return;
1169 }
1170
1171 wp_enqueue_script('http_headers_admin_scripts', plugin_dir_url( __FILE__ ) . 'assets/scripts.js', array(), '1.13.0', true);
1172 wp_localize_script('http_headers_admin_scripts', 'hh', array(
1173 'lbl_delete' => __('Delete', 'http-headers'),
1174 'lbl_value' => __('Value', 'http-headers'),
1175 ));
1176 wp_enqueue_style('http_headers_admin_styles', plugin_dir_url( __FILE__ ) . 'assets/styles.css');
1177 }
1178
1179 function http_headers_ajax_inspect() {
1180 check_ajax_referer('inspect');
1181 if (current_user_can('manage_options')) {
1182 include 'views/ajax-inspect.php';
1183 }
1184 wp_die();
1185 }
1186
1187 function http_headers_post_import() {
1188 check_admin_referer('import');
1189 global $wpdb;
1190 if (!(isset($_FILES['file']['tmp_name'])
1191 && is_uploaded_file($_FILES['file']['tmp_name'])
1192 && $_FILES['file']['error'] == UPLOAD_ERR_OK
1193 )) {
1194 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=100", get_admin_url()));
1195 exit;
1196 }
1197
1198 $string = @file_get_contents($_FILES['file']['tmp_name']);
1199 if ($string === false) {
1200 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=101", get_admin_url()));
1201 exit;
1202 }
1203
1204 $arr = preg_split('/;(\s+)?\n/', $string);
1205 foreach ($arr as $statement) {
1206 $wpdb->query($statement);
1207 }
1208
1209 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=OK", get_admin_url()));
1210 exit;
1211 }
1212
1213 function http_headers_post_export() {
1214 check_admin_referer('export');
1215 global $wpdb;
1216 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
1217 $opts = array();
1218 foreach ($options as $option)
1219 {
1220 $opts[] = $option[0];
1221 }
1222 $statement = sprintf("SELECT * FROM %s WHERE option_name IN ('%s');", $wpdb->options, join("','", $opts));
1223 $results = $wpdb->get_results($statement, ARRAY_A);
1224 $sql = array();
1225
1226 $indexes = array();
1227 foreach ($options as $option)
1228 {
1229 foreach ($results as $item)
1230 {
1231 if ($item['option_name'] == $option[0])
1232 {
1233 $indexes[$option[0]] = 1;
1234
1235 $value = str_replace("'", "''", $item['option_value']);
1236 $query = array();
1237 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1238 $query[] = sprintf("VALUES (NULL, '%s', '%s', '%s')", $item['option_name'], $value, $item['autoload']);
1239 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = '%s';", $value, $item['autoload']);
1240 $sql[] = join("\n", $query);
1241 break;
1242 }
1243 }
1244
1245 if (!isset($indexes[$option[0]]))
1246 {
1247 $query = array();
1248 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1249 $query[] = sprintf("VALUES (NULL, '%s', '%s', 'yes')", $option[0], $option[1]);
1250 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = 'yes';", $option[1]);
1251 $sql[] = join("\n", $query);
1252 }
1253 }
1254
1255 $sql = join("\n\n", $sql);
1256 $length = function_exists('mb_strlen') ? mb_strlen($sql) : strlen($sql);
1257 $name = sprintf('WP-HTTP-Headers-%u.sql', time());
1258
1259 # Send headers
1260 header('Pragma: public');
1261 header('Expires: 0');
1262 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1263 header('Cache-Control: private', false);
1264 header('Content-Transfer-Encoding: binary');
1265 header('Content-Disposition: attachment; filename="'.$name.'";');
1266 header('Content-Type: application/sql');
1267 header('Content-Length: ' . $length);
1268
1269 echo $sql;
1270 exit;
1271 }
1272
1273 function check_filename($filename) {
1274 if (!is_file($filename)) {
1275 return -1;
1276 }
1277
1278 clearstatcache();
1279 if (!is_writable($filename)) {
1280 return -2;
1281 }
1282
1283 return true;
1284 }
1285
1286 function check_webserver_requirements() {
1287 $method = get_option('hh_method');
1288 if ($method == 'htaccess') {
1289 return apache_check_requirements();
1290 }
1291
1292 return true;
1293 }
1294
1295 function check_php_requirements() {
1296 if (strpos(PHP_SAPI, 'cgi') !== false) {
1297 // cgi, cgi-fcgi, fpm-fcgi
1298 return check_filename(get_home_path().ini_get('user_ini.filename'));
1299 }
1300
1301 return true;
1302 }
1303
1304 function http_headers_logout() {
1305 if (get_option('hh_clear_site_data') == 1) {
1306 $values = get_option('hh_clear_site_data_value', array());
1307 $tmp = array_keys($values);
1308 if ($tmp) {
1309 header(sprintf('Clear-Site-Data: "%s"', join('", "', $tmp)));
1310 }
1311 }
1312 }
1313
1314 function http_headers_activate() {
1315 update_headers_directives();
1316 update_auth_credentials();
1317 update_auth_directives();
1318 update_content_encoding_directives();
1319 update_expires_directives();
1320 update_cookie_security_directives();
1321 update_timing_directives();
1322 }
1323
1324 function http_headers_deactivate() {
1325 $filename = get_home_path().'.htaccess';
1326
1327 insert_with_markers($filename, "HttpHeaders", array());
1328 insert_with_markers($filename, "HttpHeadersCompression", array());
1329 insert_with_markers($filename, "HttpHeadersExpires", array());
1330 insert_with_markers($filename, "HttpHeadersTiming", array());
1331 insert_with_markers($filename, "HttpHeadersAuth", array());
1332 insert_with_markers($filename, "HttpHeadersCookieSecurity", array());
1333 }
1334
1335 register_activation_hook(__FILE__, 'http_headers_activate');
1336 register_deactivation_hook(__FILE__, 'http_headers_deactivate');
1337 add_action('wp_logout', 'http_headers_logout');
1338
1339 if ( is_admin() ){ // admin actions
1340 add_action('admin_menu', 'http_headers_admin_add_page');
1341 add_action('admin_init', 'http_headers_admin');
1342 add_action("added_option", 'http_headers_option');
1343 add_action("updated_option", 'http_headers_option');
1344 add_action('admin_enqueue_scripts', 'http_headers_enqueue');
1345 add_action('after_setup_theme', 'http_headers_after_setup_theme');
1346 add_action('plugins_loaded', 'http_headers_text_domain');
1347 add_action('wp_ajax_inspect', 'http_headers_ajax_inspect');
1348 add_action('admin_post_import', 'http_headers_post_import');
1349 add_action('admin_post_export', 'http_headers_post_export');
1350 } else {
1351 // non-admin enqueues, actions, and filters
1352 add_action('send_headers', 'http_headers');
1353 }
1354
1355 function http_headers_admin_page() {
1356 include 'views/index.php';
1357 }