Why save output until the end? - php

Very quick question about programming practices here:
I've always used echo() to output HTML code to the user as soon as it was generated, and used ob_start() at the same time to be able to output headers later in the code. Recently, I was made aware that this is bad programming practice and I should be saving HTML output until the end.
Is there a reason for this? What is it, and why isn't output buffering a good alternative?
Thanks!

Some thoughts, not necessarily in order.
Using echo to output HTML is messy. PHP is a template language, you can break out of it if you need to output HTML:
<?php echo "<div id=\"foo\">" . $bar . "</div>"; ?>
vs
<div id="foo"><?php echo $bar; ?></div>
Producing HTML first and outputting headers later is messy logic. Decide what you want to send first, then send appropriate headers, then produce the content.
Buffering HTML to send headers later itself is not really a problem, but it's an indicator of badly structured flow.
Your apps could likely benefit from some compartmentalization/breaking down of logical steps.
Look into the MVC pattern.

Whenever any HTML is sent to the browser, headers are received/created. PHP can't send any more headers after this happens. So, by sending code "early", you're disabling PHP's ability to send headers, and limiting the flexibility of your code (either now or for future changes).

It is good to handle all sorts of things before you output in a view - for example, you may need to send additional headers such as Location and Set-Cookie.
Also, you never know what kind of view you will need - this response this time is HTML, but what if you want it as JSON or XML later? You'll have a difficult time restructuring.
If you had left all output to a final view, you could swap the HTML for an XML template.

Related

Are there any limitations on where PHP code can go inside a file?

Can you put PHP anywhere in a file? Inside tags and quotes? For example, is something like this guaranteed to work (even though it isn't always recognized by an IDE's syntax highlighter):
<tr><tbody <?php if(!$row) echo "style='display: none;'"; ?>>
<!-- stuff that we only want to show if $row exists -->
</tbody></tr>
Or for example:
<a href="http://www.google.com/search?q=<?= echo $searchTerm; ?>"</a>
I know I can test this sort of thing on my machine, but I'm wondering if it is guaranteed/defined behavior and if there are any edge cases that don't work that I've missed.
Also, is there good reason not to do this? Is it dangerous because the next person looking at the code might miss it? Should I put a comment in? Does having to add a comment defeat the purpose of this method - succinctness?
Yes you can put the php tags anywhere in the page (html) there is no stopping you on that.
If we go under the hood, your web server sends the code to the php interpreter via a handler and merges the output with your static html file and sends the merged file as the response.
To add to my answer, developers usually go for MVC based frameworks so that the php code inside html page is restricted to only printing the variables and the business logic is performed in the controllers. I personally prefer CakePHP. Apart from that you might not want to put code that manipulates session or performs redirection between html tags else you will recieve the headers already set error as you have already printed certain html code before modifying the headers.

I need to add content at the end of each page

I have a client, whose website has 108 different php static pages, and we need to add some content at the end of each page. I want to avoid doing this manually. Is there any way I can add a link at the end of each page programmatically by using .htaccess or php?
Its a limited hosting account, no ssl
You can use auto_append_file
webbiedave's answer looks simple - but what happens when you append the content to...
<html>
...
</html>
Whether the text is rendered, and how it is rendered will depend very much on the browser. Also, as per the link provided "If the script is terminated with exit(), auto-append will not occur" - while PHP does a good job of cleaning up the resources at exit, it is still good practice to explicitly call exit when the code should terminate.
Although it's still not a generic solution, I'd go with auto prepend script containing something like:
<?php
register_shutdown_function('add_footer');
function add_footer()
{
// try loading a javascript to render the required text
print '<script type="text/javascript" src="/somepath/addfooter.js"></script>' . "\n";
// and for browsers with js disabled but which will render the text include it inline
print '<noscript>' . $include_as_static_text_here . '</noscript>';
}
(IME a script tag appended after the closing html tag is generally acceptable to most browsers even though the resulting html is not well formed - and in the few cases where it is not, the worst that happens is that the script is ignored).
Then in addfooter.js, add the content to the end of the body of the document.
Obviously this will result in the content being sent twice in some cases - solutions to this should be obvious - but I've omitted them for reasons of time and clarity.

<iframe> instead of include

