So we all know that you should always, not only in PHP, separate code from content/design/html. (I have seen people that say the opposite here today)
I mean, you don't want one of these in bigger projects, do you?
<?php
echo '<div id="blah"><b>'
. $username . '</b>'
. $stuff . '<more HTML mixed with PHP...>';
?>
But: What is a good approach to separate code from content?
I have been using a simple template system that replaces wildcards in templates mostly.
e.g:
<div id="blah"><b>%USERNAME%</b>%STUFF% <...>
(located in a single file)
Later you can just call a function similar to GetTemplate( 'myTemplate', array ( 'USERNAME' => 'Stranger' ) );
Finally, the questions:
Is this a good way of separating code and content?
How do you do that when not working with a framework?
Is there a better way?
you should realize that PHP itself is a templating language. your
<div id="blah"><b>%USERNAME%</b>%STUFF% <...>
differs from
<div id="blah"><b><?php echo $USERNAME; ?></b><?php echo $STUFF; ?> <...>
only very superficially. granted, PHP is quite stupid with its NOTICEs and WARNINGs instead of exceptions (a point Python has over PHP), and your custom implementation may more easily allow you to e. g. throw instead of producing a fatal error (oh the joys of Smarty) if putting logic into a template somewhere turns out to be the lesser of two evils (loops). you may want to throw if the template mentions an undefined variable (PHP would issue a NOTICE), etc.
Im not fan ov additional templating languages (that replace wildcards) instead i like to keep my templates pure php so my vertion of what you have done would be:
<div id="blah"><b><?php echo $username ?></b><?php echo $stuff ?><...>
echo GetTemplate( 'myTemplate.php', array ( 'username' => 'Stranger', 'stuff' => 'Stuff' ) );
function GetTemplate($templatePath, array $vars = array())
{
extract($vars);
ob_start();
include($templatePath);
return ob_get_clean();
}
I alos combine this with helper functions/object->methods as well for example:
<?php echo link_to($name, $url); ?>
function link_to($name, $url, array $attributes = array())
{
$attributes['href'] = urlencode($url);
foreach($attributes as $attrib => $value)
{
$attributes[$attrib] = $attrib."=\"$value\"";
}
return sprintf('<a %s>%s</a>', implode(" ",$attributes), $name);
}
I generally apply helpers like these to commonly used tags/structures as well as having a general purpose html tag one that looks something like content_tag($tag, $content, $attributes); This helps me avoid a php echo for tons of attributes for random tags. I obviously dont use it for every html tag i use only for ones where it makes for better readability than a ton of echos.
As far as templating engines go i dont really see the benefit as php is templating language. As far as non-programmers/coders they have to leanr the syntax for a loop and a variable any how so i dont see how changing it to wildcards or the {} syntax of smarty adds anything.
There is a tried-and-true Templating Engine for PHP called Smarty. It isn't part of a massive framework, which is a huge plus for me. Smarty supports caching and has other performance boosts over traditional find/replace templating due to it's "compilation" of template files.
Big projects like, phpBB work using templates. Its slightly more complicated as they also allow for (for)lists, including other templates and other advanced features. You definitely want to separate code and content.
As a bonus this allows non programmers to make your html.
The approach of the Zend Framework which uses PHP as the template language (which does not add an extra parsing overhead) seems like a good apporach
Another way I really like is the approach used by limonade framework which uses ob_start() and includes to actually handle the templates
Related
What is the faster way to output html in PHP that contains PHP variables?
Version A:
<div id="example"><?php echo $var; ?></div>
... much more like this
or
Version B:
$html = array();
$html[] = '<div id ="example">';
$html[] = &$var;
$html[] = '</div>';
$html[] = '... much more like this';
echo implode( '', $html );
PHP - Hypertext Pre Processor
In fact, PHP is a templating engine itself. In any case variant A is better, but such code isn't the best solution for bigger projects. Try looking on MVC design pattern, which will help you separate database/business logic from the representation part of your application. Using an template engine (like Twig, Smarty, Blitz etc.) will help you achieve this too.
In this case it is faster to mix html and php. Version B, will essentially hold a big array in memory, and in the end loop through all the elements. So it will be slower, than just print/echo the data right away. Either way, I won't recommend either approach. I will suggest using a template engine and provide it with data, instead of mixing php and html, this way you can keep markup and logic completely separate. This is often done as a part of a MVC pattern as #Wrong described.
I was always curious, is there any significant advantage or disadvantage of writing php inside html or vice versa
example:
echo '<ul>'
foreach ($items as $item)
{
echo "<li>$item</li>";
}
echo '</ul>
As opposed to:
<ul>
<? foreach($items as $item): ?>
<li>$item</li>
<? endforeach; ?>
</ul>
Since these essentially generate the same thing, when would you actually use one over the other?
Functionally they are the exact same and won't have an appreciable affect on performance, if any. It comes down to personal preference and readability - if one is clearer than the other and will be easier for others (or the future you) to understand, go with that one.
I personally find it better to use the latter if you actually have PHP in a mostly HTML file. The clear opening/closing tags match up visually with HTML easier. I find it can be hard to line up curly braces visually.
As an example, in the case of a MVC framework I would use the first way of outputting things in a controller or model context, while the second way in my view files. Some templating languages like smarty have similar looking constructs.
ie:
{ if [condition] }
{ /if }
The first one echoes meaningless strings from the IDE's point of view, whereas the latter one is a mix of HTML and PHP and will be handled properly by your editor. In other words, it's better to actually separate HTML from PHP as it allows your editor to parse HTML and provide some usefull features like syntax validation or autoclosing of HTML tags.
basically php is a server side scripting and html is client side scripting. So if it is php inside html then it generates faster response and you can format a better view. However for some scenario you might have to consider the other case for developing.
Is there an standard output library that "knows" that php outputs to html?
For instance:
var_dump - this should be wrapped in <pre> or maybe in a table if the variable is an array
a version of echo that adds a "<br/>\n" in the end
Somewhere in the middle of PHPcode I want to add an H3 title:
.
?><h3><?= $title ?></h3><?
Out of php and then back in. I'd rather write:
tag_wrap($title, 'h3');
or
h3($title);
Obviously I can write a library myself, but I would prefer to use a conventional way if there is one.
Edit
3 Might not be a good example - I don't get much for using alternative syntax and I could have made it shorter.
1 and 2 are useful for debugging and quick testing.
I doubt that anyone would murder me for using some high-level html emitting functions of my own making when it saves a lot of writing.
In regards to #1, try xdebug's var_dump override, if you control your server and can install PHP extensions. The remote debugger and performance tools provided by xdebug are great additions to your arsenal. If you're looking only for pure PHP code, consider Kint or dBug to supplement var_dump.
In regards to #2 and #3, you don't need to do this. Rather, you probably shouldn't do this.
PHP makes a fine HTML templating language. Trying to create functions to emit HTML is going to lead you down a horrible road of basically implementing the DOM in a horribly awkward and backwards way. Considering how horribly awkward the DOM already is, that'll be quite an accomplishment. The future maintainers of your code are going to want to murder you for it.
There is no shame in escaping out of PHP to emit large blocks of HTML. Escaping out to emit a single tag, though, is completely silly. Don't do that, and don't create functions that do that. There are better ways.
First, don't forget that print and echo aren't functions, they're built in to the language parser. Because they're special snowflakes, they can take a list without parens. This can make some awkward HTML construction far less awkward. For example:
echo '<select name="', htmlspecialchars($select_name), '</select>';
foreach($list as $key => $value) {
echo '<option value="',
htmlspecialchars($key),
'">',
htmlspecialchars($value),
'</option>'
}
echo '</select>';
Next, PHP supports heredocs, a method of creating a double-quoted string without the double-quotes:
$snippet = <<<HERE
<h1>$heading</h1>
<p>
<span class="aside">$aside_content</span>
$actual_content
</p>
HERE;
With these two tools in your arsenal, you may find yourself breaking out of PHP far less frequently.
While there is a case for helper functions (there are only so many ways you can build a <select>, for example), you want to use these carefully and create them to reduce copy and paste, not simply to create them. The people that will be taking care of the code you're writing five years from now will appreciate you for it.
You should use a php template engine and just separate the entire presentation and logic. It make no sense for a educated programmer to try to create a library like that.
This is the most optimal way of dealing with a multilingual website I can think of, right now (not sure) which doesn't involve gettext, zend_translate or any php plugin or framework.
I think its pretty straight forward: I have 3 languages and I write their "content" in different files (in form of arrays), and later, I call that content to my index.php like you can appreciate in the following picture:
alt text http://img31.imageshack.us/img31/1471/codew.png
I just started with php and I would like to know if I'm breaking php good practices, if the code is vulnerable to XSS attack or if I'm writing more code than necessary.
EDIT: I posted a picture so that you can see the files tree (I'm not being lazy)
EDIT2: I'm using Vim with the theme ir_black and NERDTree.
Looks all right to me, although I personally prefer creating and using a dictionary helper function:
<?php echo dictionary("showcase_li2"); ?>
that would enable you to easily switch methods later, and gives you generally more control over your dictionary. Also with an array, you will have the problem of scope - you will have to import it into every function using global $language; very annoying.
You will probably also reach the point when you have to insert values into an internationalized string:
You have %1 votes left in the next %2 hours.
Sie haben %1 stimmen übrig für die nächsten %2 stunden.
Sinulla on %1 ääntä jäljellä seuraavan %2 tunnin ajassa.
that is something a helper function can be very useful for:
<?php echo dictionary("xyz", $value1, $value2 ); ?>
$value1 and $value2 would be inserted into %1 and %2 in the dictionary string.
Such a helper function can easily be built with an unlimited number of parameters using func_get_args().
It's OK generally. For instance, punBB's localization works this way. It is very fast. Faster than calling a function or an object's method or property. But I see a problem with this approach, since it doesn't support language fallbacks easily. I mean, if you don't have a string for Chinese, let it be displayed in English.
This problem is topical when you upgrade your system and you don't have time to translate everything in every language.
I'd better use something like
lang.en.php
$langs['en'] = array(
...
);
lang.cn.php
$langs['cn'] = array(
...
);
[prepend].php (some common lib)
define('DEFAULT_LANG', 'en');
include_once('lang.' . DEFAULT_LANG '.php');
include_once('lang.' . $user->lang . '.php');
$lang = array_merge($langs[DEFAULT_LANG], $langs[$user->lang]);
Looks all right to me also, but:
Seems that you have localization for multiple modules/sites, so why not break it down to multidimensional array?
$localization = array(
'module' => (object)array(
'heading' => 'oh, no!',
'perex' => 'oh, yes!'
)
);
I personally like to creat stdClass out of arrays with
$localization = (object)$localization;
so you can use
$localization->module->heading;
:) my 2 cents
The only way that this could be xss is if you have register_globals=On and you don't set $lang['showcase_lil'] or other $lang's. But I don't think you have to worry about this. So I think your in the clear.
as an xss test:
http://127.0.0.1/whatever.php?lang[showcase_lil]=alert(/xss/)
Wouldn't it have been better to post code and briefly explain this issue to us?
Anyway, putting each language in its own file and loading it through some sort of language component seems okay. I'd prefer using some sort of gettext, but this is okay too, I guess.
You should make a function for calling the language keys rather than relying on an array, something like
<?php echo lang('yourKey'); ?>
One thing to watch for is interpolation; that's really the only place XSS could sneak in if your server settings are sensible. If you at any point need to do something along the lines of translating "$project->name has $project->member_count members", you'll have to make sure you escape all HTML that goes in there.
But other than that, you should be fine.
Whats the best way to create my own template engine using php, to transfer html templates into actual websites, and replacing the placeholders with the actual data... well, let me solve my own question...
class Template{
$private $output = '';
public function Load_Template($template){
ob_start();
include($template);
$this->output = ob_get_clean();
}
public function Replace($data){
$this->output = str_replace(array_keys($data), array_values($data), $this->output);
}
public function Display($add_footer = true){
echo $this->output;
}
}
This would work for a simple Template like...
<div>{username}</div>
But what would be the best way to do it with loops in my template.
Lets say something like
<ul>
<li>{username}</li>//Loop this line for each user
</ul>
Also, I dont want to use a third party engine like smarty, I would just like to know how to do it myself. Thank you
How about use php itself?
<div><?php echo $username ?></div>
<ul>
<?php foreach($users as $user): ?>
<li><?php echo $user->username ?></li>
<?php endforeach ?>
</ul>
*note: Funky endforeach syntax explained here.
Honestly, if I had to whip up my own template engine in PHP, I'd just use PHP. Just restrict yourself to only using variable interpolation and loops within the "templates".
Writing your own template engine is a tricky thing. You're inventing an entirely new language, after all, albeit a simple one. For it to be very powerful (i.e., beyond simple string replacement), you'd probably have to write an actual stack-based parser rather than rely on str_replace.
You could do this with regular expressions, much as you could parse HTML with regular expressions, but it won't be very reliable, easy to read, easy to debug, or easy to extend.
You mention that you don't want to use a third-party engine like Smarty, but you are basically setting out to do the exact same thing that Smarty is doing.
Something that people often overlook when talking about templating in PHP is that PHP is a templating language. There's no reason you can't just use regular old PHP inside your templates. In fact, that's what it was originally designed for.
If you really want to build your own templating engine, then you're going to have to sit down and design a syntax for looping and whatever other templating structures you'll want to use. Something like [do 5 times] { loop code }. Make up whatever you want. Then you'll have to parse it with PHP, and modify the template to replace it with the looped structure.
It's a big job... using normal PHP would be much easier.
Well, most of the answer to your question is preg_replace_callback().
I agree with everyone in this discussion - I have never understood the use of proprietary languages for templating in PHP - you know PHP so just use that.
If you are disciplined (e.g. follow MVC architectural pattern) in keeping a clear difference between PHP scripts that do things, and PHP that display things, there won't be any problems.
A couple of ways that can help are calling your PHP template files .phtml, and using alternative PHP syntax which is a little easier to maintain in templateswhich contain both HTML and PHP:
<?php if ( $a == $b ) : ?>
<strong>True</strong>
<?php else: ?>
<strong>False</strong>
<?php endif; ?>