I have a PHP script that takes a few minutes to finish processing. While the page is still loading, I want to show part of the PHP output as it becomes available, which can be done using ob_start() and ob_flush().
After the entire script has finish executing, I want to save all the PHP output right from the start into a HTML file. This can be done using ob_start() and file_put_contents("log.html", ob_get_contents());
Problem: However, because we are calling ob_flush() along the way, the final file that gets saved with file_put_contents() appears to be separated into different files. I suspect this has to do with the buffer being cleared by the ob_start() calls before file_put_contents() is called, but why did it not just save the output between the final ob_flush() and file_put_contents() to the file, but instead saves several different files? (I may be wrong, the seperate partial files may be due to partial execution of the script)
In other words, how do I show PHP output as a long script executes, and still save all the PHP output to a single HTML file?
PHP Code
// Start the buffering
ob_start();
......
ob_flush();
......
ob_flush();
......
file_put_contents("log.html", ob_get_contents());
Couple of ways I can think of:
Keep a variable (called something like $content), and append the current buffer every time you call ob_flush():
$content = '';
...
$content .= ob_get_contents();
ob_flush();
...
$content .= ob_get_contents();
ob_flush();
...
file_put_contents('log.html', $content . ob_get_contents());
ob_flush();
Use fopen():
$fp = fopen('log.html', 'w+');
...
fwrite($fp, ob_get_contents());
ob_flush();
...
fwrite($fp, ob_get_contents());
ob_flush();
...
fwrite($fp, ob_get_contents());
fclose($fp);
ob_flush();
You could also use ob_get_contents() along the way, save it to a variable and then into the file and the outputstream...
You can grab the buffer contents, and store it in a a variable by calling ob_get_contents.
Have you read the manual?
Related
So I have a page called create.php that creates another php file called "1". In this php file called "1". I was hoping to use
<?php echo $_SERVER['PHP_SELF'];?>
or
<?php $path = $_SERVER["SCRIPT_NAME"];echo $path;?>
To create a link that would take the number of the page and +1 it. When I do both of these functions instead of getting what I would think I would get, "1", I get "create", the page that it was created with. I'm quite dumbfounded by why this is happening, the code is most definitely on "1" and I even double checked to make sure create made a file and that I was on it so why does it think the current page is "create"?
Code being used
<?php
// start the output buffer
ob_start(); ?>
<?php echo $_SERVER['PHP_SELF'];?>
<?php
// open the cache file "cache/1" for writing
$fp = fopen("cache/1", 'w');
// save the contents of output buffer to the file
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_flush();
?>
You split the code in pieces and you probably have a wrong idea about what happens and what will be written in cache/1. Your code is the same as the following:
<?php
// start the output buffer
ob_start();
// echo the path of the current script
echo $_SERVER['PHP_SELF'];
// open the cache file "cache/1" for writing
$fp = fopen("cache/1", 'w');
// save the contents of output buffer to the file
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_flush();
I removed the closing PHP tag (?>) when it was followed by an open PHP tag (<?php).
Now it should be clear that, without output buffering, the script create.php display its own path relative to the document root. The output buffering captures the output and puts it into file cache/1.
You don't even need output buffering for this. You can simply remove all the calls to ob_* functions, remove the echo() line and use:
fwrite($fp, $_SERVER['PHP_SELF']);
It's clear that this is not your goal. You probably want to generate a PHP file that contains the following content:
<?php echo $_SERVER['PHP_SELF'];?>
This is as simple as it putting this text into a string and writing the string to the file:
<?php
$code = '<?php echo $_SERVER["PHP_SELF"];?>';
$fp = fopen("cache/1", 'w');
fwrite($fp, $code);
fclose($fp);
You can even use the PHP function file_put_contents() and all the code you posted in the question becomes:
file_put_contents('cache/1', '<?php echo $_SERVER["PHP_SELF"];?>');
If you need to put a bigger block of PHP code in the generated file then you can use the nowdoc string syntax:
$code = <<<'END_CODE'
<?php
// A lot of code here
// on multiple lines
// It is not parsed for variables and it arrives as is
// into the $code variable
$path = $_SERVER['PHP_SELF'];
echo('The path of this file is: '.$path."\n");
$newPath = dirname($path).'/'.(1+(int)basename($path));
echo('The path of next file is: '.$newPath."\n");
// That's all; there is no need for the PHP closing tag
END_CODE;
// Now, the lines 2-11 from the code above are stored verbatim in variable $code
// Put them in a file
file_put_contents('cache/1', $code);
I've been writing a php/html page encoder/decoder... I know it already exists but it's a university project so go on XDDD
I encode the pages that I want to protect let's say hypothetically with base64_encode and when I receive a request of any pages I have a loader that reads the coded page, decrypts it and with eval executes it. The real problems arise when I try to decrypt and execute a mixed php/html page. Obviously eval can't execute html code so my question is do I really become crazy about splitting the page executing the php code and print the html? And also if I include an encoded php or php/html page do I really have to reuse the method up here?
I hope someone can really help me because i have a week left before the deadline and I can't change the project at this point.
chris here the function and the fisrt calling in $param[0] i've got the filename called
function MyInclude($filename)
{
// create the temp file
$temp_filename = "tmp.php";
$handle = fopen($temp_filename , 'w+');
if (!$handle)
die('Error creating temp file');
// write the decrypted data, close the handle
$tmp=file_get_contents($filename);
$data=MCrypt_Decode($tmp,'PFL_EPU_V100_mia');
fwrite($handle,$data );
fclose($handle);
// start output buffering to contain any output the script creates
ob_start();
try {
include($temp_filename);
} catch (Exception $e) {
die('There was an error in the encrypted file, cannot process');
}
// get the output, clear the buffer
$output = ob_get_contents();
ob_end_clean();
//destroy the temp file
unlink($temp_filename);
// now you can output the buffer, if desired:
echo $output;
}
MyInclude($param[0]);
the $param[0] file here
<?php
session_start();
$_SESSION['title']='Home';
MyInclude("header.php");
?>
<body>
sono il body <?php echo APP_PATH; ?>
</body>
<?
echo "boss";
MyInclude("footer.php");
?>
any idea about it??? or you need some other code??? let me know T_T
Mike
You can eval() a string that contains mixed html and php, just so long as the tags are included.
http://php.net/manual/en/function.eval.php
When eval() encounters a php close tag (?>), it will stop trying to treat it as php code and just echo everything out until it comes to a php open tag.
The typical solution to your problem is something like this:
$file = ... //Your decoded php/html code here
$file = '?>' . $file; //Add a close tag to the beginning;
ob_start();
eval($file);
$output = ob_get_clean();
echo $output; //Or do something else with it... really, if you're
//just going to be echoing it you can skip the output buffering
Is it possible to decrypt the page, write it to a file, then include it? That would let the PHP interpreter do what it does best - interpret PHP documents. That will include HTML/PHP combinations without relying on eval.
The outline of that would be:
// create the temp file
$temp_filename = "tmp.php";
$handle = fopen($filename , 'w');
if (!$handle)
die('Error creating temp file');
// write the decrypted data, close the handle
fwrite($handle, $decrypted_data);
fclose($handle);
// start output buffering to contain any output the script creates
ob_start();
try {
include_once($temp_filename);
} catch (Exception $e) {
die('There was an error in the encrypted file, cannot process');
}
// get the output, clear the buffer
$output = ob_get_contents();
ob_end_clean();
//destroy the temp file
unlink($temp_filename);
// now you can output the buffer, if desired:
echo $output;
Function references
fopen: http://us2.php.net/manual/en/function.fopen.php
fwrite: http://us2.php.net/manual/en/function.fwrite.php
fclose: http://us2.php.net/manual/en/function.fclose.php
ob_start: http://us2.php.net/manual/en/function.ob-start.php
ob_get_contents: http://us2.php.net/manual/en/function.ob-get-contents.php
ob_end_clean: http://us2.php.net/manual/en/function.ob-end-clean.php
unlink: http://www.php.net/manual/en/function.unlink.php
You will need dump the decoded file to another file and include(); it. The eval approach will not work because it will exit with a parse error if the first item in the file is not either an opening <?php tag, or a valid bit of PHP code.
More than this, you will need to find/replace any occurences of include(), require(), include_once(), and require_once() within the encrypted file with a different function, to ensure you don't try to execute another encrypted file before it has been decrypted. You could do this at execution (ie decryption) time, but it would be much better to it a encryption time, to minimise the time required to pre-fetch the code before it is executed.
You can define these customised functions to decrypt a file and include/require it in your loader script.
Your problem description is a bit vague however your problem seems to be solvable with output buffering.
Have you tried decrypting the page, then parsing the text to split out anything between and then only executing that code?
I'm trying to write to a file in PHP to cache the output of a small portion of code.
ob_start();
echo "Hello";
$fp = fopen("cache/ttcache.php", 'w');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_flush();
The file exists and is blank. The fwrite function points to the correct location. It just doesn't write.
Any help?
Try to write first small word or sentence first.
fwrite($fp, 'hello')
Also check your file permission's should be writable.
Make sure ob_get_contents() is really not empty. Then try
fflush($fp);
right before fclose().
Am I allowed to have two or more ob_start(); in my php files if so what is the proper way to end one ob_start(); and start another?
From the 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.
In addition to stacking (nesting), you can have separate blocks in sequence.
<?
ob_start();
echo "Foo";
ob_end_flush(); // outputs buffer contents and turns off output buffering
ob_start();
echo "Bar";
ob_end_flush();
?>
You are allowed to do more than one ob_start() on a page. You end ob_start() with ob_end_clean().
ob_start();
$postOutput = preg_replace('/<img[^>]+./','', ob_get_contents());
ob_end_clean();
echo $postOutput;
So, I'm looking for something more efficient than this:
<?php
ob_start();
include 'test.php';
$content = ob_get_contents();
file_put_contents('test.html', $content);
echo $content;
?>
The problems with the above:
Client doesn't receive anything until the entire page is rendered
File might be enormous, so I'd rather not have the whole thing in memory
Any suggestions?
Interesting problem; don't think I've tried to solve this before.
I'm thinking you'll need to have a second request going from your front-facing PHP script to your server. This could be a simple call to http://localhost/test.php. If you use fopen-wrappers, you could use fread() to pull the output of test.php as it is rendered, and after each chunk is received, output it to the screen and append it to your test.html file.
Here's how that might look (untested!):
<?php
$remote_fp = fopen("http://localhost/test.php", "r");
$local_fp = fopen("test.html", "w");
while ($buf = fread($remote_fp, 1024)) {
echo $buf;
fwrite($local_fp, $buf);
}
fclose($remote_fp);
fclose($local_fp);
?>
A better way to do this is to use the first two parameters accepted by ob_start: output_callback and chunk_size. The former specifies a callback to handle output as it's buffered, and the latter specifies the size of the chunks of output to handle.
Here's an example:
$output_file = fopen('test.html', 'w');
if ($output_file === false) {
// Handle error
}
$write_ob_to_file = function($buffer) use ($output_file) {
fwrite($output_file, $buffer);
// Output string as-is
return false;
};
ob_start($write_ob_to_file, 4096);
include 'test.php';
ob_end_flush();
fclose($output_file);
In this example, the output buffer will be flushed (sent) for every 4096 bytes of output (and once more at the end by the ob_end_flush call). Each time the buffer is flushed, the callback $write_ob_to_file will be called and passed the latest chunk. This gets written to test.html. The callback then returns false, meaning "output this chunk as is". If you wanted to only write the output to file and not to PHP's output stream, you could return an empty string instead.
Pix0r's answer is what you want unless you actually need it "included" rather than just executed. For example, if you have login information before the test.php, it will not get passed into the file if you call it with fopen.
If you need it genuinely included, then what you have is the simplest method, but if you want constant output, you'll need to actually write test.php in a manner that outputs as well as stores the information as it goes. As far as I know there's no way to both collect buffer and output it as you go.
Here you go x-send-file, use mod_xsendfile to send file efficiently, really easy.