1

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?

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
Norman
  • 6,159
  • 23
  • 88
  • 141
  • 1
    Either in script by `ini_set('key', 'value');` or in .htaccess using `php_value key value` for the settings question. – Skip Dec 24 '22 at 16:18
  • 1
    > Similarly, I'd like to set unique a session.name for each sites. A unique name for every site, for every session or for every session on that site? What do you want to achieve? – Skip Dec 24 '22 at 16:23
  • 1
    ses-sitea for sites.com and ses-siteb for siteb.com – Norman Dec 24 '22 at 16:28
  • 1
    _sitea.com_ and _siteb.com_ are unique already, can't you just use these? Where is this information needed? – Skip Dec 24 '22 at 16:31
  • session_name is PHPSESSID for both sites currently. I'm trying to give sitea.com a session_name of ses-sitea etc. – Norman Dec 24 '22 at 16:37
  • 3
    Please remember that your question should contain all the information. If you're adding new requirements, or additional details, do not use comments for that: [put them in your post](/help/how-to-ask). Also note that the PHP manual [already tells you how to do this](https://www.php.net/manual/en/configuration.file.per-user.php), so: did that not work? Did you try that already? – Mike 'Pomax' Kamermans Dec 24 '22 at 16:37

3 Answers3

2

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...

Guss
  • 30,470
  • 17
  • 104
  • 128
  • 1
    `.htaccess` does work for setting custom ini directives but only for *SOME* PHP installations. If you're using "FastCGI" or "CGI" SAPI then this will infact crash the website with a 500 error – Martin Jan 02 '23 at 18:05
  • 1
    If you're using the FastCGI SAPI you can use a custom `php.ini` location per user or even per directory - check the PHP website for instructions. But the OP clearly said Apache so I didn't mention other options – Guss Jan 02 '23 at 18:07
  • 1
    Yes, @Guss, but Apache is flexible and can run any of the SAPI mentioned. The fact the user is asking this question shows they're probably not too familiar with the deep working of the SAPI so it's worth highlighting if they set values in the `.htaccess` and suddenly the site breaks, there will probably be a bit of "WTF" going on at their end! – Martin Jan 02 '23 at 18:11
1

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.

Martin
  • 22,212
  • 11
  • 70
  • 132
-1

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.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • 1
    This is an overhead for the system and using exec on a JSON file is at best questionable from a security point of view. This approach is not recommended. – Martin Jan 02 '23 at 17:17
  • 1
    @Martin thanks for the comment. I do not see the security issue in this particular case, given the fact that this JSON file is only accessed by trusted developers. I think it's not more risky than having a harmful code being written into a PHP file. If this json would be some third-party file achieved from somewhere then I would agree. As about this being an overhead, it depends. If there are lots of sites being involved and their settings may frequently change, then simplifying the process becomes a primary interest. – Lajos Arpad Jan 02 '23 at 17:21