PluginProbe ʕ •ᴥ•ʔ
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More / trunk
Reviews Feed – Add Testimonials and Customer Reviews From Google Reviews, Yelp, TripAdvisor, and More vtrunk
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.7 2.6.8 2.6.5 2.6.4 2.6.3 2.6.2 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 trunk 1.0 1.0.1 1.0.2 1.0.3 1.1 1.1.1 1.1.2 1.2.0 2.0 2.1.0 2.1.1 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1
reviews-feed / class / Common / UsageTracking / Core / Sender.php
reviews-feed / class / Common / UsageTracking / Core Last commit date
PayloadBuilder.php 6 days ago RegisterSite.php 6 days ago Scheduler.php 6 days ago Sender.php 6 days ago
Sender.php
119 lines
1 <?php
2
3 /**
4 * Sends the usage report payload to the API.
5 *
6 * @package SmashBalloon\Reviews\Common\UsageTracking\Core
7 * @since 1.0
8 */
9
10 namespace SmashBalloon\Reviews\Common\UsageTracking\Core;
11
12 use SmashBalloon\Reviews\Common\UsageTracking\Config;
13
14 if (! defined('ABSPATH')) {
15 exit;
16 }
17
18 class Sender {
19 /**
20 * Response body of the last non-2xx response, for error classification.
21 *
22 * @var string
23 */
24 private $last_error_body = '';
25
26 /**
27 * Send the usage report payload to the API.
28 * Skips send if payload exceeds max size to avoid timeouts.
29 *
30 * @param array $payload Full JSON-serializable payload.
31 * @return int HTTP status code of the response, or 0 when no request was
32 * made (encode failure, oversize payload, transport error).
33 * Callers treat 2xx as success; 401/403/410 mean the site
34 * token was rejected and should be re-registered.
35 */
36 public function send(array $payload): int
37 {
38 // Reset per send so a stale body from a prior call on the same
39 // instance can never influence last_error_rejected_token().
40 $this->last_error_body = '';
41
42 if ('' === Config::get_api_url()) {
43 // Filter kill switch — no base URL, no request.
44 return 0;
45 }
46
47 $url = Config::get_usage_report_url();
48 $body = wp_json_encode($payload);
49 if (false === $body) {
50 return 0;
51 }
52
53 $max_bytes = (int) apply_filters('sbr_smash_usage_tracking_max_payload_bytes', Config::MAX_PAYLOAD_BYTES);
54 if ($max_bytes > 0 && strlen($body) > $max_bytes) {
55 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG && function_exists('error_log')) {
56 error_log('[SBR Usage Tracking] Payload size ' . strlen($body) . ' exceeds max ' . $max_bytes . ', send skipped.');
57 }
58 return 0;
59 }
60
61 $timeout = (int) apply_filters('sbr_smash_usage_tracking_request_timeout', Config::REQUEST_TIMEOUT);
62 $timeout = max(15, min(120, $timeout));
63
64 $response = wp_remote_post(
65 $url,
66 array(
67 'method' => 'POST',
68 'timeout' => $timeout,
69 // No redirects and strict TLS: the request body is the full
70 // usage payload, so it must only ever reach the validated URL —
71 // a redirect (e.g. from a MITM of the API host) could hand it
72 // to an arbitrary or internal destination.
73 'redirection' => 0,
74 'sslverify' => true,
75 'reject_unsafe_urls' => true,
76 'httpversion' => '1.1',
77 'blocking' => true,
78 'headers' => array(
79 'Content-Type' => 'application/json',
80 ),
81 'body' => $body,
82 'user-agent' => 'SBR/' . (defined('SBRVER') ? SBRVER : '') . '; ' . get_bloginfo('url'),
83 )
84 );
85
86 if (is_wp_error($response)) {
87 return 0;
88 }
89
90 $code = (int) wp_remote_retrieve_response_code($response);
91 $this->last_error_body = ($code < 200 || $code >= 300) ? (string) wp_remote_retrieve_body($response) : '';
92
93 return $code;
94 }
95
96 /**
97 * Whether the last failed response rejected the site token specifically.
98 * The API returns 401/403/410 for auth failures, but a Laravel
99 * ValidationException for an unknown token arrives as 422 with a
100 * site_token entry in the errors object — distinguish that from a 422
101 * caused by a malformed payload, where re-registering would be wrong.
102 *
103 * @param int $code HTTP status code returned by send().
104 * @return bool
105 */
106 public function last_error_rejected_token(int $code): bool
107 {
108 if (in_array($code, array( 401, 403, 410 ), true)) {
109 return true;
110 }
111 if (422 !== $code || '' === $this->last_error_body) {
112 return false;
113 }
114 $decoded = json_decode($this->last_error_body, true);
115
116 return is_array($decoded) && isset($decoded['errors']['site_token']);
117 }
118 }
119