CheckoutWizard   F
last analyzed

Complexity

Total Complexity 62

Size/Duplication

Total Lines 474
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 271
dl 0
loc 474
rs 3.44
c 1
b 0
f 0
wmc 62

15 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 27 8
A prepareFieldtype() 0 8 1
F completeCallback() 0 159 13
A prepareDefaultvalue() 0 20 5
A processFieldtype() 0 7 1
A processSettings() 0 16 3
A isValidEmail() 0 3 1
A processSearch() 0 17 3
B prepareSettings() 0 37 10
A processDefaultValue() 0 10 2
A processLookup() 0 25 4
A prepareFieldname() 0 19 3
A processFieldname() 0 17 3
A processConfirm() 0 3 1
A prepareSearch() 0 13 4

How to fix   Complexity   

Complex Class

Complex classes like CheckoutWizard often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CheckoutWizard, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace XoopsModules\Pedigree;
4
5
//require_once __DIR__ . '/wizard.php';
6
use RuntimeException;
7
8
use const _MA_PEDIGREE_FIELD_EXPLAN1;
9
10
use const ENT_HTML5;
11
12
/**
13
 * Class CheckoutWizard
14
 */
15
class CheckoutWizard extends ZervWizard
16
{
17
    /**
18
     * CheckoutWizard constructor.
19
     */
20
    public function __construct()
21
    {
22
        global $field;
23
        // start the session and initialize the wizard
24
        if (null === $_SESSION) {
25
            if (false === @\session_start()) {
26
                throw new RuntimeException('Session could not start.');
27
            }
28
        }
29
        parent::__construct($_SESSION, __CLASS__);
30
31
        $this->addStep('fieldname', \_MA_PEDIGREE_ENTER_FIELD);
32
        if (0 == $this->getValue('field')) { //only for a new field
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $this->getValue('field') of type mixed|null to 0; this is ambiguous as not only 0 == 0 is true, but null == 0 is true, too. Consider using a strict comparison ===.
Loading history...
33
            $this->addStep('fieldtype', \_MA_PEDIGREE_FIELD_TYP_SEL);
34
            if (('selectbox' === $this->getValue('fieldtype')) || ('radiobutton' === $this->getValue('fieldtype'))) {
35
                $this->addStep('lookup', \_MA_PEDIGREE_FIELD_ADD_VALUE);
36
            }
37
        }
38
39
        $this->addStep('Settings', \_MA_PEDIGREE_FIELD_PARAM);
40
        if ('hassearch' === $this->getValue('hassearch')) {
41
            $this->addStep('search', \_MA_PEDIGREE_SEARCH_PARAMFIELD);
42
        }
43
        if ('picture' !== $this->getValue('fieldtype')) {
44
            $this->addStep('defaultvalue', \_MA_PEDIGREE_FIELD_DEFAUT);
45
        }
46
        $this->addStep('confirm', \_MA_PEDIGREE_FIELDCONFIRM);
47
    }
48
49
    /**
50
     * @todo change access to fields using Pedigree\Fields
51
     */
52
    public function prepareFieldname()
53
    {
54
        global $field;
55
        if (0 == !$field) {
56
            // field already exists (editing mode)
57
58
            $sql    = 'SELECT * FROM ' . $GLOBALS['xoopsDB']->prefix('pedigree_fields') . ' WHERE id=' . $field;
59
            $result = $GLOBALS['xoopsDB']->query($sql);
60
            while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
61
                $name             = $row['fieldname'];
62
                $fieldexplanation = $row['fieldexplanation'];
63
                $fieldtype        = $row['fieldtype'];
64
            }
65
            $this->setValue('name', $name);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.
Loading history...
66
            $this->setValue('explain', $fieldexplanation);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fieldexplanation does not seem to be defined for all execution paths leading up to this point.
Loading history...
67
            //set the fieldtype because we wont allow it to be edited
68
            $this->setValue('fieldtype', $fieldtype);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fieldtype does not seem to be defined for all execution paths leading up to this point.
Loading history...
69
        }
70
        $this->setValue('field', $field); //is it a new field or are we editing a field
71
    }
