dolibarr  20.0.0-beta
barcode.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
4  * Copyright (C) 2004-2010 Folke Ashberg: Some lines of code were inspired from work
5  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6  * of Folke Ashberg into PHP-Barcode 0.3pl2, available as GPL
7  * source code at http://www.ashberg.de/bar.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  */
22 
29 /* ******************************************************************** */
30 /* COLORS */
31 /* ******************************************************************** */
32 $bar_color = array(0, 0, 0);
33 $bg_color = array(255, 255, 255);
34 $text_color = array(0, 0, 0);
35 
36 
37 /* ******************************************************************** */
38 /* FONT FILE */
39 /* ******************************************************************** */
40 if (defined('DOL_DEFAULT_TTF_BOLD')) {
41  $font_loc = constant('DOL_DEFAULT_TTF_BOLD');
42 }
43 // Automatic-Detection of Font if running Windows
44 // @CHANGE LDR
45 if (isset($_SERVER['WINDIR']) && @file_exists($_SERVER['WINDIR'])) {
46  $font_loc = $_SERVER['WINDIR'].'\Fonts\arialbd.ttf';
47 }
48 if (empty($font_loc)) {
49  die('DOL_DEFAULT_TTF_BOLD must de defined with full path to a TTF font.');
50 }
51 
52 
53 /* ******************************************************************** */
54 /* GENBARCODE */
55 /* ******************************************************************** */
56 /* location of 'genbarcode'
57  * leave blank if you don't have them :(
58 * genbarcode is needed to render encodings other than EAN-12/EAN-13/ISBN
59 */
60 
61 if (defined('PHP-BARCODE_PATH_COMMAND')) {
62  $genbarcode_loc = constant('PHP-BARCODE_PATH_COMMAND');
63 } else {
64  $genbarcode_loc = '';
65  if (getDolGlobalString('GENBARCODE_LOCATION')) {
66  $genbarcode_loc = getDolGlobalString('GENBARCODE_LOCATION');
67  }
68 }
69 
70 
71 
72 
83 function barcode_print($code, $encoding = "ANY", $scale = 2, $mode = "png", $filebarcode = '')
84 {
85  dol_syslog("barcode.lib.php::barcode_print $code $encoding $scale $mode");
86 
87  $bars = barcode_encode($code, $encoding);
88  if (!$bars || !empty($bars['error'])) {
89  // Return error message instead of array
90  if (empty($bars['error'])) {
91  $error = 'Bad Value '.$code.' for encoding '.$encoding;
92  } else {
93  $error = $bars['error'];
94  }
95  dol_syslog('barcode.lib.php::barcode_print '.$error, LOG_ERR);
96  return $error;
97  }
98  if (!$mode) {
99  $mode = "png";
100  }
101  //if (preg_match("/^(text|txt|plain)$/i",$mode)) print barcode_outtext($bars['text'],$bars['bars']);
102  //elseif (preg_match("/^(html|htm)$/i",$mode)) print barcode_outhtml($bars['text'],$bars['bars'], $scale,0, 0);
103  //else
104 
105  barcode_outimage($bars['text'], $bars['bars'], $scale, $mode, 0, [], $filebarcode);
106 
107  return $bars;
108 }
109 
132 function barcode_encode($code, $encoding)
133 {
134  global $genbarcode_loc;
135 
136  if ((preg_match("/^upc$/i", $encoding))
137  && (preg_match("/^[0-9]{11,12}$/", $code))
138  ) {
139  /* use built-in UPC-Encoder */
140  dol_syslog("barcode.lib.php::barcode_encode Use barcode_encode_upc");
141  $bars = barcode_encode_upc($code, $encoding);
142  } elseif ((preg_match("/^ean$/i", $encoding))
143 
144  || (($encoding) && (preg_match("/^isbn$/i", $encoding))
145  && ((strlen($code) == 9 || strlen($code) == 10) ||
146  (((preg_match("/^978/", $code) && strlen($code) == 12) ||
147  (strlen($code) == 13)))))
148 
149  || ((!isset($encoding) || !$encoding || (preg_match("/^ANY$/i", $encoding)))
150  && (preg_match("/^[0-9]{12,13}$/", $code)))
151  ) {
152  /* use built-in EAN-Encoder */
153  dol_syslog("barcode.lib.php::barcode_encode Use barcode_encode_ean");
154  $bars = barcode_encode_ean($code, $encoding);
155  } elseif (file_exists($genbarcode_loc)) { // For example C39
156  /* use genbarcode */
157  dol_syslog("barcode.lib.php::barcode_encode Use genbarcode ".$genbarcode_loc." code=".$code." encoding=".$encoding);
158  $bars = barcode_encode_genbarcode($code, $encoding);
159  } else {
160  print "barcode_encode needs an external program for encodings other then EAN/ISBN (code=".dol_escape_htmltag($code).", encoding=".dol_escape_htmltag($encoding).")<BR>\n";
161  print "<UL>\n";
162  print "<LI>download gnu-barcode from <A href=\"https://www.gnu.org/software/barcode/\">www.gnu.org/software/barcode/</A>\n";
163  print "<LI>compile and install them\n";
164  print "<LI>specify path the genbarcode in barcode module setup\n";
165  print "</UL>\n";
166  print "<BR>\n";
167  return false;
168  }
169 
170  return $bars;
171 }
172 
173 
180 function barcode_gen_ean_sum($ean)
181 {
182  $even = true;
183  $esum = 0;
184  $osum = 0;
185  $ln = strlen($ean) - 1;
186  for ($i = $ln; $i >= 0; $i--) {
187  if ($even) {
188  $esum += $ean[$i];
189  } else {
190  $osum += $ean[$i];
191  }
192  $even = !$even;
193  }
194  return (10 - ((3 * $esum + $osum) % 10)) % 10;
195 }
196 
197 
204 function barcode_gen_ean_bars($ean)
205 {
206  $digits = array('3211', '2221', '2122', '1411', '1132', '1231', '1114', '1312', '1213', '3112');
207  $mirror = array("000000", "001011", "001101", "001110", "010011", "011001", "011100", "010101", "010110", "011010");
208  $guards = array("9a1a", "1a1a1", "a1a7");
209 
210  $line = $guards[0];
211  for ($i = 1; $i < 13; $i++) {
212  $str = $digits[(int) $ean[$i]];
213  if ($i < 7 && $mirror[(int) $ean[0]][$i - 1] == 1) {
214  $line .= strrev($str);
215  } else {
216  $line .= $str;
217  }
218  if ($i == 6) {
219  $line .= $guards[1];
220  }
221  }
222  $line .= $guards[2];
223 
224  return $line;
225 }
226 
234 function barcode_encode_ean($ean, $encoding = "EAN-13")
235 {
236  $ean = trim($ean);
237  if (preg_match("/[^0-9]/i", $ean)) {
238  return array("error" => "Invalid encoding/code. encoding=".$encoding." code=".$ean." (not a numeric)", "text" => "Invalid encoding/code. encoding=".$encoding." code=".$ean." (not a numeric)");
239  }
240  $encoding = strtoupper($encoding);
241  if ($encoding == "ISBN") {
242  if (!preg_match("/^978/", $ean)) {
243  $ean = "978".$ean;
244  }
245  }
246  if (preg_match("/^97[89]/", $ean)) {
247  $encoding = "ISBN";
248  }
249  if (strlen($ean) < 12 || strlen($ean) > 13) {
250  return array("error" => "Invalid encoding/code. encoding=".$encoding." code=".$ean." (must have 12/13 numbers)", "text" => "Invalid encoding/code. encoding=".$encoding." code=".$ean." (must have 12/13 numbers)");
251  }
252 
253  $ean = substr($ean, 0, 12);
254  $eansum = barcode_gen_ean_sum($ean);
255  $ean .= $eansum;
256  $bars = barcode_gen_ean_bars($ean);
257 
258  /* create text */
259  $pos = 0;
260  $text = "";
261  for ($a = 0; $a < 13; $a++) {
262  if ($a > 0) {
263  $text .= " ";
264  }
265  $text .= $pos.":12:".$ean[$a];
266  if ($a == 0) {
267  $pos += 12;
268  } elseif ($a == 6) {
269  $pos += 12;
270  } else {
271  $pos += 7;
272  }
273  }
274 
275  return array(
276  "error" => '',
277  "encoding" => $encoding,
278  "bars" => $bars,
279  "text" => $text
280  );
281 }
282 
290 function barcode_encode_upc($upc, $encoding = "UPC")
291 {
292  $upc = trim($upc);
293  if (preg_match("/[^0-9]/i", $upc)) {
294  return array("error" => "Invalid encoding/code. encoding=".$encoding." code=".$upc." (not a numeric)", "text" => "Invalid encoding/code. encoding=".$encoding." code=".$upc." (not a numeric)");
295  }
296  $encoding = strtoupper($encoding);
297  if (strlen($upc) < 11 || strlen($upc) > 12) {
298  return array("error" => "Invalid encoding/code. encoding=".$encoding." code=".$upc." (must have 11/12 numbers)", "text" => "Invalid encoding/code. encoding=".$encoding." code=".$upc." (must have 11/12 numbers)");
299  }
300 
301  $upc = substr("0".$upc, 0, 12);
302  $eansum = barcode_gen_ean_sum($upc);
303  $upc .= $eansum;
304  $bars = barcode_gen_ean_bars($upc);
305 
306  /* create text */
307  $pos = 0;
308  $text = "";
309  for ($a = 1; $a < 13; $a++) {
310  if ($a > 1) {
311  $text .= " ";
312  }
313  $text .= $pos.":12:".$upc[$a];
314  if ($a == 1) {
315  $pos += 15;
316  } elseif ($a == 6) {
317  $pos += 17;
318  } elseif ($a == 11) {
319  $pos += 15;
320  } else {
321  $pos += 7;
322  }
323  }
324 
325  return array(
326  "error" => '',
327  "encoding" => $encoding,
328  "bars" => $bars,
329  "text" => $text
330  );
331 }
332 
340 function barcode_encode_genbarcode($code, $encoding)
341 {
342  global $conf, $db, $genbarcode_loc;
343 
344  // Clean parameters
345  if (preg_match("/^ean$/i", $encoding) && strlen($code) == 13) {
346  $code = substr($code, 0, 12);
347  }
348  if (!$encoding) {
349  $encoding = "ANY";
350  }
351  $encoding = dol_string_nospecial($encoding, '_');
352  $code = dol_string_nospecial($code, "_");
353 
354  $command = escapeshellarg($genbarcode_loc);
355  $paramclear = " ".escapeshellarg($code)." ".escapeshellarg(strtoupper($encoding));
356 
357  $fullcommandclear = $command." ".$paramclear." 2>&1";
358  //print $fullcommandclear."<br>\n";exit;
359 
360  dol_syslog("Run command ".$fullcommandclear);
361 
362  $outputfile = $conf->user->dir_temp.'/genbarcode.tmp'; // File used with popen method
363 
364  // Execute a CLI
365  include_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php';
366  $utils = new Utils($db);
367  $result = $utils->executeCLI($fullcommandclear, $outputfile);
368 
369  if (!empty($result['output'])) {
370  $tmparr = explode("\n", $result['output']);
371  $bars = $tmparr[0];
372  $text = $tmparr[1];
373  $encoding = $tmparr[2];
374  } else {
375  dol_syslog("barcode.lib.php::barcode_encode_genbarcode failed to run ".$fullcommandclear, LOG_ERR);
376  return false;
377  }
378 
379  //var_dump($bars);
380  $ret = array(
381  "bars" => trim($bars),
382  "text" => trim($text),
383  "encoding" => trim($encoding),
384  "error" => ""
385  );
386  //var_dump($ret);
387  if (preg_match('/permission denied/i', $ret['bars'])) {
388  $ret['error'] = $ret['bars'];
389  $ret['bars'] = '';
390  return $ret;
391  }
392  if (!$ret['bars']) {
393  return false;
394  }
395  if (!$ret['text']) {
396  return false;
397  }
398  if (!$ret['encoding']) {
399  return false;
400  }
401  return $ret;
402 }
403 
416 function barcode_outimage($text, $bars, $scale = 1, $mode = "png", $total_y = 0, $space = [], $filebarcode = '')
417 {
418  global $bar_color, $bg_color, $text_color, $font_loc;
419 
420  //print "$text, $bars, $scale, $mode, $total_y, $space, $font_loc, $filebarcode<br>";
421 
422  /* set defaults */
423  if ($scale < 1) {
424  $scale = 2;
425  }
426  $total_y = (int) $total_y;
427  if ($total_y < 1) {
428  $total_y = (int) $scale * 60;
429  }
430  if (!is_array($space) || empty($space)) {
431  $space = array('top' => 2 * $scale, 'bottom' => 2 * $scale, 'left' => 2 * $scale, 'right' => 2 * $scale);
432  }
433 
434  /* count total width */
435  $xpos = 0;
436  $width = true;
437  $ln = strlen($bars);
438  for ($i = 0; $i < $ln; $i++) {
439  $val = strtolower($bars[$i]);
440  if ($width) {
441  $xpos += (int) $val * $scale;
442  $width = false;
443  continue;
444  }
445  if (preg_match("/[a-z]/", $val)) {
446  /* tall bar */
447  $val = ord($val) - ord('a') + 1;
448  }
449  $xpos += $val * $scale;
450  $width = true;
451  }
452 
453  /* allocate the image */
454  $total_x = ($xpos) + $space['right'] + $space['right'];
455  $xpos = $space['left'];
456  if (!function_exists("imagecreate")) {
457  print "You don't have the gd2 extension enabled<br>\n";
458  return;
459  }
460  $im = imagecreate($total_x, $total_y);
461  /* create two images */
462  $col_bg = imagecolorallocate($im, $bg_color[0], $bg_color[1], $bg_color[2]);
463  $col_bar = imagecolorallocate($im, $bar_color[0], $bar_color[1], $bar_color[2]);
464  $col_text = imagecolorallocate($im, $text_color[0], $text_color[1], $text_color[2]);
465  $height = (int) round($total_y - ($scale * 10));
466  $height2 = (int) round($total_y - $space['bottom']);
467 
468  /* paint the bars */
469  $width = true;
470  $ln = strlen($bars);
471  for ($i = 0; $i < $ln; $i++) {
472  $val = strtolower($bars[$i]);
473  if ($width) {
474  $xpos += (float) $val * $scale;
475  $width = false;
476  continue;
477  }
478  if (preg_match("/[a-z]/", $val)) {
479  /* tall bar */
480  $val = ord($val) - ord('a') + 1;
481  $h = $height2;
482  } else {
483  $h = $height;
484  }
485  imagefilledrectangle($im, $xpos, $space['top'], $xpos + (int) ((float) $val * $scale) - 1, $h, $col_bar);
486  $xpos += $val * $scale;
487  $width = true;
488  }
489 
490  $chars = explode(" ", $text);
491  foreach ($chars as $v) {
492  if (trim($v)) {
493  $inf = explode(":", $v);
494  $fontsize = $scale * ((float) $inf[1] / 1.8);
495  $fontheight = (int) round($total_y - ($fontsize / 2.7) + 2);
496  imagettftext($im, $fontsize, 0, $space['left'] + (int) ($scale * (float) $inf[0]) + 2, $fontheight, $col_text, $font_loc, $inf[2]);
497  }
498  }
499 
500  /* output the image */
501  $mode = strtolower($mode);
502  if (!empty($filebarcode) && (empty($mode) || $mode == 'png')) {
503  // To write into a file onto disk
504  imagepng($im, $filebarcode);
505  } elseif ($mode == 'jpg' || $mode == 'jpeg') {
506  top_httphead('image/jpeg; name="barcode.jpg"');
507  imagejpeg($im);
508  } elseif ($mode == 'gif') {
509  top_httphead('image/gif; name="barcode.gif"');
510  imagegif($im);
511  } elseif ($mode == 'png') {
512  top_httphead('image/png; name="barcode.png"');
513  imagepng($im);
514  }
515 
516  return;
517 }
518 
525 function isAValidEAN13($ean)
526 {
527  $sumEvenIndexes = 0;
528  $sumOddIndexes = 0;
529 
530  $eanAsArray = array_map('intval', str_split($ean));
531 
532  if (!(count($eanAsArray) === 13)) {
533  return false;
534  };
535 
536  $num = (count($eanAsArray) - 1);
537  for ($i = 0; $i < $num; $i++) {
538  if ($i % 2 === 0) {
539  $sumOddIndexes += $eanAsArray[$i];
540  } else {
541  $sumEvenIndexes += $eanAsArray[$i];
542  }
543  }
544 
545  $rest = ($sumOddIndexes + (3 * $sumEvenIndexes)) % 10;
546 
547  if ($rest !== 0) {
548  $rest = 10 - $rest;
549  }
550 
551  return $rest === $eanAsArray[12];
552 }
if(getDolGlobalString('GENBARCODE_LOCATION')) barcode_print($code, $encoding="ANY", $scale=2, $mode="png", $filebarcode='')
Print barcode.
Definition: barcode.lib.php:83
barcode_encode_genbarcode($code, $encoding)
Encode result of genbarcode command.
barcode_gen_ean_sum($ean)
Calculate EAN sum.
barcode_encode_upc($upc, $encoding="UPC")
Encode UPC.
barcode_outimage($text, $bars, $scale=1, $mode="png", $total_y=0, $space=[], $filebarcode='')
Output image onto standard output, or onto disk if $filebarcode is defined.
barcode_gen_ean_bars($ean)
Generate EAN bars.
barcode_encode_ean($ean, $encoding="EAN-13")
Encode EAN.
isAValidEAN13($ean)
Check if EAN13 code is valid.
barcode_encode($code, $encoding)
Encodes $code with $encoding using genbarcode OR built-in encoder if you don't have genbarcode only E...
Class to manage utility methods.
Definition: utils.class.php:34
dol_string_nospecial($str, $newstr='_', $badcharstoreplace='', $badcharstoremove='', $keepspaces=0)
Clean a string from all punctuation characters to use it as a ref or login.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
if(!defined('NOREQUIREMENU')) if(!empty(GETPOST('seteventmessages', 'alpha'))) if(!function_exists("llxHeader")) top_httphead($contenttype='text/html', $forcenocache=0)
Show HTTP header.
Definition: main.inc.php:1648
div float
Buy price without taxes.
Definition: style.css.php:960