Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

PHP Short Open Tag: Convenient Shortcut or Short Changing Security?

[ Echo Shortcut Code ] Most of us learned how to use “echo()” in one of our very first PHP tutorials. That was certainly the case for me. As a consequence, I never really had a need to visit PHP’s documentation page for echo(). On a recent visit to Perishable Press, I saw a Tumblr post from Jeff about the use of PHP’s shortcut syntax for echo() but somewhere deep in my memory, there lurked a warning about its use. I decided to investigate.

My first step in the investigation was to visit PHP’s documentation, where I learned:

  • echo() is a language construct, not a true function
  • if I pass echo() more than one parameter, I cannot use parentheses
  • echo() has a shortcut syntax (<?=$variable?>), but it requires that the short_open_tag configuration is enabled (see popout note below)
Editor’s Note: According to the PHP docs, the <?= tag always is available regardless of the short_open_tag ini setting.

Recalling that I had once heard something about the insecurity of enabling the short_open_tag, I googled away. I saw a lot of opinions, but no real hard facts or examples showcasing any possible problems. It was time to experiment.

Using an Ubuntu Ibex box with PHP 5 on the Apache 2.2 server, I created a PHP document which contained only the following code:

<?
	$username = "username";
	$password = "password";
	$message1 = "<p>This is my primary message.</p>\n";
	$message2 = "<p>This is my secondary message.</p>\n";
	$message3 = "<p>This is my tertiary message.</p>\n";
?>
<?=$message1?>
<?=$message2?>
<?=$message3?>

As you’d expect, I saw the following output in my browser:

<p>This is my primary message.</p>
<p>This is my secondary message.</p>
<p>This is my tertiary message.</p>

This seemed fine to me, so I decided to go into my php.ini file and disable short_open_tag and see what happened. On line 77, I found this ominous and foreboding harbinger of doom:

; Allow the <? tag.  Otherwise, only <?php and <script> tags are recognized.
; NOTE: Using short tags should be avoided when developing applications or
; libraries that are meant for redistribution, or deployment on PHP
; servers which are not under your control, because short tags may not
; be supported on the target server. For portable, redistributable code,
; be sure not to use short tags.
short_open_tag = On

I guess it’s not really all that ominous but why wasn’t it in the PHP documentation? Anyway, a quick toggle…

short_open_tag = Off

…and back to the browser resulted in this unexpected output:

<?
	$username = "username";
	$password = "password";
	$message1 = "<p>This is my primary message.</p>\n";
	$message2 = "<p>This is my secondary message.</p>\n";
	$message3 = "<p>This is my tertiary message.</p>\n";
?>
<?=$message1?>
<?=$message2?>
<?=$message3?>

All of my PHP code was silently output directly to the browser, completely ignored by PHP! No runs, no hits, no errors. “Not good,” I thought. So, I changed the code a little bit to ensure that PHP was still functioning properly. So now this bit of PHP code:

<?php
	$username = "username";
	$password = "password";
	$message1 = "<p>This is my primary message.</p>\n";
	$message2 = "<p>This is my secondary message.</p>\n";
	$message3 = "<p>This is my tertiary message.</p>\n";
?>
<?=$message1?>
<?=$message2?>
<?=$message3?>

…resulted in this output:

<?=$message1?>
<?=$message2?>
<?=$message3?>

Obviously, this is a contrived example. Programmers don’t hardcode sensitive information like that. We ARE all keeping our MySQL connection scripts outside the web root anyway, right? Still, it doesn’t produce the results we want.

Modifying both code blocks to use the full syntax fixed this:

<?php
	$username = "username";
	$password = "password";
	$message1 = "<p>This is my primary message.</p>\n";
	$message2 = "<p>This is my secondary message.</p>\n";
	$message3 = "<p>This is my tertiary message.</p>\n";
?>
<?php
	echo $message1,
	     $message2,
	     $message3;
?>

…reliably and predictably resulting in this output (regardless of the short_open_tag configuration):

<p>This is my primary message.</p>
<p>This is my secondary message.</p>
<p>This is my tertiary message.</p>

To ensure short_open_tag was set to “off”, I also added this block to my central HTAccess file:

php_flag short_open_tag off

On my system, at least, I was able to use the HTAccess file to toggle this configuration. The short_open_tag configuration cannot be toggled using ini_set(), although you can test against it by using ini_get("short_open_tag").

Comma here, I wanna show you something…

Those of you with keen eyes may have also noticed my use of commas to separate instead of periods to concatenate my variables in that last echo(). I tend to use commas because once again, they produce more predictable and reliable results. Consider the following:

<?php
	function echo_message () {
		echo "I am a message.";
	}
	echo "<p>Message: ".echo_message()."</p>";
	echo "<p>Message: ",echo_message(),"</p>";
?>

You’d probably expect the output to look like this:

<p>Message: I am a message.</p>
<p>Message: I am a message.</p>

…but what you actually get is this:

I am a message.
<p>Message: </p>
<p>Message: I am a message.</p>

This is a result of echo()’s special place as a language construct. When using concatenation, echo() must first evaluate the full, concatenated parameter before proceeding. When it does that, it triggers the echo() inside our echo_message() function which is immediately output to the browser before our first echo() has had a chance to complete its evaluation. Thus, we get the mixed up order of our output. In the second example, our first echo() evaluates and outputs each parameter individually. Since echo() itself actually returns NULL, from PHP’s point of view, our code looks more or less something like this:

