PHPackages                             plainsimple/cloudflare-sdk-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. plainsimple/cloudflare-sdk-php

ActiveLibrary

plainsimple/cloudflare-sdk-php
==============================

PHP SDK for working with Cloudflare API

0.1.0(today)00MITPHP &gt;=8.3

Since Jul 22Compare

[ Source](https://github.com/plainsimpledev/cloudflare-php-sdk)[ Packagist](https://packagist.org/packages/plainsimple/cloudflare-sdk-php)[ RSS](/packages/plainsimple-cloudflare-sdk-php/feed)WikiDiscussions Synced today

READMEChangelog (1)Dependencies (8)Versions (2)Used By (0)

Cloudflare PHP SDK
==================

[](#cloudflare-php-sdk)

[![CI](https://github.com/plainsimpledev/cloudflare-php-sdk/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/plainsimpledev/cloudflare-php-sdk/actions/workflows/ci.yml)[![PHP Version](https://camo.githubusercontent.com/ecbf012e3704aed80a710e072f8a2b65afb62dddc90cadf159926d8678d54888/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253345253344382e332d3737374242342e737667)](https://camo.githubusercontent.com/ecbf012e3704aed80a710e072f8a2b65afb62dddc90cadf159926d8678d54888/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d253345253344382e332d3737374242342e737667)[![License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)

PHP 8.3+ client for the [Cloudflare API v4](https://developers.cloudflare.com/api/).

Supported API
-------------

[](#supported-api)

- **Accounts:** `list`, `get`, `create`, `update`, `delete`.
- **Zones:** `list`, `get`, `create`, `update`, `delete`, `rerunActivationCheck`.
- **DNS Records:** `list`, `get`, `create`, `update` (PATCH), `overwrite` (PUT), `delete`, `export`, `import`, legacy `scan`, `triggerScan`, `listScanned`, `reviewScan`, `batch`.
- **Zone Settings:** `list`, `get`, `update`, `updateMany`.
- **Rulesets:** account and zone scopes; `list`, `get`, `create`, `replace`, `delete`; `getEntrypoint`, `replaceEntrypoint`; `listEntrypointVersions`, `getEntrypointVersion`; `listVersions`, `getVersion`, `getVersionByTag`, `deleteVersion`; `createRule`, `updateRule`, `deleteRule`.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.3
- `ext-json`
- Guzzle 7.15.1+

Installation
------------

[](#installation)

```
composer require plainsimple/cloudflare-sdk-php
```

Client
------

[](#client)

Use the token factory for the standard transport:

```
use PlainSimple\Cloudflare\Client;

$client = Client::withApiToken($_ENV['CLOUDFLARE_API_TOKEN']);
```

The factory also accepts a base URI and Guzzle client options:

```
$client = Client::withApiToken(
    $_ENV['CLOUDFLARE_API_TOKEN'],
    'https://api.cloudflare.com/client/v4',
    ['timeout' => 5.0],
);
```

Inject the bundled adapter, or any `AdapterInterface` implementation, when transport construction belongs to the application:

```
use PlainSimple\Cloudflare\Adapters\GuzzleAdapter;
use PlainSimple\Cloudflare\Auth\ApiToken;
use PlainSimple\Cloudflare\Client;

$adapter = new GuzzleAdapter(
    new ApiToken($_ENV['CLOUDFLARE_API_TOKEN']),
    'https://api.cloudflare.com/client/v4',
    ['timeout' => 5.0],
);
$client = new Client($adapter);
```

Responses And Entities
----------------------

[](#responses-and-entities)

Endpoints return response wrappers. Read one entity with `getEntity()`, lists with `getItems()`, action data with `getResult()`, and raw export text with `getBody()`. Wrappers are not iterable.

```
$account = $client->accounts()->get('account-id')->getEntity();

foreach ($client->accounts()->list()->getItems() as $listedAccount) {
    echo $listedAccount->getName() . PHP_EOL;
}
```

The SDK uses a Data Mapper design. Create-purpose entity factories set writable create fields. API responses hydrate new clean entities. Setters mark fields dirty; endpoints serialize each resource's patch or replacement contract.

```
use PlainSimple\Cloudflare\Entities\Account;
use PlainSimple\Cloudflare\Enums\AccountType;

$draft = Account::forCreate('Example Account', AccountType::Standard);
$account = $client->accounts()->create($draft)->getEntity();

$account->setName('Renamed Account');
$account = $client->accounts()->update($account)->getEntity();

$client->accounts()->delete($account);
```

Use `forCreate()` on `Account`, `Zone`, `DnsRecord`, and `Ruleset`. Zone settings provide `forUpdate()` and `forEnabledUpdate()`. Prefer returned entities after create/update calls: they contain server IDs and are clean for later mutation.

Accounts
--------

[](#accounts)

```
$accounts = $client->accounts()->list(
    name: 'Example Account',
    page: 1,
    perPage: 20,
)->getItems();

$account = $client->accounts()->get('account-id')->getEntity();
echo $account->getName();
```

`update()` performs a PUT from present replacement fields. `delete()` accepts an `Account` or account ID and returns an `ActionResponse`.

Zones
-----

[](#zones)

```
use PlainSimple\Cloudflare\Entities\Zone;
use PlainSimple\Cloudflare\Enums\ZoneStatus;
use PlainSimple\Cloudflare\Enums\ZoneType;
use PlainSimple\Cloudflare\ValueObjects\ZoneListQuery;

$zones = $client->zones()->list(new ZoneListQuery(
    accountId: 'account-id',
    status: ZoneStatus::Active,
    types: [ZoneType::Full],
))->getItems();

$zone = $client->zones()->create(
    Zone::forCreate('example.com', 'account-id', ZoneType::Full),
)->getEntity();

$zone->setPaused(true);
$zone = $client->zones()->update($zone)->getEntity();
$client->zones()->rerunActivationCheck($zone);
```

A zone update requires exactly one dirty writable field: `paused`, `type`, or `vanity_name_servers`.

DNS Records
-----------

[](#dns-records)

```
use PlainSimple\Cloudflare\Entities\DnsRecord;
use PlainSimple\Cloudflare\Enums\DnsRecordType;
use PlainSimple\Cloudflare\ValueObjects\DnsRecordListQuery;

$records = $client->dnsRecords()->list('zone-id', new DnsRecordListQuery(
    name: ['exact' => 'www.example.com'],
    type: DnsRecordType::A,
))->getItems();

$draft = DnsRecord::forCreate(
    DnsRecordType::A,
    'www.example.com',
    '192.0.2.1',
    300,
);
$draft->setProxied(true);
$record = $client->dnsRecords()->create('zone-id', $draft)->getEntity();

$record->setContent('192.0.2.2');
$record = $client->dnsRecords()->update('zone-id', $record)->getEntity();
$client->dnsRecords()->delete('zone-id', $record);
```

`update()` sends dirty writable fields plus required `name`, `ttl`, and `type`. `overwrite()` sends all present writable fields. Simple record types use `content`; structured types use `data`.

Import, scan review, and batch operations use dedicated value objects. Export returns a raw response body:

```
use PlainSimple\Cloudflare\ValueObjects\DnsBatch;
use PlainSimple\Cloudflare\ValueObjects\DnsImport;
use PlainSimple\Cloudflare\ValueObjects\DnsScanReview;

$bindText = $client->dnsRecords()->export('zone-id')->getBody();
$importResult = $client->dnsRecords()->import(
    'zone-id',
    new DnsImport($bindText, 'example.com.bind', proxied: false),
)->getResult();

$client->dnsRecords()->triggerScan('zone-id');
$scanned = $client->dnsRecords()->listScanned('zone-id')->getItems();
$client->dnsRecords()->reviewScan('zone-id', new DnsScanReview(
    accepts: $scanned,
    rejects: ['rejected-record-id'],
));

$batchResult = $client->dnsRecords()->batch(
    'zone-id',
    new DnsBatch(
        deletes: ['old-record-id'],
        posts: [DnsRecord::forCreate('A', 'new.example.com', '192.0.2.10')],
    ),
)->getResult();
```

Zone Settings
-------------

[](#zone-settings)

```
use PlainSimple\Cloudflare\Entities\ZoneSetting;

$settings = $client->zoneSettings()->list('zone-id')->getItems();

$ssl = $client->zoneSettings()->get('zone-id', 'ssl')->getEntity();
$ssl->setValue('full');
$ssl = $client->zoneSettings()->update('zone-id', $ssl)->getEntity();

$client->zoneSettings()->updateMany('zone-id', [
    ZoneSetting::forUpdate('always_use_https', 'on'),
    ZoneSetting::forEnabledUpdate('ssl_recommender', true),
]);
```

Each update requires exactly one non-null dirty field. Use `enabled` only for `ssl_recommender`; all other settings use `value`.

Rulesets
--------

[](#rulesets)

Every operation takes an explicit account or zone `RulesetScope`:

```
use PlainSimple\Cloudflare\ValueObjects\RulesetListQuery;
use PlainSimple\Cloudflare\ValueObjects\RulesetScope;

$zoneScope = RulesetScope::zone('zone-id');
$accountScope = RulesetScope::account('account-id');

$zoneRulesets = $client->rulesets()->list($zoneScope)->getItems();
$accountRulesets = $client->rulesets()->list(
    $accountScope,
    new RulesetListQuery(perPage: 25),
)->getItems();
```

Create a zone custom WAF ruleset with an embedded rule:

```
use PlainSimple\Cloudflare\Entities\Rule;
use PlainSimple\Cloudflare\Entities\Ruleset;
use PlainSimple\Cloudflare\Enums\RuleAction;
use PlainSimple\Cloudflare\Enums\RulesetKind;
use PlainSimple\Cloudflare\Enums\RulesetPhase;

$wafRule = new Rule();
$wafRule->setRef('block-admin');
$wafRule->setDescription('Block the admin path');
$wafRule->setAction(RuleAction::Block);
$wafRule->setExpression('(http.request.uri.path eq "/admin")');
$wafRule->setEnabled(true);

$wafRuleset = Ruleset::forCreate(
    'Custom WAF',
    RulesetKind::Custom,
    RulesetPhase::HttpRequestFirewallCustom,
    'Application firewall rules',
    [$wafRule],
);
$wafRuleset = $client->rulesets()->create($zoneScope, $wafRuleset)->getEntity();
```

Add a cache rule to a zone cache entrypoint:

```
$cacheRule = new Rule();
$cacheRule->setRef('cache-static-assets');
$cacheRule->setDescription('Cache static assets for one day');
$cacheRule->setAction(RuleAction::SetCacheSettings);
$cacheRule->setExpression('(http.request.uri.path.extension in {"css" "js"})');
$cacheRule->setActionParameters([
    'cache' => true,
    'edge_ttl' => [
        'mode' => 'override_origin',
        'default' => 86400,
    ],
]);
$cacheRule->setEnabled(true);

$cacheEntrypoint = $client->rulesets()->getEntrypoint(
    $zoneScope,
    RulesetPhase::HttpRequestCacheSettings,
)->getEntity();
$cacheEntrypoint = $client->rulesets()->createRule(
    $zoneScope,
    $cacheEntrypoint->getId(),
    $cacheRule,
)->getEntity();
```

`replace()` and `replaceEntrypoint()` use PUT with explicitly present non-null `description` and `rules`. A rule definition PATCH serializes all present writable rule fields, not only dirty fields, and requires `action` plus `expression`. For position-only updates, pass an empty `Rule` with a `RulePosition`.

Development
-----------

[](#development)

Install exactly as CI:

```
composer install --prefer-dist --no-progress
```

Current Composer scripts:

```
composer lint          # php-cs-fixer fix --dry-run --diff
composer lint-fix      # php-cs-fixer fix
composer analyse       # phpstan analyse --memory-limit=512M
composer test          # phpunit --coverage-text
composer test-coverage # phpunit --coverage-html coverage
composer docs          # phpdoc
composer check         # lint, analyse, test
```

CI runs `composer validate --strict`, installation, `composer lint`, `composer analyse`, then `composer test` on PHP 8.3 and 8.4. Tests use mocked transports and require no network access.

The devcontainer defaults to `XDEBUG_MODE=debug`. Enable coverage for coverage-producing scripts:

```
XDEBUG_MODE=coverage composer test
docker compose -f .devcontainer/compose.yml run --rm -e XDEBUG_MODE=coverage app composer test
```

Contributing
------------

[](#contributing)

Read [CONTRIBUTING.md](CONTRIBUTING.md), then run `composer check` before opening a pull request. See [CHANGELOG.md](CHANGELOG.md) for release history and [AGENTS.md](AGENTS.md) for repository-specific implementation notes.

License
-------

[](#license)

Licensed under the [MIT License](LICENSE).

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2a1c3535ea2deb9dfb2d47ec477baec8700801cfa8afa0dbd58536bc2c4b5dca?d=identicon)[vzhabonos](/maintainers/vzhabonos)

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/plainsimple-cloudflare-sdk-php/health.svg)

```
[![Health](https://phpackages.com/badges/plainsimple-cloudflare-sdk-php/health.svg)](https://phpackages.com/packages/plainsimple-cloudflare-sdk-php)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.7k](/packages/aws-aws-sdk-php)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

293.1k](/packages/eslazarev-wildberries-sdk)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k46](/packages/neuron-core-neuron-ai)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M753](/packages/sylius-sylius)[oat-sa/tao-core

TAO core extension

66143.7k124](/packages/oat-sa-tao-core)[google/cloud

Google Cloud Client Library

1.2k16.7M57](/packages/google-cloud)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