I want to include multiple comments sections on one page using the Commentics php sript.
First I tried accomplishing this using include like so:
<div id="1">
<?php
include "comments_id1.php";
?>
</div>
<div id="2">
<?php
include "comments_id2.php";
?>
</div>
comments_id1.php:
<?php
session_start();
ob_start();
?>
[...]
<?php
$page_id = "1";
$reference = "Page One";
$path_to_comments_folder = "comments/";
define ('IN_COMMENTICS', 'true');
require $path_to_comments_folder . "includes/commentics.php";
?>
(comments_id2.php accordingly: $page_id = "2"; $reference = "Page Two")
Apparently (and it might be worth noting that I'm still pretty clueless when it comes to PHP), this doesn't work or at least leads to all kinds of troubles (e.g. "Warning: Cannot modify header information - headers already sent").
So the solution I came up with was using the <iframe> tag, like so:
<div id="1">
<iframe width="100%" src="comments_id1.php"></iframe>
</div>
<div id="2">
<iframe width="100%" src="comments_id2.php"></iframe>
</div>
Now here's my question:
Is this even a valid solution that anyone would recommend? And if so are there any major consequences (besides search engines) using <iframe> for that purpose?
If this is not the way to go, any suggestions?
Thanks!
Personally I deeply hate IFRAMEs for may reasons, so I'd recommend to stay away from them.
Have you read the Commentics' integration guide?
It seems you have to put
<?php
session_start();
ob_start();
?>
at the beginning of the pag, and
<?php
$page_id = "1";
$reference = "Page One";
$path_to_comments_folder = "comments/";
define ('IN_COMMENTICS', 'true'); //no need to edit this line
require $path_to_comments_folder . "includes/commentics.php"; //no need to edit this line
?>
where you want your comments. There's also an extended integration guide.
i wouldn't use iframes …
to work around the headers problem, you can buffer output (headers can only be sent before the actual content) and then send all at once:
ob_start();
// your code with includes
ob_end_flush();
I'm not familiar with the script you're using, but iframes have some significant downsides. Some downsides to that approach could be:
Iframes need their width and height defined in the HTML tag. If the dimensions inside the Iframe differ (because of an longer than usual comment, for example), you would get extra set(s) of scrollbars.
The memory usage and render times of iframes are high, especially in older Internet Explorer versions
To avoid the "Cannot modify header information" warnings, you could enable output buffering in PHP, or you could look at what headers the script you're using is actually sending. Maybe they're unnecessary?
Another consequence of using iframes is that the rendering may be out of order, since it is an independent HTTP request, and, because it is an additional request, this can add overall time to the retrieval of the data, especially in IE versions before 8 where they were limited to 2 simultaneous HTTP requests at a time--so if you have images or other scripts loading at the same time, some of these may be queued until one or both of the two slots are free. IE8 (and Firefox) boosted this to 6.
While it seems the real solution is looking into them fixing the Commentics script, or you finding another library, despite all advice you will probably find here to the contrary (albeit for good reasons of course), for beginners, I recommend focused on practicality and experimentation rather than dogma; in other words, it could work out all right for you, as long as there are no links inside the iframes which, if clicked, would lead to only the iframe being replaced with the content. Not a best practice though for reasons I and others have mentioned.
Another issue to watch for is that even the slightest whitespace before your beginning <?php is interpreted as text sent to the user, so if a script you include tries to then add headers, you could have problems. The headers being already sent message means that the script has started to send headers since it needed to send them before starting to send the content (in this case the whitespace) which you already started printing out (without buffering).
For PHP, I really recommend a templating engine like Smarty (and Smarty is nicely documented) where you get comfortable with the pattern of letting your business logic run first, and then supplying variables to the design logic for use there (currently what is your HTML + includes). When you're including others libraries which output text, you will need to still use buffering though for such reasons as you discovered.
Just remove:
<?php
session_start();
ob_start();
?>
from comments_id1.php
It will work.

Can't send content-type: text/xml header from PHP at the same time getting the data from MYSQL

i hope you can cast some light on my problem. I need to do an AJAX / PHP / MYSQL application to display posts and stuff on the page i'm writing.
I only discovered how to do some simple stuff in PHP after taking some mushrooms but that was years ago and now i don't have mushrooms and i'm just stuck!
So here's the problem:
i think i need to send a proper "xml" file through php so the ajax part can take it but: when i try to put the header on top of the php it displays this error:
" Extra content at the end of the document "
When i looked at some tutorials people were using the "header" fearlesly to do such stuff as i want to do and no comments suggested that it didn't work. so why it doesn't work on my local server?
I'm running:
WAMP
Apache 2.2.11
PHP 5.3.0
It also doesn't work on a remote server (PHP 5.3.0) :/
I read all the stuff i could find till 5am and decided to ask you for help for the first time :)
Thank you!
header('content-type: application/xhtml+xml; charset=utf-8');
require_once("allyouneed.php");
require_once("bazingablob.php");
$category=$_GET["category"];
$post_tags=$_GET["post_tags"];
$language=$_GET["language"];
$author=$_GET["author"];
$posts_per_page=$_GET["posts_per_page"];
$current_page=$_GET["current_page"];
$order=$_GET["order"];
$hard_limit=$_GET["hard_limit"];
$show_hidden=$_GET["show_hidden"];*/
$wypluj="";
$wypluj="<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>";
$bazinga_blob = new bazingablob;
if (!$bazinga_blob->connect_to_database())
{
$wypluj.="<IsOK>0</IsOK>";
echo $wypluj;
exit;
}
else
{
$wypluj.="<IsOK>jedziem</IsOK>";
}
$bb_result=$bazinga_blob->get_all_posts($category,$post_tags,$language,$author,$posts_per_page,$current_page,$order,$hard_limit,$show_hidden);
if ($bb_result) //udalo sie cos znalezc w bazie wedlug kryteriow
{
$wypluj.="<Pagination>";
$wypluj.="<CurrentPage>";
$wypluj.=$bazinga_blob->posts_pagination["current_page"];
$wypluj.="</CurrentPage>";
$wypluj.="<LastPage>";
$wypluj.=$bazinga_blob->posts_pagination["last_page"];
$wypluj.="</LastPage>";
$wypluj.="<PostsCount>";
$wypluj.=$bazinga_blob->posts_pagination["posts_count"];
$wypluj.="</PostsCount>";
$wypluj.="</Pagination>";
$wypluj.="<Posts>";
foreach ($bb_result as $item)
{
$wypluj.="<Post>";
$wypluj.="<PostId>".$item->post_id."</PostId>";
$wypluj.="<PostAuthor>".$item->post_author."</PostAuthor>";
$wypluj.="<PostLangId>".$item->post_langid."</PostLangId>";
$wypluj.="<PostSlug>".$item->post_slug."</PostSlug>";
$wypluj.="<PostTitle>".$item->post_title."</PostTitle>";
$wypluj.="<PostGreetingPicture>".$item->post_greeting_picture."</PostGreetingPicture>";
$wypluj.="<PostGreetingVideo>".$item->post_greeting_video."</PostGreetingVideo>";
$wypluj.="<PostGreetingSound>".$item->post_greeting_sound."</PostGreetingSound>";
$wypluj.="<PostShort>".$item->post_short."</PostShort>";
$wypluj.="<PostBody>".$item->post_body."</PostBody>";
$wypluj.="<PostDate>".$item->post_date."</PostDate>";
$wypluj.="<PostPublished>".$item->post_published."</PostPublished>";
$wypluj.="<PostSticky>".$item->post_sticky."</PostSticky>";
$wypluj.="<PostComments>".$item->post_comments."</PostComments>";
$wypluj.="<PostProtected>".$item->post_protected."</PostProtected>";
$wypluj.="</Post>";
}
$wypluj.="</Posts>";
}
echo $wypluj;
The error comes from your browser and indicates that your XML is malformed.
Setting the application/xhtml+xml header tells the browser to process the document as serious XML. XML needs to be "well-formed", i.e. it must not contain any syntax errors. Apparently you do have a syntax error on line 1 at column 73, which makes the browser abort the attempt to process the document.
For this reason it's a pain to hand-code XML, you should really look into a library that takes care of the well-formedness for you, like PHP's own XMLWriter.
Have you validated your XML?
http://friendsofed.infopop.net/4/OpenTopic?a=tpc&s=989094322&f=5283032876&m=4521066061
I'm honestly not sure what you're trying to do with the header, it's not any Ajax method I've ever been taught. The header method you're doing looks just a few lines short of outputting the XML to a download prompt.
Here's my favorite way to do AJAX. Simple, understandable, and quick.
Include Jquery.
Setup your data--whether by form with a Serialize (gets form data into a Javascript Variable) or by just setting some variables as it seems you're doing above.
Send via Jquery Ajax to a separate processing page. The page will receive the data you setup as a $_REQUEST variable, with the method depending on whether you defined it as a POST or not (defaults to a GET)
The processing page --does-- stuff with the REQUEST data and may or may not respond back to the page. This is where you can do stuff like update divs, alert that it worked, etc.
Here's a great tutorial. Focus on the code under "Hello Ajax, Meet Jquery"
If you get yourself any more of those mushrooms, a PHP familiar way to do AJAX is with XAJAX. It allows you to do asynchronous calls to PHP functions. Be aware, though, that the forums are not the most english-friendly and documentation is a bit cryptic.

