ftimme
2012-04-18 2743621223d852cca4dad85aa6b026870f96d17f
- Added PHP-FPM support for Apache.
6 files modified
303 ■■■■■ changed files
interface/web/admin/templates/server_config_web_edit.htm 10 ●●●● patch | view | raw | blame | history
interface/web/sites/ajax_get_json.php 9 ●●●●● patch | view | raw | blame | history
interface/web/sites/form/web_domain.tform.php 2 ●●● patch | view | raw | blame | history
interface/web/sites/templates/web_domain_advanced.htm 17 ●●●● patch | view | raw | blame | history
server/conf/vhost.conf.master 17 ●●●●● patch | view | raw | blame | history
server/plugins-available/apache2_plugin.inc.php 248 ●●●●● patch | view | raw | blame | history
interface/web/admin/templates/server_config_web_edit.htm
@@ -121,23 +121,23 @@
          <label for="php_ini_path_cgi">{tmpl_var name='php_ini_path_cgi_txt'}</label>
        <input name="php_ini_path_cgi" id="php_ini_path_cgi" value="{tmpl_var name='php_ini_path_cgi'}" size="40" maxlength="255" type="text" class="textInput" />
      </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder">
          <label for="php_fpm_init_script">{tmpl_var name='php_fpm_init_script_txt'}</label>
        <input name="php_fpm_init_script" id="php_fpm_init_script" value="{tmpl_var name='php_fpm_init_script'}" size="40" maxlength="255" type="text" class="textInput" />
      </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder">
          <label for="php_fpm_ini_path">{tmpl_var name='php_fpm_ini_path_txt'}</label>
        <input name="php_fpm_ini_path" id="php_fpm_ini_path" value="{tmpl_var name='php_fpm_ini_path'}" size="40" maxlength="255" type="text" class="textInput" />
      </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder">
          <label for="php_fpm_pool_dir">{tmpl_var name='php_fpm_pool_dir_txt'}</label>
        <input name="php_fpm_pool_dir" id="php_fpm_pool_dir" value="{tmpl_var name='php_fpm_pool_dir'}" size="40" maxlength="255" type="text" class="textInput" />
      </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder">
          <label for="php_fpm_start_port">{tmpl_var name='php_fpm_start_port_txt'}</label>
        <input name="php_fpm_start_port" id="php_fpm_start_port" value="{tmpl_var name='php_fpm_start_port'}" size="40" maxlength="255" type="text" class="textInput" />
      </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder">
          <label for="php_fpm_socket_dir">{tmpl_var name='php_fpm_socket_dir_txt'}</label>
        <input name="php_fpm_socket_dir" id="php_fpm_socket_dir" value="{tmpl_var name='php_fpm_socket_dir'}" size="40" maxlength="255" type="text" class="textInput" />
      </div>
interface/web/sites/ajax_get_json.php
@@ -88,6 +88,15 @@
        if(substr($json,-1) == ',') $json = substr($json,0,-1);
        $json .= '}';
    }
    if($type == 'getphptype'){
        $json = '{"phptype":"';
        $sql = "SELECT php FROM web_domain WHERE domain_id = $web_id";
        $php = $app->db->queryOneRecord($sql);
        $json .= $php['php'];
        unset($php);
        $json .= '"}';
    }
