-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathEndpoint_Installer.php
More file actions
executable file
·168 lines (139 loc) · 5.31 KB
/
Endpoint_Installer.php
File metadata and controls
executable file
·168 lines (139 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<?php
/**
* @package koko-analytics
* @license GPL-3.0+
* @author Danny van Kooten
*/
namespace KokoAnalytics;
use WP_Error;
class Endpoint_Installer
{
public function get_file_name(): string
{
return rtrim(ABSPATH, '/') . '/koko-analytics-collect.php';
}
public function make_relative_to_abspath(string $path): string
{
// make path relative to ABSPATH again
if (str_starts_with($path, ABSPATH)) {
$path = ltrim(substr($path, strlen(ABSPATH)), '/');
}
return $path;
}
public function get_file_contents(): string
{
$settings = get_settings();
$upload_dir = $this->make_relative_to_abspath(get_upload_dir());
$wp_timezone_string = wp_timezone_string();
$excluded_ip_addresses_string = var_export($settings['exclude_ip_addresses'], true);
// create require statements for all necessary files
$files = [
'wp-includes/plugin.php',
KOKO_ANALYTICS_PLUGIN_DIR . '/src/Resources/functions/collect.php',
];
$files = apply_filters('koko_analytics_endpoint_files', $files);
$files = array_unique($files);
$files = array_map([$this, 'make_relative_to_abspath'], $files);
$require_statements = array_reduce($files, function ($result, $f) {
$result .= "require '$f';\n";
return $result;
}, '');
return <<<EOT
<?php
/**
* @package koko-analytics
* @license GPL-3.0+
* @author Danny van Kooten
*
* This file acts as an optimized endpoint file for the Koko Analytics plugin.
*/
// path to pageviews.php file in uploads directory
define('KOKO_ANALYTICS_UPLOAD_DIR', '$upload_dir');
define('KOKO_ANALYTICS_TIMEZONE', '$wp_timezone_string');
// required files
$require_statements
// check if IP address is on list of addresses to ignore
if (!isset(\$_POST['test']) && in_array(KokoAnalytics\get_client_ip(), $excluded_ip_addresses_string)) {
exit;
}
// function call to collect the request data
KokoAnalytics\collect_request();
EOT;
}
/**
* @return string|bool
*/
public function install()
{
/* Do nothing if KOKO_ANALYTICS_CUSTOM_ENDPOINT is defined (means users disabled this feature or is using their own version of it) */
if (defined('KOKO_ANALYTICS_CUSTOM_ENDPOINT') || is_multisite()) {
return false;
}
/* If we made it this far we ideally want to use the custom endpoint file */
/* Therefore we schedule a recurring health check event to periodically re-attempt and re-test */
if (! wp_next_scheduled('koko_analytics_test_custom_endpoint')) {
wp_schedule_event(time() + HOUR_IN_SECONDS, 'hourly', 'koko_analytics_test_custom_endpoint');
}
// attempt to overwrite file with latest contents to ensure it's up-to-date
file_put_contents($this->get_file_name(), $this->get_file_contents());
return $this->test(true);
}
public function uninstall(): void
{
$file_name = $this->get_file_name();
if (is_file($file_name)) {
unlink($file_name);
}
wp_clear_scheduled_hook('koko_analytics_test_custom_endpoint');
}
/**
* @return string|bool
*/
public function test($force_test = false)
{
// No need to test if not using it
if (!$force_test && ! get_option('koko_analytics_use_custom_endpoint')) {
return true;
}
// Check if file exists
// Note that we're not checking whether we were able to write to the file
// To allow for users manually creating the file with the correct contents
$exists = is_file($this->get_file_name());
// Check if endpoint returns correct HTTP response
$works = $this->verify();
update_option('koko_analytics_use_custom_endpoint', $exists && !is_wp_error($works), true);
if (! $exists) {
return __('Error creating file.', 'koko-analytics');
}
if (is_wp_error($works)) {
return __('Error verifying HTTP response.', 'koko-analytics') . ' ' . join(', ', $works->get_error_messages());
}
return true;
}
/**
* Performs an HTTP request to the optimized endpoint to verify that it works
*/
private function verify()
{
$tracker_url = site_url('/koko-analytics-collect.php?test=1');
$response = wp_remote_post($tracker_url, [
'body' => [
'pa' => '/',
'po' => 0,
'test' => 1,
],
'timeout' => 10,
'sslverify' => false,
]);
if (is_wp_error($response)) {
return $response;
}
$status = wp_remote_retrieve_response_code($response);
$headers = wp_remote_retrieve_headers($response);
if ($status != 200 || ! isset($headers['Content-Type']) || ! str_contains($headers['Content-Type'], 'text/plain')) {
error_log(sprintf("Koko Analaytics: Error verifying optimized endpoint because it did not return the expected HTTP response.\nHTTP code: %s\nHTTP headers: %s\nHTTP body: %s", $status, var_export($headers, true), wp_remote_retrieve_body($response)));
return new WP_Error('response_mismatch', __('Unexpected response headers.', 'koko-analytics'));
}
return true;
}
}