PHPackages                             ecourty/presidio-client - 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. ecourty/presidio-client

ActiveLibrary

ecourty/presidio-client
=======================

A PHP client for Microsoft Presidio — detect and anonymize PII in text via Presidio's REST APIs.

1.0.0(1mo ago)10MITPHPPHP &gt;=8.3CI passing

Since Mar 19Pushed 1mo agoCompare

[ Source](https://github.com/EdouardCourty/presidio-client)[ Packagist](https://packagist.org/packages/ecourty/presidio-client)[ RSS](/packages/ecourty-presidio-client/feed)WikiDiscussions main Synced 1mo ago

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

Presidio Client for PHP
=======================

[](#presidio-client-for-php)

[![PHP CI](https://github.com/EdouardCourty/presidio-client/actions/workflows/ci.yml/badge.svg)](https://github.com/EdouardCourty/presidio-client/actions/workflows/ci.yml)

A typed PHP client for [Microsoft Presidio](https://github.com/microsoft/presidio) — detect and anonymize PII (Personally Identifiable Information) in text.

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

[](#requirements)

- PHP 8.3+
- A running [Microsoft Presidio](https://github.com/microsoft/presidio) instance (Analyzer + Anonymizer services)

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

[](#installation)

```
composer require ecourty/presidio-client
```

Quick Start
-----------

[](#quick-start)

The `Presidio` facade is the simplest way to use the library — it combines both clients and provides convenience methods:

```
use Ecourty\PresidioClient\Client\PresidioAnalyzer;
use Ecourty\PresidioClient\Client\PresidioAnonymizer;
use Ecourty\PresidioClient\Presidio;

// Use with default configuration (localhost:5001 for Analyzer, localhost:5002 for Anonymizer)
$presidio = new Presidio();

// Use with custom base URLs
$presidio = new Presidio(
    analyzer: new PresidioAnalyzer('http://presidio-analyzer:5001'),
    anonymizer: new PresidioAnonymizer('http://presidio-anonymizer:5002'),
);

// Analyze + Anonymize in a single call
$result = $presidio->anonymize('My email is john@example.com and my name is John Smith');

echo $result->getText();
// My email is  and my name is
```

### Custom Operators

[](#custom-operators)

You can configure different anonymization strategies per entity type:

```
use Ecourty\PresidioClient\Enum\OperatorType;
use Ecourty\PresidioClient\Model\OperatorConfig;

$result = $presidio->anonymize(
    text: 'My name is John Smith, email: john@example.com',
    operators: [
        'PERSON' => new OperatorConfig(OperatorType::REPLACE, ['new_value' => '[REDACTED]']),
        'EMAIL_ADDRESS' => new OperatorConfig(OperatorType::MASK, [
            'masking_char' => '*',
            'chars_to_mask' => 12,
            'from_end' => false,
        ]),
    ],
);
```

Available operators: `replace`, `redact`, `hash`, `mask`, `encrypt`, `decrypt`, `custom`, `keep`.
Check the [OperatorType enum](src/Enum/OperatorType.php) for details.

### Encrypt &amp; Decrypt (Round-Trip)

[](#encrypt--decrypt-round-trip)

```
use Ecourty\PresidioClient\Enum\OperatorType;
use Ecourty\PresidioClient\Model\DeanonymizeRequest;
use Ecourty\PresidioClient\Model\OperatorConfig;

$key = 'aaaaaaaaaaaaaaaa'; // 128-bit AES key

// Encrypt PII
$anonymized = $presidio->anonymize(
    text: 'My name is John Smith',
    operators: [
        'DEFAULT' => new OperatorConfig(OperatorType::ENCRYPT, ['key' => $key]),
    ],
);

// Decrypt PII
$deanonymized = $presidio->deanonymize(new DeanonymizeRequest(
    text: $anonymized->getText(),
    anonymizerResults: $anonymized->getItems(),
    deanonymizers: [
        'DEFAULT' => new OperatorConfig(OperatorType::DECRYPT, ['key' => $key]),
    ],
));

echo $deanonymized->getText();
// My name is John Smith
```

### Filter by Entity Type

[](#filter-by-entity-type)

```
use Ecourty\PresidioClient\Enum\EntityType;

$result = $presidio->anonymize(
    text: 'Contact john@example.com or call 555-123-4567',
    entities: [EntityType::EMAIL_ADDRESS], // only detect emails
    scoreThreshold: 0.8,
);
```

### Allow List

[](#allow-list)

Exclude specific values from being detected as PII:

```
use Ecourty\PresidioClient\Enum\AllowListMatch;

// "Acme Corp" will not be detected as an organization, but "John" will still be detected as a person.
$result = $presidio->anonymize(
    text: 'Contact John at Acme Corp',
    allowList: ['Acme Corp'],
    allowListMatch: AllowListMatch::EXACT,
);
```

### Ad-Hoc Recognizers

[](#ad-hoc-recognizers)

Add custom recognizers on the fly without modifying the Presidio server:

```
use Ecourty\PresidioClient\Model\AdHocRecognizer;
use Ecourty\PresidioClient\Model\Pattern;

// Pattern-based recognizer
$zipRecognizer = new AdHocRecognizer(
    name: 'Zip code Recognizer',
    supportedLanguage: 'en',
    supportedEntity: 'ZIP',
    patterns: [new Pattern('zip code (weak)', '(\b\d{5}(?:\-\d{4})?\b)', 0.01)],
    context: ['zip', 'code'],
);

// Deny-list based recognizer
$titleRecognizer = new AdHocRecognizer(
    name: 'Title Recognizer',
    supportedLanguage: 'en',
    supportedEntity: 'TITLE',
    denyList: ['Mr', 'Mr.', 'Mrs', 'Ms'],
);

$result = $presidio->anonymize(
    text: 'Mr. Smith lives at zip code 12345',
    adHocRecognizers: [$zipRecognizer, $titleRecognizer],
);
```

### Decision Process (Explainability)

[](#decision-process-explainability)

Get detailed explanations of why each entity was detected (requires low-level client access):

```
use Ecourty\PresidioClient\Model\AnalyzerRequest;

$results = $presidio->analyze(new AnalyzerRequest(
    text: 'Call me at 555-123-4567',
    returnDecisionProcess: true,
));

foreach ($results as $result) {
    $explanation = $result->getAnalysisExplanation();
    if ($explanation !== null) {
        echo $explanation->getRecognizer();              // "PhoneRecognizer"
        echo $explanation->getPatternName();             // "US Phone Regex"
        echo $explanation->getOriginalScore();           // 0.8
        echo $explanation->getScoreContextImprovement(); // 0.15
    }

    $metadata = $result->getRecognitionMetadata();       // ['recognizer_name' => '...']
}
```

### Health Checks

[](#health-checks)

```
$health = $presidio->health();

$health->isHealthy();           // true if both services are up
$health->isAnalyzerHealthy();   // true if Analyzer is reachable
$health->isAnonymizerHealthy(); // true if Anonymizer is reachable
```

### List Capabilities

[](#list-capabilities)

```
$presidio->getSupportedEntities(); // ['EMAIL_ADDRESS', 'PHONE_NUMBER', 'PERSON', ...]
$presidio->getRecognizers();       // [RecognizerResult, ...] (name, supported entities, languages)

$presidio->getAnonymizers();       // ['replace', 'redact', 'hash', 'mask', 'encrypt']
$presidio->getDeanonymizers();     // ['decrypt']
```

Supported Entity Types
----------------------

[](#supported-entity-types)

The `EntityType` enum provides all supported PII types:

`PERSON`, `PHONE_NUMBER`, `EMAIL_ADDRESS`, `CREDIT_CARD`, `CRYPTO`, `DATE_TIME`, `DOMAIN_NAME`, `IBAN_CODE`, `IP_ADDRESS`, `LOCATION`, `MEDICAL_LICENSE`, `NRP`, `SG_NRIC_FIN`, `UK_NHS`, `URL`, `US_BANK_NUMBER`, `US_DRIVER_LICENSE`, `US_ITIN`, `US_PASSPORT`, `US_SSN`, `AU_ABN`, `AU_ACN`, `AU_TFN`, `AU_MEDICARE`, `IN_PAN`, `IN_AADHAAR`, `IN_VEHICLE_REGISTRATION`, `IN_VOTER`, `IN_PASSPORT`

Error Handling
--------------

[](#error-handling)

API errors throw `ApiException` with the HTTP status code and response body:

```
use Ecourty\PresidioClient\Exception\ApiException;

try {
    $analyzer->analyze($request);
} catch (ApiException $e) {
    echo $e->getStatusCode();   // 400
    echo $e->getResponseBody(); // {"error": "..."}
}
```

All exceptions extend `PresidioException` (which extends `RuntimeException`).

Custom HTTP Client
------------------

[](#custom-http-client)

The facade accepts pre-configured client instances. Each client accepts a Symfony `HttpClientInterface`:

```
use Ecourty\PresidioClient\Client\PresidioAnalyzer;
use Ecourty\PresidioClient\Client\PresidioAnonymizer;
use Ecourty\PresidioClient\Presidio;
use Symfony\Component\HttpClient\HttpClient;

// Simple: custom base URLs
$presidio = new Presidio(
    analyzer: new PresidioAnalyzer('http://presidio-analyzer:5001'),
    anonymizer: new PresidioAnonymizer('http://presidio-anonymizer:5002'),
);

// Advanced: full HTTP client control
$analyzerClient = HttpClient::create(['base_uri' => 'http://presidio-analyzer:5001', 'timeout' => 10]);
$anonymizerClient = HttpClient::create(['base_uri' => 'http://presidio-anonymizer:5002', 'timeout' => 10]);

$presidio = new Presidio(
    analyzer: new PresidioAnalyzer(httpClient: $analyzerClient),
    anonymizer: new PresidioAnonymizer(httpClient: $anonymizerClient),
);

// Direct client access for advanced use cases
$analyzer = $presidio->getAnalyzer();
$anonymizer = $presidio->getAnonymizer();
```

Examples
--------

[](#examples)

See the [`examples/`](examples/) directory for runnable scripts:

```
docker compose up -d
php examples/01-quickstart.php
```

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

[](#development)

```
# Start Presidio services
docker compose up -d

# Run unit tests
composer test-unit

# Run integration tests (requires Presidio services)
composer test-integration

# Run all tests
composer test

# Static analysis (PHPStan level max)
composer phpstan

# Code style check / fix
composer cs-check
composer cs-fix

# Full QA (PHPStan + CS check + tests)
composer qa
```

License
-------

[](#license)

MIT

###  Health Score

40

—

FairBetter than 87% of packages

Maintenance96

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

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

51d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/3150ffb131124e5f03272d9ed8084c514f18fff6aafff1a5973c016993f6ef66?d=identicon)[ecourty](/maintainers/ecourty)

---

Top Contributors

[![EdouardCourty](https://avatars.githubusercontent.com/u/37371516?v=4)](https://github.com/EdouardCourty "EdouardCourty (7 commits)")

---

Tags

textnlpgdprprivacyanonymizationpiipresidio

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ecourty-presidio-client/health.svg)

```
[![Health](https://phpackages.com/badges/ecourty-presidio-client/health.svg)](https://phpackages.com/packages/ecourty-presidio-client)
```

###  Alternatives

[edyan/neuralyzer

Library and CLI for Data anonymization

53147.1k2](/packages/edyan-neuralyzer)[statikbe/laravel-cookie-consent

Cookie consent modal for EU

213396.7k](/packages/statikbe-laravel-cookie-consent)[opengento/module-gdpr

Gdpr Compliance Module for Magento 2

14481.5k](/packages/opengento-module-gdpr)[devrabiul/laravel-cookie-consent

A GDPR-compliant cookie consent solution for Laravel applications with fully customizable cookie banners, granular consent control, and enterprise-grade compliance features.

17633.8k1](/packages/devrabiul-laravel-cookie-consent)[georgringer/gdpr

Make TYPO3 more compatible to GDPR

4657.1k](/packages/georgringer-gdpr)[flarum/gdpr

Features for GDPR, PII management

1425.2k15](/packages/flarum-gdpr)

PHPackages © 2026

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