# PHP SDK

Official PHP SDK for KeyEnv.

Source: https://keyenv.dev/docs/sdks/php/

Official PHP SDK for KeyEnv with PHP 8.0+ support.

> **Warning**
>
>   **Beta Release**: This SDK is currently in development. APIs may change before the stable 1.0 release.

## Installation

Install via Composer:

```bash
composer require keyenv/keyenv
```

## Quick Start

```php
<?php

use KeyEnv\KeyEnv;

$client = KeyEnv::create($_ENV['KEYENV_TOKEN']);

// Load secrets into $_ENV and putenv()
$count = $client->loadEnv('your-project-id', 'production');
echo "Loaded {$count} secrets\n";

// Access secrets
echo $_ENV['DATABASE_URL'];
echo getenv('DATABASE_URL');
```

## Initialize the Client

### Simple Initialization

```php
<?php

use KeyEnv\KeyEnv;

$client = KeyEnv::create($_ENV['KEYENV_TOKEN']);
```

### With Options

```php
<?php

use KeyEnv\KeyEnv;

$client = new KeyEnv(
    token: $_ENV['KEYENV_TOKEN'],
    timeout: 60  // Request timeout in seconds
);
```

## Loading Secrets

### Load into Environment

The simplest way to use secrets in your application:

```php
<?php

$count = $client->loadEnv('project-id', 'production');
echo "Loaded {$count} secrets\n";

// Access via $_ENV
echo $_ENV['DATABASE_URL'];
echo $_ENV['API_KEY'];

// Or via getenv()
echo getenv('DATABASE_URL');
echo getenv('API_KEY');
```

### Get Secrets as Array

Get secrets as a key-value associative array:

```php
<?php

$secrets = $client->exportSecretsAsArray('project-id', 'production');
echo $secrets['DATABASE_URL'];
echo $secrets['API_KEY'];
```

### Export as List

Get secrets with metadata:

```php
<?php

$secrets = $client->exportSecrets('project-id', 'production');
foreach ($secrets as $secret) {
    echo "{$secret->key}={$secret->value}\n";
}
```

## Managing Secrets

### Get a Single Secret

```php
<?php

$secret = $client->getSecret('project-id', 'production', 'DATABASE_URL');
echo $secret->value;
echo $secret->description;
```

### Set a Secret

Creates or updates a secret:

```php
<?php

$client->setSecret('project-id', 'production', 'API_KEY', 'sk_live_...');

// With description
$client->setSecret(
    'project-id',
    'production',
    'API_KEY',
    'sk_live_...',
    description: 'Production API key'
);
```

### Create a Secret

Explicitly create a new secret (fails if exists):

```php
<?php

$secret = $client->createSecret(
    'project-id',
    'production',
    'NEW_KEY',
    'new_value',
    description: 'New secret'
);
```

### Update a Secret

Explicitly update an existing secret (fails if not exists):

```php
<?php

$secret = $client->updateSecret(
    'project-id',
    'production',
    'EXISTING_KEY',
    'updated_value'
);
```

### Delete a Secret

```php
<?php

$client->deleteSecret('project-id', 'production', 'OLD_KEY');
```

## Environments

### List Environments

```php
<?php

$environments = $client->listEnvironments('project-id');
foreach ($environments as $env) {
    echo $env->name . "\n";
}
```

## Generate .env File

```php
<?php

$envContent = $client->generateEnvFile('project-id', 'production');
file_put_contents('.env', $envContent);
```

## Error Handling

```php
<?php

use KeyEnv\KeyEnv;
use KeyEnv\KeyEnvException;

try {
    $secret = $client->getSecret('project-id', 'production', 'MISSING_KEY');
} catch (KeyEnvException $e) {
    echo "Error {$e->getCode()}: {$e->getMessage()}\n";

    if ($e->isNotFound()) {
        echo "Secret not found\n";
    } elseif ($e->isUnauthorized()) {
        echo "Invalid or expired token\n";
    } elseif ($e->isForbidden()) {
        echo "Access denied\n";
    }

    // Access error details
    if ($e->getDetails()) {
        print_r($e->getDetails());
    }
}
```

## API Reference

