Completed
Pull Request — master (#25)
by
unknown
03:00
created

Validator::isEmail()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 2
eloc 6
nc 2
nop 1
1
<?php
2
3
/**
4
 * This file is part of the php-epp2 library.
5
 *
6
 * (c) Gunter Grodotzki <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE file
9
 * that was distributed with this source code.
10
 */
11
12
namespace AfriCC\EPP;
13
14
/**
15
 * various validating methods needed to create sane EPP requests
16
 */
17
class Validator
18
{
19
    const TYPE_IPV4 = 1;
20
    const TYPE_IPV6 = 2;
21
22
    /**
23
     * hashmap country-code -> country name (english)
24
     * @link https://gist.github.com/vxnick/380904
25
     * @var array
26
     */
27
    protected static $countries = [
28
        'AF' => 'Afghanistan',
29
        'AX' => 'Aland Islands',
30
        'AL' => 'Albania',
31
        'DZ' => 'Algeria',
32
        'AS' => 'American Samoa',
33
        'AD' => 'Andorra',
34
        'AO' => 'Angola',
35
        'AI' => 'Anguilla',
36
        'AQ' => 'Antarctica',
37
        'AG' => 'Antigua And Barbuda',
38
        'AR' => 'Argentina',
39
        'AM' => 'Armenia',
40
        'AW' => 'Aruba',
41
        'AU' => 'Australia',
42
        'AT' => 'Austria',
43
        'AZ' => 'Azerbaijan',
44
        'BS' => 'Bahamas',
45
        'BH' => 'Bahrain',
46
        'BD' => 'Bangladesh',
47
        'BB' => 'Barbados',
48
        'BY' => 'Belarus',
49
        'BE' => 'Belgium',
50
        'BZ' => 'Belize',
51
        'BJ' => 'Benin',
52
        'BM' => 'Bermuda',
53
        'BT' => 'Bhutan',
54
        'BO' => 'Bolivia',
55
        'BA' => 'Bosnia And Herzegovina',
56
        'BW' => 'Botswana',
57
        'BV' => 'Bouvet Island',
58
        'BR' => 'Brazil',
59
        'IO' => 'British Indian Ocean Territory',
60
        'BN' => 'Brunei Darussalam',
61
        'BG' => 'Bulgaria',
62
        'BF' => 'Burkina Faso',
63
        'BI' => 'Burundi',
64
        'KH' => 'Cambodia',
65
        'CM' => 'Cameroon',
66
        'CA' => 'Canada',
67
        'CV' => 'Cape Verde',
68
        'KY' => 'Cayman Islands',
69
        'CF' => 'Central African Republic',
70
        'TD' => 'Chad',
71
        'CL' => 'Chile',
72
        'CN' => 'China',
73
        'CX' => 'Christmas Island',
74
        'CC' => 'Cocos (Keeling) Islands',
75
        'CO' => 'Colombia',
76
        'KM' => 'Comoros',
77
        'CG' => 'Congo',
78
        'CD' => 'Congo, Democratic Republic',
79
        'CK' => 'Cook Islands',
80
        'CR' => 'Costa Rica',
81
        'CI' => 'Cote D\'Ivoire',
82
        'HR' => 'Croatia',
83
        'CU' => 'Cuba',
84
        'CY' => 'Cyprus',
85
        'CZ' => 'Czech Republic',
86
        'DK' => 'Denmark',
87
        'DJ' => 'Djibouti',
88
        'DM' => 'Dominica',
89
        'DO' => 'Dominican Republic',
90
        'EC' => 'Ecuador',
91
        'EG' => 'Egypt',
92
        'SV' => 'El Salvador',
93
        'GQ' => 'Equatorial Guinea',
94
        'ER' => 'Eritrea',
95
        'EE' => 'Estonia',
96
        'ET' => 'Ethiopia',
97
        'FK' => 'Falkland Islands (Malvinas)',
98
        'FO' => 'Faroe Islands',
99
        'FJ' => 'Fiji',
100
        'FI' => 'Finland',
101
        'FR' => 'France',
102
        'GF' => 'French Guiana',
103
        'PF' => 'French Polynesia',
104
        'TF' => 'French Southern Territories',
105
        'GA' => 'Gabon',
106
        'GM' => 'Gambia',
107
        'GE' => 'Georgia',
108
        'DE' => 'Germany',
109
        'GH' => 'Ghana',
110
        'GI' => 'Gibraltar',
111
        'GR' => 'Greece',
112
        'GL' => 'Greenland',
113
        'GD' => 'Grenada',
114
        'GP' => 'Guadeloupe',
115
        'GU' => 'Guam',
116
        'GT' => 'Guatemala',
117
        'GG' => 'Guernsey',
118
        'GN' => 'Guinea',
119
        'GW' => 'Guinea-Bissau',
120
        'GY' => 'Guyana',
121
        'HT' => 'Haiti',
122
        'HM' => 'Heard Island & Mcdonald Islands',
123
        'VA' => 'Holy See (Vatican City State)',
124
        'HN' => 'Honduras',
125
        'HK' => 'Hong Kong',
126
        'HU' => 'Hungary',
127
        'IS' => 'Iceland',
128
        'IN' => 'India',
129
        'ID' => 'Indonesia',
130
        'IR' => 'Iran, Islamic Republic Of',
131
        'IQ' => 'Iraq',
132
        'IE' => 'Ireland',
133
        'IM' => 'Isle Of Man',
134
        'IL' => 'Israel',
135
        'IT' => 'Italy',
136
        'JM' => 'Jamaica',
137
        'JP' => 'Japan',
138
        'JE' => 'Jersey',
139
        'JO' => 'Jordan',
140
        'KZ' => 'Kazakhstan',
141
        'KE' => 'Kenya',
142
        'KI' => 'Kiribati',
143
        'KR' => 'Korea',
144
        'KW' => 'Kuwait',
145
        'KG' => 'Kyrgyzstan',
146
        'LA' => 'Lao People\'s Democratic Republic',
147
        'LV' => 'Latvia',
148
        'LB' => 'Lebanon',
149
        'LS' => 'Lesotho',
150
        'LR' => 'Liberia',
151
        'LY' => 'Libyan Arab Jamahiriya',
152
        'LI' => 'Liechtenstein',
153
        'LT' => 'Lithuania',
154
        'LU' => 'Luxembourg',
155
        'MO' => 'Macao',
156
        'MK' => 'Macedonia',
157
        'MG' => 'Madagascar',
158
        'MW' => 'Malawi',
159
        'MY' => 'Malaysia',
160
        'MV' => 'Maldives',
161
        'ML' => 'Mali',
162
        'MT' => 'Malta',
163
        'MH' => 'Marshall Islands',
164
        'MQ' => 'Martinique',
165
        'MR' => 'Mauritania',
166
        'MU' => 'Mauritius',
167
        'YT' => 'Mayotte',
168
        'MX' => 'Mexico',
169
        'FM' => 'Micronesia, Federated States Of',
170
        'MD' => 'Moldova',
171
        'MC' => 'Monaco',
172
        'MN' => 'Mongolia',
173
        'ME' => 'Montenegro',
174
        'MS' => 'Montserrat',
175
        'MA' => 'Morocco',
176
        'MZ' => 'Mozambique',
177
        'MM' => 'Myanmar',
178
        'NA' => 'Namibia',
179
        'NR' => 'Nauru',
180
        'NP' => 'Nepal',
181
        'NL' => 'Netherlands',
182
        'AN' => 'Netherlands Antilles',
183
        'NC' => 'New Caledonia',
184
        'NZ' => 'New Zealand',
185
        'NI' => 'Nicaragua',
186
        'NE' => 'Niger',
187
        'NG' => 'Nigeria',
188
        'NU' => 'Niue',
189
        'NF' => 'Norfolk Island',
190
        'MP' => 'Northern Mariana Islands',
191
        'NO' => 'Norway',
192
        'OM' => 'Oman',
193
        'PK' => 'Pakistan',
194
        'PW' => 'Palau',
195
        'PS' => 'Palestinian Territory, Occupied',
196
        'PA' => 'Panama',
197
        'PG' => 'Papua New Guinea',
198
        'PY' => 'Paraguay',
199
        'PE' => 'Peru',
200
        'PH' => 'Philippines',
201
        'PN' => 'Pitcairn',
202
        'PL' => 'Poland',
203
        'PT' => 'Portugal',
204
        'PR' => 'Puerto Rico',
205
        'QA' => 'Qatar',
206
        'RE' => 'Reunion',
207
        'RO' => 'Romania',
208
        'RU' => 'Russian Federation',
209
        'RW' => 'Rwanda',
210
        'BL' => 'Saint Barthelemy',
211
        'SH' => 'Saint Helena',
212
        'KN' => 'Saint Kitts And Nevis',
213
        'LC' => 'Saint Lucia',
214
        'MF' => 'Saint Martin',
215
        'PM' => 'Saint Pierre And Miquelon',
216
        'VC' => 'Saint Vincent And Grenadines',
217
        'WS' => 'Samoa',
218
        'SM' => 'San Marino',
219
        'ST' => 'Sao Tome And Principe',
220
        'SA' => 'Saudi Arabia',
221
        'SN' => 'Senegal',
222
        'RS' => 'Serbia',
223
        'SC' => 'Seychelles',
224
        'SL' => 'Sierra Leone',
225
        'SG' => 'Singapore',
226
        'SK' => 'Slovakia',
227
        'SI' => 'Slovenia',
228
        'SB' => 'Solomon Islands',
229
        'SO' => 'Somalia',
230
        'ZA' => 'South Africa',
231
        'GS' => 'South Georgia And Sandwich Isl.',
232
        'ES' => 'Spain',
233
        'LK' => 'Sri Lanka',
234
        'SD' => 'Sudan',
235
        'SR' => 'Suriname',
236
        'SJ' => 'Svalbard And Jan Mayen',
237
        'SZ' => 'Swaziland',
238
        'SE' => 'Sweden',
239
        'CH' => 'Switzerland',
240
        'SY' => 'Syrian Arab Republic',
241
        'TW' => 'Taiwan',
242
        'TJ' => 'Tajikistan',
243
        'TZ' => 'Tanzania',
244
        'TH' => 'Thailand',
245
        'TL' => 'Timor-Leste',
246
        'TG' => 'Togo',
247
        'TK' => 'Tokelau',
248
        'TO' => 'Tonga',
249
        'TT' => 'Trinidad And Tobago',
250
        'TN' => 'Tunisia',
251
        'TR' => 'Turkey',
252
        'TM' => 'Turkmenistan',
253
        'TC' => 'Turks And Caicos Islands',
254
        'TV' => 'Tuvalu',
255
        'UG' => 'Uganda',
256
        'UA' => 'Ukraine',
257
        'AE' => 'United Arab Emirates',
258
        'GB' => 'United Kingdom',
259
        'US' => 'United States',
260
        'UM' => 'United States Outlying Islands',
261
        'UY' => 'Uruguay',
262
        'UZ' => 'Uzbekistan',
263
        'VU' => 'Vanuatu',
264
        'VE' => 'Venezuela',
265
        'VN' => 'Viet Nam',
266
        'VG' => 'Virgin Islands, British',
267
        'VI' => 'Virgin Islands, U.S.',
268
        'WF' => 'Wallis And Futuna',
269
        'EH' => 'Western Sahara',
270
        'YE' => 'Yemen',
271
        'ZM' => 'Zambia',
272
        'ZW' => 'Zimbabwe',
273
    ];
274
275
    /**
276
     * @var array
277
     */
278
    protected static $contact_role = [
279
        2 => "admin",
280
        3 => "billing",
281
        4 => "tech",
282
        5 => "registrant"
283
    ];
284
285
    /**
286
     * @var array
287
     */
288
    protected static $contact_type = [
289
        0 => "private_person",
290
        1 => "company",
291
        2 => "corporation",
292
        3 => "institution",
293
        4 => "political_party",
294
        5 => "township",
295
        6 => "government",
296
        7 => "public_community"
297
    ];
298
299
    /**
300
     * returns version of IP address, or false if not an IP
301
     * @param string $ip
302
     * @return bool|int
303
     */
304
    public static function getIPType($ip)
305
    {
306
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
307
            return self::TYPE_IPV4;
308
        } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
309
            return self::TYPE_IPV6;
310
        } else {
311
            return false;
312
        }
313
    }
