Sunday, January 11, 2015

PCSC sample in PHP5

In PC/SC sample in different languages I "promised" to give the implementation of the same sample program in many different programming languages.


In a previous article "PCSC sample in PHP" I wrote about SCardSCR.

SCardSCR is a project for Windows by Johann Dantant. The project web site is no more available because the domain name do not exist any more.

A user reported the problem to me and asked where the web site was available. I used a web search service to find were the project SCardSCR had been moved but I found a new PHP PC/SC wrapper instead.


PC/SC for PHP is the continuation of SCardSCR by Marco Schuster and Johannes Findeisen and is licensed under the PHP license:
This code is licensed under the terms of the PHP License version 3.01. PCSC-Lite is licensed in a way where it is possible to integrate it native in the PHP environment.

The project is hosted at and is also available at

From the project About section:
This is the only extension for using PC/SC based smart cards with PHP. It is a wrapper to the wonderful and free project PCSC-Lite which is the middleware to access a smart card using SCard API (PC/SC). Since PCSC-Lite is compatible to the winscard API it should be possible to compile this extension using a Windows(R) operating system. Currently I only take focus on Linux environments.

Thanks are going to Johann Dantant! He provides a PC/SC extension for PHP since 2005 and I reused some of his code. He allowed me to relicense these parts under the terms of the PHP license so I could integrate PCSC-Lite natively into PHP. You find his work here.
Latest version is 0.3 released 2014-04-23

Since the project is hosted inside the PECL (PHP Extension Community Library) I guess/hope the "PC/SC for PHP" project will not disapear soon. From
PECL is a repository for PHP Extensions, providing a directory of all known extensions and hosting facilities for downloading and development of PHP extensions.


The API is documented at PC/SC for PHP - An extension for PHP using the winscard PC/SC API.

I note some missing PC/SC features:


I had to patch the code to add support of T=0 cards.
Index: pcsc.c
--- pcsc.c (révision 335717)
+++ pcsc.c (copie de travail)
@@ -590,7 +590,7 @@ PHP_FUNCTION(scard_list_readers)
    Return a handle to the card */
-  DWORD dwPreferredProtocol = SCARD_PROTOCOL_T1; 
+  DWORD dwPreferredProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; 
   DWORD dwCurrentProtocol;
   SCARDHANDLE hCard = 0;
   LONG rc = 0;


The installation on Debian is quiet easy.

I had to install the Debian packages:
  • php-pear to get the pecl(1) command
  • php5-dev to get the phpize(1) command (prepare a PHP extension for compiling)

$ sudo pecl install pcsc-alpha
downloading pcsc-0.3.tgz ...
Starting to download pcsc-0.3.tgz (8,939 bytes)
.....done: 8,939 bytes
4 source files, building
running: phpize
Configuring for:
PHP Api Version:         20131106
Zend Module Api No:      20131226
Zend Extension Api No:   220131226
building in /tmp/pear/temp/pear-build-rootMiAGhV/pcsc-0.3
running: /tmp/pear/temp/pcsc/configure
checking for grep that handles long lines and -e... /bin/grep
checking for egrep... /bin/grep -E
checking for a sed that does not truncate output... /bin/sed


libtool: finish: PATH="/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/sbin" ldconfig -n /tmp/pear/temp/pear-build-rootMiAGhV/pcsc-0.3/modules
Libraries have been installed in:

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR'
flag during linking and do at least one of the following:
   - add LIBDIR to the `LD_LIBRARY_PATH' environment variable
     during execution
   - add LIBDIR to the `LD_RUN_PATH' environment variable
     during linking
   - use the `-Wl,-rpath -Wl,LIBDIR' linker flag
   - have your system administrator add LIBDIR to `/etc/'

See any operating system documentation about shared libraries for
more information, such as the ld(1) and manual pages.

Build complete.
Don't forget to run 'make test'.

running: make INSTALL_ROOT="/tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3" install
Installing shared extensions:     /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/lib/php5/20131226/
Installing header files:          /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/include/php5/
running: find "/tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3" | xargs ls -dils
305074  4 drwxr-xr-x 3 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3
305078  4 drwxr-xr-x 4 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr
305082  4 drwxr-xr-x 3 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/include
305083  4 drwxr-xr-x 2 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/include/php5
276538  4 -rw-r--r-- 1 root root  1238 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/include/php5/php_pcsc.h
305079  4 drwxr-xr-x 3 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/lib
305080  4 drwxr-xr-x 3 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/lib/php5
305081  4 drwxr-xr-x 2 root root  4096 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/lib/php5/20131226
276304 60 -rwxr-xr-x 1 root root 60896 janv. 11 14:21 /tmp/pear/temp/pear-build-rootMiAGhV/install-pcsc-0.3/usr/lib/php5/20131226/

Build process completed successfully
Installing '/usr/lib/php5/20131226/'
Installing '/usr/include/php5/php_pcsc.h'
install ok: channel://
configuration option "php_ini" is not set to php.ini location
You should add "" to php.ini

I had to edit the file /etc/php5/cli/php.ini to change the enable_dl definition:
; Whether or not to enable the dl() function.  The dl() function
; does NOT work properly in multithreaded servers, such as IIS or Zeus,
; and is automatically disabled on them.
;enable_dl = Off
enable_dl = On

Source code


if (!extension_loaded('pcsc')) {

# Get a PC/SC context
$context = scard_establish_context();

# Get the reader list
$readers = scard_list_readers($context);

# Use the first reader
$reader = $readers[0];
echo "Using reader: ", $reader, "\n";

# Connect to the card
$connection = scard_connect($context, $reader);

# Select Applet APDU
$CMD = "00A404000AA00000006203010C0601";
$res = scard_transmit($connection, $CMD);

# test APDU
$CMD = "00000000";
$res = scard_transmit($connection, $CMD);
echo pack("H*", $res), "\n";

# Release the PC/SC context



$ php sample.php 
Using reader: Gemalto PC Twin Reader 00 00
string(4) "9000"
string(28) "48656C6C6F20776F726C64219000"
Hello world!�


I have only tested the wrapper using the command line php5 program. I guess the wrapper should also be available from a PHP script in a HTML page hosted by a web server. In that case the PC/SC commands are executed on the server. I don't know what it can be used for. In general you want to use the smart card on the client side.

Happy hacking with this PHP PC/SC wrapper.