, 3 min read

Mixing PHP into Markdown

Original post is here eklausmeier.goip.de/blog/2023/08-27-mixing-php-into-markdown.


Markdown is a simple language to write documents, which are finally converted to HTML. There are many conversion programs to convert from Markdown to HTML. This blog uses MD4C for this.

The CommonMark specification says:

An HTML block is a group of lines that is treated as raw HTML (and will not be escaped in HTML output).

Start condition: line begins with the string <?.

End condition: line contains the string ?>.

So it is possible to embed PHP in Markdown. Unfortunately, not every construct in Markdown passes PHP through undisturbed. For example, links and images, i.e., [reftext](ref) and ![](/imgref) destroy the PHP start- and endtags <? and ?>. Luckily, these small glitches can be cured with some string-replacements.

1. Examples

1. Uses. Embedding PHP code in Markdown allows us to write something like this, below is Markdown:

<?php
    $pkgList = explode("\n",`pacman -Q`);
    $pkg = array();
    foreach ($pkgList as $e) { $f=explode(' ',$e); $pkg[$f[0]??'x'] = $f[1]??''; }
?>

Using neovim version <?=$pkg['neovim']?>.

That's exactly what is done in /uses.

2. Shell code. Another example is adding information based on time:

On <?=date('d-M-Y')?> this blog has <?= `find ~klm/php/sndsaaze/content -name \*.md | wc -l` ?> entries.

Above code is used in Blog Anniversary: 500 posts.

3. Chapter numbering. Below code also shows the use of PHP within Markdown:

<?php $chap=0; $subchap=0; ?>

# <?=++$chap?>. First chapter
# <?=++$chap?>. Second chapter
## <?=$chap.'.'.(++$subchap)?> Subchapter

This produces:

<h1>1. First chapter</h1>
<h1>2. Second chapter</h1>
<h2>2.1 Subchapter</h2>

When PHP code is included in HTML code, which is legal in Markdown, then no "escaping" with a star (*) is required.

PHP code in HTML code can be included verbatim. For example:

<p>2021-04-02 <a href="<?=$rbase?>/pkg/jpilot_2.0.1-1_amd64.deb">jpilot_2.0.1-1_amd64.deb</a>

4. Specifying URLs. Here is an example of PHP code in the URL part in Markdown:

The Markdown for _Simplified Saaze_ can also [contain PHP code](*<?=$rbase?>*/blog/2023/08-27-mixing-php-into-markdown)!

Embedding PHP in ordinary text is also no problem. No escaping with a star (*) is required.

5. Table numbering. In /aux/blogroll table entries are numbered like this:

<?php
    $c = 0;
    $r = '<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 -960 960 960" width="32"><path d="M200-120q-33 0-56.5-23.5T120-200q0-33 23.5-56.5T200-280q33 0 56.5 23.5T280-200q0 33-23.5 56.5T200-120Zm480 0q0-117-44-218.5T516-516q-76-76-177.5-120T120-680v-120q142 0 265 53t216 146q93 93 146 216t53 265H680Zm-240 0q0-67-25-124.5T346-346q-44-44-101.5-69T120-440v-120q92 0 171.5 34.5T431-431q60 60 94.5 139.5T560-120H440Z"/></svg>';
?>

Nr.       | Blog                                                             | Categories                           | RSS
----------|------------------------------------------------------------------|--------------------------------------|-----------
<?=++$c?> | [Alice Girard Guittard](https://alicegg.tech/table-of-contents)  | Software Engineering, Graphics       | [*<?=$r?>*](https://www.alicegg.tech/feed.xml)
<?=++$c?> | [Andrew Healey](https://healeycodes.com)                         | compiler, WebAssembly                | [*<?=$r?>*](https://healeycodes.com/feed.xml)

Also, PHP is used to save a number of keystrokes.

2. Implementation

1. Using asterisks. Within ordinary paragraph text it is easy to just embed PHP, which is passed through to HTML unchanged. In references I now use this character combination to later string-replace any glitches introduced by the Markdown-to-HTML conversion.

[reference text](*<?=$rbase?>*/htmlRef)

With these added asterisks I then later replace any conversion errors. Previously I just used below code to include HTML in Simplified Saaze's templates:

<?= $entry['content'] ?>

Now I use (please mentally uppercase 3c and 3e):

$s = str_replace('*%3c?','<?',$entry['content']);
$s = str_replace('?%3e*','?>',$s);
require 'data:text/plain;base64,'.base64_encode($s);

2. php.ini When using require with data:text then you have to activate this in php.ini:

allow_url_include = On

See allow_url_include.

More information on data-wrappers is here: data:// and the comment by brainbox. Furthermore see PHP include and the comment by sPlayer. RFC 2397 details data:[<mediatype>][;base64],<data>.