Compare commits

...

28 commits

Author SHA1 Message Date
0b0fab487f Link in README update. 2024-05-12 00:46:29 +02:00
37ecbc4eb0 .gitignore update 2022-05-05 03:17:27 +02:00
9ab1ae883a Testscript simple.php cleaned up 2021-02-23 23:30:10 +01:00
1c14647729 .gitignore update 2021-02-23 22:57:46 +01:00
a722128295 Added Jan Erhardt to list of contributors 2021-02-23 22:52:12 +01:00
1503e63658 Fixed compile error be generating arginfo headers 2021-02-23 22:45:15 +01:00
aab796c982 .gitignore update 2021-02-23 20:37:54 +01:00
4b2df9bae8 Copy/Paste fix 2021-02-22 04:32:30 +01:00
62b8e1e6d8 Added scard_begin_transaction and scard_end_transaction; SEGFAULTS when using it 2021-02-22 04:21:28 +01:00
9023e2a831 README update 2021-02-22 04:17:32 +01:00
576a3c6ca0 .gitignore update 2021-02-22 04:16:16 +01:00
1226d9ace8 Replaced tabs with 2 whitespaces in pcsc.c 2021-02-22 02:46:54 +01:00
aac7782210 Moved content from CREDITS and TODO to README and deleted files 2021-02-22 02:09:10 +01:00
87c612789b Added more API docs 2021-02-21 08:41:11 +01:00
2e58c9192d Added more API docs 2021-02-21 08:38:33 +01:00
ac8fa37a53 Content update 2021-02-21 08:19:09 +01:00
744c0e7654 Content update 2021-02-21 08:18:39 +01:00
41eafbe76f Content update 2021-02-21 08:17:03 +01:00
23bc4ea3e4 Content update 2021-02-21 08:04:53 +01:00
d76a0296ec Content update 2021-02-21 07:56:18 +01:00
6508c44984 Content update 2021-02-21 07:50:36 +01:00
83de43d9fe Content update 2021-02-21 07:04:51 +01:00
4b7273ae39 Content update 2021-02-21 06:59:46 +01:00
6a3027b35b Content update 2021-02-21 06:59:18 +01:00
fc687719c6 Content update 2021-02-21 06:58:03 +01:00
2562478bd4 Fixed and added some more PHP test code; Not stable 2021-02-21 06:19:50 +01:00
5aad57fa26 CREDITS name order fix 2021-02-21 03:10:30 +01:00
851e1dded2 API documentation fix. 2021-02-21 01:55:04 +01:00
13 changed files with 508 additions and 202 deletions

7
.gitignore vendored
View file

@ -1,3 +1,7 @@
nbproject/
*.dep
# Object files # Object files
*.o *.o
*.lo *.lo
@ -28,11 +32,14 @@ config.cache
config.guess config.guess
config.h config.h
config.h.in config.h.in
config.h.in~
config.log config.log
config.nice config.nice
config.status config.status
config.sub config.sub
configure configure
configure~
configure.ac
configure.in configure.in
conftest conftest
conftest.c conftest.c

View file

@ -1,11 +0,0 @@
# Contributors
## In alphabetical order:
* Johann Dantant (Original author)
* Anatol Belski (Contributor)
* Calvin Buckley (Contributor)
* Remi Collet (Contributor)
* Johannes Findeisen (Maintainer)
* Marco Schuster (Contributor)

165
README.md
View file

@ -29,21 +29,92 @@ After that you have all needed files in ./modules/ .
## API ## API
The extension currently provides the following API: The extension currently provides the following API (alphabetical order):
### scard_establish_context">scard_establish_context(); ### pcsc_stringify_error($errno);
Returns $errstr for $errno or NULL.
**NOT IMPLEMENTED!** - Should be available!
Duplicate of scard_errstr() but this should be the default.
### scard_begin_transaction($connection);
**NOT IMPLEMENTED!** - Should be available!
Establishes a temporary exclusive access mode for doing a serie of commands in a transaction.
You might want to use this when you are selecting a few files and then writing a large file so you can make sure that another application will not change the current file. If another application has a lock on this reader or this application is in SCARD_SHARE_EXCLUSIVE there will be no action taken.
### scard_cancel($context);
**NOT IMPLEMENTED!** - Maybe not useful because of this extension is for server side usage designed but since we want the API implemented it should be available.
### scard_connect($context, "OMNIKEY CardMan 5x21 00 00" [, int $protocol]);
Connects to a card. Returns the $connection to a reader or FALSE.
Where optional $protocol is:
* 1 = T=0
* 2 = T=1
Default $protocol is T=1.
### scard_control($connection);
**NOT IMPLEMENTED!** - Should be available!
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader.
### scard_disconnect($connection);
Disconnects the $connection to a card. Returns the TRUE if disconnecting was succesful or FALSE.
### scard_end_transaction($connection);
**NOT IMPLEMENTED!** - Should be available!
Ends a previously begun transaction.
The calling application must be the owner of the previously begun transaction or an error will occur.
### scard_errstr($errno); - Not PC/SC standard.
Returns $errstr for $errno or NULL.
### scard_establish_context();
Returns the application $context to the PC/SC resource manager. Returns the application $context to the PC/SC resource manager.
### scard_is_valid_context">scard_is_valid_context($context); ### scard_get_attrib($connection);
**NOT IMPLEMENTED!** - Should be available!
Get an attribute from the IFD Handler (reader driver).
### scard_get_status_change($context);
**NOT IMPLEMENTED!** - Should be available!
Blocks execution until the current availability of the cards in a specific set of readers changes.
### scard_is_valid_context($context);
Returns TRUE if $context is valid or FALSE if $context is not valid. Returns TRUE if $context is valid or FALSE if $context is not valid.
### scard_release_context">scard_release_context($context); ### scard_last_errno(); - Not PC/SC standard.
Releases the application $context. Returns the last $errno or nothing? NULL or FALSE? (TODO)
### scard_list_readers">scard_list_readers($context); ### scard_list_reader_groups($context);
**NOT IMPLEMENTED!** - Should be available!
Returns a list of currently available reader groups on the system.
### scard_list_readers($context);
Returns an array of available readers or FALSE. Returns an array of available readers or FALSE.
@ -60,37 +131,97 @@ array(3) {
} }
``` ```
### scard_connect">scard_connect($context, "OMNIKEY CardMan 5x21 00 00"); ### scard_reconnect($connection);
Connects to a card. Returns the $connection to a reader or FALSE. **NOT IMPLEMENTED!** - Should be available!
### scard_reconnect">scard_reconnect($connection);
Returns the $connection to a reader or FALSE. Returns the $connection to a reader or FALSE.
### scard_disconnect">scard_disconnect($connection); ### scard_release_context($context);
Disconnects the $connection to a card. Returns the TRUE if disconnecting was succesful or FALSE. Releases the application $context.
### scard_transmit">scard_transmit($connection, $apdu); ### scard_set_attrib($connection);
**NOT IMPLEMENTED!** - Should be available!
Set an attribute of the IFD Handler.
### scard_status($connection);
Returns the status array or FALSE.
#### Example:
```
array(7) {
["state"]=>
int(52)
["SCARD_PRESENT"]=>
int(1)
["SCARD_POWERED"]=>
int(1)
["SCARD_NEGOTIABLE"]=>
int(1)
["SCARD_PROTOCOL_T1"]=>
int(1)
["PROTOCOL"]=>
string(3) "T=1"
["ATR"]=>
string(28) "3B8980014A434F5033315632324A"
}
```
### scard_transmit($connection, $apdu);
Returns the response $apdu as string or FALSE. Returns the response $apdu as string or FALSE.
### scard_status">scard_status($connection); ## To do:
Returns the status or FALSE. There is some stuff to do. Some things are important but some are not.
### scard_cancel">scard_cancel($context); ### Implement important missing PC/SC functions and write documentation:
* SCardBeginTransaction()
* SCardEndTransaction()
* SCardControl()
* SCardGetStatusChange()
* Write complete API documentation
### Implement less important missing PC/SC functions:
* SCardGetAttrib()
* SCardSetAttrib()
* SCardListReaderGroups()
* SCardReconnect()
### Goal:
Completely implement the full API from [PC/SC API from PCSC-Lite](https://pcsclite.apdu.fr/api/group__API.html)
## License ## 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. 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.
## Credits
This extension was originally written in 2005 by Johann Dantant. In 2011 Johannes Findeisen took his code and updated it to work with the current PHP version. Johannes maintains the code to this day, but there have been some contributions from other people in the past. All people who have worked on extending or porting the "pcsc" extension are listed below in alphabetical order by their last name. Thanks to all!
* [Anatol Belski](https://github.com/weltling) (Contributor)
* [Calvin Buckley](https://github.com/NattyNarwhal) (Contributor)
* [Remi Collet](https://github.com/remicollet) (Contributor)
* Johann Dantant (Original author)
* [Jan Ehrhardt](https://github.com/Jan-E) (Contributor)
* [Johannes Findeisen](https://github.com/hanez) (Maintainer)
* Marco Schuster (Contributor)
## Links ## Links
* [PECL Project Page](http://pecl.php.net/package/pcsc) - Page for package download at PHP.net * [PECL Project Page](http://pecl.php.net/package/pcsc) - Page for package download at PHP.net
* [PC/SC Worgroup](http://www.pcscworkgroup.com/) - Homepage and definition file downloads * [PC/SC Worgroup](http://www.pcscworkgroup.com/) - Homepage and definition file downloads
* [PC/SC](http://en.wikipedia.org/wiki/PC/SC) - PC/SC at Wikipedia * [PC/SC](http://en.wikipedia.org/wiki/PC/SC) - PC/SC at Wikipedia
* [PC/SC-Lite](https://pcsclite.apdu.fr/) - The free and open implementation of the PC/SC SCard API for UNIX * [PC/SC-Lite](https://pcsclite.apdu.fr/) - The free and open implementation of the PC/SC SCard API for UNIX
* [PCSC sample in PHP5](http://ludovicrousseau.blogspot.de/2015/01/pcsc-sample-in-php5.html) - Ludovic Rousseau about "PC/SC for PHP" * [PC/SC API from PCSC-Lite](https://pcsclite.apdu.fr/api/group__API.html) - Documentation of the PCSC-Lite API
* [PCSC sample in PHP5](https://blog.apdu.fr/posts/2015/01/pcsc-sample-in-php5/) - Ludovic Rousseau about "PC/SC for PHP"
* [winscard.h header](https://docs.microsoft.com/en-us/windows/win32/api/winscard/) - Microsoft Documentation

17
TODO.md
View file

@ -1,17 +0,0 @@
# TODO
## Implement important missing PC/SC functions and write documentation:
* SCardControl()
* SCardGetStatusChange()
* SCardBeginTransaction()
* SCardEndTransaction()
* Write complete API documentation
## Implement less important missing PC/SC functions:
* SCardGetAttrib()
* SCardSetAttrib()
* SCardListReaderGroups()
* SCardReconnect

View file

@ -14,39 +14,39 @@ class PCSC {
function __construct() { function __construct() {
$this->context = scard_establish_context(); $this->context = scard_establish_context();
} }
function __destruct() { /*function __destruct() {
$this->context = scard_release_context($this->context); $this->context = scard_release_context($this->context);
} }*/
function connect($reader) { function connect($reader) {
return $this->connection = scard_connect($this->context, $reader); return $this->connection = scard_connect($this->context, $reader);
} }
/*function reconnect() { /*function reconnect() {
return $this->connection = scard_reconnect($this->connection); return $this->connection = scard_reconnect($this->connection);
}*/ }*/
function disconnect() { function disconnect() {
return scard_disconnect($this->connection); return scard_disconnect($this->connection);
} }
function listreaders() { function listreaders() {
return $this->readers = scard_list_readers($this->context); return $this->readers = scard_list_readers($this->context);
} }
function transmit($apdu) { function transmit($apdu) {
return scard_transmit($this->connection, $apdu); return scard_transmit($this->connection, $apdu);
} }
function isvalidcontext() { function isvalidcontext() {
return scard_is_valid_context($this->context); return scard_is_valid_context($this->context);
} }
function releasecontext() { function releasecontext() {
return scard_release_context($this->context); return scard_release_context($this->context);
} }
function status() { function status() {
return scard_status($this->connection); return scard_status($this->connection);
} }

119
docs/examples/simple.php Normal file
View file

@ -0,0 +1,119 @@
<?php
if (!extension_loaded('pcsc')) {
dl('pcsc.so');
}
# Get a PC/SC context
echo ">> Create Context\n";
$context = scard_establish_context();
var_dump($context);
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Get the reader list
echo ">> Get Readers\n";
$readers = scard_list_readers($context);
var_dump($readers);
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Use the first reader
echo ">> Select Reader\n";
$reader = $readers[1];
echo "Using reader: ", $reader, "\n";
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Connect to the card
echo ">> Connect to Card\n";
$card = scard_connect($context, $reader, 2);
var_dump( $card );
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Begin Transaction
echo ">> Begin Transaction\n";
$begin= scard_begin_transaction($card);
var_dump($begin);
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Select Applet APDU
echo ">> Select Applet\n";
$apdu = "00a4040c0cD2760001354B414E4D30310000";
$res = scard_transmit($card , $apdu);
var_dump($res);
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# test APDU
echo ">> Send APDU\n";
$apdu = "0084000008";
$res = scard_transmit($card, $apdu);
var_dump($res);
#echo pack("H*", $res), "\n";
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# End Transaction
echo ">> End Transaction\n";
$begin= scard_end_transaction($card);
var_dump( $card );
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Show Status
echo ">> Show Status\n";
$status = scard_status($card);
var_dump($status);
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
# Release the PC/SC context
echo ">> Release Context\n";
scard_release_context($context);
$errno = scard_last_errno();
var_dump($errno);
$errstr = scard_errstr($errno);
var_dump($errstr);
echo "\n";
?>

View file

@ -13,19 +13,22 @@ $foo = new PCSC();
echo "Create Context:\n"; echo "Create Context:\n";
var_dump($foo->context); var_dump($foo->context);
#echo "Last Error String:";
#var_dump($foo->scard_errstr($foo->scard_last_errno()));
echo "List Readers:\n"; echo "List Readers:\n";
var_dump($foo->listreaders()); var_dump($foo->listreaders());
echo "Connect Card:\n"; echo "Connect Card:\n";
var_dump($foo->connect("OMNIKEY CardMan 5x21 00 01")); var_dump($foo->connect("OMNIKEY CardMan (076B:5321) 5321 00 01"));
#echo "Reconnect:\n"; #echo "Reconnect:\n";
#var_dump($foo->reconnect()); #var_dump($foo->reconnect());
echo "Some Transmits:\n"; echo "Some Transmits:\n";
// Select applet
var_dump($foo->transmit("00a4040c0cD2760001354B414E4D30310000")); var_dump($foo->transmit("00a4040c0cD2760001354B414E4D30310000"));
var_dump($foo->transmit("0084000008")); // APDU to execute RNG function on card applet
var_dump($foo->transmit("0084000008"));
var_dump($foo->transmit("0084000008")); var_dump($foo->transmit("0084000008"));
echo "Is Valid Context?\n"; echo "Is Valid Context?\n";

View file

@ -23,7 +23,7 @@ http://pear.php.net/dtd/package-2.0.xsd">
<date>2021-02-21</date> <date>2021-02-21</date>
<time>01:26:42</time> <time>01:26:42</time>
<version> <version>
<release>0.5.1</release> <release>0.6.0</release>
<api>0.3.1</api> <api>0.3.1</api>
</version> </version>
<stability> <stability>
@ -35,7 +35,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<contents> <contents>
<dir name="/"> <dir name="/">
<file name="COPYING" role="doc" /> <file name="COPYING" role="doc" />
<file name="CREDITS.md" role="doc" />
<file name="config.m4" role="src" /> <file name="config.m4" role="src" />
<file name="config.w32" role="src" /> <file name="config.w32" role="src" />
<file name="pcsc.c" role="src" /> <file name="pcsc.c" role="src" />
@ -44,7 +43,6 @@ http://pear.php.net/dtd/package-2.0.xsd">
<file name="pcsc_arginfo.h" role="src" /> <file name="pcsc_arginfo.h" role="src" />
<file name="pcsc_legacy_arginfo.h" role="src" /> <file name="pcsc_legacy_arginfo.h" role="src" />
<file name="README.md" role="doc" /> <file name="README.md" role="doc" />
<file name="TODO.md" role="doc" />
</dir> <!-- / --> </dir> <!-- / -->
</contents> </contents>
<dependencies> <dependencies>

305
pcsc.c
View file

@ -28,7 +28,7 @@ ZEND_DECLARE_MODULE_GLOBALS(pcsc);
/* Compatibility shims */ /* Compatibility shims */
#ifndef ZEND_FETCH_RESOURCE #ifndef ZEND_FETCH_RESOURCE
#define ZEND_FETCH_RESOURCE(res, stmt_type, stmt, stmt_id, resource_type_name, le_stmt) \ #define ZEND_FETCH_RESOURCE(res, stmt_type, stmt, stmt_id, resource_type_name, le_stmt) \
res = (stmt_type)zend_fetch_resource(Z_RES_P(*stmt),resource_type_name,le_stmt); res = (stmt_type)zend_fetch_resource(Z_RES_P(*stmt),resource_type_name,le_stmt);
#endif #endif
#ifndef FALSE #ifndef FALSE
@ -71,44 +71,44 @@ ZEND_GET_MODULE(pcsc)
/* resource container: context */ /* resource container: context */
static int le_pcsc_ctx_res; static int le_pcsc_ctx_res;
static void php_pcsc_ctx_res_dtor(zend_resource *rsrc) { static void php_pcsc_ctx_res_dtor(zend_resource *rsrc) {
SCARDCONTEXT context; SCARDCONTEXT context;
LONG rc=0; LONG rc=0;
context=(SCARDCONTEXT)rsrc->ptr;
rc = SCardIsValidContext(context);
if (rc != SCARD_S_SUCCESS) {
php_error_docref(NULL, E_WARNING, "PC/SC context dtor: SCardIsValidContext returned %s (0x%lx)", php_pcsc_error_to_string(rc), rc);
return;
}
rc = SCardReleaseContext(context); context=(SCARDCONTEXT)rsrc->ptr;
if (rc != SCARD_S_SUCCESS) { rc = SCardIsValidContext(context);
php_error_docref(NULL, E_WARNING, "PC/SC context dtor: SCardReleaseContext returned %s (0x%lx)", php_pcsc_error_to_string(rc), rc); if (rc != SCARD_S_SUCCESS) {
return; php_error_docref(NULL, E_WARNING, "PC/SC context dtor: SCardIsValidContext returned %s (0x%lx)", php_pcsc_error_to_string(rc), rc);
} return;
return; }
rc = SCardReleaseContext(context);
if (rc != SCARD_S_SUCCESS) {
php_error_docref(NULL, E_WARNING, "PC/SC context dtor: SCardReleaseContext returned %s (0x%lx)", php_pcsc_error_to_string(rc), rc);
return;
}
return;
} }
/* resource container: connection */ /* resource container: connection */
static int le_pcsc_conn_res; static int le_pcsc_conn_res;
static void php_pcsc_conn_res_dtor(zend_resource *rsrc) { static void php_pcsc_conn_res_dtor(zend_resource *rsrc) {
SCARDHANDLE hCard; SCARDHANDLE hCard;
LONG rc; LONG rc;
//TODO: actually use this //TODO: actually use this
return; return;
php_printf("conn dtor\n"); php_printf("conn dtor\n");
hCard=(SCARDHANDLE)rsrc->ptr; hCard=(SCARDHANDLE)rsrc->ptr;
rc = SCardDisconnect(hCard, SCARD_LEAVE_CARD); rc = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
php_error_docref(NULL, E_WARNING, "PC/SC connection dtor: SCardDisconnect returned %s (0x%lx)", php_pcsc_error_to_string(rc), rc); php_error_docref(NULL, E_WARNING, "PC/SC connection dtor: SCardDisconnect returned %s (0x%lx)", php_pcsc_error_to_string(rc), rc);
} }
} }
/* TLS */ /* TLS */
static void php_pcsc_globals_ctor(zend_pcsc_globals* pcsc_globals) { static void php_pcsc_globals_ctor(zend_pcsc_globals* pcsc_globals) {
pcsc_globals->last_errno=SCARD_S_SUCCESS; pcsc_globals->last_errno=SCARD_S_SUCCESS;
} }
/* {{{ PHP_MINIT_FUNCTION /* {{{ PHP_MINIT_FUNCTION
@ -194,18 +194,18 @@ PHP_MINIT_FUNCTION(pcsc)
#ifdef SCARD_E_WRITE_TOO_MANY #ifdef SCARD_E_WRITE_TOO_MANY
REGISTER_PCSC_CONSTANT(SCARD_E_WRITE_TOO_MANY); REGISTER_PCSC_CONSTANT(SCARD_E_WRITE_TOO_MANY);
#endif #endif
REGISTER_PCSC_CONSTANT(SCARD_F_COMM_ERROR); REGISTER_PCSC_CONSTANT(SCARD_F_COMM_ERROR);
REGISTER_PCSC_CONSTANT(SCARD_F_INTERNAL_ERROR); REGISTER_PCSC_CONSTANT(SCARD_F_INTERNAL_ERROR);
REGISTER_PCSC_CONSTANT(SCARD_F_UNKNOWN_ERROR); REGISTER_PCSC_CONSTANT(SCARD_F_UNKNOWN_ERROR);
REGISTER_PCSC_CONSTANT(SCARD_F_WAITED_TOO_LONG); REGISTER_PCSC_CONSTANT(SCARD_F_WAITED_TOO_LONG);
#ifdef SCARD_P_SHUTDOWN #ifdef SCARD_P_SHUTDOWN
REGISTER_PCSC_CONSTANT(SCARD_P_SHUTDOWN); REGISTER_PCSC_CONSTANT(SCARD_P_SHUTDOWN);
#endif #endif
REGISTER_PCSC_CONSTANT(SCARD_S_SUCCESS); REGISTER_PCSC_CONSTANT(SCARD_S_SUCCESS);
#ifdef SCARD_W_CANCELLED_BY_USER #ifdef SCARD_W_CANCELLED_BY_USER
REGISTER_PCSC_CONSTANT(SCARD_W_CANCELLED_BY_USER); REGISTER_PCSC_CONSTANT(SCARD_W_CANCELLED_BY_USER);
#endif #endif
@ -284,82 +284,82 @@ PHP_MINFO_FUNCTION(pcsc)
/* map error codes to string */ /* map error codes to string */
static char* php_pcsc_error_to_string(DWORD dwRC) { static char* php_pcsc_error_to_string(DWORD dwRC) {
switch(dwRC) { switch(dwRC) {
#ifdef SCARD_E_BAD_SEEK #ifdef SCARD_E_BAD_SEEK
case SCARD_E_BAD_SEEK: return "SCARD_E_BAD_SEEK"; case SCARD_E_BAD_SEEK: return "SCARD_E_BAD_SEEK";
#endif #endif
case SCARD_E_CANCELLED: return "SCARD_E_CANCELLED"; case SCARD_E_CANCELLED: return "SCARD_E_CANCELLED";
case SCARD_E_CANT_DISPOSE: return "SCARD_E_CANT_DISPOSE"; case SCARD_E_CANT_DISPOSE: return "SCARD_E_CANT_DISPOSE";
case SCARD_E_CARD_UNSUPPORTED: return "SCARD_E_CARD_UNSUPPORTED"; case SCARD_E_CARD_UNSUPPORTED: return "SCARD_E_CARD_UNSUPPORTED";
#ifdef SCARD_E_CERTIFICATE_UNAVAILABLE #ifdef SCARD_E_CERTIFICATE_UNAVAILABLE
case SCARD_E_CERTIFICATE_UNAVAILABLE: return "SCARD_E_CERTIFICATE_UNAVAILABLE"; case SCARD_E_CERTIFICATE_UNAVAILABLE: return "SCARD_E_CERTIFICATE_UNAVAILABLE";
#endif #endif
#ifdef SCARD_E_COMM_DATA_LOST #ifdef SCARD_E_COMM_DATA_LOST
case SCARD_E_COMM_DATA_LOST: return "SCARD_E_COMM_DATA_LOST"; case SCARD_E_COMM_DATA_LOST: return "SCARD_E_COMM_DATA_LOST";
#endif #endif
#ifdef SCARD_E_DIR_NOT_FOUND #ifdef SCARD_E_DIR_NOT_FOUND
case SCARD_E_DIR_NOT_FOUND: return "SCARD_E_DIR_NOT_FOUND"; case SCARD_E_DIR_NOT_FOUND: return "SCARD_E_DIR_NOT_FOUND";
#endif #endif
case SCARD_E_DUPLICATE_READER: return "SCARD_E_DUPLICATE_READER"; case SCARD_E_DUPLICATE_READER: return "SCARD_E_DUPLICATE_READER";
#ifdef SCARD_E_FILE_NOT_FOUND #ifdef SCARD_E_FILE_NOT_FOUND
case SCARD_E_FILE_NOT_FOUND: return "SCARD_E_FILE_NOT_FOUND"; case SCARD_E_FILE_NOT_FOUND: return "SCARD_E_FILE_NOT_FOUND";
#endif #endif
#ifdef SCARD_E_ICC_CREATEORDER #ifdef SCARD_E_ICC_CREATEORDER
case SCARD_E_ICC_CREATEORDER: return "SCARD_E_ICC_CREATEORDER"; case SCARD_E_ICC_CREATEORDER: return "SCARD_E_ICC_CREATEORDER";
#endif #endif
#ifdef SCARD_E_ICC_INSTALLATION #ifdef SCARD_E_ICC_INSTALLATION
case SCARD_E_ICC_INSTALLATION: return "SCARD_E_ICC_INSTALLATION"; case SCARD_E_ICC_INSTALLATION: return "SCARD_E_ICC_INSTALLATION";
#endif #endif
case SCARD_E_INSUFFICIENT_BUFFER: return "SCARD_E_INSUFFICIENT_BUFFER"; case SCARD_E_INSUFFICIENT_BUFFER: return "SCARD_E_INSUFFICIENT_BUFFER";
case SCARD_E_INVALID_ATR: return "SCARD_E_INVALID_ATR"; case SCARD_E_INVALID_ATR: return "SCARD_E_INVALID_ATR";
#ifdef SCARD_E_INVALID_CHV #ifdef SCARD_E_INVALID_CHV
case SCARD_E_INVALID_CHV: return "SCARD_E_INVALID_CHV"; case SCARD_E_INVALID_CHV: return "SCARD_E_INVALID_CHV";
#endif #endif
case SCARD_E_INVALID_HANDLE: return "SCARD_E_INVALID_HANDLE"; case SCARD_E_INVALID_HANDLE: return "SCARD_E_INVALID_HANDLE";
case SCARD_E_INVALID_PARAMETER: return "SCARD_E_INVALID_PARAMETER"; case SCARD_E_INVALID_PARAMETER: return "SCARD_E_INVALID_PARAMETER";
case SCARD_E_INVALID_TARGET: return "SCARD_E_INVALID_TARGET"; case SCARD_E_INVALID_TARGET: return "SCARD_E_INVALID_TARGET";
case SCARD_E_INVALID_VALUE: return "SCARD_E_INVALID_VALUE"; case SCARD_E_INVALID_VALUE: return "SCARD_E_INVALID_VALUE";
#ifdef SCARD_E_NO_ACCESS #ifdef SCARD_E_NO_ACCESS
case SCARD_E_NO_ACCESS: return "SCARD_E_NO_ACCESS"; case SCARD_E_NO_ACCESS: return "SCARD_E_NO_ACCESS";
#endif #endif
#ifdef SCARD_E_NO_DIR #ifdef SCARD_E_NO_DIR
case SCARD_E_NO_DIR: return "SCARD_E_NO_DIR"; case SCARD_E_NO_DIR: return "SCARD_E_NO_DIR";
#endif #endif
#ifdef SCARD_E_NO_FILE #ifdef SCARD_E_NO_FILE
case SCARD_E_NO_FILE: return "SCARD_E_NO_FILE"; case SCARD_E_NO_FILE: return "SCARD_E_NO_FILE";
#endif #endif
#ifdef SCARD_E_NO_KEY_CONTAINER #ifdef SCARD_E_NO_KEY_CONTAINER
case SCARD_E_NO_KEY_CONTAINER: return "SCARD_E_NO_KEY_CONTAINER"; case SCARD_E_NO_KEY_CONTAINER: return "SCARD_E_NO_KEY_CONTAINER";
#endif #endif
case SCARD_E_NO_MEMORY: return "SCARD_E_NO_MEMORY"; case SCARD_E_NO_MEMORY: return "SCARD_E_NO_MEMORY";
case SCARD_E_NO_READERS_AVAILABLE: return "SCARD_E_NO_READERS_AVAILABLE"; case SCARD_E_NO_READERS_AVAILABLE: return "SCARD_E_NO_READERS_AVAILABLE";
case SCARD_E_NO_SERVICE: return "SCARD_E_NO_SERVICE"; case SCARD_E_NO_SERVICE: return "SCARD_E_NO_SERVICE";
case SCARD_E_NO_SMARTCARD: return "SCARD_E_NO_SMARTCARD"; case SCARD_E_NO_SMARTCARD: return "SCARD_E_NO_SMARTCARD";
#ifdef SCARD_E_NO_ACCESS #ifdef SCARD_E_NO_ACCESS
case SCARD_E_NO_SUCH_CERTIFICATE: return "SCARD_E_NO_SUCH_CERTIFICATE"; case SCARD_E_NO_SUCH_CERTIFICATE: return "SCARD_E_NO_SUCH_CERTIFICATE";
#endif #endif
case SCARD_E_NOT_READY: return "SCARD_E_NOT_READY"; case SCARD_E_NOT_READY: return "SCARD_E_NOT_READY";
case SCARD_E_NOT_TRANSACTED: return "SCARD_E_NOT_TRANSACTED"; case SCARD_E_NOT_TRANSACTED: return "SCARD_E_NOT_TRANSACTED";
case SCARD_E_PCI_TOO_SMALL: return "SCARD_E_PCI_TOO_SMALL"; case SCARD_E_PCI_TOO_SMALL: return "SCARD_E_PCI_TOO_SMALL";
case SCARD_E_PROTO_MISMATCH: return "SCARD_E_PROTO_MISMATCH"; case SCARD_E_PROTO_MISMATCH: return "SCARD_E_PROTO_MISMATCH";
case SCARD_E_READER_UNAVAILABLE: return "SCARD_E_READER_UNAVAILABLE"; case SCARD_E_READER_UNAVAILABLE: return "SCARD_E_READER_UNAVAILABLE";
case SCARD_E_READER_UNSUPPORTED: return "SCARD_E_READER_UNSUPPORTED"; case SCARD_E_READER_UNSUPPORTED: return "SCARD_E_READER_UNSUPPORTED";
#ifdef SCARD_E_SERVER_TOO_BUSY #ifdef SCARD_E_SERVER_TOO_BUSY
case SCARD_E_SERVER_TOO_BUSY: return "SCARD_E_SERVER_TOO_BUSY"; case SCARD_E_SERVER_TOO_BUSY: return "SCARD_E_SERVER_TOO_BUSY";
#endif #endif
case SCARD_E_SERVICE_STOPPED: return "SCARD_E_SERVICE_STOPPED"; case SCARD_E_SERVICE_STOPPED: return "SCARD_E_SERVICE_STOPPED";
case SCARD_E_SHARING_VIOLATION: return "SCARD_E_SHARING_VIOLATION"; case SCARD_E_SHARING_VIOLATION: return "SCARD_E_SHARING_VIOLATION";
case SCARD_E_SYSTEM_CANCELLED: return "SCARD_E_SYSTEM_CANCELLED"; case SCARD_E_SYSTEM_CANCELLED: return "SCARD_E_SYSTEM_CANCELLED";
case SCARD_E_TIMEOUT: return "SCARD_E_TIMEOUT"; case SCARD_E_TIMEOUT: return "SCARD_E_TIMEOUT";
#ifdef SCARD_E_UNEXPECTED #ifdef SCARD_E_UNEXPECTED
case SCARD_E_UNEXPECTED: return "SCARD_E_UNEXPECTED"; case SCARD_E_UNEXPECTED: return "SCARD_E_UNEXPECTED";
#endif #endif
case SCARD_E_UNKNOWN_CARD: return "SCARD_E_UNKNOWN_CARD"; case SCARD_E_UNKNOWN_CARD: return "SCARD_E_UNKNOWN_CARD";
case SCARD_E_UNKNOWN_READER: return "SCARD_E_UNKNOWN_READER"; case SCARD_E_UNKNOWN_READER: return "SCARD_E_UNKNOWN_READER";
#ifdef SCARD_E_UNKNOWN_RES_MNG #ifdef SCARD_E_UNKNOWN_RES_MNG
case SCARD_E_UNKNOWN_RES_MNG: return "SCARD_E_UNKNOWN_RES_MNG"; case SCARD_E_UNKNOWN_RES_MNG: return "SCARD_E_UNKNOWN_RES_MNG";
#endif #endif
/* apparently E_UNEXPECTED and E_UNSUPPORTED are defined /* apparently E_UNEXPECTED and E_UNSUPPORTED are defined
by a buggy header file on Linux, causing a "double used constant" by a buggy header file on Linux, causing a "double used constant"
error. Just leave this out on Linux, then. error. Just leave this out on Linux, then.
*/ */
@ -367,50 +367,50 @@ static char* php_pcsc_error_to_string(DWORD dwRC) {
case SCARD_E_UNSUPPORTED_FEATURE: return "SCARD_E_UNSUPPORTED_FEATURE"; case SCARD_E_UNSUPPORTED_FEATURE: return "SCARD_E_UNSUPPORTED_FEATURE";
#endif #endif
#ifdef SCARD_E_WRITE_TOO_MANY #ifdef SCARD_E_WRITE_TOO_MANY
case SCARD_E_WRITE_TOO_MANY: return "SCARD_E_WRITE_TOO_MANY"; case SCARD_E_WRITE_TOO_MANY: return "SCARD_E_WRITE_TOO_MANY";
#endif #endif
case SCARD_F_COMM_ERROR: return "SCARD_E_WRITE_TOO_MANY"; case SCARD_F_COMM_ERROR: return "SCARD_E_WRITE_TOO_MANY";
case SCARD_F_INTERNAL_ERROR: return "SCARD_F_INTERNAL_ERROR"; case SCARD_F_INTERNAL_ERROR: return "SCARD_F_INTERNAL_ERROR";
case SCARD_F_UNKNOWN_ERROR: return "SCARD_F_UNKNOWN_ERROR"; case SCARD_F_UNKNOWN_ERROR: return "SCARD_F_UNKNOWN_ERROR";
case SCARD_F_WAITED_TOO_LONG: return "SCARD_F_WAITED_TOO_LONG"; case SCARD_F_WAITED_TOO_LONG: return "SCARD_F_WAITED_TOO_LONG";
#ifdef SCARD_P_SHUTDOWN #ifdef SCARD_P_SHUTDOWN
case SCARD_P_SHUTDOWN: return "SCARD_P_SHUTDOWN"; case SCARD_P_SHUTDOWN: return "SCARD_P_SHUTDOWN";
#endif #endif
case SCARD_S_SUCCESS: return "SCARD_S_SUCCESS"; case SCARD_S_SUCCESS: return "SCARD_S_SUCCESS";
#ifdef SCARD_W_CANCELLED_BY_USER #ifdef SCARD_W_CANCELLED_BY_USER
case SCARD_W_CANCELLED_BY_USER: return "SCARD_W_CANCELLED_BY_USER"; case SCARD_W_CANCELLED_BY_USER: return "SCARD_W_CANCELLED_BY_USER";
#endif #endif
#ifdef SCARD_W_CACHE_ITEM_NOT_FOUND #ifdef SCARD_W_CACHE_ITEM_NOT_FOUND
case SCARD_W_CACHE_ITEM_NOT_FOUND: return "SCARD_W_CACHE_ITEM_NOT_FOUND"; case SCARD_W_CACHE_ITEM_NOT_FOUND: return "SCARD_W_CACHE_ITEM_NOT_FOUND";
#endif #endif
#ifdef SCARD_W_CACHE_ITEM_STALE #ifdef SCARD_W_CACHE_ITEM_STALE
case SCARD_W_CACHE_ITEM_STALE: return "SCARD_W_CACHE_ITEM_STALE"; case SCARD_W_CACHE_ITEM_STALE: return "SCARD_W_CACHE_ITEM_STALE";
#endif #endif
#ifdef SCARD_W_CACHE_ITEM_TOO_BIG #ifdef SCARD_W_CACHE_ITEM_TOO_BIG
case SCARD_W_CACHE_ITEM_TOO_BIG: return "SCARD_W_CACHE_ITEM_TOO_BIG"; case SCARD_W_CACHE_ITEM_TOO_BIG: return "SCARD_W_CACHE_ITEM_TOO_BIG";
#endif #endif
#ifdef SCARD_W_CARD_NOT_AUTHENTICATED #ifdef SCARD_W_CARD_NOT_AUTHENTICATED
case SCARD_W_CARD_NOT_AUTHENTICATED: return "SCARD_W_CARD_NOT_AUTHENTICATED"; case SCARD_W_CARD_NOT_AUTHENTICATED: return "SCARD_W_CARD_NOT_AUTHENTICATED";
#endif #endif
#ifdef SCARD_W_CHV_BLOCKED #ifdef SCARD_W_CHV_BLOCKED
case SCARD_W_CHV_BLOCKED: return "SCARD_W_CHV_BLOCKED"; case SCARD_W_CHV_BLOCKED: return "SCARD_W_CHV_BLOCKED";
#endif #endif
#ifdef SCARD_W_EOF #ifdef SCARD_W_EOF
case SCARD_W_EOF: return "SCARD_W_EOF"; case SCARD_W_EOF: return "SCARD_W_EOF";
#endif #endif
case SCARD_W_REMOVED_CARD: return "SCARD_W_REMOVED_CARD"; case SCARD_W_REMOVED_CARD: return "SCARD_W_REMOVED_CARD";
case SCARD_W_RESET_CARD: return "SCARD_W_RESET_CARD"; case SCARD_W_RESET_CARD: return "SCARD_W_RESET_CARD";
#ifdef SCARD_W_SECURITY_VIOLATION #ifdef SCARD_W_SECURITY_VIOLATION
case SCARD_W_SECURITY_VIOLATION: return "SCARD_W_SECURITY_VIOLATION"; case SCARD_W_SECURITY_VIOLATION: return "SCARD_W_SECURITY_VIOLATION";
#endif #endif
case SCARD_W_UNPOWERED_CARD: return "SCARD_W_UNPOWERED_CARD"; case SCARD_W_UNPOWERED_CARD: return "SCARD_W_UNPOWERED_CARD";
case SCARD_W_UNRESPONSIVE_CARD: return "SCARD_W_UNRESPONSIVE_CARD"; case SCARD_W_UNRESPONSIVE_CARD: return "SCARD_W_UNRESPONSIVE_CARD";
case SCARD_W_UNSUPPORTED_CARD: return "SCARD_W_UNSUPPORTED_CARD"; case SCARD_W_UNSUPPORTED_CARD: return "SCARD_W_UNSUPPORTED_CARD";
#ifdef SCARD_W_WRONG_CHV #ifdef SCARD_W_WRONG_CHV
case SCARD_W_WRONG_CHV: return "SCARD_W_WRONG_CHV"; case SCARD_W_WRONG_CHV: return "SCARD_W_WRONG_CHV";
#endif #endif
default: return "Unknown"; default: return "Unknown";
} }
} }
static char *e_bytes_to_hex(BYTE *buffer, DWORD length) static char *e_bytes_to_hex(BYTE *buffer, DWORD length)
@ -453,15 +453,15 @@ static BYTE *e_hex_to_bytes(char *str, DWORD *length)
DWORD i, l; DWORD i, l;
BYTE *buf; BYTE *buf;
if (str == NULL) { if (str == NULL) {
return NULL; return NULL;
} }
l = strlen(str) / 2; l = strlen(str) / 2;
if (length != NULL) { if (length != NULL) {
*length = l; *length = l;
} }
buf = emalloc(l); buf = emalloc(l);
for (i = 0; i < l; i++) { for (i = 0; i < l; i++) {
@ -484,10 +484,10 @@ PHP_FUNCTION(scard_establish_context)
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard_context); rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scard_context);
if (rc != SCARD_S_SUCCESS) if (rc != SCARD_S_SUCCESS)
{ {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
RETURN_RES(zend_register_resource((void*)scard_context,le_pcsc_ctx_res)); RETURN_RES(zend_register_resource((void*)scard_context,le_pcsc_ctx_res));
} }
/* }}} */ /* }}} */
@ -499,15 +499,15 @@ PHP_FUNCTION(scard_is_valid_context)
LONG rc = 0; LONG rc = 0;
zval* ctx_res; zval* ctx_res;
SCARDCONTEXT context; SCARDCONTEXT context;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ctx_res) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ctx_res) == FAILURE) {
RETURN_NULL(); RETURN_NULL();
} }
ZEND_FETCH_RESOURCE(context, SCARDCONTEXT, &ctx_res, -1, PHP_PCSC_CTX_RES_NAME, le_pcsc_ctx_res); ZEND_FETCH_RESOURCE(context, SCARDCONTEXT, &ctx_res, -1, PHP_PCSC_CTX_RES_NAME, le_pcsc_ctx_res);
rc = SCardIsValidContext(context); rc = SCardIsValidContext(context);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
RETURN_TRUE; RETURN_TRUE;
@ -520,7 +520,7 @@ PHP_FUNCTION(scard_release_context)
{ {
zval* ctx_res; zval* ctx_res;
SCARDCONTEXT context; SCARDCONTEXT context;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ctx_res) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ctx_res) == FAILURE) {
RETURN_NULL(); RETURN_NULL();
} }
@ -542,22 +542,22 @@ PHP_FUNCTION(scard_list_readers)
LONG rc = 0; LONG rc = 0;
zval* ctx_res; zval* ctx_res;
SCARDCONTEXT context; SCARDCONTEXT context;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ctx_res) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &ctx_res) == FAILURE) {
RETURN_NULL(); RETURN_NULL();
} }
ZEND_FETCH_RESOURCE(context, SCARDCONTEXT, &ctx_res, -1, PHP_PCSC_CTX_RES_NAME, le_pcsc_ctx_res); ZEND_FETCH_RESOURCE(context, SCARDCONTEXT, &ctx_res, -1, PHP_PCSC_CTX_RES_NAME, le_pcsc_ctx_res);
rc = SCardListReaders(context, NULL, (char *) &strReaders, &dwLen); rc = SCardListReaders(context, NULL, (char *) &strReaders, &dwLen);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
if (strReaders == NULL) { if (strReaders == NULL) {
RETURN_FALSE; RETURN_FALSE;
} }
array_init(return_value); array_init(return_value);
ptrReader = strReaders; ptrReader = strReaders;
@ -566,7 +566,7 @@ PHP_FUNCTION(scard_list_readers)
ptrReader+= strlen(ptrReader); ptrReader+= strlen(ptrReader);
ptrReader++; ptrReader++;
} while (*ptrReader != '\0'); } while (*ptrReader != '\0');
SCardFreeMemory(context, strReaders); SCardFreeMemory(context, strReaders);
} }
/* }}} */ /* }}} */
@ -575,7 +575,7 @@ PHP_FUNCTION(scard_list_readers)
Return a handle to the card */ Return a handle to the card */
PHP_FUNCTION(scard_connect) PHP_FUNCTION(scard_connect)
{ {
DWORD dwPreferredProtocol = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; DWORD dwPreferredProtocol = SCARD_PROTOCOL_RAW | SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
DWORD dwCurrentProtocol; DWORD dwCurrentProtocol;
SCARDHANDLE hCard = 0; SCARDHANDLE hCard = 0;
LONG rc = 0; LONG rc = 0;
@ -585,7 +585,7 @@ PHP_FUNCTION(scard_connect)
char *strReaderName; char *strReaderName;
size_t strReaderNameLen; size_t strReaderNameLen;
zend_long preferred_protocol; zend_long preferred_protocol;
current_protocol = NULL; current_protocol = NULL;
ctx_res = NULL; ctx_res = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|lz", &ctx_res, &strReaderName, &strReaderNameLen, &preferred_protocol, &current_protocol) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs|lz", &ctx_res, &strReaderName, &strReaderNameLen, &preferred_protocol, &current_protocol) == FAILURE) {
@ -602,13 +602,13 @@ PHP_FUNCTION(scard_connect)
rc = SCardConnect(context, strReaderName, SCARD_SHARE_SHARED, dwPreferredProtocol, &hCard, &dwCurrentProtocol); rc = SCardConnect(context, strReaderName, SCARD_SHARE_SHARED, dwPreferredProtocol, &hCard, &dwCurrentProtocol);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
if (current_protocol != NULL) { if (current_protocol != NULL) {
ZVAL_LONG(current_protocol, dwCurrentProtocol); ZVAL_LONG(current_protocol, dwCurrentProtocol);
} }
RETURN_RES(zend_register_resource((void*)hCard, le_pcsc_conn_res)); RETURN_RES(zend_register_resource((void*)hCard, le_pcsc_conn_res));
} }
/* }}} */ /* }}} */
@ -621,15 +621,57 @@ PHP_FUNCTION(scard_disconnect)
LONG rc; LONG rc;
zval* conn_res; zval* conn_res;
SCARDHANDLE hCard; SCARDHANDLE hCard;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &conn_res, &dwDisposition) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &conn_res, &dwDisposition) == FAILURE) {
return; return;
} }
ZEND_FETCH_RESOURCE(hCard, SCARDHANDLE, &conn_res, -1, PHP_PCSC_CONN_RES_NAME, le_pcsc_conn_res); ZEND_FETCH_RESOURCE(hCard, SCARDHANDLE, &conn_res, -1, PHP_PCSC_CONN_RES_NAME, le_pcsc_conn_res);
rc = SCardDisconnect(hCard, (DWORD)dwDisposition); rc = SCardDisconnect(hCard, (DWORD)dwDisposition);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto boolean scard_begin_transaction(resource card_handle)
Begin transaction on a card connection obtained with scard_connect */
PHP_FUNCTION(scard_begin_transaction)
{
LONG rc;
zval* conn_res;
SCARDHANDLE hCard;
ZEND_FETCH_RESOURCE(hCard, SCARDHANDLE, &conn_res, -1, PHP_PCSC_CONN_RES_NAME, le_pcsc_conn_res);
rc = SCardBeginTransaction(hCard);
if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc;
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
/* {{{ proto boolean scard_end_transaction(resource card_handle, [long disposition = SCARD_LEAVE_CARD])
End a previously begun transaction invoked by scard_begin_transaction on a card connection obtained with scard_connect; If no transaction began, do nothing. */
PHP_FUNCTION(scard_end_transaction)
{
zend_long dwDisposition = SCARD_LEAVE_CARD;
LONG rc;
zval* conn_res;
SCARDHANDLE hCard;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|l", &conn_res, &dwDisposition) == FAILURE) {
return;
}
ZEND_FETCH_RESOURCE(hCard, SCARDHANDLE, &conn_res, -1, PHP_PCSC_CONN_RES_NAME, le_pcsc_conn_res);
rc = SCardEndTransaction(hCard, (DWORD)dwDisposition);
if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
RETURN_TRUE; RETURN_TRUE;
@ -652,7 +694,7 @@ PHP_FUNCTION(scard_transmit)
LONG rc; LONG rc;
char *apdu; char *apdu;
size_t apduLen; size_t apduLen;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &conn_res, &apdu, &apduLen) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "rs", &conn_res, &apdu, &apduLen) == FAILURE) {
return; return;
} }
@ -661,15 +703,15 @@ PHP_FUNCTION(scard_transmit)
/* Are we in T=0 or T=1 ? Is the card powered? */ /* Are we in T=0 or T=1 ? Is the card powered? */
rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, NULL, NULL); rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, NULL, NULL);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
if (!(dwState & SCARD_POWERED)) { if (!(dwState & SCARD_POWERED)) {
PCSC_G(last_errno) = SCARD_W_UNPOWERED_CARD; PCSC_G(last_errno) = SCARD_W_UNPOWERED_CARD;
RETURN_FALSE; RETURN_FALSE;
} }
switch (dwProtocol) { switch (dwProtocol) {
case SCARD_PROTOCOL_RAW : sendPci = SCARD_PCI_RAW; break; case SCARD_PROTOCOL_RAW : sendPci = SCARD_PCI_RAW; break;
case SCARD_PROTOCOL_T0 : sendPci = SCARD_PCI_T0; break; case SCARD_PROTOCOL_T0 : sendPci = SCARD_PCI_T0; break;
@ -690,7 +732,7 @@ PHP_FUNCTION(scard_transmit)
rc = SCardTransmit(hCard, sendPci, sendBuffer, sendLen, recvPci, recvBuffer, &recvLen); rc = SCardTransmit(hCard, sendPci, sendBuffer, sendLen, recvPci, recvBuffer, &recvLen);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
efree(recvPci); efree(recvPci);
efree(recvBuffer); efree(recvBuffer);
efree(sendBuffer); efree(sendBuffer);
@ -717,16 +759,16 @@ PHP_FUNCTION(scard_status)
BYTE atrBuffer[32]; BYTE atrBuffer[32];
DWORD atrLen; DWORD atrLen;
LONG rc; LONG rc;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &conn_res) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &conn_res) == FAILURE) {
return; return;
} }
ZEND_FETCH_RESOURCE(hCard, SCARDHANDLE, &conn_res, -1, PHP_PCSC_CONN_RES_NAME, le_pcsc_conn_res); ZEND_FETCH_RESOURCE(hCard, SCARDHANDLE, &conn_res, -1, PHP_PCSC_CONN_RES_NAME, le_pcsc_conn_res);
atrLen = sizeof(atrBuffer); atrLen = sizeof(atrBuffer);
rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, atrBuffer, &atrLen); rc = SCardStatus(hCard, NULL, NULL, &dwState, &dwProtocol, atrBuffer, &atrLen);
if (rc != SCARD_S_SUCCESS) { if (rc != SCARD_S_SUCCESS) {
PCSC_G(last_errno) = rc; PCSC_G(last_errno) = rc;
RETURN_FALSE; RETURN_FALSE;
} }
@ -751,7 +793,6 @@ PHP_FUNCTION(scard_status)
add_assoc_long(return_value, "SCARD_SPECIFIC", 1); add_assoc_long(return_value, "SCARD_SPECIFIC", 1);
switch (dwProtocol) { 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); case SCARD_PROTOCOL_RAW : add_assoc_long(return_value, "SCARD_PROTOCOL_RAW", 1);
add_assoc_string(return_value, "PROTOCOL", "RAW"); add_assoc_string(return_value, "PROTOCOL", "RAW");
break; break;
@ -780,7 +821,7 @@ PHP_FUNCTION(scard_last_errno)
if (zend_parse_parameters_none() == FAILURE) { if (zend_parse_parameters_none() == FAILURE) {
return; return;
} }
RETURN_LONG(PCSC_G(last_errno)); RETURN_LONG(PCSC_G(last_errno));
} }
/* }}} */ /* }}} */

View file

@ -37,6 +37,18 @@ function scard_connect($context, string $reader_name, int $preferred_protocol=SC
*/ */
function scard_disconnect($card, int $disposition=SCARD_EJECT_CARD): bool {} function scard_disconnect($card, int $disposition=SCARD_EJECT_CARD): bool {}
/**
* @param resource $card
* @return resource|false
*/
function scard_begin_transaction($card): bool {}
/**
* @param resource $card
* @return resource|false
*/
function scard_end_transaction($card, int $disposition=SCARD_LEAVE_CARD): bool {}
/** /**
* @param resource $card * @param resource $card
* @return resource|false * @return resource|false

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 3e1df1d509b6416c1eb997f61295c26d9ad0fd03 */ * Stub hash: 676b86ff0a1ee4d762d86126e8068f4cb6805272 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_establish_context, 0, 0, 0) ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_establish_context, 0, 0, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
@ -26,6 +26,15 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_scard_disconnect, 0, 1, _IS_BOOL
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, disposition, IS_LONG, 0, "SCARD_EJECT_CARD") ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, disposition, IS_LONG, 0, "SCARD_EJECT_CARD")
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_scard_begin_transaction, 0, 1, _IS_BOOL, 0)
ZEND_ARG_INFO(0, card)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_scard_end_transaction, 0, 1, _IS_BOOL, 0)
ZEND_ARG_INFO(0, card)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, disposition, IS_LONG, 0, "SCARD_LEAVE_CARD")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_scard_transmit, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_scard_transmit, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_ARG_INFO(0, card) ZEND_ARG_INFO(0, card)
ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, command, IS_STRING, 0)
@ -49,6 +58,8 @@ ZEND_FUNCTION(scard_is_valid_context);
ZEND_FUNCTION(scard_list_readers); ZEND_FUNCTION(scard_list_readers);
ZEND_FUNCTION(scard_connect); ZEND_FUNCTION(scard_connect);
ZEND_FUNCTION(scard_disconnect); ZEND_FUNCTION(scard_disconnect);
ZEND_FUNCTION(scard_begin_transaction);
ZEND_FUNCTION(scard_end_transaction);
ZEND_FUNCTION(scard_transmit); ZEND_FUNCTION(scard_transmit);
ZEND_FUNCTION(scard_status); ZEND_FUNCTION(scard_status);
ZEND_FUNCTION(scard_last_errno); ZEND_FUNCTION(scard_last_errno);
@ -62,6 +73,8 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(scard_list_readers, arginfo_scard_list_readers) ZEND_FE(scard_list_readers, arginfo_scard_list_readers)
ZEND_FE(scard_connect, arginfo_scard_connect) ZEND_FE(scard_connect, arginfo_scard_connect)
ZEND_FE(scard_disconnect, arginfo_scard_disconnect) ZEND_FE(scard_disconnect, arginfo_scard_disconnect)
ZEND_FE(scard_begin_transaction, arginfo_scard_begin_transaction)
ZEND_FE(scard_end_transaction, arginfo_scard_end_transaction)
ZEND_FE(scard_transmit, arginfo_scard_transmit) ZEND_FE(scard_transmit, arginfo_scard_transmit)
ZEND_FE(scard_status, arginfo_scard_status) ZEND_FE(scard_status, arginfo_scard_status)
ZEND_FE(scard_last_errno, arginfo_scard_last_errno) ZEND_FE(scard_last_errno, arginfo_scard_last_errno)

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead. /* This is a generated file, edit the .stub.php file instead.
* Stub hash: 3e1df1d509b6416c1eb997f61295c26d9ad0fd03 */ * Stub hash: 676b86ff0a1ee4d762d86126e8068f4cb6805272 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_establish_context, 0, 0, 0) ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_establish_context, 0, 0, 0)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
@ -24,14 +24,18 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_disconnect, 0, 0, 1)
ZEND_ARG_INFO(0, disposition) ZEND_ARG_INFO(0, disposition)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_begin_transaction, 0, 0, 1)
ZEND_ARG_INFO(0, card)
ZEND_END_ARG_INFO()
#define arginfo_scard_end_transaction arginfo_scard_disconnect
ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_transmit, 0, 0, 2) ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_transmit, 0, 0, 2)
ZEND_ARG_INFO(0, card) ZEND_ARG_INFO(0, card)
ZEND_ARG_INFO(0, command) ZEND_ARG_INFO(0, command)
ZEND_END_ARG_INFO() ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_scard_status, 0, 0, 1) #define arginfo_scard_status arginfo_scard_begin_transaction
ZEND_ARG_INFO(0, card)
ZEND_END_ARG_INFO()
#define arginfo_scard_last_errno arginfo_scard_establish_context #define arginfo_scard_last_errno arginfo_scard_establish_context
@ -46,6 +50,8 @@ ZEND_FUNCTION(scard_is_valid_context);
ZEND_FUNCTION(scard_list_readers); ZEND_FUNCTION(scard_list_readers);
ZEND_FUNCTION(scard_connect); ZEND_FUNCTION(scard_connect);
ZEND_FUNCTION(scard_disconnect); ZEND_FUNCTION(scard_disconnect);
ZEND_FUNCTION(scard_begin_transaction);
ZEND_FUNCTION(scard_end_transaction);
ZEND_FUNCTION(scard_transmit); ZEND_FUNCTION(scard_transmit);
ZEND_FUNCTION(scard_status); ZEND_FUNCTION(scard_status);
ZEND_FUNCTION(scard_last_errno); ZEND_FUNCTION(scard_last_errno);
@ -59,6 +65,8 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(scard_list_readers, arginfo_scard_list_readers) ZEND_FE(scard_list_readers, arginfo_scard_list_readers)
ZEND_FE(scard_connect, arginfo_scard_connect) ZEND_FE(scard_connect, arginfo_scard_connect)
ZEND_FE(scard_disconnect, arginfo_scard_disconnect) ZEND_FE(scard_disconnect, arginfo_scard_disconnect)
ZEND_FE(scard_begin_transaction, arginfo_scard_begin_transaction)
ZEND_FE(scard_end_transaction, arginfo_scard_end_transaction)
ZEND_FE(scard_transmit, arginfo_scard_transmit) ZEND_FE(scard_transmit, arginfo_scard_transmit)
ZEND_FE(scard_status, arginfo_scard_status) ZEND_FE(scard_status, arginfo_scard_status)
ZEND_FE(scard_last_errno, arginfo_scard_last_errno) ZEND_FE(scard_last_errno, arginfo_scard_last_errno)

