PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 9.1.3
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v9.1.3
9.1.3 9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 All 222 releases
← All changes | vendor/posthog/posthog-php/lib/Client.php +28 -467 8.5.379.1.3 View file →
@@ -7,12 +7,11 @@
7 7 use PostHog\Consumer\ForkCurl;
8 8 use PostHog\Consumer\LibCurl;
9 9 use PostHog\Consumer\Socket;
10 10
11 -const SIZE_LIMIT = 50_000;
12 -
13 11 class Client
14 12 {
13 +
15 14 private const CONSUMERS = [
16 15 "socket" => Socket::class,
17 16 "file" => File::class,
18 17 "fork_curl" => ForkCurl::class,
@@ -25,18 +24,8 @@
25 24 */
26 25 private $apiKey;
27 26
28 27 /**
29 - * @var string
30 - */
31 - private $personalAPIKey;
32 -
33 - /**
34 - * @var integer
35 - */
36 - private $featureFlagsRequestTimeout;
37 -
38 - /**
39 28 * Consumer object handles queueing and bundling requests to PostHog.
40 29 *
41 30 * @var Consumer
42 31 */
@@ -44,32 +33,12 @@
44 33
45 34 /**
46 35 * @var HttpClient
47 36 */
48 - public $httpClient;
37 + private $httpClient;
49 38
50 - /**
51 - * @var array
52 - */
53 - public $featureFlags;
54 39
55 40 /**
56 - * @var array
57 - */
58 - public $groupTypeMapping;
59 -
60 - /**
61 - * @var array
62 - */
63 - public $cohorts;
64 -
65 -
66 - /**
67 - * @var SizeLimitedHash
68 - */
69 - public $distinctIdsFeatureFlagsReported;
70 -
71 - /**
72 41 * Create a new posthog object with your app's API key
73 42 * key
74 43 *
75 44 * @param string $apiKey
@@ -75,42 +44,20 @@
75 44 * @param string $apiKey
76 45 * @param array $options array of consumer options [optional]
77 46 * @param HttpClient|null $httpClient
78 47 */
79 - public function __construct(
80 - string $apiKey,
81 - array $options = [],
82 - ?HttpClient $httpClient = null,
83 - ?string $personalAPIKey = null,
84 - bool $loadFeatureFlags = true,
85 - ) {
48 + public function __construct(string $apiKey, array $options = [], ?HttpClient $httpClient = null)
49 + {
86 50 $this->apiKey = $apiKey;
87 - $this->personalAPIKey = $personalAPIKey;
88 51 $Consumer = self::CONSUMERS[$options["consumer"] ?? "lib_curl"];
89 - $this->consumer = new $Consumer($apiKey, $options, $httpClient);
52 + $this->consumer = new $Consumer($apiKey, $options);
90 53 $this->httpClient = $httpClient !== null ? $httpClient : new HttpClient(
91 54 $options['host'] ?? "app.posthog.com",
92 55 $options['ssl'] ?? true,
93 - (int) ($options['maximum_backoff_duration'] ?? 10000),
56 + 10000,
94 57 false,
95 - $options["debug"] ?? false,
96 - null,
97 - (int) ($options['timeout'] ?? 10000)
58 + $options["debug"] ?? false
98 59 );
99 - $this->featureFlagsRequestTimeout = (int) ($options['feature_flag_request_timeout_ms'] ?? 3000);
100 - $this->featureFlags = [];
101 - $this->groupTypeMapping = [];
102 - $this->cohorts = [];
103 - $this->distinctIdsFeatureFlagsReported = new SizeLimitedHash(SIZE_LIMIT);
104 -
105 - // Populate featureflags and grouptypemapping if possible
106 - if (
107 - count($this->featureFlags) == 0
108 - && !is_null($this->personalAPIKey)
109 - && $loadFeatureFlags
110 - ) {
111 - $this->loadFlags();
112 - }
113 60 }
114 61
115 62 public function __destruct()
116 63 {
@@ -127,34 +74,8 @@
127 74 {
128 75 $message = $this->message($message);
129 76 $message["type"] = "capture";
130 77
131 - if (array_key_exists('$groups', $message)) {
132 - $message["properties"]['$groups'] = $message['$groups'];
133 - }
134 -
135 - $extraProperties = [];
136 - $flags = [];
137 - if (array_key_exists("send_feature_flags", $message) && $message["send_feature_flags"]) {
138 - $flags = $this->fetchFeatureVariants($message["distinct_id"], $message["groups"]);
139 - } elseif (count($this->featureFlags) != 0) {
140 - # Local evaluation is enabled, flags are loaded, so try and get all flags we can without going to the server
141 - $flags = $this->getAllFlags($message["distinct_id"], $message["groups"], [], [], true);
142 - }
143 -
144 - // Add all feature variants to event
145 - foreach ($flags as $flagKey => $flagValue) {
146 - $extraProperties[sprintf('$feature/%s', $flagKey)] = $flagValue;
147 - }
148 -
149 - // Add all feature flag keys that aren't false to $active_feature_flags
150 - // decide v2 does this automatically, but we need it for when we upgrade to v3
151 - $extraProperties['$active_feature_flags'] = array_keys(array_filter($flags, function ($flagValue) {
152 - return $flagValue !== false;
153 - }));
154 -
155 - $message["properties"] = array_merge($extraProperties, $message["properties"]);
156 -
157 78 return $this->consumer->capture($message);
158 79 }
159 80
160 81 /**
@@ -180,11 +101,10 @@
180 101 * decide if the feature flag is enabled for this distinct id.
181 102 *
182 103 * @param string $key
183 104 * @param string $distinctId
105 + * @param mixed $defaultValue
184 106 * @param array $groups
185 - * @param array $personProperties
186 - * @param array $groupProperties
187 107 * @return bool
188 108 * @throws Exception
189 109 */
190 110 public function isFeatureEnabled(
@@ -189,356 +109,44 @@
189 109 */
190 110 public function isFeatureEnabled(
191 111 string $key,
192 112 string $distinctId,
193 - array $groups = array(),
194 - array $personProperties = array(),
195 - array $groupProperties = array(),
196 - bool $onlyEvaluateLocally = false,
197 - bool $sendFeatureFlagEvents = true
198 - ): null | bool {
199 - $result = $this->getFeatureFlag(
200 - $key,
201 - $distinctId,
202 - $groups,
203 - $personProperties,
204 - $groupProperties,
205 - $onlyEvaluateLocally,
206 - $sendFeatureFlagEvents
207 - );
113 + $defaultValue = false,
114 + array $groups = array()
115 + ): bool {
116 + $flags = $this->fetchEnabledFeatureFlags($distinctId, $groups);
208 117
209 - if (is_null($result)) {
210 - return $result;
211 - } else {
212 - return boolval($result);
213 - }
214 - }
118 + $result = in_array($key, $flags);
215 119
216 - /**
217 - * get the feature flag value for this distinct id.
218 - *
219 - * @param string $key
220 - * @param string $distinctId
221 - * @param array $groups
222 - * @param array $personProperties
223 - * @param array $groupProperties
224 - * @return bool | string
225 - * @throws Exception
226 - */
227 - public function getFeatureFlag(
228 - string $key,
229 - string $distinctId,
230 - array $groups = array(),
231 - array $personProperties = array(),
232 - array $groupProperties = array(),
233 - bool $onlyEvaluateLocally = false,
234 - bool $sendFeatureFlagEvents = true
235 - ): null | bool | string {
236 - [$personProperties, $groupProperties] = $this->addLocalPersonAndGroupProperties(
237 - $distinctId,
238 - $groups,
239 - $personProperties,
240 - $groupProperties
241 - );
242 - $result = null;
243 -
244 - foreach ($this->featureFlags as $flag) {
245 - if ($flag["key"] == $key) {
246 - try {
247 - $result = $this->computeFlagLocally(
248 - $flag,
249 - $distinctId,
250 - $groups,
251 - $personProperties,
252 - $groupProperties
253 - );
254 - } catch (InconclusiveMatchException $e) {
255 - $result = null;
256 - } catch (Exception $e) {
257 - $result = null;
258 - error_log("[PostHog][Client] Error while computing variant:" . $e->getMessage());
259 - }
260 - }
261 - }
262 -
263 - $flagWasEvaluatedLocally = !is_null($result);
264 - $requestId = null;
265 - $flagDetail = null;
266 -
267 - if (!$flagWasEvaluatedLocally && !$onlyEvaluateLocally) {
268 - try {
269 - $response = $this->fetchFlagsResponse($distinctId, $groups, $personProperties, $groupProperties);
270 - $requestId = isset($response['requestId']) ? $response['requestId'] : null;
271 - $flagDetail = isset($response['flags'][$key]) ? $response['flags'][$key] : null;
272 - $featureFlags = $response['featureFlags'] ?? [];
273 - if (array_key_exists($key, $featureFlags)) {
274 - $result = $featureFlags[$key];
275 - } else {
276 - $result = null;
277 - }
278 - } catch (Exception $e) {
279 - error_log("[PostHog][Client] Unable to get feature variants:" . $e->getMessage());
280 - $result = null;
281 - }
282 - }
283 -
284 - if ($sendFeatureFlagEvents && !$this->distinctIdsFeatureFlagsReported->contains($key, $distinctId)) {
285 - $properties = [
120 + $this->capture([
121 + "properties" => [
286 122 '$feature_flag' => $key,
287 123 '$feature_flag_response' => $result,
288 - ];
124 + ],
125 + "distinct_id" => $distinctId,
126 + "event" => '$feature_flag_called',
127 + ]);
289 128
290 - if (!is_null($requestId)) {
291 - $properties['$feature_flag_request_id'] = $requestId;
292 - }
293 -
294 - if (!is_null($flagDetail)) {
295 - $properties['$feature_flag_id'] = $flagDetail['metadata']['id'];
296 - $properties['$feature_flag_version'] = $flagDetail['metadata']['version'];
297 - $properties['$feature_flag_reason'] = $flagDetail['reason']['description'];
298 - }
299 -
300 - $this->capture([
301 - "properties" => $properties,
302 - "distinct_id" => $distinctId,
303 - "event" => '$feature_flag_called',
304 - '$groups' => $groups
305 - ]);
306 - $this->distinctIdsFeatureFlagsReported->add($key, $distinctId);
129 + if ($result) {
130 + return true;
307 131 }
308 -
309 - if (!is_null($result)) {
310 - return $result;
311 - }
312 - return null;
132 + return $defaultValue;
313 133 }
314 134
315 - /**
316 - * @param string $key
317 - * @param string $distinctId
318 - * @param array $groups
319 - * @param array $personProperties
320 - * @param array $groupProperties
321 - * @return mixed
322 - */
323 - public function getFeatureFlagPayload(
324 - string $key,
325 - string $distinctId,
326 - array $groups = array(),
327 - array $personProperties = array(),
328 - array $groupProperties = array(),
329 - ): mixed {
330 - $results = json_decode(
331 - $this->flags($distinctId, $groups, $personProperties, $groupProperties),
332 - true
333 - );
334 135
335 - if (isset($results['featureFlags'][$key]) === false || $results['featureFlags'][$key] !== true) {
336 - return null;
337 - }
338 -
339 - $payload = $results['featureFlagPayloads'][$key] ?? null;
340 -
341 - if ($payload === null) {
342 - return null;
343 - }
344 -
345 - # feature flag payloads are always JSON encoded strings.
346 - return json_decode($payload, true);
347 - }
348 -
349 136 /**
350 - * get the feature flag value for this distinct id.
351 - *
352 137 * @param string $distinctId
353 138 * @param array $groups
354 - * @param array $personProperties
355 - * @param array $groupProperties
356 - * @return array
139 + * @return array of enabled feature flags
357 140 * @throws Exception
358 141 */
359 - public function getAllFlags(
360 - string $distinctId,
361 - array $groups = array(),
362 - array $personProperties = array(),
363 - array $groupProperties = array(),
364 - bool $onlyEvaluateLocally = false
365 - ): array {
366 - [$personProperties, $groupProperties] = $this->addLocalPersonAndGroupProperties(
367 - $distinctId,
368 - $groups,
369 - $personProperties,
370 - $groupProperties
371 - );
372 - $response = [];
373 - $fallbackToFlags = false;
374 -
375 - if (count($this->featureFlags) > 0) {
376 - foreach ($this->featureFlags as $flag) {
377 - try {
378 - $response[$flag['key']] = $this->computeFlagLocally(
379 - $flag,
380 - $distinctId,
381 - $groups,
382 - $personProperties,
383 - $groupProperties
384 - );
385 - } catch (InconclusiveMatchException $e) {
386 - $fallbackToFlags = true;
387 - } catch (Exception $e) {
388 - $fallbackToFlags = true;
389 - error_log("[PostHog][Client] Error while computing variant:" . $e->getMessage());
390 - }
391 - }
392 - } else {
393 - $fallbackToFlags = true;
394 - }
395 -
396 - if ($fallbackToFlags && !$onlyEvaluateLocally) {
397 - try {
398 - $featureFlags = $this->fetchFeatureVariants($distinctId, $groups, $personProperties, $groupProperties);
399 - $response = array_merge($response, $featureFlags);
400 - } catch (Exception $e) {
401 - error_log("[PostHog][Client] Unable to get feature variants:" . $e->getMessage());
402 - }
403 - }
404 -
405 - return $response;
406 - }
407 -
408 - private function computeFlagLocally(
409 - array $featureFlag,
410 - string $distinctId,
411 - array $groups = array(),
412 - array $personProperties = array(),
413 - array $groupProperties = array()
414 - ): bool | string {
415 - if ($featureFlag["ensure_experience_continuity"] ?? false) {
416 - throw new InconclusiveMatchException("Flag has experience continuity enabled");
417 - }
418 -
419 - if (!$featureFlag["active"]) {
420 - return false;
421 - }
422 -
423 - $flagFilters = $featureFlag["filters"] ?? [];
424 - $aggregationGroupTypeIndex = $flagFilters["aggregation_group_type_index"] ?? null;
425 -
426 - if (!is_null($aggregationGroupTypeIndex)) {
427 - $groupName = $this->groupTypeMapping[strval($aggregationGroupTypeIndex)] ?? null;
428 -
429 - if (is_null($groupName)) {
430 - throw new InconclusiveMatchException("Flag has unknown group type index");
431 - }
432 -
433 - if (!array_key_exists($groupName, $groups)) {
434 - return false;
435 - }
436 -
437 - $focusedGroupProperties = $groupProperties[$groupName];
438 - return FeatureFlag::matchFeatureFlagProperties($featureFlag, $groups[$groupName], $focusedGroupProperties);
439 - } else {
440 - return FeatureFlag::matchFeatureFlagProperties($featureFlag, $distinctId, $personProperties, $this->cohorts);
441 - }
442 - }
443 -
444 -
445 - /**
446 - * @param string $distinctId
447 - * @param array $groups
448 - * @return array of feature flags
449 - * @throws Exception
450 - */
451 - public function fetchFeatureVariants(
452 - string $distinctId,
453 - array $groups = [],
454 - array $personProperties = [],
455 - array $groupProperties = []
456 - ): array {
457 - $response = $this->fetchFlagsResponse($distinctId, $groups, $personProperties, $groupProperties);
458 - return $response['featureFlags'] ?? [];
459 - }
460 -
461 - /**
462 - * @param string $distinctId
463 - * @param array $groups
464 - * @return array of feature flags
465 - * @throws Exception
466 - */
467 - private function fetchFlagsResponse(
468 - string $distinctId,
469 - array $groups = [],
470 - array $personProperties = [],
471 - array $groupProperties = []
472 - ): ?array {
473 - return json_decode(
474 - $this->flags($distinctId, $groups, $personProperties, $groupProperties),
475 - true
476 - );
477 - }
478 -
479 - /**
480 - * @throws Exception
481 - */
482 -
483 - public function loadFlags()
142 + public function fetchEnabledFeatureFlags(string $distinctId, array $groups = array()): array
484 143 {
485 - $payload = json_decode($this->localFlags(), true);
486 -
487 - if ($payload && array_key_exists("detail", $payload)) {
488 - throw new Exception($payload["detail"]);
489 - }
490 -
491 - $this->featureFlags = $payload['flags'] ?? [];
492 - $this->groupTypeMapping = $payload['group_type_mapping'] ?? [];
493 - $this->cohorts = $payload['cohorts'] ?? [];
144 + return json_decode($this->decide($distinctId, $groups), true)['featureFlags'] ?? [];
494 145 }
495 146
496 -
497 - public function localFlags()
147 + public function decide(string $distinctId, array $groups = array())
498 148 {
499 - return $this->httpClient->sendRequest(
500 - '/api/feature_flag/local_evaluation?send_cohorts&token=' . $this->apiKey,
501 - null,
502 - [
503 - // Send user agent in the form of {library_name}/{library_version} as per RFC 7231.
504 - "User-Agent: posthog-php/" . PostHog::VERSION,
505 - "Authorization: Bearer " . $this->personalAPIKey
506 - ]
507 - )->getResponse();
508 - }
509 -
510 - private function normalizeFeatureFlags(string $response): string
511 - {
512 - $decoded = json_decode($response, true);
513 - if (isset($decoded['flags']) && !empty($decoded['flags'])) {
514 - // This is a v4 response, we need to transform it to a v3 response for backwards compatibility
515 - $transformedFlags = [];
516 - $transformedPayloads = [];
517 - foreach ($decoded['flags'] as $key => $flag) {
518 - if ($flag['variant'] !== null) {
519 - $transformedFlags[$key] = $flag['variant'];
520 - } else {
521 - $transformedFlags[$key] = $flag['enabled'] ?? false;
522 - }
523 - if (isset($flag['metadata']['payload'])) {
524 - $transformedPayloads[$key] = $flag['metadata']['payload'];
525 - }
526 - }
527 - $decoded['featureFlags'] = $transformedFlags;
528 - $decoded['featureFlagPayloads'] = $transformedPayloads;
529 - return json_encode($decoded);
530 - }
531 -
532 - return $response;
533 - }
534 -
535 - public function flags(
536 - string $distinctId,
537 - array $groups = array(),
538 - array $personProperties = [],
539 - array $groupProperties = []
540 - ) {
541 149 $payload = array(
542 150 'api_key' => $this->apiKey,
543 151 'distinct_id' => $distinctId,
544 152 );
@@ -546,30 +154,16 @@
546 154 if (!empty($groups)) {
547 155 $payload["groups"] = $groups;
548 156 }
549 157
550 - if (!empty($personProperties)) {
551 - $payload["person_properties"] = $personProperties;
552 - }
553 -
554 - if (!empty($groupProperties)) {
555 - $payload["group_properties"] = $groupProperties;
556 - }
557 -
558 - $response = $this->httpClient->sendRequest(
559 - '/flags/?v=2',
158 + return $this->httpClient->sendRequest(
159 + '/decide/',
560 160 json_encode($payload),
561 161 [
562 162 // Send user agent in the form of {library_name}/{library_version} as per RFC 7231.
563 163 "User-Agent: posthog-php/" . PostHog::VERSION,
564 - ],
565 - [
566 - "shouldRetry" => false,
567 - "timeout" => $this->featureFlagsRequestTimeout
568 164 ]
569 165 )->getResponse();
570 -
571 - return $this->normalizeFeatureFlags($response);
572 166 }
573 167
574 168 /**
575 169 * Aliases from one user id to another
@@ -687,17 +281,8 @@
687 281 $msg["distinct_id"] = $msg["distinctId"];
688 282 unset($msg["distinctId"]);
689 283 }
690 284
691 - if (isset($msg["sendFeatureFlags"])) {
692 - $msg["send_feature_flags"] = $msg["sendFeatureFlags"];
693 - unset($msg["sendFeatureFlags"]);
694 - }
695 -
696 - if (!isset($msg["groups"])) {
697 - $msg["groups"] = [];
698 - }
699 -
700 285 if (!isset($msg["timestamp"])) {
701 286 $msg["timestamp"] = null;
702 287 }
703 288 $msg["timestamp"] = $this->formatTime($msg["timestamp"]);
@@ -702,30 +287,6 @@
702 287 }
703 288 $msg["timestamp"] = $this->formatTime($msg["timestamp"]);
704 289
705 290 return $msg;
706 - }
707 -
708 - private function addLocalPersonAndGroupProperties(
709 - string $distinctId,
710 - array $groups,
711 - array $personProperties,
712 - array $groupProperties
713 - ): array {
714 - $allPersonProperties = array_merge(
715 - ["distinct_id" => $distinctId],
716 - $personProperties
717 - );
718 -
719 - $allGroupProperties = [];
720 - if (count($groups) > 0) {
721 - foreach ($groups as $groupName => $groupValue) {
722 - $allGroupProperties[$groupName] = array_merge(
723 - ["\$group_key" => $groupValue],
724 - $groupProperties[$groupName] ?? []
725 - );
726 - }
727 - }
728 -
729 - return [$allPersonProperties, $allGroupProperties];
730 291 }
731 292 }