What about calling aspx in php?

Here is my code
<html>
<body>
<?php
include("Default.aspx");
?>
</body>
</html>
but it keeps giving me the output of
<%# Page Language="C#"
AutoEventWireup="true"
CodeFile="Default.aspx.cs"
Inherits="_Default" %> <%
Response.Write("Hello world!"); %>
I just need to run the Hello World on the site.
If you want the output of the aspx file, you will need to request it via a web server which can understand aspx files rather than the file system, e.g.
include("http://example.com/Default.aspx");
Your PHP installation must have URL fopen wrappers enabled for this to work.
As Magnus Nordlander notes in another answer, you should only use include if you expect to find php code in the file. If you don't, you could simply use readfile to output the data verbatim:
readfile("http://example.com/Default.aspx");
You seem to be going about this in a very wrong way.
What include() (and require(), for that matter) does is that it parses the specified file with the PHP interpreter. If your aspx-code for some reason generates PHP-code, which is supposed to be parsed by the PHP interpreter, then the way Paul Dixon suggests would be the right way of going about this. However, I would strongly advice against doing this.
For one thing, it's a huge security disaster waiting to happen. It's also incredibly bad architecturally speaking.
If you want to include HTML markup etc. generated using aspx, what you should do is to use
echo file_get_contents("http://www.example.com/Default.aspx");
This way, any PHP code in the output remains unparsed, thus avoiding the aforementioned security disaster. However, if you're able to do without mixing languages like this, that's probably going to be a much better solution.

Categories