Download the PHP package kanopi/crs-engine without Composer

On this page you can find all versions of the php package kanopi/crs-engine. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package crs-engine

kanopi/crs-engine

A standalone, pure-PHP engine that parses the OWASP Core Rule Set and evaluates HTTP requests against it. No FFI, no sidecars, no external runtimes — just PHP.

It exists so that a PHP-based firewall (or any PHP application) can speak the same rule format as ModSecurity / Coraza / CRS without shelling out, embedding a Go binary, or hand-translating thousands of regexes.

This package is a sibling of kanopi/firewall and is consumed by it through a thin plugin adapter — but the engine itself depends on nothing in the firewall and can be used standalone in any framework (Symfony, Laravel, Drupal, WordPress, raw PHP).


Table of contents


How it works

The engine has three stages:

  1. Refresh (build time)bin/refresh-crs downloads a pinned CRS release from GitHub, parses every REQUEST-*.conf file with the bundled SecLang parser, and writes the result to rules/:

    • rules/<source>.json — one human-reviewable JSON file per CRS source file, used to make diff review of CRS bumps painless.
    • rules/compiled.php — a single var_export'd PHP array that opcache can preload, used as the runtime hot path.
    • rules/manifest.json — version, rule counts, parser warnings.
  2. Load (process start)CrsEngine's constructor reads rules/compiled.php once. With opcache enabled, subsequent processes hit a warm cache and pay almost no cost.

  3. Evaluate (per request) — the application adapts its framework request into a RequestData DTO and calls $engine->evaluate($request). The evaluator resolves CRS target expressions against the request, applies transforms, runs operators (mostly @rx), accumulates per-category anomaly scores, and returns a CrsVerdict carrying the action (allow / log / block), matched rules, and scores.

The refresh step runs on a schedule in CI — never on production hot paths.


Requirements

The package has no runtime composer dependencies — only phpunit, phpstan, rector, and php_codesniffer for development.


Installation

After installing, generate the rule cache once:

This downloads the CRS release pinned in the package's .crs-version and populates vendor/kanopi/crs-engine/rules/. You only need to do this on fresh installs or when the pinned tag changes.


Quick start

For framework-specific adapters (Symfony Request, PSR-7, Laravel Illuminate\Http\Request, Drupal Symfony\HttpFoundation\Request), write a small mapper that produces RequestData. There is intentionally no built-in adapter — keeping the engine framework-free is the point.


Configuration

All configuration is constructor arguments on CrsConfig. Build it directly or with CrsConfig::fromArray() if you load config from YAML / env.

Field Default Notes
paranoia 1 Rules tagged with paranoia-level/N above this are skipped.
mode block monitor evaluates and records matches but never returns block.
anomalyThresholds severity-keyed The critical value is compared against accumulated inbound_anomaly_score_plN totals.
disabledRules [] List of CRS rule IDs to skip — useful for known false positives.
disabledCategories [] Skip an entire category (sqli, xss, lfi, etc.) for targeted tuning.
rulesPath bundled rules/ Point at a custom rule directory (used for testing and custom rulesets).

The request DTO

Kanopi\Crs\Request\RequestData is the framework-agnostic input. Build it once per request from whatever your framework provides:

RequestData::fromGlobals() is provided for CLI experimentation but should not be used in framework integrations — your framework has a richer, already-parsed request object.


The verdict

CrsEngine::evaluate() returns a Kanopi\Crs\CrsVerdict:

In monitor mode action is log whenever any rule matched and allow otherwise — isBlocked() always returns false. In block mode, the first rule that asks to deny short-circuits evaluation.


Supported SecLang subset

The parser is deliberately narrower than full ModSecurity. It covers everything CRS 4.x uses in its REQUEST-* rule files, with the explicit exception of operators that need libinjection.

Directives: SecRule (full), SecAction/SecMarker (parsed and ignored — used only as skipAfter targets).

Operators (16): @rx, @pm, @pmf, @beginsWith, @endsWith, @contains, @containsWord, @streq, @eq/@gt/@lt/@ge/@le, @within, @ipMatch (with CIDR), @validateByteRange, @validateUrlEncoding, @validateUtf8Encoding.

Unsupported operators (@detectSQLi, @detectXSS, etc.) cause the rule to be parsed-and-skipped with a warning recorded in manifest.json. These two operators back CRS rules 942100 and 941100 specifically — the libinjection-backed SQLi and XSS detectors. The other 50+ SQLi and 40+ XSS rules in CRS are pure @rx and work normally.

Transforms (20+): none, lowercase/uppercase, urlDecode/urlDecodeUni, htmlEntityDecode, compressWhitespace/removeWhitespace, replaceNulls/removeNulls, utf8toUnicode, base64Decode/base64DecodeExt, cmdLine, normalisePath, length, sha1/md5, trim, removeComments/replaceComments.

Variables (targets): ARGS, ARGS_GET, ARGS_POST, ARGS_NAMES, ARGS_GET_NAMES, ARGS_POST_NAMES, REQUEST_URI, REQUEST_URI_RAW, REQUEST_FILENAME, REQUEST_METHOD, REQUEST_PROTOCOL, REQUEST_LINE, REQUEST_BODY, REQUEST_HEADERS, REQUEST_HEADERS_NAMES, REQUEST_COOKIES, REQUEST_COOKIES_NAMES, QUERY_STRING, REMOTE_ADDR, FILES_NAMES, TX:<name>.

Target modifiers !collection:selector (exclude), &collection (count), and regex selectors collection:/pattern/ are all supported.

