mrcnpdlk/validator

View on GitHub
src/mrcnpdlk/Validator/Types/Phone.php

Summary

Maintainability
C
7 hrs
Test Coverage
<?php
/**
 * Validator
 *
 * Copyright (c) 2017 pudelek.org.pl
 *
 * @license MIT License (MIT)
 *
 * For the full copyright and license information, please view source file
 * that is bundled with this package in the file LICENSE
 *
 * @author  Marcin Pudełek <marcin@pudelek.org.pl>
 */


namespace mrcnpdlk\Validator\Types;


use mrcnpdlk\Validator\Exception;
use mrcnpdlk\Validator\TypeInterface;

/**
 * Class Phone
 *
 * Polish phone number validator
 *
 * @package mrcnpdlk\Validator\Types
 */
class Phone extends TypeAbstract implements TypeInterface
{
    const COUNTRY_PREFIX         = '48';
    const NATIONAL_NUMBER_LENGTH = 9;
    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})/';
    const REGEX_MOBILE           = '/(?:45|5[0137]|6[069]|7[2389]|88)\d{7}/';
    const REGEX_TOLL_FREE        = '/800\d{6}/';
    const REGEX_PREMIUM_RATE     = '/70[01346-8]\d{6}/';
    const REGEX_SHARED_COST      = '/801\d{6}/';
    const REGEX_VOIP             = '/39\d{7}/';
    const REGEX_UAN              = '/804\d{6}/';

    private $ukeMobilePlan = [];
    private $ukeFixedPlan  = [];

    /**
     * Phone constructor.
     *
     * @param $checkedValue
     */
    public function __construct($checkedValue)
    {
        parent::__construct($checkedValue);
        //pobieramy sam numer krajowy
        $this->checkedValue = substr($this->checkedValue, -9);
    }

    /**
     * Usuwamy niepotrzebne separatory
     *
     * @param mixed $checkedValue
     *
     * @return string
     */
    public static function clean($checkedValue)
    {
        static::isValidType($checkedValue, static::TYPE_STRING, true);

        return preg_replace('/[\s]/', '', trim($checkedValue));
    }

    /**
     * @param mixed $checkedValue
     * @param bool  $asEx
     *
     * @return bool
     * @throws Exception
     */
    public static function isValid($checkedValue, bool $asEx = false): bool
    {
        try {
            static::isValidType($checkedValue, static::TYPE_STRING, true);
            if (strlen($checkedValue) !== 9 && strlen($checkedValue) !== 11) {
                throw new \Exception(sprintf('invalid length'));
            }
            if (!preg_match('/^' . static::COUNTRY_PREFIX . '[\d]{9}$/', $checkedValue)
                && !preg_match('/^[\d]{9}$/', $checkedValue)) {
                throw new \Exception('regex error');
            }

            return true;
        } catch (\Exception $e) {
            if ($asEx) {
                throw new Exception(sprintf("Invalid phone number [%s], reason: %s", $checkedValue, $e->getMessage()));
            } else {
                return false;
            }
        }
    }

    /**
     * @return string
     */
    public function getCountryCode()
    {
        return static::COUNTRY_PREFIX;
    }

    /**
     * @return string
     */
    public function getInternationalFormat()
    {
        return sprintf('%s%s', static::COUNTRY_PREFIX, $this->get());
    }

    /**
     * @return bool
     */
    public function isPremiumRate()
    {
        return preg_match(static::REGEX_PREMIUM_RATE, $this->checkedValue) === 1;
    }

    /**
     * @return bool
     */
    public function isSharedCost()
    {
        return preg_match(static::REGEX_SHARED_COST, $this->checkedValue) === 1;
    }

    /**
     * @return bool
     */
    public function isTollFree()
    {
        return preg_match(static::REGEX_TOLL_FREE, $this->checkedValue) === 1;
    }

    /**
     * @return bool
     */
    public function isUAN()
    {
        return preg_match(static::REGEX_UAN, $this->checkedValue) === 1;
    }

    /**
     * @return bool
     */
    public function isVoip()
    {
        return preg_match(static::REGEX_VOIP, $this->checkedValue) === 1;
    }

    public function getRegion()
    {
        $sRegion = null;
        if ($this->isMobile()) {
            $nr = $this->getNationalFormat();
            while (strlen($nr) > 0 || is_null($sRegion)) {
                if (array_key_exists($nr, $this->getUkeMobilePlan())) {
                    $sRegion = $this->getUkeMobilePlan()[$nr]['operator'];
                }
                $nr = substr($nr, 0, -1);
            }
        } elseif ($this->isFixed()) {
            $sRegion = $this->getUkeFixedPlan()[substr($this->getNationalFormat(), 0, 2)] ?? null;
        }

        return $sRegion ?? 'Polska';
    }

    /**
     * @return bool
     */
    public function isMobile()
    {
        return preg_match(static::REGEX_MOBILE, $this->checkedValue) === 1;
    }

    /**
     * @return mixed|string
     */
    public function getNationalFormat()
    {
        return $this->get();
    }

    /**
     * @return array
     */
    private function getUkeMobilePlan()
    {
        if (empty($this->ukeMobilePlan)) {
            $oXml = new \SimpleXMLElement(file_get_contents(__DIR__ . '/../Databases/T2-PLMN_T9-MVNO.xml'));

            foreach ($oXml->numery->plmn as $oNr) {
                $t = $this->parseNumberPlan(strval($oNr->numer));
                foreach ($t as $n) {
                    $this->ukeMobilePlan[$n] = [
                        'numer'    => strval($oNr->numer),
                        'operator' => strval($oNr->operator),
                        'typ'      => strval($oNr->typ),
                    ];
                }
            }
        }

        return $this->ukeMobilePlan;
    }

    /**
     * @param string $plan
     *
     * @return array
     * @throws \Exception
     */
    private function parseNumberPlan(string $plan)
    {
        if (preg_match("/(?'prefix'[\d]*)(\((?'suffix'[\d\-,]*)\))?/", strval($plan), $f)) {
            $answer = [];
            $prefix = $f['prefix'];
            $suffix = $f['suffix'] ?? null;
            $tSuf   = [];
            if (!is_null($suffix)) {
                foreach (explode(',', $suffix) as $digit) {
                    if (preg_match("/((?'first'[\d]{1})\-(?'last'[\d]{1}))/", $digit, $f)) {
                        $first = intval($f['first']);
                        $last  = intval($f['last']);
                        if ($last === 0) {
                            $last   = 9;
                            $tSuf[] = 0;
                        }
                        for ($i = $first; $i <= $last; $i++) {
                            $tSuf[] = $i;
                        }
                    } else {
                        $tSuf[] = intval($digit);
                    }
                }
            }
            if (empty($tSuf)) {
                $answer = [$prefix];
            } else {
                foreach ($tSuf as $d) {
                    $answer[] = $prefix . $d;
                }
            }

            return $answer;
        } else {
            throw new \Exception('regex error');
        }
    }

    /**
     * @return bool
     */
    public function isFixed()
    {
        return preg_match(static::REGEX_FIXED, $this->checkedValue) === 1;
    }

    /**
     * @return array
     */
    private function getUkeFixedPlan()
    {
        if (empty($this->ukeMobilePlan)) {
            include __DIR__ . '/../Databases/ukeFixedPlan.php';
            $this->ukeFixedPlan = $ukeFixedPlan;
        }

        return $this->ukeFixedPlan;
    }
}