Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Spdx Licenses Laravel Package

composer/spdx-licenses

Standalone PHP library for SPDX license data and validation. Look up licenses and exceptions by identifier or name, check OSI approval and deprecation status, and validate SPDX license expressions. Lightweight and dependency-free, originally extracted from Composer. Requires PHP 5.3.2+.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer — this is a data + validation library with zero dependencies, so it won't fight your Laravel stack:

composer require composer/spdx-licenses

Then instantiate and hit the two methods you'll actually use 90% of the time:

use Composer\Spdx\SpdxLicenses;

$spdx = new SpdxLicenses();

// 1. Is this string a legal SPDX expression?
$isValid = $spdx->validate('MIT OR Apache-2.0'); // true
$isValid = $spdx->validate('MIT OR');            // false

// 2. Canonicalise / look up a single identifier
$license = $spdx->getLicenseByIdentifier('MIT');
// ['name' => 'MIT License', 'identifier' => 'MIT', 'osiApproved' => true, ...]

Look first at the SpdxLicenses class itself (Composer\Spdx\SpdxLicenses) — it's a small surface area, and the README maps every public method. The bundled resources/ directory (JSON files of the SPDX list) is where the actual data lives; you should almost never touch it directly.

Your first real use case will be a form that accepts a license: a package manifest editor, an onboarding screen for partner integrations, or a field on a "third-party component" model. Wire validate() to that input and store the canonical getIdentifierByName()/getLicenseByIdentifier() result rather than the raw user string. That single change is what makes downstream filtering (WHERE license IN ('MIT','Apache-2.0')) and reporting possible.

Implementation Patterns

1. Form request validation (the bread-and-butter pattern). Wrap validate() in a Laravel Rule. This keeps controllers clean and gives you a reusable validator across requests:

namespace App\Rules;

use Composer\Spdx\SpdxLicenses;
use Illuminate\Contracts\Validation\Rule;

class SpdxExpression implements Rule
{
    public function passes($attribute, $value): bool
    {
        return (new SpdxLicenses())->validate($value);
    }

    public function message(): string
    {
        return 'The :attribute must be a valid SPDX license expression.';
    }
}

Then 'license' => ['required', new SpdxExpression()] on any DTO. Because identifiers are case-insensitive since 1.3.0, you don't need to pre-lowercase.

2. A thin application service so you're not new SpdxLicenses() everywhere. Bind it as a singleton in a service provider (it's cheap but the full license list is loaded lazily), then depend on a facade-like wrapper:

// App\Services\LicenseService
public function isAcceptable(string $expression): bool
{
    if (!$this->spdx->validate($expression)) {
        return false;
    }
    // Policy layer: reject deprecated IDs and unapproved variants.
    foreach ($this->identifiersIn($expression) as $id) {
        if ($this->spdx->isDeprecatedByIdentifier($id)) {
            return false;
        }
    }
    return true;
}

3. Dependency triage / SBOM export. When generating composer.json for downstream packages, or building a CycloneDX component list, use getLicenseByIdentifier() to resolve the human-readable name and OSI flag once, at write time:

$result = $spdx->getLicenseByIdentifier($row->license);
if ($result === null) {
    // Unknown — fall back to validating the raw expression, or flag for review
}

Store the canonical identifier for joins and the name for display. This is the single highest-leverage thing for procurement questionnaires and audit reports.

4. CI checks with a warning-first policy. Use the library in your build script (not just runtime) to gate PRs. Start with warnings for a few weeks, then flip to blocking at release, then at PR — otherwise you'll get a spike of false positives that erodes trust in the check. The isDeprecatedByIdentifier() check alone catches most stale metadata.

5. Policy engine integration. Wrap OSI/deprecation checks into a LicensePolicy object so the product decision (block copyleft? allow only OSI?) lives in one place and can change per tenant or package tier without touching validation code.

Gotchas and Tips

  • validate() is expression-level, not identifier-level. MIT OR Apache-2.0 is valid even if you've never enumerated the components. If your business rule is "must be a single known license," check getLicenseByIdentifier() and validate — don't rely on validate() alone.
  • getLicenseByIdentifier() returns null for unknown identifiers, and returns a null/array depending on version quirks for deprecated IDs — always null-check rather than assuming an array is returned.
  • The bundled SPDX list is a snapshot. Each release bumps the SPDX version (3.3 → 3.28 across the changelog). Pin the package version or upgrade deliberately: if you block deprecated IDs, a new release can suddenly reject previously-accepted data. Run CI against the upgrade before merging.
  • Deprecation ≠ invalid. isDeprecatedByIdentifier('GPL-2.0') returns true, but the expression still validates. Decide explicitly whether deprecated IDs are blocked — the library won't do it for you.
  • The + operator (GPL-2.0+) and WITH clauses are easy to mis-validate manually. This is the strongest argument for not hand-rolling validation; the regex implementation (since 1.0.0) handles parens/WITH/+ correctly.
  • Performance: 1.1.1 improved single-license lookup; the instance loads data lazily. For high-throughput endpoints, resolve once at startup via a singleton rather than instantiating in a hot loop.
  • Extension points: SpdxLicenses::LICENSES_FILE, EXCEPTIONS_FILE, and getResourcesDir() exist if you ever need to point at a custom snapshot — but treat the data as append-only and version-controlled, not something you edit in place.
  • No SBOM output here. This library validates and looks up; it does not emit SPDX/CycloneDX documents. Pair it with a generator when you need actual SBOMs.
  • Debugging tip: when a real-world license string fails, echo the exception/false path and test against the raw SPDX spec site — most failures are typos (Apache 2.0 vs Apache-2.0) or free-text (MIT License is a name, not an identifier; use getIdentifierByName()).
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource