PluginProbe
HTTP Headers / 1.13.1
HTTP Headers v1.13.1
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.1, at http-headers.php

1,361 lines 48.7 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.1
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_vary', $_POST):
608 check_admin_referer('http-headers-vary-options');
609 update_content_encoding_directives();
610 break;
611 case array_key_exists('hh_expires', $_POST):
612 check_admin_referer('http-headers-exp-options');
613 update_expires_directives();
614 break;
615 case array_key_exists('hh_cookie_security', $_POST):
616 check_admin_referer('http-headers-cose-options');
617 update_cookie_security_directives();
618 break;
619 case array_key_exists('hh_timing_allow_origin', $_POST):
620 check_admin_referer('http-headers-tao-options');
621 update_timing_directives();
622 break;
623 case array_key_exists('option_page', $_POST) && strpos($_POST['option_page'], 'http-headers-') === 0:
624 check_admin_referer($_POST['option_page'].'-options');
625 update_headers_directives();
626 break;
627 }
628 }
629 }
630
631 function nginx_headers_directives() {
632 $lines = array();
633 list($headers, $statuses, $unset, $append) = get_http_headers();
634
635 foreach ($unset as $header) {
636 $lines[] = sprintf(' more_clear_headers "%s";', $header);
637 }
638 $cors = $cors_header = $cors_inner = $cors_footer = array();
639 $all = array();
640 foreach ($headers as $key => $value) {
641 if (in_array($key, array('WWW-Authenticate'))) {
642 continue;
643 }
644 if (in_array($key, array('X-Content-Type-Options'))) {
645 $all[] = sprintf('add_header %s %s always;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
646 continue;
647 }
648 if ($key == 'Access-Control-Allow-Origin' && is_array($value)) {
649 $cors_header[] = sprintf('if ($http_origin ~* ^(%s)$) {', str_replace('.', '\.', join('|', $value)));
650 $cors_footer[] = '}';
651 $cors_inner[] = ' add_header Access-Control-Allow-Origin "$http_origin";';
652 continue;
653 }
654 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'))) {
655 $cors_inner[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
656 continue;
657 }
658 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
659 }
660 foreach ($append as $key => $value) {
661 $lines[] = sprintf(' add_header %s %s;', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
662 }
663 if (!empty($cors_inner))
664 {
665 $cors = array_merge(
666 $cors_header,
667 $cors_inner,
668 $cors_footer
669 );
670 }
671 if (!empty($lines)) {
672 $lines = array_merge(
673 $all,
674 $cors,
675 array('location ~* \.(php|html)$ {'),
676 $lines,
677 array('}')
678 );
679 }
680 return $lines;
681 }
682
683 function nginx_content_encoding_directives() {
684 $lines = array();
685 if (get_option('hh_content_encoding') == 1) {
686
687 $lines[] = 'gzip on;';
688
689 $content_encoding_value = get_option('hh_content_encoding_value');
690 if (!$content_encoding_value) {
691 $content_encoding_value = array();
692 }
693
694 $content_encoding_ext = get_option('hh_content_encoding_ext');
695 if (!$content_encoding_ext) {
696 $content_encoding_ext = array();
697 }
698 if (!empty($content_encoding_ext)) {
699 //$lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
700 }
701 if (!empty($content_encoding_value)) {
702 $lines[] = sprintf('gzip_types %s;', join(' ', array_keys($content_encoding_value)));
703 }
704 }
705 return $lines;
706 }
707
708 function nginx_expires_directives() {
709 $lines = array();
710 if (get_option('hh_expires') == 1) {
711
712 $types = get_option('hh_expires_type', array());
713 $values = get_option('hh_expires_value', array());
714
715 $lines[] = 'map $sent_http_content_type $expires {';
716 foreach ($types as $type => $whatever) {
717 list($base, $period, $suffix) = explode('_', $values[$type]);
718 if (in_array($base, array('access', 'modification'))) {
719 $lines[] = $type != 'default'
720 ? sprintf(' %s %u%s;', $type, $period, $suffix[0])
721 : sprintf(' default %u%s;', $period, $suffix[0]);
722 } elseif ($base == 'invalid') {
723 $lines[] = $type != 'default'
724 ? sprintf(' %s 0;', $type)
725 : sprintf(' default 0;');
726 }
727 }
728 $lines[] = '}';
729
730 $lines[] = 'expires $expires;';
731 }
732 return $lines;
733 }
734
735 function nginx_timing_directives() {
736 $lines = array();
737 if (get_option('hh_timing_allow_origin') == 1) {
738 $value = get_option('hh_timing_allow_origin_value');
739 switch ($value)
740 {
741 case 'origin':
742 $value = get_option('hh_timing_allow_origin_url');
743 break;
744 }
745 if (!empty($value))
746 {
747 $lines[] = 'location ~* \.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$ {';
748 $lines[] = sprintf(' add_header Timing-Allow-Origin "%s";', $value);
749 $lines[] = '}';
750 }
751 }
752 return $lines;
753 }
754
755 function nginx_auth_directives() {
756 $lines = array();
757 if (get_option('hh_www_authenticate') == 1) {
758
759 $type = get_option('hh_www_authenticate_type');
760
761 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
762
763 $lines[] = 'location ~ ^\.hh-ht(digest|passwd)$ {';
764 $lines[] = ' deny all;';
765 $lines[] = '}';
766
767 $lines[] = sprintf('location %s {', get_home_path());
768 if ($type == 'Basic') {
769 $lines[] = sprintf(' auth_basic "%s";', get_option('hh_www_authenticate_realm'));
770 $lines[] = sprintf(' auth_basic_user_file %s%s;', get_home_path(), $file);
771 } else {
772 $lines[] = sprintf(' auth_digest "%s";', get_option('hh_www_authenticate_realm'));
773 $lines[] = sprintf(' auth_digest_user_file %s%s;', get_home_path(), $file);
774 }
775 $lines[] = '}';
776 }
777 return $lines;
778 }
779
780 function nginx_auth_credentials() {
781 return apache_auth_credentials();
782 }
783
784 function nginx_cookie_security_directives() {
785 $lines = array();
786
787 //TODO
788
789 return $lines;
790 }
791
792 function nginx_check_requirements() {
793 //TODO scheduled for v2.0.0
794 return true;
795 }
796
797 function iis_headers_directives() {
798 //TODO scheduled for v2.0.0
799 }
800
801 function iis_content_encoding_directives() {
802 //TODO scheduled for v2.0.0
803 }
804
805 function iis_expires_directives() {
806 //TODO scheduled for v2.0.0
807 }
808
809 function iis_timing_directives() {
810 //TODO scheduled for v2.0.0
811 }
812
813 function iis_auth_directives() {
814 //TODO scheduled for v2.0.0
815 }
816
817 function iis_auth_credentials() {
818 //TODO scheduled for v2.0.0
819 }
820
821 function iis_cookie_security_directives() {
822 //TODO scheduled for v2.0.0
823 }
824
825 function iis_check_requirements() {
826 //TODO scheduled for v2.0.0
827 return true;
828 }
829
830 function apache_headers_directives() {
831 $lines = array();
832 list($headers, $statuses, $unset, $append) = get_http_headers();
833
834 foreach ($unset as $header) {
835 $lines[] = sprintf(' Header unset %s', $header);
836 }
837 $all = array();
838 foreach ($headers as $key => $value) {
839 if (in_array($key, array('WWW-Authenticate'))) {
840 continue;
841 }
842 if (in_array($key, array('X-Content-Type-Options'))) {
843 $all[] = sprintf(' Header always set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
844 continue;
845 }
846 if ($key == 'Strict-Transport-Security') {
847 $lines[] = sprintf(' Header set %s %s env=HTTPS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
848 continue;
849 }
850 if ($key == 'Access-Control-Allow-Origin') {
851 $all[] = ' <IfModule mod_setenvif.c>';
852 if (!is_array($value)) {
853 if ($value) {
854 $value = array($value);
855 } else {
856 $value = array();
857 }
858 }
859 $value[] = 'null';
860 if (is_array($value))
861 {
862 $all[] = sprintf(' SetEnvIf Origin "^(%s)$" CORS=$0', str_replace('.', '\.', join('|', $value)));
863 } else {
864 $all[] = ' SetEnvIf Origin "^(.+)$" CORS=$0';
865 }
866 $all[] = ' </IfModule>';
867 $all[] = ' Header set Access-Control-Allow-Origin %{CORS}e env=CORS';
868 continue;
869 }
870 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'))) {
871 $all[] = sprintf(' Header set %s %s env=CORS', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
872 continue;
873 }
874 $lines[] = sprintf(' Header set %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
875 }
876 foreach ($append as $key => $value) {
877 $lines[] = sprintf(' Header append %s %s', $key, sprintf('%1$s%2$s%1$s', strpos($value, '"') === false ? '"' : "'", $value));
878 }
879 if (!empty($lines)) {
880 $lines = array_merge(
881 array('<IfModule mod_headers.c>'),
882 $all,
883 array(' <FilesMatch "\.(php|html)$">'),
884 $lines,
885 array(' </FilesMatch>', '</IfModule>')
886 );
887 }
888 return $lines;
889 }
890
891 function apache_content_encoding_directives() {
892 $lines = array();
893 if (get_option('hh_content_encoding') == 1) {
894
895 $content_encoding_module = get_option('hh_content_encoding_module');
896 switch ($content_encoding_module) {
897 case 'brotli':
898 $module = 'mod_brotli.c';
899 $module_end = '';
900 $filter = 'BROTLI_COMPRESS';
901 break;
902 case 'brotli_deflate':
903 $module = "mod_brotli.c>\n<IfModule mod_deflate.c";
904 $module_end = "\n</IfModule>";
905 $filter = 'BROTLI_COMPRESS;DEFLATE';
906 break;
907 case 'deflate':
908 default:
909 $module = 'mod_deflate.c';
910 $module_end = '';
911 $filter = 'DEFLATE';
912 break;
913 }
914
915 $content_encoding_value = get_option('hh_content_encoding_value');
916 if (!$content_encoding_value) {
917 $content_encoding_value = array();
918 }
919
920 $content_encoding_ext = get_option('hh_content_encoding_ext');
921 if (!$content_encoding_ext) {
922 $content_encoding_ext = array();
923 }
924 if (!empty($content_encoding_ext)) {
925 $lines[] = sprintf('<FilesMatch "\.(%s)$">', join('|', array_keys($content_encoding_ext)));
926 $lines[] = sprintf(' <IfModule %s>', $module);
927 $lines[] = sprinf(' SetOutputFilter %s', $filter);
928 $lines[] = sprintf(' </IfModule>%s', $module_end);
929 $lines[] = '</FilesMatch>';
930 }
931 if (!empty($content_encoding_value)) {
932 if (!empty($lines)) {
933 $lines[] = '';
934 }
935 $lines[] = sprintf('<IfModule %s>', $module);
936 foreach (array_keys($content_encoding_value) as $item) {
937 $lines[] = sprintf(' AddOutputFilterByType %s %s', $filter, $item);
938 }
939 $lines[] = sprintf('</IfModule>%s', $module_end);
940 }
941 }
942
943 return $lines;
944 }
945
946 function apache_expires_directives() {
947 $lines = array();
948 if (get_option('hh_expires') == 1) {
949
950 $types = get_option('hh_expires_type', array());
951 $values = get_option('hh_expires_value', array());
952
953 $lines[] = '<IfModule mod_expires.c>';
954 $lines[] = ' ExpiresActive On';
955 foreach ($types as $type => $whatever) {
956 list($base, $period, $suffix) = explode('_', $values[$type]);
957 if (in_array($base, array('access', 'modification'))) {
958 $lines[] = $type != 'default'
959 ? sprintf(' ExpiresByType %s "%s plus %u %s"', $type, $base, $period, $suffix)
960 : sprintf(' ExpiresDefault "%s plus %u %s"', $base, $period, $suffix);
961 } elseif ($base == 'invalid') {
962 $lines[] = $type != 'default'
963 ? sprintf(' ExpiresByType %s A0', $type)
964 : sprintf(' ExpiresDefault A0');
965 }
966 }
967 $lines[] = '</IfModule>';
968 }
969
970 return $lines;
971 }
972
973 function apache_timing_directives() {
974 $lines = array();
975 if (get_option('hh_timing_allow_origin') == 1) {
976 $value = get_option('hh_timing_allow_origin_value');
977 switch ($value)
978 {
979 case 'origin':
980 $value = get_option('hh_timing_allow_origin_url');
981 break;
982 }
983 if (!empty($value))
984 {
985 $lines[] = '<IfModule mod_headers.c>';
986 $lines[] = ' <FilesMatch "\\.(js|css|jpe?g|png|gif|eot|otf|svg|ttf|woff2?)$">';
987 $lines[] = sprintf(' Header set Timing-Allow-Origin "%s"', $value);
988 $lines[] = ' </FilesMatch>';
989 $lines[] = '</IfModule>';
990 }
991 }
992
993 return $lines;
994 }
995
996 function apache_auth_directives() {
997 $lines = array();
998 if (get_option('hh_www_authenticate') == 1) {
999
1000 $type = get_option('hh_www_authenticate_type');
1001
1002 $file = $type == 'Basic' ? '.hh-htpasswd' : '.hh-htdigest';
1003
1004 $lines[] = '<FilesMatch "^\.hh-ht(digest|passwd)$">';
1005 $lines[] = ' Order deny,allow';
1006 $lines[] = ' Deny from all';
1007 $lines[] = '</FilesMatch>';
1008
1009 $lines[] = sprintf('<IfModule mod_auth_%s.c>', strtolower($type));
1010 $lines[] = sprintf(' AuthType %s', get_option('hh_www_authenticate_type'));
1011 $lines[] = sprintf(' AuthName "%s"', get_option('hh_www_authenticate_realm'));
1012 $lines[] = sprintf(' AuthUserFile "%s%s"', get_home_path(), $file);
1013 $lines[] = ' Require valid-user';
1014 $lines[] = '</IfModule>';
1015 }
1016
1017 return $lines;
1018 }
1019
1020 function apache_auth_credentials() {
1021 if (get_option('hh_www_authenticate') == 1) {
1022 $type = get_option('hh_www_authenticate_type');
1023 $usernames = get_option('hh_www_authenticate_user', array());
1024 $passwords = get_option('hh_www_authenticate_pswd', array());
1025 if (!is_array($usernames)) {
1026 $usernames = array($usernames);
1027 }
1028 if (!is_array($passwords)) {
1029 $passwords = array($passwords);
1030 }
1031 $realm = get_option('hh_www_authenticate_realm');
1032 $auth = array();
1033 switch ($type) {
1034 case 'Basic':
1035 $ht_file = get_home_path().'.hh-htpasswd';
1036 foreach ($usernames as $k => $user) {
1037 $auth[] = sprintf('%s:{SHA}%s', $user, base64_encode(sha1($passwords[$k], true)));
1038 }
1039 break;
1040 case 'Digest':
1041 $ht_file = get_home_path().'.hh-htdigest';
1042 foreach ($usernames as $k => $user) {
1043 $auth[] = sprintf('%s:%s:%s', $user, $realm, md5($user.':'.$realm.':'.$passwords[$k]));
1044 }
1045 break;
1046 }
1047 $auth = join("\n", $auth);
1048
1049 return compact('ht_file', 'auth');
1050 }
1051 return false;
1052 }
1053
1054 function apache_cookie_security_directives() {
1055 $lines = array();
1056 if (get_option('hh_cookie_security') == 1) {
1057 $value = get_option('hh_cookie_security_value', array());
1058 if (isset($value['HttpOnly'])) {
1059 $lines[] = 'php_flag session.cookie_httponly on';
1060 }
1061 if (isset($value['Secure'])) {
1062 $lines[] = 'php_flag session.cookie_secure on';
1063 }
1064 if (isset($value['SameSite']) && in_array($value['SameSite'], array('None', 'Lax', 'Strict'))) {
1065 $lines[] = sprintf('php_value session.cookie_samesite "%s"', $value['SameSite']);
1066 }
1067 }
1068
1069 return $lines;
1070 }
1071
1072 function apache_check_requirements() {
1073 return check_filename(get_home_path().'.htaccess');
1074 }
1075
1076 function update_headers_directives() {
1077 $lines = array();
1078 if (get_option('hh_method') == 'htaccess') {
1079 $lines = apache_headers_directives();
1080 }
1081
1082 return insert_with_markers(get_home_path().'.htaccess', "HttpHeaders", $lines);
1083 }
1084
1085 function update_content_encoding_directives() {
1086 $lines = array();
1087 if (get_option('hh_method') == 'htaccess') {
1088 $lines = apache_content_encoding_directives();
1089 }
1090
1091 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersCompression", $lines);
1092 }
1093
1094 function update_expires_directives() {
1095 $lines = array();
1096 if (get_option('hh_method') == 'htaccess') {
1097 $lines = apache_expires_directives();
1098 }
1099
1100 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersExpires", $lines);
1101 }
1102
1103 function update_timing_directives() {
1104 $lines = array();
1105 if (get_option('hh_method') == 'htaccess') {
1106 $lines = apache_timing_directives();
1107 }
1108
1109 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersTiming", $lines);
1110 }
1111
1112 function update_auth_directives() {
1113 $lines = array();
1114 if (get_option('hh_method') == 'htaccess') {
1115 $lines = apache_auth_directives();
1116 }
1117
1118 return insert_with_markers(get_home_path().'.htaccess', "HttpHeadersAuth", $lines);
1119 }
1120
1121 function update_auth_credentials() {
1122 if (get_option('hh_method') == 'htaccess') {
1123 $credentials = apache_auth_credentials();
1124
1125 return @file_put_contents($credentials['ht_file'], $credentials['auth']);
1126 }
1127
1128 return false;
1129 }
1130
1131 function update_cookie_security_directives() {
1132 $lines = array();
1133 $is_apache = get_option('hh_method') == 'htaccess';
1134 $htaccess = get_home_path().'.htaccess';
1135 if (strpos(PHP_SAPI, 'cgi') !== false) {
1136 $filename = get_home_path().ini_get('user_ini.filename');
1137 $lines = php_cookie_security_directives();
1138 } elseif ($is_apache) {
1139 $filename = $htaccess;
1140 $lines = apache_cookie_security_directives();
1141 }
1142
1143 if (!$is_apache) {
1144 insert_with_markers($htaccess, "HttpHeadersCookieSecurity", array());
1145 }
1146
1147 return insert_with_markers($filename, "HttpHeadersCookieSecurity", $lines);
1148 }
1149
1150 function is_samesite_supported() {
1151 return version_compare(PHP_VERSION, '7.3.0', '>=');
1152 }
1153
1154 function http_headers_text_domain() {
1155 load_plugin_textdomain('http-headers', false, basename( dirname( __FILE__ ) ) . '/languages/');
1156 }
1157
1158 function http_headers_settings_link( $links ) {
1159 $url = get_admin_url() . 'options-general.php?page=http-headers';
1160 $settings_link = '<a href="' . $url . '">' . __('Settings', 'http-headers') . '</a>';
1161 array_unshift( $links, $settings_link );
1162 return $links;
1163 }
1164
1165 function http_headers_after_setup_theme() {
1166 add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'http_headers_settings_link');
1167 }
1168
1169 function http_headers_enqueue($hook) {
1170 if ( 'http-headers.php' != $hook ) {
1171 # FIXME
1172 //return;
1173 }
1174
1175 wp_enqueue_script('http_headers_admin_scripts', plugin_dir_url( __FILE__ ) . 'assets/scripts.js', array(), '1.13.0', true);
1176 wp_localize_script('http_headers_admin_scripts', 'hh', array(
1177 'lbl_delete' => __('Delete', 'http-headers'),
1178 'lbl_value' => __('Value', 'http-headers'),
1179 ));
1180 wp_enqueue_style('http_headers_admin_styles', plugin_dir_url( __FILE__ ) . 'assets/styles.css');
1181 }
1182
1183 function http_headers_ajax_inspect() {
1184 check_ajax_referer('inspect');
1185 if (current_user_can('manage_options')) {
1186 include 'views/ajax-inspect.php';
1187 }
1188 wp_die();
1189 }
1190
1191 function http_headers_post_import() {
1192 check_admin_referer('import');
1193 global $wpdb;
1194 if (!(isset($_FILES['file']['tmp_name'])
1195 && is_uploaded_file($_FILES['file']['tmp_name'])
1196 && $_FILES['file']['error'] == UPLOAD_ERR_OK
1197 )) {
1198 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=100", get_admin_url()));
1199 exit;
1200 }
1201
1202 $string = @file_get_contents($_FILES['file']['tmp_name']);
1203 if ($string === false) {
1204 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=ERR&code=101", get_admin_url()));
1205 exit;
1206 }
1207
1208 $arr = preg_split('/;(\s+)?\n/', $string);
1209 foreach ($arr as $statement) {
1210 $wpdb->query($statement);
1211 }
1212
1213 wp_redirect(sprintf("%soptions-general.php?page=http-headers&tab=advanced&status=OK", get_admin_url()));
1214 exit;
1215 }
1216
1217 function http_headers_post_export() {
1218 check_admin_referer('export');
1219 global $wpdb;
1220 $options = include dirname(__FILE__) . '/views/includes/options.inc.php';
1221 $opts = array();
1222 foreach ($options as $option)
1223 {
1224 $opts[] = $option[0];
1225 }
1226 $statement = sprintf("SELECT * FROM %s WHERE option_name IN ('%s');", $wpdb->options, join("','", $opts));
1227 $results = $wpdb->get_results($statement, ARRAY_A);
1228 $sql = array();
1229
1230 $indexes = array();
1231 foreach ($options as $option)
1232 {
1233 foreach ($results as $item)
1234 {
1235 if ($item['option_name'] == $option[0])
1236 {
1237 $indexes[$option[0]] = 1;
1238
1239 $value = str_replace("'", "''", $item['option_value']);
1240 $query = array();
1241 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1242 $query[] = sprintf("VALUES (NULL, '%s', '%s', '%s')", $item['option_name'], $value, $item['autoload']);
1243 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = '%s';", $value, $item['autoload']);
1244 $sql[] = join("\n", $query);
1245 break;
1246 }
1247 }
1248
1249 if (!isset($indexes[$option[0]]))
1250 {
1251 $query = array();
1252 $query[] = sprintf("INSERT INTO %s (option_id, option_name, option_value, autoload)", $wpdb->options);
1253 $query[] = sprintf("VALUES (NULL, '%s', '%s', 'yes')", $option[0], $option[1]);
1254 $query[] = sprintf("ON DUPLICATE KEY UPDATE option_value = '%s', autoload = 'yes';", $option[1]);
1255 $sql[] = join("\n", $query);
1256 }
1257 }
1258
1259 $sql = join("\n\n", $sql);
1260 $length = function_exists('mb_strlen') ? mb_strlen($sql) : strlen($sql);
1261 $name = sprintf('WP-HTTP-Headers-%u.sql', time());
1262
1263 # Send headers
1264 header('Pragma: public');
1265 header('Expires: 0');
1266 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
1267 header('Cache-Control: private', false);
1268 header('Content-Transfer-Encoding: binary');
1269 header('Content-Disposition: attachment; filename="'.$name.'";');
1270 header('Content-Type: application/sql');
1271 header('Content-Length: ' . $length);
1272
1273 echo $sql;
1274 exit;
1275 }
1276
1277 function check_filename($filename) {
1278 if (!is_file($filename)) {
1279 return -1;
1280 }
1281
1282 clearstatcache();
1283 if (!is_writable($filename)) {
1284 return -2;
1285 }
1286
1287 return true;
1288 }
1289
1290 function check_webserver_requirements() {
1291 $method = get_option('hh_method');
1292 if ($method == 'htaccess') {
1293 return apache_check_requirements();
1294 }
1295
1296 return true;
1297 }
1298
1299 function check_php_requirements() {
1300 if (strpos(PHP_SAPI, 'cgi') !== false) {
1301 // cgi, cgi-fcgi, fpm-fcgi
1302 return check_filename(get_home_path().ini_get('user_ini.filename'));
1303 }
1304
1305 return true;
1306 }
1307
1308 function http_headers_logout() {
1309 if (get_option('hh_clear_site_data') == 1) {
1310 $values = get_option('hh_clear_site_data_value', array());
1311 $tmp = array_keys($values);
1312 if ($tmp) {
1313 header(sprintf('Clear-Site-Data: "%s"', join('", "', $tmp)));
1314 }
1315 }
1316 }
1317
1318 function http_headers_activate() {
1319 update_headers_directives();
1320 update_auth_credentials();
1321 update_auth_directives();
1322 update_content_encoding_directives();
1323 update_expires_directives();
1324 update_cookie_security_directives();
1325 update_timing_directives();
1326 }
1327
1328 function http_headers_deactivate() {
1329 $filename = get_home_path().'.htaccess';
1330
1331 insert_with_markers($filename, "HttpHeaders", array());
1332 insert_with_markers($filename, "HttpHeadersCompression", array());
1333 insert_with_markers($filename, "HttpHeadersExpires", array());
1334 insert_with_markers($filename, "HttpHeadersTiming", array());
1335 insert_with_markers($filename, "HttpHeadersAuth", array());
1336 insert_with_markers($filename, "HttpHeadersCookieSecurity", array());
1337 }
1338
1339 register_activation_hook(__FILE__, 'http_headers_activate');
1340 register_deactivation_hook(__FILE__, 'http_headers_deactivate');
1341 add_action('wp_logout', 'http_headers_logout');
1342
1343 if ( is_admin() ){ // admin actions
1344 add_action('admin_menu', 'http_headers_admin_add_page');
1345 add_action('admin_init', 'http_headers_admin');
1346 add_action("added_option", 'http_headers_option');
1347 add_action("updated_option", 'http_headers_option');
1348 add_action('admin_enqueue_scripts', 'http_headers_enqueue');
1349 add_action('after_setup_theme', 'http_headers_after_setup_theme');
1350 add_action('plugins_loaded', 'http_headers_text_domain');
1351 add_action('wp_ajax_inspect', 'http_headers_ajax_inspect');
1352 add_action('admin_post_import', 'http_headers_post_import');
1353 add_action('admin_post_export', 'http_headers_post_export');
1354 } else {
1355 // non-admin enqueues, actions, and filters
1356 add_action('send_headers', 'http_headers');
1357 }
1358
1359 function http_headers_admin_page() {
1360 include 'views/index.php';
1361 }