mirror of
https://github.com/pcsc-for-php/pcsc.git
synced 2026-08-08 21:09:26 +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