Streaming output to a file and the browser - php

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.

Related

How to write file checking code for best performance

Is there any appreciable difference, in terms of speed on a low-traffic website, between the following snippets of code?
$html = file_get_contents('cache/foo.html');
if ($html) {
echo $html;
exit;
}
Or this:
$file = 'cache/foo.html';
if (file_exists($file)) {
echo file_get_contents($file);
exit;
}
In the first snippet, there's a single call to file_get_contents() whereas in the second there's also a call to file_exists(). The page does involve database access - and this caching would avoid that entirely.
It will be unnoticeably slower on a low-traffic website; but there is no reason to perform that check anyway if you're going to get the contents if it exists, since file_get_contents() already performs that check behind-the-scenes, returning false if the file doesn't exist.
You can even put the call to file_get_contents() directly inside the condition:
if ($html = file_get_contents('cache/foo.html')) {
echo $html;
exit;
}
The runtime differences are so minimal for both variants that it does not matter in practice.
The first variant is slightly faster if the file exists. The second variant is faster if the file does not exist.
Both solutions do not have the best performance because the entire HTML is first loaded into memory before the output is done with echo. Better is:
$ok = #readfile ('cache/foo.html');
With readfile the file is output directly or without detours. The # operator suppresses the warning if the file does not exist.
$ok contains the number of bytes output if the output was successful and false if the file does not exist.

Store PHP Output To File?

I'm working on a cron php script which will run once a day. Because it runs this way, the output from the file can't be seen.
I could literally write all the messages I want into a variable, appending constantly information I want to be written to file, but this would be very tedious and I have a hunch not necessary.
Is there a PHP command to tell the write buffer to write to a log file somewhere? Is there a way to get access to what has been sent to the buffer already so that I can see the messages my script makes.
For example lets say the script says
PHP:
<?
echo 'hello there';
echo 'hello world';
?>
It should output to a file saying: 'hello therehello world';
Any ideas? Is this possible?
I'm already aware of
file_put_contents('log.txt', 'some data', FILE_APPEND);
This is dependent upon 'some data', when I don't know what 'some data' is unless I put it in a variable. I'm trying to catch the results of whatever PHP has outputted.
You may want to redirect your output in crontab:
php /path/to/php/file.php >> log.txt
Or use PHP with, for example, file_put_contents():
file_put_contents('log.txt', 'some data', FILE_APPEND);
If you want to capture all PHP output, then use ob_ function, like:
ob_start();
/*
We're doing stuff..
stuff
...
and again
*/
$content = ob_get_contents();
ob_end_clean(); //here, output is cleaned. You may want to flush it with ob_end_flush()
file_put_contents('log.txt', $content, FILE_APPEND);
you can use ob_start() to store script output into buffer. See php documentation ob_get_clean
<?php
ob_start();
echo "Hello World";
$out = ob_get_clean();
$out = strtolower($out);
var_dump($out);
?>
If You're using cron I suppose that You run this on a Unix machine so:
One of approach is to write everything You want to stdout stream so in Unix You may grab this output to a file:
in php script:
$handle = fopen("php://stdout","w");
fwrite($handle,"Hello world"); // Hello world will be written to console
in cron job grab this output to a file:
#hourly php /var/www/phpscript.php >> /path/to/your/outputfile.txt
Notice: >> operator will append to a file and > operator will overwrite file by new data. File will be created automatically by first write
So everything you put to fwrite call as second argument will be placed in /path/to/your/outputfile.txt
You may call fwrite as many time as you want. Don't forget to close handler by fclose($handle);

Php ob_get_contents() returns empty string if the included file during buffering is not small

Let's say i have a file consisting of 5 lines of text and every line has 50 chars. The output buffer contents are returned correctly but if I have a file containing 100 lines of text the output buffer returns empty string (string with value null).
I do it like so:
ob_start();
include "file.php"
$string = ob_get_contents();
ob_end_clean();
OR
$string = $this->load->view('view', $data, true);
Im doing this inside codeigniter if that makes any difference.
I tried to load the file with Code igniter's load->view function with third parameter set to true the result is the same. Tried also giving ob_start() a big number -> ob_start(9999999); same result;
I'd propose to use ob_get_flush to ensure, that nothing is still kept in some internal buffer..
Quite unlikely, but what does this instead of your code print?
require_once( "file.php" );
Just to ensure, that the stuff in file.php isn't surrounded by <?php /** **/ php?>.
And what does
echo ob_get_level();
output just before your code? Shouldn't be relevant, if other outbut-buffering is already enabled, but...
Why are you using ob functions to get the contents of a file? Why not file_get_contents?
you have just to add some lines in index.php (the root of CodeIgniter)
ob_start();
/*
*---------------------------------------------------------------
* APPLICATION ENVIRONMENT
*------------
+
require_once BASEPATH.'core/CodeIgniter.php';
$data = ob_get_contents();
ob_clean();
echo $data; /// or anything else
that's all !

Php problem eval/html/php

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?

Generate php source code based on php array

I've got a non-modifiable function which takes several seconds to finish.
The function returns an array of objects. The result only changes about once per day.
To speed things up I wanted to cache the result using APC but the hosting provider(shared hosting environment) does not offer any memory caching solutions (APC, memcache, ...).
The only solution I found was using serialize() to store the data into a file and then deserializing the data back again.
What about generating php source code out of the array? Later I could simple call
require data.php
to get the data into a predefined variable.
Thanks!
UPDATE: Storing the resulting .html is no option because the output is user-dependant.
Do you mean something like this?
// File: data.php
<?php
return array(
32,
42
);
// Another file
$result = include 'data.php';
var_dump($result);
This is already possible. To update your file, you can use something like this
file_put_contents('data.php', '<?php return ' . var_export($array, true) . ';');
Update:
However, there is also nothing wrong with serialize()/unserialize() and storing the serialized array into a file.
Why not just cache the resulting html page that is generated? You could do that fairly simply:
// Check to see if cached file exists
// You could run a crob job to delete this at a certain time
// or have the cache file expire after a set amount of time
if(file_exists('cache.html')) {
include('cache.html');
exit;
}
ob_start(); // start capturing output buffer
// do output
$output = ob_get_contents();
$handle = fopen('cache.html', 'w');
fwrite($handle, $output);
fclose($handle);
ob_end_flush();
You could just write the answers to a database, and use the function arguments as key.

Categories