PHP output buffer - How to access a specific level? - php

When I do:
print_r(ob_list_handlers());
I get:
Array ( [0] => default output handler [1] => W3TC\Generic_Plugin::ob_callback [2] => Weglot::treatPage )
It seems that every time ob_start() is called it creates a new level or a new index or something in the ob stack.
How can I access the content of a specific level instead of just the default one?

yes you are exactly right with each ob_start() you're adding one level to the stack but if you want to accumulate the outputs and later you want to use that output, i recommend using an array to put the output in. at the end of each ob_start() you need to close the buffer with ob_end_...() either you add levels to the buffer or open and close the buffer at each time so
$output = array();
ob_start();
echo("<h1>hello</h1>");
array_push($output, ob_get_contents());
ob_end_clean();
ob_start();
echo("<h3> world</h3>");
array_push($output, ob_get_contents());
ob_end_clean();
echo $output[0]." ".$output[1];
or
$output = array();
ob_start();
echo("<h1>hello</h1>");
array_push($output, ob_get_contents());
ob_start();
echo("<h3> world</h3>");
array_push($output, ob_get_contents());
ob_end_clean();
ob_end_clean();
echo $output[0]." ".$output[1];
doesn't make any difference. i hope this could help

Related

PHP Piping Data with f_open

I have a piece of code, the issue is the file "data" is over 8GB. This is very memory intensive. I want to reduce the usage of RAM and saw the f_load would be ideal, however, how could i explode this data?
This is my current code:
$data = file_get_contents("data");
$data = explode("|", $data);
foreach ($data as $d) { // rest of code
theoretically, i need to open a pipe, stream and close a pipe How would i go about this?
I've tried using f_open rather than file_get_contents but errors started popping up so i'm doing something wrong and would really like to learn.
You can use stream_get_line to read your data block per block (with | as the delimiter character) : PHP stream_get_line()
$fh = fopen('data', 'r'); // open the file in read-only mode
while( $d = stream_get_line($fh, 1000, '|') ) // read the file until the next |
{
echo $d . PHP_EOL ; // display one block of data
}
fclose($fh); // close the file

PHP File Handling (Download Counter) Reading file data as a number, writing it as that plus 1

I'm trying to make a download counter in a website for a video game in PHP, but for some reason, instead of incrementing the contents of the downloadcount.txt file by 1, it takes the number, increments it, and appends it to the end of the file. How could I just make it replace the file contents instead of appending it?
Here's the source:
<?php
ob_start();
$newURL = 'versions/v1.0.0aplha/Dungeon1UP.zip';
//header('Location: '.$newURL);
//increment download counter
$file = fopen("downloadcount.txt", "w+") or die("Unable to open file!");
$content = fread($file,filesize("downloadcount.txt"));
echo $content;
$output = (int) $content + 1;
//$output = 'test';
fwrite($file, $output);
fclose($file);
ob_end_flush();
?>
The number in the file is supposed to increase by one every time, but instead, it gives me numbers like this: 101110121011101310111012101110149.2233720368548E+189.2233720368548E+189.2233720368548E+18
As correctly pointed out in one of the comments, for your specific case you can use fseek ( $file, 0 ) right before writing, such as:
fseek ( $file, 0 );
fwrite($file, $output);
Or even simpler you can rewind($file) before writing, this will ensure that the next write happens at byte 0 - ie the start of the file.
The reason why the file gets appended it is because you're opening the file in append and truncate mode, that is "w+". You have to open it in readwrite mode in case you do not want to reset the contents, just "r+" on your fopen, such as:
fopen("downloadcount.txt", "r+")
Just make sure the file exists before writing!
Please see fopen modes here:
https://www.php.net/manual/en/function.fopen.php
And working code here:
https://bpaste.net/show/iasj
It will be much simpler to use file_get_contents/file_put_contents:
// update with more precise path to file:
$content = file_get_contents(__DIR__ . "/downloadcount.txt");
echo $content;
$output = (int) $content + 1;
// by default `file_put_contents` overwrites file content
file_put_contents(__DIR__ . "/downloadcount.txt", $output);
That appending should just be a typecasting problem, but I would not encourage you to handle counts the file way. In order to count the number of downloads for a file, it's better to make a database update of a row using transactions to handle concurrency properly, as doing it the file way could compromise accuracy.
You can get the content, check if the file has data. If not initialise to 0 and then just replace the content.
$fileContent = file_get_contents("downloadcount.txt");
$content = (!empty($fileContent) ? $fileContent : 0);
$content++;
file_put_contents('downloadcount.txt', $content);
Check $str or directly content inside the file

PHP ob_start within foreach unexpected resuts

I have the following code
foreach($this->load as $count=>$test){
ob_start();
echo $count;
$cached = ob_get_contents();
ob_end_clean();
echo $cached
}
The foreach should loop 2 times. I want to get
12
but I get
11
I do not think it is clearing the ob_start.
Any Help please.

How to use ob_start on a string?

I have a project where I am using OB_START to gather output from a PHP file. The problem is that sometimes I need the contents of the PHP file 20 - 30 times in 1 call.
I'd like to do something like get_file_contents({file}) then use that string for the OB_START() call. However, all the examples I've seen use an include() call to get the script each time.
Is there a way to load the script one time but use it several times in OB_START() calls?
ob_start();
include "file.php";
$output = ob_get_clean();
What I would like to do:
$script = get_file_contents(file);
$output = '';
begin loop;
ob_start();
{somehow make $script execute as code}
$output .= ob_get_clean();
end loop;
You can just use include over-and-over again.
$file = "SomeScript.php"
$output = '';
begin loop;
ob_start();
include $file
$output .= ob_get_clean();
end loop;
If you're dead-set on doing it the way you're describing, you can do the following, but it's weird:
$script = get_file_contents(file);
$output = '';
begin loop;
ob_start();
eval($script);
$output .= ob_get_clean();
end loop;
In my opinion, a much better solution would be to make the script a function that outputs it's results instead of printing them. So let's say you put the "script" into a function call foo(), Then you could do this:
$file = "SomeScript.php"
include $file
$output = '';
begin loop;
$output .= foo();
end loop;
But if you cannot change the contents of the script, then my first two examples should work for you.

Using print_r in ob_start

As mentioned in the manual it's not working. i tried var_dump it too suffers from the same problem.
ob_start()
$debugdata=print_r ($var,true)
This prints the result on screen than storing to a variable
The second parameter of print_r is $return which allows the output to be returned as a string rather than outputting it:
$debugData = print_r($var, true);
There is no need to use output buffering for this, and in fact it cannot be used. You will need to end the output buffering before this and then restart the buffering after your print_r call:
ob_start();
// stuff
$output = ob_end_clean();
$debugData = print_r($var, true);
ob_start();
// more stuff
$output .= ob_end_clean();
EDIT: Another option is to nest output buffers and have an inner buffer do the print_r work:
ob_start(); // your original start
// stuff
ob_start();
print_r($var);
$debugData = ob_get_clean();
// more stuff
$output = ob_get_clean(); // your original end
ob_start() starts outbut buffering. But you also need to end and retrieve the contents of the buffer as well.
Here are the functions you could use:
ob_get_clean() - puts the contents of the output buffer in a variable, ends and cleans the buffer.
ob_start();
print_r($foo);
$output = ob_get_clean();
ob_get_contents() - fetches the contents of the output buffer without closing or cleaning it.
ob_end_clean() - closes and cleans the buffer.
ob_start();
print_r($foo);
$output = ob_get_contents();
ob_end_clean();
There are a few other possibilities. Please make yourself familiar with the output buffering functions.
Also, a remark. You don't just assign the output of print_r to a variable. You just print stuff as if you were printing it on the screen. With output buffering on, all output will be buffered instead of being sent to stdout immediately. So, first you print_r, then retrieve the contents of the buffer.
[EDIT]
In the light of the conversation going on in the comments, I recommend having a look at the notes section of the print_r() manual. As #RomiHalasz and #cbuckley observe, due to print_r's internal output buffering, it cannot be used in conjunction with ob_start()
while the second parametre, return, is used, as the two will collide.
You have to EITHER use output buffering and plain print_r (with only the first parametre), or end the output buffering before you use print_r with the second parametre.
Either this:
ob_start();
print_r($foo);
$output = ob_get_clean();
or this:
ob_start();
// blah
$output = ob_get_clean();
$output .= print_r($foo,true);
ob_start();
// blah
$output .= ob_get_clean();

Categories