How to Make PHP Barcode Reader on Linux

When developing a web barcode reader app in PHP, you can either use some JavaScript barcode libraries to recognize barcode images on client-side or read the barcode images on server-side with some PHP extensions that capable of reading 1D and 2D barcode. In this post, I will demonstrate how to create a PHP barcode reader with DBR (Dynamsoft Barcode Reader for Linux) on Ubuntu 14.04.

How to Make PHP Extension with C Source Code and Shared Library

Install DBR.

To build PHP extension, you need to use the source code. Before download, you have to check which PHP version used:

php –v

Download the corresponding source code of PHP.

Extract the package and change to the ext folder. Here is mine:

cd ~/Downloads/php-5.5.9/ext

Create an extension dbr:

./ext_skel --extname=dbr

Change directory to dbr:

cd dbr

Edit config.m4 to configure the paths of include and library:

PHP_ARG_ENABLE(dbr, whether to enable dbr support,

dnl Make sure that the comment is aligned:

[  --enable-dbr           Enable dbr support])

if test "$PHP_DBR" != "no"; then

  PHP_ADD_LIBRARY_WITH_PATH(DynamsoftBarcodeReaderx64, /home/xiao/Dynamsoft/BarcodeReader4.0/Redist, DBR_SHARED_LIBADD) 

  PHP_ADD_INCLUDE(/home/xiao/Dynamsoft/BarcodeReader4.0/Include)

  PHP_SUBST(DBR_SHARED_LIBADD)

  PHP_NEW_EXTENSION(dbr, dbr.c, $ext_shared)

fi

Edit dbr.c:

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_dbr.h"

#include "If_DBR.h"
#include "BarcodeFormat.h"
#include "BarcodeStructs.h"
#include "ErrorCode.h"
#include <stdbool.h>

/* If you declare any globals in php_dbr.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(dbr)
*/

/* True global resources - no need for thread safety here */
static int le_dbr;

/* {{{ dbr_functions[]
 *
 * Every user visible function must have an entry in dbr_functions[].
 */
const zend_function_entry dbr_functions[] = {
	PHP_FE(DecodeBarcodeFile,	NULL)		/* For testing, remove later. */
	PHP_FE_END	/* Must be the last line in dbr_functions[] */
};
/* }}} */

/* {{{ dbr_module_entry
 */
zend_module_entry dbr_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
	STANDARD_MODULE_HEADER,
#endif
	"dbr",
	dbr_functions,
	PHP_MINIT(dbr),
	PHP_MSHUTDOWN(dbr),
	PHP_RINIT(dbr),		/* Replace with NULL if there's nothing to do at request start */
	PHP_RSHUTDOWN(dbr),	/* Replace with NULL if there's nothing to do at request end */
	PHP_MINFO(dbr),
#if ZEND_MODULE_API_NO >= 20010901
	PHP_DBR_VERSION,
#endif
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_DBR
ZEND_GET_MODULE(dbr)
#endif

