PHP short_open_tag in php.ini: Enable Short Open Tags + the Short Echo Tag

Featured image illustration for the DevAnswers tutorial: ENABLE PHP SHORT TAGS

We may earn a referral fee at no additional cost to you when you shop through the links on this page.

Legacy PHP code using <? stops working on modern servers: the block renders as raw text in some places, throws a parse error in others. The directive is short_open_tag, off by default on modern Linux. This DevAnswers guide flips it on in the right php.ini, plus answers two recurring questions: is <?= controlled by the same setting, and was the directive removed in PHP 8?

Is <?= Controlled by short_open_tag? 

No. Since PHP 5.4 the short echo tag <?= is always available, regardless of how short_open_tag is set. The PHP manual is explicit about this on its PHP Tags page: <?= is shorthand for <?php echo and is treated by the parser as a permanent part of the language. Every RFC that has proposed deprecating the general short open tag <? has explicitly exempted <?=.

If your application uses only <?= $var ?> for echoing values, you do not need to touch short_open_tag at all. The setting only governs the general open tag <?, which is what triggers the parse errors that bring most readers here.

PHP Open Tag Overview: <?php, <?, <?= 

PHP currently recognises three opening tags. Knowing which one a directive affects saves a lot of guesswork:

  • <?php: the standard tag. Always enabled, portable everywhere, recommended by PSR-1. Code starting with <?php works on any modern server with zero configuration.
  • <?: the short open tag. Controlled by the short_open_tag directive in php.ini. Off by default in php.ini-production; reader-facing modern Linux distributions ship with it disabled.
  • <?=: the short echo tag. Always on since PHP 5.4. Shorthand for <?php echo. Use it freely in templates.

There was also a fourth pair, the ASP-style <% and <%=, controlled by an asp_tags directive added in PHP 3.0.4. Those were removed entirely in PHP 7.0 and have no equivalent today. If you are dealing with an application old enough to use ASP-style tags, the codebase needs to be ported, not configured.

Step 1: Locate Your php.ini File 

Most failed attempts to enable short_open_tag come down to editing the wrong php.ini. A modern Debian-family system keeps a separate php.ini for each SAPI under /etc/php/<version>/<sapi>/:

  • Apache2 (/etc/php/X.Y/apache2/php.ini) (used when Apache runs PHP through the mod_php module, the classic LAMP setup).
  • FPM (/etc/php/X.Y/fpm/php.ini) (used by Nginx, and by Apache when PHP runs through PHP-FPM (FastCGI)).
  • CLI (/etc/php/X.Y/cli/php.ini) (used when you run php from the terminal). Editing this does not affect your web server.

The version segment depends on the distribution. Each current release ships a different default PHP in its repositories, so the path changes with it:

DistributionDefault PHPApache mod_php pathPHP-FPM path
Ubuntu 22.048.1/etc/php/8.1/apache2/php.ini/etc/php/8.1/fpm/php.ini
Ubuntu 24.048.3/etc/php/8.3/apache2/php.ini/etc/php/8.3/fpm/php.ini
Ubuntu 26.048.5/etc/php/8.5/apache2/php.ini/etc/php/8.5/fpm/php.ini
Debian 128.2/etc/php/8.2/apache2/php.ini/etc/php/8.2/fpm/php.ini
Debian 138.4/etc/php/8.4/apache2/php.ini/etc/php/8.4/fpm/php.ini

Pick the column for your stack: Apache with mod_php (the classic LAMP stack many older PHP apps still run on) or PHP-FPM (nginx, or modern Apache through mod_proxy_fcgi). For terminal scripts, use the cli directory instead, for example /etc/php/8.3/cli/php.ini. The edit is identical whichever file you open.

To confirm which file is loaded for the CLI on your own machine, ask PHP itself:

Terminal
php --ini

The output lists every .ini file PHP examined plus the Loaded Configuration File at the end. If you only want that single line, filter for it:

Terminal
php -i | grep "Loaded Configuration File"

This shows you the CLI path. Your web server uses a different one. To see which php.ini Apache or Nginx actually loads, drop a phpinfo() file into your web root and open it in a browser, then look at the Loaded Configuration File row. Delete the file immediately after checking: a public phpinfo() page exposes PHP version, loaded modules, paths, and environment variables to anyone who finds the URL. For a comprehensive guide to all the places php.ini lives on Linux and Windows, see find and edit php.ini.

