Completed
Push — master ( 7d590b...c042a0 )
by Ronan
02:07
created

ZipCode::validatePortugal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 6
rs 9.4286
cc 1
eloc 3
nc 1
nop 1
1
<?php
2
3
namespace IsoCodes;
4
5
/**
6
 * Class ZipCode.
7
 */
8
class ZipCode
9
{
10
    /**
11
     * ZipCode patterns, generated from http://i18napis.appspot.com (updated: 2015-05-08)
12
     *
13
     * <code>
14
     *  $patterns = [];
15
     *  $data = json_decode(file_get_contents('http://i18napis.appspot.com/address/data'), true);
16
     *  $countries = explode('~', $data['countries']);
17
     *  foreach ($countries as $country) {
18
     *     $data = json_decode(file_get_contents('http://i18napis.appspot.com/address/data/'.$country), true);
19
     *     if (isset($data['zip'])) {
20
     *         $patterns[$country] = $data['zip'];
21
     *     }
22
     *  }
23
     *  var_export($patterns);
24
     * </code>
25
     */
26
    protected static $patterns = array (
27
      'AC' => 'ASCN 1ZZ',
28
      'AD' => 'AD[1-7]0\\d',
29
      'AF' => '\\d{4}',
30
      'AI' => '2640',
31
      'AL' => '\\d{4}',
32
      'AM' => '(37)?\\d{4}',
33
      'AR' => '((?:[A-HJ-NP-Z])?\\d{4})([A-Z]{3})?',
34
      'AS' => '(96799)(?:[ \\-](\\d{4}))?',
35
      'AT' => '\\d{4}',
36
      'AU' => '\\d{4}',
37
      'AX' => '22\\d{3}',
38
      'AZ' => '\\d{4}',
39
      'BA' => '\\d{5}',
40
      'BB' => '(?:BB\\d{5})?',
41
      'BD' => '\\d{4}',
42
      'BE' => '\\d{4}',
43
      'BG' => '\\d{4}',
44
      'BH' => '(?:(?:\\d|1[0-2])\\d{2})?',
45
      'BL' => '9[78][01]\\d{2}',
46
      'BM' => '[A-Z]{2}[ ]?[A-Z0-9]{2}',
47
      'BN' => '[A-Z]{2}[ ]?\\d{4}',
48
      'BR' => '\\d{5}[\\-]?\\d{3}',
49
      'BT' => '\\d{5}',
50
      'BY' => '\\d{6}',
51
      'CA' => '[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z][ ]?\\d[ABCEGHJ-NPRSTV-Z]\\d',
52
      'CC' => '6799',
53
      'CH' => '\\d{4}',
54
      'CL' => '\\d{7}',
55
      'CN' => '\\d{6}',
56
      'CO' => '\\d{6}',
57
      'CR' => '\\d{4,5}|\\d{3}-\\d{4}',
58
      'CV' => '\\d{4}',
59
      'CX' => '6798',
60
      'CY' => '\\d{4}',
61
      'CZ' => '\\d{3}[ ]?\\d{2}',
62
      'DE' => '\\d{5}',
63
      'DK' => '\\d{4}',
64
      'DO' => '\\d{5}',
65
      'DZ' => '\\d{5}',
66
      'EC' => '(?:[A-Z]\\d{4}[A-Z]|(?:[A-Z]{2})?\\d{6})?',
67
      'EE' => '\\d{5}',
68
      'EG' => '\\d{5}',
69
      'EH' => '\\d{5}',
70
      'ES' => '\\d{5}',
71
      'ET' => '\\d{4}',
72
      'FI' => '\\d{5}',
73
      'FK' => 'FIQQ 1ZZ',
74
      'FM' => '(9694[1-4])(?:[ \\-](\\d{4}))?',
75
      'FO' => '\\d{3}',
76
      'FR' => '\\d{2}[ ]?\\d{3}',
77
      'GB' => 'GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|BX|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\\d{1,4}',
78
      'GE' => '\\d{4}',
79
      'GF' => '9[78]3\\d{2}',
80
      'GG' => 'GY\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}',
81
      'GI' => 'GX11 1AA',
82
      'GL' => '39\\d{2}',
83
      'GN' => '\\d{3}',
84
      'GP' => '9[78][01]\\d{2}',
85
      'GR' => '\\d{3} ?\\d{2}',
86
      'GS' => 'SIQQ 1ZZ',
87
      'GT' => '\\d{5}',
88
      'GU' => '(969(?:[12]\\d|3[12]))(?:[ \\-](\\d{4}))?',
89
      'GW' => '\\d{4}',
90
      'HM' => '\\d{4}',
91
      'HN' => '\\d{5}',
92
      'HR' => '\\d{5}',
93
      'HT' => '\\d{4}',
94
      'HU' => '\\d{4}',
95
      'ID' => '\\d{5}',
96
      'IL' => '\\d{5}(?:\\d{2})?',
97
      'IM' => 'IM\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}',
98
      'IN' => '\\d{6}',
99
      'IO' => 'BBND 1ZZ',
100
      'IQ' => '\\d{5}',
101
      'IR' => '\\d{5}-?\\d{5}',
102
      'IS' => '\\d{3}',
103
      'IT' => '\\d{5}',
104
      'JE' => 'JE\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}',
105
      'JO' => '\\d{5}',
106
      'JP' => '\\d{3}-?\\d{4}',
107
      'KE' => '\\d{5}',
108
      'KG' => '\\d{6}',
109
      'KH' => '\\d{5}',
110
      'KR' => '\\d{3}[\\-]\\d{3}',
111
      'KW' => '\\d{5}',
112
      'KY' => 'KY\\d-\\d{4}',
113
      'KZ' => '\\d{6}',
114
      'LA' => '\\d{5}',
115
      'LB' => '(?:(?:\\d{4})(?:[ ]?(?:\\d{4}))?)?',
116
      'LI' => '(948[5-9])|(949[0-7])',
117
      'LK' => '\\d{5}',
118
      'LR' => '\\d{4}',
119
      'LS' => '\\d{3}',
120
      'LT' => '\\d{5}',
121
      'LU' => '\\d{4}',
122
      'LV' => 'LV-\\d{4}',
123
      'MA' => '\\d{5}',
124
      'MC' => '980\\d{2}',
125
      'MD' => '\\d{4}',
126
      'ME' => '8\\d{4}',
127
      'MF' => '9[78][01]\\d{2}',
128
      'MG' => '\\d{3}',
129
      'MH' => '(969[67]\\d)(?:[ \\-](\\d{4}))?',
130
      'MK' => '\\d{4}',
131
      'MM' => '\\d{5}',
132
      'MN' => '\\d{5}',
133
      'MP' => '(9695[012])(?:[ \\-](\\d{4}))?',
134
      'MQ' => '9[78]2\\d{2}',
135
      'MT' => '[A-Z]{3}[ ]?\\d{2,4}',
136
      'MU' => '(?:\\d{3}(?:\\d{2}|[A-Z]{2}\\d{3}))?',
137
      'MV' => '\\d{5}',
138
      'MX' => '\\d{5}',
139
      'MY' => '\\d{5}',
140
      'MZ' => '\\d{4}',
141
      'NC' => '988\\d{2}',
142
      'NE' => '\\d{4}',
143
      'NF' => '2899',
144
      'NG' => '(?:\\d{6})?',
145
      'NI' => '\\d{5}',
146
      'NL' => '[1-9]{1}\\d{3}[ ]?[A-Z]{2}',    // Changed: ZipCode cannot start with 0
147
      'NO' => '\\d{4}',
148
      'NP' => '\\d{5}',
149
      'NZ' => '\\d{4}',
150
      'OM' => '(PC )?\\d{3}',
151
      'PE' => '(?:LIMA \\d|CALLAO 0?)\\d|[0-2]\\d{4}',
152
      'PF' => '987\\d{2}',
153
      'PG' => '\\d{3}',
154
      'PH' => '\\d{4}',
155
      'PK' => '\\d{5}',
156
      'PL' => '\\d{2}-\\d{3}',
157
      'PM' => '9[78]5\\d{2}',
158
      'PN' => 'PCRN 1ZZ',
159
      'PR' => '(00[679]\\d{2})(?:[ \\-](\\d{4}))?',
160
      'PT' => '\\d{4}-\\d{3}',
161
      'PW' => '(969(?:39|40))(?:[ \\-](\\d{4}))?',
162
      'PY' => '\\d{4}',
163
      'RE' => '9[78]4\\d{2}',
164
      'RO' => '\\d{6}',
165
      'RS' => '\\d{5,6}',
166
      'RU' => '\\d{6}',
167
      'SA' => '\\d{5}',
168
      'SE' => '\\d{3}[ ]?\\d{2}',
169
      'SG' => '\\d{6}',
170
      'SH' => '(ASCN|STHL) 1ZZ',
171
      'SI' => '\\d{4}',
172
      'SJ' => '\\d{4}',
173
      'SK' => '\\d{3}[ ]?\\d{2}',
174
      'SM' => '4789\\d',
175
      'SN' => '\\d{5}',
176
      'SO' => '\\d{5}',
177
      'SV' => 'CP [1-3][1-7][0-2]\\d',
178
      'SZ' => '[HLMS]\\d{3}',
179
      'TA' => 'TDCU 1ZZ',
180
      'TC' => 'TKCA 1ZZ',
181
      'TH' => '\\d{5}',
182
      'TJ' => '\\d{6}',
183
      'TM' => '\\d{6}',
184
      'TN' => '\\d{4}',
185
      'TR' => '\\d{5}',
186
      'TW' => '\\d{3}(\\d{2})?',
187
      'TZ' => '\\d{4}',
188
      'UA' => '\\d{5}',
189
      'UM' => '96898',
190
      'US' => '(\\d{5})(?:[ \\-](\\d{4}))?',
191
      'UY' => '\\d{5}',
192
      'UZ' => '\\d{6}',
193
      'VA' => '00120',
194
      'VC' => 'VC\\d{4}',
195
      'VE' => '\\d{4}',
196
      'VG' => 'VG\\d{4}',
197
      'VI' => '(008(?:(?:[0-4]\\d)|(?:5[01])))(?:[ \\-](\\d{4}))?',
198
      'VN' => '\\d{6}',
199
      'WF' => '986\\d{2}',
200
      'XK' => '[1-7]\\d{4}',
201
      'YT' => '976\\d{2}',
202
      'ZA' => '\\d{4}',
203
      'ZM' => '\\d{5}',
204
    );
205
206
    /**
207
     * @param  string $zipcode
208
     * @param  string $country
209
     *
210
     * @return bool
211
     *
212
     * @throws \InvalidArgumentException
213
     */
214
    public static function validate($zipcode, $country)
215
    {
216
        $zipcode = trim($zipcode);
217
        if (empty($zipcode)) {
218
            return false;
219
        }
220
221
        $country = strtoupper($country);
222
        if (!isset(self::$patterns[$country])) {
223
            throw new \InvalidArgumentException("ERROR: The zipcode validator for $country does not exists yet: feel free to add it.");
224
        }
225
226
        return (boolean) preg_match('/^'.self::$patterns[$country].'$/', $zipcode);
227
    }
228
229
    /**
230
     * @return array The available countries code list. ['FR', 'US', 'ZA', ...]
231
     */
232
    public static function getAvailableCountries()
233
    {
234
        return array_keys(self::$patterns);
235
    }
236
}
237