72
73
    /**
74
     * @param $form
75
     *
76
     * @return bool
77
     */
78
    public function processFieldname($form)
79
    {
80
        $name = $this->coalesce($form['name']);
81
        if (\mb_strlen($name) > 0) {
82
            $this->setValue('name', $name);
83
        } else {
84
            $this->addError('name', \_MA_PEDIGREE_FIELD_NAM);
85
        }
86
87
        $fieldexplanation = $this->coalesce($form['explain']);
88
        if (\mb_strlen($fieldexplanation) > 0) {
89
            $this->setValue('explain', $fieldexplanation);
90
        } else {
91
            $this->addError('explain', _MA_PEDIGREE_FIELD_EXPLAN1);
92
        }
93
94
        return !$this->isError();
95
    }
96
97
    /**
98
     * Setup this class' fieldtype array
99
     */
100
    public function prepareFieldtype()
101
    {
102
        $this->fieldtype[] = ['value' => 'radiobutton', 'description' => \_MA_PEDIGREE_RADIOBUTTONFIELD];
0 ignored issues
show
Bug Best Practice introduced by
The property fieldtype does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
103
        $this->fieldtype[] = ['value' => 'selectbox', 'description' => \_MA_PEDIGREE_DROPDOWNFIELD];
104
        $this->fieldtype[] = ['value' => 'textbox', 'description' => \_MA_PEDIGREE_TEXTBOXFIELD];
105
        $this->fieldtype[] = ['value' => 'textarea', 'description' => \_MA_PEDIGREE_TEXTAREAFIELD];
106
        $this->fieldtype[] = ['value' => 'DateSelect', 'description' => \_MA_PEDIGREE_DATEFIELD];
107
        $this->fieldtype[] = ['value' => 'UrlField', 'description' => \_MA_PEDIGREE_URLFIELD];
108
    }
109
110
    /**
111
     * @param $form
112
     *
113
     * @return bool
114
     */
115
    public function processFieldtype($form)
116
    {
117
        $this->prepareFieldtype();
118
        $fieldtype = $this->coalesce($form['fieldtype']);
119
        $this->setValue('fieldtype', $fieldtype);
120
121
        return !$this->isError();
122
    }
123
124
    /**
125
     * @param $form
126
     *
127
     * @return bool
128
     */
129
    public function processLookup($form)
130
    {
131
        $fc = $this->coalesce($form['fc']);
132
        $this->setValue('fc', $fc);
133
        $lookup   = $this->coalesce($form['lookup' . $fc]);
134
        $lookupid = $this->coalesce($form['id' . $fc]);
135
        if (\mb_strlen($lookup) > 0) {
136
            $this->setValue('lookup' . $fc, $lookup);
137
            $this->setValue('id' . $fc, $lookupid);
138
        }
139
        $lastlookup = $this->getValue('lookup' . $fc);
140
        if ('' == $lastlookup) {
141
            $this->setValue('fc', $fc - 1);
142
        }
143
144
        for ($i = 0; $i < $fc; ++$i) {
145
            $radioarray[] = [
146
                'id'    => $this->getValue('id' . ($i + 1)),
147
                'value' => $this->getValue('lookup' . ($i + 1)),
148
            ];
149
        }
150
        //print_r($radioarray); exit();
151
        $this->setValue('radioarray', $radioarray);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $radioarray does not seem to be defined for all execution paths leading up to this point.
Loading history...
152
153
        return !$this->isError();
154
    }
155
156
    public function prepareSettings()
