Completed
Push — master ( 767580...41593b )
by Elf
22:40 queued 20:07
created

Support::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 4
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace ElfSundae\Support;
4
5
use SplFileInfo;
6
use Illuminate\Support\Str;
7
use Illuminate\Foundation\Application;
8
use Illuminate\Support\Traits\Macroable;
9
use Intervention\Image\File as ImageFile;
10
use Symfony\Component\HttpFoundation\File\File as SymfonyFile;
11
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
12
13
class Support
14
{
15
    use Macroable;
16
17
    /**
18
     * The application instance.
19
     *
20
     * @var \Illuminate\Foundation\Application
21
     */
22
    protected $app;
23
24
    /**
25
     * Create a new Support instance.
26
     *
27
     * @param  \Illuminate\Foundation\Application  $app
28
     */
29
    public function __construct(Application $app)
30
    {
31
        $this->app = $app;
32
    }
33
34
    /**
35
     * Get the file extension.
36
     *
37
     * @param  mixed  $file
38
     * @param  string  $prefix
39
     * @return string|null
40
     */
41
    public function extension($file, $prefix = '')
42
    {
43
        if (is_string($file)) {
44
            if (substr_count($file, '/') === 1) {
45
                $ext = $this->extensionForMime($file);
46
            } else {
47
                $ext = pathinfo($file, PATHINFO_EXTENSION);
48
            }
49
        } elseif ($file instanceof SymfonyFile) {
50
            $ext = $file->guessExtension();
51
        } elseif ($file instanceof SplFileInfo) {
52
            $ext = $file->getExtension();
53
        } elseif ($file instanceof ImageFile) {
54
            $ext = $file->extension ?: $this->extensionForMime($file->mime);
55
        }
56
57
        if (! empty($ext)) {
58
            if ($ext == 'jpeg') {
59
                $ext = 'jpg';
60
            }
61
62
            return $prefix.$ext;
63
        }
64
    }
65
66
    /**
67
     * Get the file extension for the given MIME type.
68
     *
69
     * @param  string  $mimeType
70
     * @return string|null
71
     */
72
    public function extensionForMime($mimeType)
73
    {
74
        return ExtensionGuesser::getInstance()->guess($mimeType);
75
    }
76
77
    /**
78
     * Convert an iOS platform to the device model name.
79
     *
80
     * @see https://www.theiphonewiki.com/wiki/Models
81
     * @see https://support.hockeyapp.net/kb/client-integration-ios-mac-os-x-tvos/ios-device-types
82
     *
83
     * @param  string  $platform
84
     * @return string
85
     */
86
    public function iDeviceModel($platform)
87
    {
88
        static $iDeviceModels = null;
89
90
        if (is_null($iDeviceModels)) {
91
            $iDeviceModels = [
92
                'i386' => 'Simulator',
93
                'x86_64' => 'Simulator',
94
95
                'iPhone1,1' => 'iPhone',
96
                'iPhone1,2' => 'iPhone 3G',
97
                'iPhone2,1' => 'iPhone 3GS',
98
                'iPhone3,1' => 'iPhone 4',
99
                'iPhone3,2' => 'iPhone 4',
100
                'iPhone3,3' => 'iPhone 4',
101
                'iPhone4,1' => 'iPhone 4S',
102
                'iPhone5,1' => 'iPhone 5',
103
                'iPhone5,2' => 'iPhone 5',
104
                'iPhone5,3' => 'iPhone 5c',
105
                'iPhone5,4' => 'iPhone 5c',
106
                'iPhone6,1' => 'iPhone 5s',
107
                'iPhone6,2' => 'iPhone 5s',
108
                'iPhone7,1' => 'iPhone 6 Plus',
109
                'iPhone7,2' => 'iPhone 6',
110
                'iPhone8,1' => 'iPhone 6s',
111
                'iPhone8,2' => 'iPhone 6s Plus',
112
                'iPhone8,4' => 'iPhone SE',
113
                'iPhone9,1' => 'iPhone 7',
114
                'iPhone9,2' => 'iPhone 7 Plus',
115
                'iPhone9,3' => 'iPhone 7',
116
                'iPhone9,4' => 'iPhone 7 Plus',
117
118
                'iPod1,1' => 'iPod touch',
119
                'iPod2,1' => 'iPod touch 2G',
120
                'iPod3,1' => 'iPod touch 3G',
121
                'iPod4,1' => 'iPod touch 4G',
122
                'iPod5,1' => 'iPod touch 5G',
123
                'iPod7,1' => 'iPod touch 6G',
124
125
                'iPad1,1' => 'iPad',
126
                'iPad2,1' => 'iPad 2',
127
                'iPad2,2' => 'iPad 2',
128
                'iPad2,3' => 'iPad 2',
129
                'iPad2,4' => 'iPad 2',
130
                'iPad2,5' => 'iPad mini',
131
                'iPad2,6' => 'iPad mini',
132
                'iPad2,7' => 'iPad mini',
133
                'iPad3,1' => 'iPad 3',
134
                'iPad3,2' => 'iPad 3',
135
                'iPad3,3' => 'iPad 3',
136
                'iPad3,4' => 'iPad 4',
137
                'iPad3,5' => 'iPad 4',
138
                'iPad3,6' => 'iPad 4',
139
                'iPad4,1' => 'iPad Air',
140
                'iPad4,2' => 'iPad Air',
141
                'iPad4,3' => 'iPad Air',
142
                'iPad4,4' => 'iPad mini 2',
143
                'iPad4,5' => 'iPad mini 2',
144
                'iPad4,6' => 'iPad mini 2',
145
                'iPad4,7' => 'iPad mini 3',
146
                'iPad4,8' => 'iPad mini 3',
147
                'iPad4,9' => 'iPad mini 3',
148
                'iPad5,1' => 'iPad mini 4',
149
                'iPad5,2' => 'iPad mini 4',
150
                'iPad5,3' => 'iPad Air 2',
151
                'iPad5,4' => 'iPad Air 2',
152
                'iPad6,3' => 'iPad Pro',
153
                'iPad6,4' => 'iPad Pro',
154
                'iPad6,7' => 'iPad Pro',
155
                'iPad6,8' => 'iPad Pro',
156
157
                'AppleTV2,1' => 'Apple TV 2G',
158
                'AppleTV3,1' => 'Apple TV 3G',
159
                'AppleTV3,2' => 'Apple TV 3G',
160
                'AppleTV5,3' => 'Apple TV 4G',
161
162
                'Watch1,1' => 'Apple Watch',
163
                'Watch1,2' => 'Apple Watch',
164
                'Watch2,6' => 'Apple Watch Series 1',
165
                'Watch2,7' => 'Apple Watch Series 1',
166
                'Watch2,3' => 'Apple Watch Series 2',
167
                'Watch2,4' => 'Apple Watch Series 2',
168
            ];
169
        }
170
171
        return $iDeviceModels[$platform] ?? $platform;
172
    }
173
174
    /**
175
     * Get the home or login URL for an email address.
176
     *
177
     * @param  string  $email
178
     * @return string|null
179
     */
180
    public function emailHome($email)
181
    {
182
        if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
183
            return;
184
        }
185
186
        static $emailHomeUrls = null;
187
188
        if (is_null($emailHomeUrls)) {
189
            $emailHomeUrls = [
190
                'gmail.com' => 'https://mail.google.com',
191
                'yahoo.com' => 'https://mail.yahoo.com',
192
                'outlook.com' => 'https://outlook.live.com',
193
                'qq.com' => 'https://mail.qq.com',
194
                'vip.qq.com' => 'https://mail.qq.com',
195
                '163.com' => 'http://mail.163.com',
196
                '126.com' => 'http://www.126.com',
197
                'yeah.net' => 'http://www.yeah.net',
198
                'sina.com' => 'https://mail.sina.com.cn',
199
                'sina.cn' => 'https://mail.sina.com.cn',
200
                'vip.sina.com' => 'https://mail.sina.com.cn',
201
                'sohu.com' => 'https://mail.sohu.com',
202
                'vip.sohu.com' => 'https://vip.sohu.com',
203
                'aliyun.com' => 'https://mail.aliyun.com',
204
                'tom.com' => 'http://mail.tom.com',
205
                '139.com' => 'http://mail.10086.cn',
206
                'wo.cn' => 'https://mail.wo.cn',
207
                '189.cn' => 'https://mail.189.cn',
208
            ];
209
        }
210
211
        $domain = strtolower(Str::after($email, '@'));
212
213
        return $emailHomeUrls[$domain] ?? 'http://'.$domain;
214
    }
