Пример #1
0
/**
 * Removes service parameters from URL
 * @param string $url URL
 * @return string clean URL
 */
function fn_url_remove_service_params($url)
{
    $params = array('is_ajax', 'callback', 'full_render', 'result_ids', 'init_context', 'skip_result_ids_check', 'anchor', Session::getName());
    array_unshift($params, $url);
    return call_user_func_array('fn_query_remove', $params);
}
Пример #2
0
        } elseif ($mode == 'finish') {
            $order_info = fn_get_order_info($order_id);
            if ($order_info['status'] == 'O') {
                $pp_response = array();
                $pp_response['order_status'] = 'F';
                $pp_response['reason_text'] = __('merchant_response_was_not_received');
                $pp_response['transaction_id'] = '';
                fn_finish_payment($order_id, $pp_response);
            }
            fn_order_placement_routines('route', $order_id, false);
        }
    }
} else {
    $current_location = Registry::get('config.current_location');
    $lang_code = CART_LANGUAGE == 'th' ? 'TH' : 'EN';
    $sess = '&' . Session::getName() . '=' . Session::getId();
    $_SESSION['thaiepay_refno'] = $order_id;
    $return_url = fn_url("payment_notification.finish?payment=thaiepay&refno={$order_id}{$sess}", AREA, 'current');
    echo <<<EOT
<form method="post" action="https://www.thaiepay.com/epaylink/payment.aspx" name="process">
    <input type="hidden" name="refno" value="{$order_id}">
    <input type="hidden" name="merchantid" value="{$processor_data['processor_params']['merchantid']}">
    <input type="hidden" name="customeremail" value="{$order_info['email']}">
    <input type="hidden" name="productdetail" value="{$processor_data['processor_params']['details']}">
    <input type="hidden" name="total" value="{$order_info['total']}">
    <input type="hidden" name="cc" value="{$processor_data['processor_params']['currency']}">
    <input type="hidden" name="lang" value="{$lang_code}">
    <input type="hidden" name="returnurl" value="{$return_url}">
EOT;
    $msg = __('text_cc_processor_connection', array('[processor]' => 'thaiepay.com server'));
    echo <<<EOT
Пример #3
0
 /**
  * Processes payment form to make payment submit via non-embedded mode
  * @param string $submit_url payment submit URL
  * @param array $data payment data
  * @param array $payment_name payment name
  * @param boolean $exclude_empty_values flag to exclude empty values
  * @param string $method submit method
  * @return array data to submit form to host server
  */
 public static function processPaymentForm($submit_url, $data, $payment_name, $exclude_empty_values, $method)
 {
     $data = array(Session::getName() => Session::getId(), 'data' => json_encode(array('submit_url' => $submit_url, 'data' => $data, 'payment_name' => $payment_name, 'method' => $method, 'exclude_empty_values' => $exclude_empty_values)));
     $submit_url = fn_url('payment_notification.process_embedded');
     $method = 'post';
     $payment_name = '';
     return array($submit_url, $data, $method, $payment_name);
 }
Пример #4
0
/**
 * Make cmpi_lookup request to 3-D Secure sevice provider
 *
 * @param array $processor_data Payment processor data
 * @param array $order_info Order information
 * @return boolean true
 */
function fn_cmpi_lookup($processor_data, $order_info, $mode = '')
{
    unset($_SESSION['cmpi']);
    $amount = preg_replace('/\\D/', '', $order_info['total']);
    // array with ISO codes of currencies. //TODO: move to database.
    $iso4217 = array('USD' => 840, 'GBP' => 826, 'EUR' => 978, 'AUD' => 036, 'CAD' => 124, 'JPY' => 392);
    $settings = array('processor_id', 'merchant_id', 'transaction_password', 'transaction_url');
    foreach ($settings as $setting) {
        $_SESSION['cmpi'][$setting] = $processor_data['processor_params'][$setting];
    }
    $cardinal_request = <<<EOT
<CardinalMPI>
<MsgType>cmpi_lookup</MsgType>
<Version>1.7</Version>
<ProcessorId>{$_SESSION['cmpi']['processor_id']}</ProcessorId>
<MerchantId>{$_SESSION['cmpi']['merchant_id']}</MerchantId>
<TransactionPwd>{$_SESSION['cmpi']['transaction_password']}</TransactionPwd>
<TransactionType>C</TransactionType>
<Amount>{$amount}</Amount>
<CurrencyCode>{$iso4217[$processor_data['processor_params']['currency']]}</CurrencyCode>
<CardNumber>{$order_info['payment_info']['card_number']}</CardNumber>
<CardExpMonth>{$order_info['payment_info']['expiry_month']}</CardExpMonth>
<CardExpYear>20{$order_info['payment_info']['expiry_year']}</CardExpYear>
<OrderNumber>{$order_info['order_id']}</OrderNumber>
<OrderDesc>Order #{$order_info['order_id']}; customer: {$order_info['b_firstname']} {$order_info['b_lastname']};</OrderDesc>
<BrowserHeader>*/*</BrowserHeader>
<EMail>{$order_info['email']}</EMail>
<IPAddress>{$_SERVER['REMOTE_ADDR']}</IPAddress>
<BillingFirstName>{$order_info['b_firstname']}</BillingFirstName>
<BillingLastName>{$order_info['b_lastname']}</BillingLastName>
<BillingAddress1>{$order_info['b_address']}</BillingAddress1>
<BillingAddress2>{$order_info['b_address_2']}</BillingAddress2>
<BillingCity>{$order_info['b_city']}</BillingCity>
<BillingState>{$order_info['b_state']}</BillingState>
<BillingPostalCode>{$order_info['b_zipcode']}</BillingPostalCode>
<BillingCountryCode>{$order_info['b_country']}</BillingCountryCode>
<ShippingFirstName>{$order_info['s_firstname']}</ShippingFirstName>
<ShippingLastName>{$order_info['s_lastname']}</ShippingLastName>
<ShippingAddress1>{$order_info['s_address']}</ShippingAddress1>
<ShippingAddress2>{$order_info['s_address_2']}</ShippingAddress2>
<ShippingCity>{$order_info['s_city']}</ShippingCity>
<ShippingState>{$order_info['s_state']}</ShippingState>
<ShippingPostalCode>{$order_info['s_zipcode']}</ShippingPostalCode>
<ShippingCountryCode>{$order_info['s_country']}</ShippingCountryCode>
</CardinalMPI>
EOT;
    Registry::set('log_cut_data', array('CardNumber', 'CardExpMonth', 'CardExpYear'));
    $response_data = Http::post($_SESSION['cmpi']['transaction_url'], array('cmpi_msg' => $cardinal_request));
    $cmpi = @simplexml_load_string($response_data);
    $err_no = 0;
    $_SESSION['cmpi']['enrolled'] = 'U';
    $acs_url = '';
    if (empty($response_data) || $cmpi === false) {
        $_SESSION['cmpi']['eci_flag'] = fn_get_payment_card($order_info['payment_info']['card_number'], array('mastercard' => 1, 'visa' => 7, 'jcb' => 7));
        $err_desc = 'Connection problem';
    } else {
        $err_no = intval((string) $cmpi->ErrorNo);
        $err_desc = (string) $cmpi->ErrorDesc;
        $acs_url = (string) $cmpi->ACSUrl;
        $_SESSION['cmpi']['enrolled'] = (string) $cmpi->Enrolled;
        $_SESSION['cmpi']['transaction_id'] = (string) $cmpi->TransactionId;
        $_SESSION['cmpi']['eci_flag'] = (string) $cmpi->EciFlag;
    }
    if ($err_no == 0 && $_SESSION['cmpi']['enrolled'] == 'Y' && !empty($acs_url)) {
        $sess = Session::getName() . '=' . Session::getId();
        $payment_name = str_replace('.php', '', $processor_data['processor_script']);
        $_SESSION['cmpi']['acs_url'] = $acs_url;
        $_SESSION['cmpi']['order_id'] = $order_info['order_id'];
        $_SESSION['cmpi']['frame_data'] = array('PaReq' => (string) $cmpi->Payload, 'TermUrl' => fn_url("payment_notification.bank?payment={$payment_name}&{$sess}", AREA, 'current'), 'MD' => '');
        $frame_src = fn_url("payment_notification.frame?payment={$payment_name}&{$sess}", AREA, 'current');
        $msg = __('text_cmpi_frame_message');
        $back_link_msg = __('text_cmpi_go_back');
        $dispatch = $mode == 'repay' ? 'orders.details?order_id=' . $order_info['order_id'] . '&' : 'checkout.checkout?';
        $back_link = fn_url($dispatch . $sess, AREA, 'current');
        echo <<<EOT
<table width="100%" cellspacing="0" cellpadding="0">
    <tr>
        <td valign="top" align="center">
            <div style="width:500px;">
                {$msg}
                <br /><br />
            </div>
        </td>
    </tr>
    <tr>
        <td valign="top" align="center">
            <iframe width="420" height="420" marginwidth="0" marginheight="0" src="{$frame_src}"></iframe><br />
            <br />
            <div>
                <a href="{$back_link}>{$back_link_msg}</a>
            </div>
        </td>
    </tr>
</table>
EOT;
        exit;
    } else {
        $_SESSION['cmpi']['err_no'][0] = $err_no;
        $_SESSION['cmpi']['err_desc'][0] = $err_desc;
        define('DO_DIRECT_PAYMENT', true);
    }
    return true;
}
Пример #5
0
/**
* Redirect browser to the new location
*
* @param string $location - destination of redirect
* @param bool $allow_external_redirect - allow redirection to external resource
* @param bool $is_permanent - if true, perform 301 redirect
* @return
*/
function fn_redirect($location, $allow_external_redirect = false, $is_permanent = false)
{
    $external_redirect = false;
    $protocol = defined('HTTPS') ? 'https' : 'http';
    $meta_redirect = false;
    // Cleanup location from &amp; signs and call fn_url()
    $location = fn_url(str_replace(array('&amp;', "\n", "\r"), array('&', '', ''), $location));
    // Convert absolute link with location to relative one
    if (strpos($location, '://') !== false || substr($location, 0, 7) == 'mailto:') {
        if (strpos($location, Registry::get('config.http_location')) !== false) {
            $location = str_replace(array(Registry::get('config.http_location') . '/', Registry::get('config.http_location')), '', $location);
            $protocol = 'http';
        } elseif (strpos($location, Registry::get('config.https_location')) !== false) {
            $location = str_replace(array(Registry::get('config.https_location') . '/', Registry::get('config.https_location')), '', $location);
            $protocol = 'https';
        } else {
            if ($allow_external_redirect == false) {
                // if external redirects aren't allowed, redirect to index script
                $location = '';
            } else {
                $external_redirect = true;
            }
        }
        // Convert absolute link without location to relative one
    } else {
        $_protocol = "";
        $_location = "";
        $http_path = Registry::get('config.http_path');
        $https_path = Registry::get('config.https_path');
        if (!empty($http_path) && substr($location, 0, strlen($http_path)) == $http_path) {
            $_location = substr($location, strlen($http_path) + 1);
            $_protocol = 'http';
        }
        if (!empty($https_path) && substr($location, 0, strlen($https_path)) == $https_path) {
            // if https path partially equal to http path check if https path is not just a part of http path
            // e. g. http://example.com/pathsimple & https://example.com/path
            if ($_protocol != 'http' || empty($http_path) || substr($http_path, 0, strlen($https_path)) != $https_path) {
                $_location = substr($location, strlen($https_path) + 1);
                $_protocol = 'https';
            }
        }
        $protocol = Registry::get('config.http_path') != Registry::get('config.https_path') && !empty($_protocol) ? $_protocol : $protocol;
        $location = !empty($_protocol) ? $_location : $location;
    }
    if ($external_redirect == false) {
        fn_set_hook('redirect', $location);
        $protocol_changed = defined('HTTPS') && $protocol == 'http' || !defined('HTTPS') && $protocol == 'https';
        // For correct redirection, location must be absolute with path
        $location = ($protocol == 'http' ? Registry::get('config.http_location') : Registry::get('config.https_location')) . '/' . ltrim($location, '/');
        // Parse the query string
        $fragment = '';
        $query_array = array();
        $parsed_location = parse_url($location);
        if (!empty($parsed_location['query'])) {
            parse_str($parsed_location['query'], $query_array);
            $location = str_replace('?' . $parsed_location['query'], '', $location);
        }
        if (!empty($parsed_location['fragment'])) {
            $fragment = '#' . $parsed_location['fragment'];
            $location = str_replace($fragment, '', $location);
        }
        if ($protocol_changed && (Registry::get('config.http_host') != Registry::get('config.https_host') || Registry::get('config.http_path') != Registry::get('config.https_path'))) {
            $query_array[Session::getName()] = Session::getId();
        }
        // If this is not ajax request, remove ajax specific parameters
        if (!defined('AJAX_REQUEST')) {
            unset($query_array['is_ajax']);
            unset($query_array['result_ids']);
        } else {
            $query_array['result_ids'] = implode(',', Tygh::$app['ajax']->result_ids);
            $query_array['is_ajax'] = Tygh::$app['ajax']->redirect_type;
            $query_array['full_render'] = !empty($_REQUEST['full_render']) ? $_REQUEST['full_render'] : false;
            $query_array['callback'] = Tygh::$app['ajax']->callback;
            $ajax_assigned_vars = Tygh::$app['ajax']->getAssignedVars();
            if (!empty($ajax_assigned_vars['html'])) {
                unset($ajax_assigned_vars['html']);
            }
            $query_array['_ajax_data'] = $ajax_assigned_vars;
        }
        if (!empty($query_array)) {
            $location .= '?' . http_build_query($query_array) . $fragment;
        }
        // Redirect from https to http location
        if ($protocol_changed && defined('HTTPS')) {
            $meta_redirect = true;
        }
    }
    fn_set_hook('redirect_complete', $meta_redirect);
    if (!defined('AJAX_REQUEST') && Embedded::isEnabled()) {
        if (strpos($location, Registry::get('config.http_location')) === 0) {
            $location = str_replace(Registry::get('config.http_location'), '', $location);
        } elseif (strpos($location, Registry::get('config.https_location')) === 0) {
            $location = str_replace(Registry::get('config.https_location'), '', $location);
        }
        $location = Embedded::getUrl() . '#!' . urlencode($location);
        $meta_redirect = true;
    }
    if (defined('AJAX_REQUEST')) {
        // make in-script redirect during ajax request
        $_purl = parse_url($location);
        $_GET = array();
        $_POST = array();
        if (!empty($_purl['query'])) {
            parse_str($_purl['query'], $_GET);
        }
        $_REQUEST = Bootstrap::safeInput($_GET);
        $_SERVER['REQUEST_METHOD'] = 'GET';
        $_SERVER['REQUEST_URI'] = $_purl['path'];
        $_SERVER['QUERY_STRING'] = !empty($_purl['query']) ? $_purl['query'] : '';
        fn_get_route($_REQUEST);
        Registry::save();
        // save registry cache to execute cleanup handlers
        fn_init_settings();
        fn_init_addons();
        Registry::clearCacheLevels();
        Tygh::$app['ajax']->updateRequest();
        return fn_dispatch();
    } elseif (!ob_get_contents() && !headers_sent() && !$meta_redirect) {
        if ($is_permanent) {
            header('HTTP/1.0 301 Moved Permanently');
        }
        header('Location: ' . $location);
        exit;
    } else {
        $delay = (Debugger::isActive() || fn_is_development()) && !Registry::get('runtime.comet') ? 10 : 0;
        if ($delay != 0) {
            fn_echo('<a href="' . htmlspecialchars($location) . '" style="text-transform: lowercase;">' . __('continue') . '</a>');
        }
        fn_echo('<meta http-equiv="Refresh" content="' . $delay . ';URL=' . htmlspecialchars($location) . '" />');
    }
    fn_flush();
    exit;
}
Пример #6
0
    $pp_response['order_status'] = $_REQUEST['transStatus'] == 'Y' && (!empty($processor_data['processor_params']['callback_password']) ? !empty($_REQUEST['callbackPW']) && $_REQUEST['callbackPW'] == $processor_data['processor_params']['callback_password'] : true) ? 'P' : 'F';
    if ($_REQUEST['transStatus'] == 'Y') {
        $pp_response['reason_text'] = $_REQUEST['rawAuthMessage'];
        $pp_response['transaction_id'] = $_REQUEST['transId'];
        $pp_response['descr_avs'] = 'CVV (Security Code): ' . $avs_res[substr($_REQUEST['AVS'], 0, 1)] . '; Postcode: ' . $avs_res[substr($_REQUEST['AVS'], 1, 1)] . '; Address: ' . $avs_res[substr($_REQUEST['AVS'], 2, 1)] . '; Country: ' . $avs_res[substr($_REQUEST['AVS'], 3)];
    }
    if (!empty($_REQUEST['testMode'])) {
        $pp_response['reason_text'] .= '; This a TEST Transaction';
    }
    $area = db_get_field("SELECT data FROM ?:order_data WHERE order_id = ?i AND type = 'E'", $order_id);
    $override = $area == 'A' ? true : false;
    fn_finish_payment($order_id, $pp_response, false);
    echo "<head><meta http-equiv='refresh' content='0; url=" . fn_url("payment_notification.notify?payment=worldpay&order_id={$order_id}", $area, 'current', CART_LANGUAGE, $override) . "'></head><body><wpdisplay item=banner></body>";
    exit;
} else {
    if (!defined('BOOTSTRAP')) {
        die('Access denied');
    }
    $_order_id = $order_info['repaid'] ? $order_id . '_' . $order_info['repaid'] : $order_id;
    $s_id = Session::getId();
    $sess_name = Session::getName();
    $card_holder = $processor_data['processor_params']['test'] == $mode_test_declined ? $card_holder_for_declined_test : $order_info['b_firstname'] . ' ' . $order_info['b_lastname'];
    $test_mode_id = $processor_data['processor_params']['test'] == $mode_test_declined ? $mode_test : $processor_data['processor_params']['test'];
    $signature = md5($processor_data['processor_params']['md5_secret'] . ':' . $processor_data['processor_params']['account_id'] . ':' . $order_info['total'] . ':' . $processor_data['processor_params']['currency'] . ':' . $_order_id);
    $data = array('signatureFields' => 'instId:amount:currency:cartId', 'signature' => $signature, 'instId' => $processor_data['processor_params']['account_id'], 'cartId' => $_order_id, 'amount' => $order_info['total'], 'currency' => $processor_data['processor_params']['currency'], 'testMode' => $test_mode_id, 'authMode' => $processor_data['processor_params']['authmode'], 'name' => $card_holder, 'tel' => $order_info['phone'], 'email' => $order_info['email'], 'address' => $order_info['b_address'] . ' ' . $order_info['b_city'] . ' ' . $order_info['b_state'] . ' ' . $order_info['b_country'], 'postcode' => $order_info['b_zipcode'], 'country' => $order_info['b_country'], "MC_{$sess_name}" => $s_id);
    $order_data = array('order_id' => $order_id, 'type' => 'E', 'data' => AREA);
    db_query("REPLACE INTO ?:order_data ?e", $order_data);
    $submit_url = $processor_data['processor_params']['test'] == $mode_test_declined || $processor_data['processor_params']['test'] == $mode_test ? 'https://secure-test.worldpay.com/wcc/purchase' : 'https://secure.worldpay.com/wcc/purchase';
    fn_create_payment_form($submit_url, $data, 'World Pay server', false);
    exit;
}
Пример #7
0
                $pp_response['order_status'] = 'P';
                $pp_response['reason_text'] = $_REQUEST['msg'];
                $pp_response['transaction_id'] = $_REQUEST['TxnGUID'];
                $pp_response['card_number'] = $_REQUEST['mPAN'];
                $pp_response['card'] = $_REQUEST['type'];
                $pp_response['cardholder_name'] = $_REQUEST['name'];
                $pp_response['expiry_month'] = substr($_REQUEST['exp'], 0, 2);
                $pp_response['expiry_year'] = substr($_REQUEST['exp'], -2);
            } elseif (!empty($_REQUEST['error'])) {
                $pp_response['order_status'] = 'F';
                $pp_response['reason_text'] = !empty($_REQUEST['msg']) ? $_REQUEST['msg'] : __('error');
            } else {
                $pp_response['order_status'] = 'N';
                $pp_response['reason_text'] = __('transaction_cancelled');
            }
            if (fn_check_payment_script('cresecure.php', $order_id)) {
                fn_finish_payment($order_id, $pp_response);
                fn_order_placement_routines('route', $order_id);
            }
        }
    } else {
        if ($processor_data['processor_params']['test'] == 'live') {
            $post_address = "https://safe.cresecure.net/securepayments/a1/cc_collection.php";
        } else {
            $post_address = "https://sandbox-cresecure.net/securepayments/a1/cc_collection.php";
        }
        $post_data = array('CRESecureID' => $processor_data['processor_params']['cresecureid'], 'total_amt' => sprintf('%.2f', $order_info['total']), 'return_url' => fn_url("payment_notification.return?payment=cresecure&order_id={$order_id}", AREA, 'https'), 'content_template_url' => fn_payment_url('https', "cresecure.php?order_id={$order_id}&display_full_path=Y"), 'b_country' => db_get_field('SELECT a.code_A3 FROM ?:countries as a WHERE a.code = ?s', $order_info['b_country']), 's_country' => db_get_field('SELECT a.code_A3 FROM ?:countries as a WHERE a.code = ?s', $order_info['s_country']), 'customer_address' => $order_info['b_address'] . (!empty($order_info['b_address_2']) ? ' ' . $order_info['b_address_2'] : ''), 'delivery_address' => $order_info['s_address'] . (!empty($order_info['s_address_2']) ? ' ' . $order_info['s_address_2'] : ''), 'customer_phone' => !empty($order_info['b_phone']) ? $order_info['b_phone'] : '', 'delivery_phone' => !empty($order_info['s_phone']) ? $order_info['s_phone'] : '', 'allowed_types' => !empty($processor_data['processor_params']['allowed_types']) ? join('|', $processor_data['processor_params']['allowed_types']) : 'Visa|MasterCard', 'sess_id' => Session::getId(), 'sess_name' => Session::getName(), 'order_id' => $order_info['order_id'], 'currency' => $processor_data['processor_params']['currency'], 'CRESecureAPIToken' => $processor_data['processor_params']['cresecureapitoken'], 'customer_id' => $order_info['user_id'], 'customer_company' => $order_info['company'], 'customer_firstname' => $order_info['b_firstname'], 'customer_lastname' => $order_info['b_lastname'], 'customer_email' => $order_info['email'], 'customer_city' => $order_info['b_city'], 'customer_state' => $order_info['b_state'], 'customer_postal_code' => $order_info['b_zipcode'], 'customer_country' => $order_info['b_country'], 'delivery_firstname' => $order_info['s_firstname'], 'delivery_lastname' => $order_info['s_lastname'], 'delivery_city' => $order_info['s_city'], 'delivery_state' => $order_info['s_state'], 'delivery_postal_code' => $order_info['s_zipcode'], 'ip_address' => $_SERVER['REMOTE_ADDR']);
        fn_create_payment_form($post_address, $post_data, 'CRE secure', false);
    }
    exit;
}
Пример #8
0
/**
 * Dispathes the execution control to correct controller
 *
 * @return nothing
 */
