mirror of
https://github.com/pcsc-for-php/pcsc.git
synced 2026-08-10 22:02:46 +02:00
Initial commit of the PC/SC (pcsc) extension. There is some stuff that needs to be romoved like the build.sh script and the subfolders tmp/ and php/.
I think the .m4 file has some bugs because it fails to build without my weird build.sh script. I will fix that ASAP. git-svn-id: https://svn.php.net/repository/pecl/pcsc/trunk@320951 c90b9560-bf6c-de11-be94-00142212c4b1
This commit is contained in:
parent
230d4052b2
commit
8db0824d92
11 changed files with 1306 additions and 0 deletions
69
COPYING
Normal file
69
COPYING
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
The PHP License, version 3.01
|
||||||
|
Copyright (c) 1999 - 2010 The PHP Group. All rights reserved.
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, is permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
3. The name "PHP" must not be used to endorse or promote products
|
||||||
|
derived from this software without prior written permission. For
|
||||||
|
written permission, please contact group@php.net.
|
||||||
|
|
||||||
|
4. Products derived from this software may not be called "PHP", nor
|
||||||
|
may "PHP" appear in their name, without prior written permission
|
||||||
|
from group@php.net. You may indicate that your software works in
|
||||||
|
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||||
|
it "PHP Foo" or "phpfoo"
|
||||||
|
|
||||||
|
5. The PHP Group may publish revised and/or new versions of the
|
||||||
|
license from time to time. Each version will be given a
|
||||||
|
distinguishing version number.
|
||||||
|
Once covered code has been published under a particular version
|
||||||
|
of the license, you may always continue to use it under the terms
|
||||||
|
of that version. You may also choose to use such covered code
|
||||||
|
under the terms of any subsequent version of the license
|
||||||
|
published by the PHP Group. No one other than the PHP Group has
|
||||||
|
the right to modify the terms applicable to covered code created
|
||||||
|
under this License.
|
||||||
|
|
||||||
|
6. Redistributions of any form whatsoever must retain the following
|
||||||
|
acknowledgment:
|
||||||
|
"This product includes PHP software, freely available from
|
||||||
|
<http://www.php.net/software/>".
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||||
|
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||||
|
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
This software consists of voluntary contributions made by many
|
||||||
|
individuals on behalf of the PHP Group.
|
||||||
|
|
||||||
|
The PHP Group can be contacted via Email at group@php.net.
|
||||||
|
|
||||||
|
For more information on the PHP Group and the PHP project,
|
||||||
|
please see <http://www.php.net>.
|
||||||
|
|
||||||
|
PHP includes the Zend Engine, freely available at
|
||||||
|
<http://www.zend.com>.
|
||||||
|
|
||||||
2
CREDITS
Normal file
2
CREDITS
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pcsc
|
||||||
|
Johann Dantant, Johannes Findeisen
|
||||||
3
README
Normal file
3
README
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
This is totally unstable! Don't use in production environments!
|
||||||
|
|
||||||
|
You have been warned... ;)
|
||||||
7
TODO
Normal file
7
TODO
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
Some things that need to be done:
|
||||||
|
|
||||||
|
- Find all leaks and fix them
|
||||||
|
- Write all function documentation
|
||||||
|
- Write complete API documentation
|
||||||
|
- ...
|
||||||
|
|
||||||
24
build.sh
Executable file
24
build.sh
Executable file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#echo "Cleaning up ...\n"
|
||||||
|
|
||||||
|
make clean
|
||||||
|
phpize --clean
|
||||||
|
|
||||||
|
#echo "Compile package...\n"
|
||||||
|
|
||||||
|
phpize
|
||||||
|
aclocal
|
||||||
|
libtoolize --force
|
||||||
|
autoheader
|
||||||
|
autoconf
|
||||||
|
|
||||||
|
#echo "Configure package...\n"
|
||||||
|
|
||||||
|
./configure --enable-pcsc --prefix=/usr
|
||||||
|
|
||||||
|
make
|
||||||
|
|
||||||
|
#echo "Now type su and the make install...\n"
|
||||||
|
|
||||||
|
|
||||||
39
config.m4
Normal file
39
config.m4
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
dnl $Id$
|
||||||
|
dnl config.m4 for PC/SC extension
|
||||||
|
|
||||||
|
PHP_ARG_ENABLE(pcsc, PC/SC Smart Card support for PHP,
|
||||||
|
[ --enable-pcsc Enable PC/SC Smart Card support])
|
||||||
|
|
||||||
|
dnl Check whether the extension is enabled at all
|
||||||
|
if test "$PHP_PCSC" != "no"; then
|
||||||
|
if test -r $PHP_PCSC/include/PCSC/winscard.h; then
|
||||||
|
PCSC_DIR=$PHP_PCSC
|
||||||
|
else
|
||||||
|
AC_MSG_CHECKING(for PC/SC in default path)
|
||||||
|
for i in /usr/local /usr; do
|
||||||
|
if test -r $i/include/PCSC/winscard.h; then
|
||||||
|
PCSC_DIR=$i
|
||||||
|
AC_MSG_RESULT(found in $i)
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -z "$PCSC_DIR"; then
|
||||||
|
AC_MSG_RESULT(not found)
|
||||||
|
AC_MSG_ERROR(Please reinstall the pcsc-lite distribution -
|
||||||
|
winscard.h should be in <pcsc-dir>/include/PCSC/)
|
||||||
|
fi
|
||||||
|
AC_MSG_RESULT($PCSC_DIR)
|
||||||
|
AC_MSG_RESULT($PCSC_DIR)
|
||||||
|
AC_MSG_RESULT($PCSC_DIR)
|
||||||
|
PHP_ADD_INCLUDE($PCSC_DIR/include/PCSC/)
|
||||||
|
dnl PHP_EVAL_LIBLINE($PCSC_LIBS, PCSC_SHARED_LIBADD)
|
||||||
|
PHP_ADD_LIBRARY_WITH_PATH(pcsclite, "$PCSC_DIR/lib/", PCSC_SHARED_LIBADD)
|
||||||
|
|
||||||
|
dnl Finally, tell the build system about the extension and what files are needed
|
||||||
|
PHP_NEW_EXTENSION(pcsc, pcsc.c, $ext_shared)
|
||||||
|
PHP_INSTALL_HEADERS([php_pcsc.h])
|
||||||
|
PHP_SUBST(PCSC_SHARED_LIBADD)
|
||||||
|
fi
|
||||||
|
|
||||||
536
pcsc.c
Normal file
536
pcsc.c
Normal file
|
|
@ -0,0 +1,536 @@
|
||||||
|
/*
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| PHP Version 5 |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Copyright (c) 1997-2006 The PHP Group |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| This source file is subject to version 3.01 of the PHP license, |
|
||||||
|
| that is bundled with this package in the file LICENSE, and is |
|
||||||
|
| available through the world-wide-web at the following url: |
|
||||||
|
| http://www.php.net/license/3_01.txt |
|
||||||
|
| If you did not receive a copy of the PHP license and are unable to |
|
||||||
|
| obtain it through the world-wide-web, please send a note to |
|
||||||
|
| license@php.net so we can mail you a copy immediately. |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
| Author: Johannes Findeisen <you@hanez.org> - 2010 |
|
||||||
|
+----------------------------------------------------------------------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "php.h"
|
||||||
|
#include "php_ini.h"
|
||||||
|
#include "ext/standard/info.h"
|
||||||
|
#include "php_pcsc.h"
|
||||||
|
|
||||||
|
#include <PCSC/winscard.h>
|
||||||
|
#include <PCSC/pcsclite.h>
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* {{{ pcsc_functions[]
|
||||||
|
*
|
||||||
|
* Every user visible function must have an entry in pcsc_functions[].
|
||||||
|
*/
|
||||||
|
function_entry pcsc_functions[] = {
|
||||||
|
PHP_FE(scard_establish_context, NULL)
|
||||||
|
PHP_FE(scard_release_context, NULL)
|
||||||
|
PHP_FE(scard_is_valid_context, NULL)
|
||||||
|
PHP_FE(scard_list_readers, NULL)
|
||||||
|
PHP_FE(scard_connect, NULL)
|
||||||
|
//PHP_FE(scard_reconnect, NULL)
|
||||||
|
PHP_FE(scard_disconnect, NULL)
|
||||||
|
PHP_FE(scard_transmit, NULL)
|
||||||
|
PHP_FE(scard_status, NULL)
|
||||||
|
//PHP_FE(scard_cancel, NULL)
|
||||||
|
{NULL, NULL, NULL}
|
||||||
|
};
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ pcsc_module_entry
|
||||||
|
*/
|
||||||
|
zend_module_entry pcsc_module_entry = {
|
||||||
|
#if ZEND_MODULE_API_NO >= 20010901
|
||||||
|
STANDARD_MODULE_HEADER,
|
||||||
|
#endif
|
||||||
|
"PC/SC",
|
||||||
|
pcsc_functions,
|
||||||
|
PHP_MINIT(pcsc),
|
||||||
|
PHP_MSHUTDOWN(pcsc),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
PHP_MINFO(pcsc),
|
||||||
|
#if ZEND_MODULE_API_NO >= 20010901
|
||||||
|
"0.0.1", /* Replace with version number for your extension */
|
||||||
|
#endif
|
||||||
|
STANDARD_MODULE_PROPERTIES
|
||||||
|
};
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
#ifdef COMPILE_DL_PCSC
|
||||||
|
ZEND_GET_MODULE(pcsc)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define REGISTER_PCSC_CONSTANT(__c) REGISTER_LONG_CONSTANT(#__c, __c, CONST_CS | CONST_PERSISTENT)
|
||||||
|
|
||||||
|
/* {{{ PHP_MINIT_FUNCTION
|
||||||
|
*/
|
||||||
|
PHP_MINIT_FUNCTION(pcsc)
|
||||||
|
{
|
||||||
|
/* Return Codes */
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_BAD_SEEK);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_CANCELLED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_CANT_DISPOSE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_CARD_UNSUPPORTED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_CERTIFICATE_UNAVAILABLE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_COMM_DATA_LOST);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_DIR_NOT_FOUND);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_DUPLICATE_READER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_FILE_NOT_FOUND);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_ICC_CREATEORDER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_ICC_INSTALLATION);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INSUFFICIENT_BUFFER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INVALID_ATR);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INVALID_CHV);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INVALID_HANDLE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INVALID_PARAMETER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INVALID_TARGET);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_INVALID_VALUE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_ACCESS);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_DIR);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_FILE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_KEY_CONTAINER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_MEMORY);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_READERS_AVAILABLE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_SERVICE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_SMARTCARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NO_SUCH_CERTIFICATE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NOT_READY);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_NOT_TRANSACTED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_PCI_TOO_SMALL);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_PROTO_MISMATCH);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_READER_UNAVAILABLE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_READER_UNSUPPORTED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_SERVER_TOO_BUSY);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_SERVICE_STOPPED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_SHARING_VIOLATION);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_SYSTEM_CANCELLED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_TIMEOUT);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_UNEXPECTED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_UNKNOWN_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_UNKNOWN_READER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_UNKNOWN_RES_MNG);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_UNSUPPORTED_FEATURE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_E_WRITE_TOO_MANY);
|
||||||
|
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_F_COMM_ERROR);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_F_INTERNAL_ERROR);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_F_UNKNOWN_ERROR);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_F_WAITED_TOO_LONG);
|
||||||
|
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_P_SHUTDOWN);
|
||||||
|
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_S_SUCCESS);
|
||||||
|
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_CANCELLED_BY_USER);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_CARD_NOT_AUTHENTICATED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_CHV_BLOCKED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_EOF);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_REMOVED_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_RESET_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_SECURITY_VIOLATION);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_UNPOWERED_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_UNRESPONSIVE_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_UNSUPPORTED_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_W_WRONG_CHV);
|
||||||
|
|
||||||
|
/* Protocols */
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_PROTOCOL_RAW);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_PROTOCOL_T0);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_PROTOCOL_T1);
|
||||||
|
|
||||||
|
/* Disconnect Modes */
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_EJECT_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_LEAVE_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_RESET_CARD);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_UNPOWER_CARD);
|
||||||
|
|
||||||
|
/* Status codes */
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_ABSENT);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_NEGOTIABLE);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_POWERED);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_PRESENT);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_SPECIFIC);
|
||||||
|
REGISTER_PCSC_CONSTANT(SCARD_SWALLOWED);
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ PHP_MSHUTDOWN_FUNCTION
|
||||||
|
*/
|
||||||
|
PHP_MSHUTDOWN_FUNCTION(pcsc)
|
||||||
|
{
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ PHP_MINFO_FUNCTION
|
||||||
|
*/
|
||||||
|
PHP_MINFO_FUNCTION(pcsc)
|
||||||
|
{
|
||||||
|
php_info_print_table_start();
|
||||||
|
php_info_print_table_header(2, "PC/SC support", "enabled");
|
||||||
|
php_info_print_table_end();
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
static char *e_bytes_to_hex(BYTE *buffer, DWORD length)
|
||||||
|
{
|
||||||
|
DWORD i;
|
||||||
|
char tmp[3];
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
str = emalloc(2 * length + 1);
|
||||||
|
str[0] = '\0';
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
sprintf(tmp, "%02X", buffer[i]);
|
||||||
|
strcat(str, tmp);
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE hex_to_nibble(char chr)
|
||||||
|
{
|
||||||
|
if ((chr >= '0') && (chr <= '9')) {
|
||||||
|
return chr - '0';
|
||||||
|
}
|
||||||
|
if ((chr >= 'A') && (chr <= 'F')) {
|
||||||
|
return chr - 'A' + 10;
|
||||||
|
}
|
||||||
|
if ((chr >= 'a') && (chr <= 'f')) {
|
||||||
|
return chr - 'a' + 10;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE hex_to_byte(char *str)
|
||||||
|
{
|
||||||
|
return hex_to_nibble(str[0]) * 0x10 + hex_to_nibble(str[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE *e_hex_to_bytes(char *str, DWORD *length)
|
||||||
|
{
|
||||||
|
DWORD i, l;
|
||||||
|
BYTE *buf;
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = strlen(str) / 2;
|
||||||
|
if (length != NULL) {
|
||||||
|
*length = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = emalloc(l);
|
||||||
|
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
buf[i] = hex_to_byte(&str[2 * i]);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* {{{ proto array pcsc_establishcontext()
|
||||||
|
Return a a context to the PC/SC layer */
|
||||||
|
PHP_FUNCTION(scard_establish_context)
|
||||||
|
{
|
||||||
|
/* TODO: Make the use of SCARDCONTEXT for the context everywhere instead of LONG */
|
||||||
|
SCARDCONTEXT scard_context = 0;
|
||||||
|
LONG rc = 0;
|
||||||
|
|
||||||
|
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard_context);
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
RETURN_LONG(scard_context);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto boolean scard_is_valid_context(long context)
|
||||||
|
Return a a context to the PC/SC layer */
|
||||||
|
PHP_FUNCTION(scard_is_valid_context)
|
||||||
|
{
|
||||||
|
LONG rc = 0;
|
||||||
|
LONG *context;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &context) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardIsValidContext(context);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto array pcsc_establishcontext(long context)
|
||||||
|
Return a a context to the PC/SC layer */
|
||||||
|
PHP_FUNCTION(scard_release_context)
|
||||||
|
{
|
||||||
|
LONG rc = 0;
|
||||||
|
LONG *context;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &context) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardIsValidContext(context);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardReleaseContext(context);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
RETURN_LONG(context);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto array pcsc_listreaders(long context)
|
||||||
|
Return a an array of available PC/SC readers */
|
||||||
|
PHP_FUNCTION(scard_list_readers)
|
||||||
|
{
|
||||||
|
char *strReaders = NULL;
|
||||||
|
char *ptrReader;
|
||||||
|
DWORD dwLen = SCARD_AUTOALLOCATE;
|
||||||
|
LONG rc = 0;
|
||||||
|
LONG *context;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &context) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardIsValidContext(context);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardListReaders(context, NULL, (char *) &strReaders, &dwLen);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strReaders == NULL) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_init(return_value);
|
||||||
|
|
||||||
|
ptrReader = strReaders;
|
||||||
|
do {
|
||||||
|
add_next_index_string(return_value, ptrReader, TRUE);
|
||||||
|
ptrReader+= strlen(ptrReader);
|
||||||
|
ptrReader++;
|
||||||
|
} while (*ptrReader != '\0');
|
||||||
|
|
||||||
|
SCardFreeMemory(context, strReaders);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto long scardconnect(long context, string reader_name, [long preferred_protocol], [long ¤t_protocol])
|
||||||
|
Return a handle to the card */
|
||||||
|
/* TODO: Add support for the protocol parameters; default is "T=1" now and not changeable */
|
||||||
|
PHP_FUNCTION(scard_connect)
|
||||||
|
{
|
||||||
|
DWORD dwPreferredProtocol = SCARD_PROTOCOL_T1;
|
||||||
|
DWORD dwCurrentProtocol;
|
||||||
|
SCARDHANDLE hCard = 0;
|
||||||
|
LONG rc = 0;
|
||||||
|
LONG *context;
|
||||||
|
char *strReaderName;
|
||||||
|
int strReaderNameLen;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &context, &strReaderName, &strReaderNameLen) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardIsValidContext(context);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = SCardConnect(context, strReaderName, SCARD_SHARE_SHARED, dwPreferredProtocol, &hCard, &dwCurrentProtocol);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_LONG(hCard);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto boolean scarddisconnect(long card_handle, [long disposition])
|
||||||
|
Close a card connection obtained with scardconnect */
|
||||||
|
/* TODO: Add support for disposition. */
|
||||||
|
PHP_FUNCTION(scard_disconnect)
|
||||||
|
{
|
||||||
|
DWORD dwDisposition = SCARD_EJECT_CARD;
|
||||||
|
LONG rc;
|
||||||
|
SCARDHANDLE *hCard;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hCard) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*if (argc >= 2) {
|
||||||
|
convert_to_long(ARG(1));
|
||||||
|
dwDisposition = ARG(1)->value.lval;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
rc = SCardDisconnect(hCard, dwDisposition);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto string scardtransmit(long card_handle, string send_command)
|
||||||
|
Transmit (and receive) data to (and from) the card */
|
||||||
|
PHP_FUNCTION(scard_transmit)
|
||||||
|
{
|
||||||
|
SCARDHANDLE hCard;
|
||||||
|
DWORD dwProtocol;
|
||||||
|
DWORD dwState;
|
||||||
|
const SCARD_IO_REQUEST *sendPci = NULL;
|
||||||
|
SCARD_IO_REQUEST *recvPci = NULL;
|
||||||
|
BYTE *sendBuffer;
|
||||||
|
BYTE *recvBuffer;
|
||||||
|
DWORD sendLen, recvLen;
|
||||||
|
LONG rc;
|
||||||
|
char *apdu;
|
||||||
|
int apduLen;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &hCard, &apdu, &apduLen) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Are we in T=0 or T=1 ? */
|
||||||
|
rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, NULL, NULL);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dwState & SCARD_POWERED)) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (dwProtocol) {
|
||||||
|
case SCARD_PROTOCOL_RAW : sendPci = SCARD_PCI_RAW; break;
|
||||||
|
case SCARD_PROTOCOL_T0 : sendPci = SCARD_PCI_T0; break;
|
||||||
|
case SCARD_PROTOCOL_T1 : sendPci = SCARD_PCI_T1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get buffer to send */
|
||||||
|
sendBuffer = e_hex_to_bytes(apdu, &sendLen);
|
||||||
|
|
||||||
|
/* Guess the size of the buffer to recv */
|
||||||
|
recvLen = 2 + 256;
|
||||||
|
recvBuffer = emalloc(recvLen);
|
||||||
|
|
||||||
|
/* Perform the exchange */
|
||||||
|
recvPci = emalloc(1024);
|
||||||
|
recvPci->dwProtocol = dwProtocol;
|
||||||
|
recvPci->cbPciLength = 1024;
|
||||||
|
|
||||||
|
rc = SCardTransmit(hCard, sendPci, sendBuffer, sendLen, recvPci, recvBuffer, &recvLen);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
efree(recvPci);
|
||||||
|
efree(recvBuffer);
|
||||||
|
efree(sendBuffer);
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
efree(recvPci);
|
||||||
|
|
||||||
|
/* Return the response */
|
||||||
|
RETVAL_STRING(e_bytes_to_hex(recvBuffer, recvLen), TRUE);
|
||||||
|
|
||||||
|
/* Free local data */
|
||||||
|
efree(recvBuffer);
|
||||||
|
efree(sendBuffer);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto array scardstatus([long card_handle])
|
||||||
|
Retrieve reader's or card's status */
|
||||||
|
PHP_FUNCTION(scard_status)
|
||||||
|
{
|
||||||
|
SCARDHANDLE hCard = 0;
|
||||||
|
char *strReader = NULL;
|
||||||
|
DWORD dwProtocol, dwState;
|
||||||
|
BYTE atrBuffer[32];
|
||||||
|
DWORD atrLen;
|
||||||
|
LONG rc;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &hCard) == FAILURE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
atrLen = sizeof(atrBuffer);
|
||||||
|
rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, atrBuffer, &atrLen);
|
||||||
|
if (rc != SCARD_S_SUCCESS) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_init(return_value);
|
||||||
|
add_assoc_long(return_value, "state", dwState);
|
||||||
|
if (dwState & SCARD_ABSENT)
|
||||||
|
add_assoc_long(return_value, "SCARD_ABSENT", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_PRESENT)
|
||||||
|
add_assoc_long(return_value, "SCARD_PRESENT", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_SWALLOWED)
|
||||||
|
add_assoc_long(return_value, "SCARD_SWALLOWED", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_POWERED)
|
||||||
|
add_assoc_long(return_value, "SCARD_POWERED", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_NEGOTIABLE)
|
||||||
|
add_assoc_long(return_value, "SCARD_NEGOTIABLE", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_SPECIFIC)
|
||||||
|
add_assoc_long(return_value, "SCARD_SPECIFIC", 1);
|
||||||
|
|
||||||
|
switch (dwProtocol) {
|
||||||
|
/* Maybe change to bool type here instead of add_assoc_long...? */
|
||||||
|
case SCARD_PROTOCOL_RAW : add_assoc_long(return_value, "SCARD_PROTOCOL_RAW", 1);
|
||||||
|
add_assoc_string(return_value, "PROTOCOL", "RAW", TRUE);
|
||||||
|
break;
|
||||||
|
case SCARD_PROTOCOL_T0 : add_assoc_long(return_value, "SCARD_PROTOCOL_T0", 1);
|
||||||
|
add_assoc_string(return_value, "PROTOCOL", "T=0", TRUE);
|
||||||
|
break;
|
||||||
|
case SCARD_PROTOCOL_T1 : add_assoc_long(return_value, "SCARD_PROTOCOL_T1", 1);
|
||||||
|
add_assoc_string(return_value, "PROTOCOL", "T=1", TRUE);
|
||||||
|
break;
|
||||||
|
default : add_assoc_long(return_value, "PROTOCOL", dwProtocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atrLen) {
|
||||||
|
char *atrString;
|
||||||
|
atrString = e_bytes_to_hex(atrBuffer, atrLen);
|
||||||
|
add_assoc_string(return_value, "ATR", atrString, TRUE);
|
||||||
|
efree(atrString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
55
php/pcsc.class.php
Normal file
55
php/pcsc.class.php
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* Don't use this! this is a raw and dirty written class just for testing some
|
||||||
|
* stuff... Johannes
|
||||||
|
*/
|
||||||
|
|
||||||
|
class PCSC {
|
||||||
|
|
||||||
|
public $context;
|
||||||
|
public $card;
|
||||||
|
public $readers;
|
||||||
|
public $connection;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
$this->context = scard_establish_context();
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
$this->context = scard_release_context($this->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect($reader) {
|
||||||
|
return $this->connection = scard_connect($this->context, $reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*function reconnect() {
|
||||||
|
return $this->connection = scard_reconnect($this->connection);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
function disconnect() {
|
||||||
|
return scard_disconnect($this->connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
function listreaders() {
|
||||||
|
return $this->readers = scard_list_readers($this->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
function transmit($apdu) {
|
||||||
|
return scard_transmit($this->connection, $apdu);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isvalidcontext() {
|
||||||
|
return scard_is_valid_context($this->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
function releasecontext() {
|
||||||
|
return scard_release_context($this->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
function status() {
|
||||||
|
return scard_status($this->connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
43
php/test.php
Normal file
43
php/test.php
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/* Just a test script for checking the implementation... */
|
||||||
|
|
||||||
|
if (!extension_loaded('pcsc')) {
|
||||||
|
dl('pcsc.so');
|
||||||
|
}
|
||||||
|
|
||||||
|
include("./pcsc.class.php");
|
||||||
|
|
||||||
|
$foo = new PCSC();
|
||||||
|
|
||||||
|
echo "Create Context:\n";
|
||||||
|
var_dump($foo->context);
|
||||||
|
|
||||||
|
echo "List Readers:\n";
|
||||||
|
var_dump($foo->listreaders());
|
||||||
|
|
||||||
|
echo "Connect Card:\n";
|
||||||
|
var_dump($foo->connect("OMNIKEY CardMan 5x21 00 01"));
|
||||||
|
|
||||||
|
#echo "Reconnect:\n";
|
||||||
|
#var_dump($foo->reconnect());
|
||||||
|
|
||||||
|
echo "Some Transmits:\n";
|
||||||
|
var_dump($foo->transmit("00a4040c0cD2760001354B414E4D30310000"));
|
||||||
|
var_dump($foo->transmit("0084000008"));
|
||||||
|
var_dump($foo->transmit("0084000008"));
|
||||||
|
var_dump($foo->transmit("0084000008"));
|
||||||
|
|
||||||
|
echo "Is Valid Context?\n";
|
||||||
|
var_dump($foo->isvalidcontext());
|
||||||
|
|
||||||
|
echo "Status:\n";
|
||||||
|
var_dump($foo->status());
|
||||||
|
|
||||||
|
echo "Disconnect Card:\n";
|
||||||
|
var_dump($foo->disconnect());
|
||||||
|
|
||||||
|
echo "Release Context:\n";
|
||||||
|
var_dump($foo->releasecontext());
|
||||||
|
|
||||||
|
?>
|
||||||
32
php_pcsc.h
Normal file
32
php_pcsc.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#ifndef PHP_PCSC_H
|
||||||
|
#define PHP_PCSC_H
|
||||||
|
|
||||||
|
extern zend_module_entry pcsc_module_entry;
|
||||||
|
#define phpext_pcsc_ptr &pcsc_module_entry
|
||||||
|
|
||||||
|
#ifdef PHP_WIN32
|
||||||
|
#define PHP_PCSC_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define PHP_PCSC_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ZTS
|
||||||
|
#include "TSRM.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PHP_MINIT_FUNCTION(pcsc);
|
||||||
|
PHP_MSHUTDOWN_FUNCTION(pcsc);
|
||||||
|
PHP_MINFO_FUNCTION(pcsc);
|
||||||
|
|
||||||
|
PHP_FUNCTION(scard_establish_context);
|
||||||
|
PHP_FUNCTION(scard_is_valid_context);
|
||||||
|
PHP_FUNCTION(scard_release_context);
|
||||||
|
PHP_FUNCTION(scard_list_readers);
|
||||||
|
PHP_FUNCTION(scard_connect);
|
||||||
|
//PHP_FUNCTION(scard_reconnect);
|
||||||
|
PHP_FUNCTION(scard_disconnect);
|
||||||
|
PHP_FUNCTION(scard_status);
|
||||||
|
PHP_FUNCTION(scard_transmit);
|
||||||
|
//PHP_FUNCTION(scard_cancel);
|
||||||
|
|
||||||
|
#endif /* PHP_PCSC_H */
|
||||||
496
tmp/pcsc2.c
Normal file
496
tmp/pcsc2.c
Normal file
|
|
@ -0,0 +1,496 @@
|
||||||
|
PHP_FUNCTION(pcsc_test)
|
||||||
|
{
|
||||||
|
|
||||||
|
//php_printf("Huhudeldiehu: %d::\n", hContext);
|
||||||
|
|
||||||
|
char *strReaders = "";
|
||||||
|
char *ptrReader;
|
||||||
|
DWORD dwLen = SCARD_AUTOALLOCATE;
|
||||||
|
LONG rc3;
|
||||||
|
|
||||||
|
/*
|
||||||
|
LONG rc;
|
||||||
|
rc = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* php_printf("%d: %d<br/>\n", __LINE__, SCARD_S_SUCCESS);
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, lLastError);
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, hContext);
|
||||||
|
rc3 = SCardListReaders(hContext, NULL, (char *) &strReaders, &dwLen);
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, hContext);
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, lLastError);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (rc3 != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, 1);
|
||||||
|
lLastError = rc3;
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, rc3);
|
||||||
|
//RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strReaders == NULL) {
|
||||||
|
php_printf("%d: %d<br/>\n", __LINE__, 2);
|
||||||
|
//RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_init(return_value);
|
||||||
|
|
||||||
|
ptrReader = strReaders;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
add_next_index_string(return_value, ptrReader, TRUE);
|
||||||
|
ptrReader += strlen(ptrReader); /* End of the line */
|
||||||
|
ptrReader ++; /* Beginning of next list */
|
||||||
|
} while (*ptrReader != '\0');
|
||||||
|
|
||||||
|
SCardFreeMemory(hContext, strReaders);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* {{{ proto long scardconnect(string reader_name, [long preferred_protocol], [long ¤t_protocol])
|
||||||
|
Return a handle to the card */
|
||||||
|
PHP_FUNCTION(scardconnect)
|
||||||
|
{
|
||||||
|
DWORD dwPreferredProtocol, dwCurrentProtocol;
|
||||||
|
SCARDHANDLE hCard;
|
||||||
|
char *strReader;
|
||||||
|
LONG rc;
|
||||||
|
PARSE_ARGS(1, 3);
|
||||||
|
|
||||||
|
hLastCard = 0;
|
||||||
|
|
||||||
|
if (ARG(0)->type == IS_LONG)
|
||||||
|
{
|
||||||
|
/* Find reader by index */
|
||||||
|
char *strReaders = NULL;
|
||||||
|
char *ptrReader;
|
||||||
|
LONG idxReader;
|
||||||
|
DWORD dwLen = SCARD_AUTOALLOCATE;
|
||||||
|
|
||||||
|
/* Reader name not supplied, select it in readers list */
|
||||||
|
rc = SCardListReaders(hContext, NULL, (char *) &strReaders, &dwLen);
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strReaders == NULL)
|
||||||
|
RETURN_FALSE;
|
||||||
|
|
||||||
|
/* Loop */
|
||||||
|
idxReader = 0;
|
||||||
|
ptrReader = strReaders;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (idxReader == ARG(0)->value.lval)
|
||||||
|
{
|
||||||
|
strReader = estrdup(ptrReader);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idxReader ++;
|
||||||
|
ptrReader += strlen(ptrReader); /* End of the line */
|
||||||
|
ptrReader ++; /* Beginning of next list */
|
||||||
|
} while (*ptrReader != '\0');
|
||||||
|
|
||||||
|
SCardFreeMemory(hContext, strReaders);
|
||||||
|
|
||||||
|
/* Check */
|
||||||
|
if (strReader == NULL)
|
||||||
|
RETURN_FALSE; /* Reader not found ? */
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/* Use reader's name */
|
||||||
|
strReader = estrdup(ARG(0)->value.str.val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preferred protocol */
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(1));
|
||||||
|
dwPreferredProtocol = ARG(1)->value.lval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/* dwPreferredProtocol = SCARD_PROTOCOL_DEFAULT | SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; */
|
||||||
|
dwPreferredProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the function */
|
||||||
|
rc = SCardConnect(hContext, strReader, SCARD_SHARE_SHARED, dwPreferredProtocol, &hCard, &dwCurrentProtocol);
|
||||||
|
|
||||||
|
/* Free the string ASAP */
|
||||||
|
efree(strReader);
|
||||||
|
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current protocol */
|
||||||
|
if ((argc >= 3) && (PZVAL_IS_REF(ARG(2))))
|
||||||
|
{
|
||||||
|
ARG(2)->value.lval = dwCurrentProtocol;
|
||||||
|
ARG(2)->type = IS_LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We store a copy of the handle in case we need it in a shortcut function */
|
||||||
|
hLastCard = hCard;
|
||||||
|
|
||||||
|
/* We return the handle */
|
||||||
|
RETURN_LONG(hCard);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto boolean scardreconnect([long card_handle], [long preferred_protocol], [long initialisation], [long ¤t_protocol])
|
||||||
|
Return a handle to the card */
|
||||||
|
PHP_FUNCTION(scardreconnect)
|
||||||
|
{
|
||||||
|
DWORD dwPreferredProtocol, dwInitialization, dwCurrentProtocol;
|
||||||
|
SCARDHANDLE hCard;
|
||||||
|
LONG rc;
|
||||||
|
PARSE_ARGS(0, 4);
|
||||||
|
|
||||||
|
hLastCard = 0;
|
||||||
|
|
||||||
|
if (argc >= 1)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(0));
|
||||||
|
hCard = ARG(0)->value.lval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
hCard = hLastCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Preferred protocol */
|
||||||
|
if (ARG(1) != NULL)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(1));
|
||||||
|
dwPreferredProtocol = ARG(1)->value.lval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
dwPreferredProtocol = SCARD_PROTOCOL_DEFAULT | SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
|
||||||
|
*/
|
||||||
|
dwPreferredProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialisation */
|
||||||
|
if (ARG(2) != NULL)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(2));
|
||||||
|
dwInitialization = ARG(2)->value.lval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
dwInitialization = SCARD_LEAVE_CARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the function */
|
||||||
|
rc = SCardReconnect(hCard, SCARD_SHARE_SHARED, dwPreferredProtocol, dwInitialization, &dwCurrentProtocol);
|
||||||
|
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Current protocol */
|
||||||
|
if ((ARG(3) != NULL) && (PZVAL_IS_REF(ARG(3))))
|
||||||
|
{
|
||||||
|
ARG(3)->value.lval = dwCurrentProtocol;
|
||||||
|
ARG(3)->type = IS_LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* OK */
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto boolean scarddisconnect([long card_handle], [long disposition])
|
||||||
|
Close a card connection obtained with scardconnect */
|
||||||
|
PHP_FUNCTION(scarddisconnect)
|
||||||
|
{
|
||||||
|
SCARDHANDLE hCard;
|
||||||
|
DWORD dwDisposition;
|
||||||
|
LONG rc;
|
||||||
|
PARSE_ARGS(0, 2);
|
||||||
|
|
||||||
|
/* Retrieve parameters */
|
||||||
|
hCard = hLastCard;
|
||||||
|
dwDisposition = SCARD_EJECT_CARD;
|
||||||
|
|
||||||
|
if (argc >= 1)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(0));
|
||||||
|
hLastCard = ARG(0)->value.lval;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(1));
|
||||||
|
dwDisposition = ARG(1)->value.lval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disconnect */
|
||||||
|
rc = SCardDisconnect(hCard, dwDisposition);
|
||||||
|
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drop current card handle */
|
||||||
|
if (hLastCard == hCard)
|
||||||
|
hLastCard = 0;
|
||||||
|
|
||||||
|
/* OK */
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto array scardstatus([long card_handle])
|
||||||
|
Retrieve reader's or card's status */
|
||||||
|
PHP_FUNCTION(scardstatus)
|
||||||
|
{
|
||||||
|
SCARDHANDLE hCard = 0;
|
||||||
|
char *strReader = NULL;
|
||||||
|
DWORD dwProtocol, dwState;
|
||||||
|
BYTE atrBuffer[32];
|
||||||
|
DWORD atrLen;
|
||||||
|
LONG rc;
|
||||||
|
PARSE_ARGS(0, 1);
|
||||||
|
|
||||||
|
/* Retrieve parameters */
|
||||||
|
if (argc >= 1)
|
||||||
|
{
|
||||||
|
hCard = ARG(0)->value.lval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
hCard = hLastCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read card's status */
|
||||||
|
atrLen = sizeof(atrBuffer);
|
||||||
|
rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, atrBuffer, &atrLen);
|
||||||
|
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put result in an array */
|
||||||
|
array_init(return_value);
|
||||||
|
|
||||||
|
add_assoc_long(return_value, "state", dwState);
|
||||||
|
|
||||||
|
if (dwState & SCARD_ABSENT)
|
||||||
|
add_assoc_long(return_value, "SCARD_ABSENT", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_PRESENT)
|
||||||
|
add_assoc_long(return_value, "SCARD_PRESENT", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_SWALLOWED)
|
||||||
|
add_assoc_long(return_value, "SCARD_SWALLOWED", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_POWERED)
|
||||||
|
add_assoc_long(return_value, "SCARD_POWERED", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_NEGOTIABLE)
|
||||||
|
add_assoc_long(return_value, "SCARD_NEGOTIABLE", 1);
|
||||||
|
|
||||||
|
if (dwState & SCARD_SPECIFIC)
|
||||||
|
add_assoc_long(return_value, "SCARD_SPECIFIC", 1);
|
||||||
|
|
||||||
|
switch (dwProtocol)
|
||||||
|
{
|
||||||
|
case SCARD_PROTOCOL_RAW : add_assoc_long(return_value, "SCARD_PROTOCOL_RAW", 1);
|
||||||
|
add_assoc_string(return_value, "protocol", "RAW", TRUE);
|
||||||
|
break;
|
||||||
|
case SCARD_PROTOCOL_T0 : add_assoc_long(return_value, "SCARD_PROTOCOL_T0", 1);
|
||||||
|
add_assoc_string(return_value, "protocol", "T=0", TRUE);
|
||||||
|
break;
|
||||||
|
case SCARD_PROTOCOL_T1 : add_assoc_long(return_value, "SCARD_PROTOCOL_T1", 1);
|
||||||
|
add_assoc_string(return_value, "protocol", "T=1", TRUE);
|
||||||
|
break;
|
||||||
|
default : add_assoc_long(return_value, "protocol", dwProtocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (atrLen)
|
||||||
|
{
|
||||||
|
char *atrString;
|
||||||
|
atrString = e_bytes_to_hex(atrBuffer, atrLen);
|
||||||
|
add_assoc_string(return_value, "atr", atrString, TRUE);
|
||||||
|
efree(atrString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto array scardgetstatuschange(string reader_name, [long current_state])
|
||||||
|
Retrieve the status of a reader */
|
||||||
|
PHP_FUNCTION(scardgetstatuschange)
|
||||||
|
{
|
||||||
|
SCARD_READERSTATE rgReaderState = { 0 };
|
||||||
|
LONG rc;
|
||||||
|
PARSE_ARGS(1, 2);
|
||||||
|
|
||||||
|
/* Retrieve parameters */
|
||||||
|
rgReaderState.szReader = ARG(0)->value.str.val;
|
||||||
|
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(1));
|
||||||
|
rgReaderState.dwCurrentState = ARG(1)->value.lval;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
rgReaderState.dwCurrentState = SCARD_STATE_UNAWARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read reader's status */
|
||||||
|
rc = SCardGetStatusChange(hContext, 0, &rgReaderState, 1);
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Put result in an array */
|
||||||
|
array_init(return_value);
|
||||||
|
|
||||||
|
add_assoc_long(return_value, "state", rgReaderState.dwEventState);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_IGNORE)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_IGNORE", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_UNKNOWN)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_UNKNOWN", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_UNAVAILABLE)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_UNAVAILABLE", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_EMPTY)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_EMPTY", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_PRESENT)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_PRESENT", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_ATRMATCH)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_ATRMATCH", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_EXCLUSIVE)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_EXCLUSIVE", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_INUSE)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_INUSE", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.dwEventState & SCARD_STATE_MUTE)
|
||||||
|
add_assoc_long(return_value, "SCARD_STATE_MUTE", 1);
|
||||||
|
|
||||||
|
if (rgReaderState.cbAtr)
|
||||||
|
{
|
||||||
|
char *atrString;
|
||||||
|
atrString = e_bytes_to_hex(rgReaderState.rgbAtr, rgReaderState.cbAtr);
|
||||||
|
add_assoc_string(return_value, "atr", atrString, TRUE);
|
||||||
|
efree(atrString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
/* {{{ proto string scardtransmit([long card_handle], string send_command)
|
||||||
|
Transmit (and receive) data to (and from) the card */
|
||||||
|
PHP_FUNCTION(scardtransmit)
|
||||||
|
{
|
||||||
|
SCARDHANDLE hCard;
|
||||||
|
DWORD dwProtocol, dwState;
|
||||||
|
const SCARD_IO_REQUEST *sendPci = NULL;
|
||||||
|
SCARD_IO_REQUEST *recvPci = NULL;
|
||||||
|
BYTE *sendBuffer;
|
||||||
|
BYTE *recvBuffer;
|
||||||
|
DWORD sendLen, recvLen;
|
||||||
|
zval *argb = NULL;
|
||||||
|
LONG rc;
|
||||||
|
PARSE_ARGS(0, 3);
|
||||||
|
|
||||||
|
/* Retrieve parameters */
|
||||||
|
hCard = hLastCard;
|
||||||
|
argb = ARG(0);
|
||||||
|
if (argc >= 2)
|
||||||
|
{
|
||||||
|
convert_to_long(ARG(0));
|
||||||
|
hCard = ARG(0)->value.lval;
|
||||||
|
argb = ARG(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Are we in T=0 or T=1 ? */
|
||||||
|
rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, NULL, NULL);
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dwState & SCARD_POWERED))
|
||||||
|
RETURN_FALSE;
|
||||||
|
|
||||||
|
switch (dwProtocol)
|
||||||
|
{
|
||||||
|
case SCARD_PROTOCOL_RAW : sendPci = SCARD_PCI_RAW; break;
|
||||||
|
case SCARD_PROTOCOL_T0 : sendPci = SCARD_PCI_T0; break;
|
||||||
|
case SCARD_PROTOCOL_T1 : sendPci = SCARD_PCI_T1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get buffer to send */
|
||||||
|
convert_to_string(argb);
|
||||||
|
sendBuffer = e_hex_to_bytes(argb->value.str.val, &sendLen);
|
||||||
|
|
||||||
|
/* Guess the size of the buffer to recv */
|
||||||
|
recvLen = 2+256;
|
||||||
|
recvBuffer = emalloc(recvLen);
|
||||||
|
|
||||||
|
/* Perform the exchange */
|
||||||
|
recvPci = emalloc(1024);
|
||||||
|
recvPci->dwProtocol = dwProtocol;
|
||||||
|
recvPci->cbPciLength = 1024;
|
||||||
|
|
||||||
|
rc = SCardTransmit(hCard, sendPci, sendBuffer, sendLen, recvPci, recvBuffer, &recvLen);
|
||||||
|
if (rc != SCARD_S_SUCCESS)
|
||||||
|
{
|
||||||
|
efree(recvPci);
|
||||||
|
efree(recvBuffer);
|
||||||
|
efree(sendBuffer);
|
||||||
|
lLastError = rc;
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
efree(recvPci);
|
||||||
|
|
||||||
|
/* Return the response */
|
||||||
|
RETVAL_STRING(e_bytes_to_hex(recvBuffer, recvLen), TRUE);
|
||||||
|
|
||||||
|
/* Free local data */
|
||||||
|
efree(recvBuffer);
|
||||||
|
efree(sendBuffer);
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
/* {{{ proto long scardgetlasterror()
|
||||||
|
Retrieve value of last error */
|
||||||
|
PHP_FUNCTION(scardgetlasterror)
|
||||||
|
{
|
||||||
|
RETVAL_LONG(lLastError);
|
||||||
|
lLastError = SCARD_S_SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue