תבניות Smarty

איך תבניות .tpl מעובדות ב-WizzoCMS (Smarty 5): $this->view, FILES::html_template, המשתנים שזמינים, התוספים המובנים, כתיבת תוסף משלכם, ומלכודות האבטחה והמטמון.

⏱ 6 דק' קריאה 1120 מילים ערוך דף זה ב-GitHub

כל HTML של האתר עובר דרך תבניות Smarty: ה-theme, תבניות הבקרים, ואפילו פאנלי הניהול. בעמוד הזה: הדרכים לעבד תבנית, מה הליבה מגדירה ב-Smarty, איזה תחביר ותוספים זמינים, איך כותבים תוסף, ואילו מלכודות כדאי להכיר לפני שמעבדים ב-Smarty תוכן שבא ממשתמש.

עיבוד תבנית#

קריאהפירוט
$this->view($tpl, $vars = [])מתוך בקר: מעבד את application/views/<tpl>.tpl ומחזיר HTML. $tpl בלי סיומת, למשל "news/list"
$this->system_view($tpl, $vars = [])כמו view, אבל מתוך core_path/views/ (לבקרים של הליבה ופאנלים)
FILES::html_template($tmpl_file, $varsArr = [], $settings = [])הפונקציה שמאחורי השתיים: מקבלת נתיב מלא מקובץ, מחזירה HTML
FILES::string_template($tmpl_string, $varsArr = [], $settings = [])מעבדת מחרוזת כתבנית (ראו אזהרה)
class news extends bgl_controller
{
	public function index()
	{
		$items = DB::query("news", ["active" => 1], "id DESC", "", "0,10")->get_all();

		return $this->view("news/list", [
			"items" => $items,
			"title" => "חדשות",
		]);
	}
}
{* application/views/news/list.tpl *}
<h1>{$title|escape}</h1>
<ul>
{foreach $items as $item}
	<li><a href="news/{$item.id}">{$item.title|escape}</a></li>
{foreachelse}
	<li>אין חדשות</li>
{/foreach}
</ul>

$settings של html_template מכיל שני מפתחות:

מפתחברירת מחדלפירוט
use_smartynull (לפי CONFIG::$use_smarty)דריסה למקרה אחד: true, false או "plain"
cachefalseמדליק את המטמון של Smarty ל-120 שניות (ראו מלכודות)

מה הליבה מגדירה ב-Smarty#

הליבה משתמשת ב-Smarty 5.8 (api/core/addons/Smarty) ויוצרת מופע חדש לכל קריאה:

הגדרהערך
תיקיית התבניות./, כלומר שורש האתר. נתיב ב-{include} נמדד משם: {include file="application/views/partials/menu.tpl"}
תיקיית קומפילציהcache/Smarty/templates_c/ (עם תתי-תיקיות), יחסית לשורש האתר
תיקיית מטמוןcache/Smarty/cache/
משתנים שמוקצים תמידGLOBALS (כל MISC::$GLOBALS) ובנוסף כל מפתחות $vars
escape אוטומטיכבוי (escape_html בברירת המחדל של Smarty 5, שהיא false)
מטמון של Smartyכבוי (caching = 0), אלא אם ביקשתם cache
אזהרה
אין escape אוטומטי. {$title} מדפיס את הערך כמות שהוא, ולכן ערך שהגיע ממשתמש או מבסיס הנתונים וכולל <script> יתבצע בדפדפן. תמיד {$value|escape} בטקסט, ו-{$value|escape:'url'} בפרמטר של כתובת. nofilter, שמופיע בדוגמאות ({$content nofilter}), אינו משנה כאן כלום כי אין מה לבטל, אבל הוא מסמן בבירור שהערך הוא HTML מכוון (XSS).

תחביר שימושי#

התחביר הוא Smarty 5 סטנדרטי, וכל ה-תיעוד של Smarty תקף. הקצרים הנפוצים:

{$user.name|escape}                  {* משתנה ומודיפייר *}
{if $items|count > 0} ... {else} ... {/if}
{foreach $items as $k => $item} ... {/foreach}
{include file="application/views/partials/card.tpl" item=$item}
{$GLOBALS.body_class}                {* MISC::$GLOBALS *}
{$smarty.now|date_format:"%Y"}
{literal} function(){ return {a: 1}; } {/literal}   {* סוגריים מסולסלים של JS/CSS *}

