How to Build PHP Barcode QR Code Reading Extension on Windows and Linux
Tags: php, qrcode, barcode, extension
Published: 2022-08-03 08:05:19

When using PHP, you may need to integrate a few C++ libraries sometimes. This article guides you through the process of building a PHP Barcode QR code reading extension with Dynamsoft C++ Barcode SDK on Windows and Linux.


## Download

- PHP on Windows
	- [php-sdk-binary-tools](https://github.com/php/php-sdk-binary-tools)

		Contains some build-required binaries for Windows, such as `bison` and `re2c`.

	- [PHP 7.4 source code](https://windows.php.net/downloads/releases/php-7.4.30-src.zip)
	
		You can build the extension statically with the source code.

	- [PHP 7.4](https://windows.php.net/downloads/releases/php-7.4.30-nts-Win32-vc15-x64.zip)
	
		The pre-built PHP 7.4 for Windows.

	- [Development package (SDK to develop PHP extensions)](https://windows.php.net/downloads/releases/php-devel-pack-7.4.30-nts-Win32-vc15-x64.zip)
		
		Contains `phpize`, which is used to build PHP extensions with pre-built binaries.

- PHP on Linux

	```bash
	php7.4-dev php7.4 libxml2-dev
	```

- [Dynamsoft C++ Barcode Reader v9.2](https://www.dynamsoft.com/barcode-reader/downloads)

	The C++ barcode SDK contains shared libraries for Windows and Linux.

## Visual C++ Compiler

According to the [PHP online tutorial](https://wiki.php.net/internals/windows/stepbystepbuild_sdk_2), the supported Visual C++ compilers are as follows:

```bash
Visual C++ 14.0 (Visual Studio 2015) for PHP 7.0 or PHP 7.1.
Visual C++ 15.0 (Visual Studio 2017) for PHP 7.2, PHP 7.3 or PHP 7.4.
Visual C++ 16.0 (Visual Studio 2019) for master.
```

If you only have `Visual Studio 2022` on Windows, you must install the corresponding Visual C++ build tools by `Visual Studio Installer`.

![visual studio build tools](https://www.dynamsoft.com/codepool/img/2022/08/msvc-install.png)

Afterwards, find and run the `vcvars64.bat` file to set the environment variables.

![visual c++ environment varaibles](https://www.dynamsoft.com/codepool/img/2022/08/vcvars64.png)

**For example**

Here we use PHP 7.4, so we should run `Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat` via `cmd.exe`.

**Note: It is important to use the matching Visual C++ compiler version. Otherwise, the generated extension cannot be loaded by PHP.**

## Create PHP Barcode QR Code Extension Project
We scaffold a PHP extension project with the following commands:

```bash
cd php-7.4.30-src/ext
php ext_skel.php --ext dbr
cd dbr
```

Then copy `DynamsoftCommon.h`, `DynamsoftBarcodeReader.h` and `DBRx64.lib` to the project directory. 

In `dbr.c`, we implement the extension functions `DBRInitLicense()` and `DecodeBarcodeFile()`.

```c
#include "DynamsoftBarcodeReader.h"

static void *hBarcode = NULL;

#define CHECK_DBR() 										\
if (!hBarcode) 												\
{															\
	hBarcode = DBR_CreateInstance();						\
	const char* versionInfo = DBR_GetVersion();				\
	printf("Dynamsoft Barcode Reader %s\n", versionInfo);	\
}


PHP_FUNCTION(DBRInitLicense)
{
	CHECK_DBR();

	char *pszLicense;
	size_t iLen;
	
	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &pszLicense, &iLen) == FAILURE)
	{
		RETURN_STRING("Invalid parameters");
	}
	char errorMsgBuffer[512];
	// Click https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr to get a trial license.
	DBR_InitLicense(pszLicense, errorMsgBuffer, 512);
	printf("DBR_InitLicense: %s\n", errorMsgBuffer);
}

PHP_FUNCTION(DecodeBarcodeFile)
{
	CHECK_DBR();

	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");
	}

	if (hBarcode)
	{
		int iMaxCount = 0x7FFFFFFF;
		TextResultArray *pResults = NULL;

		// Update DBR params
		PublicRuntimeSettings pSettings = {0};
		DBR_GetRuntimeSettings(hBarcode, &pSettings);
		pSettings.barcodeFormatIds = barcodeType;
		char szErrorMsgBuffer[256];
		DBR_UpdateRuntimeSettings(hBarcode, &pSettings, szErrorMsgBuffer, 256);

		// Barcode detection
		int ret = DBR_DecodeFile(hBarcode, pFileName, "");
		DBR_GetAllTextResults(hBarcode, &pResults);
		if (pResults)
		{
			int count = pResults->resultsCount;
			int i = 0;
			char strLocalization[128];
			for (; i < count; i++)
			{
				zval tmp_array;
				array_init(&tmp_array);
				add_next_index_string(&tmp_array, pResults->results[i]->barcodeFormatString);
				add_next_index_string(&tmp_array, pResults->results[i]->barcodeText);
				add_next_index_stringl(&tmp_array, pResults->results[i]->barcodeBytes, pResults->results[i]->barcodeBytesLength);

				memset(strLocalization, 0, 128);
				sprintf(strLocalization, "[(%d,%d),(%d,%d),(%d,%d),(%d,%d)]", \
				pResults->results[i]->localizationResult->x1, pResults->results[i]->localizationResult->y1, \
				pResults->results[i]->localizationResult->x2, pResults->results[i]->localizationResult->y2, \
				pResults->results[i]->localizationResult->x3, pResults->results[i]->localizationResult->y3, \
				pResults->results[i]->localizationResult->x4, pResults->results[i]->localizationResult->y4); 
				add_next_index_string(&tmp_array, strLocalization);

				add_next_index_zval(return_value, &tmp_array);
			}
			DBR_FreeTextResults(&pResults);
		}
	}
}

static const zend_function_entry dbr_functions[] = {
	PHP_FE(DBRInitLicense, NULL)
	PHP_FE(DecodeBarcodeFile, NULL)
	PHP_FE_END
};
```

### config.w32 for Windows

To link `DBRx64.lib`, we specify `LDFLAGS` with [linker options](https://docs.microsoft.com/en-us/cpp/build/reference/libpath-additional-libpath?view=msvc-170) in `config.w32` file.

```bash
ARG_ENABLE('dbr', 'dbr support', 'no');

if (PHP_DBR != 'no') {
	lib_path = "ext\\dbr";

	ADD_FLAG("LDFLAGS", '/libpath:"' + lib_path + '" /DYNAMICBASE "DBRx64.lib"');

	AC_DEFINE('HAVE_DBR', 1, 'dbr support enabled');

	EXTENSION('dbr', 'dbr.c', null, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1');
}
```

### config.m4 for Linux
To link shared libraries on Linux, we edit the `config.m4` file.

```bash
PHP_ARG_ENABLE([dbr],
  [whether to enable dbr support],
  [AS_HELP_STRING([--enable-dbr],
    [Enable dbr support])],
  [no])

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)

  AC_DEFINE(HAVE_DBR, 1, [ Have dbr support ])

  PHP_NEW_EXTENSION(dbr, dbr.c, $ext_shared)
fi
```

Then copy `libDynamicPdf.so`, `libDynamsoftBarcodeReader.so`, `libDynamsoftLicenseClient.so` to the `/usr/bin` directory.

## Steps to Build and Install the PHP Extension
There are two ways to build the extension. One is to use the source code, and the other is to use the pre-built binaries. 

### Build the PHP Extension from Source Code

**Windows**
```bash
cd php-7.4.30-src
buildconf
configure --disable-all --enable-cli --enable-dbr
nmake
```

**Linux**
```bash
cd php-7.4.30-src
./buildconf
./configure --disable-all --enable-cli --enable-dbr
make
```

By default, the extension is statically linked. To build shared libraries, we can modify the line:

```diff
- configure --disable-all --enable-cli --enable-dbr
+ configure --disable-all --enable-cli --enable-dbr=shared
```

### Build the PHP Extension with phpize

**Windows**
```bash
cd php-7.4.30-src/ext/dbr
phpize
configure --enable-dbr
nmake
```

**Linux**
```bash
cd php-7.4.30-src/ext/dbr
phpize
./configure --enable-dbr
make
```

### Install the PHP Extension with *.dll and *.so Files

**Windows**
1. Add `extension=dbr` to `php.ini`.
2. Copy the generated `php_dbr.dll` to the `php/ext/` folder, and copy `DynamicPdfx64.dll`, `DynamsoftBarcodeReaderx64.dll`, `DynamsoftLicenseClientx64.dll` and `vcomp110.dll` to the PHP root directory.

	![install PHP barcode Qr code extension on Windows](https://www.dynamsoft.com/codepool/img/2022/08/php-install-barcode-extension.png)

**Linux**
1. Add `extension=dbr` to `/etc/php/7.4/cli/php.ini`.
2. Run `make install`.

## Test the PHP Barcode QR Code Reader Extension
1. Apply for a [30-day FREE trial license](https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr).
2. Create a PHP script `reader.php` that reads the barcode and QR code from a local image.
	```php
	<?php

	$filename = "AllSupportedBarcodeTypes.tif";
	if (file_exists($filename)) {
		echo "Barcode file: $filename \n";

		// Get license key from https://www.dynamsoft.com/customer/license/trialLicense/?product=dbr
		DBRInitLicense("DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==");

		//Best coverage settings
		DBRInitRuntimeSettingsWithString("{\"ImageParameter\":{\"Name\":\"BestCoverage\",\"DeblurLevel\":9,\"ExpectedBarcodesCount\":512,\"ScaleDownThreshold\":100000,\"LocalizationModes\":[{\"Mode\":\"LM_CONNECTED_BLOCKS\"},{\"Mode\":\"LM_SCAN_DIRECTLY\"},{\"Mode\":\"LM_STATISTICS\"},{\"Mode\":\"LM_LINES\"},{\"Mode\":\"LM_STATISTICS_MARKS\"}],\"GrayscaleTransformationModes\":[{\"Mode\":\"GTM_ORIGINAL\"},{\"Mode\":\"GTM_INVERTED\"}]}}");		

		$resultArray = DecodeBarcodeFile($filename, 0x3FF | 0x2000000 | 0x4000000 | 0x8000000 | 0x10000000); // 1D, PDF417, QRCODE, DataMatrix, Aztec Code

		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], ";
				echo "value: $result[1], ";
				echo "raw: ", bin2hex($result[2]), "\n";
				echo "Localization : ", $result[3], "\n";
			}
		} else {
			echo "$resultArray[0]";
		}
	} else {
		echo "The file $filename does not exist";
	}
	?>

	```

3. Run the PHP script in the terminal.

	```bash
	php reader.php
	```

	![PHP barcode Qr code reader extension](https://www.dynamsoft.com/codepool/img/2022/08/php-barcode-qrcode-reader.png)

## Source Code

[https://github.com/yushulx/php-laravel-barcode-qr-reader/tree/main/ext/dbr](https://github.com/yushulx/php-laravel-barcode-qr-reader/tree/main/ext/dbr)