PluginProbe
HTTP Headers / 1.13.4
HTTP Headers v1.13.4
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.4, at http-headers.php

1,367 lines 49.1 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.4
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 (in_array($value, array('*', 'null'))) {
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 always unset %s', $header);
832 $lines[] = sprintf(' Header unset %s', $header);
833 }
834 $all = array();
835 foreach ($headers as $key => $value) {
836 if (in_array($key, array('WWW-Authenticate'))) {
837 continue;
838 }
839 if (in_array($key, array('X-Content-Type-Options'))) {
840 $all[] = sprintf(' Header always set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
841 continue;
842 }
843 if ($key == 'Strict-Transport-Security') {
844 $lines[] = sprintf(' Header set %s %s env=HTTPS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
845 continue;
846 }
847 if ($key == 'Access-Control-Allow-Origin') {
848 $all[] = ' <IfModule mod_setenvif.c>';
849 if (!is_array($value)) {
850 if ($value) {
851 $value = array($value);
852 } else {
853 $value = array();
854 }
855 }
856 //$value[] = 'null';
857 if (is_array($value))
858 {
859 $all[] = sprintf(' SetEnvIf Origin "^(%s)$" CORS=$0', str_replace('.', '\.', join('|', $value)));
860 } else {
861 $all[] = ' SetEnvIf Origin "^(.+)$" CORS=$0';
862 }
863 $all[] = ' </IfModule>';
864 $all[] = ' Header set Access-Control-Allow-Origin %{CORS}e env=CORS';
865 continue;
866 }
867 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'))) {
868 $all[] = sprintf(' Header set %s %s env=CORS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
869 continue;
870 }
871 $lines[] = sprintf(' Header set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
872 }
873 foreach ($append as $key => $value) {
874 $lines[] = sprintf(' Header append %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
875 }
876 if (!empty($lines)) {
877 $lines = array_merge(
878 array('<IfModule mod_headers.c>'),
879 $all,
880 array(' <FilesMatch "\.(php|html)$">'),
881 $lines,
882 array(' </FilesMatch>', '</IfModule>')
883 );
884 }
885 return $lines;
886 }
887
888 function apache_content_encoding_directives() {
889 $lines = array();
890 if (get_option('hh_content_encoding') == 1) {
891
892 $content_encoding_module = get_option('hh_content_encoding_module');
893 switch ($content_encoding_module) {
894 case 'brotli':
895 $module = 'mod_brotli.c';
896 $module_end = '';
897 $filter = 'BROTLI_COMPRESS';
898 break;
899 case 'brotli_deflate':
900 $module = "mod_brotli.c>\n<IfModule mod_deflate.c";
901 $module_end = "\n</IfModule>";
902 $filter = 'BROTLI_COMPRESS;DEFLATE';
903 break;
904 case 'deflate':
905 default:
906 $module = 'mod_deflate.c';
907 $module_end = '';
908 $filter = 'DEFLATE';
909 break;
910 }
911
912 $content_encoding_value = get_option('hh_content_encoding_value');
913 if (!$content_encoding_value) {
914 $content_encoding_value = array();
915 }
916
917 $content_encoding_ext = get_option('hh_content_encoding_ext');
918 if (!$content_encoding_ext) {
919 $content_encoding_ext = array();
920 }
921 if (!empty($content_encoding_ext)) {
922 $lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
923 $lines[] = sprintf(' <IfModule %s>', $module);
924 $lines[] = sprintf(' SetOutputFilter %s', $filter);
925 $lines[] = sprintf(' </IfModule>%s', $module_end);
926 $lines[] = '</FilesMatch>';
927 }
928 if (!empty($content_encoding_value)) {
929 if (!empty($lines)) {
930 $lines[] = '';
931 }
932 $lines[] = sprintf('<IfModule %s>', $module);
933 foreach (array_keys($content_encoding_value) as $item) {
934 $lines[] = sprintf(' AddOutputFilterByType %s %s', $filter, $item);
935 }
936 $lines[] = sprintf('</IfModule>%s', $module_end);
937 }
938 }
939
940 return $lines;
941 }
942
943 function apache_expires_directives() {
944 $lines = array();
945 if (get_option('hh_expires') == 1) {
946
947 $types = get_option('hh_expires_type', array());
948 $values = get_option('hh_expires_value', array());
949
950 $lines[] = '<IfModule mod_expires.c>';
951 $lines[] = ' ExpiresActive On';
952 foreach ($types as $type => $whatever) {
953 list($base, $period, $suffix) = explode('_', $values[$type]);
954 if (in_array($base, array('access', 'modification'))) {
955 $lines[] = $type != 'default'
956 ? sprintf(' ExpiresByType %s "%s plus %u %s"', $type, $base, $period, $suffix)
957 : sprintf(' ExpiresDefault "%s plus %u %s"', $base, $period, $suffix);
958 } elseif ($base == 'invalid') {
959 $lines[] = $type != 'default'
960 ? sprintf(' ExpiresByType %s A0', $type)
961 : sprintf(' ExpiresDefault A0');
962 }
963 }
964 $lines[] = '</IfModule>';
965 }
966
967 return $lines;
968 }
969
970 function apache_timing_directives() {
971 $lines = array();
972 if (get_option('hh_timing_allow_origin') == 1) {
973 $value = get_option('hh_timing_allow_origin_value');
974 switch ($value)
975 {
976 case 'origin':
977 $value = get_option('hh_timing_allow_origin_url');
978 break;
979 }
980 if (!empty($value))
981 {
982 $lines[] = '<IfModule mod_headers.c>';
983 $lines[] = ' <FilesMatch "\\.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$">';
984 $lines[] = sprintf(' Header set Timing-Allow-Origin "%s"', $value);
985 $lines[] = ' </FilesMatch>';
986 $lines[] = '</IfModule>';
987 }
988 }
989
990 return $lines;
991 }
992
993 function apache_auth_directives() {
994 $lines = array();
995 if (get_option('hh_www_authenticate') == 1) {
996
997 $type = get_option('hh_www_authenticate_type');
998
999 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
1000
1001 $lines[] = '<FilesMatch "^\.hh-ht(digest|passwd)$">';
1002 $lines[] = ' <IfModule mod_authz_core.c>';
1003 $lines[] = ' Require all denied';
1004 $lines[] = ' </IfModule>';
1005 $lines[] = ' <IfModule !mod_authz_core.c>';
1006 $lines[] = ' Order deny,allow';
1007 $lines[] = ' Deny from all';
1008 $lines[] = ' </IfModule>';
1009 $lines[] = '</FilesMatch>';
1010 // no empty AuthName
1011 $realm = get_option('hh_www_authenticate_realm'); // AuthName
1012 $realm = ($realm == '') ? 'restricted area':$realm; // Empty => give fixed value
1013
1014 $lines[] = sprintf('<IfModule mod_auth_%s.c>', strtolower($type));
1015 $lines[] = sprintf(' AuthType %s', get_option('hh_www_authenticate_type'));
1016 $lines[] = sprintf(' AuthName "%s"', $realm);
1017 $lines[] = sprintf(' AuthUserFile "%s%s"', get_home_path(), $file);
1018 $lines[] = ' Require valid-user';
1019 $lines[] = '</IfModule>';
1020 }
1021
1022 return $lines;
1023 }
1024
1025 function apache_auth_credentials() {
1026 if (get_option('hh_www_authenticate') == 1) {
1027 $type = get_option('hh_www_authenticate_type');
1028 $usernames = get_option('hh_www_authenticate_user', array());
1029 $passwords = get_option('hh_www_authenticate_pswd', array());
1030 if (!is_array($usernames)) {
1031 $usernames = array($usernames);
1032 }
1033 if (!is_array($passwords)) {
1034 $passwords = array($passwords);
1035 }
1036 $realm = get_option('hh_www_authenticate_realm');
1037 $auth = array();
1038 switch ($type) {
1039 case 'Basic':
1040 $ht_file = get_home_path().'.hh-htpasswd';
1041 foreach ($usernames as $k => $user) {
1042 $auth[] = sprintf('%s:{SHA}%s', $user, base64_encode(sha1($passwords[$k], true)));
1043 }
1044 break;
1045 case 'Digest':
1046 $ht_file = get_home_path().'.hh-htdigest';
1047 foreach ($usernames as $k => $user) {
1048 $auth[] = sprintf('%s:%s:%s', $user, $realm, md5($user.':'.$realm.':'.$passwords[$k]));
1049 }
1050 break;
1051 }
1052 $auth = join("\n", $auth);
1053
1054 return compact('ht_file', 'auth');
1055 }
1056 return false;
1057 }
1058
1059 function apache_cookie_security_directives() {
1060 $lines = array();
1061 if (get_option('hh_cookie_security') == 1) {
1062 $value = get_option('hh_cookie_security_value', array());
1063 if (isset($value['HttpOnly'])) {
1064 $lines[] = 'php_flag session.cookie_httponly on';
1065 }
1066 if (isset($value['Secure'])) {
1067 $lines[] = 'php_flag session.cookie_secure on';
1068 }
1069 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
1070 $lines[] = sprintf('php_value session.cookie_samesite "%s"', $value['SameSite']);
1071 }
1072 }
1073
1074 return $lines;
1075 }
1076
1077 function apache_check_requirements() {
1078 return check_filename(get_home_path().'.htaccess');
1079 }
1080
1081 function update_headers_directives() {
1082 $lines = array();
1083 if (get_option('hh_method') == 'htaccess') {
1084 $lines = apache_headers_directives();
1085 }
1086
1087 return insert_with_markers(get_home_path().'.htaccess', "HttpHeaders", $lines);
1088 }
1089
1090 function update_content_encoding_directives() {
1091 $lines = array();
1092 if (get_option('hh_method') == 'htaccess') {
1093 $lines = apache_content_encoding_directives();
1094 }
1095
1096 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersCompression", $lines);
1097 }
1098
1099 function update_expires_directives() {
1100 $lines = array();
1101 if (get_option('hh_method') == 'htaccess') {
1102 $lines = apache_expires_directives();
1103 }
1104
1105 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersExpires", $lines);
1106 }
1107
1108 function update_timing_directives() {
1109 $lines = array();
1110 if (get_option('hh_method') == 'htaccess') {
1111 $lines = apache_timing_directives();
1112 }
1113
1114 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersTiming", $lines);
1115 }
1116
1117 function update_auth_directives() {
1118 $lines = array();
1119 if (get_option('hh_method') == 'htaccess') {
1120 $lines = apache_auth_directives();
1121 }
1122
1123 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersAuth", $lines);
1124 }
1125
1126 function update_auth_credentials() {
1127 if (get_option('hh_method') == 'htaccess') {
1128 $credentials = apache_auth_credentials();
1129
1130 return @file_put_contents($credentials['ht_file'], $credentials['auth']);
1131 }
1132
1133 return false;
1134 }
1135
1136 function update_cookie_security_directives() {
1137 $lines = array();
1138 $is_apache = get_option('hh_method') == 'htaccess';
1139 $htaccess = get_home_path().'.htaccess';
1140 if (strpos(PHP_SAPI, 'cgi') !== false) {
1141 $filename = get_home_path().ini_get('user_ini.filename');
1142 $lines = php_cookie_security_directives();
1143 } elseif ($is_apache) {
1144 $filename = $htaccess;
1145 $lines = apache_cookie_security_directives();
1146 }
1147
1148 if (!$is_apache) {
1149 insert_with_markers($htaccess, "HttpHeadersCookieSecurity", array());
1150 }
1151
1152 return insert_with_markers($filename, "HttpHeadersCookieSecurity", $lines);
1153 }
1154
1155 function is_samesite_supported() {
1156 return version_compare(PHP_VERSION, '7.3.0', '>=');
1157 }
1158
1159 function http_headers_text_domain() {
1160 load_plugin_textdomain('http-headers', false, basename( dirname( __FILE__ ) ) . '/languages/');
1161 }
1162
1163 function http_headers_settings_link( $links ) {
1164 $url = get_admin_url() . 'options-general.php?page=http-headers';
1165 $settings_link = '<a href="' . $url . '">' . __('Settings', 'http-headers') . '</a>';
1166 array_unshift( $links, $settings_link );
1167 return $links;
1168 }
1169
1170 function http_headers_after_setup_theme() {
1171 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'http_headers_settings_link');
1172 }
1173
1174 function http_headers_enqueue($hook) {
1175 if ( 'http-headers.php' != $hook ) {
1176 # FIXME
1177 //return;
1178 }
1179
1180 wp_enqueue_script('http_headers_admin_scripts', plugin_dir_url( __FILE__ ) . 'assets/scripts.js', array(), '1.13.0', true);
1181 wp_localize_script('http_headers_admin_scripts', 'hh', array(
1182 'lbl_delete' => __('Delete', 'http-headers'),
1183 'lbl_value' => __('Value', 'http-headers'),
1184 ));
1185 wp_enqueue_style('http_headers_admin_styles', plugin_dir_url( __FILE__ ) . 'assets/styles.css');
1186 }
1187
1188 function http_headers_ajax_inspect() {
1189 check_ajax_referer('inspect');
1190 if (current_user_can('manage_options')) {
1191 include 'views/ajax-inspect.php';
1192 }
1193 wp_die();
1194 }
1195
1196 function http_headers_post_import() {
1197 check_admin_referer('import');
1198 global $wpdb;
1199 if (!(isset($_FILES['file']['tmp_name'])
1200 && is_uploaded_file($_FILES['file']['tmp_name'])
1201 && $_FILES['file']['error'] == UPLOAD_ERR_OK
1202 )) {
1203 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=100", get_admin_url()));
1204 exit;
1205 }
1206
1207 $string = @file_get_contents($_FILES['file']['tmp_name']);
1208 if ($string === false) {
1209 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=101", get_admin_url()));
1210 exit;
1211 }
1212
1213 $arr = preg_split('/;(\s+)?\n/', $string);
1214 foreach ($arr as $statement) {
1215 $statement = preg_replace("/(INSERT\s*INTO\s*)[\w\_]+options/", '${1}'.$wpdb->options, $statement);
1216 $wpdb->query($statement);
1217 }
1218
1219 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=OK", get_admin_url()));
1220 exit;
1221 }
1222
1223 function http_headers_post_export() {
1224 check_admin_referer('export');
1225 global $wpdb;
1226 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
1227 $opts = array();
1228 foreach ($options as $option)
1229 {
1230 $opts[] = $option[0];
1231 }
1232 $statement = sprintf("SELECT * FROM %s WHERE option_name IN ('%s');", $wpdb->options, join("','", $opts));
1233 $results = $wpdb->get_results($statement, ARRAY_A);
1234 $sql = array();
1235
1236 $indexes = array();
1237 foreach ($options as $option)
1238 {
1239 foreach ($results as $item)
1240 {
1241 if ($item['option_name'] == $option[0])
1242 {
1243 $indexes[$option[0]] = 1;
1244
1245 $value = str_replace("'", "''", $item['option_value']);
1246 $query = array();
1247 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1248 $query[] = sprintf("VALUES (NULL, '%s', '%s', '%s')", $item['option_name'], $value, $item['autoload']);
1249 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = '%s';", $value, $item['autoload']);
1250 $sql[] = join("\n", $query);
1251 break;
1252 }
1253 }
1254
1255 if (!isset($indexes[$option[0]]))
1256 {
1257 $query = array();
1258 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1259 $query[] = sprintf("VALUES (NULL, '%s', '%s', 'yes')", $option[0], $option[1]);
1260 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = 'yes';", $option[1]);
1261 $sql[] = join("\n", $query);
1262 }
1263 }
1264
1265 $sql = join("\n\n", $sql);
1266 $length = function_exists('mb_strlen') ? mb_strlen($sql) : strlen($sql);
1267 $name = sprintf('WP-HTTP-Headers-%u.sql', time());
1268
1269 # Send headers
1270 header('Pragma: public');
1271 header('Expires: 0');
1272 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1273 header('Cache-Control: private', false);
1274 header('Content-Transfer-Encoding: binary');
1275 header('Content-Disposition: attachment; filename="'.$name.'";');
1276 header('Content-Type: application/sql');
1277 header('Content-Length: ' . $length);
1278
1279 echo $sql;
1280 exit;
1281 }
1282
1283 function check_filename($filename) {
1284 if (!is_file($filename)) {
1285 return -1;
1286 }
1287
1288 clearstatcache();
1289 if (!is_writable($filename)) {
1290 return -2;
1291 }
1292
1293 return true;
1294 }
1295
1296 function check_webserver_requirements() {
1297 $method = get_option('hh_method');
1298 if ($method == 'htaccess') {
1299 return apache_check_requirements();
1300 }
1301
1302 return true;
1303 }
1304
1305 function check_php_requirements() {
1306 if (strpos(PHP_SAPI, 'cgi') !== false) {
1307 // cgi, cgi-fcgi, fpm-fcgi
1308 return check_filename(get_home_path().ini_get('user_ini.filename'));
1309 }
1310
1311 return true;
1312 }
1313
1314 function http_headers_logout() {
1315 if (get_option('hh_clear_site_data') == 1) {
1316 $values = get_option('hh_clear_site_data_value', array());
1317 $tmp = array_keys($values);
1318 if ($tmp) {
1319 header(sprintf('Clear-Site-Data: "%s"', join('", "', $tmp)));
1320 }
1321 }
1322 }
1323
1324 function http_headers_activate() {
1325 update_headers_directives();
1326 update_auth_credentials();
1327 update_auth_directives();
1328 update_content_encoding_directives();
1329 update_expires_directives();
1330 update_cookie_security_directives();
1331 update_timing_directives();
1332 }
1333
1334 function http_headers_deactivate() {
1335 $filename = get_home_path().'.htaccess';
1336
1337 insert_with_markers($filename, "HttpHeaders", array());
1338 insert_with_markers($filename, "HttpHeadersCompression", array());
1339 insert_with_markers($filename, "HttpHeadersExpires", array());
1340 insert_with_markers($filename, "HttpHeadersTiming", array());
1341 insert_with_markers($filename, "HttpHeadersAuth", array());
1342 insert_with_markers($filename, "HttpHeadersCookieSecurity", array());
1343 }
1344
1345 register_activation_hook(__FILE__, 'http_headers_activate');
1346 register_deactivation_hook(__FILE__, 'http_headers_deactivate');
1347 add_action('wp_logout', 'http_headers_logout');
1348
1349 if ( is_admin() ){ // admin actions
1350 add_action('admin_menu', 'http_headers_admin_add_page');
1351 add_action('admin_init', 'http_headers_admin');
1352 add_action("added_option", 'http_headers_option');
1353 add_action("updated_option", 'http_headers_option');
1354 add_action('admin_enqueue_scripts', 'http_headers_enqueue');
1355 add_action('after_setup_theme', 'http_headers_after_setup_theme');
1356 add_action('plugins_loaded', 'http_headers_text_domain');
1357 add_action('wp_ajax_inspect', 'http_headers_ajax_inspect');
1358 add_action('admin_post_import', 'http_headers_post_import');
1359 add_action('admin_post_export', 'http_headers_post_export');
1360 } else {
1361 // non-admin enqueues, actions, and filters
1362 add_action('send_headers', 'http_headers');
1363 }
1364
1365 function http_headers_admin_page() {
1366 include 'views/index.php';
1367 }