Created
October 31, 2019 08:35
-
-
Save jasminsuljic/5955c8ed715bee6060c2208626a55bcc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace app\controllers; | |
use http\Exception\InvalidArgumentException; | |
use Yii; | |
use yii\base\Security; | |
use yii\helpers\Json; | |
use yii\helpers\Url; | |
use yii\helpers\VarDumper; | |
use yii\web\Controller; | |
use yii\web\HttpException; | |
use yii\web\Response; | |
class ExampleController extends Controller | |
{ | |
var $url; | |
var $appUrl; | |
public function beforeAction($action) | |
{ | |
\Yii::$app->response->format = Response::FORMAT_JSON; | |
return parent::beforeAction($action); | |
} | |
public function init() | |
{ | |
parent::init(); | |
// Test env url -> https://ipgtest.monri.com | |
// Prod env url -> https://ipg.monri.com | |
$this->url = Yii::$app->params['baseUrlTest']; | |
// Your application url | |
$this->appUrl = !isset(Yii::$app->params['appUrl']) ? "https://mobile.webteh.hr" : Yii::$app->params['appUrl']; | |
} | |
/** | |
* @return array | |
* @throws HttpException | |
*/ | |
public function actionOrder() | |
{ | |
$this->checkIfPostRequest(); | |
$transactionData = $this->transactionData('purchase'); | |
$transactionAuthorizationResponse = $this->transactionAuthorization($this->url, $transactionData); | |
if ($transactionAuthorizationResponse['status'] == 'declined') { | |
return [ | |
'status' => 'declined', | |
'response' => $transactionAuthorizationResponse | |
]; | |
} | |
$response = $transactionAuthorizationResponse['response']; | |
if ($this->isSecureMessageResponse($response)) { | |
return $this->userActionRequired($transactionData['order_number'], $response['secure_message']); | |
} else if ($this->isTransactionResponse($response)) { | |
$transaction = $response['transaction']; | |
$this->updateOrder($transaction); | |
return [ | |
'status' => self::statusFromTrxResponse($transaction), | |
'transaction' => $transaction | |
]; | |
} else { | |
// This should never happen | |
return [ | |
'status' => 'declined', | |
'transaction' => $response | |
]; | |
} | |
} | |
function isSecureMessageResponse($response) | |
{ | |
return $response && isset($response['secure_message']); | |
} | |
function isTransactionResponse($response) | |
{ | |
return $response && isset($response['transaction']); | |
} | |
function threeDsFormUrl($id) | |
{ | |
return Url::to($this->appUrl . "/example/three-ds-form?id=$id"); | |
} | |
function threeDSForm($data) | |
{ | |
$str = <<<HTML | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>3D Secure Verification</title> | |
<script language="Javascript"> | |
function OnLoadEvent() { | |
document.form.submit(); | |
} | |
</script> | |
</head> | |
<body OnLoad="OnLoadEvent();"> | |
Invoking 3-D secure form, please wait ... | |
<form name="form" action="{$data['acs_url']}" method="post"> | |
<input type="hidden" name="PaReq" value="{$data['pareq']}"> | |
<input type="hidden" name="TermUrl" value="{$data['term_url']}"> | |
<input type="hidden" name="MD" value="{$data['authenticity_token']}"> | |
<noscript> | |
<p>Please click</p> | |
<input id="to-acs-button" type="submit"> | |
</noscript> | |
</form> | |
</body> | |
</html> | |
HTML; | |
return $str; | |
} | |
function transactionData($transactionType) | |
{ | |
$amount = '100'; | |
$sec = new Security(); | |
$currency = 'EUR'; | |
$order_number = Yii::$app->request->post('order_number'); | |
$key = 'TestKeyXULLyvgWyPJSwOHe'; // TODO: replace with your merchant's key | |
$authenticity_token = '6a13d79bde8da9320e88923cb3472fb638619ccb'; // TODO: replace with your merchant's authenticity token | |
//digest = SHA512(key + order_number + amount + currency) | |
$digest = hash('sha512', $key . $order_number . $amount . $currency); | |
return [ | |
"transaction_type" => $transactionType, | |
"amount" => $amount, | |
"ip" => '10.1.10.111', | |
'order_info' => 'Monri components trx', | |
'ch_address' => 'Adresa', | |
'ch_city' => 'Grad', | |
'ch_country' => 'BIH', | |
'ch_email' => 'test@test.com', | |
'ch_full_name' => 'Test', | |
'ch_phone' => '061 000 000', | |
'ch_zip' => '71000', | |
'currency' => $currency, | |
'digest' => $digest, | |
'order_number' => $order_number, | |
'authenticity_token' => $authenticity_token, | |
'language' => 'en', | |
// This part is important! Extract monriToken from post body | |
'temp_card_id' => Yii::$app->request->post('monriToken') | |
]; | |
} | |
public function actionThreeDsForm() | |
{ | |
Yii::$app->response->format = Response::FORMAT_HTML; | |
return $this->threeDSForm(Yii::$app->cache->get(Yii::$app->request->get('id'))); | |
} | |
private static function statusFromTrxResponse($response) | |
{ | |
$approved = $response['status'] === 'approved' && $response['response_code'] === '0000'; | |
return $approved ? 'approved' : 'declined'; | |
} | |
function updateOrder($transaction) | |
{ | |
$status = self::statusFromTrxResponse($transaction); | |
if ('approved' === $status) { | |
// execute order | |
// Save in db | |
// deliver goods | |
} else { | |
// reverse | cancel order | |
// Save in db | |
} | |
} | |
/** | |
* @throws HttpException | |
*/ | |
public function checkIfPostRequest() | |
{ | |
if (!\Yii::$app->request->isPost) { | |
throw new HttpException(405); | |
} | |
} | |
private function userActionRequired($order_number, $secure_message) | |
{ | |
\Yii::$app->cache->set($order_number, [ | |
"acs_url" => $secure_message['acs_url'], | |
"pareq" => $secure_message['acs_url'], | |
"authenticity_token" => $secure_message['authenticity_token'], | |
'term_url' => Url::to($this->appUrl . "/example/three-ds-result?id=$order_number") | |
]); | |
return [ | |
'status' => 'action_required', | |
'action' => [ | |
'redirect_to' => $this->threeDsFormUrl($order_number) | |
] | |
]; | |
} | |
/** | |
* @param $id | |
* @throws HttpException | |
*/ | |
public function actionThreeDsResult($id) | |
{ | |
$this->checkIfPostRequest(); | |
$data = Yii::$app->request->post(); | |
$paresResponse = $this->pares($this->url, $data); | |
Yii::$app->cache->delete($id); | |
if ($paresResponse['status'] == 'declined') { | |
$this->redirect("monriapp://example.monri.com/transaction-result?order_number=$id"); | |
} else { | |
$response = $paresResponse['response']; | |
if ($this->isTransactionResponse($response)) { | |
$transaction = $response['transaction']; | |
$this->updateOrder($transaction); | |
} else { | |
// This should not happen | |
} | |
$this->redirect("monriapp://example.monri.com/transaction-result?order_number=$id"); | |
} | |
} | |
function transactionAuthorization($url, $data) | |
{ | |
$result = ''; | |
try { | |
/** @noinspection DuplicatedCode */ | |
$data_string = Json::encode(['transaction' => $data]); | |
// Execute transaction | |
$ch = curl_init($url . '/v2/transaction'); | |
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_HTTPHEADER, array( | |
'Content-Type: application/json', | |
'Content-Length: ' . strlen($data_string)) | |
); | |
$result = curl_exec($ch); | |
if (curl_errno($ch)) { | |
return ['response' => null, 'status' => 'declined', 'error' => curl_error($ch)]; | |
} | |
curl_close($ch); | |
return ['response' => Json::decode($result), 'status' => 'approved']; | |
} catch (\Exception $exception) { | |
return ['response' => null, 'status' => 'declined', 'result' => $result, 'url' => $url]; | |
} | |
} | |
function pares($url, $data) | |
{ | |
$data_string = Json::encode($data); | |
$ch = curl_init($url . '/v2/pares'); | |
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); | |
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); | |
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($ch, CURLOPT_HTTPHEADER, array( | |
'Content-Type: application/json', | |
'Content-Length: ' . strlen($data_string)) | |
); | |
$result = curl_exec($ch); | |
$result = curl_exec($ch); | |
if (curl_errno($ch)) { | |
return ['response' => null, 'status' => 'declined', 'error' => curl_error($ch)]; | |
} | |
return ['response' => Json::decode($result), 'status' => 'approved']; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment