ivantcholakov / starter-public-edition-4

A PHP application starter, based on CodeIgniter 3
MIT License
164 stars 89 forks source link

email config #68

Closed quasiperfect closed 8 years ago

quasiperfect commented 8 years ago

hi

can you please add support for

$mail->SMTPOptions = array(
    'ssl' => array(
        'verify_peer' => false,
        'verify_peer_name' => false,
        'allow_self_signed' => true
    )
);

PHP 5.6 certificate verification failure

In a change from earlier versions, PHP 5.6 verifies certificates on SSL connections. If the SSL config of the server you are connecting to is not correct, you will get an error like this:

Warning: stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

The correct fix for this is to replace the invalid, misconfigured or self-signed certificate with a good one. Failing that, you can allow insecure connections via the SMTPOptions property introduced in PHPMailer 5.2.10 (it's possible to do this by subclassing the SMTP class in earlier versions), though this is not recommended:

ivantcholakov commented 8 years ago

https://github.com/PHPMailer/PHPMailer/issues/368

ivantcholakov commented 8 years ago

smtp_conn_options (CodeIgniter) ---> SMTPOptions (PHPMailer)

ivantcholakov commented 8 years ago

v4.0.126

ivantcholakov commented 8 years ago

A note: For 'smtp_conn_options' in the administration panel I use a text area control for this setting. I enter the value in JSON notation:

{
    "ssl": {
        "verify_peer": false,
        "verify_peer_name": false,
        "allow_self_signed": true
    }
}

The helper function set_email_settings() takes the decoded value (an object), converts it into an associative array recursively and then stores it within the database, the 'settings' table. The stored array is PHP-serialized. Sounds weird, but it works.

ivantcholakov commented 8 years ago

Demo code for an administrative page:

Controller: Email_settings_controller.php

<?php defined('BASEPATH') OR exit('No direct script access allowed.');

class Email_settings_controller extends Base_Authenticated_Controller {

    public function __construct() {

        parent::__construct();

        $this->load
            ->language('email_settings')
        ;

        $this->_set_nav('settings/email_settings');
    }

    public function index() {

        $this->load->helper('email');

        $this->_set_title($this->lang->line('email_settings'), $this->lang->line('ui_settings').': '.$this->lang->line('email_settings'));

        $settings = get_email_settings();

        $settings['smtp_port'] = empty($settings['smtp_port']) ? '' : $settings['smtp_port'];
        $settings['mailer_enabled'] = (int) $settings['mailer_enabled'];
        $settings['smtp_conn_options'] = empty($settings['smtp_conn_options'])
            ? ''
            : (is_php('5.4')
                ? json_encode($settings['smtp_conn_options'], JSON_PRETTY_PRINT)
                : json_encode($settings['smtp_conn_options']));

        $validation_rules = array(
            array(
                'field' => 'site_email',
                'label' => $this->lang->line('site_email'),
                'rules' => 'nohtml|trim'.($this->input->post('site_email') != '' ? '|valid_email' : '')
            ),
            array(
                'field' => 'notification_email',
                'label' => $this->lang->line('notification_email'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'cc_email',
                'label' => $this->lang->line('cc_email'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'mailer_enabled',
                'label' => $this->lang->line('status'),
                'rules' => 'nohtml|trim|required'
            ),
            array(
                'field' => 'protocol',
                'label' => $this->lang->line('email_protocol'),
                'rules' => 'nohtml|trim|required'
            ),
            array(
                'field' => 'mailpath',
                'label' => $this->lang->line('email_mailpath'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'smtp_host',
                'label' => $this->lang->line('email_smtp_host'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'smtp_user',
                'label' => $this->lang->line('email_smtp_user'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'smtp_pass',
                'label' => $this->lang->line('email_smtp_pass'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'smtp_port',
                'label' => $this->lang->line('email_smtp_port'),
                'rules' => 'nohtml|trim'.($this->input->post('smtp_port') != '' ? '|is_natural|greater_than[0]|less_than_equal_to[65535]' : '')
            ),
            array(
                'field' => 'smtp_crypto',
                'label' => $this->lang->line('email_smtp_crypto'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'smtp_auto_tls',
                'label' => $this->lang->line('email_smtp_auto_tls'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'smtp_conn_options',
                'label' => $this->lang->line('email_smtp_conn_options'),
                'rules' => 'trim'
            ),
            array(
                'field' => 'dkim_domain',
                'label' => $this->lang->line('email_dkim_domain'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'dkim_private',
                'label' => $this->lang->line('email_dkim_private'),
                'rules' => 'strval'
            ),
            array(
                'field' => 'dkim_selector',
                'label' => $this->lang->line('email_dkim_selector'),
                'rules' => 'nohtml|trim'
            ),
            array(
                'field' => 'dkim_passphrase',
                'label' => $this->lang->line('email_dkim_passphrase'),
                'rules' => 'strval'
            ),
            array(
                'field' => 'dkim_identity',
                'label' => $this->lang->line('email_dkim_identity'),
                'rules' => 'nohtml|trim'
            ),
        );

        $this->form_validation->set_rules($validation_rules);

        if ($this->form_validation->run()) {

            $data = array_only($this->input->post(), array(
                'protocol',
                'mailpath',
                'smtp_host',
                'smtp_user',
                'smtp_pass',
                'smtp_port',
                'smtp_crypto',

                'smtp_auto_tls',
                'smtp_conn_options',

                'dkim_domain',
                'dkim_private',
                'dkim_selector',
                'dkim_passphrase',
                'dkim_identity',

                'mailer_enabled',
                'site_email',
                'notification_email',
                'cc_email',
            ));

            $smtp_conn_options = @ json_decode($data['smtp_conn_options']);

            if (empty($smtp_conn_options)) {
                $smtp_conn_options = array();
            }

            $data['smtp_conn_options'] = $smtp_conn_options;

            // Store data.
            set_email_settings($data);

            $this->session->set_flashdata('confirmation_message', $this->lang->line('settings_saved'));
            redirect(site_url('email-settings'));

        } elseif (validation_errors()) {

            $this->template->set('error_message', '<ul>'.validation_errors('<li>', '</li>').'</ul>');
            $this->template->set('validation_errors', $this->form_validation->error_array());
        }

        $this->template
            ->set($settings)
            ->set_partial('scripts', 'email_settings_scripts')
            ->build('email_settings');
    }

    public function _status_active_dropdown($value = '') {

        $this->load->model('status_active');

        return form_dropdown(
            'mailer_enabled',
            array('' => '-- '.$this->lang->line('ui_choose').' --') + $this->status_active->dropdown(),
            $value,
            'id="mailer_enabled" class="form-control" style="width: 100%;"'
        );
    }

}

View: email_settings.html.twig


                            {{ form_open('', 'name="admin_form" id="admin_form" method="post" class="form-horizontal" role="form"') }}

                                <div class="form-group{% if validation_errors['site_email'] is not empty %} has-error{% endif %}">

                                    <label for="site_email" class="col-sm-4 control-label">
                                        {{ lang('site_email') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('site_email_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6">
                                        <input type="text" name="site_email" id="site_email" class="form-control"
                                            value="{{ set_value('site_email', site_email) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['notification_email'] is not empty %} has-error{% endif %}">

                                    <label for="notification_email" class="col-sm-4 control-label">
                                        {{ lang('notification_email') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('notification_email_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6">
                                        <input type="text" name="notification_email" id="notification_email" class="form-control"
                                            value="{{ set_value('notification_email', notification_email) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['cc_email'] is not empty %} has-error{% endif %}">

                                    <label for="cc_email" class="col-sm-4 control-label">
                                        {{ lang('cc_email') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('cc_email_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6">
                                        <input type="text" name="cc_email" id="cc_email" class="form-control"
                                            value="{{ set_value('cc_email', cc_email) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['mailer_enabled'] is not empty %} has-error{% endif %}">

                                    <label for="mailer_enabled" class="col-sm-4 control-label">
                                        * {{ lang('status') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('mailer_enabled_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-2">
                                        {{ widget('email_settings/_status_active_dropdown', set_value('mailer_enabled', mailer_enabled)) }}
                                    </div>

                                </div>

                                <hr />

                                <div class="form-group{% if validation_errors['protocol'] is not empty %} has-error{% endif %}">

                                    <label for="protocol" class="col-sm-4 control-label">
                                        * {{ lang('email_protocol') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_protocol_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-2">

{{ form_dropdown(
    'protocol',
    {'': '-- ' ~ lang('ui_choose') ~ ' --', 'mail': 'mail', 'sendmail': 'sendmail', 'smtp': 'smtp'},
    protocol,
    'id="protocol" class="form-control" style="width: 100%;"'
) }}

                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['mailpath'] is not empty %} has-error{% endif %}">

                                    <label for="mailpath" class="col-sm-4 control-label">
                                        {{ lang('email_mailpath') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_mailpath_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="mailpath" id="mailpath" class="form-control"
                                            value="{{ set_value('mailpath', mailpath) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['smtp_host'] is not empty %} has-error{% endif %}">

                                    <label for="smtp_host" class="col-sm-4 control-label">
                                        {{ lang('email_smtp_host') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_smtp_host_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="smtp_host" id="smtp_host" class="form-control"
                                            value="{{ set_value('smtp_host', smtp_host) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['smtp_user'] %} has-error{% endif %}">

                                    <label for="smtp_user" class="col-sm-4 control-label">
                                        {{ lang('email_smtp_user') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_smtp_user_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="smtp_user" id="smtp_user" class="form-control"
                                            value="{{ set_value('smtp_user', smtp_user) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['smtp_pass'] %} has-error{% endif %}">

                                    <label for="smtp_pass" class="col-sm-4 control-label">
                                        {{ lang('email_smtp_pass') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_smtp_pass_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="password" name="smtp_pass" id="smtp_pass" class="form-control"
                                            value="{{ set_value('smtp_pass', smtp_pass) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['smtp_port'] %} has-error{% endif %}">

                                    <label for="smtp_port" class="col-sm-4 control-label">
                                        {{ lang('email_smtp_port') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_smtp_port_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-2">
                                        <input type="text" name="smtp_port" id="smtp_port" class="form-control"
                                            value="{{ set_value('smtp_port', smtp_port) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['smtp_crypto'] %} has-error{% endif %}">

                                    <label for="smtp_crypto" class="col-sm-4 control-label">
                                        {{ lang('email_smtp_crypto') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_smtp_crypto_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-2">
{{ form_dropdown(
    'smtp_crypto',
    {'': '-- ' ~ lang('email_none') ~ ' --', 'ssl': 'ssl', 'tls': 'tls'},
    smtp_crypto,
    'id="smtp_crypto" class="form-control" style="width: 100%;"'
) }}

                                    </div>

                                </div>

                                <div class="form-group">

                                    <div class="col-sm-offset-4 col-sm-8">

                                        <div class="checkbox">
                                            <label for="smtp_auto_tls">
                                                <input type="checkbox" id="smtp_auto_tls" name="smtp_auto_tls" value="1" {{ set_checkbox('smtp_auto_tls', '1', smtp_auto_tls|int != 0) }} /> {{ lang('email_smtp_auto_tls') }}
                                                <a href="javascript://"
                                                   class="popover-top"
                                                   data-toggle="popover"
                                                   title="{{ lang('ui_help') }}"
                                                   data-content="{{ lang('email_smtp_auto_tls_tip') }}"
                                                   >
                                                    <i class="fa fa-question-circle"></i>
                                                </a>
                                            </label>
                                        </div>

                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['smtp_conn_options'] is not empty %} has-error{% endif %}">

                                    <label for="smtp_conn_options" class="col-sm-4 control-label">
                                        {{ lang('email_smtp_conn_options') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_smtp_conn_options_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6">
                                        <textarea class="form-control" rows="8" name="smtp_conn_options" id="smtp_conn_options">{{ set_value('smtp_conn_options', smtp_conn_options, true) }}</textarea>
                                    </div>

                                </div>

                                <hr />

                                <div class="form-group{% if validation_errors['dkim_domain'] is not empty %} has-error{% endif %}">

                                    <label for="dkim_domain" class="col-sm-4 control-label">
                                        {{ lang('email_dkim_domain') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_dkim_domain_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="dkim_domain" id="dkim_domain" class="form-control"
                                            value="{{ set_value('dkim_domain', dkim_domain) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['dkim_private'] is not empty %} has-error{% endif %}">

                                    <label for="dkim_private" class="col-sm-4 control-label">
                                        {{ lang('email_dkim_private') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_dkim_private_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="dkim_private" id="dkim_private" class="form-control"
                                            value="{{ set_value('dkim_private', dkim_private) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['dkim_selector'] is not empty %} has-error{% endif %}">

                                    <label for="dkim_selector" class="col-sm-4 control-label">
                                        {{ lang('email_dkim_selector') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_dkim_selector_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="dkim_selector" id="dkim_selector" class="form-control"
                                            value="{{ set_value('dkim_selector', dkim_selector) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['dkim_passphrase'] is not empty %} has-error{% endif %}">

                                    <label for="dkim_passphrase" class="col-sm-4 control-label">
                                        {{ lang('email_dkim_passphrase') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_dkim_passphrase_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="password" name="dkim_passphrase" id="dkim_passphrase" class="form-control"
                                            value="{{ set_value('dkim_passphrase', dkim_passphrase) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group{% if validation_errors['dkim_identity'] is not empty %} has-error{% endif %}">

                                    <label for="dkim_identity" class="col-sm-4 control-label">
                                        {{ lang('email_dkim_identity') }}:
                                        <a href="javascript://"
                                           class="popover-top"
                                           title="{{ lang('ui_help') }}"
                                           data-content="{{ lang('email_dkim_identity_tip') }}"
                                           >
                                            <i class="fa fa-question-circle"></i>
                                        </a>
                                    </label>

                                    <div class="col-sm-6 col-lg-4">
                                        <input type="text" name="dkim_identity" id="dkim_identity" class="form-control"
                                            value="{{ set_value('dkim_identity', dkim_identity) }}"
                                        />
                                    </div>

                                </div>

                                <div class="form-group">

                                    <div class="col-sm-offset-4 col-sm-8">

                                        <p class="help-block">
                                            {{ lang('ui_required_fields_note') }}
                                        </p>

                                    </div>

                                </div>

                                <div class="form-group">

                                    <div class="col-sm-offset-4 col-sm-8">

                                        <button type="submit" class="btn btn-primary">
                                            <i class="fa fa-check"></i>
                                            {{ lang('ui_save') }}
                                        </button>

                                    </div>

                                </div>

                            {{ form_close() }}