215
216
    /**
217
     * Encrypt ASCII string via XOR.
218
     *
219
     * @param  string  $text
220
     * @param  string|null  $key
221
     * @return string
222
     */
223
    public function sampleEncrypt($text, $key = null)
224
    {
225
        $text = (string) $text;
226
        if (is_null($key)) {
227
            $key = $this->app['encrypter']->getKey();
228
        }
229
230
        // 生成随机字符串
231
        $random = str_random(strlen($text));
232
233
        // 按字符拼接:随机字符串 + 随机字符串异或原文
234
        $tmp = $this->sampleEncryption($text, $random, function ($a, $b) {
235
            return $b.($a ^ $b);
236
        });
237
238
        // 异或 $tmp 和 $key
239
        $result = $this->sampleEncryption($tmp, $key);
240
241
        return urlsafe_base64_encode($result);
242
    }
243
244
    /**
245
     * Decrypt string via XOR.
246
     *
247
     * @param  string  $text
248
     * @param  string|null  $key
249
     * @return string
250
     */
251
    public function sampleDecrypt($text, $key = null)
252
    {
253
        if (is_null($key)) {
254
            $key = $this->app['encrypter']->getKey();
255
        }
256
257
        $tmp = $this->sampleEncryption(urlsafe_base64_decode($text), $key);
258
        $tmpLength = strlen($tmp);
259
        $result = '';
260
        for ($i = 0; $i < $tmpLength, ($i + 1) < $tmpLength; $i += 2) {
261
            $result .= $tmp[$i] ^ $tmp[$i + 1];
262
        }
263
264
        return $result;
265
    }
