So I know you can use output buffer. The problem right now is, I am using a function in a Wordpress plugin and it is automatically and it automatically outputs the return. However, I want to check the return to see if it is false or returning my data.
I have tried:
if( function_name() ) {
}
$name = function_name();
I can still see the output in those situations, which I why I wanted to suppress it and do some checks first. I don't want to edit the core function of the plugin, but I will as a last resort. Is there a better work around?
Yes. It can be done like this:
ob_start();
if (function_name()) { }
else {}
// then you can do one of the following
ob_end_clean(); // in case you want to suppress function_name output
ob_flush(); // in case you don't want to suppress function_name output
Have a look here for more information about output control functions.
Also, instead of using ob_flush and ob_end_clean you could use ob_get_clean.
First, capture the output and return value of the function.
ob_start();
$name = function_name();
$output = ob_get_clean();
Next, decide whether or not you want to output it.
if ($name !== false) {
echo $output;
}
You weren't clear what you wanted to do with the return value if it wasn't false or if it was actually the output of the function that you wanted to send to the page.
Related
How does one stop calls to the ob_start callback when issue-ing *_clean() calls.
ob_start(function($buffer, $phase){
// code here
}, 0, PHP_OUTPUT_HANDLER_FLUSHABLE | PHP_OUTPUT_HANDLER_REMOVABLE);
Doesn't prevent ob_end_clean, ob_get_clean or ob_clean calls from being ran.
I'd expect a notice that the buffer wasn't started with the proper PHP_OUTPUT_HANDLER_CLEANABLE flag
as per the docs.
As for the PHP_OUTPUT_HANDLER_* constants, I haven't found a suitable man page where the $phase parameter is explained and the groups of bits pertaining to those constants detailed. Even the actual names / values I've had to get them from the CONSTANTS global variable.
PHP_OUTPUT_HANDLER_START
PHP_OUTPUT_HANDLER_WRITE
PHP_OUTPUT_HANDLER_FLUSH
PHP_OUTPUT_HANDLER_CLEAN
PHP_OUTPUT_HANDLER_FINAL
PHP_OUTPUT_HANDLER_CONT
PHP_OUTPUT_HANDLER_END
PHP_OUTPUT_HANDLER_CLEANABLE
PHP_OUTPUT_HANDLER_FLUSHABLE
PHP_OUTPUT_HANDLER_REMOVABLE
PHP_OUTPUT_HANDLER_STDFLAGS
PHP_OUTPUT_HANDLER_STARTED
PHP_OUTPUT_HANDLER_DISABLED
Knowing these constants I've tried to limit so that no clean methods trigger my callback and short-circuit its logic. But I couldn't get the $phase content for any of the clean methods out (can't call printf, echo,ob_start from within the callback).
Maybe I'm going at this wrong, my scenario is:
I start a buffer at the beginning to process all output later
A lot of code that I don't control runs:
for ($i = 0; $i < ob_get_level(); $i++) { $final .= ob_get_clean(); }
Triggers my callback even though it shouldn't as the code is not its owner / no cleanable flag was set
I trigger alerts for empty buffers even though it isn't the case as they reconstruct it in another buffer
Basically my questions are:
Am I able to stop such a thing?
If not is there another way?
If you have code which clears the whole buffer and you cannot control it - there's no way you get ob_* commands to work properly. You can implement your own buffer construction though and add output there manually.
The class might look like this
<?php
class MyBuffer
{
static $buffer = '';
public static function add(string $output)
{
self::$buffer .= $output;
}
public static function get()
{
return self::$buffer;
}
public static function get_clean()
{
$buffer = self::$buffer;
self::$buffer = '';
return $buffer;
}
}
An you could use it in the following way
// ... some code
MyBuffer::add('Hello user, glad you joined us!');
// ... some more code
MyBuffer::add('Your socore is ' . $score . '. Congratz!');
// ...
echo MyBuffer::get_clean();
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.
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).
Output buffering in PHP is fun. It simplifies many things. I use ob_start() at the top of the script and ob_get_clean() (or any other function) at the bottom.
Between those two calls is it possible to call those functions again, without interfering the parent calls.
Is this type of code valid ? (it works fine, but...) Is this a good habit ?
<?php
ob_start(); //NOTICE !!!
echo '<p>echos of the top of the script</p>';
echo GetSomeOtherData(true);
echo '<p>echos after GetSomeOtherData()</p>';
$data = ob_get_clean(); //NOTICE !!!
echo $data;
//just a function to return something, with the help of output buffering
function GetSomeOtherData($toReturn)
{
ob_start(); //NOTICE !!!
echo '<p>This has been rendered inside a function</p>';
$function_data = ob_get_clean(); //NOTICE !!!
if($toReturn===true)
{
return $function_data;
}
else
{
//may be an error | return something else
return '<p>An Error</p>';
}
}
?>
From the ob_start() manual:
Output buffers are stackable, that is, you may call ob_start() while
another ob_start() is active. Just make sure that you call
ob_end_flush() the appropriate number of times. If multiple output
callback functions are active, output is being filtered sequentially
through each of them in nesting order.
So it is perfectly valid to assume that an ob_end/get will end/return the matching ob_start e.g.:
ob_start();
echo "<div class=outer>";
ob_start();
echo "<div class=inner></div>";
$inner = ob_get_clean(); // <div class=inner></div>
echo "</div>";
$outer = ob_get_clean(); // <div class=outer></div>
In all honesty, I don't see any problem with that. Every call to ob_start() is matched by an ob_get_clean() call, so the use of such functions is completely transparent to the "parent" ob_start(). It would be a horrible habit if pairs (of calls to ob_start() and ob_get_clean()) didn't match -- but as long as they do, it shouldn't (and won't) cause you any trouble.
I am trying to keep my code clean break up some of it into files (kind of like libraries). But some of those files are going to need to run PHP.
So what I want to do is something like:
$include = include("file/path/include.php");
$array[] = array(key => $include);
include("template.php");
Than in template.php I would have:
foreach($array as $a){
echo $a['key'];
}
So I want to store what happens after the php runs in a variable to pass on later.
Using file_get_contents doesn't run the php it stores it as a string so are there any options for this or am I out of luck?
UPDATE:
So like:
function CreateOutput($filename) {
if(is_file($filename)){
file_get_contents($filename);
}
return $output;
}
Or did you mean create a function for each file?
It seems you need to use Output Buffering Control -- see especially the ob_start() and ob_get_clean() functions.
Using output buffering will allow you to redirect standard output to memory, instead of sending it to the browser.
Here's a quick example :
// Activate output buffering => all that's echoed after goes to memory
ob_start();
// do some echoing -- that will go to the buffer
echo "hello %MARKER% !!!";
// get what was echoed to memory, and disables output buffering
$str = ob_get_clean();
// $str now contains what whas previously echoed
// you can work on $str
$new_str = str_replace('%MARKER%', 'World', $str);
// echo to the standard output (browser)
echo $new_str;
And the output you'll get is :
hello World !!!
How does your file/path/include.php look like?
You would have to call file_get_contents over http to get the output of it, e.g.
$str = file_get_contents('http://server.tld/file/path/include.php');
It would be better to modify your file to output some text via a function:
<?php
function CreateOutput() {
// ...
return $output;
}
?>
Than after including it, call the function to get the output.
include("file/path/include.php");
$array[] = array(key => CreateOutput());