PluginProbe
HTTP Headers / 1.13.3
HTTP Headers v1.13.3
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.3, at http-headers.php

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