266
267
    /**
268
     * Do a sample XOR encryption.
269
     *
270
     * @param  string  $text
271
     * @param  string  $key
272
     * @param  \Closure|null  $callback `($a, $b, $index)`
273
     * @return string
274
     */
275
    protected function sampleEncryption($text, $key, $callback = null)
276
    {
277
        // 对 $text 和 $key 的每个字符进行运算。
278
        // $callback 为 null 时默认进行异或运算。
279
        // $callback 参数: 第 i 位 $text, 第 i 位 $key, 下标 i
280
        // $callback 返回 false 时,结束字符循环.
281
282
        $text = (string) $text;
283
        $key = (string) $key;
284
        $keyLength = strlen($key);
285
        if (is_null($callback)) {
286
            $callback = function ($a, $b) {
287
                return $a ^ $b;
288
            };
289
        }
290
291
        $result = '';
292
        $textLength = strlen($text);
293
        for ($i = 0; $i < $textLength; $i++) {
294
            $tmp = $callback($text[$i], $key[$i % $keyLength], $i);
295
            if (false === $tmp) {
296
                break;
297
            }
298
            $result .= $tmp;
299
        }
300
301
        return $result;
302
    }
303
304
    /**
305
     * Fake current agent client to an app client.
306
     *
307
     * @param  array  $client
308
     * @return void
309
     */
310
    public function fakeAppClient(array $client)
311
    {
312
        $this->app->resolving('agent.client', function ($agent, $app) use ($client) {
313
            if ($agent->is('AppClient')) {
314
                return;
315
            }
316
317
            $agent->setUserAgent(
318
                $app['request']->header('User-Agent').
319
                ' client('.urlsafe_base64_encode(json_encode($client)).')'
320
            );
321
        });
322
    }
323
324
    /**
325
     * Set faked api token for the current request.
326
     *
327
     * @param  string|null  $appKey
328
     * @return void
329
     */
330
    public function fakeApiToken($appKey = null)
331
    {
332
        $this->app->rebinding('request', function ($app, $request) use ($appKey) {
333
            if ($request->hasHeader('X-API-TOKEN') || $request->has('_token')) {
334
                return;
335
            }
336
337
            $data = $app['api.token']->generateDataForKey(
338
                $appKey ?: $app['api.client']->defaultAppKey()
339
            );
340
341
            foreach ($data as $key => $value) {
342
                $request->headers->set('X-API-'.strtoupper($key), $value);
343
            }
344
        });
345
    }
346
}
347