From 9f5782e0bae17d2d88f60e1c652744b274aaadb2 Mon Sep 17 00:00:00 2001 From: jekkos Date: Sun, 13 Dec 2015 15:45:45 +0100 Subject: [PATCH] Add validation for barcode types (#111, #246) Fallback to code128 if invalid EAN8 or EAN13 is detected --- application/libraries/Barcode_lib.php | 49 +++++++++--- application/views/barcodes/BarcodeBase.php | 11 ++- application/views/barcodes/Ean13.php | 68 ++++++++++------- application/views/barcodes/Ean8.php | 86 +++++++--------------- 4 files changed, 112 insertions(+), 102 deletions(-) diff --git a/application/libraries/Barcode_lib.php b/application/libraries/Barcode_lib.php index 2213ecade..e0e5dcacc 100644 --- a/application/libraries/Barcode_lib.php +++ b/application/libraries/Barcode_lib.php @@ -70,9 +70,24 @@ class Barcode_lib try { $barcode = $this->get_barcode_instance($barcode_config['barcode_type']); + $is_valid = $barcode->validate($item['item_number']); + + // if barcdoe validation does not succeed, then fallback to the default, which should not require specific formatting + if (!$is_valid) + { + $barcode = $this->get_barcode_instance(); + } $barcode_content = $barcode_config['barcode_content'] !== "id" && isset($item['item_number']) ? $item['item_number'] : $item['item_id']; $barcode->setData($barcode_content); + if( $barcode_config['barcode_content'] !== "id" && isset($item['item_number'])) + { + $barcode->setData($item['item_number']); + } + else + { + $barcode->setData($item['item_id']); + } $barcode->setQuality($barcode_config['barcode_quality']); $barcode->setDimensions($barcode_config['barcode_width'], $barcode_config['barcode_height']); @@ -113,24 +128,34 @@ class Barcode_lib } } - public function get_barcode($item, $barcode_config) + public function get_new_barcode($item, $barcode_config) { try { $barcode = $this->get_barcode_instance($barcode_config['barcode_type']); - - $barcode_content = $barcode_config['barcode_content'] !== "id" && isset($item['item_number']) ? $item['item_number'] : $item['item_id']; - $barcode->setData($barcode_content); - - $code = $barcode->getData(); - - // in case no new code is generated like in Code39 and Code128 return an empty string because we don't want to override it with a pure item_id - if( $code == $item['item_id'] ) + + // generate a barcode only if one is not already available and we use the item_id as seed. + // This to avoid generating Barcodes out of existing Barcodes + if( $barcode_config['barcode_content'] !== "id" && isset($item['item_number']) ) { - $code = null; + $barcode->setData($item['item_number'], false); + + return null; + } + else + { + $barcode->setData($item['item_id'], true); + + $code = $barcode->getData(); + + // in case no new code is generated like in Code39 and Code128 return an empty string because we don't want to override it with a pure item_id + if( $code == $item['item_id'] ) + { + $code = null; + } + + return $code; } - - return $code; } catch(Exception $e) { diff --git a/application/views/barcodes/BarcodeBase.php b/application/views/barcodes/BarcodeBase.php index a9859a4dd..93f7bbc21 100644 --- a/application/views/barcodes/BarcodeBase.php +++ b/application/views/barcodes/BarcodeBase.php @@ -74,7 +74,16 @@ abstract class BarcodeBase { return $this->data; } - + + /** + * Validate the given barcode. + * @param $barcode The barcode to validate + * @return bool true if it complies with the barcode formatting + */ + public function validate($barcode) + { + return TRUE; + } /* * (Abstract) Draw the image * diff --git a/application/views/barcodes/Ean13.php b/application/views/barcodes/Ean13.php index 90fc5438d..9b30f8dd6 100644 --- a/application/views/barcodes/Ean13.php +++ b/application/views/barcodes/Ean13.php @@ -116,42 +116,54 @@ class Ean13 extends BarcodeBase '9' => array('A','B','B','A','B','A') ); - /* - * Generate EAN13 code out of a provided number - * Code taken from http://stackoverflow.com/questions/19890144/generate-valid-ean13-in-php (unknown copyright / license claims) - * - * @param number is the internal code you want to have EANed. The prefix, zero-padding and checksum are added by the function. - * @return string with complete EAN13 code - */ - private function generateEAN($number) - { - $this->data = '200' . str_pad($number, 9, '0'); - $weightflag = true; - $sum = 0; - - // Weight for a digit in the checksum is 3, 1, 3.. starting from the last digit. - // loop backwards to make the loop length-agnostic. The same basic functionality - // will work for codes of different lengths. - for ($i = strlen($this->data) - 1; $i >= 0; $i--) - { - $sum += (int)$this->data[$i] * ($weightflag?3:1); - $weightflag = !$weightflag; - } - $this->data .= (10 - ($sum % 10)) % 10; - - return $this->data; - } - /* * Set the data * * @param mixed data - (int or string) Data to be encoded * @return instance of \emberlabs\Barcode\BarcodeInterface - * @return throws \OverflowException */ public function setData($data) { - $this->data = $this->generateEAN($data); + $this->data = $data; + } + + public function validate($barcode) + { + // check to see if barcode is 13 digits long + if (!preg_match("/^[0-9]{13}$/", $barcode)) { + return false; + } + + $digits = $barcode; + + // 1. Add the values of the digits in the + // even-numbered positions: 2, 4, 6, etc. + $even_sum = $digits[1] + $digits[3] + $digits[5] + + $digits[7] + $digits[9] + $digits[11]; + + // 2. Multiply this result by 3. + $even_sum_three = $even_sum * 3; + + // 3. Add the values of the digits in the + // odd-numbered positions: 1, 3, 5, etc. + $odd_sum = $digits[0] + $digits[2] + $digits[4] + + $digits[6] + $digits[8] + $digits[10]; + + // 4. Sum the results of steps 2 and 3. + $total_sum = $even_sum_three + $odd_sum; + + // 5. The check character is the smallest number which, + // when added to the result in step 4, produces a multiple of 10. + $next_ten = (ceil($total_sum / 10)) * 10; + $check_digit = $next_ten - $total_sum; + + // if the check digit and the last digit of the + // barcode are OK return true; + if ($check_digit == $digits[12]) { + return true; + } + + return false; } /* diff --git a/application/views/barcodes/Ean8.php b/application/views/barcodes/Ean8.php index 2e98da107..c3cdf542c 100644 --- a/application/views/barcodes/Ean8.php +++ b/application/views/barcodes/Ean8.php @@ -89,69 +89,34 @@ class Ean8 extends BarcodeBase ) ); - /* - * Calculate EAN8 or EAN13 automatically - * set $len = 8 for EAN8, $len = 13 for EAN13 - * - * @param number is the internal code you want to have EANed. The prefix, zero-padding and checksum are added by the function. - * @return string with complete EAN code - */ - private function generateEAN($number, $len = 8) + public function validate($barcode) { - $this->data = null; - - if($number > -1) + $ean = str_replace(array("-","/"," ","\t","\n"), "", $barcode); // make a clean ean + $len = strlen($ean); + + if( !is_numeric($ean) ) { - $data_len = $len - 1; - $this->data = $number; - - //Padding - $this->data = str_pad($this->data, $data_len, '0', STR_PAD_LEFT); - $this->data_len = strlen($this->data); - - // calculate check digit - $sum_a = 0; - for ($i = 1; $i < $data_len; $i += 2) - { - $sum_a += $this->data{$i}; - } - - if ($len > 12) - { - $sum_a *= 3; - } - - $sum_b = 0; - for ($i = 0; $i < $data_len; $i += 2) - { - $sum_b += ($this->data{$i}); - } - - if ($len < 13) - { - $sum_b *= 3; - } - - $r = ($sum_a + $sum_b) % 10; - - if($r > 0) - { - $r = (10 - $r); - } - - if ($this->data_len == $data_len) - { - // add check digit - $this->data .= $r; - } - elseif ($r !== intval($this->data{$data_len})) - { - // wrong checkdigit - $this->data = null; - } + return false; } - return $this->data; + $weights = array(3,1,3,1,3,1,3); // weights + $chk = $ean{7}; // 8. digit + + $i = 0; + $sum = 0; + + // sum or weight * digit + foreach($weights as $num) { + + $sum += $num * $ean{$i}; + $i++; + } + + if( (($sum + $chk) % 10) == 0 ) + { + return true; + } + return false; } /* @@ -159,11 +124,10 @@ class Ean8 extends BarcodeBase * * @param mixed data - (int or string) Data to be encoded * @return instance of \emberlabs\Barcode\BarcodeInterface - * @return throws \OverflowException */ public function setData($data) { - $this->data = $this->generateEAN($data); + $this->data = $data; } /*