contenzi/sdk-php

Contenzi SDK for PHP with OpenFeature

v0.1.0-beta 2025-02-20 14:17 UTC

This package is not auto-updated.

Last update: 2025-05-30 14:03:26 UTC


README

Installation

To use the Contenzi PHP SDK, install it using Composer:

composer require contenzi/sdk-php "v0.1.0-beta"

Setting Up the SDK

The SDK is based on OpenFeature and requires setting up a provider, evaluation context, and client. Follow these steps to configure it properly.

1. Generate a Targeting Key

Each user should have a unique targeting key stored in a cookie for consistent evaluations. If the cookie does not exist, generate a new targeting key and store it.

function generateTargetingKey() {
    return (string)rand(1, 10000); // Can also use a random UUID if preferred
}

// Check if the targeting key exists, otherwise generate and store it
$targetingKey = isset($_COOKIE['exp_seed']) ? $_COOKIE['exp_seed'] : generateTargetingKey();
setcookie('exp_seed', $targetingKey, time() + (86400 * 365), "/"); // Store for 1 year

2. Initialize the SDK

Create an instance of ContenziProvider, ensuring you pass both the App ID and the cache path as parameters. The App ID can be found in the SDK configuration screen of the Contenzi app. The cache path needs to be shared with the scheduled feature flag update job and must be writable by that job.

use Contenzi\Sdk\OpenFeature\ContenziProvider;
use OpenFeature\implementation\flags\EvaluationContext;
use OpenFeature\OpenFeatureAPI;

$api = OpenFeatureAPI::getInstance();
$api->setProvider(new ContenziProvider("35bc2c6d-036d-4142-807c-e8e281fdfc25", "/opt/contenzi/php-sdk/flags"));
$api->setEvaluationContext(new EvaluationContext($targetingKey));
$openFeatureClient = $api->getClient();

3. Retrieve Feature Flags

Retrieve the flag values using standard OpenFeature Evaluation API

// Retrieve feature flag values
$value = $openFeatureClient->getStringValue('example', "x");
echo "example flag: " . $value;

Setting Up the Settings Fetcher Cron Job

The SDK requires periodic flag updates via the SettingsFetcher.php script. This should be set up as a cron job running every minute.

Example Cron Job Setup

* * * * * /usr/local/bin/php /path/to/sdk/SettingsFetcher.php a12345.ctz-content.com 35bc2c6d-036d-4142-807c-e8e281fdfc25 /opt/contenzi/php-sdk/flags

Explanation of Parameters

  1. API endpoint, replace "a12345" with the correct account identifier
  2. 35bc2c6d-036d-4142-807c-e8e281fdfc25 → Application ID (retrieved from the user interface)
  3. /opt/contenzi/php-sdk/flags → Path to store the cached flags (ensure this path is writable)

Note: Ensure that the path to SettingsFetcher.php is correctly set based on your installation.

Important Considerations

  • Writable Cache Directory: The flag storage path (/opt/contenzi/php-sdk/flags) must be writable by the PHP process.
  • Persistent User Identification: Store the generated targetingKey in a cookie to maintain consistent evaluations across sessions.
  • Experiment seed cookie: Ensure this cookie has a uniform random distribution for your visitors.

Example Code

The following code combines all the steps listed above:

use Contenzi\Sdk\OpenFeature\ContenziProvider;
use OpenFeature\implementation\flags\EvaluationContext;
use OpenFeature\OpenFeatureAPI;

// Generate or retrieve a user-specific targeting key
function generateTargetingKey() {
    return (string)rand(1, 10000); // Can also use UUID if preferred
}

$targetingKey = isset($_COOKIE['exp_seed']) ? $_COOKIE['exp_seed'] : generateTargetingKey();
setcookie('exp_seed', $targetingKey, time() + (86400 * 365), "/"); // Store for 1 year

// Initialize the SDK
$api = OpenFeatureAPI::getInstance();
$api->setProvider(new ContenziProvider("35bc2c6d-036d-4142-807c-e8e281fdfc25", "/opt/contenzi/php-sdk/flags"));
$api->setEvaluationContext(new EvaluationContext($targetingKey));
$openFeatureClient = $api->getClient();

// Retrieve feature flag values
$value = $openFeatureClient->getStringValue('example', "x");
echo "example flag: " . $value;

Handling Caching

Ensure the experiment cookie is not cached

If full page caching is used it is important to ensure the cookie used to set the experiment seed is not cached since this would prevent the users from being randomly distributed among the test groups. To solve this, set the cookie at the edge.

Varnish example

import std;

sub vcl_deliver {
    if (!req.http.Cookie ~ "exp_seed") {
        set resp.http.Set-Cookie = "exp_seed=" + std.random(0, 10000) + "; Path=/; Max-Age=31536000";
    }
}

Nginx example

  set $new_exp_seed $request_id;
  if ($cookie_exp_seed) {
      set $new_exp_seed $cookie_exp_seed;
  }
  add_header Set-Cookie "exp_seed=$new_exp_seed; Path=/; Max-Age=31536000";

Note: This will generate a long random ID, alternatively generate a small random number between 1 and 10,000 using Nginx Lua support for better user privacy.

How to maximize caching with experiments

Pages with experiments or personalisation will have to vary per user, so full page caching can't be applied. To enhance performance of these pages, choose between the following methods:

1. Client-side experimentation

If client-side experimentation is possible, prefer this approach. Serve a generic page with full page caching, then use the Contenzi Javascript SDK to vary the page.

2. Edge-Side Includes (ESI)

Use Edge Side Includes (ESI) to isolate the part of the page that requires variations, while caching the rest of the page. Include a snippet with variation using <esi:include />, generate the snippet using the standard PHP method described above.

3. Disabling caching for a specific page

If client-side and ESI are not suitable for the page, add a cache-control header to disable caching of this specific page. Ensure the performance of the non-cached page is adequate for the expected traffic levels.