//}
interface/web/sites/form/web_domain.tform.php
@@ -208,7 +208,7 @@
            'formtype'    => 'SELECT',
            'default'    => 'fast-cgi',
            'valuelimit' => 'client:web_php_options',
            'value'        => array('no' => 'disabled_txt', 'fast-cgi' => 'Fast-CGI', 'cgi' => 'CGI', 'mod' => 'Mod-PHP', 'suphp' => 'SuPHP')
            'value'        => array('no' => 'disabled_txt', 'fast-cgi' => 'Fast-CGI', 'cgi' => 'CGI', 'mod' => 'Mod-PHP', 'suphp' => 'SuPHP', 'php-fpm' => 'PHP-FPM')
        ),
        'fastcgi_php_version' => array (
            'datatype'    => 'VARCHAR',
interface/web/sites/templates/web_domain_advanced.htm
@@ -20,25 +20,25 @@
          <label for="allow_override">{tmpl_var name='allow_override_txt'}</label>
        <input name="allow_override" id="allow_override" value="{tmpl_var name='allow_override'}" size="30" maxlength="255" type="text" class="textInput" />
      </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder phpfpm">
                <p class="label">{tmpl_var name='php_fpm_use_socket_txt'}</p>
                    <div class="multiField">
                        {tmpl_var name='php_fpm_use_socket'}
                    </div>
            </div>
      <div class="ctrlHolder nginx">
      <div class="ctrlHolder phpfpm">
          <label for="pm_max_children">{tmpl_var name='pm_max_children_txt'}</label>
        <input name="pm_max_children" id="pm_max_children" value="{tmpl_var name='pm_max_children'}" size="3" maxlength="3" type="text" class="textInput formLengthLimit" />
            </div>
    <div class="ctrlHolder nginx">
    <div class="ctrlHolder phpfpm">
          <label for="pm_start_servers">{tmpl_var name='pm_start_servers_txt'}</label>
        <input name="pm_start_servers" id="pm_start_servers" value="{tmpl_var name='pm_start_servers'}" size="3" maxlength="3" type="text" class="textInput formLengthLimit" />
            </div>
    <div class="ctrlHolder nginx">
    <div class="ctrlHolder phpfpm">
          <label for="pm_min_spare_servers">{tmpl_var name='pm_min_spare_servers_txt'}</label>
        <input name="pm_min_spare_servers" id="pm_min_spare_servers" value="{tmpl_var name='pm_min_spare_servers'}" size="3" maxlength="3" type="text" class="textInput formLengthLimit" />
            </div>
    <div class="ctrlHolder nginx">
    <div class="ctrlHolder phpfpm">
          <label for="pm_max_spare_servers">{tmpl_var name='pm_max_spare_servers_txt'}</label>
        <input name="pm_max_spare_servers" id="pm_max_spare_servers" value="{tmpl_var name='pm_max_spare_servers'}" size="3" maxlength="3" type="text" class="textInput formLengthLimit" />
            </div>
@@ -91,6 +91,13 @@
                    jQuery('.apache').show();
                }
            });
            jQuery.getJSON('sites/ajax_get_json.php'+ '?' + Math.round(new Date().getTime()), {web_id : webId, type : "getphptype"}, function(data) {
                if(data.phptype == "php-fpm"){
                    jQuery('.phpfpm').show();
                } else {
                    jQuery('.phpfpm').hide();
                }
            });
        }
            
</script>
server/conf/vhost.conf.master
@@ -214,6 +214,23 @@
        Allow from all
    </Directory>
</tmpl_if>
<tmpl_if name='php' op='==' value='php-fpm'>
    <IfModule mod_fastcgi.c>
        <Directory /usr/lib/cgi-bin>
            Order allow,deny
            Allow from all
        </Directory>
        AddHandler php5-fcgi .php
        Action php5-fcgi /php5-fcgi
        Alias /php5-fcgi /usr/lib/cgi-bin/php5-fcgi
<tmpl_if name='use_tcp'>
        FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -host 127.0.0.1:<tmpl_var name='fpm_port'> -pass-header Authorization
</tmpl_if>
<tmpl_if name='use_socket'>
        FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket <tmpl_var name='fpm_socket'> -pass-header Authorization
</tmpl_if>
    </IfModule>
</tmpl_if>
<tmpl_if name="rewrite_enabled">
    RewriteEngine on
