skip to Main Content

I have multiple sites running on Apache2 and PHP on Ubuntu Server. I know PHP has a php.ini file that lets you set values for upload_max_filesize, max_file_uploads , upload_tmp_dir etc. But that applies one value to all sites.

How can set directives for each site? For Eg: I’d like to set upload_max_filesize to 50M for sitea.com and upload_max_filesize to 5M for siteb.com.

Similarly, I’d like to set unique a session.name for each sites. How can this be done? I read there’s something called PHP_INI_USER, PHP_INI_PERDIR, PHP_INI_SYSTEM, PHP_INI_ALL, so how can I do this?

3

Answers


  1. You can use .htaccess files per site (or even per-folder) to set PHP configuration values – at least for most settings: if you look in the configuration directives documentation, for every setting that is marked as either PHP_INI_PERDIR or PHP_INI_ALL you can set these in a .htaccess file using the php_value or php_flag commands as documented in PHP’s "How to change configuration settings" document.

    For example to set upload_max_filesize in a website, create a .htaccess file at the document root of that website and put in it the text:

    php_value upload_max_filesize 24M
    

    Unfortunately, max_file_uploads and upload_tmp_dir are settings marked as PHP_INI_SYSTEM and you cannot change them in a .htaccess file…

    Login or Signup to reply.
  2. Your settings are in php.ini indeed. Yet, if you have multiple sites to set, then you can set values inside the .htaccess file in the root of the site folder.

    However, you can create a json file somewhere on your server, let’s assume it’s at /path/settings.json of the format of:

    {
        sitename1: {
            setting1: value1
            setting2: value2
        },
        sitename2: {
            setting1: value3
            setting2: value4
        }
    }
    

    Now, you can create a deploy.php file at all your sites that will run cat /path/settings.json via exec, like

    if (exec('cat /path/settings/json', $output, $retval)) {
        $currentSettings = json_decode($output, true)['mysitename'];
    }
    

    You will then have an array of key-value pairs that can be looped and the setting will be known, like:

    $script = "";
    foreach ($currentSettings as $key => $value) {
        $script .= "ini_set('{$key}', '{$value}');n";
    }
    

    and then save $script into a file, let’s call it init.php for now. You require_once this file and then you can maintain a single json file and deploy it per site by running a single cli command. You can even create an sh file that runs all deployment commands so you will be able to deploy everything via a one-liner.

    Login or Signup to reply.
  3. How can set directives for each site? For Eg: I’d like to set upload_max_filesize to 50M for sitea.com and upload_max_filesize to 5M for siteb.com.

    The comment by Mike ‘Pomax’ Kamermans explicitly states how this should be done. However PHP manual documentation can be a little off-putting.

    Also some clarifiers re the other answers here:

    • Using a PHP parser file (as described by Lajos Arpad) adds some security risks and a pile of coding, syntax and some processing overhead that really isn’t needed.

    • .htaccess does work for setting custom ini directives for some PHP installations but if you’re using "FastCGI" or "CGI" (and possibly suPHP) PHP installations then this will infact crash your website with a 500 error, so instead use a local .user.ini file as described here. How do I find out my SAPI?

    • ONLY if you are running PHP as an Apache module (eg mod_php), use .htaccess. How do I find out my SAPI?

    PHP suPHP/FastCGI/CGI SAPI

    So, how should your aspiration be completed?

    1) Look up the Core PHP.ini details.

    Read your PHP.ini file for your current version of PHP.

    Around line 180 (for PHP 8.1) it should say something like this:

    ;==================;
    ; php.ini Options ;
    ;==================;
    ; Name for user-defined php.ini (.htaccess) files. Default is ".user.ini"
    user_ini.filename = ".account-php81.ini"

    Make a note of this value and I would suggest customising this value (as shown in this example). This value is the file name of the file which will sit in each unique account on the server, holding the account specific "local" settings for the global PHP.ini file.

    The file typically sits in the public_html folder so should begin with a . so as to set as hidden by default (see more about this later on). If the file doesn’t exist an an account no core PHP settings are changed.

    2) Remember/Set the Filename and Create the New Rules

    So you now know/ have set the name for your custom PHP file; now generate the file in your account and you can then set the PHP.ini settings you want to customise for this account alone.

    For example;

    file: /home/sitea.com_account/public_html/.account-php81.ini

    Would contain the following example information:

    ;
    ; Some optional comment text here for human consumption
    ;
    session.cookie_secure=1
    session.save_path=/home/sitea.com_account/sessions
    session.name=session-sitea
    error_log=/home/sitea.com_account/errors/PHP_errors.log
    upload_max_filesize=50M
    

    This information is parsed by PHP and overwrites any corresponding values in the core PHP.ini but only for this account.

    3) Customise for Each Account as Needed

    For example, for your siteb.com php user ini file it would look more like this:

    file: /home/siteb.com_account/public_html/.account-php81.ini

    Would contain the following example information:

    ;
    ; Some optional comment text here for human consumption
    ;
    session.cookie_secure=1
    session.save_path=/home/siteb.com_account/session_b
    session.name=site-b-UniqueSession
    error_log=/home/siteb.com_account/errors/PHP_errors.log
    upload_max_filesize=5M
    

    You can then check that these account settings are set correctly by exploring phpinfo() on each account and noting the local and core differences as displayed.

    4) Test And Confirm

    The core user.ini file in the /public_html/ path should be all you need for every child file/folder on that account to process (This can sometimes depend on your exact LAMP server setup and your PHP handler).

    As I say, once you’ve set a test ini file you should run phpinfo() to check its values are implemented.

    If you don’t want to use phpinfo() then you can just as easily use [ini_get](https://www.php.net/manual/en/function.ini-get) to dump sensitive data out to the error log rather than to the browser.

    <?php
    error_log("ini data for this account: ".ini_get('upload_max_filesize'));
    exit;
    

    5) Security

    The user.ini file is typically started with a . character to hide it in the directory, but that doesn’t make it untouchable by browser agents, therefore it’s best practise to add a few lines to your .htaccess to deny access to this file.

    <Files .account-php81.ini>
        Require all denied
    </Files>
    

    Some Final Thoughts:

    Core PHP.ini values do change in new versions of PHP and so this is why it’s best practise to have different local .ini files for different PHP versions (.account-php80.ini, .account-php81.ini, etc.). Note that each php.ini core will need to explicitly call their respective local user.ini file, as referenced in step 1 above.

    The principles of the above are outlined in the PHP Manual and it must be noted:

    If you are running PHP as Apache module, use .htaccess files for the same effect.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search