Development

SymfonyPHPsuexec

You must first sign up to be able to contribute.

Running Symfony on a shared server, with PHPsuexec

For those running on a shared host with PHPsuexec, I have found the following information essential. (Note that for performance reasons, it is recommended to run Symfony on a virtual private server, and not on a shared server).

Note these permissions are only relevant to servers with PHPsuexec

This is because under PHPsuexec, the Apache service runs as the same user as the owner of the files. Thus it has full access to them, as it is the same user. If file permissions are set to to 600 on a different server, "permission denied" errors may result.

Security Issues

Following these steps is not enough to prevent Symfony from creating world writable PHP files in which other hosting customers could easily overwrite code and take over your site. Please read and understand Why Symfony is not safe in many shared hosting environments, a patch for some but not all shared hosts, and alternatives to shared hosting before following this HOWTO. You will need to apply a patch to Symfony before you can safely use it in some suPHP environments. Others are safe because they do not allow other customers' files to be found at all via the file system.

How to tell if the shared server is running PHPsuexec

If the host provider hasn't already informed you, carry out the following steps:

  1. Create a file called phpinfo.php with the contents:

phpinfo.php

<?php phpinfo() ?>
  1. Upload phpinfo.php to the root of the webserver.
  2. Point browser at http://yoursite/phpinfo.php
  3. Look for the Server API section (it's the fourth setting). If the value is CGI or CGI/FastCGI then the server is using PHPsuexec.
  4. Once finished, remove phpinfo.php for better security

With PHPsuexec, we have several special requirements, which this document addresses:

  • If a server's default php.ini settings need to be overridden, then each folder that contains any PHP scripts must contain a custom php.ini file, which is used to override the server's php.ini settings.
  • Directories can't have more than 755 permissions
  • Files can't have more than 644 permissions

Further information on PHPsuexec

Introduction to this guide

NOTE This guide requires access to the shared server command line

If your shared host doesn't allow access to the command line, there are some alternatives that can be tried. Please see the appendix section at the end of the guide titled "What to do when shell access is not available"

Directories to be used

In this guide, the public web directory is called public_html. This is the root web directory. This is where pages like CSS (cascading style sheets) and favicon are served from. We will set up our public_html directory with these permissions:

  • public_html directories 755
  • public_html files 644

Our Symfony directories contain all our Symfony libraries. The permissions should be quite restrictive:

  • Symfony directories 700
  • Symfony files 600

Other special permission settings:

  • php.ini 600
  • .htaccess 644

If Symfony skeletons are created on the shared server (via telnet or SSH) (eg php symfony init-module), the file permissions for the created files may be incorrect for PHPsuexec. This is due to a combination of the default umask and Symfony's handling of permissions on newly created files and directories.

This discussion ignores what permissions Symfony sets for files it creates (e.g. via symfony init-project) and simply states how to set appropriate permissions. Instead, we assume that the project is "frozen" via the "symfony freeze" command, then ftped to the server. Permissions are then applied after the ftp to the server.

1) First, a quick note on shared server directory arrangements.

On a shared server it's not a bad idea to move the Symfony libraries to the same level as the public_html folder. One possible configuration (described in the book in Chapter 19, "Modifying the Project Web Root" is as follows (Note that it's also necessary to change a few settings in the configuration files and the front controller, as described in that section of the book, to get this to work):

symfony/
  apps/
  batch/
...
public_html/
  images/
  css/
  index.php

This arrangement also simplifies our tasks, as the public_html and symfony directories will have different permissions applied.

2) If necessary, copy a php.ini override file to each directory that requires it

Shared servers don't always have ideal settings for running Symfony. Here is an example php.ini override file that was required to override some unsafe settings. A php.ini override file with a full list of all safe settings is also provided. Note that most of those settings will not be necessary as many servers will already have the correct values for most settings.

Check existing php.ini settings

To check the existing PHP settings on the server, place a function call to phpinfo() in a single PHP script called phpinfo.php, and point the browser to http://yoursite/phpinfo.php. This can also be called after the php.ini override file is installed, to confirm the desired settings are overridden correctly. Once finished, remove phpinfo.php for better security.

phpinfo.php

<?php phpinfo() ?>

For a production server, it's a good idea to divert PHP error reporting to a file. In this example, we also turn off magic quotes as magic_quotes_gpc is set to "On" on the webserver which was used in this example. The following php.ini file will turn magic_quotes_gpc Off. Note this is an example only. Please create a version of php.ini specific to your needs.

To override default settings, our example file php.ini contains:

php.ini override file, typical settings for a production server

; This is an example php.ini override file
; It contains typical settings used on a production server that already has the correct defaults for most settings
; so only a few need overrides

; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = Off

; Do not print out errors as a part of the output
display_errors = Off

; Log errors to specified file
error_log = /home/myuserid/php_error_log.txt

; error_reporting reporting level
error_reporting  =  E_ERROR|E_WARNING