314
315
    /**
316
     * returns true if hostname is usuable
317
     * @author velcrow
318
     * @link http://stackoverflow.com/a/4694816
319
     * @param string $hostname
320
     * @return bool
321
     */
322
    public static function isHostname($hostname)
323
    {
324
        if (preg_match('/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i', $hostname) && //valid chars check
325
            preg_match('/^.{1,253}$/', $hostname) && //overall length check
326
            preg_match('/^[^\.]{1,63}(\.[^\.]{1,63})*$/', $hostname) && //length of each label
327
            strpos($hostname, '.') // has at least two labels (SLD + TLD)
328
        ) {
329
            return true;
330
        }
331
        return false;
332
    }
333
334
    /**
335
     * returns true if email is usuable
336
     * @param string $email
337
     */
338
    public static function isEmail($email)
339
    {
340
        $pos = strrpos($email, '@');
341
        if ($pos === false) {
342
            return false;
343
        }
344
345
        $ascii_email = substr($email, 0, $pos) . '@' . idn_to_ascii(substr($email, $pos + 1), 0, INTL_IDNA_VARIANT_2003);
346
347
        return filter_var($ascii_email, FILTER_VALIDATE_EMAIL);
348
    }
349
350
    /**
351
     * returns country name if country code is known, false if unknown
352
     * @param string $country_code
353
     * @return bool|string
354
     */
