How to Convert Markdown to PDF with PHP

Convert Markdown articles into styled, tagged PDFs with PHP, including table formatting and uploaded images.
Share this page

This PHP tutorial converts Markdown into a tagged PDF with the pdfRest Convert to PDF API Tool. The sample sends the article, a referenced image, and structured styling options together so the downloadable document matches the intended content.

Why Convert Markdown to PDF with PHP?

Content portals and support sites often store articles as Markdown because editors can maintain headings, links, procedures, and code examples without working in raw HTML. Customers may still need a PDF for offline troubleshooting, field work, or sharing with someone who cannot access the portal.

Imagine a PHP knowledge base containing a repair procedure with ordered steps, a parts table, command examples, and an annotated image. When a technician requests a download, the application can convert the existing Markdown into a formatted PDF and map the uploaded illustration to its source reference. The team maintains one article instead of a web version and a separately edited manual.

Configurable table fills, borders, padding, typography, and page margins help the export look intentional rather than like a browser printout. Tags and image alternate text add useful document semantics, while the PHP application continues using its established Markdown publishing workflow.

PHP Code Example for Converting Markdown to PDF

require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Utils;

// By default, we use the US-based API service. This is the primary endpoint for global use.
$apiUrl = "https://api.pdfrest.com";

/* For GDPR compliance and enhanced performance for European users, you can switch to the EU-based service by uncommenting the URL below.
 * For more information visit https://pdfrest.com/pricing#how-do-eu-gdpr-api-calls-work
 */
//$apiUrl = "https://eu-api.pdfrest.com";

$inputPath = '/path/to/sample.md';
$imagePath = '/path/to/logo.png';
$options = json_decode('{"title":"Structured Content Sample","language":"en-US","enable_tagging":true,"page_setup":{"size":"Letter","orientation":"portrait","margin":{"top":36,"right":42,"bottom":36,"left":42}},"style":{"font":"Arial","heading_font":"Arial","code_font":"Courier","text_size":11,"text_color_rgb":[34,34,34],"heading_scale":1.35,"table":{"column_width_weights":[2,3,2],"keep_header_with_first_row":true,"repeat_headers_on_overflow":true,"show_borders":true,"border_width":0.75,"border_color_rgb":[180,188,200],"header_fill_color_rgb":[33,64,98],"header_text_color_rgb":[255,255,255],"row_fill_color_rgb":[250,250,252],"alternate_row_fill_color_rgb":[235,240,246],"cell_padding":{"top":6,"right":8,"bottom":6,"left":8}}},"markdown":{"image_alt_text":{"sample-logo":"Sample logo"},"missing_image_alt_text":"fail","image_sources":{"sample-logo":{"upload_index":0}}}}', true);

// This sample converts Markdown input to a tagged PDF through multipart /pdf.
// It demonstrates structured_text_options, table styling, tagging, and uploaded Markdown image mapping.
$multipart = [
  ['name' => 'file', 'contents' => Utils::tryFopen($inputPath, 'r'), 'filename' => basename($inputPath)],
  ['name' => 'image_files', 'contents' => Utils::tryFopen($imagePath, 'r'), 'filename' => basename($imagePath)],
  ['name' => 'structured_text_options', 'contents' => json_encode($options)],
  ['name' => 'output', 'contents' => 'pdf_from_markdown'],
];
$response = (new Client())->post($apiUrl . '/pdf', ['headers' => ['Api-Key' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'Accept' => 'application/json'], 'multipart' => $multipart]);
echo $response->getBody();

Source: View the sample on GitHub

Breaking Down the Code

The sample uses Composer to load the Guzzle HTTP client and related utilities. When using this example outside the pdfRest API samples repository, install Guzzle with composer require guzzlehttp/guzzle.

require 'vendor/autoload.php';

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Utils;

The Client class sends the HTTP request, while Utils::tryFopen opens the local Markdown and image files for the multipart form.

$apiUrl = "https://api.pdfrest.com";
//$apiUrl = "https://eu-api.pdfrest.com";

The API URL selects the US-based pdfRest service by default. An EU endpoint is included as a commented alternative when that service region is appropriate for your workflow.

$inputPath = '/path/to/sample.md';
$imagePath = '/path/to/logo.png';
$options = json_decode('{"title":"Structured Content Sample", ... }', true);

These values identify the Markdown source, local image file, and structured-text conversion options. The API determines that the source is Markdown from the uploaded file extension, so the options JSON does not need an input_format property.

The options array becomes the structured_text_options form field. It sets the PDF title and language, enables tagged output, configures the page, and applies typography and table styling. The table settings control relative column widths, repeated headers, borders, colors, padding, and alternating row fills for Markdown tables.

The markdown.image_sources configuration maps the Markdown image target sample-logo to the first uploaded image, represented by "upload_index": 0. The Markdown source should contain the same target, such as ![Company logo](sample-logo). The image_alt_text value supplies alternate text, while missing_image_alt_text is set to fail so that conversion stops if a meaningful image lacks alternate text.

$multipart = [
  ['name' => 'file', 'contents' => Utils::tryFopen($inputPath, 'r'), 'filename' => basename($inputPath)],
  ['name' => 'image_files', 'contents' => Utils::tryFopen($imagePath, 'r'), 'filename' => basename($imagePath)],
  ['name' => 'structured_text_options', 'contents' => json_encode($options)],
  ['name' => 'output', 'contents' => 'pdf_from_markdown'],
];

The multipart array includes the Markdown source as file, the local image as image_files, and the JSON configuration as structured_text_options. The uploaded image is available to the Markdown conversion through its zero-based upload index. The output field sets the output filename for the generated PDF.

$response = (new Client())->post($apiUrl . '/pdf', ['headers' => ['Api-Key' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', 'Accept' => 'application/json'], 'multipart' => $multipart]);
echo $response->getBody();

The request sends the multipart data to /pdf with the pdfRest API key and requests a JSON response. Replace the placeholder key with your own pdfRest API key. The response body contains the generated PDF resource details and download URL.

Beyond the Tutorial

This example shows how a PHP application can create a polished, tagged PDF from Markdown while controlling document presentation and resolving a local image in the same request. Tagged output adds logical document structure that can support accessibility and downstream processing, but it does not by itself guarantee conformance with a specific accessibility standard.

PHP implementations can keep the request compact by retaining only the Markdown presentation and asset settings their documents require. Explore those combinations in API Lab, and verify the full contract in the Convert to PDF API documentation.

Generate a self-service API Key now!
Create your FREE API Key to start processing PDFs in seconds, only possible with pdfRest.