Here is another version of a possible php.ini. It has most of the appropriate settings required for a secure Symfony website. It's likely that the production webserver has already set most of these correctly. Check which ones are already correct (via http://yoursite/phpinfo.php) and remove them from this php.ini override file. The php.ini override file is read every time a PHP script in that directory is executed, so it will slow down the server. It's best to make it as short as possible and remove what isn't needed.

php.ini override file, version with all Symfony settings (Reminder: We can remove any entries that are already at the correct value, check phpinfo to determine this).

; This version of a php.ini override file has a full list of all the settings required
; for a shared server running Symfony
; Check phpinfo to determine which ones are not needed here

; safe_mode should not be used
safe_mode = Off

; magic quotes should not be used
magic_qutoes_gpc = Off

; register globals should always be off
register_globals = Off

; default value for this is Off anyway but here you go
session.auto_start = Off

; Hide errors from the user, because the error message can contain information about web server you want to hide
; Instead we place them in the log file below
display_errors = Off

; Write error messages to this file, which should be above the public html directory and writeable
error_log = /home/myuserid/sitename_php_errorlog.txt

; Log levels for a production server should be minimal
error_reporting = E_ERROR | E_WARNING

; Send errors to a log file
log_errors = On

; Hide the PHP HTTP header so people examining the website headers don't know if PHP is being used
; Of minimal protection but hey
expose_php = Off

; Turn off error reporting, even at at PHP restart
; Hardly ever going to be of use but could be significant if a webhost is having issues rebooting a box
display_startup_errors = Off

IMPORTANT: REMEMBER TO REMOVE phpinfo.php ONCE php.ini IS WORKING AS DESIRED

Now that we have a nice tight php.ini, it's time to install it on our shared server

Create list of directories that require a php.ini override file

This relies on some cool bash shell magic.

  1. Change directory into the directory above public_html/ and symfony/ (e.g. If the full path to public_html is /home/userid/public_html, then execute cd /home/userid
  2. Place the custom php.ini into this directory.
  3. Run the following commands:
find public_html -name '*.php'  -printf '%h \n' | sort -u > dirlist.txt
find symfony     -name '*.php'  -printf '%h \n' | sort -u >> dirlist.txt

Explanation

The first command searches everywhere in directory public_html for files that match wildcard "*.php". It prints out the directory in which that file is found. The output of this is piped to sort, duplicate entries are removed by the -u flag, and the result is stored in new file dirlist.txt. The second command does almost the same thing, except it starts in directory symfony and appends to dirlist.txt.

  1. dirlist.txt will now contain a list of all directories that contain a PHP script. Let's copy our custom php.ini into these directories with the following command:
for x in `cat dirlist.txt` ; do cp php.ini $x ; echo "Copied php.ini to $x" ; done; echo "Finished"; 

Explanation

Loop through the directories listed on each line of dirlist.txt, for each one copy php.ini into it.

  1. Now point a browser to http://yoursite/phpinfo.php and confirm the required settings are as desired.
  2. If all is OK, delete public_html/phpinfo.php

3) Set required file and directory permissions

From the same directory (parent directory of public_html/ and symfony/) run the following:

This will set all files and directories in symfony/ to be accessible only to the owner:

find symfony/ -type f -exec chmod 600 '{}' \;
find symfony/ -type d -exec chmod 700 '{}' \;

We're going to treat public_html a little differently. The reason for this is that it is set up very carefully by your shared host administrators. We will not touch the permissions on the actual public_html directory itself. Instead, let's cd into it first, and then run find on all files and directories inside it.

This will set all files and directories in public_html/ to be read accessible to everyone (except for php.ini):

cd public_html
find . -type f -exec chmod 644 '{}' \;
find . -type d -exec chmod 755 '{}' \;
find . -name php.ini -exec chmod 600 '{}' \;

The last line just tightens up security a bit; it's actually pretty dangerous to blindly make all files 644, so please ensure there is nothing in public_html that should be visible to the general public. For example, if chmod 600 php.ini isn't run, then browsing http://yoursite/php.ini will reveal the contents of the custom php.ini file!

APPENDIX: What to do when shell access is not available

If shell access is not available, then here are some workarounds.

File permissions

File permissions will be set according to the user's default umask when the file is ftped to the shared server. If the file already exists, it must be deleted first, otherwise it will keep its old permissions. Therefore it may be necessary to delete all files and re-upload them to reset their permissions.

Also, some ftp clients can be used to set file permissions. For example the Firebug extension for Firefox. Simply select the required files (more than one if necessary), right-click, choose Properties, then set the permissions. They can be made to propagate to subdirectories too.

To copy php.ini to each directory that needs it

On a Unix (or Linux) development box: Build a pre-production environment that is identical to the structure you will use in production. Then follow the guide, and once done, ftp. Note the file permissions of the local files will not be respected, the file permissions will behave as described in the above step.

On a Windows development box: This guide has been tested with Cygwin for the php.ini copying step. Note the file permissions of the local files will not be respected, the file permissions must be set as described in the above step File permissions.

Further Assistance

Please log any problems in the Symfony installation forum.