Issues (83)

src/Payment/Notify/Handler.php (3 issues)

Labels
1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace EasyWeChat\Payment\Notify;
13
14
use Closure;
15
use EasyWeChat\Kernel\Exceptions\Exception;
16
use EasyWeChat\Kernel\Support;
17
use EasyWeChat\Kernel\Support\XML;
18
use EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException;
19
use Symfony\Component\HttpFoundation\Response;
20
21
abstract class Handler
22
{
23
    public const SUCCESS = 'SUCCESS';
24
    public const FAIL = 'FAIL';
25
26
    /**
27
     * @var \EasyWeChat\Payment\Application
28
     */
29
    protected $app;
30
31
    /**
32
     * @var array
33
     */
34
    protected $message;
35
36
    /**
37
     * @var string|null
38
     */
39
    protected $fail;
40
41
    /**
42
     * @var array
43
     */
44
    protected $attributes = [];
45
46
    /**
47
     * Check sign.
48
     * If failed, throws an exception.
49
     *
50
     * @var bool
51
     */
52
    protected $check = true;
53
54
    /**
55
     * Respond with sign.
56
     *
57
     * @var bool
58
     */
59
    protected $sign = false;
60
61
    /**
62
     * @param \EasyWeChat\Payment\Application $app
63
     */
64 9
    public function __construct($app)
65
    {
66 9
        $this->app = $app;
67 9
    }
68
69
    /**
70
     * Handle incoming notify.
71
     *
72
     * @param \Closure $closure
73
     *
74
     * @return \Symfony\Component\HttpFoundation\Response
75
     */
76
    abstract public function handle(Closure $closure);
77
78
    /**
79
     * @param string $message
80
     */
81 3
    public function fail(string $message)
82
    {
83 3
        $this->fail = $message;
84 3
    }
85
86
    /**
87
     * @param array $attributes
88
     * @param bool  $sign
89
     *
90
     * @return $this
91
     */
92 2
    public function respondWith(array $attributes, bool $sign = false)
93
    {
94 2
        $this->attributes = $attributes;
95 2
        $this->sign = $sign;
96
97 2
        return $this;
98
    }
99
100
    /**
101
     * Build xml and return the response to WeChat.
102
     *
103
     * @return \Symfony\Component\HttpFoundation\Response
104
     *
105
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
106
     */
107 4
    public function toResponse(): Response
108
    {
109
        $base = [
110 4
            'return_code' => is_null($this->fail) ? static::SUCCESS : static::FAIL,
111 4
            'return_msg' => $this->fail,
112
        ];
113
114 4
        $attributes = array_merge($base, $this->attributes);
115
116 4
        if ($this->sign) {
117 2
            $attributes['sign'] = Support\generate_sign($attributes, $this->app->getKey());
0 ignored issues
show
The function generate_sign was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

117
            $attributes['sign'] = /** @scrutinizer ignore-call */ Support\generate_sign($attributes, $this->app->getKey());
Loading history...
118
        }
119
120 4
        return new Response(XML::build($attributes));
121
    }
122
123
    /**
124
     * Return the notify message from request.
125
     *
126
     * @return array
127
     *
128
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
129
     */
130 9
    public function getMessage(): array
131
    {
132 9
        if (!empty($this->message)) {
133 4
            return $this->message;
134
        }
135
136
        try {
137 9
            $message = XML::parse(strval($this->app['request']->getContent()));
138 1
        } catch (\Throwable $e) {
139 1
            throw new Exception('Invalid request XML: '.$e->getMessage(), 400);
140
        }
141
142 8
        if (!is_array($message) || empty($message)) {
0 ignored issues
show
The condition is_array($message) is always true.
Loading history...
143 1
            throw new Exception('Invalid request XML.', 400);
144
        }
145
146 7
        if ($this->check) {
147 2
            $this->validate($message);
148
        }
149
150 6
        return $this->message = $message;
151
    }
152
153
    /**
154
     * Decrypt message.
155
     *
156
     * @param string $key
157
     *
158
     * @return string|null
159
     *
160
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
161
     */
162 3
    public function decryptMessage(string $key)
163
    {
164 3
        $message = $this->getMessage();
165 3
        if (empty($message[$key])) {
166 2
            return null;
167
        }
168
169 2
        return Support\AES::decrypt(
170 2
            base64_decode($message[$key], true),
171 2
            md5($this->app['config']->key),
172 2
            '',
173 2
            OPENSSL_RAW_DATA,
174 2
            'AES-256-ECB'
175
        );
176
    }
177
178
    /**
179
     * Validate the request params.
180
     *
181
     * @param array $message
182
     *
183
     * @throws \EasyWeChat\Payment\Kernel\Exceptions\InvalidSignException
184
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
185
     */
186 2
    protected function validate(array $message)
187
    {
188 2
        $sign = $message['sign'];
189 2
        unset($message['sign']);
190
191 2
        if (Support\generate_sign($message, $this->app->getKey()) !== $sign) {
0 ignored issues
show
The function generate_sign was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

191
        if (/** @scrutinizer ignore-call */ Support\generate_sign($message, $this->app->getKey()) !== $sign) {
Loading history...
192 1
            throw new InvalidSignException();
193
        }
194 1
    }
195
196
    /**
197
     * @param mixed $result
198
     */
199 2
    protected function strict($result)
200
    {
201 2
        if (true !== $result && is_null($this->fail)) {
202 2
            $this->fail(strval($result));
203
        }
204 2
    }
205
}
206