├── .editorconfig ├── .github └── workflows │ └── php.yml ├── .styleci.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── composer.json ├── prefill.php └── src ├── Facades └── TaiwanIdentityCard.php ├── IdentityCardServiceProvider.php ├── IdentityCardValidator.php └── TaiwanIdentityCard.php /.editorconfig: -------------------------------------------------------------------------------- 1 | ; This file is for unifying the coding style for different editors and IDEs. 2 | ; More information at http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.github/workflows/php.yml: -------------------------------------------------------------------------------- 1 | name: PHP 2 | 3 | on: [ 'push', 'pull_request' ] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | operating-system: [ 'ubuntu-latest' ] 12 | php-versions: [ '7.2','7.3','7.4','8.0' ] 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Setup PHP 17 | uses: shivammathur/setup-php@v2 18 | with: 19 | php-version: ${{ matrix.php-versions }} 20 | 21 | - name: Validate composer.json and composer.lock 22 | run: composer validate --strict 23 | 24 | - name: Cache Composer packages 25 | id: composer-cache 26 | uses: actions/cache@v3 27 | with: 28 | path: vendor 29 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 30 | restore-keys: | 31 | ${{ runner.os }}-php- 32 | 33 | - name: Install dependencies 34 | run: composer install --prefer-dist --no-progress 35 | 36 | - name: Run test suite 37 | run: composer run-script test 38 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr2 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `:package_name` will be documented in this file. 4 | 5 | Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) principles. 6 | 7 | ## NEXT - YYYY-MM-DD 8 | 9 | ### Added 10 | - Nothing 11 | 12 | ### Deprecated 13 | - Nothing 14 | 15 | ### Fixed 16 | - Nothing 17 | 18 | ### Removed 19 | - Nothing 20 | 21 | ### Security 22 | - Nothing 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to make participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at `:author_email`. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/:vendor/:package_name). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - Check the code style with ``$ composer check-style`` and fix it with ``$ composer fix-style``. 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ composer test 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Detailed description 4 | 5 | Provide a detailed description of the change or addition you are proposing. 6 | 7 | Make it clear if the issue is a bug, an enhancement or just a question. 8 | 9 | ## Context 10 | 11 | Why is this change important to you? How would you use it? 12 | 13 | How can it benefit other users? 14 | 15 | ## Possible implementation 16 | 17 | Not obligatory, but suggest an idea for implementing addition or change. 18 | 19 | ## Your environment 20 | 21 | Include as many relevant details about the environment you experienced the bug in and how to reproduce it. 22 | 23 | * Version used (e.g. PHP 5.6, HHVM 3): 24 | * Operating system and version (e.g. Ubuntu 16.04, Windows 7): 25 | * Link to your project: 26 | * ... 27 | * ... 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2018 :author_name <:author_email> 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | Describe your changes in detail. 6 | 7 | ## Motivation and context 8 | 9 | Why is this change required? What problem does it solve? 10 | 11 | If it fixes an open issue, please link to the issue here (if you write `fixes #num` 12 | or `closes #num`, the issue will be automatically closed when the pull is accepted.) 13 | 14 | ## How has this been tested? 15 | 16 | Please describe in detail how you tested your changes. 17 | 18 | Include details of your testing environment, and the tests you ran to 19 | see how your change affects other areas of the code, etc. 20 | 21 | ## Screenshots (if appropriate) 22 | 23 | ## Types of changes 24 | 25 | What types of changes does your code introduce? Put an `x` in all the boxes that apply: 26 | - [ ] Bug fix (non-breaking change which fixes an issue) 27 | - [ ] New feature (non-breaking change which adds functionality) 28 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 29 | 30 | ## Checklist: 31 | 32 | Go over all the following points, and put an `x` in all the boxes that apply. 33 | 34 | Please, please, please, don't send your pull request until all of the boxes are ticked. Once your pull request is created, it will trigger a build on our [continuous integration](http://www.phptherightway.com/#continuous-integration) server to make sure your [tests and code style pass](https://help.github.com/articles/about-required-status-checks/). 35 | 36 | - [ ] I have read the **[CONTRIBUTING](CONTRIBUTING.md)** document. 37 | - [ ] My pull request addresses exactly one patch/feature. 38 | - [ ] I have created a branch for this patch/feature. 39 | - [ ] Each individual commit in the pull request is meaningful. 40 | - [ ] I have added tests to cover my changes. 41 | - [ ] If my change requires a change to the documentation, I have updated it accordingly. 42 | 43 | If you're unsure about any of these, don't hesitate to ask. We're here to help! 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Taiwan ID Number validation and maker 2 | 3 | meditate/twid is PHP Library to validate and make Taiwan ID Number. 4 | 5 | ## Contents 6 | 7 | - [Installation](#installation) 8 | - [Usage](#usage) 9 | - [Basic](#basic) 10 | - [Facade](#facade) 11 | - [Laravel validation](#laravel-validation) 12 | - [License](#license) 13 | 14 | ## Installation 15 | 16 | You can install the package via composer: 17 | 18 | ```bash 19 | composer require meditate/twid 20 | ``` 21 | 22 | If you are Laravel project, add twid facade in `app/config/app.php`: 23 | 24 | ```php 25 | 'aliases' => [ 26 | ... 27 | 28 | 'Twid' => Meditate\IdentityCard\Facades\TaiwanIdentityCard::class, 29 | ] 30 | ``` 31 | 32 | ## Usage 33 | 34 | ### Basic 35 | 36 | ```php 37 | use Meditate\IdentityCard\TaiwanIdentityCard; 38 | 39 | $taiwanIdCard = new TaiwanIdentityCard; 40 | ``` 41 | 42 | Now, you can use `check` method to validate ID Number: 43 | 44 | ```php 45 | $taiwanIdCard->check('A123456789'); // true 46 | $taiwanIdCard->check('A223456789'); // false 47 | ``` 48 | 49 | Or generate a fake ID Number: 50 | 51 | ```php 52 | // A123456789 53 | $taiwanIdCard->make(); 54 | 55 | // B167663827 56 | $taiwanIdCard->make('B'); 57 | 58 | // A259776352 59 | $taiwanIdCard->make('A', 2); 60 | ``` 61 | 62 | ### Facade 63 | 64 | Also you can use facade: 65 | 66 | ```php 67 | Twid::check('A123456789'); 68 | 69 | Twid::make(); 70 | ``` 71 | 72 | ### Laravel validation 73 | 74 | In Laravel, you can easy use in "form request". Just need to add `tw_id` rule to the `rules` method: 75 | 76 | ```php 77 | public function rules() 78 | { 79 | return [ 80 | 'id_number' => 'tw_id' 81 | ]; 82 | } 83 | ``` 84 | 85 | ## License 86 | 87 | The MIT License (MIT). Please see [License File](https://github.com/thephpleague/skeleton/blob/master/LICENSE.md) for more information. 88 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "meditate/twid", 3 | "description": "Taiwan ID Number validation and maker.", 4 | "type": "package", 5 | "license": "MIT", 6 | "keywords": [ 7 | "taiwan", 8 | "identity card", 9 | "ID number", 10 | "validation", 11 | "laravel", 12 | "laravel-dojo", 13 | "meditate" 14 | ], 15 | "authors": [ 16 | { 17 | "name": "Wei-Cheng Shi", 18 | "email": "tentail10@gmail.com", 19 | "role": "Developer" 20 | } 21 | ], 22 | "require": { 23 | "php": "^7.0|^8.0" 24 | }, 25 | "require-dev": { 26 | "illuminate/support": "^5.3", 27 | "phpunit/phpunit": "^8.5.12", 28 | "squizlabs/php_codesniffer": "^3.3" 29 | }, 30 | "autoload": { 31 | "psr-4": { 32 | "Meditate\\IdentityCard\\": "src/" 33 | } 34 | }, 35 | "autoload-dev": { 36 | "psr-4": { 37 | "Meditate\\IdentityCard\\Tests\\": "tests/" 38 | } 39 | }, 40 | "scripts": { 41 | "test": "phpunit", 42 | "check-style": "phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests", 43 | "fix-style": "phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 src tests" 44 | }, 45 | "config": { 46 | "preferred-install": "dist", 47 | "sort-packages": true, 48 | "optimize-autoloader": true, 49 | "allow-plugins": { 50 | "kylekatarnls/update-helper": false 51 | } 52 | }, 53 | "extra": { 54 | "laravel": { 55 | "providers": [ 56 | "Meditate\\IdentityCard\\IdentityCardServiceProvider" 57 | ] 58 | }, 59 | "branch-alias": { 60 | "dev-master": "1.0-dev" 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /prefill.php: -------------------------------------------------------------------------------- 1 | ['Your name', '', ''], 7 | 'author_github_username' => ['Your Github username', ' in https://github.com/username', ''], 8 | 'author_email' => ['Your email address', '', ''], 9 | 'author_twitter' => ['Your twitter username', '', '@{author_github_username}'], 10 | 'author_website' => ['Your website', '', 'https://github.com/{author_github_username}'], 11 | 'package_vendor' => ['Package vendor', ' in https://github.com/vendor/package', '{author_github_username}'], 12 | 'package_name' => ['Package name', ' in https://github.com/vendor/package', ''], 13 | 'package_description' => ['Package very short description', '', ''], 14 | 'psr4_namespace' => ['PSR-4 namespace', 'usually, Vendor\\Package', '{package_vendor}\\{package_name}'], 15 | ]; 16 | $values = []; 17 | $replacements = [ 18 | ':vendor\\\\:package_name\\\\' => function () use(&$values) { return str_replace('\\', '\\\\', $values['psr4_namespace']) . '\\\\'; }, 19 | ':author_name' => function () use(&$values) { return $values['author_name']; }, 20 | ':author_username' => function () use(&$values) { return $values['author_github_username']; }, 21 | ':author_website' => function () use(&$values) { return $values['author_website'] ?: ('https://github.com/' . $values['author_github_username']); }, 22 | ':author_email' => function () use(&$values) { return $values['author_email'] ?: ($values['author_github_username'] . '@example.com'); }, 23 | ':vendor' => function () use(&$values) { return $values['package_vendor']; }, 24 | ':package_name' => function () use(&$values) { return $values['package_name']; }, 25 | ':package_description' => function () use(&$values) { return $values['package_description']; }, 26 | 'League\\Skeleton' => function () use(&$values) { return $values['psr4_namespace']; }, 27 | ]; 28 | function read_from_console ($prompt) { 29 | if ( function_exists('readline') ) { 30 | $line = trim(readline($prompt)); 31 | if (!empty($line)) { 32 | readline_add_history($line); 33 | } 34 | } else { 35 | echo $prompt; 36 | $line = trim(fgets(STDIN)); 37 | } 38 | return $line; 39 | } 40 | function interpolate($text, $values) 41 | { 42 | if (!preg_match_all('/\{(\w+)\}/', $text, $m)) { 43 | return $text; 44 | } 45 | foreach ($m[0] as $k => $str) { 46 | $f = $m[1][$k]; 47 | $text = str_replace($str, $values[$f], $text); 48 | } 49 | return $text; 50 | } 51 | $modify = 'n'; 52 | do { 53 | if ($modify == 'q') { 54 | exit; 55 | } 56 | $values = []; 57 | echo "----------------------------------------------------------------------\n"; 58 | echo "Please, provide the following information:\n"; 59 | echo "----------------------------------------------------------------------\n"; 60 | foreach ($fields as $f => $field) { 61 | $default = isset($field[COL_DEFAULT]) ? interpolate($field[COL_DEFAULT], $values): ''; 62 | $prompt = sprintf( 63 | '%s%s%s: ', 64 | $field[COL_DESCRIPTION], 65 | $field[COL_HELP] ? ' (' . $field[COL_HELP] . ')': '', 66 | $field[COL_DEFAULT] !== '' ? ' [' . $default . ']': '' 67 | ); 68 | $values[$f] = read_from_console($prompt); 69 | if (empty($values[$f])) { 70 | $values[$f] = $default; 71 | } 72 | } 73 | echo "\n"; 74 | echo "----------------------------------------------------------------------\n"; 75 | echo "Please, check that everything is correct:\n"; 76 | echo "----------------------------------------------------------------------\n"; 77 | foreach ($fields as $f => $field) { 78 | echo $field[COL_DESCRIPTION] . ": $values[$f]\n"; 79 | } 80 | echo "\n"; 81 | } while (($modify = strtolower(read_from_console('Modify files with these values? [y/N/q] '))) != 'y'); 82 | echo "\n"; 83 | $files = array_merge( 84 | glob(__DIR__ . '/*.md'), 85 | glob(__DIR__ . '/*.xml.dist'), 86 | glob(__DIR__ . '/composer.json'), 87 | glob(__DIR__ . '/src/*.php'), 88 | glob(__DIR__ . '/tests/*.php') 89 | ); 90 | foreach ($files as $f) { 91 | $contents = file_get_contents($f); 92 | foreach ($replacements as $str => $func) { 93 | $contents = str_replace($str, $func(), $contents); 94 | } 95 | file_put_contents($f, $contents); 96 | } 97 | echo "Done.\n"; 98 | echo "Now you should remove the file '" . basename(__FILE__) . "'.\n"; 99 | -------------------------------------------------------------------------------- /src/Facades/TaiwanIdentityCard.php: -------------------------------------------------------------------------------- 1 | app->singleton(TaiwanIdentityCard::class, function () { 29 | return new TaiwanIdentityCard; 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/IdentityCardValidator.php: -------------------------------------------------------------------------------- 1 | check($value ?? ''); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/TaiwanIdentityCard.php: -------------------------------------------------------------------------------- 1 | 1, 'B' => 10, 'C' => 19, 'D' => 28, 'E' => 37, 'F' => 46, 'G' => 55, 14 | 'H' => 64, 'I' => 39, 'J' => 73, 'K' => 82, 'L' => 2, 'M' => 11, 'N' => 20, 15 | 'O' => 48, 'P' => 29, 'Q' => 38, 'R' => 47, 'S' => 56, 'T' => 65, 'U' => 74, 16 | 'V' => 83, 'W' => 21, 'X' => 3, 'Y' => 12, 'Z' => 30 17 | ]; 18 | 19 | /** 20 | * The weights which the every numbers represents. 21 | * 22 | * @var array 23 | */ 24 | protected $weights = [8, 7, 6, 5, 4, 3, 2, 1, 1]; 25 | 26 | /** 27 | * Validate ID number. 28 | * 29 | * @param string $id_number 30 | * @return boolean 31 | */ 32 | public function check(string $id_number = '') 33 | { 34 | if (!$this->checkIdNumberFormat($id_number)) { 35 | return false; 36 | } 37 | 38 | $id_number_chars = str_split($id_number); 39 | 40 | if (!in_array($id_number_chars[1], [1, 2, 8, 9])) { 41 | return false; 42 | } 43 | 44 | $count = $this->locations[$id_number_chars[0]]; 45 | foreach ($this->weights as $i => $weight) { 46 | $count += $id_number_chars[$i + 1] * $weight; 47 | } 48 | 49 | return ($count % 10 === 0) ? true : false; 50 | } 51 | 52 | /** 53 | * Make a fake ID number. 54 | * 55 | * @param string|null $location 56 | * @param integer|null $gender 57 | * @return string 58 | */ 59 | public function make($location = null, $gender = null) 60 | { 61 | if (is_null($location)) { 62 | $location = array_rand($this->locations); 63 | } elseif (!(is_string($location) && array_key_exists($location, $this->locations))) { 64 | throw new \Exception("Argument 1 must be of the char 'A' to 'Z'", 1); 65 | } 66 | 67 | if (is_null($gender)) { 68 | $gender = random_int(1, 2); 69 | } elseif (!(is_int($gender) && in_array($gender, [1, 2, 8, 9]))) { 70 | throw new \Exception("Argument 2 must be of the integer 1, 2, 8 or 9", 1); 71 | } 72 | 73 | $fake_id_number = $location . $gender . random_int(1000000, 9999999); 74 | 75 | $id_number_chars = str_split($fake_id_number); 76 | 77 | $count = $this->locations[$id_number_chars[0]]; 78 | foreach ($this->weights as $i => $weight) { 79 | if ($i == 8) { 80 | break; 81 | } 82 | $count += $id_number_chars[$i + 1] * $weight; 83 | } 84 | 85 | $fake_id_number .= ($count % 10 == 0) ? 0 : (10 - ($count % 10)); 86 | 87 | return $fake_id_number; 88 | } 89 | 90 | /** 91 | * Check ID number format. 92 | * 93 | * @param string $id_number 94 | * @return boolean 95 | */ 96 | private function checkIdNumberFormat($id_number) 97 | { 98 | return (preg_match('/(^[A-Z][0-9]{9})/u', $id_number) === 1) ? true : false; 99 | } 100 | } 101 | --------------------------------------------------------------------------------