dzentota / template-engine
A secure template engine with native PHP syntax and context-aware escaping
Requires
- php: ^8.1
- dzentota/template-variable: dev-main
- dzentota/typedvalue: dev-master
Requires (Dev)
- phpstan/phpstan: ^1.0
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.7
This package is auto-updated.
Last update: 2025-07-13 21:50:10 UTC
README
A secure template engine for PHP with native syntax and context-aware escaping, built on top of dzentota/template-variable
and dzentota/typedvalue
.
Features
🔒 Security First: Built following the AppSec Manifesto principles
- Context-aware automatic escaping (HTML, attributes, JavaScript, CSS, URLs)
- Protection against XSS attacks
- Secure by default configuration
- Template security auditing
🚀 Native PHP Syntax: Similar to bareui, uses familiar PHP syntax
- No custom template language to learn
- Full PHP power when needed
- Clean, readable templates
⚡ Performance:
- Optional template caching
- Optimized for production use
- Minimal overhead
🛡️ Developer Experience:
- Comprehensive error handling
- Debug mode for development
- Template includes and partials
- Global variables support
- Namespaced template directories
Installation
composer require dzentota/template-engine
Note: This package depends on development versions of dzentota/template-variable
and dzentota/typedvalue
. You may need to adjust your minimum-stability
setting in composer.json
to "dev"
or use --prefer-source
flag during installation.
Quick Start
<?php use Dzentota\TemplateEngine\TemplateEngine; // Initialize the engine $engine = new TemplateEngine([ 'auto_escape' => true, 'debug' => true ]); // Add template directory $engine->addPath(__DIR__ . '/templates'); // Render template with data echo $engine->render('welcome', [ 'title' => 'Hello World', 'user' => ['name' => 'John Doe'] ]);
Template (templates/welcome.php):
<!DOCTYPE html> <html> <head> <title><?= $title ?></title> </head> <body> <h1>Welcome, <?= $user['name'] ?>!</h1> </body> </html>
Security Features
Automatic Context-Aware Escaping
The template engine wraps all variables as TemplateVariable
instances, which provide automatic escaping through magic methods:
<?= $variable ?>
- Uses__toString()
for HTML context escaping<?= $variable('attr') ?>
- Uses__invoke('attr')
for attribute context escaping<?= $variable('js') ?>
- Uses__invoke('js')
for JavaScript context escaping
The template engine automatically escapes variables based on their output context:
<!-- HTML Context (default via __toString magic method) --> <p><?= $userInput ?></p> <!-- Attribute Context --> <input value="<?= $userInput('attr') ?>"> <!-- JavaScript Context --> <script>var data = <?= $userInput('js') ?>;</script> <!-- CSS Context --> <style>.class { color: <?= $userInput('css') ?>; }</style> <!-- URL Context --> <a href="<?= $userInput('url') ?>">Link</a> <!-- Raw Output (use with extreme caution) --> <div><?= $trustedContent('raw') ?></div>
XSS Protection
All variables are automatically escaped unless explicitly marked as raw:
$data = [ 'safe_text' => 'Hello World', 'unsafe_html' => '<script>alert("XSS")</script>' ]; // This is safe - script tags will be escaped echo $engine->render('template', $data);
Template:
<p><?= $unsafe_html ?></p> <!-- Output: <script>alert("XSS")</script> -->
Template Syntax
Variables
<!-- Escaped output (automatic via __toString) --> <?= $variable ?> <!-- Different contexts --> <?= $variable('attr') ?> <!-- For HTML attributes --> <?= $variable('js') ?> <!-- For JavaScript --> <?= $variable('css') ?> <!-- For CSS values --> <?= $variable('url') ?> <!-- For URLs --> <?= $variable('raw') ?> <!-- Raw/unescaped (use with caution) -->
Control Structures
Use native PHP syntax:
<!-- Conditionals --> <?php if ($user['is_admin']): ?> <p>Admin panel available</p> <?php endif; ?> <!-- Loops --> <?php foreach ($items as $item): ?> <div><?= $item['name'] ?></div> <?php endforeach; ?> <!-- Switch statements --> <?php switch ($user['role']): ?> <?php case 'admin': ?> <p>Administrator</p> <?php break; ?> <?php case 'user': ?> <p>Regular user</p> <?php break; ?> <?php endswitch; ?>
Template Includes
<!-- Include other templates --> <?= $include('partials/header', ['title' => 'Page Title']) ?> <!-- Content here --> <?= $include('partials/footer') ?>
Global Variables
// Set global variables $engine->addGlobal('app_name', 'My App'); $engine->addGlobal('version', '1.0.0'); // Use in templates <p><?= $app_name ?> v<?= $version ?></p>
Configuration
$engine = new TemplateEngine([ 'auto_escape' => true, // Enable automatic escaping 'strict_variables' => true, // Throw errors for undefined variables 'debug' => false, // Enable debug mode 'cache' => true, // Enable template caching 'cache_dir' => '/tmp/templates', // Cache directory 'default_context' => 'html', // Default escaping context 'file_extension' => '.php' // Template file extension ]);
Template Directories
Single Directory
$engine->addPath('/path/to/templates');
Multiple Namespaced Directories
$engine->addPath('/path/to/app/templates', 'app'); $engine->addPath('/path/to/admin/templates', 'admin'); // Use namespaced templates echo $engine->render('@admin/dashboard'); echo $engine->render('@app/welcome');
Security Auditing
The template engine includes security auditing capabilities:
use Dzentota\TemplateEngine\Security\SecurityManager; $security = new SecurityManager(); // Audit a template $templateSource = file_get_contents('template.php'); $audit = $security->auditTemplate($templateSource, 'template.php'); echo "Security Score: " . $audit['security_score'] . "/100\n"; foreach ($audit['issues'] as $issue) { echo "- " . $issue['message'] . " (Severity: " . $issue['severity'] . ")\n"; }
Advanced Usage
Custom Security Configuration
use Dzentota\TemplateEngine\Security\SecurityManager; $security = new SecurityManager([ 'strict_mode' => true, 'allow_php_functions' => false, 'max_template_size' => 1024 * 1024 ]); $engine = new TemplateEngine(['security_manager' => $security]);
Content Security Policy
$security = new SecurityManager(); $headers = $security->generateCSPHeaders(); foreach ($headers as $name => $value) { header("$name: $value"); }
Template Metadata
$template = $engine->load('welcome'); $metadata = $template->getMetadata(); echo "Template: " . $metadata['name'] . "\n"; echo "Size: " . $metadata['size'] . " bytes\n"; echo "Modified: " . date('Y-m-d H:i:s', $metadata['modified']) . "\n";
Error Handling
try { $output = $engine->render('template', $data); echo $output; } catch (RuntimeException $e) { // Template not found, rendering error, etc. error_log("Template error: " . $e->getMessage()); echo "Template error occurred"; } catch (InvalidArgumentException $e) { // Invalid configuration, variable names, etc. error_log("Configuration error: " . $e->getMessage()); }
Best Practices
1. Use TemplateVariable for Automatic Escaping
<!-- ✅ Good - automatic escaping via TemplateVariable --> <p><?= $userInput ?></p> <!-- ❌ Bad - raw PHP variable (bypasses TemplateVariable) --> <p><?= $_GET['user_input'] ?></p>
2. Use Context-Appropriate Escaping
<!-- ✅ Good --> <input value="<?= $value('attr') ?>"> <script>var data = <?= $data('js') ?>;</script> <!-- ❌ Bad --> <input value="<?= $value ?>"> <script>var data = "<?= $data ?>";</script>
3. Validate Template Security
// In development, audit your templates if ($developmentMode) { $security = new SecurityManager(); $audit = $security->auditTemplate($templateSource, $templateName); if ($audit['security_score'] < 80) { throw new Exception("Template security score too low: " . $audit['security_score']); } }
4. Use Template Caching in Production
$engine = new TemplateEngine([ 'cache' => true, 'cache_dir' => sys_get_temp_dir() . '/template_cache' ]);
Examples
See the examples/
directory for complete working examples:
basic_usage.php
- Basic template renderingtemplates/welcome.php
- Comprehensive template with security featurestemplates/partials/
- Template includes and partials
Security
This template engine is designed with security as a primary concern:
- XSS Prevention: All output is escaped by default
- Context Awareness: Different escaping for HTML, attributes, JS, CSS, URLs
- Directory Traversal Protection: Templates cannot access files outside designated directories
- Function Restrictions: Dangerous PHP functions are blocked in templates
- Security Auditing: Built-in tools to audit template security
Requirements
- PHP 8.1 or higher
dzentota/template-variable
(dev-main)dzentota/typedvalue
(dev-master)
License
MIT License - see LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Support
For issues and questions:
- GitHub Issues: Report a bug
- Security Issues: Email webtota@gmail.com