PHP Short Open Tag: Convenient Shortcut or Short Changing Security?
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 theshort_open_tag
configuration is enabled (see popout note below)
<?=
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:
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.
43 responses to “PHP Short Open Tag: Convenient Shortcut or Short Changing Security?”
@Jakub:
Of course, there are many ways to bypass the XML declaration issue when you have PHP short tags enabled. Since the intention of the fix you posted is to fix the problem when short tags are enabled, you could probably shorten your hack by leaving the PHP off altogether.
I haven’t tested, but in theory, any of these should work:
<<??>?xml version="1.0" encoding="utf-8"?>
<<?/*XML*/?>?xml version="1.0" encoding="utf-8"?>
<<?php?>?xml version="1.0" encoding="utf-8"?>
<<?php/*XML*/?>?xml version="1.0" encoding="utf-8"?>
thanks Bill,
i think u r great n i hop u’ll continue to do well.
I have a question ,please someone suggest me.
why we use $ before a varible . a mean is there any logical reason bahind it?
Thanks in advance.
Currently working on a site that is based on Joomla. One of the extensions I intend using requires that I enable the short open tag option in my php.ini.
Am I safe to turn this option on?
I am working on a script, and it gives me trouble when run on Apache under win. Works great on Unix, though. All being said, I will stick to _not_ using short tags. Thanks for the great post!
I must say, there’s nothing wrong with short_open_tag, and it’s not a “bad habit”.
i haven’t used short tags for quite a while up until recently. When you work with MVC, short open tags are comfortable, and i found myself using them more often now.
in MVC btw, when you load a view you can easily replace <?= to <?php echo (same thing is done in code igniter and other frameworks).
imo, if you are sloppy enough to leave short tags in sensitive files and execute it on a server with short tags disabled then you are in the wrong area.
Thank you. That was very helpful. I’ve been using short tags for a while, and had a nagging idea that I should consider it more carefully. I can now use it more intelligently. I still favor them for reasons that Antoine gave early on, but your observations are enlightening (and delightfully unassuming). I love reading folks can distinguish and represent mountains and molehills at proper scale. Again, thanks.