1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace ElfSundae\Laravel\Support; |
4
|
|
|
|
5
|
|
|
use SplFileInfo; |
6
|
|
|
use Illuminate\Support\Str; |
7
|
|
|
use Intervention\Image\File as ImageFile; |
8
|
|
|
use Illuminate\Foundation\Application; |
9
|
|
|
use Illuminate\Support\Traits\Macroable; |
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 mail homepage. |
176
|
|
|
* |
177
|
|
|
* @param string $address |
178
|
|
|
* @return string|null |
179
|
|
|
*/ |
180
|
|
|
public function mailHomepage($address) |
181
|
|
|
{ |
182
|
|
|
static $mailHomepages = null; |
183
|
|
|
|
184
|
|
|
if (filter_var($address, FILTER_VALIDATE_EMAIL)) { |
185
|
|
|
if (is_null($mailHomepages)) { |
186
|
|
|
$mailHomepages = [ |
187
|
|
|
'gmail.com' => 'https://mail.google.com', |
188
|
|
|
'yahoo.com' => 'https://mail.yahoo.com', |
189
|
|
|
'outlook.com' => 'https://outlook.live.com', |
190
|
|
|
'qq.com' => 'https://mail.qq.com', |
191
|
|
|
'vip.qq.com' => 'https://mail.qq.com', |
192
|
|
|
'163.com' => 'http://mail.163.com', |
193
|
|
|
'126.com' => 'http://www.126.com', |
194
|
|
|
'yeah.net' => 'http://www.yeah.net', |
195
|
|
|
'sina.com' => 'https://mail.sina.com.cn', |
196
|
|
|
'sina.cn' => 'https://mail.sina.com.cn', |
197
|
|
|
'vip.sina.com' => 'https://mail.sina.com.cn', |
198
|
|
|
'sohu.com' => 'https://mail.sohu.com', |
199
|
|
|
'vip.sohu.com' => 'https://vip.sohu.com', |
200
|
|
|
'aliyun.com' => 'https://mail.aliyun.com', |
201
|
|
|
'tom.com' => 'http://mail.tom.com', |
202
|
|
|
'139.com' => 'http://mail.10086.cn', |
203
|
|
|
'wo.cn' => 'https://mail.wo.cn', |
204
|
|
|
'189.cn' => 'https://mail.189.cn', |
205
|
|
|
]; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
$domain = strtolower(Str::after($address, '@')); |
209
|
|
|
|
210
|
|
|
return $mailHomepages[$domain] ?? 'http://'.$domain; |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
/** |
215
|
|
|
* Encrypt ASCII string via XOR. |
216
|
|
|
* |
217
|
|
|
* @param string $text |
218
|
|
|
* @param string|null $key |
219
|
|
|
* @return string |
220
|
|
|
*/ |
221
|
|
|
public function sampleEncrypt($text, $key = null) |
222
|
|
|
{ |
223
|
|
|
$text = (string) $text; |
224
|
|
|
if (is_null($key)) { |
225
|
|
|
$key = app('encrypter')->getKey(); |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
// 生成随机字符串 |
229
|
|
|
$random = str_random(strlen($text)); |
230
|
|
|
|
231
|
|
|
// 按字符拼接:随机字符串 + 随机字符串异或原文 |
232
|
|
|
$tmp = static::sampleEncryption($text, $random, function ($a, $b) { |
233
|
|
|
return $b.($a ^ $b); |
234
|
|
|
}); |
235
|
|
|
|
236
|
|
|
// 异或 $tmp 和 $key |
237
|
|
|
$result = static::sampleEncryption($tmp, $key); |
238
|
|
|
|
239
|
|
|
return urlsafe_base64_encode($result); |
240
|
|
|
} |
241
|
|
|
|
242
|
|
|
/** |
243
|
|
|
* Decrypt string via XOR. |
244
|
|
|
* |
245
|
|
|
* @param string $text |
246
|
|
|
* @param string|null $key |
247
|
|
|
* @return string |
248
|
|
|
*/ |
249
|
|
|
public function sampleDecrypt($text, $key = null) |
250
|
|
|
{ |
251
|
|
|
if (is_null($key)) { |
252
|
|
|
$key = app('encrypter')->getKey(); |
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
$tmp = static::sampleEncryption(urlsafe_base64_decode($text), $key); |
256
|
|
|
$tmpLength = strlen($tmp); |
257
|
|
|
$result = ''; |
258
|
|
|
for ($i = 0; $i < $tmpLength, ($i + 1) < $tmpLength; $i += 2) { |
259
|
|
|
$result .= $tmp[$i] ^ $tmp[$i + 1]; |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
return $result; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Do a sample XOR encryption. |
267
|
|
|
* |
268
|
|
|
* @param string $text |
269
|
|
|
* @param string $key |
270
|
|
|
* @param \Closure|null $callback `($a, $b, $index)` |
271
|
|
|
* @return string |
272
|
|
|
*/ |
273
|
|
|
protected static function sampleEncryption($text, $key, $callback = null) |
274
|
|
|
{ |
275
|
|
|
// 对 $text 和 $key 的每个字符进行运算。 |
276
|
|
|
// $callback 为 null 时默认进行异或运算。 |
277
|
|
|
// $callback 参数: 第 i 位 $text, 第 i 位 $key, 下标 i |
278
|
|
|
// $callback 返回 false 时,结束字符循环. |
279
|
|
|
|
280
|
|
|
$text = (string) $text; |
281
|
|
|
$key = (string) $key; |
282
|
|
|
$keyLength = strlen($key); |
283
|
|
|
if (is_null($callback)) { |
284
|
|
|
$callback = function ($a, $b) { |
285
|
|
|
return $a ^ $b; |
286
|
|
|
}; |
287
|
|
|
} |
288
|
|
|
|
289
|
|
|
$result = ''; |
290
|
|
|
$textLength = strlen($text); |
291
|
|
|
for ($i = 0; $i < $textLength; $i++) { |
292
|
|
|
$tmp = $callback($text[$i], $key[$i % $keyLength], $i); |
293
|
|
|
if (false === $tmp) { |
294
|
|
|
break; |
295
|
|
|
} |
296
|
|
|
$result .= $tmp; |
297
|
|
|
} |
298
|
|
|
|
299
|
|
|
return $result; |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
/** |
303
|
|
|
* Fake current agent client to an app client. |
304
|
|
|
* |
305
|
|
|
* @param array $client |
306
|
|
|
* @return void |
307
|
|
|
*/ |
308
|
|
|
public function fakeAppClient(array $client) |
309
|
|
|
{ |
310
|
|
|
app()->resolving('agent.client', function ($agent, $app) use ($client) { |
311
|
|
|
if ($agent->is('AppClient')) { |
312
|
|
|
return; |
313
|
|
|
} |
314
|
|
|
|
315
|
|
|
$client = urlsafe_base64_encode(json_encode($client)); |
|
|
|
|
316
|
|
|
|
317
|
|
|
$agent->setUserAgent( |
318
|
|
|
$app['request']->header('User-Agent')." client($client)" |
319
|
|
|
); |
320
|
|
|
}); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Set faked api token for the current request. |
325
|
|
|
* |
326
|
|
|
* @param string|null $appKey |
327
|
|
|
* @return void |
328
|
|
|
*/ |
329
|
|
|
public function fakeApiToken($appKey = null) |
330
|
|
|
{ |
331
|
|
|
app()->rebinding('request', function ($app, $request) use ($appKey) { |
332
|
|
|
if ($request->hasHeader('X-API-TOKEN') || $request->has('_token')) { |
333
|
|
|
return; |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
$appKey = $appKey ?: app('api.client')->defaultAppKey(); |
|
|
|
|
337
|
|
|
|
338
|
|
|
foreach (app('api.token')->generateDataForKey($appKey) as $key => $value) { |
339
|
|
|
$request->headers->set('X-API-'.strtoupper($key), $value); |
340
|
|
|
} |
341
|
|
|
}); |
342
|
|
|
} |
343
|
|
|
} |
344
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.