Rules
Usage
A ruleset is a list of rules, and each rule pairs an expression — which traffic it matches — with an action — what Cloudflare does about it. This package ships one class per action, so the action name is picked by the class you construct rather than by a string you have to remember.
use Cloudflare\Configurations\Ruleset;
use Cloudflare\Configurations\Rules\ManagedChallengeRule;
$rule = (new ManagedChallengeRule())
->enable()
->setDescription('Challenge logins from outside the office')
->setExpression('http.request.uri.path eq "/login" and ip.src ne 203.0.113.4');
$ruleset = (new Ruleset('Login protection'))
->zone()
->requestFirewallCustom()
->addRule($rule);
$response = $client->rulesets()->create(zoneId: 'zone_id', values: $ruleset);
addRule() takes a rule object. If you would rather hand-write the whole payload, skip these classes and pass a plain array to $client->rulesets()->create() instead — it accepts either.
Every rule shares these
| Method | Effect |
|---|---|
enable() / disable() | Whether Cloudflare runs the rule. Rules are disabled until you call enable(). |
setExpression($expression) | Which traffic matches. Takes a string, an Expression Builder, or a closure that receives one. Matches everything when unset. |
setDescription($description) | An informative description of the rule. |
setLogging($enabled) | Whether Cloudflare logs when the rule matches. |
setActionParameters($parameters) | Parameters for the rule's action, merged over whatever the class builds. Calling it twice merges rather than replaces. |
setId($id) / setRef($reference) | Identify an existing rule, for updates. |
Expressions read well as a closure:
use Cloudflare\Configurations\Rules\BlockRule;
$rule = (new BlockRule('{"error":"blocked"}'))
->enable()
->setExpression(fn ($builder) => $builder->field('ip.src')->eq('203.0.113.4'));
The rules
Cloudflare defines a different set of parameters for each action. Where it requires them, the class asks for them in its constructor; where they are optional, pass them with setActionParameters().
| Class | Cloudflare action | Parameters |
|---|---|---|
BlockRule | block | $content, $contentType, $statusCode |
ChallengeRule | challenge | none |
JSChallengeRule | js_challenge | none |
ManagedChallengeRule | managed_challenge | none |
LogRule | log | none |
DDoSDynamicRule | ddos_dynamic | none |
ForceConnectionCloseRule | force_connection_close | none |
ExecuteRule | execute | $rulesetId, plus optional overrides and matched_data |
ScoreRule | score | $increment |
ServeErrorRule | serve_error | $contentType, $content, $statusCode |
CompressionRule | compress_response | $algorithm |
ConfigRule | set_config | $settings |
SkipRule | skip | $skip |
RedirectRule | redirect | from_value or from_list |
RewriteRule | rewrite | uri, headers |
OriginRule | route | origin, host_header, sni |
CacheSettingsRule | set_cache_settings | cache, edge_ttl, browser_ttl, cache_key, and more |
LogCustomFieldRule | log_custom_field | request_fields, response_fields, cookie_fields, and more |
Rules that take constructor arguments
use Cloudflare\Configurations\Rules\BlockRule;
use Cloudflare\Configurations\Rules\CompressionRule;
use Cloudflare\Configurations\Rules\ConfigRule;
use Cloudflare\Configurations\Rules\ExecuteRule;
use Cloudflare\Configurations\Rules\ScoreRule;
use Cloudflare\Configurations\Rules\ServeErrorRule;
use Cloudflare\Configurations\Rules\SkipRule;
// Answer the request yourself. `content` is sent as-is, so encode it to match
// the content type you declare.
new BlockRule('{"error":"blocked"}', 'application/json', 403);
// Run one of Cloudflare's managed rulesets.
new ExecuteRule('4814384a9e5d4991b9815dcfc25d2f1f');
// Add to the request's cumulative score.
new ScoreRule(20);
// Serve an error page instead of reaching the origin.
new ServeErrorRule('text/html', '<h1>Gone</h1>', 410);
// Compress the response with a named algorithm.
new CompressionRule('brotli');
// Change zone settings for this request only.
new ConfigRule(['ssl' => 'full', 'automatic_https_rewrites' => true]);
// Skip Cloudflare's own products or rules.
new SkipRule(['products' => ['waf', 'rateLimit']]);
Everything else
The remaining actions take parameters Cloudflare defines per action and extends over time, so they are passed through as given rather than modelled one method at a time:
use Cloudflare\Configurations\Rules\RedirectRule;
use Cloudflare\Configurations\Rules\RewriteRule;
$redirect = (new RedirectRule())
->enable()
->setExpression('http.request.uri.path eq "/old"')
->setActionParameters([
'from_value' => [
'status_code' => 301,
'target_url' => ['value' => 'https://example.com/new'],
'preserve_query_string' => true,
],
]);
$rewrite = (new RewriteRule())
->enable()
->setActionParameters([
'uri' => ['path' => ['value' => '/rewritten']],
'headers' => ['x-source' => ['operation' => 'set', 'value' => 'cloudflare']],
]);
setActionParameters() works on every rule, including the ones with constructors, so anything Cloudflare adds is reachable without waiting for this package to catch up.

