Day 0x9 - 插播 - 建立 Sinopac Controller

0x1 前言

  • 是的,要继续写 Webhook 时却发现,Day 0x4 ~ 0x6 写的函数的都没有先包装好,要呼叫 API 时得再写一次,所以今天先把要传得先包好。
  • 严格来说应该是要建立 Service,但这个分界点一直有点混乱,因此这里依照自己脑海的想法来走,欢迎各位给我建议。

0x2 API Controller 建立

$ php artisan make:controller Sinopac

然後把函数建立好,如下

// app/Http/Controllers/Sinopac.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;

class Sinopac extends Controller
{
    private $shop_no;
    private $key_a1;
    private $key_a2;
    private $key_b1;
    private $key_b2;

    public function __construct(string $shop_no, string $key_a1, string $key_a2, string $key_b1, string $key_b2)
    {
        $this->shop_no = $shop_no;
        $this->key_a1 = $key_a1;
        $this->key_a2 = $key_a2;
        $this->key_b1 = $key_b1;
        $this->key_b2 = $key_b2;
    }

    public function callApi($url, $post_data)
    {
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_HEADER => 0,
            CURLOPT_NOBODY => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_HTTPHEADER => ["Content-type: application/json; charset=utf-8"],
            CURLOPT_POST => 1,
            CURLOPT_POSTFIELDS => json_encode($post_data),
            CURLOPT_SSL_VERIFYPEER => 0,
            CURLOPT_SSL_VERIFYHOST => 0,
            CURLOPT_SSLVERSION => 6
        ]);
        $result = curl_exec($ch);
        curl_close($ch);

        return json_decode($result, true);
    }

    public function getNonce()
    {
        $url = 'https://sandbox.sinopac.com/QPay.WebAPI/api/Nonce';
        return $this->callApi($url, ['ShopNo' => $this->shop_no]);
    }

    public function calculateIv($nonce): string
    {
        $hash = hash('SHA256', $nonce);
        return strtoupper(substr($hash, 48));
    }

    private function calcHashId(): string
    {
        $a = $b = '';
        $length = strlen($this->key_a1);
        for ($i = 0; $i < $length; $i += 4) {
            $a .= dechex(hexdec(substr($this->key_a1, $i, 4)) ^ hexdec(substr($this->key_a2, $i, 4)));
            $b .= dechex(hexdec(substr($this->key_b1, $i, 4)) ^ hexdec(substr($this->key_b2, $i, 4)));
        }
        return strtoupper($a . $b);
    }

    public function generateSign($data, $nonce, $hash_id): string
    {
        $keys = array_keys($data);
        foreach ($keys as $key) {
            $value = array_shift($data);
            if (gettype($value) === 'array' || trim($value) === '') {
                continue;
            }

            $upper_key = strtoupper($key);
            $data[$upper_key] = "$key=$value";
        }

        ksort($data);
        $body = implode('&', $data) . $nonce . $hash_id;
        return strtoupper(hash('sha256', $body));
    }

    public function encryptMessage($data, $key, $iv): string
    {
        $data = json_encode(array_filter((array)($data)));

        $padding = 16 - (strlen($data) % 16);
        $data .= str_repeat(chr($padding), $padding);
        $encrypt = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);

        return strtoupper(bin2hex($encrypt));
    }

    public function decryptMessage($data, $key, $iv)
    {
        $encrypt = hex2bin($data);
        $decrypt = openssl_decrypt($encrypt, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
        $padding = ord($decrypt[strlen($decrypt) - 1]);

        $result = substr($decrypt, 0, -$padding);
        return json_decode($result, true);
    }
}

0x3 今日小结

  • 今天花了一些时间整理程序,看能不能再把函数切得更细,虽然都是复制贴上前几天的程序码 ;D
  • 明天把 recevie_msg 完成

<<:  Day19 javascript 阵列方法-1

>>:  【没钱买ps,PyQt自己写】Day 4 - 重要的 Qt 程序逻辑观念,务必先有此观念後面才会懂自己在干嘛

Day 33 | 常见 Livewire 问题:解决 Livewire.on() 没有作用的问题

这个问题其实在 Day8 的文章有稍微提到过,但大多数人看文件时都大致看一下而会忽略一些小细节,包含...

第二十八天:UI切版 & 元件-清单表格、弹出视窗

※ 今天的内容 一、清单表格:QTable、QMarkupTable 二、弹出视窗:QDialog、...

工作散记 - Spotify for Developers

embed 连结格式: Podcast - https://open.spotify.com/em...

【Day 28】Hook 08:useCallback

useCallback 如果父元件所传递的 props 包含 Object, 则在元件因状态改变而 ...

远端系列-3:如何更新远端数据库的档案?

角色情境 小华一边讲解、一边指导小明如何使用 GitHub 建立远端数据库。 小明认真地遵循小华的指...