Skip to content

Commit 51861ab

Browse files
sakshamg1304rohitesh-wingify
authored andcommitted
feat: proxy URL
1 parent 54fd505 commit 51861ab

File tree

19 files changed

+167
-97
lines changed

19 files changed

+167
-97
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.19.0] - 2026-02-11
9+
10+
### Added
11+
12+
- Added support for redirecting all network calls through a custom proxy URL. This feature allows users to route all SDK network requests (settings, tracking, etc.) through their own proxy server.
13+
14+
```php
15+
$vwoClient = VWO::init([
16+
'sdkKey' => '32-alpha-numeric-sdk-key',
17+
'accountId' => 123456,
18+
'proxy' => [
19+
'url' => 'http://custom.proxy.com',
20+
'isUrlNotSecure' => true
21+
],
22+
]);
23+
```
24+
825
## [1.18.0] - 2026-02-05
926

1027
### Added

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ To customize the SDK further, additional parameters can be passed to the `init()
6464
| `accountId` | VWO Account ID for authentication. | Yes | string | `'123456'` |
6565
| `pollInterval` | Time interval for fetching updates from VWO servers (in milliseconds). | No | integer | `60000` |
6666
| `gatewayService` | An object representing configuration for integrating VWO Gateway Service. | No | array | see [Gateway](#gateway) section |
67+
| `proxy` | An object representing configuration for routing all SDK network requests through a custom proxy server. | No | array | See [Proxy](#proxy) section |
6768
| `storage` | Custom storage connector for persisting user decisions and campaign data. | No | array | See [Storage](#storage) section |
6869
| `logger` | Toggle log levels for more insights or for debugging purposes. You can also customize your own transport in order to have better control over log messages. | No | array | See [Logger](#logger) section |
6970
| `Integrations` | Callback function for integrating with third-party analytics services. | No | object | See [Integrations](#integrations) section |
@@ -236,6 +237,28 @@ $vwoClient = VWO::init([
236237

237238
Refer to the [Gateway Documentation](https://developers.vwo.com/v2/docs/gateway-service) for further details.
238239

240+
### Proxy
241+
242+
The `proxy` parameter allows you to redirect all SDK network calls through a custom proxy URL. This feature enables you to route all SDK network requests (settings, tracking, etc.) through your own proxy server, providing better control over network traffic and security.
243+
244+
```php
245+
$vwoClient = VWO::init([
246+
'sdkKey' => '32-alpha-numeric-sdk-key',
247+
'accountId' => 123456,
248+
'proxy' => [
249+
'url' => 'http://custom.proxy.com',
250+
'isUrlNotSecure' => false // be default, it should be true
251+
],
252+
]);
253+
```
254+
255+
The `proxy` object accepts the following parameters:
256+
257+
| **Parameter** | **Description** | **Required** | **Type** | **Example** |
258+
| --------------------- | ------------------------------------------------------------------------------- | ------------ | -------- | ------------------------------- |
259+
| `url` | The proxy server URL to route all SDK network requests through | Yes | string | `'http://localhost:8000'` |
260+
| `isUrlNotSecure` | Set to `true` if the proxy URL uses HTTP (not HTTPS). Defaults to `false` (HTTPS) | No | boolean | `true` |
261+
239262
### Synchronous network calls
240263

241264
Synchronous network calls differ from the default (asynchronous or fire-and-forget) tracking behavior by waiting for the tracking request to return a response from the VWO server before proceeding with the rest of your application code. By default, the SDK sends tracking network calls in a way that does not block your application, providing maximum throughput and lowest latency for user actions.

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vwo/vwo-fme-php-sdk",
33

4-
"version": "1.18.0",
4+
"version": "1.19.0",
55
"keywords": ["vwo", "fme", "sdk"],
66
"license": "Apache-2.0",
77
"authors": [{

src/Api/GetFlag.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ public function get(
171171
$payload = $evaluateRuleResult['payload'];
172172

173173
if(!$isDebuggerUsed) {
174-
if($serviceContainer->getSettingsService()->isGatewayServiceProvided && $payload !== null) {
175-
ImpressionUtil::SendImpressionForVariationShown($serviceContainer->getSettings(), $payload, $context);
174+
if(($serviceContainer->getSettingsService()->isGatewayServiceProvided || $serviceContainer->getSettingsService()->isProxyUrlProvided) && $payload !== null) {
175+
ImpressionUtil::SendImpressionForVariationShown($serviceContainer, $payload, $context);
176176
} else {
177177
if($payload !== null) {
178178
$batchPayload[] = $payload;
@@ -215,8 +215,8 @@ public function get(
215215
$context
216216
);
217217

218-
if($serviceContainer->getSettingsService()->isGatewayServiceProvided && $payload !== null) {
219-
ImpressionUtil::SendImpressionForVariationShown($serviceContainer->getSettings(), $payload, $context);
218+
if(($serviceContainer->getSettingsService()->isGatewayServiceProvided || $serviceContainer->getSettingsService()->isProxyUrlProvided) && $payload !== null) {
219+
ImpressionUtil::SendImpressionForVariationShown($serviceContainer, $payload, $context);
220220
} else {
221221
//push this payload to the batch payload
222222
if($payload !== null) {
@@ -256,8 +256,8 @@ public function get(
256256
} else {
257257
$isEnabled = true;
258258
$payload = $evaluateRuleResult['payload'];
259-
if($serviceContainer->getSettingsService()->isGatewayServiceProvided && $payload !== null) {
260-
ImpressionUtil::SendImpressionForVariationShown($serviceContainer->getSettings(), $payload, $context);
259+
if(($serviceContainer->getSettingsService()->isGatewayServiceProvided || $serviceContainer->getSettingsService()->isProxyUrlProvided) && $payload !== null) {
260+
ImpressionUtil::SendImpressionForVariationShown($serviceContainer, $payload, $context);
261261
} else {
262262
if($payload !== null) {
263263
$batchPayload[] = $payload;
@@ -300,8 +300,8 @@ public function get(
300300
$context
301301
);
302302

303-
if($serviceContainer->getSettingsService()->isGatewayServiceProvided && $payload !== null) {
304-
ImpressionUtil::SendImpressionForVariationShown($serviceContainer->getSettings(), $payload, $context);
303+
if(($serviceContainer->getSettingsService()->isGatewayServiceProvided || $serviceContainer->getSettingsService()->isProxyUrlProvided) && $payload !== null) {
304+
ImpressionUtil::SendImpressionForVariationShown($serviceContainer, $payload, $context);
305305
} else {
306306
//push this payload to the batch payload
307307
if($payload !== null) {
@@ -351,8 +351,8 @@ public function get(
351351
$context
352352
);
353353

354-
if($serviceContainer->getSettingsService()->isGatewayServiceProvided && $payload !== null) {
355-
ImpressionUtil::SendImpressionForVariationShown($serviceContainer->getSettings(), $payload, $context);
354+
if(($serviceContainer->getSettingsService()->isGatewayServiceProvided || $serviceContainer->getSettingsService()->isProxyUrlProvided) && $payload !== null) {
355+
ImpressionUtil::SendImpressionForVariationShown($serviceContainer, $payload, $context);
356356
} else {
357357
//push this payload to the batch payload
358358
if($payload !== null) {
@@ -370,7 +370,7 @@ public function get(
370370
$variablesForEvaluatedFlag = $rolloutVariationToReturn->getVariables();
371371
}
372372

373-
if(!$serviceContainer->getSettingsService()->isGatewayServiceProvided) {
373+
if(!$serviceContainer->getSettingsService()->isGatewayServiceProvided && !$serviceContainer->getSettingsService()->isProxyUrlProvided) {
374374
ImpressionUtil::SendImpressionForVariationShownInBatch($batchPayload, $serviceContainer);
375375
}
376376

src/Constants/Constants.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class Constants {
4040
const DEFAULT_EVENTS_PER_REQUEST = 100;
4141
const SDK_NAME = 'vwo-fme-php-sdk';
4242

43-
const SDK_VERSION = '1.18.0';
43+
const SDK_VERSION = '1.19.0';
4444
const AP = 'server';
4545

4646
const SETTINGS = 'settings';

src/Packages/NetworkLayer/Client/NetworkClient.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class NetworkClient implements NetworkClientInterface
3131
const HTTPS = 'HTTPS';
3232
const DEFAULT_TIMEOUT = 5; // seconds
3333
private $isGatewayUrlNotSecure = false; // Flag to store the value
34+
private $isProxyUrlNotSecure = false; // Flag to store the value
3435
private $shouldWaitForTrackingCalls = false;
3536
private $retryConfig = Constants::DEFAULT_RETRY_CONFIG;
3637
private $logManager;
@@ -40,6 +41,9 @@ public function __construct($options = []) {
4041
if (isset($options['isGatewayUrlNotSecure'])) {
4142
$this->isGatewayUrlNotSecure = $options['isGatewayUrlNotSecure'];
4243
}
44+
if (isset($options['isProxyUrlNotSecure'])) {
45+
$this->isProxyUrlNotSecure = $options['isProxyUrlNotSecure'];
46+
}
4347
if (isset($options['shouldWaitForTrackingCalls'])) {
4448
$this->shouldWaitForTrackingCalls = $options['shouldWaitForTrackingCalls'];
4549
}
@@ -53,7 +57,7 @@ public function __construct($options = []) {
5357

5458
private function shouldUseCurl($networkOptions)
5559
{
56-
if ($this->isGatewayUrlNotSecure || $this->shouldWaitForTrackingCalls) {
60+
if ($this->isGatewayUrlNotSecure || $this->shouldWaitForTrackingCalls || $this->isProxyUrlNotSecure) {
5761
return true;
5862
}
5963
return false;
@@ -109,11 +113,9 @@ private function makeCurlRequest($url, $method, $headers, $body = null, $timeout
109113
curl_setopt($ch, CURLOPT_POSTREDIR, 3); // keep POST on 301/302 redirects
110114
}
111115
}
112-
113116
$response = curl_exec($ch);
114117
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
115118
$error = curl_error($ch);
116-
117119
curl_close($ch);
118120

119121
// Check if request was successful
@@ -126,11 +128,11 @@ private function makeCurlRequest($url, $method, $headers, $body = null, $timeout
126128

127129
// Store the error for potential re-throwing
128130
$lastError = $error ? "cURL error: $error" : "HTTP error: $httpCode";
129-
131+
130132
// If this is not the last attempt, wait before retrying
131133
if ($attempt < $maxRetries ) {
132134
$delay = $retryDelays[$attempt] ?? $baseDelay;
133-
135+
134136
LoggerService::error('NETWORK_CALL_RETRY_ATTEMPT', [
135137
'endPoint' => $url,
136138
'err' => $lastError,
@@ -279,7 +281,6 @@ public function GET($request)
279281
);
280282
$rawResponse = $curlResponse['body'];
281283
$responseModel->setStatusCode($curlResponse['status_code']);
282-
283284

284285
$parsedData = json_decode($rawResponse, false);
285286
if ($parsedData === null && json_last_error() !== JSON_ERROR_NONE) {

src/Packages/NetworkLayer/Manager/NetworkManager.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class NetworkManager {
3131
private $client;
3232
private static $instance;
3333
private $isGatewayUrlNotSecure = false; // Store the flag here
34+
private $isProxyUrlNotSecure = false; // Store the flag here
3435
private $shouldWaitForTrackingCalls = false;
3536
private $retryConfig = Constants::DEFAULT_RETRY_CONFIG;
3637
private $logManager;
@@ -44,6 +45,9 @@ public function attachClient($client = null, $options = []) {
4445
if(isset($options['isGatewayUrlNotSecure'])) {
4546
$this->isGatewayUrlNotSecure = $options['isGatewayUrlNotSecure'];
4647
}
48+
if(isset($options['isProxyUrlNotSecure'])) {
49+
$this->isProxyUrlNotSecure = $options['isProxyUrlNotSecure'];
50+
}
4751
if(isset($options['shouldWaitForTrackingCalls'])) {
4852
$this->shouldWaitForTrackingCalls = $options['shouldWaitForTrackingCalls'];
4953
}
@@ -63,6 +67,7 @@ public function attachClient($client = null, $options = []) {
6367
'shouldWaitForTrackingCalls' => $this->shouldWaitForTrackingCalls,
6468
'retryConfig' => $this->retryConfig,
6569
'logManager' => $this->logManager,
70+
'isProxyUrlNotSecure' => $this->isProxyUrlNotSecure,
6671
];
6772
$this->client = $client ?: new NetworkClient($clientOptions);
6873
}

src/Packages/SegmentationEvaluator/Core/SegmentationManager.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,15 @@ public function setContextualData(ServiceContainer $serviceContainer, $feature,
6161
return;
6262
}
6363

64-
$baseUrl = UrlService::getBaseUrl();
64+
$baseUrl = $serviceContainer->getSettingsService()->hostname;
6565
$isDefaultHost = strpos($baseUrl, Constants::HOST_NAME) !== false;
6666

67-
// Call gateway service if required for segmentation OR if gateway service is provided and user agent/IP is available
68-
$shouldCallGatewayService = (
69-
($feature->getIsGatewayServiceRequired() === true && !$isDefaultHost) ||
70-
(!$isDefaultHost && ($context->getUserAgent() !== null || $context->getIpAddress() !== null))
71-
);
72-
73-
if ($shouldCallGatewayService && $context->getVwo() === null) {
67+
68+
if (
69+
$feature->getIsGatewayServiceRequired() &&
70+
$serviceContainer->getSettingsService()->isGatewayServiceProvided &&
71+
$context->getVwo() === null
72+
) {
7473
// if both user agent and ip address are not available, return
7574
if ($context->getUserAgent() === null && $context->getIpAddress() === null) {
7675
return;

src/Packages/SegmentationEvaluator/Evaluators/SegmentOperandEvaluator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ private function logMissingContextError($operandType) {
367367
$this->serviceContainer->getLogManager()->info('To evaluate browser version segmentation, please provide userAgent in context');
368368
break;
369369
default:
370-
$this->serviceContainer->getLogManager()->info('To evaluate OS version segmentation, please provide userAgent in context');
370+
$this->serviceContainer->getLogManager()->info('To evaluate OS version segmentation, please provide userAgent in context');
371371
break;
372372
}
373373
}

src/Services/ServiceContainer.php

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -144,24 +144,8 @@ public function updateSettings(SettingsModel $settingsModel)
144144
$this->settingsModel = $settingsModel;
145145
}
146146

147-
/**
148-
* Gets the base URL for API calls
149-
* @return string
150-
*/
151-
public function getBaseUrl(): string
152-
{
153-
$baseUrl = $this->settingsService->hostname;
154-
155-
// If collection prefix is set, return the base url with the collection prefix
156-
if (
157-
$baseUrl == Constants::HOST_NAME &&
158-
$this->settingsModel->getCollectionPrefix() &&
159-
DataTypeUtil::isString($this->settingsModel->getCollectionPrefix())
160-
) {
161-
return $baseUrl . '/' . $this->settingsModel->getCollectionPrefix();
162-
}
163-
164-
return $baseUrl;
147+
public function getBaseUrl(): string {
148+
return $this->settingsService->getBaseUrl();
165149
}
166150

167151
/**

0 commit comments

Comments
 (0)