/* {{{ PHP_INI
 */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("dbr.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_dbr_globals, dbr_globals)
    STD_PHP_INI_ENTRY("dbr.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_dbr_globals, dbr_globals)
PHP_INI_END()
*/
/* }}} */

/* {{{ php_dbr_init_globals
 */
/* Uncomment this function if you have INI entries
static void php_dbr_init_globals(zend_dbr_globals *dbr_globals)
{
	dbr_globals->global_value = 0;
	dbr_globals->global_string = NULL;
}
*/
/* }}} */

/* {{{ PHP_MINIT_FUNCTION
 */
PHP_MINIT_FUNCTION(dbr)
{
	/* If you have INI entries, uncomment these lines 
	REGISTER_INI_ENTRIES();
	*/
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(dbr)
{
	/* uncomment this line if you have INI entries
	UNREGISTER_INI_ENTRIES();
	*/
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(dbr)
{
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(dbr)
{
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(dbr)
{
	php_info_print_table_start();
	php_info_print_table_header(2, "dbr support", "enabled");
	php_info_print_table_end();

	/* Remove comments if you have entries in php.ini
	DISPLAY_INI_ENTRIES();
	*/
}
/* }}} */

// Barcode format
const char * GetFormatStr(__int64 format)
{
	if (format == CODE_39)
		return "CODE_39";
	if (format == CODE_128)
		return "CODE_128";
	if (format == CODE_93)
		return "CODE_93";
	if (format == CODABAR)
		return "CODABAR";
	if (format == ITF)
		return "ITF";
	if (format == UPC_A)
		return "UPC_A";
	if (format == UPC_E)
		return "UPC_E";
	if (format == EAN_13)
		return "EAN_13";
	if (format == EAN_8)
		return "EAN_8";
	if (format == INDUSTRIAL_25)
		return "INDUSTRIAL_25";
	if (format == QR_CODE)
		return "QR_CODE";
	if (format == PDF417)
		return "PDF417";
	if (format == DATAMATRIX)
		return "DATAMATRIX";

	return "UNKNOWN";
}

PHP_FUNCTION(DecodeBarcodeFile)
{
	array_init(return_value);

	// Get Barcode image path
	char* pFileName = NULL;
	int barcodeType = 0;
	int iLen = 0;

	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &pFileName, &iLen, &barcodeType) == FAILURE) {
        RETURN_STRING("Invalid parameters", true);
    }
	
	// Dynamsoft Barcode Reader: init
	__int64 llFormat = barcodeType > 0 ? barcodeType : (OneD | QR_CODE | PDF417 | DATAMATRIX);
	int iMaxCount = 0x7FFFFFFF;
	int iIndex = 0;
	ReaderOptions ro = {0};
	pBarcodeResultArray pResults = NULL;
	int iRet = -1;
	char * pszTemp = NULL;

	// Initialize license
	iRet = DBR_InitLicense("84D34246FC1BC4BDD4078D71FCB5A3AA");
	printf("DBR_InitLicense ret: %d\n", iRet);
	ro.llBarcodeFormat = llFormat;
	ro.iMaxBarcodesNumPerPage = iMaxCount;

	// Decode barcode image
	int ret = DBR_DecodeFile(pFileName, &ro, &pResults);
	if (ret == DBR_OK)
	{
		int count = pResults->iBarcodeCount;
		pBarcodeResult* ppBarcodes = pResults->ppBarcodes;
		pBarcodeResult tmp = NULL;
		char result[2048] = {0};
		int i = 0;
		if (count == 0)
		{
			add_next_index_string(return_value, "No Barcode detected", true);
		}

		// loop all results
		for (; i < count; i++)
		{
			char barcodeResult[1024];

			// A barcode result.
			tmp = ppBarcodes[i];
			{
				// Working with PHP array: http://php.net/manual/en/internals2.variables.arrays.php
				zval *tmp_array;
				// Initialize zval
				MAKE_STD_ZVAL(tmp_array);
				array_init(tmp_array);
				// Add format & value to an array
				add_next_index_string(tmp_array, GetFormatStr(tmp->llFormat), true);
				add_next_index_string(tmp_array, tmp->pBarcodeData, true);
				// Add result to returned array
				add_next_index_zval(return_value, tmp_array);
			}
		}

		// Dynamsoft Barcode Reader: release memory
		DBR_FreeBarcodeResults(&pResults);
	}
	else
	{
		add_next_index_string(return_value, "No Barcode detected", true);
	}

}

To build PHP extension independently, you need to use phpize, which is a shell script to prepare PHP extension for compiling. Install the dev package as follows:

sudo apt-get install php5-dev

Build the extension with following commands:

phpize
./configure
make

C90 does not support the boolean data type. If you see the error “unknown type name ‘bool'”, please include the header file:

#include <stdbool.h>

A shared library dbr.so is generated under folder modules:

php extension generated

Simple PHP Barcode Reader

Create reader.php:

<?php
$filename = "/home/xiao/Dynamsoft/BarcodeReader4.0/Images/AllSupportedBarcodeTypes.tif";
if (file_exists($filename)) {
  echo "Barcode file: $filename \n";
  $resultArray = DecodeBarcodeFile($filename, 0);
  if (is_array($resultArray[0])) {
	$resultCount = count($resultArray);
	echo "Total count: $resultCount\n";
	for($i = 0; $i < $resultCount ; $i++) {
		$result = $resultArray[$i];
        	echo "Barcode format: $result[0], value: $result[1]\n";
	}
  }
  else {
    echo "$resultArray[0]";
  }
} else {
    echo "The file $filename does not exist";
}
?>

Install the PHP Barcode extension:

sudo make install

To load the custom extension, you have to add the library path (e.g. /usr/lib/php5/20121212/dbr.so ) into php.ini:

locate php.ini

php.ini path

You may ask which php.ini file should be used? The answer is that you can modify any php.ini file or make it yourself. When executing PHP script, you can designate the php.ini file. I picked php.ini-production and then added the following line:

extension=/usr/lib/php5/20121212/dbr.so

Test the simple PHP barcode reader:

php -c /usr/share/php5/php.ini-production reader.php

linux php barcode reader

Source Code

https://github.com/dynamsoftlabs/linux-php-barcode-reader-