smnandre / pandoc
Pandoc PHP - Document Converter for Mardown, HTML, Latex, PDF, RST
Fund package maintenance!
smnandre
Requires
- php: ^8.3
- psr/log: ^2.0 || ^3.0
- symfony/process: ^7.3 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.82
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^12.3
- symfony/filesystem: ^7.3 || ^8.0
README
PHP Pandoc Document Converter. Typed, tested & mockable.
Why Pandoc PHP
Replace shell commands with type-safe objects and structured error handling.
$html = Pandoc::convert('# Hello', 'html'); // Static facade for quick tasks $html = new Converter() // ConverterInterface ->file('document.txt') ->to('html') ->getContent(); // Traceable, testable, mockable Pandoc::file('reporting.md') // Options, variables, metadata ->option('toc', true) ->metadata('author', 'John Doe') ->variable('title', 'My Document')
- 60+ formats - Markdown, HTML, PDF, DOCX, LaTeX, RST, EPUB, RTF, and more
- Dual API Design - Static
Pandoc
facade for quick tasks,ConverterInterface
for dependency injection - Smart Format Detection - Auto-detects input/output formats from file extensions and content patterns
- Unit Testing -
MockConverter
for tests without Pandoc installation, real Pandoc for integration - Production Ready - PHPStan level 10, full test coverage, rich error handling
Installation
Requirements
- PHP 8.3 or higher
- Pandoc (see below)
Pandoc PHP
Install via Composer.
composer require smnandre/pandoc
Pandoc Binary
Install Pandoc first using your system package manager.
# Ubuntu/Debian sudo apt-get install pandoc # macOS brew install pandoc
Usage
Input
Specify source content using string input, file paths, or explicit format overrides when automatic detection fails.
// String content with automatic format detection $converter = Pandoc::content('# Hello World'); // File input with extension-based format detection $converter = Pandoc::file('document.md'); // Override automatic format detection when needed $converter = Pandoc::content($data)->from('markdown'); // Check format compatibility if (Pandoc::supports('markdown', 'pdf')) { // Proceed with conversion }
Output
Control conversion targets through format specification, file destinations, or directory outputs.
// Get content as string $htmlContent = Pandoc::file('doc.md')->to('html')->convert()->getContent(); // Save to specific file path Pandoc::file('doc.md')->to('pdf')->output('reports/final-report.pdf')->convert(); // Save to directory (filename inferred from input) Pandoc::file('doc.md')->to('pdf')->output('reports/')->convert(); // Save to file (format inferred from extension) Pandoc::file('doc.md')->output('documentation.html')->convert();
Options
Configure Pandoc behavior using individual options, batch option arrays, template variables, or document metadata.
// Individual option configuration $converter->option('toc', true)->option('standalone', true); // Batch option setting $converter->options(['toc' => true, 'number-sections' => true]); // Template variables and metadata $converter->variable('title', 'Report')->variable('grade', 'A+'); // Document metadata for publishing workflows $converter->metadata('author', 'The Team')->metadata('date', '2025-01-01');
Configuration
Framework integration and custom binary paths for non-standard installations.
// Custom binary path configuration $binary = PandocBinary::fromPath('/opt/pandoc/bin/pandoc'); Pandoc::setDefaultBinary($binary); // Check supported formats Pandoc::getInputFormats(); // Get all supported input formats Pandoc::getOutputFormats(); // Get all supported output formats Pandoc::supports('markdown', 'html'); // Check if conversion is supported
Test
Unit testing with MockConverter
records method calls without requiring Pandoc installation. Integration testing
verifies actual Pandoc functionality.
// Unit testing with MockConverter class DocumentServiceTest extends TestCase { public function testGenerateReport(): void { $mock = new MockConverter(); $service = new DocumentService($mock); $service->createReport('# Test'); // Verify calls without external dependencies $calls = $mock->getCalls(); $this->assertCount(1, $calls); $this->assertEquals('# Test', $calls[0]['inputContent']); $this->assertEquals('html', $calls[0]['outputFormat']); $this->assertTrue($calls[0]['options']['standalone']); } } // Integration testing with real Pandoc class PandocIntegrationTest extends TestCase { public function testConversion(): void { if (!Pandoc::isInstalled()) { $this->markTestSkipped('Pandoc not installed'); } $html = Pandoc::content('# Test')->to('html')->convert()->getContent(); $this->assertStringContainsString('<h1>Test</h1>', $html); } }
Examples
Convert multiple Markdown files to HTML
$posts = glob('content/*.md'); foreach ($posts as $post) { Pandoc::convertFile($post, 'public/'.basename($post, '.md').'.html'); }
Generate academic paper with citations and formatting
$result = Pandoc::file('manuscript.md') ->to('pdf') ->option('toc', true) ->option('bibliography', 'references.bib') ->variable('title', 'Research Paper') ->variable('author', 'The Team') ->convert();
Handle document conversion in web applications with error handling
class DocumentController { public function convert(Request $request): Response { $result = $this->converter->content($request->getContent())->to('html')->convert(); if (!$result->isSuccess()) { throw new BadRequestHttpException($result->getError()); } return new Response($result->getContent()); } }
Troubleshooting
Pandoc not found
This error occurs when the library cannot find the pandoc executable in your system PATH.
// Solution: Specify custom binary path use Pandoc\PandocBinary; $binary = PandocBinary::fromPath('/opt/pandoc/bin/pandoc'); Pandoc::setDefaultBinary($binary);
Format detection
Automatic format detection fails when file extensions are missing or content format is ambiguous.
// Solution: Explicitly specify input and output formats $result = Pandoc::content($unknownContent) ->from('markdown') // Override input format detection ->to('html') // Ensure output format is clear ->convert();
Conversion errors
Pandoc conversion failures provide detailed error messages through the result object.
$result = Pandoc::file('input.md')->to('pdf')->convert(); if (!$result->isSuccess()) { // Access detailed error information from Pandoc $errorMessage = $result->getError(); echo "Conversion failed: " . $errorMessage; }
Contributing
Contributions are welcome! Please start by creating an issue to discuss your changes.
Credits
Built on Pandoc by John MacFarlane.
Created and maintained by Simon André.
Tip
This library is developed and maintained by a single developer in their free time.
To ensure continued maintenance and improvements, consider sponsoring development.
License
MIT License - see LICENSE file for details.