355
    public static function isCountryCode($country_code)
356
    {
357
        // actually we don't need to check for any conventions...
358
        $country_code = strtoupper($country_code);
359
360
        if (isset(self::$countries[$country_code])) {
361
            return self::$countries[$country_code];
362
        }
363
364
        return false;
365
    }
366
367
    /**
368
     * Returns value of key from self::$contact_role
369
     * @param $role
370
     * @return bool
371
     */
372
    public static function isValidContactRole($role)
373
    {
374
        if (is_int($role) && array_key_exists($role, self::$contact_role)) {
375
            return $role;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $role; (integer) is incompatible with the return type documented by AfriCC\EPP\Validator::isValidContactRole of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
376
        }
377
378
        if (is_string($role) && array_key_exists($role, array_flip(self::$contact_role))) {
379
            return array_flip(self::$contact_role)[$role];
380
        }
381
382
        return false;
383
    }
384
385
    /**
386
     * Returns value of key from: self::$contact_type
387
     * @param $type
388
     * @return bool
389
     */
390
    public static function isValidContactType($type)
391
    {
392
        if (is_int($type) && array_key_exists($type, self::$contact_type)) {
393
            return $type;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $type; (integer) is incompatible with the return type documented by AfriCC\EPP\Validator::isValidContactType of type boolean.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
394
        }
395
396
        if (is_string($type) && array_key_exists($type, array_flip(self::$contact_type))) {
397
            return array_flip(self::$contact_type)[$type];
398
        }
399
400
        return false;
401
    }
402
}
403