157
    {
158
        if (0 == !$this->getValue('field')) {
159
            // field already exists (editing mode)
160
161
            {
162
                $sql = 'SELECT * FROM ' . $GLOBALS['xoopsDB']->prefix('pedigree_fields') . " WHERE id='" . $this->getValue('field') . "'";
163
            }
164
            $result = $GLOBALS['xoopsDB']->query($sql);
165
            while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
166
                $hs = $row['hassearch'];
167
                if ('1' == $hs) {
168
                    $this->setValue('hassearch', 'hassearch');
169
                }
170
                $vip = $row['viewinpedigree'];
171
                if ('1' == $vip) {
172
                    $this->setValue('viewinpedigree', 'viewinpedigree');
173
                }
174
                $via = $row['viewinadvanced'];
175
                if ('1' == $via) {
176
                    $this->setValue('viewinadvanced', 'viewinadvanced');
177
                }
178
                $vipie = $row['viewinpie'];
179
                if ('1' == $vipie) {
180
                    $this->setValue('viewinpie', 'viewinpie');
181
                }
182
                $vil = $row['viewinlist'];
183
                if ('1' == $vil) {
184
                    $this->setValue('viewinlist', 'viewinlist');
185
                }
186
                $lit = $row['litter'];
187
                if ('1' == $lit) {
188
                    $this->setValue('litter', 'litter');
189
                }
190
                $glit = $row['generallitter'];
191
                if ('1' == $glit) {
192
                    $this->setValue('generallitter', 'generallitter');
193
                }
194
            }
195
        }
196
    }
197
198
    /**
199
     * @param $form
200
     *
201
     * @return bool
202
     */
203
    public function processSettings($form)
204
    {
205
        $this->setValue('hassearch', $this->coalesce($form['hasSearch']));
206
        $this->setValue('viewinpedigree', $this->coalesce($form['viewinpedigree']));
207
        $this->setValue('viewinadvanced', $this->coalesce($form['viewinadvanced']));
208
        $this->setValue('viewinpie', $this->coalesce($form['viewinpie']));
209
        $this->setValue('viewinlist', $this->coalesce($form['viewinlist']));
210
        $this->setValue('litter', $this->coalesce($form['litter']));
211
        $this->setValue('generallitter', $this->coalesce($form['generallitter']));
212
213
        //if both litter and general litter are set; unset generallitter
214
        if (('litter' === $this->getValue('litter')) && ('generallitter' === $this->getValue('generallitter'))) {
215
            $this->setValue('generallitter', 0);
216
        }
217
218
        return !$this->isError();
219
    }
220
221
    public function prepareSearch()
222
    {
223
        if (0 == !$this->getValue('field')) {
224
            // field already exists (editing mode)
225
226
            $sql    = 'SELECT * FROM ' . $GLOBALS['xoopsDB']->prefix('pedigree_fields') . ' WHERE id=' . $this->getValue('field');
227
            $result = $GLOBALS['xoopsDB']->query($sql);
228
            while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
229
                if ('hasearch' === $this->getValue('hassearch')) {
230
                    $searchname = $row['searchname'];
231
                    $this->setValue('searchname', $searchname);
232
                    $searchexplain = $row['searchexplanation'];
233
                    $this->setValue('searchexplain', $searchexplain);
234
                }
235
            }
236
        }
237
    }
238
239
    /**
240
     * @param $form
241
     *
242
     * @return bool
243
     * @todo move language strings to language files
244
     */
245
    public function processSearch($form)
246
    {
247
        $searchname = $this->coalesce($form['searchname']);
248
        if (\mb_strlen($searchname) > 0) {
249
            $this->setValue('searchname', $searchname);
250
        } else {
251
            $this->addError('searchname', 'Please enter the searchname');
252
        }
253
254
        $fieldexplanation = $this->coalesce($form['searchexplain']);
255
        if (\mb_strlen($fieldexplanation) > 0) {
256
            $this->setValue('searchexplain', $fieldexplanation);
257
        } else {
258
            $this->addError('searchexplain', 'Please enter the search explanation for this field');
259
        }
260
261
        return !$this->isError();
262
    }
263
264
    public function prepareDefaultvalue()
