Missing Copyright Or Licence Header

ID

php.track_lack_copyright_license_headers

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

Php

Tags

best-practice, code-style

Description

Reports a PHP source file whose leading comment block — the comments above the first parsed token, be that a declare, a namespace clause or the first declaration — does not carry the project’s copyright or licence notice.

What counts as a header is a project decision, so the notice is supplied as a regular expression in the headerPattern property. The property is empty by default, and an empty pattern makes the rule a no-op: a project with no header policy gets no findings at all, because flagging every one of its files would be pure noise. Configure the pattern to switch the rule on.

All three comment forms count, so a // run, a # run and a block comment or docblock are equally good places for the notice. Machine-generated files carrying a @generated or DO NOT EDIT banner are skipped: nobody hand-edits them, and the generator rather than the project decides what their first lines say.

Rationale

A file with no header leaves its ownership and its redistribution terms undeclared. Source files travel on their own: they get vendored into another project, copied into a snippet, pasted into an issue, or shipped inside a container image. Once separated from the repository’s LICENSE file, an unheaded file carries no evidence of the terms it was released under.

That has concrete consequences. Licence-compliance scans and SPDX inventories read per-file notices, so an unheaded file shows up as unknown-licence and blocks the release. Contributors cannot tell whether a file is safe to reuse. And in a repository that mixes licences — a vendored third-party directory, a dual-licensed module — the absence of a header is genuinely ambiguous rather than merely untidy.

PHP makes the omission easy: the <?php tag opens the file, and the first thing most editors generate after it is the namespace clause, with nothing in between.

<?php

namespace App\Billing;

class Invoice
{
    public function total(int $a, int $b): int
    {
        return $a + $b;
    }
}

Remediation

Add the project’s notice as a comment block immediately after the open tag. A docblock or a declare(strict_types=1) may sit between the notice and the namespace clause; the pattern is searched anywhere in the leading block, so any order matches.

<?php
// Copyright 2026 Example Corp.
// SPDX-License-Identifier: Apache-2.0

declare(strict_types=1);

namespace App\Billing;

class Invoice
{
    public function total(int $a, int $b): int
    {
        return $a + $b;
    }
}

Adding headers across an existing repository is mechanical and worth automating — reuse and similar tools insert the block in place. Most IDEs also apply a copyright profile to every new file, which keeps the problem from coming back.

Configuration

Property Default Description

headerPattern

"" (rule disabled)

Regular expression searched inside the file’s leading comment block. Set it to the notice the project enforces — SPDX-License-Identifier for an SPDX policy, Copyright \(c\) [0-9]{4} for a classic notice. While empty, the rule reports nothing.

© 2026 Xygeni. All rights reserved