<?php

define('SECRET_KEY', 'hmONCD8TEa6SUeRd'); // секретный ключ проекта

abstract class DBConfig {
    const HOST = 'localhost';
    const PORT = '11211'; //mysql порт (default: 11211)
    const USER = 'db1'; //имя пользователя
    const PASS = '4S8f8P5s'; //пароль
    const DB = 'db1'; //база данных

}

abstract class ResponseCode {
    const OK = 0;
    const ERROR_TEMP = 1;
    const NO_USER = 2;
    const INVALID_USER = 7;
    const INVALID_INVOICE = 2;
    const INVALID_MD5 = 3;
    const INVALID_REQUEST = 4;
    const ERROR_OTHER = 5;
    const ERROR_TECHNICAL = 7;
    const ERROR_NOCANCEL = 7;

}

abstract class VirtualCurrencyXsolla {

    private $db;
    private $params;
    public $id;
    public $id_user;
    public $sum;
    public $md5;

    public function __construct() {
        //set custom error handler
        set_exception_handler(array($this, 'errorHandler'));
        $this->id = Yii::app()->request->getParam('id');
        $this->id_user = Yii::app()->request->getParam('v1');
        $this->sum = Yii::app()->request->getParam('sum');
        $this->md5 = Yii::app()->request->getParam('md5');
    }

    public function process() {
        //define whitelist of Xsolla ip addresses
        $whiteList = array("185.30.20.17", "185.30.20.18", "185.30.20.18", "185.30.20.19", "185.30.20.20", "185.30.20.21", "185.30.20.22",
            "185.30.21.17", "185.30.21.18", "185.30.21.18", "185.30.21.19", "185.30.21.20", "185.30.21.21", "185.30.21.22",
            "185.30.20.0", "94.103.26.178", "94.103.26.181", "159.255.220.241", "159.255.220.242",
            "159.255.220.243", "159.255.220.244", "159.255.220.245", "159.255.220.246",
            "159.255.220.247", "159.255.220.248", "159.255.220.249", "159.255.220.250",
            "159.255.220.251", "159.255.220.252", "159.255.220.253", "159.255.220.254");
        //make sure the request came from Xsolla
        if (!in_array($_SERVER['REMOTE_ADDR'], $whiteList))
            throw new Exception('originating ip address not in IP whitelist.');
        //make sure command is set
        if (!isset($_GET['command']))
            throw new Exception('param "command" was not included in request.');
        //select appropriate method via param 'command'
        switch ($_GET['command']) {
            case 'check': $this->params = array('v1', 'md5');
                break;
            case 'pay': $this->params = array('id', 'v1', 'sum', 'md5');
                break;
            case 'cancel': $this->params = array('id', 'md5');
                break;
            default: throw new Exception($_GET['command'] . ' is not an acceptable command.');
                break;
        }

        //make sure the required parameters were included in the request
        $this->validateParams($this->params);
        //validate the md5 hash
        if (!$this->validHash())
            $this->createResponse(ResponseCode::INVALID_MD5, 'invalid signature.');
        //call the appropriate method
        $this->$_GET['command']();
    }

    public function check() {
        $responseCode = ResponseCode::OK;
        $responseMsg = 'OK';
        //user exists or no?
        $userExists = $this->userExists($this->id_user);
        if (!$userExists) {
            $responseCode = ResponseCode::INVALID_USER;
            $responseMsg = 'user does not exist.';
        }
        $this->createResponse($responseCode, $responseMsg);
    }

    public function pay() {

        $responseCode = ResponseCode::OK;
        $responseMsg = 'OK';

        $userExists = $this->userExists($this->id_user);

        if (!$userExists) {
            $responseCode = ResponseCode::NO_USER;
            $responseMsg = 'user does not exist.';
        }
        else {
            $invoiceExists = $this->invoiceExists($this->id);

            if (!$invoiceExists)
                $this->newInvoice($this->id, $this->id_user, $this->sum);
            if ($responseMsg == 'OK' and ! $invoiceExists) {
                $this->paySuccess($this->id_user, $this->sum, $this->id);
            }
        }
        $this->createResponse($responseCode, $responseMsg);
    }

    public function cancel() {
        $responseCode = ResponseCode::OK;
        $responseMsg = 'OK';

        //does the invoice exist?
        $invoiceExists = $this->invoiceExists($this->id);

        if (!$invoiceExists) {
            $responseCode = ResponseCode::INVALID_INVOICE;
            $responseMsg = 'invoice not found.';
        } else {
            $this->cancelInvoice($this->id);
            $this->payCancel($this->id);
        }
        $this->createResponse($responseCode, $responseMsg);
    }

    protected function validateParams($params) {
        //check that required parameters where included in the request
        $error = array();
        foreach ($params as $param)
            if (!isset($_GET[$param]))
                $error[] = $param;
        if (count($error) > 0)
            throw new Exception('param "' . implode('", "', $error) . '" not included in request.');
    }

    protected function validHash() {
        $invoiceID = isset($this->id) ? $this->id : '';
        return md5($_GET['command'] . $this->id_user . $invoiceID . SECRET_KEY) == $this->md5;
    }

    protected function createResponse($responseCode, $responseMsg) {
        $xml = new SimpleXMLElement('<response></response>');
        $xml->addChild('result', $responseCode);
        if ($_GET['command'] == "pay") {
            $xml->addChild("sum", $this->sum);
            $xml->addChild("id_shop", $this->id);
        }
        if ($_GET['command'] == "cancel") {
            
        }
        if ($responseMsg)
            $xml->addChild('comment', $responseMsg);
        header('Content-Type: text/xml; charset=cp1251');
        echo html_entity_decode($xml->asXML(), ENT_COMPAT, 'windows-1251');
        exit;
    }

    public static function errorHandler($e) {
        $xml = new SimpleXMLElement('<response></response>');
        $xml->addChild('result', ResponseCode::ERROR_TECHNICAL);
        $xml->addChild('comment', $e->getMessage());
        header('Content-Type: text/xml; charset=cp1251');
        echo html_entity_decode($xml->asXML(), ENT_COMPAT, 'windows-1251');
        exit;
    }
}
?>