<?php
	echo_message();
	echo "<p>Message: ".NULL."</p>";
	echo "<p>Message: ";
	echo echo_message(); # outputs "I am a message." and returns null
	echo "</p>";
?>

To produce more predictable results, we could also do this:

<?php
	function return_message () {
		return "I am a message.";
	}
	echo "<p>Message: ".return_message()."</p>";
	echo "<p>Message: ",return_message(),"</p>";
?>

…which will now produce exactly what we want:

<p>Message: I am a message.</p>
<p>Message: I am a message.</p>

Download/Demo

Check out the demo files that show some examples for this tutorial:

Note: the demo files require PHP to work properly. Please don’t host these files on a live production server — for private use only. Disclaimer: by downloading the demo files, you accept all liability for use and agree not to sue anyone.

Conclusion

The idea of an echo() shortcut is brilliant. It might be more useful had it been carried through so that <?php=$something?> would also result in output being echoed to the browser. In its current incarnation, I find it too unpredictable to be used in a production level application.

That’s my opinion, but the real question was: Are short open tags (and therefore the echo shortcut) security risks?

Anything that doesn’t produce predictable, reliable results can be problematic. Using short open tags when they are disabled produces no error or warning message of any kind. It simply fails, outputting your code directly and silently. In contrived examples, this can show devastating results. In real life, it’s more likely to be annoying than catastrophic. The most important thing is to be aware of it. Then, you can decide for yourself.

About the Author
Bill is the creator of WebDevelopedia.com and is an active member of several discussion lists, including the CSS Discussion List. When not online, Bill can be found enjoying the company of his girlfriend, Jessica and their dog, Leica (she doesn’t have a web site).
Banhammer: Protect your WordPress site against threats.

43 responses to “PHP Short Open Tag: Convenient Shortcut or Short Changing Security?”

  1. kanwaljit singh 2009/08/19 7:25 pm

    I totally agree with bill, as we know that support for short tags might be discontinued in future(at least its not going to be set to on for default), its better to avoid it if u dont have access to your php.ini or if you want to make portable scripts for distribution or selling.

    For that reason I always turn off short tags option on my development PC’s Php.ini.

    Really nice and detailed article :-)

  2. hi how r u …i have the problem with php .. the page is not display the data but it display the header and footer
    i am totally confused what is the problem .. the code is working on other machine but not working on my machine. i installed wamp server which is working.

  3. i have a problem in PHP. i installed my project in a linux OS. then when i click one of the menu on my project, a window will pop up asking me if i want to open the *.php..Is there any concern with the rights?

  4. “All of my PHP code was silently output directly to the browser, completely ignored by PHP! No runs, no hits, no errors.”

    Perhaps you forgot to restart Apache after changing php.ini?

    Regards,

    Marcos.

  5. Well, I’ll be…..

    You learn something new every day!
    I’m a code minimilist so this will be usefull for me, thanks :)

  6. Jakub Lédl 2010/01/03 3:26 pm

    Sorry, sir, but few of your programming techniques really made me wonder what kind of programmer are you.

    WTF is supposed to be this:

    function echo_message() {
           echo "Message."
    }

    echo "blah", echo_message(), "blah"

    This has nothing to do with echo beign a language construct, this is just stupid! I mean, if ... elseif ... else is also an language construct, and still you would write

    function create_cond() {
           return true;
    }

    if (create_cond()) {
           ...
    }

    and not

    function create_cond() {
           echo true;
    }

    so that the value is returned, not echoed (if you won’t, then you totally don’t grasp basic concepts of programming. How do you ever wanna do OOP?)!

    And also, I found quite interesting this:

    if (!!ini_get("short_open_tags")) {

    why not just

    if (ini_get("short_open_tags")) {

    ???

  7. Bill Brown 2010/01/03 3:34 pm

    @Jakub

    The examples in this article are contrived as an attempt to isolate the behaviors of the echo language construct.

    I fear you’ve missed the point of the article but am happy to answer any of your questions directly, including any related to OOP, as I code solely using object oriented programming techniques.

    Thanks for your feedback and sorry the information wasn’t more clear to you.

  8. Dave Coleman 2010/01/06 11:36 am

    It seems to me the short tags security problem was completely artificially created by the PHP Development Team by making the setting optional. Had they made short tags always on by default when this issue began years ago, there wouldn’t be any of these ‘security’ issues.

    And the xml tag opener issue is just one single line of code at the top of xml files that can easily be worked around with about 6 characters of code ONCE, instead of adding 7 characters of code every time you want to output a variable, in particular “<?php echo” instead of “<?=”.

  9. Jakub Lédl 2010/01/06 12:04 pm

    My apologies, I misunderstood the point of this article.

    As for the problem with xml declaration, nicest solution I’ve seen so far is this:

    <?xml version="1.0" encoding="utf-8" ?>

  10. Thanks for the tip.

  11. AT Jakub <?xml such as that on http://www.sourcepod.com/idhblx03-2718

    Why is it nice? Is it an OOP solution? Just kidding.

  12. Jakub Lédl 2010/02/05 12:55 pm

    Oh sh*t, I came back. What happened to that code I posted? Does this CMS remove PHP from comments or what? I now look like an idiot :-)

    This is what I meant:

    http://www.sourcepod.com/idhblx03-2718

    Edit: <<?php ?>?xml version="1.0" encoding="utf-8"?>

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
Banhammer: Protect your WordPress site against threats.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.