265
    {
266
        if (0 == !$this->getValue('field')) {
267
            // field already exists (editing mode)
268
269
            $sql    = 'SELECT * FROM ' . $GLOBALS['xoopsDB']->prefix('pedigree_fields') . ' WHERE id=' . $this->getValue('field');
270
            $result = $GLOBALS['xoopsDB']->query($sql);
271
            while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
272
                $def = $row['DefaultValue'];
273
                $this->setValue('defaultvalue', $def);
274
                if ('1' == $row['LookupTable']) { //we have a lookup table; load values
275
                    $sql    = 'SELECT * FROM ' . $GLOBALS['xoopsDB']->prefix('pedigree_lookup' . $this->getValue('field')) . " ORDER BY 'order'";
276
                    $fc     = 0;
277
                    $result = $GLOBALS['xoopsDB']->query($sql);
278
                    while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
279
                        $radioarray[] = ['id' => $row['id'], 'value' => $row['value']];
280
                        ++$fc;
281
                    }
282
                    $this->setValue('radioarray', $radioarray);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $radioarray does not seem to be defined for all execution paths leading up to this point.
Loading history...
283
                    $this->setValue('fc', $fc);
284
                }
285
            }
286
        }
287
    }
288
289
    /**
290
     * @param $form
291
     *
292
     * @return bool
293
     * @todo move language string to language file
294
     */
295
    public function processDefaultValue($form)
296
    {
297
        $defaultvalue = $this->coalesce($form['defaultvalue']);
298
        if (\mb_strlen($defaultvalue) >= 0) {
299
            $this->setValue('defaultvalue', $defaultvalue);
300
        } else {
301
            $this->addError('defaultvalue', 'Please enter a defaultvalue');
302
        }
303
304
        return !$this->isError();
305
    }
306
307
    /**
308
     * @param $form
309
     *
310
     * @return bool
311
     */
312
    public function processConfirm($form)
0 ignored issues
show
Unused Code introduced by
The parameter $form is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

312
    public function processConfirm(/** @scrutinizer ignore-unused */ $form)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
313
    {
314
        return !$this->isError();
315
    }
316
317
    public function completeCallback()
