The first two pages used auto-encoding without explaining it. This page covers how it works, how to output trusted HTML like WYSIWYG editor content, and the row helpers that control loop layout.
Contents:
- How Auto-Encoding Works
- Where Encoding Ends
- Trusted HTML: rawHtml()
- Loop Layout: isFirst(), isLast(), position()
- Keys Are Never Encoded
A field holds your original value, exactly as it came from the database,
and produces the HTML-encoded version only at the moment you output it.
That means what you display is safe, the original is still there when you
need it with value(), and no time is spent encoding fields you never show:
use Itools\SmartArray\SmartArrayHtml;
$article = SmartArrayHtml::new(['title' => 'Tips & Tricks']);
echo $article->title; // Tips & Tricks
echo $article->title->value(); // Tips & Tricks (the original value, for logic)That covers every string context, so there's no encoding call to remember and no way to forget one. The rest of this page is about the places where you want something other than the default.
HTML encoding makes values safe as HTML text and inside quoted attribute values. A few contexts need more than encoding:
- User-supplied link URLs: encoding doesn't stop a stored
javascript:alert(1)from running as an href; check the scheme before outputting a URL that came from user input. - Inside
<script>blocks: usejsonEncode()to pass values to JavaScript; encoded text is not valid JS. - URL query strings: use
urlEncode()so&and=inside values don't split parameters.
Some fields hold real HTML that's meant to render, most often WYSIWYG
editor content. Encoding would show the tags as text, so output those
fields with rawHtml():
$article = SmartArrayHtml::new(['body' => '<p>Use <b>bold</b> for emphasis.</p>']);
echo $article->body; // <p>Use <b>bold</b> for emphasis.</p>
echo $article->body->rawHtml(); // <p>Use <b>bold</b> for emphasis.</p>Use it for content you trust, like your own CMS's editor fields; visitor input stays on the default encoded path.
More output helpers (nl2br(), appendHtml(), wrapHtml(),
urlEncode(), jsonEncode()) are on SmartString's
Encoding and HTML
page.
Every row knows where it sits in its collection, which handles the layout decisions inside loops: separators between items, wrappers around the whole list, special treatment for the first few rows.
| Method | Returns |
|---|---|
isFirst() |
true for the first row |
isLast() |
true for the last row |
position() |
the row's position, counting from 1 |
Separators go after every row except the last:
$tags = SmartArrayHtml::new([['name' => 'PHP'], ['name' => 'MySQL'], ['name' => 'Tutorials']]);
foreach ($tags as $tag) {
echo $tag->name;
if (!$tag->isLast()) {
echo ', ';
}
}
// PHP, MySQL, TutorialsAnd position() singles out rows by rank, like featuring the newest
articles in a list:
$articles = SmartArrayHtml::new([
['title' => 'Fall Fair Sept 20-21'],
['title' => 'New Trail Maps'],
['title' => 'Road Closures on Main St'],
['title' => 'Library Summer Hours'],
]);
foreach ($articles as $article) {
$class = $article->position() <= 3 ? 'featured' : 'normal';
echo "<li class='$class'>$article->title</li>\n";
}
// <li class='featured'>Fall Fair Sept 20-21</li>
// <li class='featured'>New Trail Maps</li>
// <li class='featured'>Road Closures on Main St</li>
// <li class='normal'>Library Summer Hours</li>Auto-encoding covers values, not keys: foreach hands keys back as plain
values, so they stay usable for lookups and comparisons. That matters when
the keys came from user data, like grouping by a user-entered field and
echoing the group names:
$users = SmartArrayHtml::new([
['name' => 'Jean', 'city' => "St. John's"],
['name' => 'Tom', 'city' => 'Ottawa'],
]);
$usersByCity = $users->groupBy('city');
// WRONG - foreach keys are plain values, so user-entered text lands in the page unencoded
foreach ($usersByCity as $city => $residents) {
echo "<option>$city</option>\n"; // <option>St. John's</option>
}
// RIGHT - keys() hands the keys back as fields, so they encode like any other value
foreach ($usersByCity->keys() as $city) {
echo "<option>$city</option>\n"; // <option>St. John's</option>
}