Updating PHP Barcode Extension for PHP7

Two years ago, I created a sample for demonstrating how to wrap Dynamsoft Barcode Reader 4.2, a C++ barcode library, as an extension for PHP5. How time flies, the latest barcode library is up to version 5.2. Meanwhile, many developers start to write web program in PHP7. This post will help PHP developers figure out how to build a PHP barcode reader on Ubuntu 16.04 with DBR 5.2 and PHP7.

Environment

Ubuntu 16.04

lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 16.04.3 LTS
Release:	16.04
Codename:	xenial

Installation

php7.0-cli, php7.0-dev and libxml2-dev

sudo apt-get install php7.0-cli php7.0-dev libxml2-dev

php-7.0.29 source code

DBR 5.2

  1. Add public key:
    wget -O - http://labs.dynamsoft.com/debian/conf/dbr.gpg.key | sudo apt-key add -
  2. Add source to /etc/apt/sources.list:
    deb http://labs.dynamsoft.com/debian/ dbr main non-free
  3. Install Dynamsoft Barcode Reader:
    sudo apt-get update && install dbr

Creating PHP Barcode Extension Step by Step

Unzip PHP source code and then change directory to ext.

tar -xzf php-7.0.29.tar.gz
cd ~/php-7.0.29/ext/

Create an extension directory.

./ext_skel --extname=dbr

PHP barcode extension

If you follow above guide, it will take time to build the whole project. We can use phpize to just build the extension that we created. Change directory to dbr folder and edit config.m4. What you need to do is to add the paths of the shared library (libDynamsoftBarcodeReader.so) and the header file(DynamsoftBarcodeReader.h).

PHP_ARG_ENABLE(dbr, whether to enable dbr support,
[  --enable-dbr           Enable dbr support])

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

  LIBNAME=DynamsoftBarcodeReader
  LIBSYMBOL=DBR_CreateInstance

  PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL,
  [
  PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, /usr/lib, DBR_SHARED_LIBADD)
  AC_DEFINE(HAVE_DBRLIB,1,[ ])
  ],[
  AC_MSG_ERROR([wrong dbr lib version or lib not found])
  ],[
  -L$DBR_DIR/$PHP_LIBDIR -lm
  ])
  
  PHP_SUBST(DBR_SHARED_LIBADD)
  PHP_ADD_INCLUDE(/opt/dynamsoft/dbr/include)
  PHP_NEW_EXTENSION(dbr, dbr.c, $ext_shared)
fi

Configure and build the extension.

phpize
./configure
make

A shared library dbr.so will be generated under modules folder.

xiao@ubuntu:~/php-7.0.29/ext/dbr$ ls modules
dbr.so

Install extension to /usr/lib/php/20151012/dbr.so.

sudo make install

Add the following line to /etc/php/7.0/cli/php.ini.

extension=dbr.so

Open dbr.c. Create a function DecodeBarcodeFile().

PHP_FUNCTION(DecodeBarcodeFile)
{
    array_init(return_value);
	
    // Get Barcode image path
    char *pFileName;
    long barcodeType = 0;
    size_t iLen;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &pFileName, &iLen, &barcodeType) == FAILURE) {
        RETURN_STRING("Invalid parameters");
    } 

    void* hBarcode = DBR_CreateInstance();
    if (hBarcode)
    {
	DBR_InitLicenseEx(hBarcode, "t0068MgAAAL0RPbQ2oYpnm7QMnz7rxs8rigQLePZ2NF33syCm5HOcdW17XO3YlMzEwfB9J5HrbUfMWIB97szrsUsCtDW1X78=");
	
	int iMaxCount = 0x7FFFFFFF;
	SBarcodeResultArray *pResults = NULL;
	DBR_SetBarcodeFormats(hBarcode, barcodeType);
	DBR_SetMaxBarcodesNumPerPage(hBarcode, iMaxCount);	
	
	// Barcode detection
    	int ret = DBR_DecodeFileEx(hBarcode, pFileName, &pResults);
	
	if (pResults)
	{
	    int count = pResults->iBarcodeCount;
	    SBarcodeResult** ppBarcodes = pResults->ppBarcodes;
	    SBarcodeResult* tmp = NULL;
	    int i = 0;

	    for (; i < count; i++)
	    {
		tmp = ppBarcodes[i];
		zval tmp_array;
		array_init(&tmp_array);
		add_next_index_string(&tmp_array, tmp->pBarcodeFormatString);
		add_next_index_string(&tmp_array, tmp->pBarcodeData);
		add_next_index_zval(return_value, &tmp_array);
	    }
	    DBR_FreeBarcodeResults(&pResults);
	}


	if (hBarcode) {
            DBR_DestroyInstance(hBarcode);
    	}
    }
}

const zend_function_entry dbr_functions[] = {
	PHP_FE(DecodeBarcodeFile,   NULL) 
	PHP_FE_END	/* Must be the last line in dbr_functions[] */
};

Note: when parsing the parameters, the type of string length has to be size_t not int. I remember int is fine in PHP5, but it will fail to get the string value in PHP7. In addition, the way of creating an array is changed as well.

zval tmp_array;
array_init(&tmp_array);

Re-build and re-install the extension.

make
sudo make install

Create a simple PHP barcode reader.

<?php

$filename = "/opt/dynamsoft/dbr/images/AllSupportedBarcodeTypes.tif";
if (file_exists($filename)) {
  echo "Barcode file: $filename \n";
  /*
   * Description:
   * array DecodeBarcodeFile( string $filename , long $type )
   *
   * Returned value:
   * If succeed, it is an array.
   */
  $resultArray = DecodeBarcodeFile($filename, 0x3FF | 0x2000000 | 0x8000000 | 0x4000000);
  if (is_array($resultArray)) {
	$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";
}
?>

Run the script.

php -c /etc/php/7.0/cli/php.ini reader.php

PHP barcode reader

Source Code

https://github.com/dynamsoft-dbr/linux-php-barcode-reader-