Actions: id, phase, block/deny/drop/pass/allow, chain, capture, multiMatch, t:*, msg, logdata, severity, tag, ver/rev/maturity/accuracy (recorded but unused at runtime), setvar, skipAfter. ctl:*, expirevar, deprecatevar, and similar state-management actions are accepted by the parser and silently ignored.


Rule scope

Only request-side CRS rule files are parsed (response inspection is out of scope for v1):

RESPONSE-* files and CRS's own config/init files (REQUEST-901-INITIALIZATION, REQUEST-905-COMMON-EXCEPTIONS, RESPONSE-980-CORRELATION) are not parsed.


Refreshing CRS rules

bin/refresh-crs is the single entry point for keeping the rule cache current. It is deliberately not run at runtime — only at build / CI time.

What it does:

  1. Reads .crs-version (or applies the override flag).
  2. Downloads https://github.com/coreruleset/coreruleset/archive/refs/tags/<tag>.tar.gz.
  3. Extracts to a temp directory with PharData.
  4. Parses every supported REQUEST-*.conf with the bundled SecLangParser.
  5. Writes rules/<source>.json, rules/manifest.json, and rules/compiled.php.
  6. Updates .crs-version with the new tag.

The result is normal, reviewable git changes. The intended pattern for production projects is a scheduled CI job that runs --bump weekly, opens a PR with the regenerated rules, and lets a maintainer review the diff before merging. CircleCI's weekly-refresh workflow in this repo demonstrates that pattern.

Version pin format

.crs-version is a plain key=value file:

The source field can point at a fork or mirror. sha is populated for provenance but not enforced.


Debugging a rule

bin/crs-explain prints the parsed form of a CRS rule and optionally tests a payload against it:

Output includes the rule's targets, transforms, operator, message, tags, and whether your payload matches. Useful for diagnosing false positives without trawling through CRS source.


Testing

Two test suites, separated by speed and scope.

Unit tests (tests/Unit/) cover the parser, transforms, operators, and the TxStore against hand-crafted SecLang snippets — no network, no real CRS download.

Integration tests (tests/Integration/) run real-shaped CRS rules from bundled fixtures (tests/Integration/fixtures/REQUEST-*.conf) against real attack payloads:

The fixture files mirror the format and identifier ranges of real CRS rules, so the integration tests double as regression checks for the parser.


Code quality checks

All three static analysis tools are wired into composer scripts and CI:

PHPStan runs at level: max. The full firewall library's pragmatic identifier ignores (argument.type, cast.string, missingType.iterableValue) are inherited so untrusted-JSON ingestion paths stay tractable.

Rector targets LevelSetList::UP_TO_PHP_81 so the engine stays compatible with the lower PHP bound while still picking up modern idioms (readonly properties, constructor promotion, etc.).


CircleCI pipeline

.circleci/config.yml mirrors kanopi/firewall — it uses the kanopi/ci-tools@2 orb, runs every check on a PHP-version matrix (8.1, 8.2, 8.3, 8.4, 8.5), and exposes three workflows.

Workflow Trigger Jobs (each runs across the full PHP matrix)
test every push / PR phpunit, phpstan (via check:stan:circleci), rector (check:rector:circleci), quality (check:code:circleci)
weekly-refresh scheduled trigger with pipeline-trigger=weekly-refresh refresh-and-branch (runs refresh-crs --bump, all static checks, all tests, then pushes a chore/crs-refresh-<tag>-<date> branch)
release tag push matching vX.Y.Z Same matrix as test, but gated to tag pushes — green on every PHP version is the prerequisite for the release tag to ship.

Each matrix job publishes JUnit results and stores the per-tool reports (phpcs-report.xml, phpstan-report.xml, rector-report.xml, reports/junit.xml) as CircleCI artifacts.

To wire up the weekly bump:

  1. In CircleCI's project settings, add a Scheduled Pipeline:
    • Schedule: 0 6 * * 1 (Mondays 06:00 UTC)
    • Pipeline parameter: pipeline-trigger = weekly-refresh
  2. Ensure the kanopi-code CircleCI context is attached. It carries the shared deploy SSH key (consumed by ci-tools/copy-ssh-key), the GitHub token for gh pr create, and the Docker Hub credentials.

The job:

  1. Runs bin/refresh-crs --bump to fetch the latest upstream CRS release.
  2. Re-runs phpcs / phpstan / rector / phpunit against the refreshed ruleset.
  3. If anything changed in .crs-version or rules/, commits to a new chore/crs-refresh-<tag>-<date> branch.
  4. Pushes the branch and opens a PR automatically via gh pr create, labelled crs-bump, with rule counts and warning counts in the body.

A maintainer reviews the diff and merges — the only human step.


Project layout


Versioning

The engine follows semver, with CRS pin bumps driving the change type:

Each release commit carries the CRS tag it ships with in its message, e.g. Release v0.3.0 (CRS v4.7.0). The shipped .crs-version is authoritative.


License and attribution

The engine code is licensed under the MIT License (see composer.json).

CRS rule content under rules/ is a derived work of the OWASP Core Rule Set, which is licensed under Apache 2.0. The CRS NOTICE and LICENSE files are copied into rules/ on every refresh; please retain them when redistributing.

This package does not vendor or republish CRS — it downloads it on demand during the refresh step.


All versions of crs-engine with dependencies

PHP Build Version
Package Version
Requires php Version >=8.1
ext-json Version *
ext-mbstring Version *
ext-pcre Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package kanopi/crs-engine contains the following files

Loading the files please wait ...