Step 2: Enable short_open_tag 

Open the php.ini for the SAPI your site runs under. The two common choices are Apache with mod_php (the classic LAMP stack) and PHP-FPM (nginx, or modern Apache via mod_proxy_fcgi); the edit is identical in either file. For Apache with mod_php on Ubuntu 24.04:

Terminal
sudo nano /etc/php/8.3/apache2/php.ini

Press Ctrl + W to start a search, type short_open_tag, and press Enter. You will land on a line that looks like this:

php.ini
short_open_tag = Off

Change Off to On. If the line is commented out (preceded by a ;), remove the semicolon so PHP actually reads it:

php.ini
short_open_tag = On

Save and exit (press CTRL + X, press Y, then press ENTER)

If you are running PHP-FPM (nginx, or Apache via mod_proxy_fcgi) instead, edit /etc/php/8.3/fpm/php.ini with the same change. If you want short tags everywhere (web plus CLI scripts), edit /etc/php/8.3/cli/php.ini too. Each SAPI reads its own file at start-up, so editing one does not affect the others.

Step 3: Restart the Web Service 

PHP only reads php.ini on start-up, so the change does not take effect until you restart the service that loaded the file you edited. For Apache with mod_php, restart Apache:

Terminal
sudo systemctl restart apache2

For PHP-FPM (nginx, or Apache via mod_proxy_fcgi), restart the FPM service instead, matching the name to your PHP version: php8.1-fpm (Ubuntu 22.04), php8.3-fpm (Ubuntu 24.04), php8.5-fpm (Ubuntu 26.04), php8.2-fpm (Debian 12), php8.4-fpm (Debian 13):

Terminal
sudo systemctl restart php8.3-fpm

On RHEL, Rocky Linux, or AlmaLinux the services are named differently: sudo systemctl restart php-fpm for PHP-FPM, or sudo systemctl restart httpd for Apache.

CLI scripts pick up the change immediately because each php invocation re-reads php.ini. Long-running PHP-CLI daemons (queue workers, Laravel Horizon supervisors) need to be restarted too.

Verify <? and <?= Both Work 

Drop a small test file in your web root that exercises all three tag forms:

Terminal
sudo nano /var/www/html/test_tags.php

Paste this content:

test_tags.php
<?php echo "Standard tag: OK" . PHP_EOL; ?>
<? echo "Short open tag: OK" . PHP_EOL; ?>
<?= "Short echo tag: OK" . PHP_EOL ?>

Save and exit (press CTRL + X, press Y, then press ENTER)

Visit http://your-server-ip/test_tags.php and view the page source (Ctrl+U), or fetch it with curl. The server sends each line separated by a newline; a browser collapses those into spaces in the rendered view, so read the source to see the real output. With short_open_tag = On the source shows all three lines:

Output
Standard tag: OK
Short open tag: OK
Short echo tag: OK

This is the diagnostic moment. Flip short_open_tag = Off, restart the service for the SAPI you edited (apache2 for mod_php, or php8.3-fpm for PHP-FPM), reload the page, and view page source (Ctrl+U in most browsers). The browser will hide the unparsed <?...?> token in the rendered view (it parses it as a malformed comment or processing instruction), so a quick reload may look unchanged. Page source reveals the actual server output:

Output
Standard tag: OK
<? echo "Short open tag: OK" . PHP_EOL; ?>
Short echo tag: OK

Notice the <? echo ... ?> block is printed as raw text because PHP no longer recognises it as code, while <?= still works. That is the proof that <?= is unaffected by the directive. Flip the setting back on and reload to confirm the all-three output before continuing. If nothing changes after a restart, check your PHP error log; the PHP error log on Nginx guide covers locating it across the common stacks.

Is short_open_tag Removed in PHP 8? 