### Constructor Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `token` | `string` | Yes | - | Service token |
| `timeout` | `int` | No | `30` | Request timeout (seconds) |

### Methods

| Method | Description |
|--------|-------------|
| `validateToken()` | Validate token and get user info |
| `listEnvironments(projectId)` | List environments in a project |
| `listSecrets(projectId, env)` | List secret keys (no values) |
| `exportSecrets(projectId, env)` | Export secrets with values |
| `exportSecretsAsArray(projectId, env)` | Export as associative array |
| `getSecret(projectId, env, key)` | Get single secret |
| `createSecret(projectId, env, key, value)` | Create new secret |
| `updateSecret(projectId, env, key, value)` | Update existing secret |
| `setSecret(projectId, env, key, value)` | Create or update secret |
| `deleteSecret(projectId, env, key)` | Delete secret |
| `loadEnv(projectId, env)` | Load secrets into $_ENV |
| `generateEnvFile(projectId, env)` | Generate .env file content |

## Examples

### Laravel Application

```php
<?php
// bootstrap/app.php or AppServiceProvider

use KeyEnv\KeyEnv;

if ($token = env('KEYENV_TOKEN')) {
    $client = KeyEnv::create($token);
    $client->loadEnv(env('KEYENV_PROJECT'), env('APP_ENV', 'production'));
}
```

### Laravel Service Provider

```php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use KeyEnv\KeyEnv;

class KeyEnvServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(KeyEnv::class, function () {
            return KeyEnv::create(config('services.keyenv.token'));
        });
    }

    public function boot(): void
    {
        if ($token = config('services.keyenv.token')) {
            $client = app(KeyEnv::class);
            $client->loadEnv(
                config('services.keyenv.project'),
                app()->environment()
            );
        }
    }
}
```

### Symfony Application

```php
<?php
// src/EventSubscriber/SecretsSubscriber.php

namespace App\EventSubscriber;

use KeyEnv\KeyEnv;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;

class SecretsSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => ['loadSecrets', 255],
        ];
    }

    public function loadSecrets(): void
    {
        static $loaded = false;

        if ($loaded) {
            return;
        }

        if ($token = $_ENV['KEYENV_TOKEN'] ?? null) {
            $client = KeyEnv::create($token);
            $client->loadEnv($_ENV['KEYENV_PROJECT'], $_ENV['APP_ENV'] ?? 'prod');
            $loaded = true;
        }
    }
}
```

### WordPress Plugin

```php
<?php
// In your plugin or theme's functions.php

use KeyEnv\KeyEnv;

add_action('init', function () {
    if (!defined('KEYENV_TOKEN')) {
        return;
    }

    $client = KeyEnv::create(KEYENV_TOKEN);
    $secrets = $client->exportSecretsAsArray(KEYENV_PROJECT, KEYENV_ENV ?? 'production');

    foreach ($secrets as $key => $value) {
        if (!defined($key)) {
            define($key, $value);
        }
    }
}, 1);
```

### CLI Script

```php
#!/usr/bin/env php
<?php

require_once __DIR__ . '/vendor/autoload.php';

use KeyEnv\KeyEnv;
use KeyEnv\KeyEnvException;

$token = getenv('KEYENV_TOKEN');
if (!$token) {
    fwrite(STDERR, "Error: KEYENV_TOKEN environment variable not set\n");
    exit(1);
}

try {
    $client = KeyEnv::create($token);
    $secrets = $client->exportSecrets('my-project', 'production');

    foreach ($secrets as $secret) {
        echo "{$secret->key}={$secret->value}\n";
    }
} catch (KeyEnvException $e) {
    fwrite(STDERR, "KeyEnv Error: {$e->getMessage()}\n");
    exit(1);
}
```

### PHPUnit Test Setup

```php
<?php

namespace Tests;

use KeyEnv\KeyEnv;
use PHPUnit\Framework\TestCase;

abstract class TestCaseWithSecrets extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        if ($token = getenv('KEYENV_TOKEN')) {
            $client = KeyEnv::create($token);
            $client->loadEnv(getenv('KEYENV_PROJECT'), 'test');
        }
    }
}
```
