PHPackages                             werk365/etagconditionals - 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. [HTTP &amp; Networking](/categories/http)
4. /
5. werk365/etagconditionals

ActiveLibrary[HTTP &amp; Networking](/categories/http)

werk365/etagconditionals
========================

Laravel package to enable support for ETags and handling If-Match and If-None-Match conditional requests

1.4.2(3y ago)90265.8k—6.8%14[2 issues](https://github.com/365Werk/etagconditionals/issues)[3 PRs](https://github.com/365Werk/etagconditionals/pulls)1MITPHP

Since Feb 13Pushed 8mo ago3 watchersCompare

[ Source](https://github.com/365Werk/etagconditionals)[ Packagist](https://packagist.org/packages/werk365/etagconditionals)[ Docs](https://github.com/werk365/etagconditionals)[ RSS](/packages/werk365-etagconditionals/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (18)Used By (1)

Laravel ETag &amp; Conditionals
===============================

[](#laravel-etag--conditionals)

[![Latest Version on Packagist](https://camo.githubusercontent.com/03c332d457dce2d67e88548e910af7bfccd8be6651a81b912168731027e8cfdf/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7765726b3336352f65746167636f6e646974696f6e616c732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/werk365/etagconditionals)[![Total Downloads](https://camo.githubusercontent.com/ba2d3c4328576e7fab7f41322dffa1e7bc3184dd3d9da32d873a79c50225e8a8/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7765726b3336352f65746167636f6e646974696f6e616c732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/werk365/etagconditionals)[![StyleCI](https://camo.githubusercontent.com/0bb966e200a159272a2c2339105bd982c121c34faf35368a0d686757d7785f8a/68747470733a2f2f7374796c6563692e696f2f7265706f732f3333383631373534392f736869656c64)](https://styleci.io/repos/338617549)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/b0cf6f4a499157959de8fcab126ca810f9ff7b1685afc747b5fed9cda6509300/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f3336355765726b2f65746167636f6e646974696f6e616c732f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/365Werk/etagconditionals/?branch=master)[![Build Status](https://camo.githubusercontent.com/066da332d303c36ba225ae854ade998fb54666afa8164d4cb0a116c37ceb01ac/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f3336355765726b2f65746167636f6e646974696f6e616c732f6261646765732f6275696c642e706e673f623d6d6173746572)](https://scrutinizer-ci.com/g/365Werk/etagconditionals/build-status/master)

This package provides a set of middlewares to both set [ETags](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag) and handle [HTTP Conditional Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests#conditional_headers).

Currently both `If-None-Matched` and `If-Match` are supported.

The package aims to provide the tools to provide better client-side caching when building an API with Laravel, as well as preventing mid-air collisions.

When using the package and enabling the middleware, your client (browser) will take care of handling the caching provided by the `ETag` and `If-None-Match` headers automatically.

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

[](#installation)

Via Composer

```
$ composer require werk365/etagconditionals
```

Usage
-----

[](#usage)

You can either use the middleware group, automatically applying all available middleware (recommended if using an apiResource route for example), by setting the `etag` middleware, or apply the middlewares individually.

Currently available middleware:

- `setEtag`
- `ifMatch`
- `ifNoneMatch`

### setEtag

[](#setetag)

`Method: Any`

This middleware will set the `ETag` header on your responses. The `ETag` header is equal to a md5 hash of `$response->getContent()`. `HEAD` requests are supported by transforming the request to a `GET` request and changing it back on the response.

### ifMatch

[](#ifmatch)

`Method: PATCH`

This middleware will create a new request to the `GET` equivalent of the endpoint called and retrieve the current content. After this, a hash of the current content and the `If-Match` hash will be compared. If the hashes match, the `PATCH` request will be allowed through the middleware, but if there is no match, `412` will be returned.

> **Important** Since the internal `GET` request created will also pass through enabled middleware, you might run in to some cases where this is causing issues. For example: if you have a middleware that changes the response body that was not applied to the response that the `If-Match` etag belongs to, this will result in non-matching hashes.
>
> For this scenario, this middleware sets a `X-From-Middleware: IfMatch` header which you can use in other middleware to filter these requests. Please note that since this header could also be set by a client, it should never be used to skip anything important like auth middleware.

### ifNoneMatch

[](#ifnonematch)

`Method: GET|HEAD`

This middleware will simply compare the submitted `If-None-Match` header to a newly created etag of the response. If there is no match, `200` is returned, with the new response in the case of a `GET` request. If the hashes are matching, `304` is returned with no content, allowing the browser to used cached content instead.

### Comparison algorithms

[](#comparison-algorithms)

By default, a weak comparison algorithm will be used for both the `IfMatch` and `IfNoneMatch` ETags. In practise this means that we simply strip any `W/` tags from the ETag, so they can be compared to normal tags created in the middleware. This is to support cases where certain configurations automatically add the `W/` tag to our supplied ETag.

This behaviour can be changed by either publishing the config file:

```
$ php artisan vendor:publish --provider="Werk365\EtagConditionals\EtagConditionalsServiceProvider"
```

And then changing the following values:

```
return [
    'if_match_weak' => env('IF_MATCH_WEAK', true),
    'if_none_match_weak' => env('IF_NONE_MATCH_WEAK', true),
];
```

Or by setting the ENV values above.

### Defining custom ETags

[](#defining-custom-etags)

The static method `EtagConditionals::etagGenerateUsing()` allows you to have full control over how your Etag is generated by passing a callback as argument. This means you can do simple things like returning an ETag using a different algorithm, or other custom solutions.

```
        EtagConditionals::etagGenerateUsing(function (\Symfony\Component\HttpFoundation\Response $response) {
            return hash('sha256', $response->getContent());
        });
```

```
        EtagConditionals::etagGenerateUsing(function (\Illuminate\Http\Request $request, \Symfony\Component\HttpFoundation\Response $response) {
            return Cache::rememberForever('etag.'.$request->url(), function () use ($response) {
                 return md5($response->getContent());
            });
        });
```

Change log
----------

[](#change-log)

Please see the [changelog](changelog.md) for more information on what has changed recently.

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

[](#contributing)

Feel free to create issues and submit pull requests. For any PR submitted, make sure it is covered by tests or include new tests.

Security
--------

[](#security)

If you discover any security related issues, please email author email instead of using the issue tracker.

Credits
-------

[](#credits)

- [Hergen Dillema](https://github.com/HergenD)
- [All Contributors](../../contributors)

License
-------

[](#license)

Please see the [license file](LICENSE) for more information.

###  Health Score

46

—

FairBetter than 93% of packages

Maintenance41

Moderate activity, may be stable

Popularity48

Moderate usage in the ecosystem

Community18

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 88.9% 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

Every ~85 days

Recently: every ~164 days

Total

10

Last Release

1154d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/66e3e5ddb7ac36dd1858b7ca40280233c9ecf05b5d0040353af7308c6f482259?d=identicon)[HergenD](/maintainers/HergenD)

---

Top Contributors

[![HergenD](https://avatars.githubusercontent.com/u/32772820?v=4)](https://github.com/HergenD "HergenD (48 commits)")[![asbiin](https://avatars.githubusercontent.com/u/25419741?v=4)](https://github.com/asbiin "asbiin (5 commits)")[![365werk-admin](https://avatars.githubusercontent.com/u/100219572?v=4)](https://github.com/365werk-admin "365werk-admin (1 commits)")

---

Tags

laravelEtagConditionals

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/werk365-etagconditionals/health.svg)

```
[![Health](https://phpackages.com/badges/werk365-etagconditionals/health.svg)](https://phpackages.com/packages/werk365-etagconditionals)
```

###  Alternatives

[anchu/ftp

A simple Laravel 7 ftp service provider

225579.4k](/packages/anchu-ftp)[binary-cats/laravel-mailgun-webhooks

Handle Mailgun webhooks in a Laravel application

64299.4k](/packages/binary-cats-laravel-mailgun-webhooks)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)[laravel-shift/curl-converter

A command line tool to convert curl requests to Laravel HTTP requests.

935.3k](/packages/laravel-shift-curl-converter)[illuminatech/data-provider

Allows easy build for DB queries from API requests

4413.3k](/packages/illuminatech-data-provider)[onlime/laravel-http-client-global-logger

A global logger for the Laravel HTTP Client

1935.1k](/packages/onlime-laravel-http-client-global-logger)

PHPackages © 2026

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