├── .gitignore ├── src ├── CRC16USB.php ├── CRCInterface.php ├── CRC1.php ├── AbstractCRC.php ├── CRC16QT.php ├── CRC16XModem.php ├── CRC16ZModem.php ├── CRC16Modbus.php ├── CRC16CCITT.php ├── CRC16DNP.php └── CRC16.php ├── tests ├── bootstrap.php └── CRCSuiteTest.php ├── phpunit.xml.dist ├── composer.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | nbproject/ 2 | vendor/ 3 | composer.lock 4 | -------------------------------------------------------------------------------- /src/CRC16USB.php: -------------------------------------------------------------------------------- 1 | wget http://getcomposer.org/composer.phar\n> php composer.phar install\n"); 5 | } 6 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests/ 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/CRC1.php: -------------------------------------------------------------------------------- 1 | checksum = ($this->checksum + ord($data[$i])) % 256; 15 | } 16 | } 17 | 18 | public function pack($checksum) 19 | { 20 | return pack('C', $checksum); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mermshaus/crc", 3 | "description": "Calculates CRC checksums for input data.", 4 | "keywords": [ 5 | "crc" 6 | ], 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Marc Ermshaus", 11 | "email": "marc@ermshaus.org", 12 | "homepage": "http://www.ermshaus.org/", 13 | "role": "Developer" 14 | } 15 | ], 16 | "autoload": { 17 | "psr-4": { 18 | "mermshaus\\CRC\\": "src", 19 | "mermshaus\\CRC\\Tests\\": "tests" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/AbstractCRC.php: -------------------------------------------------------------------------------- 1 | reset(); 31 | } 32 | 33 | public function finish() 34 | { 35 | return $this->pack($this->getChecksum()); 36 | } 37 | 38 | public function reset() 39 | { 40 | $this->checksum = $this->initChecksum; 41 | } 42 | 43 | /** 44 | * 45 | * @internal 46 | */ 47 | protected function getChecksum() 48 | { 49 | return $this->checksum ^ $this->xorMask; 50 | } 51 | 52 | /** 53 | * 54 | * @internal 55 | */ 56 | abstract protected function pack($checksum); 57 | } 58 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Marc Ermshaus 2 | 3 | Based on Digest CRC 4 | Copyright (c) 2010-2013 Hal Brodigan 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mermshaus/CRC 2 | 3 | This is work in progress. I am not an expert on the topic by any means. Therefore, I have trouble finding and verifying information about common CRC algorithms. I am especially looking for reliable test vectors. 4 | 5 | ## Implemented algorithms 6 | 7 | - CRC1 8 | - CRC16, CRC16-CCITT, CRC16-DNP, CRC16-Modbus, CRC16-QT, CRC16-USB, CRC16-XModem, CRC16-ZModem 9 | 10 | ## Usage example 11 | 12 | ```PHP 13 | update('Hello'); 21 | $crc16ccitt->update(' World!'); 22 | 23 | $checksum = $crc16ccitt->finish(); 24 | 25 | var_dump(bin2hex($checksum)); // string(4) "882a" 26 | ``` 27 | 28 | ## Testing 29 | 30 | ``` bash 31 | $ phpunit 32 | ``` 33 | 34 | ## Credits 35 | 36 | - This library is mostly a port of [Digest CRC](https://github.com/postmodern/digest-crc) for Ruby by Hal Brodigan. 37 | 38 | ## Links 39 | 40 | - [Digest CRC](https://github.com/postmodern/digest-crc). The Ruby library on which this library is based. 41 | - [pycrc](https://github.com/tpircher/pycrc). A tool for generating C code and corresponding lookup tables for diverse CRC algorithms. Used by Digest CRC. 42 | - [CRC calculation](http://www.zorc.breitbandkatze.de/crc.html). An online calculator to generate checksums for arbitrary polynomials and input. Recommended by pycrc. 43 | - [On-line CRC calculation and free library](http://www.lammertbies.nl/comm/info/crc-calculation.html). Another online calculator for some CRC algorithms. 44 | - [Catalogue of parametrised CRC algorithms](http://reveng.sourceforge.net/crc-catalogue/). Information about many different CRC algorithms. 45 | -------------------------------------------------------------------------------- /src/CRC16QT.php: -------------------------------------------------------------------------------- 1 | >= 1; 26 | } 27 | 28 | return $ob; 29 | } 30 | 31 | protected function reverseBits($cc) 32 | { 33 | $ob = 0; 34 | $b = (1 << 15); 35 | 36 | for ($i = 0; $i <= 15; $i++) { 37 | if (($cc & $b) !== 0) { 38 | $ob |= (1 << $i); 39 | } 40 | $b >>= 1; 41 | } 42 | 43 | return $ob; 44 | } 45 | 46 | public function update($data) 47 | { 48 | $len = strlen($data); 49 | 50 | for ($i = 0; $i < $len; $i++) { 51 | $byte = ($this->reverseData) 52 | ? $this->reverseByte(ord($data[$i])) 53 | : ord($data[$i]); 54 | 55 | $this->checksum = ($this->lookup[(($this->checksum >> 8) ^ $byte) & 0xff] ^ ($this->checksum << 8)) & 0xffff; 56 | } 57 | } 58 | 59 | protected function getChecksum() 60 | { 61 | $checksum = $this->checksum; 62 | $checksum ^= $this->xorMask; 63 | 64 | if ($this->reverseCRCResult) { 65 | $checksum = $this->reverseBits($checksum); 66 | } 67 | 68 | return $checksum; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/CRC16XModem.php: -------------------------------------------------------------------------------- 1 | checksum = ($this->lookup[(($this->checksum >> 8) ^ ord($data[$i])) & 0xff] ^ ($this->checksum << 8)) & 0xffff; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/CRC16ZModem.php: -------------------------------------------------------------------------------- 1 | checksum = ($this->lookup[(($this->checksum >> 8) ^ ord($data[$i])) & 0xff] ^ ($this->checksum << 8)) & 0xffff; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/CRC16Modbus.php: -------------------------------------------------------------------------------- 1 | checksum = (($this->checksum >> 8) ^ $this->lookup[(ord($data[$i]) ^ $this->checksum) & 0xff]) & 0xffff; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/CRC16CCITT.php: -------------------------------------------------------------------------------- 1 | checksum = ($this->lookup[(($this->checksum >> 8) ^ ord($data[$i])) & 0xff] ^ ($this->checksum << 8)) & 0xffff; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/CRC16DNP.php: -------------------------------------------------------------------------------- 1 | checksum = ($this->checksum >> 8) ^ $this->lookup[($this->checksum ^ ord($data[$i])) & 0xff]; 48 | } 49 | } 50 | 51 | public function finish() 52 | { 53 | return $this->pack(~$this->checksum); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/CRC16.php: -------------------------------------------------------------------------------- 1 | checksum = ($this->lookup[($this->checksum ^ ord($data[$i])) & 0xff] ^ ($this->checksum >> 8)) & 0xffff; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /tests/CRCSuiteTest.php: -------------------------------------------------------------------------------- 1 | > 4) ? dechex($ord) : '0' . dechex($ord)); 35 | } 36 | 37 | return $hex; 38 | } 39 | 40 | /** 41 | * @dataProvider providerAlgorithmsWork 42 | */ 43 | public function testAlgorithmsWork( 44 | CRCInterface $obj, 45 | $data, 46 | $expected 47 | ) { 48 | $chunkSize = 1; 49 | 50 | foreach (str_split($data, $chunkSize) as $byte) { 51 | $obj->update($byte); 52 | } 53 | 54 | $this->assertEquals($expected, $this->strToHex($obj->finish())); 55 | 56 | // Reset and test again 57 | 58 | $obj->reset(); 59 | 60 | foreach (str_split($data, $chunkSize) as $byte) { 61 | $obj->update($byte); 62 | } 63 | 64 | $this->assertEquals($expected, $this->strToHex($obj->finish())); 65 | 66 | // Reset and test again with different $chunkSize 67 | 68 | $obj->reset(); 69 | $chunkSize = 3; 70 | 71 | foreach (str_split($data, $chunkSize) as $byte) { 72 | $obj->update($byte); 73 | } 74 | 75 | $this->assertEquals($expected, $this->strToHex($obj->finish())); 76 | } 77 | 78 | /** 79 | * 80 | * @return array 81 | */ 82 | public function providerAlgorithmsWork() 83 | { 84 | $tests = array(); 85 | 86 | $data = '1234567890'; 87 | 88 | $tests[] = array(new CRC1(), $data, '0d'); 89 | $tests[] = array(new CRC16(), $data, 'c57a'); 90 | $tests[] = array(new CRC16CCITT(), $data, '3218'); 91 | $tests[] = array(new CRC16DNP(), $data, '1bbc'); 92 | $tests[] = array(new CRC16Modbus(), $data, 'c20a'); 93 | $tests[] = array(new CRC16QT(), $data, '4b13'); 94 | $tests[] = array(new CRC16USB(), $data, '3df5'); 95 | $tests[] = array(new CRC16XModem(), $data, 'd321'); 96 | $tests[] = array(new CRC16ZModem(), $data, 'd321'); 97 | 98 | $data = 'test'; 99 | 100 | $tests[] = array(new CRC1(), $data, 'c0'); 101 | $tests[] = array(new CRC16(), $data, 'f82e'); 102 | $tests[] = array(new CRC16CCITT(), $data, '1fc6'); 103 | $tests[] = array(new CRC16DNP(), $data, '75b4'); 104 | $tests[] = array(new CRC16Modbus(), $data, 'dc2e'); 105 | //$tests[] = array(new CRC16QT(), $data, '4b13'); 106 | //$tests[] = array(new CRC16USB(), $data, '3df5'); 107 | $tests[] = array(new CRC16XModem(), $data, '9b06'); 108 | //$tests[] = array(new CRC16ZModem(), $data, 'd321'); 109 | 110 | return $tests; 111 | } 112 | } 113 | --------------------------------------------------------------------------------