View file

@ -4,7 +4,7 @@
extern zend_module_entry pcsc_module_entry; extern zend_module_entry pcsc_module_entry;
#define phpext_pcsc_ptr &pcsc_module_entry #define phpext_pcsc_ptr &pcsc_module_entry
#define PHP_PCSC_VERSION "0.5.1" #define PHP_PCSC_VERSION "0.6.0"
#ifdef PHP_WIN32 #ifdef PHP_WIN32
#define PHP_PCSC_API __declspec(dllexport) #define PHP_PCSC_API __declspec(dllexport)
@ -32,6 +32,8 @@ PHP_FUNCTION(scard_list_readers);
PHP_FUNCTION(scard_connect); PHP_FUNCTION(scard_connect);
//PHP_FUNCTION(scard_reconnect); //PHP_FUNCTION(scard_reconnect);
PHP_FUNCTION(scard_disconnect); PHP_FUNCTION(scard_disconnect);
PHP_FUNCTION(scard_begin_transaction);
PHP_FUNCTION(scard_end_transaction);
PHP_FUNCTION(scard_status); PHP_FUNCTION(scard_status);
//PHP_FUNCTION(scard_get_status_change); //PHP_FUNCTION(scard_get_status_change);
PHP_FUNCTION(scard_transmit); PHP_FUNCTION(scard_transmit);