Custom stream wrapper with include or eval? - php

Overview
I'm currently writing a template engine. It even supports multiple "format"s. Currently it can parse .php files and .tpl (specific to this engine).
I'll give you a little example of both, just to give you an Idea.
template.php:
Name: <?php echo $this->h($name) ?>
Posts:
<?php foreach($posts as $post): ?>
- <?php echo $this->h($post->name) ?> (<?php echo count($post->comments) ?> comments)
<?php echo $this->render('post/shortpost', array('post' => $post)) ?>
<?php endforeach ?>
This is basicly just a standard PHP.
template.tpl
Name: {>$name}
Posts:
{foreach($posts as $post):}
- {>$post->name} ({=count($post->comments)} comments)
{=:render('post/shortpost', array('post' => $post))}
{endforeach}
This templating "language" simply gets translated into PHP above.
Comparission
eval()
Currently these template's are parsed using eval().
Pro
I don't have to change any code
Contra
when an error occurs in a template you only get a useless error message which doesn't
tell you in which file the error occurs and sometimes the line number is even wrong.
Security? Template files are only need to be readable?
It's difficult to debug the code.
Code is harder to understand
more .. ?
stream wrappers and include()
I recently read about stream wrappers in php. You even could create your own. A other solution than eval would be to create a custom stream wrapper for every template "format" and use include to parse the template.
This has the following (potential) flaws:
Pro
may solve the problems with showing the wrong file/line-number in error messages (has anyone experiences with this?)
you could handle the template file exactly how to want it to be handled. Full control.
Contra
allow_url_(fopen|include) has to be on?
it is slow? (is eval() slow too?)
no gain in security. include does basically the same thing as eval.
more ... ?
EDIT: cached parsed files and include()
A third option would to to parse the template to PHP code and cache them (as suggested by #Jen-YaKovalev).
Pro
includes caching
Contra
if an error occurs while including the rendered template and an error occurs
the error message doesn't point you to the correct file/eventually shows you
the wrong line number.
You need an extra tmp/ directory to save the parsed files. You need write
permissions for PHP/webserver. Would be more insecure because hackers
would append some malicious code easier.
EDIT: stream filters and include('php://filter')
lately found the following php.net pages:
php://filter: http://php.net/manual/en/wrappers.php.php
strea_filter_register http://fr2.php.net/manual/en/function.stream-filter-register.php
This would be an other possibility to solve this problem. Using include('php://filter/read=filtername/resource=file.php'), I could include a file which would first go through the filter filtername, before it gets executed.
Pro
doesn't need so much code as stream wrappers
Contra
not so much possibilities as with stream wrappers (caching?)
security?
speed?
Question
Have experiences using stream wrappers for parsing template files or similar?
Is there yet an other solution?
Are there more pro's and contras?
Which one would you recommend?

I think it's just a taste of one's coding-style, you'd better vote it or something.
I personnaly think eval is evil (in every language),
had bad experiences with include + php wrappers (even integrated ones*),
knowing all big(gish) template systems use compiling to a php file (smarty, twig), this it the one, i would use.
(*) In an earlier project we used a 1-line code (an empty class-extension) in a data-url wrapped include, and its performance was awful.

You certainly don't want to parse templates at every request on the production environment, it would be a waste of resources and consequently a slow and not a very smart approach, so I'd strongly suggest going with the cached parsed files and include() approach.

Related

PHP eval code and store the result into a variable

I have continued my voyage into creating a extremely simple template engine.
Because I wanted to add logic to my template I eventually got back to the point that I allowed PHP tags into my code which I enabled by evalling the code.
Maybe not the best solution but when looking at the WordPress templates I noticed that the idea itself may not be that bad.
But now there still is one small problem left.
And that is that I want to translate the generated code.
But it has been evalled already. Hence parsed.
I thought of solving this problem by using ob_get_contents().
But this brought one more question and in case of errors it shows a white screen. (memory usage etc.)
Plus it still did not take away the problem of eval that it parsed the contents when evalled.
In short the class logic is:
Loading template files
Adding the contents
Compiling the template
Eval the code (but unfortunately also displaying the code)
Translate the code so I can translate the code parsed by a PHP script
I would love something like:
$code = eval('?>'.$tpl.'<?php');
$code = translate($code);
WriteCache($code);
SetDocumentHeader();
echo $code;
Would anyone know how to achieve this?
Thanks in advance!
$code = eval($tpl);
Check this out.

How do I rewrite PHP code blocks before they are passed to the interpreter?

What I am trying to do is write a parser for PHP that interprets whitespace instead of brackets. I can do rewriting bit and output PHP, but what I'm not sure is how best to integrate this into an application.
In an ideal world, I imagine the best thing would be to put an include at the top of the file, which in turn rewrote all the code blocks that follow it into proper PHP syntax as they are passed to the interpreter, but I am not aware that blocks of code can be passed in this way.
Another alternative is to write it as a server extension, but I would prefer not to do this, as it makes it less accessible.
Is there an easy way to architect this?
There is a way to do this with Stream Wrappers.
With that you can basically read and re-write any code that is read by PHP before it is actually interpretted. with fopen(), fwrite(), include, require, file_get_contents() etc.
So in your case you could listen for any file that is require(_once) or include(_once) and do with the code you like. You will get the entire code in a variable and with that you can simply do all sorts of replacements in strings with regex and what not.
The only downside is, is that your index.php can't make use of this method since it is not catched by any include or require. But any other code file that is included from there can be catched by the stream wrapper.
Here is an article about a plugin system that uses that method. Maybe it can be of any help.
http://phpmyweb.net/2012/04/26/write-an-awesome-plugin-system-in-php/
In there you'll also find a link to a guthub page with the source of the plugin code. In there you can basically see how to setup your Stream Wrapper class. From there on you can make up your own code as you do not have to intercept any method calls etc. like the plugin is doing.
I don't think your include idea would work as described. Since the code would be missing braces, it probably would not make it through the normal PHP parser without throwing a 500 error. So the file you want to include could never do its work.
The opposite approach might work. Write a parser script and have it read and execute your "whitespace" PHP files.
URLs might look like this: mydomain.com/my-parsing-script.php?file=script/to/parse.php
Then you'd edit .htaccess to rewrite all your URLs to make that stuff invisible to the user.
The parsing script would simply open the "whitespace" file and do some regex magic before passing the script to eval();

Are there any downsides from using Include() or nested include's()?

I am not an expert in PHP. I am trying to increase the use of include() to make my website code as clean as possible instead of just copying, for example, code of the header in all the pages. I have two questions
1 . Is it good practice to use include() a lot in terms of server requests, speed, ...etc ?
index.php
(bunch of code)
<? include("connect.php") ?>;
(bunch of code)
<? include("header.php") ?>;
(bunch of code)
<? include("footer.php") ?>;
2 . Is it fine also to use nested include's()? example:
header.php
(some code)
<? include("searchFormInput.php") ?>;
now index.php will include header.php, then header.php will include searchFormInput.php as well
is this fine?
Thanks a lot
Yes, including is a common practice.
Yes, including gives you slight performance penalty (very small).
But including gives you readibility gain and thanks to it will be easier to employ DRY rule. Just remember the following:
if the file contains some code that should be executed only once (some setup, class definitions, function definitions etc.), use include_once() (it will have no effect if invoked again on the same filename),
if the file contains some code executed multiple times (eg. some template for a form), use simple include(),
if something is required for your application to work (eg. some security code, some setup etc.), use require() instead of include() or require_once() instead of include_once() - if the file will not be found, PHP will throw fatal error and will stop executing your script,
The principle downside to nesting includes is that you are likely to run into situations when cross-dependencies cause a file to be include more than once. That is easily solved by the use of include_once(), though.
In your example however, with header.php including searchFormInput.php, you probably won't have problems assuming these files both mostly produce HTML output rather than parsing classes and dependencies.
On the other hand, if you had some structure like
connect.php includes config.php
session.php includes config.php
you would need to use include_once('config.php').
include,require will read file and excute codes inside it.
i made some tests on speed of include and file_get_contents
results was include and require is slow in compare
so my advice don't increase numbers of inclusion.
I think you should look at autoload with PHP once. You should not need to care the include of every and each file. Just adjust your autoload and that will take care of all these. You needs to do object oriented programming with this.
It's fine to that in terms of performance and it keeps your code clean and reusable to a certain extent. However, I recommend that you use templates for this kind of code inclusion, where you load all your information into variables and then call them in your template. Consider a template engine http://www.smarty.net/ or maybe a PHP framework or CMS http://drupal.org/ which should make your life easier in the short and long run!

What about calling aspx in php?

Here is my code
<html>
<body>
<?php
include("Default.aspx");
?>
</body>
</html>
but it keeps giving me the output of
<%# Page Language="C#"
AutoEventWireup="true"
CodeFile="Default.aspx.cs"
Inherits="_Default" %> <%
Response.Write("Hello world!"); %>
I just need to run the Hello World on the site.
If you want the output of the aspx file, you will need to request it via a web server which can understand aspx files rather than the file system, e.g.
include("http://example.com/Default.aspx");
Your PHP installation must have URL fopen wrappers enabled for this to work.
As Magnus Nordlander notes in another answer, you should only use include if you expect to find php code in the file. If you don't, you could simply use readfile to output the data verbatim:
readfile("http://example.com/Default.aspx");
You seem to be going about this in a very wrong way.
What include() (and require(), for that matter) does is that it parses the specified file with the PHP interpreter. If your aspx-code for some reason generates PHP-code, which is supposed to be parsed by the PHP interpreter, then the way Paul Dixon suggests would be the right way of going about this. However, I would strongly advice against doing this.
For one thing, it's a huge security disaster waiting to happen. It's also incredibly bad architecturally speaking.
If you want to include HTML markup etc. generated using aspx, what you should do is to use
echo file_get_contents("http://www.example.com/Default.aspx");
This way, any PHP code in the output remains unparsed, thus avoiding the aforementioned security disaster. However, if you're able to do without mixing languages like this, that's probably going to be a much better solution.

PHP: Where should I store the text for info & warning messages

I have a question concerning the design of my project's Code.
In most cases, it is important to separate content from code (HTML mixed with PHP in bigger apps=No good idea, etc.) but how should I handle things like the text of error messages?
Assuming this one message will be only used in one case/PHP file:
MessageBox( 'Something gone wrong, probably your fault' );
or
MessageBox( Lang::error_usersfault );
(Where Lang is a class located in some config file, full of consts)
If you have any experiences (I think every PHP programmer will come across something like this) with things like in the example above - What are they? How do you solve it?
What is the better solution?
May be you'll find php extension gettext useful?
MessageBox(_("Have a nice day"));
PHP Manual of Gettext::gettext

Categories