How can I include PHP code in Hugo?

I’m trying to find a way to secure contact forms on Hugo sites with CSRF-tokens. I have read every topic on the forum related to PHP and Hugo. This is what I have tried so far to include PHP code to generate tokens, without any success:

Adding custom mediaTypes and outputFormats to the config file:

mediaTypes:
  application/x-php:
    suffixes:
    - php

outputFormats:
  PHP:
    mediaType: "application/x-php"
    isPlainText: true

Duplicating the affected layout file with a php suffix

In this case I duplicated layouts/_default/single.html to a .php file.

Specifing outputs in frontmatter

The relevant part from the contact page frontmatter (which is an .html, not a .md):

---
[…]
outputs:
- PHP
[…]
---

Including php code trough a shortcut

Content of layouts/shortcodes/php.html:

<?php {{ .Inner | safeHTML }} ?>

Adding code to the content file

This PHP is added to content/kontakt/index.html in an attempt to generate a token that is put in the php variable $token.

{{< php >}}
session_start(); if (empty($_SESSION['token'])) {$_SESSION['token'] = bin2hex(random_bytes(32));}$token = $_SESSION['token'];
{{< /php >}}

Results (or lack thereof):

I get a 404 error on the /kontakt-page with hugo serve, and when I build the site, Hugo does not output the /kontakt folder (or files) at all.

What am I missing?

Why is it content/kontakt/index.html and not .md?

I think in this specific case it’s maybe better if you add a sample repo so we can see the whole setup. Try running hugo with verbose and templateMetrics and parameters like that. Also: your sample is too small :wink: are you sure it’s not accidentially set to draft:true or a future date?

There’s two parts to your question:

  1. Can Hugo output php files?

Yes, if configured correctly.

  1. Will Hugo run the php code?

No. Unless you have server magic going on, but that is outside of Hugo.

Have you read through this topic?: Is it possible to use Hugo template functions and variables in a PHP file?

The first part we can probably help you with, but it will be easier if you had your code in a repo somewhere easily clone-able.

1 Like

I made this page in html as it was quicker to iterate the design, but I will eventually make each component into a shortcode and go back to markdown. But I can’t see how this could affect outputting the page as a php-file, other than some unforeseen behavior.

Everything works fine without outputs: - PHP in frontmatter, so I know that the rest of the code is working. I will try running Hugo with the verbose flag, though.

@pointyfar: I already have a php file which handles the submitted content from the contact from, which works fine (I forgot to mention this, sorry). This is a separate file which is placed in the /static-folder.

I don’t want Hugo itself to run the PHP code, I only want to add some PHP to the page which the server can process upon page load. To do this safely, the file cannot use the html-suffix, it has to be use .php to avoid certain attacks.

All I really want is for hugo to produce a .php file instead of a .html, but with the same content in it.

The repo is not public at the moment, but I might put it online in not to long. Have to clean up some loose ends.

In that case, I would suggest to start small, and break it down.

  1. create content/foo.md
  2. configure ouputs
  3. configure outputFormats
  4. configure custom mediaTypes
  5. create .php layout file

This should get you to foo.php or similar. Then diverge from there.

Perhaps move the php-specific bits into the layout file instead of the shortcode as well.

@pointyfar Great advice, I’ll just have to test this feature on an empty page to reduce the complexity. The boring, but correct answer :grin:

1 Like

After sleeping on it I quickly found the missing pieces. I’ll try to quickly summarize what I had to do:

  • Make duplicates of every relevant layout file: The baseof.html had to be duplicated with the .php suffix as well, as I use block’s in my templates – and single.php was dependent on baseof.php to render.
  • Make the $token variable persistent: The random string generated and stored in $token needs to be kept in memory when the submit-button is pressed and the PHP email script is loaded.

To accomplish the latter, you have to add a <?php session_start(); ?> before the HTML code in baseof.php, and store the string in a session variable ($_SESSION['token']). To make use of this variable on the following page load, you also have to include <?php session_start(); ?> at the start of the email script.

I should probably make a more complete and coherent how-to on how to make a contact form with CSRF, but hope the information above can help someone else in a pinch.

2 Likes

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.