This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php namespace Propaganistas\LaravelPhone; |
||
2 | |||
3 | use Exception; |
||
4 | use Illuminate\Contracts\Support\Jsonable; |
||
5 | use Illuminate\Support\Arr; |
||
6 | use Illuminate\Support\Collection; |
||
7 | use Illuminate\Support\Str; |
||
8 | use Illuminate\Support\Traits\Macroable; |
||
9 | use JsonSerializable; |
||
10 | use libphonenumber\NumberParseException as libNumberParseException; |
||
11 | use libphonenumber\PhoneNumberFormat; |
||
12 | use libphonenumber\PhoneNumberType; |
||
13 | use libphonenumber\PhoneNumberUtil; |
||
14 | use Propaganistas\LaravelPhone\Exceptions\NumberFormatException; |
||
15 | use Propaganistas\LaravelPhone\Exceptions\CountryCodeException; |
||
16 | use Propaganistas\LaravelPhone\Exceptions\NumberParseException; |
||
17 | use Propaganistas\LaravelPhone\Traits\ParsesCountries; |
||
18 | use Propaganistas\LaravelPhone\Traits\ParsesFormats; |
||
19 | use Propaganistas\LaravelPhone\Traits\ParsesTypes; |
||
20 | use Serializable; |
||
21 | |||
22 | class PhoneNumber implements Jsonable, JsonSerializable, Serializable |
||
23 | { |
||
24 | use Macroable, |
||
25 | ParsesCountries, |
||
26 | ParsesFormats, |
||
27 | ParsesTypes; |
||
28 | |||
29 | /** |
||
30 | * The provided phone number. |
||
31 | * |
||
32 | * @var string |
||
33 | */ |
||
34 | protected $number; |
||
35 | |||
36 | /** |
||
37 | * The provided phone country. |
||
38 | * |
||
39 | * @var array |
||
40 | */ |
||
41 | protected $countries = []; |
||
42 | |||
43 | /** |
||
44 | * The detected phone country. |
||
45 | * |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $country; |
||
49 | |||
50 | /** |
||
51 | * Whether to allow lenient checks (i.e. landline numbers without area codes). |
||
52 | * |
||
53 | * @var bool |
||
54 | */ |
||
55 | protected $lenient = false; |
||
56 | |||
57 | /** |
||
58 | * @var \libphonenumber\PhoneNumberUtil |
||
59 | */ |
||
60 | protected $lib; |
||
61 | |||
62 | /** |
||
63 | * Phone constructor. |
||
64 | * |
||
65 | * @param string $number |
||
66 | */ |
||
67 | 135 | public function __construct($number) |
|
68 | { |
||
69 | 135 | $this->number = $number; |
|
70 | 135 | $this->lib = PhoneNumberUtil::getInstance(); |
|
71 | 135 | } |
|
72 | |||
73 | /** |
||
74 | * Create a phone instance. |
||
75 | * |
||
76 | * @param string $number |
||
77 | * @param string|array $country |
||
78 | * @return static |
||
79 | */ |
||
80 | 48 | public static function make($number, $country = []) |
|
81 | { |
||
82 | 48 | $instance = new static($number); |
|
83 | |||
84 | 48 | return $instance->ofCountry($country); |
|
85 | } |
||
86 | |||
87 | /** |
||
88 | * Set the country to which the phone number belongs to. |
||
89 | * |
||
90 | * @param string|array $country |
||
91 | * @return static |
||
92 | */ |
||
93 | 114 | public function ofCountry($country) |
|
94 | { |
||
95 | 114 | $countries = is_array($country) ? $country : func_get_args(); |
|
96 | |||
97 | 114 | $instance = clone $this; |
|
98 | 114 | $instance->countries = array_unique( |
|
99 | 114 | array_merge($instance->countries, static::parseCountries($countries)) |
|
100 | ); |
||
101 | |||
102 | 114 | return $instance; |
|
103 | } |
||
104 | |||
105 | /** |
||
106 | * Format the phone number in international format. |
||
107 | * |
||
108 | * @return string |
||
109 | */ |
||
110 | 3 | public function formatInternational() |
|
111 | { |
||
112 | 3 | return $this->format(PhoneNumberFormat::INTERNATIONAL); |
|
113 | } |
||
114 | |||
115 | /** |
||
116 | * Format the phone number in national format. |
||
117 | * |
||
118 | * @return string |
||
119 | */ |
||
120 | 3 | public function formatNational() |
|
121 | { |
||
122 | 3 | return $this->format(PhoneNumberFormat::NATIONAL); |
|
123 | } |
||
124 | |||
125 | /** |
||
126 | * Format the phone number in E164 format. |
||
127 | * |
||
128 | * @return string |
||
129 | */ |
||
130 | 27 | public function formatE164() |
|
131 | { |
||
132 | 27 | return $this->format(PhoneNumberFormat::E164); |
|
133 | } |
||
134 | |||
135 | /** |
||
136 | * Format the phone number in RFC3966 format. |
||
137 | * |
||
138 | * @return string |
||
139 | */ |
||
140 | 12 | public function formatRFC3966() |
|
141 | { |
||
142 | 12 | return $this->format(PhoneNumberFormat::RFC3966); |
|
143 | } |
||
144 | |||
145 | /** |
||
146 | * Format the phone number in a given format. |
||
147 | * |
||
148 | * @param string $format |
||
149 | * @return string |
||
150 | * @throws \Propaganistas\LaravelPhone\Exceptions\NumberFormatException |
||
151 | */ |
||
152 | 60 | public function format($format) |
|
153 | { |
||
154 | 60 | $parsedFormat = static::parseFormat($format); |
|
155 | |||
156 | 60 | if (is_null($parsedFormat)) { |
|
157 | 3 | throw NumberFormatException::invalid($format); |
|
158 | } |
||
159 | |||
160 | 57 | return $this->lib->format( |
|
161 | 57 | $this->getPhoneNumberInstance(), |
|
162 | $parsedFormat |
||
163 | ); |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * Format the phone number in a way that it can be dialled from the provided country. |
||
168 | * |
||
169 | * @param string $country |
||
170 | * @return string |
||
171 | * @throws \Propaganistas\LaravelPhone\Exceptions\CountryCodeException |
||
172 | */ |
||
173 | 6 | View Code Duplication | public function formatForCountry($country) |
174 | { |
||
175 | 6 | if (! static::isValidCountryCode($country)) { |
|
176 | 3 | throw CountryCodeException::invalid($country); |
|
177 | } |
||
178 | |||
179 | 3 | return $this->lib->formatOutOfCountryCallingNumber( |
|
180 | 3 | $this->getPhoneNumberInstance(), |
|
181 | $country |
||
182 | ); |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Format the phone number in a way that it can be dialled from the provided country using a cellphone. |
||
187 | * |
||
188 | * @param string $country |
||
189 | * @param bool $removeFormatting |
||
190 | * @return string |
||
191 | * @throws \Propaganistas\LaravelPhone\Exceptions\CountryCodeException |
||
192 | */ |
||
193 | 6 | View Code Duplication | public function formatForMobileDialingInCountry($country, $removeFormatting = false) |
194 | { |
||
195 | 6 | if (! static::isValidCountryCode($country)) { |
|
196 | 3 | throw CountryCodeException::invalid($country); |
|
197 | } |
||
198 | |||
199 | 3 | return $this->lib->formatNumberForMobileDialing( |
|
200 | 3 | $this->getPhoneNumberInstance(), |
|
201 | $country, |
||
202 | $removeFormatting |
||
203 | ); |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Get the phone number's country. |
||
208 | * |
||
209 | * @return string |
||
210 | */ |
||
211 | 126 | public function getCountry() |
|
212 | { |
||
213 | 126 | if (! $this->country) { |
|
214 | 126 | $this->country = $this->filterValidCountry($this->countries); |
|
215 | } |
||
216 | |||
217 | 105 | return $this->country; |
|
218 | } |
||
219 | |||
220 | /** |
||
221 | * Check if the phone number is of (a) given country(ies). |
||
222 | * |
||
223 | * @param string|array $country |
||
224 | * @return bool |
||
225 | */ |
||
226 | 3 | public function isOfCountry($country) |
|
227 | { |
||
228 | 3 | $countries = static::parseCountries($country); |
|
229 | |||
230 | 3 | return in_array($this->getCountry(), $countries); |
|
231 | } |
||
232 | |||
233 | /** |
||
234 | * Filter the provided countries to the one that is valid for the number. |
||
235 | * |
||
236 | * @param string|array $countries |
||
237 | * @return string |
||
238 | * @throws \Propaganistas\LaravelPhone\Exceptions\NumberParseException |
||
239 | */ |
||
240 | 126 | protected function filterValidCountry($countries) |
|
241 | { |
||
242 | 126 | $result = Collection::make($countries) |
|
243 | ->filter(function ($country) { |
||
244 | try { |
||
245 | 111 | $instance = $this->lib->parse($this->number, $country); |
|
246 | |||
247 | 111 | return $this->lenient |
|
248 | 18 | ? $this->lib->isPossibleNumber($instance, $country) |
|
249 | 111 | : $this->lib->isValidNumberForRegion($instance, $country); |
|
250 | 3 | } catch (libNumberParseException $e) { |
|
251 | 3 | return false; |
|
252 | } |
||
253 | 126 | })->first(); |
|
254 | |||
255 | // If we got a new result, return it. |
||
256 | 126 | if ($result) { |
|
257 | 102 | return $result; |
|
258 | } |
||
259 | |||
260 | // Last resort: try to detect it from an international number. |
||
261 | 66 | if ($this->numberLooksInternational()) { |
|
262 | 33 | $countries[] = null; |
|
263 | } |
||
264 | |||
265 | 66 | foreach ($countries as $country) { |
|
0 ignored issues
–
show
|
|||
266 | 51 | $instance = $this->lib->parse($this->number, $country); |
|
267 | |||
268 | 51 | if ($this->lib->isValidNumber($instance)) { |
|
269 | 30 | return $this->lib->getRegionCodeForNumber($instance); |
|
270 | } |
||
271 | } |
||
272 | |||
273 | 48 | if ($countries = array_filter($countries)) { |
|
274 | 24 | throw NumberParseException::countryMismatch($this->number, $countries); |
|
275 | } |
||
276 | |||
277 | 30 | throw NumberParseException::countryRequired($this->number); |
|
278 | } |
||
279 | |||
280 | /** |
||
281 | * Get the phone number's type. |
||
282 | * |
||
283 | * @param bool $asConstant |
||
284 | * @return string|int|null |
||
285 | */ |
||
286 | 33 | public function getType($asConstant = false) |
|
287 | { |
||
288 | 33 | $type = $this->lib->getNumberType($this->getPhoneNumberInstance()); |
|
289 | |||
290 | 33 | if ($asConstant) { |
|
291 | 33 | return $type; |
|
292 | } |
||
293 | |||
294 | 3 | $stringType = Arr::get(static::parseTypesAsStrings($type), 0); |
|
295 | |||
296 | 3 | return $stringType ? strtolower($stringType) : null; |
|
297 | } |
||
298 | |||
299 | /** |
||
300 | * Check if the phone number is of (a) given type(s). |
||
301 | * |
||
302 | * @param string $type |
||
303 | * @return bool |
||
304 | */ |
||
305 | 30 | public function isOfType($type) |
|
306 | { |
||
307 | 30 | $types = static::parseTypes($type); |
|
308 | |||
309 | // Add the unsure type when applicable. |
||
310 | 30 | if (array_intersect([PhoneNumberType::FIXED_LINE, PhoneNumberType::MOBILE], $types)) { |
|
311 | 30 | $types[] = PhoneNumberType::FIXED_LINE_OR_MOBILE; |
|
312 | } |
||
313 | |||
314 | 30 | return in_array($this->getType(true), $types, true); |
|
315 | } |
||
316 | |||
317 | /** |
||
318 | * Get the PhoneNumber instance of the current number. |
||
319 | * |
||
320 | * @return \libphonenumber\PhoneNumber |
||
321 | */ |
||
322 | 111 | public function getPhoneNumberInstance() |
|
323 | { |
||
324 | 111 | return $this->lib->parse($this->number, $this->getCountry()); |
|
325 | } |
||
326 | |||
327 | /** |
||
328 | * Determine whether the phone number seems to be in international format. |
||
329 | * |
||
330 | * @return bool |
||
331 | */ |
||
332 | 66 | protected function numberLooksInternational() |
|
333 | { |
||
334 | 66 | return Str::startsWith($this->number, '+'); |
|
335 | } |
||
336 | |||
337 | /** |
||
338 | * Enable lenient number parsing. |
||
339 | * |
||
340 | * @return $this |
||
341 | */ |
||
342 | 39 | public function lenient() |
|
343 | { |
||
344 | 39 | $this->lenient = true; |
|
345 | |||
346 | 39 | return $this; |
|
347 | } |
||
348 | |||
349 | /** |
||
350 | * Convert the phone instance to JSON. |
||
351 | * |
||
352 | * @param int $options |
||
353 | * @return string |
||
354 | */ |
||
355 | 3 | public function toJson($options = 0) |
|
356 | { |
||
357 | 3 | return json_encode($this->jsonSerialize(), $options); |
|
358 | } |
||
359 | |||
360 | /** |
||
361 | * Convert the phone instance into something JSON serializable. |
||
362 | * |
||
363 | * @return string |
||
364 | */ |
||
365 | 3 | public function jsonSerialize() |
|
366 | { |
||
367 | 3 | return $this->formatE164(); |
|
368 | } |
||
369 | |||
370 | /** |
||
371 | * Convert the phone instance into a string representation. |
||
372 | * |
||
373 | * @return string |
||
374 | */ |
||
375 | 3 | public function serialize() |
|
376 | { |
||
377 | 3 | return $this->formatE164(); |
|
378 | } |
||
379 | |||
380 | /** |
||
381 | * Reconstructs the phone instance from a string representation. |
||
382 | * |
||
383 | * @param string $serialized |
||
384 | */ |
||
385 | 3 | public function unserialize($serialized) |
|
386 | { |
||
387 | 3 | $this->lib = PhoneNumberUtil::getInstance(); |
|
388 | 3 | $this->number = $serialized; |
|
389 | 3 | $this->country = $this->lib->getRegionCodeForNumber($this->getPhoneNumberInstance()); |
|
390 | 3 | } |
|
391 | |||
392 | /** |
||
393 | * Convert the phone instance to a formatted number. |
||
394 | * |
||
395 | * @return string |
||
396 | */ |
||
397 | 21 | public function __toString() |
|
398 | { |
||
399 | // Formatting the phone number could throw an exception, but __toString() doesn't cope well with that. |
||
400 | // Let's just return the original number in that case. |
||
401 | try { |
||
402 | 21 | return $this->formatE164(); |
|
403 | 12 | } catch (Exception $exception) { |
|
404 | 12 | return (string) $this->number; |
|
405 | } |
||
406 | } |
||
407 | } |
||
408 |
There are different options of fixing this problem.
If you want to be on the safe side, you can add an additional type-check:
If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:
Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.