318
    {
319
        //can this field be searched
320
        $search = $this->getValue('hassearch');
321
        if ('hassearch' === $search) {
322
            $search        = '1';
323
            $searchname    = $this->getValue('searchname');
324
            $searchexplain = $this->getValue('searchexplain');
325
        } else {
326
            $search        = '0';
327
            $searchname    = '';
328
            $searchexplain = '';
329
        }
330
        //show in pedigree
331
        $viewinpedigree = $this->getValue('viewinpedigree');
332
        if ('viewinpedigree' === $viewinpedigree) {
333
            $viewinpedigree = '1';
334
        } else {
335
            $viewinpedigree = '0';
336
        }
337
        //show in advanced
338
        $viewinadvanced = $this->getValue('viewinadvanced');
339
        if ('viewinadvanced' === $viewinadvanced) {
340
            $viewinadvanced = '1';
341
        } else {
342
            $viewinadvanced = '0';
343
        }
344
        //show in pie
345
        $viewinpie = $this->getValue('viewinpie');
346
        if ('viewinpie' === $viewinpie) {
347
            $viewinpie = '1';
348
        } else {
349
            $viewinpie = '0';
350
        }
351
        //view in list
352
        $viewinlist = $this->getValue('viewinlist');
353
        if ('viewinlist' === $viewinlist) {
354
            $viewinlist = '1';
355
        } else {
356
            $viewinlist = '0';
357
        }
358
        //add a litter?
359
        $litter = ('litter' === $this->getValue('litter')) ? '1' : '0';
360
361
        //general litter
362
        $generallitter = ('generallitter' === $this->getValue('generalLitter')) ? '1' : '0';
363
364
        if (0 == !$this->getValue('field')) {
365
            // field already exists (editing mode)
366
367
            //@todo refactor using class methods
368
            $sql = 'UPDATE '
369
                   . $GLOBALS['xoopsDB']->prefix('pedigree_fields')
370
                   . " SET fieldname = '"
371
                   . \htmlspecialchars($this->getValue('name'), \ENT_QUOTES | ENT_HTML5)
372
                   . "', fieldtype = '"
373
                   . $this->getValue('fieldtype')
374
                   . "', defaultvalue = '"
375
                   . $this->getValue('defaultvalue')
376
                   . "', fieldexplanation = '"
377
                   . $this->getValue('explain')
378
                   . "', hassearch = '"
379
                   . $search
380
                   . "', litter = '"
381
                   . $litter
382
                   . "', generallitter = '"
383
                   . $generallitter
384
                   . "', searchname = '"
385
                   . $searchname
386
                   . "', searchexplanation = '"
387
                   . $searchexplain
388
                   . "', viewinpedigree = '"
389
                   . $viewinpedigree
390
                   . "', viewinadvanced = '"
391
                   . $viewinadvanced
392
                   . "', viewinpie = '"
393
                   . $viewinpie
394
                   . "', viewinlist = '"
395
                   . $viewinlist
396
                   . "' WHERE id ='"
397
                   . $this->getValue('field')
398
                   . "'";
399
            $GLOBALS['xoopsDB']->queryF($sql);
400
            //possible change defaultvalue for userfield
401
            $sql = 'ALTER TABLE ' . $GLOBALS['xoopsDB']->prefix('pedigree_registry') . ' CHANGE `user' . $this->getValue('field') . '` `user' . $this->getValue('field') . "` VARCHAR( 255 ) NOT NULL DEFAULT '" . $this->getValue('defaultvalue') . "'";
402
            $GLOBALS['xoopsDB']->queryF($sql);
403
            $sql = 'ALTER TABLE ' . $GLOBALS['xoopsDB']->prefix('pedigree_temp') . ' CHANGE `user' . $this->getValue('field') . '` `user' . $this->getValue('field') . "` VARCHAR( 1024 ) NOT NULL DEFAULT '" . $this->getValue('defaultvalue') . "'";
404
            $GLOBALS['xoopsDB']->queryF($sql);
405
            $sql = 'ALTER TABLE ' . $GLOBALS['xoopsDB']->prefix('pedigree_trash') . ' CHANGE `user' . $this->getValue('field') . '` `user' . $this->getValue('field') . "` VARCHAR( 255 ) NOT NULL DEFAULT '" . $this->getValue('defaultvalue') . "'";
406
            $GLOBALS['xoopsDB']->queryF($sql);
407
        } else { //this is a new field
408
            $sql    = 'SELECT MAX(id) AS lid FROM ' . $GLOBALS['xoopsDB']->prefix('pedigree_fields') . ' LIMIT 1';
409
            $result = $GLOBALS['xoopsDB']->query($sql);
410
            while (false !== ($row = $GLOBALS['xoopsDB']->fetchArray($result))) {
411
                $nextfieldnum = $row['lid'] + 1;
412
            }
413
            //add userfield to various tables as a new field.
414
            //always add at the end of the table
415
            $tables = ['pedigree_registry', 'pedigree_temp', 'pedigree_trash'];
416
            foreach ($tables as $table) {
417
                $SQL = 'ALTER TABLE ' . $GLOBALS['xoopsDB']->prefix($table) . ' ADD `user' . $nextfieldnum . "` VARCHAR( 255 ) NOT NULL DEFAULT '" . $this->getValue('defaultvalue') . "'";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $nextfieldnum does not seem to be defined for all execution paths leading up to this point.
Loading history...
418
                $GLOBALS['xoopsDB']->queryF($SQL);
419
            }
420
            //is a lookup table present
421
            $lookup = $this->getValue('lookup1');
422
            if ('' == $lookup) {
423
                $lookup = '0';
424
            } else {
425
                $lookup = '1';
426
                //create table for lookupfield
427
                $createtable = 'CREATE TABLE ' . $GLOBALS['xoopsDB']->prefix('pedigree_lookup' . $nextfieldnum) . ' (`id` INT( 10 ) NOT NULL ,`value` VARCHAR( 255 ) NOT NULL, `order` INT( 10 )) ENGINE = MyISAM';
428
                $GLOBALS['xoopsDB']->queryF($createtable);
429
                //fill table
430
                $count = $this->getValue('fc');
431
                for ($x = 1; $x < $count + 1; ++$x) {
432
                    $y   = $x - 1;
433
                    $sql = 'INSERT INTO ' . $GLOBALS['xoopsDB']->prefix('pedigree_lookup' . $nextfieldnum) . " ( `id` , `value`, `order`) VALUES ('" . $y . "', '" . $this->getValue('lookup' . $x) . "','" . $y . "')";
434
                    $GLOBALS['xoopsDB']->queryF($sql);
435
                }
436
            }
437
438
            //Insert new record into pedigree_fields
439
            //            $sql = 'INSERT INTO ' . $GLOBALS['xoopsDB']->prefix('pedigree_fields') . " VALUES ('" . $nextfieldnum . "', '1', '" . htmlspecialchars($this->getValue('name')) . "', '" . $this->getValue('fieldtype') . "', '" . $lookup . "', '" . $this->getValue('defaultvalue') . "', '" . $this->getValue('explain') . "', '" . $search . "', '" . $Litter . "', '" . $generalLitter . "', '" . $searchname . "', '" . $searchexplain . "', '" . $viewinpedigree . "', '" . $viewinadvanced . "', '" . $viewinpie . "', '" . $viewinlist . "','','" . $nextfieldnum . "')";
440
            $sql = 'INSERT INTO '
441
                   . $GLOBALS['xoopsDB']->prefix('pedigree_fields')
442
                   . " VALUES ('"
443
                   . $nextfieldnum
444
                   . "', '1', '"
445
                   . $GLOBALS['xoopsDB']->escape(\htmlspecialchars($this->getValue('name'), \ENT_QUOTES | ENT_HTML5))
446
                   . "', '"
447
                   . $GLOBALS['xoopsDB']->escape($this->getValue('fieldtype'))
448
                   . "', '"
449
                   . $GLOBALS['xoopsDB']->escape($lookup)
450
                   . "', '"
451
                   . $GLOBALS['xoopsDB']->escape($this->getValue('defaultvalue'))
452
                   . "', '"
453
                   . $GLOBALS['xoopsDB']->escape($this->getValue('explain'))
454
                   . "', '"
455
                   . $GLOBALS['xoopsDB']->escape($search)
456
                   . "', '"
457
                   . $GLOBALS['xoopsDB']->escape($Litter)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $Litter seems to be never defined.
Loading history...
458
                   . "', '"
459
                   . $GLOBALS['xoopsDB']->escape($generallitter)
460
                   . "', '"
461
                   . $GLOBALS['xoopsDB']->escape($searchname)
462
                   . "', '"
463
                   . $GLOBALS['xoopsDB']->escape($searchexplain)
464
                   . "', '"
465
                   . $GLOBALS['xoopsDB']->escape($viewinpedigree)
466
                   . "', '"
467
                   . $GLOBALS['xoopsDB']->escape($viewinadvanced)
468
                   . "', '"
469
                   . $GLOBALS['xoopsDB']->escape($viewinpie)
470
                   . "', '"
471
                   . $GLOBALS['xoopsDB']->escape($viewinlist)
472
                   . "','','"
473
                   . $GLOBALS['xoopsDB']->escape($nextfieldnum)
474
                   . "')";
475
            $GLOBALS['xoopsDB']->queryF($sql);
476
        }
477
    }
478
479
    /**
480
     * Miscellaneous utility functions
481
     *
482
     * @param $email
483
     *
484
     * @return int
485
     */
486
    public function isValidEmail($email)
487
    {
488
        return \preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*$/i', $email);
489
    }
490
}
491