Completed
Push — master ( a679b5...bc4430 )
by Carlos
03:34
created

Http::getHandler()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 5
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 10
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
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
/**
13
 * Http.php.
14
 *
15
 * This file is part of the wechat-components.
16
 *
17
 * (c) overtrue <[email protected]>
18
 *
19
 * This source file is subject to the MIT license that is bundled
20
 * with this source code in the file LICENSE.
21
 */
22
namespace EasyWeChat\Core;
23
24
use EasyWeChat\Core\Exceptions\HttpException;
25
use EasyWeChat\Support\Log;
26
use GuzzleHttp\Client as HttpClient;
27
use GuzzleHttp\HandlerStack;
28
use Psr\Http\Message\ResponseInterface;
29
30
/**
31
 * Class Http.
32
 */
33
class Http
34
{
35
    /**
36
     * Http client.
37
     *
38
     * @var HttpClient
39
     */
40
    protected $client;
41
42
    /**
43
     * The middlewares.
44
     *
45
     * @var array
46
     */
47
    protected $middlewares = [];
48
49
    /**
50
     * Guzzle client default settings.
51
     *
52
     * @var array
53
     */
54
    protected static $defaults = [];
55
56
    /**
57
     * Set guzzle default settings.
58
     *
59
     * @param array $defaults
60
     */
61 4
    public static function setDefaultOptions($defaults = [])
62
    {
63 4
        self::$defaults = $defaults;
64 4
    }
65
66
    /**
67
     * Return current guzzle default settings.
68
     *
69
     * @return array
70
     */
71 1
    public static function getDefaultOptions()
72
    {
73 1
        return self::$defaults;
74
    }
75
76
    /**
77
     * GET request.
78
     *
79
     * @param string $url
80
     * @param array  $options
81
     *
82
     * @return ResponseInterface
83
     *
84
     * @throws HttpException
85
     */
86 2
    public function get($url, array $options = [])
87
    {
88 2
        return $this->request($url, 'GET', ['query' => $options]);
89
    }
90
91
    /**
92
     * POST request.
93
     *
94
     * @param string       $url
95
     * @param array|string $options
96
     *
97
     * @return ResponseInterface
98
     *
99
     * @throws HttpException
100
     */
101 1
    public function post($url, $options = [])
102
    {
103 1
        $key = is_array($options) ? 'form_params' : 'body';
104
105 1
        return $this->request($url, 'POST', [$key => $options]);
106
    }
107
108
    /**
109
     * JSON request.
110
     *
111
     * @param string       $url
112
     * @param string|array $options
113
     * @param int          $encodeOption
114
     *
115
     * @return ResponseInterface
116
     *
117
     * @throws HttpException
118
     */
119 1
    public function json($url, $options = [], $encodeOption = JSON_UNESCAPED_UNICODE)
120
    {
121 1
        is_array($options) && $options = json_encode($options, $encodeOption);
122
123 1
        return $this->request($url, 'POST', ['body' => $options, 'headers' => ['content-type' => 'application/json']]);
124
    }
125
126
    /**
127
     * Upload file.
128
     *
129
     * @param string $url
130
     * @param array  $files
131
     * @param array  $form
132
     *
133
     * @return ResponseInterface
134
     *
135
     * @throws HttpException
136
     */
137 1
    public function upload($url, array $files = [], array $form = [], array $queries = [])
138
    {
139 1
        $multipart = [];
140
141 1
        foreach ($files as $name => $path) {
142 1
            $multipart[] = [
143 1
                'name' => $name,
144 1
                'contents' => fopen($path, 'r'),
145
            ];
146 1
        }
147
148 1
        foreach ($form as $name => $contents) {
149 1
            $multipart[] = compact('name', 'contents');
150 1
        }
151
152 1
        return $this->request($url, 'POST', ['query' => $queries, 'multipart' => $multipart]);
153
    }
154
155
    /**
156
     * Set GuzzleHttp\Client.
157
     *
158
     * @param \GuzzleHttp\Client $client
159
     *
160
     * @return Http
161
     */
162 6
    public function setClient(HttpClient $client)
163
    {
164 6
        $this->client = $client;
165
166 6
        return $this;
167
    }
168
169
    /**
170
     * Return GuzzleHttp\Client instance.
171
     *
172
     * @return \GuzzleHttp\Client
173
     */
174 4
    public function getClient()
175
    {
176 4
        if (!($this->client instanceof HttpClient)) {
177 2
            $this->client = new HttpClient();
178 2
        }
179
180 4
        return $this->client;
181
    }
182
183
    /**
184
     * Add a middleware.
185
     *
186
     * @param callable $middleware
187
     *
188
     * @return $this
189
     */
190 9
    public function addMiddleware(callable $middleware)
191
    {
192 9
        array_push($this->middlewares, $middleware);
193
194 9
        return $this;
195
    }
196
197
    /**
198
     * Return all middlewares.
199
     *
200
     * @return array
201
     */
202 9
    public function getMiddlewares()
203
    {
204 9
        return $this->middlewares;
205
    }
206
207
    /**
208
     * Make a request.
209
     *
210
     * @param string $url
211
     * @param string $method
212
     * @param array  $options
213
     *
214
     * @return ResponseInterface
215
     *
216
     * @throws HttpException
217
     */
218 3
    public function request($url, $method = 'GET', $options = [])
219
    {
220 3
        $method = strtoupper($method);
221
222 3
        $options = array_merge(self::$defaults, $options);
223
224 3
        Log::debug('Client Request:', compact('url', 'method', 'options'));
225
226 3
        $options['handler'] = $this->getHandler();
227
228 3
        $response = $this->getClient()->request($method, $url, $options);
229
230 3
        Log::debug('API response:', [
231 3
            'Status' => $response->getStatusCode(),
232 3
            'Reason' => $response->getReasonPhrase(),
233 3
            'Headers' => $response->getHeaders(),
234 3
            'Body' => strval($response->getBody()),
235 3
        ]);
236
237 3
        return $response;
238
    }
239
240
    /**
241
     * @param \Psr\Http\Message\ResponseInterface|string $body
242
     *
243
     * @return mixed
244
     *
245
     * @throws \EasyWeChat\Core\Exceptions\HttpException
246
     */
247 10
    public function parseJSON($body)
248
    {
249 10
        if ($body instanceof ResponseInterface) {
250 2
            $body = $body->getBody();
251 2
        }
252
253
        // XXX: json maybe contains special chars. So, let's FUCK the WeChat API developers ...
254 10
        $body = $this->fuckTheWeChatInvalidJSON($body);
255
256 10
        if (empty($body)) {
257 1
            return false;
258
        }
259
260 10
        $contents = json_decode($body, true);
261
262 10
        Log::debug('API response decoded:', compact('contents'));
263
264 10
        if (JSON_ERROR_NONE !== json_last_error()) {
265 1
            throw new HttpException('Failed to parse JSON: '.json_last_error_msg());
266
        }
267
268 10
        return $contents;
269
    }
270
271
    /**
272
     * Filter the invalid JSON string.
273
     *
274
     * @param \Psr\Http\Message\StreamInterface|string $invalidJSON
275
     *
276
     * @return string
277
     */
278 10
    protected function fuckTheWeChatInvalidJSON($invalidJSON)
279
    {
280 10
        return preg_replace("/\p{Cc}/u", '', trim($invalidJSON));
281
    }
282
283
    /**
284
     * Build a handler.
285
     *
286
     * @return HandlerStack
287
     */
288 3
    protected function getHandler()
289
    {
290 3
        $stack = HandlerStack::create();
291
292 3
        foreach ($this->middlewares as $middleware) {
293 1
            $stack->push($middleware);
294 3
        }
295
296 3
        return $stack;
297
    }
298
}
299