PHP.GT

Protecting pages

HTMLDocumentProtector is responsible for taking an HTML document, generating one or more tokens, storing them, and inserting them into the right places in the markup.

Constructing a protector

The constructor accepts either a string of HTML or an existing GT\Dom\HTMLDocument, plus a token store:

use GT\Csrf\HTMLDocumentProtector;

$protector = new HTMLDocumentProtector($html, $tokenStore);

Or with an existing document:

use GT\Dom\HTMLDocument;

$document = new HTMLDocument($html);
$protector = new HTMLDocumentProtector($document, $tokenStore);

In both cases, getHTMLDocument() returns the HTMLDocument object after protection has been applied.

What protect() changes

Calling protect() does three things:

  1. finds POST forms in the document
  2. prepends a hidden <input> containing the token to each matching form
  3. creates or updates a <meta name="csrf-token"> tag in the page <head>
$protector->protect();
echo $protector->getHTMLDocument();

Only forms whose method is explicitly post are modified. Other forms are left alone.

Hidden input fields

The inserted form field has these attributes:

  • name="csrf-token"
  • value="<generated token>"
  • type="hidden"

The input is inserted before the form’s first child.

The head meta tag

The protector also keeps the token in a head meta tag:

<meta name="csrf-token" content="...">

If a matching meta tag already exists, its content attribute is replaced.

If the document has no <head>, the protector creates one and appends it to the <html> element before adding the meta tag.

One token per page or one token per form

The protect() method accepts a token-sharing mode:

$protector->protect(HTMLDocumentProtector::ONE_TOKEN_PER_PAGE);

This is the default. One token is shared by all POST forms on the page and by the head meta tag.

If needed, we can ask for one token per form:

$protector->protect(HTMLDocumentProtector::ONE_TOKEN_PER_FORM);

In that mode:

  • each POST form gets a different token
  • the head meta tag contains all generated tokens joined by commas

This is useful when one page can submit several different forms independently without a full page reload in between.

Pages with no forms

If the document contains no POST forms, protect() still generates and saves one token so the meta tag is available:

$protector->protect();

That means JavaScript can still read the token from the <head> even if the page itself has no form markup.

Return value of protect()

protect() returns the last token it generated.

  • with ONE_TOKEN_PER_PAGE, this is the shared page token
  • with ONE_TOKEN_PER_FORM, this is the final form token generated during the loop

In most cases it is simpler to work with the document output rather than using the return value directly.


Next to see how submitted tokens are checked and spent, continue on to Verifying requests.