How do you eval() a PHP code through multiple levels? - php

I have this code:
$layout_template = template_get("Layout");
$output_template = template_get("Homepage");
$box = box("Test","Test","Test");
eval("\$output = \"$layout_template\";");
echo $output;
In the $template_layout variable is a call for the
variable $output_template, so then the script moves onto the $output_template variable
But it doesn't go any further, inside the $output_template is a call to the variable $box, but it doesn't go any further than one level

I would never want nested eval(), and especially not in any recursive logic. Bad news. Use PHP's Include instead. IIRC eval() creates a new execution context, with overhead whereas include() doesn't.
If you have buffers such as:
<h1><?php echo $myCMS['title']; ?></h1>
I sometimes have files like Index.tpl such as above that access an associative array like this, then you just do in your class:
<?php
class TemplateEngine {
...
public function setvar($name, $val)
{
$this->varTable[$name]=make_safe($val);
}
....
/* Get contents of file through include() into a variable */
public function render( $moreVars )
{
flush();
ob_start();
include('file.php');
$contents = ob_get_clean();
/* $contents contains an eval()-like processed string */
...
Checkout ob_start() and other output buffer controls
If you do use eval() or any kind of user data inclusion, be super safe about sanitizing inputs for bad code.
It looks like you are writing a combined widget/template system of some kind. Write your widgets (views) as classes and allow them to be used in existing template systems. Keep things generic with $myWidget->render($model) and so on.
I saw this on the PHP doc-user-comments-thingy and it seems like a bad idea:
<?php
$var = 'dynamic content';
echo eval('?>' . file_get_contents('template.phtml') . '<?');
?>
Perhaps someone can enlighten me on that one :P

Related

PHP replace {replace_me} with <?php include ?> in output buffer

I have a file like this
**buffer.php**
ob_start();
<h1>Welcome</h1>
{replace_me_with_working_php_include}
<h2>I got a problem..</h2>
ob_end_flush();
Everything inside the buffer is dynamically made with data from the database.
And inserting php into the database is not an option.
The issue is, I got my output buffer and i want to replace '{replace}' with a working php include, which includes a file that also has some html/php.
So my actual question is: How do i replace a string with working php-code in a output-buffer?
I hope you can help, have used way to much time on this.
Best regards - user2453885
EDIT - 25/11/14
I know wordpress or joomla is using some similar functions, you can write {rate} in your post, and it replaces it with a rating system(some rate-plugin). This is the secret knowledge I desire.
You can use preg_replace_callback and let the callback include the file you want to include and return the output. Or you could replace the placeholders with textual includes, save that as a file and include that file (sort of compile the thing)
For simple text you could do explode (though it's probably not the most efficient for large blocks of text):
function StringSwap($text ="", $rootdir ="", $begin = "{", $end = "}") {
// Explode beginning
$go = explode($begin,$text);
// Loop through the array
if(is_array($go)) {
foreach($go as $value) {
// Split ends if available
$value = explode($end,$value);
// If there is an end, key 0 should be the replacement
if(count($value) > 1) {
// Check if the file exists based on your root
if(is_file($rootdir . $value[0])) {
// If it is a real file, mark it and remove it
$new[]['file'] = $rootdir . $value[0];
unset($value[0]);
}
// All others set as text
$new[]['txt'] = implode($value);
}
else
// If not an array, not a file, just assign as text
$new[]['txt'] = $value;
}
}
// Loop through new array and handle each block as text or include
foreach($new as $block) {
if(isset($block['txt'])) {
echo (is_array($block['txt']))? implode(" ",$block['txt']): $block['txt']." ";
}
elseif(isset($block['file'])) {
include_once($block['file']);
}
}
}
// To use, drop your text in here as a string
// You need to set a root directory so it can map properly
StringSwap($text);
I might be misunderstanding something here, but something simple like this might work?
<?php
# Main page (retrieved from the database or wherever into a variable - output buffer example shown)
ob_start();
<h1>Welcome</h1>
{replace_me_with_working_php_include}
<h2>I got a problem..</h2>
$main = ob_get_clean();
# Replacement
ob_start();
include 'whatever.php';
$replacement = ob_get_clean();
echo str_replace('{replace_me_with_working_php_include}', $replacement, $main);
You can also use a return statement from within an include file if you wish to remove the output buffer from that task too.
Good luck!
Ty all for some lovely input.
I will try and anwser my own question as clear as I can.
problem: I first thought that I wanted to implement a php-function or include inside a buffer. This however is not what I wanted, and is not intended.
Solution: Callback function with my desired content. By using the function preg_replace_callback(), I could find the text I wanted to replace in my buffer and then replace it with whatever the callback(function) would return.
The callback then included the necessary files/.classes and used the functions with written content in it.
Tell me if you did not understand, or want to elaborate/tell more about my solution.

What is the benefit of passing a callback to ob_start compared to just processing the result of ob_get_clean()?

I am wondering if there is any real benefit to using this...
function getSomeContent() {
ob_start(function($content) {
// ... modify content ...
return $content;
}
// ... output stuff ...
return ob_get_clean();
}
...as opposed to this...
function getSomeContent() {
ob_start();
// ... output stuff ...
$result = ob_get_clean();
// ... modify content ...
return $result;
}
...?
Assume the "output stuff" and "modify content" parts are the same in each case. The key point is that the "modify content" has changed its location, being in a callback in the first case, and being "inline" in the second case.
Is there a performance benefit of one over the other? For example, does the second form make two copies of the buffer contents when the first uses only one? Or is it purely a coding style decision? Why would you choose one form over the other?
I can see there are differences in scope access, because any variables in the enclosing scope will be available in the "modify content" part of the second example, where they would have to be "passed in" with a use clause in the first example. In fact this is exactly why I would normally choose the second form.
Now your code is clear yes, in your first samples you given a case where you used $result twice (that wasn't a good idea).
My main idea is : you call ob_start with a callback only if you do not need to use your $result in your current scope. Your first example becomes :
ob_start(function($content) {
// ... modify content ...
return $content;
}
// ... output stuff ...
ob_end_clean();
In this case, the job with $result is made in a new scope and this can make your code cleaner (example: you call ob_start(array($this, 'method'));), and you don't need to unset your $result to free it from your main scope at the end of your job (I assume you're doing something else of course).
Just to clarify Ninsuo's correct answer a bit.
My two code samples actually do not produce the same result. In fact, using the callback in combination with ob_get_clean() is completely useless.
This is because the callback is applied when cleaning or flushing the buffer.
However ob_get_clean() retrieves the contents first, and then cleans the buffer. Which means that the contents returned are not the result returned by the callback, but the input passed to the callback.
I wrote these two simple (and hacky) scripts to demonstrate.
This one uses ob_get_clean() and does not produce the correct result:
// Tests the use of callbacks with ob_get_clean().
class TestWithGetClean {
// This variable is set when obcallback is called.
public $foo = null;
// The output buffer callback.
public function obcallback($value) {
$this->foo = 'set';
return $value . '(modified)';
}
// Main method.
public function run() {
ob_start(array($this, 'obcallback'));
echo 'this is the output', PHP_EOL;
return ob_get_clean();
}
}
// Run the test with ob_get_clean().
$t = new TestWithGetClean();
echo $t->run(); // This method returns a value in this test. (But not the correct value!)
echo $t->foo, PHP_EOL;
The output from running this is:
this is the output
set
The text '(modified)' does not appear anywhere. Note however that the instance variable $foo is set, so the callback is definitely called, however the output is not as I originally expected.
Compare to this one which uses ob_end_flush():
// Tests the use of callbacks with ob_end_flush().
class TestWithEndFlush {
// This variable is set when obcallback is called.
public $foo = null;
// The output buffer callback.
public function obcallback($value) {
$this->foo = 'set';
return $value . '(modified)' . PHP_EOL;
}
// Main method.
public function run() {
ob_start(array($this, 'obcallback'));
echo 'this is the output', PHP_EOL;
ob_end_flush();
}
}
// Run the test with ob_end_flush().
$t2 = new TestWithEndFlush();
$t2->run(); // This method produces output in this test.
echo $t2->foo, PHP_EOL;
This one produces the following output:
this is the output
(modified)
set
However, this is of course not as useful because the output goes directly to the client, so we cannot further manipulate the result. (For example, wrapping the text in a Symfony HttpFoundation Component Request object).

how to turn the output of a require statement into a string in php

im working with a large team, and im making functions that return html code, and im echoing the result of those functions to get the final page. The thing is, i need some scrap of code developed by other member of the team, and i need it to be a string, but the code is available as a php file which im supposed to include or require inside my page.
Since im not writing an ht;ml page, but a function that generate that code, i need to turn the resulting html of the require statement into a string to concatenate it to the code generated by my function.
Is there any way to evaluate the require and concatenate its result to my strings?
Ive tried the function eval(), but didnt work, and read some thing about get_the_content(), but it isnt working either. I dont know if i need to import something, i think it have something to do with wordpress, and im using raw php.
thanks for all your help!!! =)
Try the ob_...() family of functions. For example:
<?php
function f(){
echo 'foo';
}
//start buffering output. now output will be sent to an internal buffer instead of to the browser.
ob_start();
//call a function that echos some stuff
f();
//save the current buffer contents to a variable
$foo = ob_get_clean();
echo 'bar';
echo $foo;
//result: barfoo
?>
If you want to put the echo'd result of an include into a variable, you could do something like this:
//untested
function get_include($file){
ob_start();
include($file);
return ob_get_clean();
}
or if you want to put the echo'd result of a function call into a variable, you could do something like this:
//untested
//signature: get_from_function(callback $function, [mixed $param1, [mixed $param2, ... ]])
function get_from_function($function){
$args = func_get_args();
shift($args);
ob_start();
call_user_func_array($function,$args);
return ob_get_clean();
}
Depending on how the other file works...
If the other file can be changed to return a value, then you should use:
$content = require 'otherfile';
If the other file simply uses echo or some other way to print directly, use:
ob_start();
require 'otherfile';
$content = ob_get_clean();
You can receive string with include or require but you have to update those files before including to add return statement.
the file to be included should return result like this
<?php
$var = 'PHP';
return $var;
?>
and you can receive the $var data by including that file
$foo = include 'file.php';
echo $foo; // will print PHP
Documentation section

Using PHP classes to format html?

I have a class designated for a certain site. In that site I have different functions to retrieve data from the database and store that data into an array. I have other functions within the same class that take the data and format it into html and returns the html containing the data from the database.
For example...
function GetUserProfile($userID){
$query = 'SELECT * FROM users WHERE userID='.$userID;
.......
blah blah blah
.......
$user = mysqli->fetch_assoc();
return $user;
}
function FormatUserProfile($user, $showDesc = false){
$profile = '< h1 >'.$user['userName'].'< / h1 >';
if($showDesc){
$profile .= '< div >'.$user['description'].'< / div >';
}
return $profile;
}
...
So if i had a function to solely gather information, and another function to solely format that gathered information.
Mainly because I will be showing the same data on different pages, but Different pages show different data, like a search would only bring up the users name, where as the users profile page would bring up the username and the description for example.
Is that good practice, or is there a better way to do this?
It's a good practice. Personally, I use the following template "engine":
<?php
class Template{
static function show($path, $arg = NULL){
include "templates/$path.php";
}
static function get($path, $arg = NULL){
ob_start();
self::show($path, $info);
$block = ob_get_contents();
ob_end_clean();
return $block;
}
}
In your case the template would be like this:
<?php
echo '<h1>'.$arg['user']['userName'].'</h1>';
if($arg['showDesc']){
echo '<div>'.$arg['user']['description'].'</div>';
}
?>
You could unpack the array with the template arguments, but I prefer to keep it all in one place, so the code is less confusing. (You always know what is coming from the input, and what's defined in the template this way. To keep things shorter, you might use $_ instead of $arg too.) For a small example like this, the benefit is not obvious, but for larger templates it save a lot of variable manipulation, as you can use PHP's own templating abilities.
You can use Smarty template engine or something
similar.
It's templates are stored separately and look like this: http://www.smarty.net/sampleapp/sampleapp_p5.php

How to pass parameters to PHP template rendered with 'include'?

need your help with PHP templating. I'm new to PHP (I'm coming from Perl+Embperl). Anyway, my problem is simple:
I have a small template to render some item, let it be a blog post.
The only way i know to use this template is to use 'include' directive.
I want to call this template inside a loop going thru all the relevant blog posts.
Problem: I need to pass a parameter(s) to this template; in this case reference to array representing a blog post.
Code looks something like this:
$rows = execute("select * from blogs where date='$date' order by date DESC");
foreach ($rows as $row){
print render("/templates/blog_entry.php", $row);
}
function render($template, $param){
ob_start();
include($template);//How to pass $param to it? It needs that $row to render blog entry!
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
Any ideas how to accomplish this? I'm really stumped :) Is there any other way to render a template?
Consider including a PHP file as if you were copy-pasting the code from the include into the position where the include-statement stands. This means that you inherit the current scope.
So, in your case, $param is already available in the given template.
$param should be already available inside the template. When you include() a file it should have the same scope as where it was included.
from http://php.net/manual/en/function.include.php
When a file is included, the code it
contains inherits the variable scope
of the line on which the include
occurs. Any variables available at
that line in the calling file will be
available within the called file, from
that point forward. However, all
functions and classes defined in the
included file have the global scope.
You could also do something like:
print render("/templates/blog_entry.php", array('row'=>$row));
function render($template, $param){
ob_start();
//extract everything in param into the current scope
extract($param, EXTR_SKIP);
include($template);
//etc.
Then $row would be available, but still called $row.
I use the following helper functions when I work on simple websites:
function function_get_output($fn)
{
$args = func_get_args();unset($args[0]);
ob_start();
call_user_func_array($fn, $args);
$output = ob_get_contents();
ob_end_clean();
return $output;
}
function display($template, $params = array())
{
extract($params);
include $template;
}
function render($template, $params = array())
{
return function_get_output('display', $template, $params);
}
display will output the template to the screen directly. render will return it as a string. It makes use of ob_get_contents to return the printed output of a function.

Categories