Introduction
Your php.ini file provides a considerable amount of power over the behavior of your PHP application ecosystem. Let’s jump into some of the most common declaratives and discuss how they impact your application performance and behavior. I won’t go into an explanation of each setting that is available, but I’ll cover the fundamental options that you should be aware of. Please keep in mind that changing any of the settings on in your php.ini can and may very well change the behavior of your application, whether positive or unfavorable. Please use caution when adjusting your settings, consult with your team, do your research, understand the implications, and, of course, test, test, and test again before deploying anything into production!
What is php.ini?
As with all complex software applications, the behavior of your PHP runtime can be configured using a php.ini file. This is the file that instructs how PHP should behave before executing your PHP application code. Your php.ini is ordinarily located in the ./lib directory of where you installed PHP. For example, if you installed php in /usr/local/, you can find the php.ini in /usr/local/php/lib.
Alternatively, you can find it yourself by turning to our all-helpful-utility-function:
<?php phpinfo(): ?>
Look for the line “Loaded Configuration File:”; this is the path to where your php.ini file resides.
I’ve organized this post into the following categories: security, memory, and performance. If you’re interested in only one aspect, feel free to jump to that category.
Basics
You can edit your php.ini file directly. However, depending on how your environment is set up, you can share the same PHP runtime but have different settings per application. Specifically, if you’re running virtual hosts with Apache, for example, you configure your server to allow a .htaccess file per application directory with specific php declaratives to override the default php.ini settings. Furthermore, you can also override php.ini settings from within the application itself in-flight via ini_set(). Keep in mind, ini_set() is only used during the lifetime execution of the script and will not persist its value permanently.
What does php.ini affect? It affects everything. Well, almost everything: you may have additional config files (e.g. apc.ini) for various libraries and tools you’re using (check with your system administrator if you’re trying to configure something that is not located within your php.ini). Generally speaking, your php.ini holds the keys to settings that impact your application security, speed, and user experience. We’ll cover some of the basics and understand why they’re important, and dive deep into how you can optimize your environment to reach your objectives. We’ll begin with a couple simple examples: short_open_tag and error_reporting.
short_open_tag
This tag is one of my favorites – it allows you to use shorthand <? instead of <?php when opening PHP code. With this shorthand, you can trim your PHP code in your HTML when you need to do something like this:
Hello, <?=$firstname>!
If you use PHP in your HTML, you can trim embedded code to make it become more readable.
error_reporting
PHP has multiple levels of errors: E_ALL, E_NOTICE, E_WARNING, etc. This directive allows you to decide the error pain threshold. You want different levels in your various environments, but try to be the most strict in development and the least in production.
A common trick that some developers are unaware of is to convert your errors into exceptions. Using this method, you can “catch” your errors and “handle” them as you normally would. This is made possible by using theErrorException class with the set_error_handler() function. Furthermore, use this setting in conjunction with display_errors when configuring how to handle displaying errors in production. Tuning this directive is best when optimized with complimentary settings.
Note: setting error_reporting to E_ALL or -1 will show all possible errors, but this depends on your version of PHP. Be sure you understand the differences.
Security
register_globals
This is reasonably one of the most dangerous directives in PHP. When this setting is turned on, it allows input data – such as POST or GET – to be accessible via the $_REQUEST variable. Imagine, for instance, an application setting a user type as “admin” in a cookie variable and that value is accessed via $_REQUEST[‘access_level’]. If a malicious user were to pass ‘?access_level=admin’ in the URL, $_REQUEST could potentially read that as the access level. This directive went from ON to OFF by default in PHP 4.2 and removed it in 5.4, so the industry has heavily matured away from this dangerous practice. Nonetheless, this is something that you should be aware of in legacy code.
magic_quotes_gpc
I won’t expand too much on this as this has been deprecated since PHP 5.4, but it is something you should note in legacy code. This declarative automatically adds a ‘\’ to help escape special characters. Unfortunately, this created a nightmare when you have addslashes() and stripslashes() throughout your code, and you’re ripping your hair out trying to keep track of when and how PHP is magically manipulating your data (pun intended). In short, turn this off, and forget it ever existed. You should manually escape input from public variables via other means when needed.
expose_php
When set to ‘On’, this will expose to the public that you’re running PHP and the version number via X-Powered-By: in the HTTP header. If this is turned on, you’re exposing yourself to security threats that may be exposed by your version of PHP or exposing that you’re running PHP itself. Keep it off and don’t let the public know what you’re running under the hood. The less that hackers know about your environment, the less of a strategy they have on how to attack you.
Memory
output_buffering
This setting controls how your HTML is sent to the browser. When turned off, the HTML is sent to the browser in pieces as PHP combs through the execution sequence and stitches your dynamic and static content together. When turned off, your HTML is turned into a single variable and sent to the browser in one giant piece. While you’re piecing your HTML together, the bits live in a buffer “zone”, and you’re still provided access to the data before it’s finally sent to the browser. Thus, if you experience an error during execution, you can choose to send the user a friendly error message instead of a half interpreted broken HTML page. This setting is advantageous because it allows you to manipulate your HTML the same way you would manipulate a string in PHP, so you have greater control. In the MVC paradigm, you can benefit from stitching together partial modular components that put together the final view.
max_execution_time
When a request comes in and PHP begins to execute your code, it takes time to complete the transaction. In some situations, you may have an execution stack that takes too long. This can happen for various reasons such as bad code, a hung database, or slow responses from third-party web service APIs. As a failsafe, PHP allows you to mitigate this risk by capping the execution time to whatever value you set here. If your threshold is high, your customers will naturally suffer from poor performance, regardless. I would recommend setting this value to enough time to reasonably capture diagnostic data for the holdup, but not too long to where the customer has to wait for minutes for a page to load because, they won’t, of course. If you’re finding that your code is executing for too long, it may be time to collect diagnostic data with theAppDynamics for PHP agent.
Note: You can set this value to 0 for infinite time, but that is not a good idea in production for obvious reasons. Do not do this. There is a native function that allows you to override this value. If you need to override it in certain scenarios, you may explore the set_time_limit() function which effectively performs the same function ad hoc.
memory_limit
In addition to the amount of time your PHP script takes to execute, there is also an amount of memory that your script will consume. This setting will set a maximum allowed quantity of memory to be allocated to the script so that if your script is running havoc, you can cap it and protect your server resources.
Note: I’ve seen certain cases where memory_limit is set to -1, which allows for unlimited memory. This is also, of course, a bad idea. Use the -1 setting only in development and testing environments, if and when needed.
upload_max_filesize
This declarative allows for the maximum file size allowed to be uploaded from the server. As a matter of good practice, I think the jury has already ruled on this one: don’t rely on the server alone to verify file size; check this first on the client side. Historically, a form would upload an entire file to the server before it was accepted or rejected. This means a user could upload a 500mb file, tie up server resources, be at the mercy of their Internet upload speed, and then finally have their inputs rejected. Imagine if their form failed validation because of an improper email address: they would have to repeat the process. A good programmer caches the uploaded file on the server side so as not to wait for the file to upload again, but if the user uploads a different file, the wait time will have to repeat. This is a dangerous practice and a potential loophole for hackers too.
post_max_size
This sets the maximum size of the entire POST data being sent. The difference between this and upload_max_filesize is that this regulates the whole size of the data being sent to the server, whereas the latter governs the size of an individual file. Adjust this accordingly.
max_input_time
This is the maximum amount of time a script is allowed to parse input data, whether POST or GET. Essentially, this is the maximum amount of time you’re allowing an upload to complete. For example, if you set this to 60, the upload must finish within 1 minute. This is a challenge for users with slow Internet connections, but the advantage for you is to make sure your server resources have a fail-safe measure to avoid being tied up.
include_path
This defines all the various system paths that PHP will need to look when you include files in PHP (e.g. require(), include(), etc.). The shorter this list, the better your performance since you won’t have to spend so much time searching for files.
Conclusion
In addition to the php.ini declaratives mentioned in this post, there are dozens of other declaratives that can help further fine-tune and tailor your PHP ecosystem to find the perfect balance of security, performance, scalability, and optimal user experience. This is only a mere introduction into the capabilities afforded to you by your php.ini settings and meant to get you to become comfortable with the various configurations that could impact you in critical ways. However, when you configure your PHP, always remember that your goal is to strike the right balance without sacrificing the end-user experience. Application performance is a moving target, and the better you’re aware and equipped with the means of reaching an optimal user experience, the happier you and your customers will be.