{"id":16553298,"url":"https://github.com/allejo/php-vcr-sanitizer","last_synced_at":"2025-03-16T20:30:19.182Z","repository":{"id":51118415,"uuid":"129168304","full_name":"allejo/php-vcr-sanitizer","owner":"allejo","description":"Bring privacy to php-vcr and erase any sensitive information. Gone are the days for hoping no one steals your API keys.","archived":false,"fork":false,"pushed_at":"2024-01-23T02:56:47.000Z","size":101,"stargazers_count":15,"open_issues_count":0,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-05-02T06:16:37.993Z","etag":null,"topics":["php-vcr"],"latest_commit_sha":null,"homepage":"https://packagist.org/packages/allejo/php-vcr-sanitizer","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/allejo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-12T00:03:44.000Z","updated_at":"2024-06-18T18:39:52.520Z","dependencies_parsed_at":"2024-01-23T03:44:02.198Z","dependency_job_id":null,"html_url":"https://github.com/allejo/php-vcr-sanitizer","commit_stats":{"total_commits":74,"total_committers":10,"mean_commits":7.4,"dds":"0.28378378378378377","last_synced_commit":"5097b96cf0de9414a03469a241ef439cb285bc8d"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allejo%2Fphp-vcr-sanitizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allejo%2Fphp-vcr-sanitizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allejo%2Fphp-vcr-sanitizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allejo%2Fphp-vcr-sanitizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/allejo","download_url":"https://codeload.github.com/allejo/php-vcr-sanitizer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243826798,"owners_count":20354221,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["php-vcr"],"created_at":"2024-10-11T19:47:43.277Z","updated_at":"2025-03-16T20:30:18.817Z","avatar_url":"https://github.com/allejo.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# php-vcr-sanitizer\n\n[![Packagist](https://img.shields.io/packagist/v/allejo/php-vcr-sanitizer.svg)](https://packagist.org/packages/allejo/php-vcr-sanitizer)\n[![Tested with php-vcr v1.4+](https://img.shields.io/badge/Tested%20with%20php--vcr-1.4%20%7C%201.5%20%7C%201.6-brightgreen)](https://github.com/php-vcr/php-vcr)\n![Unit Tests](https://github.com/allejo/php-vcr-sanitizer/workflows/Unit%20Tests/badge.svg)\n[![GitHub license](https://img.shields.io/github/license/allejo/php-vcr-sanitizer.svg)](https://github.com/allejo/php-vcr-sanitizer/blob/master/LICENSE.md)\n\n[php-vcr](https://php-vcr.github.io/) is a tool for recording and replaying outgoing requests, however it has had [\"Privacy aware\" marked as \"soon\"](https://php-vcr.github.io/#page-nav-Features) for quite some time now. Whenever I test my APIs, there will often be some sensitive information such as keys or passwords in the recordings. Up until now, I've had a separate script to always remove sensitive data before getting checked into version control.\n\nI got tired of having to always sanitize the data, so this is a quick and dirty solution until php-vcr officially supports \"private\" recordings.\n\n## Table of Contents\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Configuration](#configuration)\n    - [Sanitizing Requests](#sanitizing-requests)\n    - [Sanitizing Responses](#sanitizing-responses)\n  - [Disabling the Sanitizer](#disabling-the-sanitizer)\n- [How Sanitizing Works](#how-sanitizing-works)\n  - [Hostnames](#hostnames)\n  - [Headers](#headers)\n  - [URL Parameters](#url-parameters)\n  - [Body Content](#body-content)\n  - [Post Field Content](#post-field-content)\n- [License](#license)\n\n\n## Installation\n\nInstall the package through [Composer](https://getcomposer.org/).\n\n```bash\ncomposer require --dev allejo/php-vcr-sanitizer\n```\n\n## Usage\n\nAfter your VCR instance has been turned on, call `VCRCleaner::enable()` and pass whatever URL parameters or headers you don't want to be recorded in your fixtures.\n\n```php\nVCR::turnOn();\nVCR::insertCassette('...');\n\nVCRCleaner::enable(array(\n   'request' =\u003e array(\n       'ignoreHostname' =\u003e false,\n       'ignoreQueryFields' =\u003e array(\n           'apiKey',\n       ),\n       'ignoreHeaders' =\u003e array(\n           'X-Api-Key',\n       ),\n       'bodyScrubbers' =\u003e array(\n           function($body) {\n               return preg_replace('/\u003cpassword.*?\u003c\\/password\u003e/', 'hunter2', $body);\n           }\n       ),\n       'postFieldScrubbers' =\u003e array(\n           function(array $postFields) {\n               $postFields['Secret'] = 'REDACTED';\n               return $postFields;\n           }\n       ),\n   ),\n   'response' =\u003e array(\n       'ignoreHeaders' =\u003e array('*'),\n       'bodyScrubbers' =\u003e array(),\n   ),\n));\n```\n\n### Configuration\n\nThis library allows your sanitize both the Request and Response sections of your recordings so only non-sensitive data is written to your cassettes. You define the behavior for this sanitizer via an array with configuration options explained below.\n\n#### Sanitizing Requests\n\n- `request.ignoreHostname` - When set to true, the hostname in URLs inside of the Request will be replaced with `[]` in the `url` field and the `Host` in the headers will be set to null.\n- `request.ignoreQueryFields` - Define which GET parameters in your URL to completely strip out of your recordings.\n- `request.ignoreHeaders` - Define the headers in your recording that will automatically be set to null in your recordings. Using an asterisk (i.e. `*`) in the array can be used to strip all headers from the request.\n- `request.bodyScrubbers` - An array of callbacks that will have the request body available as a string. Each callback **must** return the modified body. The callbacks are called consecutively in the order they appear in this array and the value from one callback propagates to the next.\n- `request.postFieldScrubbers` - An array of callbacks that will have the request post fields available as an array. Each callback **must** return the modified post fields array. The callbacks are called consecutively in the order they appear in this array and the value from one callback propagates to the next.\n\n#### Sanitizing Responses\n\nThe php-vcr library does not officially support modifying its responses so this library uses reflection to modify the contents of responses. While this feature is officially supported by *this* project, bear with us if this feature were to break due to the php-vcr changing its internals.\n\n- `response.ignoreHeaders` - The same as `request.ignoreHeaders` but for your response body instead.\n- `response.bodyScrubbers` - The same as `request.bodyScrubbers` but for your response body instead.\n\n### Disabling the Sanitizer\n\nWhy is there no `VCRCleaner::disable()`? There's no simple and non-hackish way to restore the VCR to its original state. It's probably easier to just configure your VCR differently for a certain batch of unit tests anyways.\n\n## How Sanitizing Works\n\nWhen VCR is looking for recordings to playback, VCRCleaner uses modified \"matchers\" to check everything except for the fields you've marked as sensitive.\n\n### Hostnames\n\nIf the hostname of the URL endpoint you're hitting is sensitive and shouldn't be recorded, you can have the sanitizer ignore hostnames and they'll be replaced in the `url` field with a `[]` instead and the `host` header will be set to null.\n\n```yaml\n-\n    request:\n        method: GET\n        url: 'https://[]/search'\n        headers:\n            Host: null\n            X-Type: application/vcr\n    response:\n        status:\n            http_version: '1.1'\n            code: '404'\n            message: 'Not Found'\n        headers: ~\n        body: \"...response body...\"\n```\n\n### Headers\n\nLet's say you set the `X-Api-Key` header to `SuperToast`. In your recording, the header you specified will be saved as null.\n\n```yaml\n-\n    request:\n        method: GET\n        url: 'https://www.example.com/search'\n        headers:\n            Host: www.example.com\n            X-Api-Key: null\n            X-Type: application/vcr\n    response:\n        status:\n            http_version: '1.1'\n            code: '404'\n            message: 'Not Found'\n        headers: ~\n        body: \"...response body...\"\n```\n\n### URL Parameters\n\nNotice how `apiKey=yourSecretApiKey` is stripped away in your recording. During your VCR playback, it'll look for matching requests *without* the `apiKey` parameter.\n\n```yaml\n# Your cURL call to: https://www.example.com/search?q=keyword\u0026apiKey=yourSecretApiKey\n# gets recorded like so,\n-\n    request:\n        method: GET\n        url: 'https://www.example.com/search?q=keyword'\n        headers:\n            Host: www.example.com\n    response:\n        status:\n            http_version: '1.1'\n            code: '404'\n            message: 'Not Found'\n        headers: ~\n        body: \"...response body...\"\n```\n\n### Body Content\n\nUnlike ignoring headers or URL parameters, scrubbing information from both request and response bodies makes use of an array of callbacks. The result of each function is passed on to the next function.\n\nNotice how `password=hunter2` has been stripped away from the request body. The callbacks take the body as a string parameter, the modified result has to be returned.\n\n```php\nVCRCleaner::enable(array(\n    'request' =\u003e array(\n        'bodyScrubbers' =\u003e array(\n            function ($body) {\n                $parameters = array();\n\n                parse_str($body, $parameters);\n                unset($parameters['password']);\n\n                return http_build_query($parameters);\n            },\n        ),\n    ),\n));\n```\n\n```yaml\n# You POST request to `https://www.example.com/search` with a body of\n# `username=AzureDiamond\u0026password=hunter2` gets recorded like so,\n-\n    request:\n        method: POST\n        url: 'https://www.example.com/search'\n        headers:\n            Host: www.example.com\n        body: 'username=AzureDiamond'\n    response:\n        status:\n            http_version: '1.1'\n            code: '404'\n            message: 'Not Found'\n        headers: ~\n        body: '...response body...'\n```\n\n### Post Field Content\n\nWhen making POST requests, your VCR will sometimes record the data inside of a `post_fields` parameter rather than the `body`; e.g. when `CURLOPT_POSTFIELDS` is used in cURL and you do not set `CURLOPT_POST` to `true`. In those cases, this option can be used to sanitize sensitive content. Note that unlike the `body` field, `post_fields` is an array:\n\n```php\nVCRCleaner::enable(array(\n    'request' =\u003e array(\n        'postFieldScrubber' =\u003e array(\n            function (array $postFields) {\n                $postFields['Secret_Key'] = '';\n                return $postFields;\n            },\n        ),\n    ),\n));\n```\n\n```yaml\n# You POST request to `https://www.example.com/search` with a post field of\n# `['data'=\u003e 'hello world', 'Secret_Key' =\u003e 'abc']` gets recorded like so,\n-\n    request:\n        method: POST\n        url: 'https://www.example.com/search'\n        headers:\n            Host: www.example.com\n        post_fields:\n            data: 'hello world'\n            Secret_Key: ''\n    response:\n        status:\n            http_version: '1.1'\n            code: '404'\n            message: 'Not Found'\n        headers: ~\n        body: '...response body...'\n```\n\n## License\n\n[MIT](/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallejo%2Fphp-vcr-sanitizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fallejo%2Fphp-vcr-sanitizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallejo%2Fphp-vcr-sanitizer/lists"}