No. The directive is still present in PHP 8.0 through 8.5 and still controls the same behaviour it always has. The confusion comes from a 2019 RFC titled Deprecate PHP Short open tags. The RFC initially passed and proposed deprecating <? in PHP 7.4 with removal in PHP 8.0. That deprecation was reconsidered after it was accepted and never took effect, so the directive carried forward unchanged. A follow-up v2 RFC documents the current position: <? remains controlled by short_open_tag, and <?= remains exempt and always available.

What was removed in PHP 7.0 is the ASP-style tag pair (<%, <%=) along with the asp_tags directive that controlled it. If your search for “short open tag removed in PHP 8” lands on a forum thread referencing removal in version 8, it is conflating short_open_tag with asp_tags. Two separate directives, two different fates.

Why ini_set() Won’t Work for short_open_tag 

A common attempt: drop ini_set('short_open_tag', '1'); at the top of a script and avoid editing config files. It does not work. The PHP manual lists short_open_tag with mode PHP_INI_PERDIR, which means it can only be set in php.ini, .htaccess, an Apache httpd.conf block, or a .user.ini file. It cannot be changed at runtime via ini_set().

The reason is fundamental: the directive controls whether <? is recognised as a code-open marker by the parser. By the time any PHP code runs, the parser has already decided how to tokenise the file. Setting a parser directive from inside the parsed file is a chicken-and-egg problem. The only valid places to set it are configuration files PHP reads before tokenising any user code.

Why short_open_tag is Discouraged 

Enabling short_open_tag fixes the immediate parse errors, but it is worth understanding why php.ini-production ships with it disabled and why PSR-1 explicitly forbids it.

XML compatibility. An XML declaration starts with <?xml version="1.0"?>. With short_open_tag on, PHP sees the opening <? and tries to execute the rest as PHP code, which fails with a syntax error. If your application generates XML or RSS, you have to use echo to output the XML declaration. The easier path is to keep short tags off and use <?xml directly.

Portability. Code that relies on short_open_tag works only on servers configured to enable it. Move that code to a shared host or a managed PHP environment and it breaks silently: the unparsed <? ... ?> source ends up in the response body where it is exposed in page source (a leak of your application source code) while the browser silently hides it from the rendered view. Managed-PHP providers like Cloudways standardise on short_open_tag = Off and do not let you override it for the entire account, so applications that depend on it become a migration blocker.

The long-term fix is to convert <? to <?php across the codebase. php-cs-fixer handles this automatically with its full_opening_tag rule, and sed in a pinch can do a literal replacement. If you are upgrading the PHP runtime alongside the application, our upgrade PHP on Ubuntu or Debian guide covers the version-by-version repository steps. For a new Nginx + PHP-FPM build on Debian 12 from scratch, see install PHP-FPM with Nginx on Debian 13.

Wrap up 

Enabling short_open_tag is a one-line directive change in the correct php.ini followed by a service restart, and it is the right immediate fix when a legacy application uses <?. The two things that catch readers out are: the <?= short echo tag has its own rules (always on since 5.4, exempt from every short-tag deprecation discussion), and the directive itself was never removed in PHP 8 despite a 2019 RFC that briefly suggested otherwise. Both <? and short_open_tag remain part of PHP 8.x.

If the application is yours to maintain, plan a migration to <?php. The short open tag is a portability liability and a parser footgun against XML output, and the cost of converting a codebase is a one-time pass with php-cs-fixer. The cost of leaving it in place is paid every time you move servers.

Support DevAnswers
Written, tested and maintained by one developer. Your support keeps these guides accurate and ad-light.
Buy me a coffee

5 replies

Leave a reply

  1. Patanjali

    Just to avoid any confusion, as per https://www.php.net/manual/en/language.basic-syntax.phptags.php:

    As short tags can be disabled it is recommended to only use the normal tags ( and ) to maximise compatibility.

    This means that the setup is not disabled by setting short_open_tag to Off.

    In other words, only the form is disabled, not the form.

  2. Justin

    Thanks it really helped me

  3. Max

    Thank you very much!!!

  4. Aleksandr

    OH MY GAD !
    sudo service php7.2-fpm restart
    HELPS ME!

    Before this i was trying to restart nginx with sudo service php7.2-fpm restart and it was restarted but php.ini changes not appllied.

    Thank you very much!

  5. Tom

    In PHP 7.3 (and upper) directive can be double (in one more places) – be aware about that.