Completed
Push — master ( c7a3ba...81aaf1 )
by Marcin
03:18
created

Phone::parseNumberPlan()   D

Complexity

Conditions 9
Paths 5

Size

Total Lines 37
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 0
cts 23
cp 0
rs 4.909
c 0
b 0
f 0
cc 9
eloc 26
nc 5
nop 1
crap 90
1
<?php
2
/**
3
 * Validator
4
 *
5
 * Copyright (c) 2017 pudelek.org.pl
6
 *
7
 * @license MIT License (MIT)
8
 *
9
 * For the full copyright and license information, please view source file
10
 * that is bundled with this package in the file LICENSE
11
 *
12
 * @author  Marcin Pudełek <[email protected]>
13
 */
14
15
16
namespace mrcnpdlk\Validator\Types;
17
18
19
use mrcnpdlk\Validator\Exception;
20
use mrcnpdlk\Validator\TypeInterface;
21
22
/**
23
 * Class Phone
24
 *
25
 * Polish phone number validator
26
 *
27
 * @package mrcnpdlk\Validator\Types
28
 */
29
class Phone extends TypeAbstract implements TypeInterface
30
{
31
    const COUNTRY_PREFIX         = '48';
32
    const NATIONAL_NUMBER_LENGTH = 9;
33
    const REGEX_FIXED            = '/(?:1[2-8]|2[2-69]|3[2-4]|4[1-468]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145])(?:\d{7})/';
34
    const REGEX_MOBILE           = '/(?:45|5[0137]|6[069]|7[2389]|88)\d{7}/';
35
    const REGEX_TOLL_FREE        = '/800\d{6}/';
36
    const REGEX_PREMIUM_RATE     = '/70[01346-8]\d{6}/';
37
    const REGEX_SHARED_COST      = '/801\d{6}/';
38
    const REGEX_VOIP             = '/39\d{7}/';
39
    const REGEX_UAN              = '/804\d{6}/';
40
41
    private $ukeMobilePlan = [];
42
    private $ukeFixedPlan  = [];
43
44
    /**
45
     * Phone constructor.
46
     *
47
     * @param $checkedValue
48
     */
49 6
    public function __construct($checkedValue)
50
    {
51 6
        parent::__construct($checkedValue);
52
        //pobieramy sam numer krajowy
53 4
        $this->checkedValue = substr($this->checkedValue, -9);
54 4
    }
55
56
    /**
57
     * Usuwamy niepotrzebne separatory
58
     *
59
     * @param mixed $checkedValue
60
     *
61
     * @return string
62
     */
63 6
    public static function clean($checkedValue)
64
    {
65 6
        static::isValidType($checkedValue, static::TYPE_STRING, true);
66
67 6
        return preg_replace('/[\s]/', '', trim($checkedValue));
68
    }
69
70
    /**
71
     * @param mixed $checkedValue
72
     * @param bool  $asEx
73
     *
74
     * @return bool
75
     * @throws Exception
76
     */
77 6
    public static function isValid($checkedValue, bool $asEx = false): bool
78
    {
79
        try {
80 6
            static::isValidType($checkedValue, static::TYPE_STRING, true);
81 6
            if (strlen($checkedValue) !== 9 && strlen($checkedValue) !== 11) {
82 1
                throw new \Exception(sprintf('invalid length'));
83
            }
84 5
            if (!preg_match('/^' . static::COUNTRY_PREFIX . '[\d]{9}$/', $checkedValue)
85 5
                && !preg_match('/^[\d]{9}$/', $checkedValue)) {
86 1
                throw new \Exception('regex error');
87
            }
88
89 4
            return true;
90 2
        } catch (\Exception $e) {
91 2
            if ($asEx) {
92 2
                throw new Exception(sprintf("Invalid phone number [%s], reason: %s", $checkedValue, $e->getMessage()));
93
            } else {
94
                return false;
95
            }
96
        }
97
    }
98
99
    /**
100
     * @return string
101
     */
102
    public function getCountryCode()
103
    {
104
        return static::COUNTRY_PREFIX;
105
    }
106
107
    /**
108
     * @return string
109
     */
110
    public function getInternationalFormat()
111
    {
112
        return sprintf('%s%s', static::COUNTRY_PREFIX, $this->get());
113
    }
114
115
    /**
116
     * @return bool
117
     */
118 2
    public function isPremiumRate()
119
    {
120 2
        return preg_match(static::REGEX_PREMIUM_RATE, $this->checkedValue) === 1;
121
    }
122
123
    /**
124
     * @return bool
125
     */
126 2
    public function isSharedCost()
127
    {
128 2
        return preg_match(static::REGEX_SHARED_COST, $this->checkedValue) === 1;
129
    }
130
131
    /**
132
     * @return bool
133
     */
134 2
    public function isTollFree()
135
    {
136 2
        return preg_match(static::REGEX_TOLL_FREE, $this->checkedValue) === 1;
137
    }
138
139
    /**
140
     * @return bool
141
     */
142 2
    public function isUAN()
143
    {
144 2
        return preg_match(static::REGEX_UAN, $this->checkedValue) === 1;
145
    }
146
147
    /**
148
     * @return bool
149
     */
150 2
    public function isVoip()
151
    {
152 2
        return preg_match(static::REGEX_VOIP, $this->checkedValue) === 1;
153
    }
154
155
    public function getRegion()
156
    {
157
        $sRegion = null;
158
        if ($this->isMobile()) {
159
            $nr = $this->getNationalFormat();
160
            while (strlen($nr) > 0 || is_null($sRegion)) {
161
                if (array_key_exists($nr, $this->getUkeMobilePlan())) {
162
                    $sRegion = $this->getUkeMobilePlan()[$nr]['operator'];
163
                }
164
                $nr = substr($nr, 0, -1);
165
            }
166
        } elseif ($this->isFixed()) {
167
            $sRegion = $this->getUkeFixedPlan()[substr($this->getNationalFormat(),0,2)] ?? null;
168
        }
169
170
        return $sRegion ?? 'Polska';
171
    }
172
173
    /**
174
     * @return bool
175
     */
176 2
    public function isMobile()
177
    {
178 2
        return preg_match(static::REGEX_MOBILE, $this->checkedValue) === 1;
179
    }
180
181
    /**
182
     * @return mixed|string
183
     */
184
    public function getNationalFormat()
185
    {
186
        return $this->get();
187
    }
188
189
    /**
190
     * @return array
191
     */
192
    private function getUkeMobilePlan()
193
    {
194
        if (empty($this->ukeMobilePlan)) {
195
            $oXml = new \SimpleXMLElement(file_get_contents(__DIR__ . '/../Databases/T2-PLMN_T9-MVNO.xml'));
196
197
            foreach ($oXml->numery->plmn as $oNr) {
198
                $t = $this->parseNumberPlan(strval($oNr->numer));
199
                foreach ($t as $n) {
200
                    $this->ukeMobilePlan[$n] = [
201
                        'numer'    => strval($oNr->numer),
202
                        'operator' => strval($oNr->operator),
203
                        'typ'      => strval($oNr->typ),
204
                    ];
205
                }
206
            }
207
        }
208
209
        return $this->ukeMobilePlan;
210
    }
211
212
    /**
213
     * @param string $plan
214
     *
215
     * @return array
216
     * @throws \Exception
217
     */
218
    private function parseNumberPlan(string $plan)
219
    {
220
        if (preg_match("/(?'prefix'[\d]*)(\((?'suffix'[\d\-,]*)\))?/", strval($plan), $f)) {
221
            $answer = [];
222
            $prefix = $f['prefix'];
223
            $suffix = $f['suffix'] ?? null;
224
            $tSuf   = [];
225
            if ($suffix) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $suffix of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
226
                foreach (explode(',', $suffix) as $digit) {
227
                    if (preg_match("/((?'first'[\d]{1})\-(?'last'[\d]{1}))/", $digit, $f)) {
228
                        $first = intval($f['first']);
229
                        $last  = intval($f['last']);
230
                        if ($last === 0) {
231
                            $last   = 9;
232
                            $tSuf[] = 0;
233
                        }
234
                        for ($i = $first; $i <= $last; $i++) {
235
                            $tSuf[] = $i;
236
                        }
237
                    } else {
238
                        $tSuf[] = intval($digit);
239
                    }
240
                }
241
            }
242
            if (empty($tSuf)) {
243
                $answer = [$prefix];
244
            } else {
245
                foreach ($tSuf as $d) {
246
                    $answer[] = $prefix . $d;
247
                }
248
            }
249
250
            return $answer;
251
        } else {
252
            throw new \Exception('regex error');
253
        }
254
    }
255
256
    /**
257
     * @return bool
258
     */
259 2
    public function isFixed()
260
    {
261 2
        return preg_match(static::REGEX_FIXED, $this->checkedValue) === 1;
262
    }
263
264
    /**
265
     * @return array
266
     */
267
    private function getUkeFixedPlan()
268
    {
269
        if (empty($this->ukeMobilePlan)) {
270
            include __DIR__ . '/../Databases/ukeFixedPlan.php';
271
            $this->ukeFixedPlan = $ukeFixedPlan;
0 ignored issues
show
Bug introduced by
The variable $ukeFixedPlan does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
272
        }
273
274
        return $this->ukeFixedPlan;
275
    }
276
}
277