PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.15.0
Independent Analytics – WordPress Analytics Plugin v2.15.0
2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / iawp-click-endpoint.php
independent-analytics Last commit date
IAWP 2 days ago dist 2 days ago freemius 2 days ago img 2 months ago javascript-source 2 days ago languages 2 days ago vendor 2 days ago views 2 days ago iawp-bootstrap.php 2 days ago iawp-click-endpoint.php 2 days ago iawp-complianz.php 3 months ago iawp.php 2 days ago readme.txt 2 days ago
iawp-click-endpoint.php
199 lines
1 <?php
2
3 // Warning. This file is a standalone PHP file whose sole purpose is to sanitize input and store
4 // that input in a CSV for later processing. WordPress is not loaded and the classes from the
5 // plugin are not available.
6
7 class Cache
8 {
9 private array $attributes;
10
11 public function __construct(array $attributes)
12 {
13 $this->attributes = $attributes;
14 }
15
16 public function is_pro(): bool
17 {
18 return $this->attributes['is_pro'] === true;
19 }
20
21 public function avoid_temporary_directory(): bool
22 {
23 return $this->attributes['avoid_temporary_directory'] === true;
24 }
25
26 public function get_custom_ip_header(): ?string
27 {
28 if (array_key_exists('custom_ip_header', $this->attributes)) {
29 return trim($this->attributes['custom_ip_header']);
30 }
31
32 return null;
33 }
34
35 public function get_visitor_token_salt(): string
36 {
37 return trim($this->attributes['visitor_token_salt']);
38 }
39 }
40
41 function get_cache(): ?Cache
42 {
43 $suffix = file_suffix();
44 $file = __DIR__ . "/iawp-click-config{$suffix}.php";
45
46 if (!is_readable($file)) {
47 return null;
48 }
49
50 $contents = file_get_contents($file);
51
52 if (false === $contents) {
53 return null;
54 }
55
56 $lines = explode("\n", $contents);
57
58 if (count($lines) !== 2) {
59 return null;
60 }
61
62 $json = trim($lines[1]);
63 $data = json_decode($json, true);
64
65 if (is_null($data)) {
66 return null;
67 }
68
69 return new Cache($data);
70
71 }
72
73 function get_ip_address(Cache $cache): ?string
74 {
75 $headers = [
76 'HTTP_X_FORWARDED_FOR',
77 'HTTP_X_FORWARDED',
78 'HTTP_FORWARDED_FOR',
79 'HTTP_FORWARDED',
80 'REMOTE_ADDR',
81 'HTTP_CF_CONNECTING_IP',
82 'HTTP_CLIENT_IP',
83 'HTTP_INCAP_CLIENT_IP',
84 'HTTP_CF_CONNECTING_IP',
85 ];
86
87 if (is_string($cache->get_custom_ip_header())) {
88 array_unshift($headers, $cache->get_custom_ip_header());
89 }
90
91 foreach ($headers as $header) {
92 if (isset($_SERVER[$header])) {
93 return explode(',', $_SERVER[$header])[0];
94 }
95 }
96
97 return null;
98 }
99
100 function get_visitor_token(Cache $cache): ?string
101 {
102 return md5($cache->get_visitor_token_salt() . get_ip_address($cache) . $_SERVER['HTTP_USER_AGENT']);
103 }
104
105 function trailing_slash(string $path): string
106 {
107 $path = rtrim($path, '/\\');
108
109 return $path . DIRECTORY_SEPARATOR;
110 }
111
112 /**
113 * A site will have a non-empty click file suffix only if it's part of a multi-site network.
114 */
115 function file_suffix(): string
116 {
117 $site_id = get_body()['siteId'] ?? null;
118
119 if (is_string($site_id) && strlen($site_id) === 8) {
120 return '-' . $site_id;
121 }
122
123 return '';
124 }
125
126 function get_click_data_file(Cache $cache): string
127 {
128 $suffix = file_suffix();
129
130 if (!$cache->avoid_temporary_directory()) {
131 $text_file = trailing_slash(sys_get_temp_dir()) . "iawp-click-data{$suffix}.txt";
132
133 if (is_file($text_file) && is_readable($text_file) && is_writable($text_file)) {
134 return $text_file;
135 }
136
137 if (file_put_contents($text_file, "") !== false && file_get_contents($text_file) !== false) {
138 return $text_file;
139 }
140 }
141
142 $php_file = trailing_slash(__DIR__) . "iawp-click-data{$suffix}.php";
143
144 if (is_file($php_file)) {
145 return $php_file;
146 }
147
148 if (file_put_contents($php_file, "<?php exit; ?>\n") !== false) {
149 return $php_file;
150 }
151
152 // Unable to create either data file so there's nowhere to store the click data
153 exit;
154 }
155
156 function get_body()
157 {
158 $json_body = file_get_contents('php://input');
159
160 return json_decode($json_body, true);
161 }
162
163 $body = get_body();
164
165 if (is_null($body)) {
166 exit;
167 }
168
169 $cache = get_cache();
170
171 if (is_null($cache) || !$cache->is_pro() || is_null(get_ip_address($cache))) {
172 exit;
173 }
174
175 $click_data_file = get_click_data_file($cache);
176
177 $data = [
178 'href' => $body['href'],
179 'classes' => $body['classes'],
180 'ids' => $body['ids'],
181 'payload' => json_encode($body['payload']),
182 'signature' => $body['signature'],
183 'visitor_token' => get_visitor_token($cache),
184 'created_at' => time(),
185 ];
186
187 if (!is_readable($click_data_file) || !is_writable($click_data_file)) {
188 exit;
189 }
190
191 $file_resource = fopen($click_data_file, 'a');
192
193 if (false === $file_resource) {
194 exit;
195 }
196
197 fwrite($file_resource, json_encode($data) . "\n");
198 fclose($file_resource);
199