סוגריים מסולסלים של JS ו-CSS בתוך תבנית חייבים להיות בתוך {literal}...{/literal} (או עם רווח אחרי {), אחרת Smarty ינסה לפרש אותם.

מודיפיירים: כל פונקציית PHP#

ההרחבה של הליבה מאפשרת להשתמש כמודיפייר בכל פונקציית PHP בשמה, בלי להירשם:

{$price|number_format:2}
{$text|strtoupper}
{$name|trim}

זה נוח, אבל זו גם הסיבה לאזהרה על string_template למטה.

תוספים מובנים#

חמש פונקציות תבנית מגיעות עם הליבה (api/core/addons/Smarty/libs/plugins/):

תגפרמטריםמה עושה
{crm_storage_url id=…}idכתובת מלאה של קובץ מהאחסון (STORAGE::get_url)
{crm_storage_tumb id=… width=… height=…}id, width, heightכתובת תמונה ממוזערת (STORAGE::get_thumb)
{crm_live_edit id=… table=… field=… tbType=…}id, table, field, tbType (ברירת מחדל conf)מדפיס תכונות contenteditable שמאפשרות עריכה מתוך העמוד, רק לאדמין מחובר ועם ?liveEdit=true בכתובת. לכל השאר מדפיס מחרוזת ריקה
{crm_get_banner type=… tag=…}type, tagבאנר מהמערכת, דורש application/models/m_banner.php באתר
{crm_get_google_banner name=… tag=…}name, tagבאנר Google, דורש application/models/m_google_ads.php באתר
<img src="{crm_storage_tumb id=$item.image width=400 height=300}" alt="{$item.title|escape}">
<h2 {crm_live_edit id=$item.id table="news" field="title"}>{$item.title|escape}</h2>

{crm_live_edit} נכתב בתוך התג הפותח, כי הוא מדפיס תכונות ולא אלמנט. הוא גם מוסיף את נכסי CKEditor לעמוד, אבל רק כשהתנאי מתקיים.

תוסף משלכם#

הליבה מחפשת תוספים בשתי תיקיות: core_path/Smarty/plugins (שאינה קיימת) ו-addons/Smarty/libs/plugins. שתיהן חלק מהליבה שמוחלפת בעדכון גרסה, ולכן לא שמים בהן קבצים. הדרך באתר היא להגדיר פונקציה גלובלית עם השם smarty_function_<name> (וגם smarty_block_<name>) בקובץ שנטען תמיד, למשל application/includes/smarty.php. ההרחבה בודקת function_exists על השם הזה בכל תג שהיא לא מכירה.

<?php
// application/includes/smarty.php
function smarty_function_price($params, $smarty)
{
	$amount = (float)($params["amount"] ?? 0);
	return number_format($amount, 2) . " ₪";
}
{price amount=$item.price}

התוסף מקבל את מערך הפרמטרים של התג ואת אובייקט ה-Smarty, ומחזיר מחרוזת שנכנסת כמו שהיא (בלי escape). אם הפונקציה מדפיסה ערך שבא ממשתמש, אתם אחראים לעשות לו htmlspecialchars.

מצבי CONFIG::$use_smarty#

ערךהתנהגות
true (ברירת המחדל)Smarty, כל מה שלמעלה
"plain"מחזיר את תוכן הקובץ כמות שהוא, בלי עיבוד
כל ערך אחרמצב eval ישן: הקובץ נהפך למחרוזת PHP ו-eval מפענח אותה
שימו לב

מצב ה-eval (כל ערך שאינו true ואינו "plain") מריץ קוד PHP מתוך קובץ התבנית ואינו בטוח (ממצא CORE-06). השאירו use_smarty על true. הסיבה היחידה לשנות היא אתר ישן מאוד.

מלכודות#

אזהרה
לא מעבדים ב-string_template או ב-Smarty תוכן שמשתמש יכול להשפיע עליו. אין enableSecurity ואין מדיניות מגבילה (ממצא CORE-43), ומודיפייר יכול להיות כל פונקציית PHP. תוכן ממשתמש או מעורך תוכן פנימי שמוזן ל-string_template יכול לקרוא לפונקציות שמריצות פקודות. תבניות שעוברות ב-Smarty צריכות להגיע מקבצי .tpl של הקוד, והתוכן הדינמי נכנס אליהן כמשתנה, לא כחלק מהתבנית.

שימו לב
מטמון Smarty. אם מעבירים ["cache" => true], הפלט נשמר ל-120 שניות (הערך קבוע בקוד), והקריאה לא מעבירה cache_id. פלט של תבנית שמקבלת משתנים שונים בכל קריאה (עמוד מוצר, משתמש) עלול לחזור זהה. להאטה אמיתית השתמשו ב-מטמון הפריטים ובמטמון העמודים ולא במטמון של Smarty.

הערה

תיקיות הקומפילציה והמטמון (cache/Smarty/...) יחסיות לתיקיית העבודה, שהיא שורש האתר בבקשת HTTP (ממצא CORE-43). בהרצה מ-CLI או מ-cron, ודאו שתיקיית העבודה היא שורש האתר, אחרת Smarty ינסה לכתוב למקום אחר.

ראו גם#

מצאתם טעות או חוסר? תקנו את הדף או פתחו Issue בריפו. התיעוד נכתב מתוך הקוד של ליבה 5.0.115.