server/plugins-available/apache2_plugin.inc.php
@@ -961,6 +961,41 @@
            $tpl->setVar('fastcgi_config_syntax',$fastcgi_config['fastcgi_config_syntax']);
        }
        /**
        * PHP-FPM
        */
        // Support for multiple PHP versions
        if(trim($data['new']['fastcgi_php_version']) != ''){
            $default_php_fpm = false;
            list($custom_php_fpm_name, $custom_php_fpm_init_script, $custom_php_fpm_ini_dir, $custom_php_fpm_pool_dir) = explode(':', trim($data['new']['fastcgi_php_version']));
            if(substr($custom_php_fpm_ini_dir,-1) != '/') $custom_php_fpm_ini_dir .= '/';
        } else {
            $default_php_fpm = true;
        }
        if($default_php_fpm){
            $pool_dir = escapeshellcmd($web_config['php_fpm_pool_dir']);
        } else {
            $pool_dir = $custom_php_fpm_pool_dir;
        }
        if(substr($pool_dir,-1) != '/') $pool_dir .= '/';
        $pool_name = 'web'.$data['new']['domain_id'];
        $socket_dir = escapeshellcmd($web_config['php_fpm_socket_dir']);
        if(substr($socket_dir,-1) != '/') $socket_dir .= '/';
        if($data['new']['php_fpm_use_socket'] == 'y'){
            $use_tcp = 0;
            $use_socket = 1;
        } else {
            $use_tcp = 1;
            $use_socket = 0;
        }
        $tpl->setVar('use_tcp', $use_tcp);
        $tpl->setVar('use_socket', $use_socket);
        $fpm_socket = $socket_dir.$pool_name.'.sock';
        $tpl->setVar('fpm_socket', $fpm_socket);
        $tpl->setVar('fpm_port', $web_config['php_fpm_start_port'] + $data['new']['domain_id'] - 1);
        /**
         * install cgi starter script and add script alias to config.
@@ -1153,6 +1188,8 @@
            $this->awstats_update($data,$web_config);
        }
        
        $this->php_fpm_pool_update($data,$web_config,$pool_dir,$pool_name,$socket_dir);
        if($web_config['check_apache_config'] == 'y') {
            //* Test if apache starts with the new configuration file
            $apache_online_status_before_restart = $this->_checkTcp('localhost',80);
@@ -1255,6 +1292,11 @@
                if (is_dir($fastcgi_starter_path)) {
                    exec('rm -rf '.$fastcgi_starter_path);
                }
            }
            // remove PHP-FPM pool
            if ($data['old']['php'] == 'php-fpm') {
                $this->php_fpm_pool_delete($data,$web_config);
            }
            //remove the php cgi starter script if available
@@ -1879,6 +1921,212 @@
        }
    }
    
    //* Update the PHP-FPM pool configuration file
    private function php_fpm_pool_update ($data,$web_config,$pool_dir,$pool_name,$socket_dir) {
        global $app, $conf;
        //$reload = false;
        if(trim($data['new']['fastcgi_php_version']) != ''){
            $default_php_fpm = false;
            list($custom_php_fpm_name, $custom_php_fpm_init_script, $custom_php_fpm_ini_dir, $custom_php_fpm_pool_dir) = explode(':', trim($data['new']['fastcgi_php_version']));
            if(substr($custom_php_fpm_ini_dir,-1) != '/') $custom_php_fpm_ini_dir .= '/';
        } else {
            $default_php_fpm = true;
        }
        $app->uses("getconf");
        $web_config = $app->getconf->get_server_config($conf["server_id"], 'web');
        if($data['new']['php'] != 'php-fpm'){
            if(@is_file($pool_dir.$pool_name.'.conf')){
                unlink($pool_dir.$pool_name.'.conf');
                //$reload = true;
            }
            if($data['old']['php'] == 'php-fpm'){
                if(!$default_php_fpm){
                    $app->services->restartService('php-fpm','reload:'.$custom_php_fpm_init_script);
                } else {
                    $app->services->restartService('php-fpm','reload:'.$conf['init_scripts'].'/'.$web_config['php_fpm_init_script']);
                }
            }
            //if($reload == true) $app->services->restartService('php-fpm','reload');
            return;
        }
        $app->load('tpl');
        $tpl = new tpl();
        $tpl->newTemplate('php_fpm_pool.conf.master');
        if($data['new']['php_fpm_use_socket'] == 'y'){
            $use_tcp = 0;
            $use_socket = 1;
            if(!is_dir($socket_dir)) exec('mkdir -p '.$socket_dir);
        } else {
            $use_tcp = 1;
            $use_socket = 0;
        }
        $tpl->setVar('use_tcp', $use_tcp);
        $tpl->setVar('use_socket', $use_socket);
        $fpm_socket = $socket_dir.$pool_name.'.sock';
        $tpl->setVar('fpm_socket', $fpm_socket);
        $tpl->setVar('fpm_pool', $pool_name);
        $tpl->setVar('fpm_port', $web_config['php_fpm_start_port'] + $data['new']['domain_id'] - 1);
        $tpl->setVar('fpm_user', $data['new']['system_user']);
        $tpl->setVar('fpm_group', $data['new']['system_group']);
        $tpl->setVar('pm_max_children', $data['new']['pm_max_children']);
        $tpl->setVar('pm_start_servers', $data['new']['pm_start_servers']);
        $tpl->setVar('pm_min_spare_servers', $data['new']['pm_min_spare_servers']);
        $tpl->setVar('pm_max_spare_servers', $data['new']['pm_max_spare_servers']);
        $tpl->setVar('document_root', $data['new']['document_root']);
        $tpl->setVar('security_level',$web_config['security_level']);
        $php_open_basedir = ($data['new']['php_open_basedir'] == '')?escapeshellcmd($data['new']['document_root']):escapeshellcmd($data['new']['php_open_basedir']);
        $tpl->setVar('php_open_basedir', $php_open_basedir);
        if($php_open_basedir != ''){
            $tpl->setVar('enable_php_open_basedir', '');
        } else {
            $tpl->setVar('enable_php_open_basedir', ';');
        }
        // Custom php.ini settings
        $final_php_ini_settings = array();
        $custom_php_ini_settings = trim($data['new']['custom_php_ini']);
        if($custom_php_ini_settings != ''){
            // Make sure we only have Unix linebreaks
            $custom_php_ini_settings = str_replace("\r\n", "\n", $custom_php_ini_settings);
            $custom_php_ini_settings = str_replace("\r", "\n", $custom_php_ini_settings);
            $ini_settings = explode("\n", $custom_php_ini_settings);
            if(is_array($ini_settings) && !empty($ini_settings)){
                foreach($ini_settings as $ini_setting){
                        list($key, $value) = explode('=', $ini_setting);
                        if($value){
                            $value = escapeshellcmd(trim($value));
                            $key = escapeshellcmd(trim($key));
                            switch (strtolower($value)) {
                                case 'on':
                                case 'off':
                                case '1':
                                case '0':
                                    // PHP-FPM might complain about invalid boolean value if you use 0
                                    $value = 'off';
                                case 'true':
                                case 'false':
                                case 'yes':
                                case 'no':
                                    $final_php_ini_settings[] = array('ini_setting' => 'php_admin_flag['.$key.'] = '.$value);
                                    break;
                                default:
                                    $final_php_ini_settings[] = array('ini_setting' => 'php_admin_value['.$key.'] = '.$value);
                            }
                        }
                }
            }
        }
        $tpl->setLoop('custom_php_ini_settings', $final_php_ini_settings);
        file_put_contents($pool_dir.$pool_name.'.conf',$tpl->grab());
        $app->log('Writing the PHP-FPM config file: '.$pool_dir.$pool_name.'.conf',LOGLEVEL_DEBUG);
        unset($tpl);
        // delete pool in all other PHP versions
        $default_pool_dir = escapeshellcmd($web_config['php_fpm_pool_dir']);
        if(substr($default_pool_dir,-1) != '/') $default_pool_dir .= '/';
        if($default_pool_dir != $pool_dir){
            if ( @is_file($default_pool_dir.$pool_name.'.conf') ) {
                    unlink($default_pool_dir.$pool_name.'.conf');
                    $app->log('Removed PHP-FPM config file: '.$default_pool_dir.$pool_name.'.conf',LOGLEVEL_DEBUG);
                    $app->services->restartService('php-fpm','reload:'.$conf['init_scripts'].'/'.$web_config['php_fpm_init_script']);
            }
        }
        $php_versions = $app->db->queryAllRecords("SELECT * FROM server_php WHERE php_fpm_init_script != '' AND php_fpm_ini_dir != '' AND php_fpm_pool_dir != '' AND server_id = ".$conf["server_id"]);
        if(is_array($php_versions) && !empty($php_versions)){
            foreach($php_versions as $php_version){
                if(substr($php_version['php_fpm_pool_dir'],-1) != '/') $php_version['php_fpm_pool_dir'] .= '/';
                if($php_version['php_fpm_pool_dir'] != $pool_dir){
                    if ( @is_file($php_version['php_fpm_pool_dir'].$pool_name.'.conf') ) {
                        unlink($php_version['php_fpm_pool_dir'].$pool_name.'.conf');
                        $app->log('Removed PHP-FPM config file: '.$php_version['php_fpm_pool_dir'].$pool_name.'.conf',LOGLEVEL_DEBUG);
                        $app->services->restartService('php-fpm','reload:'.$php_version['php_fpm_init_script']);
                    }
                }
            }
        }
        // Reload current PHP-FPM after all others
        sleep(1);
        if(!$default_php_fpm){
            $app->services->restartService('php-fpm','reload:'.$custom_php_fpm_init_script);
        } else {
            $app->services->restartService('php-fpm','reload:'.$conf['init_scripts'].'/'.$web_config['php_fpm_init_script']);
        }
        //$reload = true;
        //if($reload == true) $app->services->restartService('php-fpm','reload');
    }
    //* Delete the PHP-FPM pool configuration file
    private function php_fpm_pool_delete ($data,$web_config) {
        global $app, $conf;
        if(trim($data['old']['fastcgi_php_version']) != ''){
            $default_php_fpm = false;
            list($custom_php_fpm_name, $custom_php_fpm_init_script, $custom_php_fpm_ini_dir, $custom_php_fpm_pool_dir) = explode(':', trim($data['old']['fastcgi_php_version']));
            if(substr($custom_php_fpm_ini_dir,-1) != '/') $custom_php_fpm_ini_dir .= '/';
        } else {
            $default_php_fpm = true;
        }
        if($default_php_fpm){
            $pool_dir = escapeshellcmd($web_config['php_fpm_pool_dir']);
        } else {
            $pool_dir = $custom_php_fpm_pool_dir;
        }
        if(substr($pool_dir,-1) != '/') $pool_dir .= '/';
        $pool_name = 'web'.$data['old']['domain_id'];
        if ( @is_file($pool_dir.$pool_name.'.conf') ) {
            unlink($pool_dir.$pool_name.'.conf');
            $app->log('Removed PHP-FPM config file: '.$pool_dir.$pool_name.'.conf',LOGLEVEL_DEBUG);
            //$app->services->restartService('php-fpm','reload');
        }
        // delete pool in all other PHP versions
        $default_pool_dir = escapeshellcmd($web_config['php_fpm_pool_dir']);
        if(substr($default_pool_dir,-1) != '/') $default_pool_dir .= '/';
        if($default_pool_dir != $pool_dir){
            if ( @is_file($default_pool_dir.$pool_name.'.conf') ) {
                    unlink($default_pool_dir.$pool_name.'.conf');
                    $app->log('Removed PHP-FPM config file: '.$default_pool_dir.$pool_name.'.conf',LOGLEVEL_DEBUG);
                    $app->services->restartService('php-fpm','reload:'.$conf['init_scripts'].'/'.$web_config['php_fpm_init_script']);
            }
        }
        $php_versions = $app->db->queryAllRecords("SELECT * FROM server_php WHERE php_fpm_init_script != '' AND php_fpm_ini_dir != '' AND php_fpm_pool_dir != '' AND server_id = ".$data['old']['server_id']);
        if(is_array($php_versions) && !empty($php_versions)){
            foreach($php_versions as $php_version){
                if(substr($php_version['php_fpm_pool_dir'],-1) != '/') $php_version['php_fpm_pool_dir'] .= '/';
                if($php_version['php_fpm_pool_dir'] != $pool_dir){
                    if ( @is_file($php_version['php_fpm_pool_dir'].$pool_name.'.conf') ) {
                        unlink($php_version['php_fpm_pool_dir'].$pool_name.'.conf');
                        $app->log('Removed PHP-FPM config file: '.$php_version['php_fpm_pool_dir'].$pool_name.'.conf',LOGLEVEL_DEBUG);
                        $app->services->restartService('php-fpm','reload:'.$php_version['php_fpm_init_script']);
                    }
                }
            }
        }
        // Reload current PHP-FPM after all others
        sleep(1);
        if(!$default_php_fpm){
            $app->services->restartService('php-fpm','reload:'.$custom_php_fpm_init_script);
        } else {
            $app->services->restartService('php-fpm','reload:'.$conf['init_scripts'].'/'.$web_config['php_fpm_init_script']);
        }
    }
    function client_delete($event_name,$data) {
        global $app, $conf;