PluginProbe
HTTP Headers / 1.14.0
HTTP Headers v1.14.0
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.14.0, at http-headers.php

1,440 lines 51.6 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.14.0
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', 'stale-while-revalidate', 'stale-if-error'))) {
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 $tmp = array();
243 $value = get_option('hh_access_control_allow_headers_value');
244 if (!empty($value))
245 {
246 $tmp = array_merge($tmp, array_keys($value));
247 }
248 $custom = get_option('hh_access_control_allow_headers_custom');
249 if (!empty($custom))
250 {
251 $tmp = array_merge($tmp, $custom);
252 }
253 if ($tmp)
254 {
255 $tmp = array_filter($tmp, 'trim');
256 $tmp = array_unique($tmp);
257 $headers['Access-Control-Allow-Headers'] = join(', ', $tmp);
258 }
259 }
260 if (get_option('hh_access_control_expose_headers') == 1)
261 {
262 $tmp = array();
263 $value = get_option('hh_access_control_expose_headers_value');
264 if (!empty($value))
265 {
266 $tmp = array_merge($tmp, array_keys($value));
267 }
268 $custom = get_option('hh_access_control_expose_headers_custom');
269 if (!empty($custom))
270 {
271 $tmp = array_merge($tmp, $custom);
272 }
273 if ($tmp)
274 {
275 $tmp = array_filter($tmp, 'trim');
276 $tmp = array_unique($tmp);
277 $headers['Access-Control-Expose-Headers'] = join(', ', $tmp);
278 }
279 }
280 if (get_option('hh_p3p') == 1)
281 {
282 $value = get_option('hh_p3p_value');
283 if (!empty($value))
284 {
285 $headers['P3P'] = 'CP="' . join(' ', array_keys($value)) . '"';
286 }
287 }
288 if (get_option('hh_referrer_policy') == 1) {
289 $headers['Referrer-Policy'] = get_option('hh_referrer_policy_value');
290 }
291 if (get_option('hh_www_authenticate') == 1) {
292
293 switch (get_option('hh_www_authenticate_type')) {
294 case 'Basic':
295 if (!(isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])
296 && $_SERVER['PHP_AUTH_USER'] == get_option('hh_www_authenticate_user')
297 && $_SERVER['PHP_AUTH_PW'] == get_option('hh_www_authenticate_pswd'))) {
298 $headers['WWW-Authenticate'] = sprintf("Basic realm='%s'", get_option('hh_www_authenticate_realm'));
299 $statuses['HTTP/1.1'] = '401 Unauthorized';
300 }
301 break;
302 case 'Digest':
303 if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
304 $realm = get_option('hh_www_authenticate_realm');
305 $headers['WWW-Authenticate'] = sprintf("Digest realm='%s',qop='auth',nonce='%s',opaque='%s'",
306 $realm, uniqid(), md5($realm));
307 $statuses['HTTP/1.1'] = '401 Unauthorized';
308 }
309 break;
310 }
311 }
312 if (get_option('hh_vary') == 1)
313 {
314 $value = get_option('hh_vary_value');
315 if (!empty($value))
316 {
317 $append['Vary'] = join(', ', array_keys($value));
318 }
319 }
320
321 if (get_option('hh_expect_ct') == 1) {
322 $expect_ct_max_age = get_option('hh_expect_ct_max_age');
323 $expect_ct_report_uri = get_option('hh_expect_ct_report_uri');
324 if (!empty($expect_ct_report_uri) && !empty($expect_ct_max_age)) {
325
326 $expect_ct = array();
327 $expect_ct[] = sprintf("max-age=%u", $expect_ct_max_age);
328 if (get_option('hh_expect_ct_enforce') == 1) {
329 $expect_ct[] = "enforce";
330 }
331 $expect_ct[] = sprintf('report-uri="%s"', $expect_ct_report_uri);
332 $headers['Expect-CT'] = join(', ', $expect_ct);
333 }
334 }
335 if (get_option('hh_custom_headers') == 1) {
336 $custom_headers = get_option('hh_custom_headers_value');
337 if (isset($custom_headers['name'], $custom_headers['value']) && !empty($custom_headers['name'])) {
338 foreach ($custom_headers['name'] as $key => $name) {
339 $name = trim($name);
340 $value = trim($custom_headers['value'][$key]);
341 if (empty($name) || empty($value)) {
342 continue;
343 }
344 $headers[$name] = $value;
345 }
346 }
347 }
348 if (get_option('hh_report_to') == 1) {
349 $report_to = get_option('hh_report_to_value');
350 $tmp = array();
351 foreach ($report_to as $item)
352 {
353 $tmp[] = sprintf('{"url": "%s", "group": "%s", "max-age": %u%s}',
354 $item['url'], $item['group'], $item['max-age'], isset($item['includeSubDomains']) ? ', includeSubDomains' : NULL);
355 }
356 if ($tmp)
357 {
358 $headers['Report-To'] = join(', ', $tmp);
359 }
360 }
361 if (get_option('hh_feature_policy') == 1) {
362 $feature_policy_feature = get_option('hh_feature_policy_feature');
363 $feature_policy_value = get_option('hh_feature_policy_value');
364 $feature_policy_origin = get_option('hh_feature_policy_origin');
365 $tmp = array();
366 $feature_policy_feature = is_array($feature_policy_feature) ? $feature_policy_feature : array();
367 foreach (array_keys($feature_policy_feature) as $feature)
368 {
369 $value = NULL;
370 switch ($feature_policy_value[$feature])
371 {
372 case '*':
373 case "'none'":
374 $value = $feature_policy_value[$feature];
375 break;
376 case "'self'":
377 $value = $feature_policy_value[$feature];
378 if (!empty($feature_policy_origin[$feature]))
379 {
380 $value .= " " . $feature_policy_origin[$feature];
381 }
382 break;
383 case 'origin(s)':
384 $value = $feature_policy_origin[$feature];
385 break;
386 }
387
388 $tmp[] = sprintf("%s %s", $feature, $value);
389 }
390 if ($tmp)
391 {
392 $headers['Feature-Policy'] = join('; ', $tmp);
393 }
394 }
395
396 return array($headers, $statuses, $unset, $append);
397 }
398
399 function http_digest_parse($txt) {
400 $txt = stripslashes($txt);
401
402 $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
403 $data = array();
404 $keys = implode('|', array_keys($needed_parts));
405
406 preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
407
408 foreach ($matches as $m) {
409 $data[$m[1]] = $m[3] ? $m[3] : $m[4];
410 unset($needed_parts[$m[1]]);
411 }
412
413 return $needed_parts ? false : $data;
414 }
415
416 function php_auth_digest() {
417 if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || get_option('hh_www_authenticate_user') != $data['username']) {
418 die('Wrong Credentials!');
419 }
420
421 $A1 = md5($data['username'] . ':' . get_option('hh_www_authenticate_realm') . ':' . get_option('hh_www_authenticate_pswd'));
422 $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
423 $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
424 if ($data['response'] != $valid_response) {
425 die('Wrong Credentials!');
426 }
427 }
428
429 function php_content_encoding() {
430 if (substr_count($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
431 ob_start('ob_gzhandler');
432 } else {
433 ob_start();
434 }
435 }
436
437 function php_cookie_security_directives() {
438 $lines = array();
439 if (get_option('hh_cookie_security') == 1) {
440 $value = get_option('hh_cookie_security_value', array());
441 if (isset($value['HttpOnly'])) {
442 $lines[] = 'session.cookie_httponly = on';
443 }
444 if (isset($value['Secure'])) {
445 $lines[] = 'session.cookie_secure = on';
446 }
447 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
448 $lines[] = sprintf('session.cookie_samesite = "%s"', $value['SameSite']);
449 }
450 }
451
452 return $lines;
453 }
454
455 function http_headers() {
456 if (get_option('hh_method') !== 'php') {
457 return;
458 }
459 // PHP method below
460 list($headers, $statuses, $unset, $append) = get_http_headers();
461 $isCors = false;
462 foreach ($headers as $key => $value) {
463 if ($key == 'Access-Control-Allow-Origin') {
464 if (isset($_SERVER['HTTP_ORIGIN'])) {
465 if (in_array($value, array('*', 'null'))) {
466 $isCors = true;
467 header(sprintf("%s: *", $key));
468 }
469
470 if (is_array($value) && in_array($_SERVER['HTTP_ORIGIN'], $value)) {
471 $isCors = true;
472 header(sprintf("%s: %s", $key, $_SERVER['HTTP_ORIGIN']));
473 }
474 }
475 continue;
476 }
477 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'))) {
478 if ($isCors) {
479 header(sprintf("%s: %s", $key, $value));
480 }
481 continue;
482 }
483 header(sprintf("%s: %s", $key, $value));
484 }
485 foreach ($append as $key => $value) {
486 header(sprintf("%s: %s", $key, $value), false);
487 }
488 foreach ($unset as $header) {
489 if (function_exists('header_remove')) {
490 header_remove($header);
491 } else {
492 header("$header:");
493 }
494 }
495 foreach ($statuses as $key => $value) {
496 header(sprintf("%s %s", $key, $value));
497 exit;
498 }
499
500 if (get_option('hh_www_authenticate') == 1) {
501 php_auth_digest();
502 }
503
504 if (get_option('hh_content_encoding') == 1) {
505 php_content_encoding();
506 }
507 }
508
509 function http_headers_admin_add_page() {
510 add_options_page('HTTP Headers', 'HTTP Headers', 'manage_options', 'http-headers', 'http_headers_admin_page');
511 }
512
513 function http_headers_admin() {
514 register_setting('http-headers-mtd', 'hh_method');
515 register_setting('http-headers-xfo', 'hh_x_frame_options');
516 register_setting('http-headers-xfo', 'hh_x_frame_options_value');
517 register_setting('http-headers-xfo', 'hh_x_frame_options_domain');
518 register_setting('http-headers-xss', 'hh_x_xxs_protection');
519 register_setting('http-headers-xss', 'hh_x_xxs_protection_value');
520 register_setting('http-headers-xss', 'hh_x_xxs_protection_uri');
521 register_setting('http-headers-cto', 'hh_x_content_type_options');
522 register_setting('http-headers-cto', 'hh_x_content_type_options_value');
523 register_setting('http-headers-sts', 'hh_strict_transport_security');
524 register_setting('http-headers-sts', 'hh_strict_transport_security_value'); //obsolete
525 register_setting('http-headers-sts', 'hh_strict_transport_security_max_age');
526 register_setting('http-headers-sts', 'hh_strict_transport_security_sub_domains');
527 register_setting('http-headers-sts', 'hh_strict_transport_security_preload');
528 register_setting('http-headers-pkp', 'hh_public_key_pins');
529 register_setting('http-headers-pkp', 'hh_public_key_pins_sha256_1');
530 register_setting('http-headers-pkp', 'hh_public_key_pins_sha256_2');
531 register_setting('http-headers-pkp', 'hh_public_key_pins_max_age');
532 register_setting('http-headers-pkp', 'hh_public_key_pins_sub_domains');
533 register_setting('http-headers-pkp', 'hh_public_key_pins_report_uri');
534 register_setting('http-headers-pkp', 'hh_public_key_pins_report_only');
535 register_setting('http-headers-uac', 'hh_x_ua_compatible');
536 register_setting('http-headers-uac', 'hh_x_ua_compatible_value');
537 register_setting('http-headers-p3p', 'hh_p3p');
538 register_setting('http-headers-p3p', 'hh_p3p_value');
539 register_setting('http-headers-rp', 'hh_referrer_policy');
540 register_setting('http-headers-rp', 'hh_referrer_policy_value');
541 register_setting('http-headers-csp', 'hh_content_security_policy');
542 register_setting('http-headers-csp', 'hh_content_security_policy_value');
543 register_setting('http-headers-csp', 'hh_content_security_policy_report_only');
544 register_setting('http-headers-acao', 'hh_access_control_allow_origin');
545 register_setting('http-headers-acao', 'hh_access_control_allow_origin_value');
546 register_setting('http-headers-acao', 'hh_access_control_allow_origin_url');
547 register_setting('http-headers-acac', 'hh_access_control_allow_credentials');
548 register_setting('http-headers-acac', 'hh_access_control_allow_credentials_value');
549 register_setting('http-headers-acam', 'hh_access_control_allow_methods');
550 register_setting('http-headers-acam', 'hh_access_control_allow_methods_value');
551 register_setting('http-headers-acah', 'hh_access_control_allow_headers');
552 register_setting('http-headers-acah', 'hh_access_control_allow_headers_value');
553 register_setting('http-headers-acah', 'hh_access_control_allow_headers_custom');
554 register_setting('http-headers-aceh', 'hh_access_control_expose_headers');
555 register_setting('http-headers-aceh', 'hh_access_control_expose_headers_value');
556 register_setting('http-headers-aceh', 'hh_access_control_expose_headers_custom');
557 register_setting('http-headers-acma', 'hh_access_control_max_age');
558 register_setting('http-headers-acma', 'hh_access_control_max_age_value');
559 register_setting('http-headers-ce', 'hh_content_encoding');
560 register_setting('http-headers-ce', 'hh_content_encoding_module');
561 register_setting('http-headers-ce', 'hh_content_encoding_value');
562 register_setting('http-headers-ce', 'hh_content_encoding_ext');
563 register_setting('http-headers-vary', 'hh_vary');
564 register_setting('http-headers-vary', 'hh_vary_value');
565 register_setting('http-headers-xpb', 'hh_x_powered_by');
566 register_setting('http-headers-xpb', 'hh_x_powered_by_option');
567 register_setting('http-headers-xpb', 'hh_x_powered_by_value');
568 register_setting('http-headers-wwa', 'hh_www_authenticate');
569 register_setting('http-headers-wwa', 'hh_www_authenticate_type');
570 register_setting('http-headers-wwa', 'hh_www_authenticate_realm');
571 register_setting('http-headers-wwa', 'hh_www_authenticate_user');
572 register_setting('http-headers-wwa', 'hh_www_authenticate_pswd');
573 register_setting('http-headers-cc', 'hh_cache_control');
574 register_setting('http-headers-cc', 'hh_cache_control_value');
575 register_setting('http-headers-age', 'hh_age');
576 register_setting('http-headers-age', 'hh_age_value');
577 register_setting('http-headers-pra', 'hh_pragma');
578 register_setting('http-headers-pra', 'hh_pragma_value');
579 register_setting('http-headers-exp', 'hh_expires');
580 register_setting('http-headers-exp', 'hh_expires_value');
581 register_setting('http-headers-exp', 'hh_expires_type');
582 register_setting('http-headers-con', 'hh_connection');
583 register_setting('http-headers-con', 'hh_connection_value');
584 register_setting('http-headers-cose', 'hh_cookie_security');
585 register_setting('http-headers-cose', 'hh_cookie_security_value');
586 register_setting('http-headers-ect', 'hh_expect_ct');
587 register_setting('http-headers-ect', 'hh_expect_ct_max_age');
588 register_setting('http-headers-ect', 'hh_expect_ct_report_uri');
589 register_setting('http-headers-ect', 'hh_expect_ct_enforce');
590 register_setting('http-headers-tao', 'hh_timing_allow_origin');
591 register_setting('http-headers-tao', 'hh_timing_allow_origin_value');
592 register_setting('http-headers-tao', 'hh_timing_allow_origin_url');
593 register_setting('http-headers-che', 'hh_custom_headers');
594 register_setting('http-headers-che', 'hh_custom_headers_value');
595 register_setting('http-headers-xdo', 'hh_x_download_options');
596 register_setting('http-headers-xdo', 'hh_x_download_options_value');
597 register_setting('http-headers-xpcd', 'hh_x_permitted_cross_domain_policies');
598 register_setting('http-headers-xpcd', 'hh_x_permitted_cross_domain_policies_value');
599 register_setting('http-headers-xdpc', 'hh_x_dns_prefetch_control');
600 register_setting('http-headers-xdpc', 'hh_x_dns_prefetch_control_value');
601 register_setting('http-headers-rt', 'hh_report_to');
602 register_setting('http-headers-rt', 'hh_report_to_value');
603 register_setting('http-headers-fp', 'hh_feature_policy');
604 register_setting('http-headers-fp', 'hh_feature_policy_value');
605 register_setting('http-headers-fp', 'hh_feature_policy_feature');
606 register_setting('http-headers-fp', 'hh_feature_policy_origin');
607 register_setting('http-headers-csd', 'hh_clear_site_data');
608 register_setting('http-headers-csd', 'hh_clear_site_data_value');
609 register_setting('http-headers-cty', 'hh_content_type');
610 register_setting('http-headers-cty', 'hh_content_type_value');
611 }
612
613 function http_headers_option($option) {
614
615 include_once ABSPATH . 'wp-admin/includes/admin.php';
616
617 if (isset($_POST['hh_method']))
618 {
619 check_admin_referer('http-headers-mtd-options');
620 # When method is changed
621 http_headers_activate();
622
623 } elseif (get_option('hh_method') == 'htaccess') {
624 # When particular header is changed
625 switch (true) {
626 case array_key_exists('hh_www_authenticate', $_POST):
627 check_admin_referer('http-headers-wwa-options');
628 update_auth_credentials();
629 update_auth_directives();
630 break;
631 case array_key_exists('hh_content_encoding', $_POST):
632 check_admin_referer('http-headers-ce-options');
633 update_content_encoding_directives();
634 break;
635 case array_key_exists('hh_content_type', $_POST):
636 check_admin_referer('http-headers-cty-options');
637 update_content_type_directives();
638 break;
639 case array_key_exists('hh_expires', $_POST):
640 check_admin_referer('http-headers-exp-options');
641 update_expires_directives();
642 break;
643 case array_key_exists('hh_cookie_security', $_POST):
644 check_admin_referer('http-headers-cose-options');
645 update_cookie_security_directives();
646 break;
647 case array_key_exists('hh_timing_allow_origin', $_POST):
648 check_admin_referer('http-headers-tao-options');
649 update_timing_directives();
650 break;
651 case array_key_exists('option_page', $_POST) && strpos($_POST['option_page'], 'http-headers-') === 0:
652 check_admin_referer($_POST['option_page'].'-options');
653 update_headers_directives();
654 break;
655 }
656 }
657 }
658
659 function nginx_headers_directives() {
660 $lines = array();
661 list($headers, $statuses, $unset, $append) = get_http_headers();
662
663 foreach ($unset as $header) {
664 $lines[] = sprintf(' more_clear_headers "%s";', $header);
665 }
666 $cors = $cors_header = $cors_inner = $cors_footer = array();
667 $all = array();
668 foreach ($headers as $key => $value) {
669 if (in_array($key, array('WWW-Authenticate'))) {
670 continue;
671 }
672 if (in_array($key, array('X-Content-Type-Options'))) {
673 $all[] = sprintf('add_header %s %s always;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
674 continue;
675 }
676 if ($key == 'Access-Control-Allow-Origin' && is_array($value)) {
677 $cors_header[] = sprintf('if ($http_origin ~* ^(%s)$) {', str_replace('.', '\.', join('|', $value)));
678 $cors_footer[] = '}';
679 $cors_inner[] = ' add_header Access-Control-Allow-Origin "$http_origin";';
680 continue;
681 }
682 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'))) {
683 $cors_inner[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
684 continue;
685 }
686 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
687 }
688 foreach ($append as $key => $value) {
689 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
690 }
691 if (!empty($cors_inner))
692 {
693 $cors = array_merge(
694 $cors_header,
695 $cors_inner,
696 $cors_footer
697 );
698 }
699 if (!empty($lines)) {
700 $lines = array_merge(
701 $all,
702 $cors,
703 array('location ~* \.(php|html)$ {'),
704 $lines,
705 array('}')
706 );
707 }
708 return $lines;
709 }
710
711 function nginx_content_encoding_directives() {
712 $lines = array();
713 if (get_option('hh_content_encoding') == 1) {
714
715 $lines[] = 'gzip on;';
716
717 $content_encoding_value = get_option('hh_content_encoding_value');
718 if (!$content_encoding_value) {
719 $content_encoding_value = array();
720 }
721
722 $content_encoding_ext = get_option('hh_content_encoding_ext');
723 if (!$content_encoding_ext) {
724 $content_encoding_ext = array();
725 }
726 if (!empty($content_encoding_ext)) {
727 //$lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
728 }
729 if (!empty($content_encoding_value)) {
730 $lines[] = sprintf('gzip_types %s;', join(' ', array_keys($content_encoding_value)));
731 }
732 }
733 return $lines;
734 }
735
736 function nginx_content_type_directives() {
737 $lines = array();
738 if (get_option('hh_content_type') == 1) {
739 $values = get_option('hh_content_type_value', array());
740 foreach ($values as $ext => $media_type) {
741 $lines[] = sprintf("%s %s;", $media_type, $ext);
742 }
743 }
744
745 return $lines;
746 }
747
748 function nginx_expires_directives() {
749 $lines = array();
750 if (get_option('hh_expires') == 1) {
751
752 $types = get_option('hh_expires_type', array());
753 $values = get_option('hh_expires_value', array());
754
755 $lines[] = 'map $sent_http_content_type $expires {';
756 foreach ($types as $type => $whatever) {
757 list($base, $period, $suffix) = explode('_', $values[$type]);
758 if (in_array($base, array('access', 'modification'))) {
759 $lines[] = $type != 'default'
760 ? sprintf(' %s %u%s;', $type, $period, $suffix[0])
761 : sprintf(' default %u%s;', $period, $suffix[0]);
762 } elseif ($base == 'invalid') {
763 $lines[] = $type != 'default'
764 ? sprintf(' %s 0;', $type)
765 : sprintf(' default 0;');
766 }
767 }
768 $lines[] = '}';
769
770 $lines[] = 'expires $expires;';
771 }
772 return $lines;
773 }
774
775 function nginx_timing_directives() {
776 $lines = array();
777 if (get_option('hh_timing_allow_origin') == 1) {
778 $value = get_option('hh_timing_allow_origin_value');
779 switch ($value)
780 {
781 case 'origin':
782 $value = get_option('hh_timing_allow_origin_url');
783 break;
784 }
785 if (!empty($value))
786 {
787 $lines[] = 'location ~* \.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$ {';
788 $lines[] = sprintf(' add_header Timing-Allow-Origin "%s";', $value);
789 $lines[] = '}';
790 }
791 }
792 return $lines;
793 }
794
795 function nginx_auth_directives() {
796 $lines = array();
797 if (get_option('hh_www_authenticate') == 1) {
798
799 $type = get_option('hh_www_authenticate_type');
800
801 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
802
803 $lines[] = 'location ~ ^\.hh-ht(digest|passwd)$ {';
804 $lines[] = ' deny all;';
805 $lines[] = '}';
806
807 $lines[] = sprintf('location %s {', get_home_path());
808 if ($type == 'Basic') {
809 $lines[] = sprintf(' auth_basic "%s";', get_option('hh_www_authenticate_realm'));
810 $lines[] = sprintf(' auth_basic_user_file %s%s;', get_home_path(), $file);
811 } else {
812 $lines[] = sprintf(' auth_digest "%s";', get_option('hh_www_authenticate_realm'));
813 $lines[] = sprintf(' auth_digest_user_file %s%s;', get_home_path(), $file);
814 }
815 $lines[] = '}';
816 }
817 return $lines;
818 }
819
820 function nginx_auth_credentials() {
821 return apache_auth_credentials();
822 }
823
824 function nginx_cookie_security_directives() {
825 $lines = array();
826
827 //TODO
828
829 return $lines;
830 }
831
832 function nginx_check_requirements() {
833 //TODO scheduled for v2.0.0
834 return true;
835 }
836
837 function iis_headers_directives() {
838 //TODO scheduled for v2.0.0
839 }
840
841 function iis_content_encoding_directives() {
842 //TODO scheduled for v2.0.0
843 }
844
845 function iis_content_type_directives() {
846 //TODO scheduled for v2.0.0
847 }
848
849 function iis_expires_directives() {
850 //TODO scheduled for v2.0.0
851 }
852
853 function iis_timing_directives() {
854 //TODO scheduled for v2.0.0
855 }
856
857 function iis_auth_directives() {
858 //TODO scheduled for v2.0.0
859 }
860
861 function iis_auth_credentials() {
862 //TODO scheduled for v2.0.0
863 }
864
865 function iis_cookie_security_directives() {
866 //TODO scheduled for v2.0.0
867 }
868
869 function iis_check_requirements() {
870 //TODO scheduled for v2.0.0
871 return true;
872 }
873
874 function apache_headers_directives() {
875 $lines = array();
876 list($headers, $statuses, $unset, $append) = get_http_headers();
877
878 foreach ($unset as $header) {
879 $lines[] = sprintf(' Header always unset %s', $header);
880 $lines[] = sprintf(' Header unset %s', $header);
881 }
882 $all = array();
883 foreach ($headers as $key => $value) {
884 if (in_array($key, array('WWW-Authenticate'))) {
885 continue;
886 }
887 if (in_array($key, array('X-Content-Type-Options'))) {
888 $all[] = sprintf(' Header always set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
889 continue;
890 }
891 if ($key == 'Strict-Transport-Security') {
892 $lines[] = sprintf(' Header set %s %s env=HTTPS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
893 continue;
894 }
895 if ($key == 'Access-Control-Allow-Origin') {
896 $all[] = ' <IfModule mod_setenvif.c>';
897 if (!is_array($value)) {
898 if ($value) {
899 $value = array($value);
900 } else {
901 $value = array();
902 }
903 }
904 //$value[] = 'null';
905 if (is_array($value))
906 {
907 $all[] = sprintf(' SetEnvIf Origin "^(%s)$" CORS=$0', str_replace(array('.', '*'), array('\.', '\*'), join('|', $value)));
908 } else {
909 $all[] = ' SetEnvIf Origin "^(.+)$" CORS=$0';
910 }
911 $all[] = ' </IfModule>';
912 $all[] = ' Header set Access-Control-Allow-Origin %{CORS}e env=CORS';
913 continue;
914 }
915 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'))) {
916 $all[] = sprintf(' Header set %s %s env=CORS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
917 continue;
918 }
919 $lines[] = sprintf(' Header set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
920 }
921 foreach ($append as $key => $value) {
922 $lines[] = sprintf(' Header append %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
923 }
924 if (!empty($lines) || !empty($all)) {
925 $lines = array_merge(
926 array('<IfModule mod_headers.c>'),
927 $all,
928 array(' <FilesMatch "\.(php|html)$">'),
929 $lines,
930 array(' </FilesMatch>', '</IfModule>')
931 );
932 }
933 return $lines;
934 }
935
936 function apache_content_encoding_directives() {
937 $lines = array();
938 if (get_option('hh_content_encoding') == 1) {
939
940 $content_encoding_module = get_option('hh_content_encoding_module');
941 switch ($content_encoding_module) {
942 case 'brotli':
943 $module = 'mod_brotli.c';
944 $module_end = '';
945 $filter = 'BROTLI_COMPRESS';
946 break;
947 case 'brotli_deflate':
948 $module = "mod_brotli.c>\n<IfModule mod_deflate.c";
949 $module_end = "\n</IfModule>";
950 $filter = 'BROTLI_COMPRESS;DEFLATE';
951 break;
952 case 'deflate':
953 default:
954 $module = 'mod_deflate.c';
955 $module_end = '';
956 $filter = 'DEFLATE';
957 break;
958 }
959
960 $content_encoding_value = get_option('hh_content_encoding_value');
961 if (!$content_encoding_value) {
962 $content_encoding_value = array();
963 }
964
965 $content_encoding_ext = get_option('hh_content_encoding_ext');
966 if (!$content_encoding_ext) {
967 $content_encoding_ext = array();
968 }
969 if (!empty($content_encoding_ext)) {
970 $lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
971 $lines[] = sprintf(' <IfModule %s>', $module);
972 $lines[] = sprintf(' SetOutputFilter %s', $filter);
973 $lines[] = sprintf(' </IfModule>%s', $module_end);
974 $lines[] = '</FilesMatch>';
975 }
976 if (!empty($content_encoding_value)) {
977 if (!empty($lines)) {
978 $lines[] = '';
979 }
980 $lines[] = sprintf('<IfModule %s>', $module);
981 foreach (array_keys($content_encoding_value) as $item) {
982 $lines[] = sprintf(' AddOutputFilterByType %s %s', $filter, $item);
983 }
984 $lines[] = sprintf('</IfModule>%s', $module_end);
985 }
986 }
987
988 return $lines;
989 }
990
991 function apache_expires_directives() {
992 $lines = array();
993 if (get_option('hh_expires') == 1) {
994
995 $types = get_option('hh_expires_type', array());
996 $values = get_option('hh_expires_value', array());
997
998 $lines[] = '<IfModule mod_expires.c>';
999 $lines[] = ' ExpiresActive On';
1000 foreach ($types as $type => $whatever) {
1001 list($base, $period, $suffix) = explode('_', $values[$type]);
1002 if (in_array($base, array('access', 'modification'))) {
1003 $lines[] = $type != 'default'
1004 ? sprintf(' ExpiresByType %s "%s plus %u %s"', $type, $base, $period, $suffix)
1005 : sprintf(' ExpiresDefault "%s plus %u %s"', $base, $period, $suffix);
1006 } elseif ($base == 'invalid') {
1007 $lines[] = $type != 'default'
1008 ? sprintf(' ExpiresByType %s A0', $type)
1009 : sprintf(' ExpiresDefault A0');
1010 }
1011 }
1012 $lines[] = '</IfModule>';
1013 }
1014
1015 return $lines;
1016 }
1017
1018 function apache_content_type_directives() {
1019 $lines = array();
1020 if (get_option('hh_content_type') == 1) {
1021 $values = get_option('hh_content_type_value', array());
1022 $lines[] = '<IfModule mod_mime.c>';
1023 foreach ($values as $ext => $media_type) {
1024 $lines[] = sprintf(" AddType %s .%s", $media_type, $ext);
1025 }
1026 $lines[] = '</IfModule>';
1027 }
1028
1029 return $lines;
1030 }
1031
1032 function apache_timing_directives() {
1033 $lines = array();
1034 if (get_option('hh_timing_allow_origin') == 1) {
1035 $value = get_option('hh_timing_allow_origin_value');
1036 switch ($value)
1037 {
1038 case 'origin':
1039 $value = get_option('hh_timing_allow_origin_url');
1040 break;
1041 }
1042 if (!empty($value))
1043 {
1044 $lines[] = '<IfModule mod_headers.c>';
1045 $lines[] = ' <FilesMatch "\\.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$">';
1046 $lines[] = sprintf(' Header set Timing-Allow-Origin "%s"', $value);
1047 $lines[] = ' </FilesMatch>';
1048 $lines[] = '</IfModule>';
1049 }
1050 }
1051
1052 return $lines;
1053 }
1054
1055 function apache_auth_directives() {
1056 $lines = array();
1057 if (get_option('hh_www_authenticate') == 1) {
1058
1059 $type = get_option('hh_www_authenticate_type');
1060
1061 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
1062
1063 $lines[] = '<FilesMatch "^\.hh-ht(digest|passwd)$">';
1064 $lines[] = ' <IfModule mod_authz_core.c>';
1065 $lines[] = ' Require all denied';
1066 $lines[] = ' </IfModule>';
1067 $lines[] = ' <IfModule !mod_authz_core.c>';
1068 $lines[] = ' Order deny,allow';
1069 $lines[] = ' Deny from all';
1070 $lines[] = ' </IfModule>';
1071 $lines[] = '</FilesMatch>';
1072 // no empty AuthName
1073 $realm = get_option('hh_www_authenticate_realm'); // AuthName
1074 $realm = ($realm == '') ? 'restricted area':$realm; // Empty => give fixed value
1075
1076 $lines[] = sprintf('<IfModule mod_auth_%s.c>', strtolower($type));
1077 $lines[] = sprintf(' AuthType %s', get_option('hh_www_authenticate_type'));
1078 $lines[] = sprintf(' AuthName "%s"', $realm);
1079 $lines[] = sprintf(' AuthUserFile "%s%s"', get_home_path(), $file);
1080 $lines[] = ' Require valid-user';
1081 $lines[] = '</IfModule>';
1082 }
1083
1084 return $lines;
1085 }
1086
1087 function apache_auth_credentials() {
1088 if (get_option('hh_www_authenticate') == 1) {
1089 $type = get_option('hh_www_authenticate_type');
1090 $usernames = get_option('hh_www_authenticate_user', array());
1091 $passwords = get_option('hh_www_authenticate_pswd', array());
1092 if (!is_array($usernames)) {
1093 $usernames = array($usernames);
1094 }
1095 if (!is_array($passwords)) {
1096 $passwords = array($passwords);
1097 }
1098 $realm = get_option('hh_www_authenticate_realm');
1099 $auth = array();
1100 switch ($type) {
1101 case 'Basic':
1102 $ht_file = get_home_path().'.hh-htpasswd';
1103 foreach ($usernames as $k => $user) {
1104 $auth[] = sprintf('%s:{SHA}%s', $user, base64_encode(sha1($passwords[$k], true)));
1105 }
1106 break;
1107 case 'Digest':
1108 $ht_file = get_home_path().'.hh-htdigest';
1109 foreach ($usernames as $k => $user) {
1110 $auth[] = sprintf('%s:%s:%s', $user, $realm, md5($user.':'.$realm.':'.$passwords[$k]));
1111 }
1112 break;
1113 }
1114 $auth = join("\n", $auth);
1115
1116 return compact('ht_file', 'auth');
1117 }
1118 return false;
1119 }
1120
1121 function apache_cookie_security_directives() {
1122 $lines = array();
1123 if (get_option('hh_cookie_security') == 1) {
1124 $value = get_option('hh_cookie_security_value', array());
1125 if (isset($value['HttpOnly'])) {
1126 $lines[] = 'php_flag session.cookie_httponly on';
1127 }
1128 if (isset($value['Secure'])) {
1129 $lines[] = 'php_flag session.cookie_secure on';
1130 }
1131 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
1132 $lines[] = sprintf('php_value session.cookie_samesite "%s"', $value['SameSite']);
1133 }
1134 }
1135
1136 return $lines;
1137 }
1138
1139 function apache_check_requirements() {
1140 return check_filename(get_home_path().'.htaccess');
1141 }
1142
1143 function update_headers_directives() {
1144 $lines = array();
1145 if (get_option('hh_method') == 'htaccess') {
1146 $lines = apache_headers_directives();
1147 }
1148
1149 return insert_with_markers(get_home_path().'.htaccess', "HttpHeaders", $lines);
1150 }
1151
1152 function update_content_encoding_directives() {
1153 $lines = array();
1154 if (get_option('hh_method') == 'htaccess') {
1155 $lines = apache_content_encoding_directives();
1156 }
1157
1158 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersCompression", $lines);
1159 }
1160
1161 function update_expires_directives() {
1162 $lines = array();
1163 if (get_option('hh_method') == 'htaccess') {
1164 $lines = apache_expires_directives();
1165 }
1166
1167 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersExpires", $lines);
1168 }
1169
1170 function update_content_type_directives() {
1171 $lines = array();
1172 if (get_option('hh_method') == 'htaccess') {
1173 $lines = apache_content_type_directives();
1174 }
1175
1176 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersContentType", $lines);
1177 }
1178
1179 function update_timing_directives() {
1180 $lines = array();
1181 if (get_option('hh_method') == 'htaccess') {
1182 $lines = apache_timing_directives();
1183 }
1184
1185 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersTiming", $lines);
1186 }
1187
1188 function update_auth_directives() {
1189 $lines = array();
1190 if (get_option('hh_method') == 'htaccess') {
1191 $lines = apache_auth_directives();
1192 }
1193
1194 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersAuth", $lines);
1195 }
1196
1197 function update_auth_credentials() {
1198 if (get_option('hh_method') == 'htaccess') {
1199 $credentials = apache_auth_credentials();
1200
1201 return @file_put_contents($credentials['ht_file'], $credentials['auth']);
1202 }
1203
1204 return false;
1205 }
1206
1207 function update_cookie_security_directives() {
1208 $lines = array();
1209 $is_apache = get_option('hh_method') == 'htaccess';
1210 $htaccess = get_home_path().'.htaccess';
1211 if (strpos(PHP_SAPI, 'cgi') !== false) {
1212 $filename = get_home_path().ini_get('user_ini.filename');
1213 $lines = php_cookie_security_directives();
1214 } elseif ($is_apache) {
1215 $filename = $htaccess;
1216 $lines = apache_cookie_security_directives();
1217 }
1218
1219 if (!$is_apache) {
1220 insert_with_markers($htaccess, "HttpHeadersCookieSecurity", array());
1221 }
1222
1223 return insert_with_markers($filename, "HttpHeadersCookieSecurity", $lines);
1224 }
1225
1226 function is_samesite_supported() {
1227 return version_compare(PHP_VERSION, '7.3.0', '>=');
1228 }
1229
1230 function http_headers_text_domain() {
1231 load_plugin_textdomain('http-headers', false, basename( dirname( __FILE__ ) ) . '/languages/');
1232 }
1233
1234 function http_headers_settings_link( $links ) {
1235 $url = get_admin_url() . 'options-general.php?page=http-headers';
1236 $settings_link = '<a href="' . $url . '">' . __('Settings', 'http-headers') . '</a>';
1237 array_unshift( $links, $settings_link );
1238 return $links;
1239 }
1240
1241 function http_headers_after_setup_theme() {
1242 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'http_headers_settings_link');
1243 }
1244
1245 function http_headers_enqueue($hook) {
1246 if ( 'http-headers.php' != $hook ) {
1247 # FIXME
1248 //return;
1249 }
1250
1251 wp_enqueue_script('http_headers_admin_scripts', plugin_dir_url( __FILE__ ) . 'assets/scripts.js', array(), '1.14.0', true);
1252 wp_localize_script('http_headers_admin_scripts', 'hh', array(
1253 'lbl_delete' => __('Delete', 'http-headers'),
1254 'lbl_value' => __('Value', 'http-headers'),
1255 ));
1256 wp_enqueue_style('http_headers_admin_styles', plugin_dir_url( __FILE__ ) . 'assets/styles.css');
1257 }
1258
1259 function http_headers_ajax_inspect() {
1260 check_ajax_referer('inspect');
1261 if (current_user_can('manage_options')) {
1262 include 'views/ajax-inspect.php';
1263 }
1264 wp_die();
1265 }
1266
1267 function http_headers_post_import() {
1268 check_admin_referer('import');
1269 global $wpdb;
1270 if (!(isset($_FILES['file']['tmp_name'])
1271 && is_uploaded_file($_FILES['file']['tmp_name'])
1272 && $_FILES['file']['error'] == UPLOAD_ERR_OK
1273 )) {
1274 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=100", get_admin_url()));
1275 exit;
1276 }
1277
1278 $string = @file_get_contents($_FILES['file']['tmp_name']);
1279 if ($string === false) {
1280 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=101", get_admin_url()));
1281 exit;
1282 }
1283
1284 $arr = preg_split('/;(\s+)?\n/', $string);
1285 foreach ($arr as $statement) {
1286 $statement = preg_replace("/(INSERT\s*INTO\s*)[\w\_]+options/", '${1}'.$wpdb->options, $statement);
1287 $wpdb->query($statement);
1288 }
1289
1290 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=OK", get_admin_url()));
1291 exit;
1292 }
1293
1294 function http_headers_post_export() {
1295 check_admin_referer('export');
1296 global $wpdb;
1297 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
1298 $opts = array();
1299 foreach ($options as $option)
1300 {
1301 $opts[] = $option[0];
1302 }
1303 $statement = sprintf("SELECT * FROM %s WHERE option_name IN ('%s');", $wpdb->options, join("','", $opts));
1304 $results = $wpdb->get_results($statement, ARRAY_A);
1305 $sql = array();
1306
1307 $indexes = array();
1308 foreach ($options as $option)
1309 {
1310 foreach ($results as $item)
1311 {
1312 if ($item['option_name'] == $option[0])
1313 {
1314 $indexes[$option[0]] = 1;
1315
1316 $value = str_replace("'", "''", $item['option_value']);
1317 $query = array();
1318 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1319 $query[] = sprintf("VALUES (NULL, '%s', '%s', '%s')", $item['option_name'], $value, $item['autoload']);
1320 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = '%s';", $value, $item['autoload']);
1321 $sql[] = join("\n", $query);
1322 break;
1323 }
1324 }
1325
1326 if (!isset($indexes[$option[0]]))
1327 {
1328 $query = array();
1329 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1330 $query[] = sprintf("VALUES (NULL, '%s', '%s', 'yes')", $option[0], $option[1]);
1331 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = 'yes';", $option[1]);
1332 $sql[] = join("\n", $query);
1333 }
1334 }
1335
1336 $sql = join("\n\n", $sql);
1337 $length = function_exists('mb_strlen') ? mb_strlen($sql) : strlen($sql);
1338 $name = sprintf('WP-HTTP-Headers-%u.sql', time());
1339
1340 # Send headers
1341 header('Pragma: public');
1342 header('Expires: 0');
1343 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1344 header('Cache-Control: private', false);
1345 header('Content-Transfer-Encoding: binary');
1346 header('Content-Disposition: attachment; filename="'.$name.'";');
1347 header('Content-Type: application/sql');
1348 header('Content-Length: ' . $length);
1349
1350 echo $sql;
1351 exit;
1352 }
1353
1354 function check_filename($filename) {
1355 if (!is_file($filename)) {
1356 return -1;
1357 }
1358
1359 clearstatcache();
1360 if (!is_writable($filename)) {
1361 return -2;
1362 }
1363
1364 return true;
1365 }
1366
1367 function check_webserver_requirements() {
1368 $method = get_option('hh_method');
1369 if ($method == 'htaccess') {
1370 return apache_check_requirements();
1371 }
1372
1373 return true;
1374 }
1375
1376 function check_php_requirements() {
1377 if (strpos(PHP_SAPI, 'cgi') !== false) {
1378 // cgi, cgi-fcgi, fpm-fcgi
1379 return check_filename(get_home_path().ini_get('user_ini.filename'));
1380 }
1381
1382 return true;
1383 }
1384
1385 function http_headers_logout() {
1386 if (get_option('hh_clear_site_data') == 1) {
1387 $values = get_option('hh_clear_site_data_value', array());
1388 $tmp = array_keys($values);
1389 if ($tmp) {
1390 header(sprintf('Clear-Site-Data: "%s"', join('", "', $tmp)));
1391 }
1392 }
1393 }
1394
1395 function http_headers_activate() {
1396 update_headers_directives();
1397 update_auth_credentials();
1398 update_auth_directives();
1399 update_content_encoding_directives();
1400 update_content_type_directives();
1401 update_expires_directives();
1402 update_cookie_security_directives();
1403 update_timing_directives();
1404 }
1405
1406 function http_headers_deactivate() {
1407 $filename = get_home_path().'.htaccess';
1408
1409 insert_with_markers($filename, "HttpHeaders", array());
1410 insert_with_markers($filename, "HttpHeadersCompression", array());
1411 insert_with_markers($filename, "HttpHeadersContentType", array());
1412 insert_with_markers($filename, "HttpHeadersExpires", array());
1413 insert_with_markers($filename, "HttpHeadersTiming", array());
1414 insert_with_markers($filename, "HttpHeadersAuth", array());
1415 insert_with_markers($filename, "HttpHeadersCookieSecurity", array());
1416 }
1417
1418 register_activation_hook(__FILE__, 'http_headers_activate');
1419 register_deactivation_hook(__FILE__, 'http_headers_deactivate');
1420 add_action('wp_logout', 'http_headers_logout');
1421
1422 if ( is_admin() ){ // admin actions
1423 add_action('admin_menu', 'http_headers_admin_add_page');
1424 add_action('admin_init', 'http_headers_admin');
1425 add_action("added_option", 'http_headers_option');
1426 add_action("updated_option", 'http_headers_option');
1427 add_action('admin_enqueue_scripts', 'http_headers_enqueue');
1428 add_action('after_setup_theme', 'http_headers_after_setup_theme');
1429 add_action('plugins_loaded', 'http_headers_text_domain');
1430 add_action('wp_ajax_inspect', 'http_headers_ajax_inspect');
1431 add_action('admin_post_import', 'http_headers_post_import');
1432 add_action('admin_post_export', 'http_headers_post_export');
1433 } else {
1434 // non-admin enqueues, actions, and filters
1435 add_action('send_headers', 'http_headers');
1436 }
1437
1438 function http_headers_admin_page() {
1439 include 'views/index.php';
1440 }