├── .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 |
--------------------------------------------------------------------------------