function fn_dispatch($controller = '', $mode = '', $action = '', $dispatch_extra = '', $area = AREA)
{
    Debugger::checkpoint('After init');
    fn_set_hook('before_dispatch');
    $controller = empty($controller) ? Registry::get('runtime.controller') : $controller;
    $mode = empty($mode) ? Registry::get('runtime.mode') : $mode;
    $action = empty($action) ? Registry::get('runtime.action') : $action;
    $dispatch_extra = empty($dispatch_extra) ? Registry::get('runtime.dispatch_extra') : $dispatch_extra;
    $regexp = "/^[a-zA-Z0-9_\\+]+\$/";
    if (!preg_match($regexp, $controller) || !preg_match($regexp, $mode)) {
        throw new InputException('Error processing request');
    }
    $view = Registry::get('view');
    $run_controllers = true;
    $external = false;
    $status = CONTROLLER_STATUS_NO_PAGE;
    // Security
    if (Registry::get('config.tweaks.anti_csrf') == true) {
        $trusted_csrf_controllers = array('auth');
        if ($_SERVER['REQUEST_METHOD'] == 'POST' && !in_array($controller, $trusted_csrf_controllers) && (empty($_SESSION['security_hash']) || empty($_REQUEST['security_hash']) || $_REQUEST['security_hash'] != $_SESSION['security_hash'])) {
            fn_set_notification('E', __('error'), __('text_csrf_attack'));
            fn_redirect(fn_url());
        }
    }
    // If $config['http_host'] was different from the domain name, there was redirection to $config['http_host'] value.
    if (Registry::get('config.current_host') != REAL_HOST && $_SERVER['REQUEST_METHOD'] == 'GET' && !defined('CONSOLE')) {
        if (!empty($_SERVER['REDIRECT_URL'])) {
            $qstring = $_SERVER['REDIRECT_URL'];
        } else {
            if (!empty($_SERVER['REQUEST_URI'])) {
                $qstring = $_SERVER['REQUEST_URI'];
            } else {
                $qstring = Registry::get('config.current_url');
            }
        }
        $curent_path = Registry::get('config.current_path');
        if (!empty($curent_path) && strpos($qstring, $curent_path) === 0) {
            $qstring = substr_replace($qstring, '', 0, fn_strlen($curent_path));
        }
        fn_redirect(Registry::get('config.current_location') . $qstring, false, true);
    }
    if (isset($_SERVER['CONTENT_LENGTH']) && ($_SERVER['CONTENT_LENGTH'] > fn_return_bytes(ini_get('upload_max_filesize')) || $_SERVER['CONTENT_LENGTH'] > fn_return_bytes(ini_get('post_max_size')))) {
        $max_size = fn_return_bytes(ini_get('upload_max_filesize')) < fn_return_bytes(ini_get('post_max_size')) ? ini_get('upload_max_filesize') : ini_get('post_max_size');
        fn_set_notification('E', __('error'), __('text_forbidden_uploaded_file_size', array('[size]' => $max_size)));
        fn_redirect($_SERVER['HTTP_REFERER']);
    }
    // If URL contains session ID, remove it
    if (!empty($_REQUEST[Session::getName()]) && $_SERVER['REQUEST_METHOD'] == 'GET') {
        fn_redirect(fn_query_remove(Registry::get('config.current_url'), Session::getName()));
    }
    // If demo mode is enabled, check permissions FIX ME - why did we need one more user login check?
    if ($area == 'A') {
        if (Registry::get('config.demo_mode') == true) {
            $run_controllers = fn_check_permissions($controller, $mode, 'demo');
            if ($run_controllers == false) {
                fn_set_notification('W', __('demo_mode'), __('demo_mode_content_text'), 'K', 'demo_mode');
                if (defined('AJAX_REQUEST')) {
                    exit;
                }
                fn_delete_notification('changes_saved');
                $status = CONTROLLER_STATUS_REDIRECT;
                $_REQUEST['redirect_url'] = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : fn_url('');
            }
        } else {
            $run_controllers = fn_check_permissions($controller, $mode, 'admin', '', $_REQUEST);
            if ($run_controllers == false) {
                if (defined('AJAX_REQUEST')) {
                    $_info = Debugger::isActive() || defined('DEVELOPMENT') ? ' ' . $controller . '.' . $mode : '';
                    fn_set_notification('W', __('warning'), __('access_denied') . $_info);
                    exit;
                }
                $status = CONTROLLER_STATUS_DENIED;
            }
        }
    }
    if ($area == 'A' && Registry::get('settings.Security.secure_admin') == 'Y' && !defined('HTTPS') && $_SERVER['REQUEST_METHOD'] != 'POST' && !defined('AJAX_REQUEST') && empty($_REQUEST['keep_location']) && !defined('CONSOLE')) {
        fn_redirect(Registry::get('config.https_location') . '/' . Registry::get('config.current_url'));
    } elseif ($area == 'C' && $_SERVER['REQUEST_METHOD'] != 'POST' && !defined('AJAX_REQUEST')) {
        $secure_controllers = fn_get_secure_controllers();
        // if we are not on https but controller is secure, redirect to https
        if (isset($secure_controllers[$controller]) && $secure_controllers[$controller] == 'active' && !defined('HTTPS')) {
            fn_redirect(Registry::get('config.https_location') . '/' . Registry::get('config.current_url'));
        }
        // if we are on https and the controller is insecure, redirect to http
        if (!isset($secure_controllers[$controller]) && defined('HTTPS') && Registry::get('settings.Security.keep_https') != 'Y') {
            fn_redirect('http://' . Registry::get('config.http_host') . Registry::get('config.http_path') . '/' . Registry::get('config.current_url'));
        }
    }
    LastView::instance()->prepare($_REQUEST);
    $controllers_cascade = array();
    $controllers_list = array('init');
    if ($run_controllers == true) {
        $controllers_list[] = $controller;
        $controllers_list = array_unique($controllers_list);
    }
    foreach ($controllers_list as $ctrl) {
        $core_controllers = fn_init_core_controllers($ctrl);
        list($addon_controllers) = fn_init_addon_controllers($ctrl);
        if (empty($core_controllers) && empty($addon_controllers)) {
            //$controllers_cascade = array(); // FIXME: controllers_cascade contains INIT. We should not clear initiation code.
            $status = CONTROLLER_STATUS_NO_PAGE;
            $run_controllers = false;
            break;
        }
        if (count($core_controllers) + count($addon_controllers) > 1) {
            throw new DeveloperException('Duplicate controller ' . $controller . var_export(array_merge($core_controllers, $addon_controllers), true));
        }
        $core_pre_controllers = fn_init_core_controllers($ctrl, GET_PRE_CONTROLLERS);
        $core_post_controllers = fn_init_core_controllers($ctrl, GET_POST_CONTROLLERS);
        list($addon_pre_controllers) = fn_init_addon_controllers($ctrl, GET_PRE_CONTROLLERS);
        list($addon_post_controllers, $addons) = fn_init_addon_controllers($ctrl, GET_POST_CONTROLLERS);
        // we put addon post-controller to the top of post-controller cascade if current addon serves this request
        if (count($addon_controllers)) {
            $addon_post_controllers = fn_reorder_post_controllers($addon_post_controllers, $addon_controllers[0]);
        }
        $controllers_cascade = array_merge($controllers_cascade, $addon_pre_controllers, $core_pre_controllers, $core_controllers, $addon_controllers, $core_post_controllers, $addon_post_controllers);
        if (empty($controllers_cascade)) {
            throw new DeveloperException("No controllers for: {$ctrl}");
        }
    }
    if ($mode == 'add') {
        $tpl = 'update.tpl';
    } elseif (strpos($mode, 'add_') === 0) {
        $tpl = str_replace('add_', 'update_', $mode) . '.tpl';
    } else {
        $tpl = $mode . '.tpl';
    }
    $view = Registry::get('view');
    if ($view->templateExists('views/' . $controller . '/' . $tpl)) {
        // try to find template in base views
        $view->assign('content_tpl', 'views/' . $controller . '/' . $tpl);
    } elseif (defined('LOADED_ADDON_PATH') && $view->templateExists('addons/' . LOADED_ADDON_PATH . '/views/' . $controller . '/' . $tpl)) {
        // try to find template in addon views
        $view->assign('content_tpl', 'addons/' . LOADED_ADDON_PATH . '/views/' . $controller . '/' . $tpl);
    } elseif (!empty($addons)) {
        // try to find template in addon views that extend base views
        foreach ($addons as $addon => $_v) {
            if ($view->templateExists('addons/' . $addon . '/views/' . $controller . '/' . $tpl)) {
                $view->assign('content_tpl', 'addons/' . $addon . '/views/' . $controller . '/' . $tpl);
                break;
            }
        }
    }
    fn_set_hook('dispatch_assign_template', $controller, $mode, $area);
    foreach ($controllers_cascade as $item) {
        $_res = fn_run_controller($item, $controller, $mode, $action, $dispatch_extra);
        // 0 - status, 1 - url
        $url = !empty($_res[1]) ? $_res[1] : '';
        $external = !empty($_res[2]) ? $_res[2] : false;
        $permanent = !empty($_res[3]) ? $_res[3] : false;
        // Status could be changed only if we allow to run controllers despite of init controller
        if ($run_controllers == true) {
            $status = !empty($_res[0]) ? $_res[0] : CONTROLLER_STATUS_OK;
        }
        if ($status == CONTROLLER_STATUS_OK && !empty($url)) {
            $redirect_url = $url;
        } elseif ($status == CONTROLLER_STATUS_REDIRECT && !empty($url)) {
            $redirect_url = $url;
            break;
        } elseif ($status == CONTROLLER_STATUS_DENIED || $status == CONTROLLER_STATUS_NO_PAGE) {
            break;
        }
    }
    LastView::instance()->init($_REQUEST);
    // In console mode, just stop here
    if (defined('CONSOLE')) {
        exit;
    }
    if (!empty($_SESSION['auth']['this_login']) && Registry::ifGet($_SESSION['auth']['this_login'], 'N') === 'Y') {
        fn_set_notification('E', __('error'), __(ACCOUNT_TYPE . LOGIN_STATUS_USER_DISABLED));
        $status = CONTROLLER_STATUS_DENIED;
    }
    // [Block manager]
    // block manager is disabled for vendors.
    if (!(fn_allowed_for('MULTIVENDOR') && Registry::get('runtime.company_id') || fn_allowed_for('ULTIMATE') && !Registry::get('runtime.company_id'))) {
        if (fn_check_permissions('block_manager', 'manage', 'admin')) {
            $dynamic_object = SchemesManager::getDynamicObject($_REQUEST['dispatch'], $area);
            if (!empty($dynamic_object)) {
                if ($area == 'A' && Registry::get('runtime.mode') != 'add' && !empty($_REQUEST[$dynamic_object['key']])) {
                    $object_id = $_REQUEST[$dynamic_object['key']];
                    $location = Location::instance()->get($dynamic_object['customer_dispatch'], $dynamic_object, CART_LANGUAGE);
                    if (!empty($location) && $location['is_default'] != 1) {
                        $params = array('dynamic_object' => array('object_type' => $dynamic_object['object_type'], 'object_id' => $object_id), $dynamic_object['key'] => $object_id, 'manage_url' => Registry::get('config.current_url'));
                        Registry::set('navigation.tabs.blocks', array('title' => __('layouts'), 'href' => 'block_manager.manage_in_tab?' . http_build_query($params), 'ajax' => true));
                    }
                }
            }
        }
    }
    // [/Block manager]
    // Redirect if controller returned successful/redirect status only
    if (in_array($status, array(CONTROLLER_STATUS_OK, CONTROLLER_STATUS_REDIRECT)) && !empty($_REQUEST['redirect_url']) && !$external) {
        $redirect_url = $_REQUEST['redirect_url'];
    }
    // If controller returns "Redirect" status, check if redirect url exists
    if ($status == CONTROLLER_STATUS_REDIRECT && empty($redirect_url)) {
        $status = CONTROLLER_STATUS_NO_PAGE;
    }
    // In backend show "changes saved" notification
    if ($area == 'A' && $_SERVER['REQUEST_METHOD'] == 'POST' && in_array($status, array(CONTROLLER_STATUS_OK, CONTROLLER_STATUS_REDIRECT))) {
        if (strpos($mode, 'update') !== false && !fn_notification_exists('extra', 'demo_mode') && !fn_notification_exists('type', 'E')) {
            fn_set_notification('N', __('notice'), __('text_changes_saved'), 'I', 'changes_saved');
        }
    }
    // Attach params and redirect if needed
    if (in_array($status, array(CONTROLLER_STATUS_OK, CONTROLLER_STATUS_REDIRECT)) && !empty($redirect_url)) {
        $params = array('page', 'selected_section', 'active_tab');
        $url_params = array();
        foreach ($params as $param) {
            if (!empty($_REQUEST[$param])) {
                $url_params[$param] = $_REQUEST[$param];
            }
        }
        if (!empty($url_params)) {
            $redirect_url = fn_link_attach($redirect_url, http_build_query($url_params));
        }
        if (!isset($external)) {
            $external = false;
        }
        if (!isset($permanent)) {
            $permanent = false;
        }
        fn_redirect($redirect_url, $external, $permanent);
    }
    if (!$view->getTemplateVars('content_tpl') && $status == CONTROLLER_STATUS_OK) {
        // FIXME
        $status = CONTROLLER_STATUS_NO_PAGE;
    }
    if ($status != CONTROLLER_STATUS_OK) {
        if ($status == CONTROLLER_STATUS_NO_PAGE) {
            if ($area == 'A' && empty($_SESSION['auth']['user_id'])) {
                // If admin is not logged in redirect to login page from not found page
                fn_set_notification('W', __('page_not_found'), __('page_not_found_text'));
                fn_redirect("auth.login_form");
            }
            header(' ', true, 404);
        }
        $view->assign('exception_status', $status);
        if ($area == 'A') {
            $view->assign('content_tpl', 'exception.tpl');
            // for backend only
        }
        if ($status == CONTROLLER_STATUS_DENIED) {
            $view->assign('page_title', __('access_denied'));
        } elseif ($status == CONTROLLER_STATUS_NO_PAGE) {
            $view->assign('page_title', __('page_not_found'));
        }
    }
    fn_set_hook('dispatch_before_display');
    Debugger::checkpoint('Before TPL');
    // Pass current URL to ajax response only if we render whole page
    if (defined('AJAX_REQUEST') && Registry::get('runtime.root_template') == 'index.tpl') {
        Registry::get('ajax')->assign('current_url', fn_url(Registry::get('config.current_url'), $area, 'current'));
    }
    Registry::get('view')->display(Registry::get('runtime.root_template'));
    Debugger::checkpoint('After TPL');
    Debugger::display();
    fn_set_hook('complete');
    exit;
    // stop execution
}