Smarty 默認從文件系統讀取模板。通過自定義資源插件,可實現從數據庫、Redis、遠程 API 等任意數據源加載模板,滿足動態模板、多租戶、版本控制等高級需求。
註冊資源時需提供四個函數,對應模板生命週期的關鍵節點:
| 函數 | 職責 | 參數 | 返回值 |
|---|---|---|---|
| get_template | 讀取模板源碼 | $tpl_name, &$tpl_source, &$smarty | true/false |
| get_timestamp | 獲取模板最後修改時間戳(用於緩存判斷) | $tpl_name, &$tpl_timestamp, &$smarty | true/false |
| get_secure | 安全性檢查(如防止目錄遍歷) | $tpl_name, &$smarty | true/false |
| get_trusted | 可信檢查({include} 等標簽調用時) | $tpl_name, &$smarty | true/false |
<?php
// 假設已有資料庫封裝類 SQL
function db_get_template($tpl_name, &$tpl_source, &$smarty_obj) {
$sql = new SQL;
$sql->query("SELECT tpl_source FROM my_templates WHERE tpl_name = '$tpl_name'");
if ($sql->num_rows) {
$tpl_source = $sql->record['tpl_source'];
return true;
}
return false;
}
function db_get_timestamp($tpl_name, &$tpl_timestamp, &$smarty_obj) {
$sql = new SQL;
$sql->query("SELECT tpl_timestamp FROM my_templates WHERE tpl_name = '$tpl_name'");
if ($sql->num_rows) {
$tpl_timestamp = (int)$sql->record['tpl_timestamp'];
return true;
}
return false;
}
function db_get_secure($tpl_name, &$smarty_obj) {
// 簡單示例:僅允許字母數字下劃線
return preg_match('/^[a-zA-Z0-9_]+$/', $tpl_name);
}
function db_get_trusted($tpl_name, &$smarty_obj) {
// 模板包含時不額外檢查
return true;
}
// 註冊資源名稱為 "db"
$smarty->register_resource("db", array(
"db_get_template",
"db_get_timestamp",
"db_get_secure",
"db_get_trusted"
));
// 使用:資源名:模板名
$smarty->display("db:index.tpl");
?>
get_template 中引入 Redis/Memcached 緩存模板內容,減少 DB 查詢。version 字段,get_timestamp 返回版本號或更新時間,配合 Smarty 編譯緩存實現熱更新。tpl_name 可設計為 tenant_id:template_name 格式,在回調中解析租戶 ID。db)必須唯一,避免與內置 file、eval 等衝突。get_timestamp 返回的時間戳必須為整數,Smarty 据此判斷是否重新編譯。get_secure 應嚴格校驗模板名,防止路徑遍歷或注入攻擊。{php} 標簽,需確保 security_policy 允許或自行過濾。