dolibarr 21.0.0-alpha
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/* ******************************************************************** */
40if (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
45if (isset($_SERVER['WINDIR']) && @file_exists($_SERVER['WINDIR'])) {
46 $font_loc = $_SERVER['WINDIR'].'\Fonts\arialbd.ttf';
47}
48if (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
61if (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
83function 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
132function 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
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
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
234function 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
290function 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
340function 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
416function 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
525function 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.
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.
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 a 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.