]> granicus.if.org Git - php/commitdiff
@- New extension "pfpro" for interface with Signio Payflow Pro (David Croft)
authorDavid Croft <david@php.net>
Sat, 15 Jul 2000 01:13:40 +0000 (01:13 +0000)
committerDavid Croft <david@php.net>
Sat, 15 Jul 2000 01:13:40 +0000 (01:13 +0000)
New extension pfpro to interface with Signio Payflow Pro library for
credit card processing etc

MAINTAINERS
ext/pfpro/Makefile.in [new file with mode: 0644]
ext/pfpro/config.m4 [new file with mode: 0644]
ext/pfpro/pfpro.c [new file with mode: 0644]
ext/pfpro/php_pfpro.h [new file with mode: 0644]
ext/pfpro/test.output [new file with mode: 0644]
ext/pfpro/test.php [new file with mode: 0644]

index 142b6fe12daf1275198ec32a469198c2b5c3687a..8c3995d2bd13547ee3357db532b98604120de05c 100644 (file)
@@ -87,6 +87,10 @@ EXTENSION:           pdf
 PRIMARY MAINTAINER:  Uwe Steinmann <steinm@php.net>
 STATUS:              Maintained
 --------------------------------------------------------------------------------
+EXTENSION:           pfpro
+PRIMARY MAINTAINER:  David Croft <david@infotrek.co.uk>
+STATUS:              Maintained
+--------------------------------------------------------------------------------
 EXTENSION:           pgsql
 PRIMARY MAINTAINER:  Jouni Ahto <jah@mork.net>
 STATUS:              Odd fixes
diff --git a/ext/pfpro/Makefile.in b/ext/pfpro/Makefile.in
new file mode 100644 (file)
index 0000000..cbe71b9
--- /dev/null
@@ -0,0 +1,8 @@
+# $Id$
+
+LTLIBRARY_NAME        = libpfpro.la
+LTLIBRARY_SOURCES     = pfpro.c
+LTLIBRARY_SHARED_NAME = pfpro.la
+LTLIBRARY_SHARED_LIBADD = $(PFPRO_SHARED_LIBADD)
+
+include $(top_srcdir)/build/dynlib.mk
diff --git a/ext/pfpro/config.m4 b/ext/pfpro/config.m4
new file mode 100644 (file)
index 0000000..9baaf92
--- /dev/null
@@ -0,0 +1,38 @@
+dnl $Id$
+dnl config.m4 for extension pfpro
+
+AC_MSG_CHECKING(for Payflow Pro support)
+
+PHP_ARG_WITH(pfpro, for pfpro support,
+[  --with-pfpro=[DIR]       Include Payflow Pro support])
+
+if test "$PHP_PFPRO" != "no"; then
+  if test -r $PHP_PFPRO/lib/libpfpro.so; then
+    PFPRO_DIR=$PHP_PFPRO
+  else
+    AC_MSG_CHECKING(for libpfpro in default path)
+    for i in /usr/local /usr; do
+      if test -r $i/lib/libpfpro.so; then
+        PFPRO_DIR=$i
+        AC_MSG_RESULT(found in $i)
+      fi
+    done
+  fi
+  if test -z "$PFPRO_DIR"; then
+    AC_MSG_RESULT(not found)
+    AC_MSG_ERROR(Please install the payflow pro SDK distribution -
+   pfpro.h should be in <pfpro-dir>/include and
+   libpfpro.so should be in <pfpro-dir>/lib)
+   Use ./configure --with-pfpro=<pfpro-dir> if necessary
+  fi
+
+  AC_ADD_INCLUDE($PFPRO_DIR/include)
+
+  PHP_SUBST(PFPRO_SHARED_LIBADD)
+
+  AC_ADD_LIBRARY_WITH_PATH(pfpro, $PFPRO_DIR, PFPRO_SHARED_LIBADD)
+
+  AC_DEFINE(HAVE_PFPRO, 1, [ ])
+
+  PHP_EXTENSION(pfpro, $ext_shared)
+fi
diff --git a/ext/pfpro/pfpro.c b/ext/pfpro/pfpro.c
new file mode 100644 (file)
index 0000000..b0aba83
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.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: David Croft <david@infotrek.co.uk>                           |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/* Note: I've left the globals and ini-file handling stuff in
+   as I've yet to decide whether this is a good way to place "default"
+   stuff like hosts and proxies */
+
+/* Status: Working. Awaiting comments from Signio as to whether
+   PNInit and ProcessPNTransaction have any meaningful return value */
+
+#include "php.h"
+#include "php_ini.h"
+#include "php_pfpro.h"
+
+#include "pfpro.h"
+
+#if HAVE_PFPRO
+
+#ifdef ZTS
+int pfpro_globals_id;
+#else
+php_pfpro_globals pfpro_globals;
+#endif
+
+/* Function table */
+
+function_entry pfpro_functions[] = {
+       PHP_FE(pfpro_version, NULL)
+       PHP_FE(pfpro_init, NULL)
+       PHP_FE(pfpro_cleanup, NULL)
+       PHP_FE(pfpro_process_raw, NULL)
+       PHP_FE(pfpro_process, NULL)
+       {NULL, NULL, NULL}
+};
+
+zend_module_entry pfpro_module_entry = {
+       "pfpro",
+       pfpro_functions,
+       PHP_MINIT(pfpro),
+       PHP_MSHUTDOWN(pfpro),
+       NULL,                                   /* request start */
+       NULL,                                   /* request end */
+       PHP_MINFO(pfpro),
+       STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_PFPRO
+ZEND_GET_MODULE(pfpro)
+#endif
+
+/*
+PHP_INI_BEGIN()
+PHP_INI_END()
+*/
+
+PHP_MINIT_FUNCTION(pfpro)
+{
+/*
+       REGISTER_INI_ENTRIES();
+*/
+       return SUCCESS;
+}
+
+PHP_MSHUTDOWN_FUNCTION(pfpro)
+{
+/*
+       UNREGISTER_INI_ENTRIES();
+*/
+       return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(pfpro)
+{
+       php_info_print_table_start();
+       php_info_print_table_header(2, "Signio Payflow Pro support", "enabled");
+       php_info_print_table_end();
+
+       /*
+       DISPLAY_INI_ENTRIES();
+       */
+}
+
+
+
+/* {{{ proto string pfpro_version()
+   Returns the version of the Payflow Pro library */
+PHP_FUNCTION(pfpro_version)
+{
+       if (ZEND_NUM_ARGS() != 0) {
+               WRONG_PARAM_COUNT;
+       }
+
+       RETURN_STRING(PNVersion(), 1);
+}
+/* }}} */
+
+
+
+/* {{{ proto void pfpro_init()
+   Initialises the Payflow Pro library */
+PHP_FUNCTION(pfpro_init)
+{
+       if (ZEND_NUM_ARGS() != 0) {
+               WRONG_PARAM_COUNT;
+       }
+
+       PNInit();
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+
+
+/* {{{ proto void pfpro_cleanup()
+   Shuts down the Payflow Pro library */
+PHP_FUNCTION(pfpro_cleanup)
+{
+       if (ZEND_NUM_ARGS() != 0) {
+               WRONG_PARAM_COUNT;
+       }
+
+       PNCleanup();
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+
+
+/* {{{ proto string pfpro_process_raw(string parmlist [, string hostaddress [, int port, [, int timeout [, string proxyAddress [, int proxyPort [, string proxyLogon [, string proxyPassword]]]]]]])
+   Raw Payflow Pro transaction processing */
+PHP_FUNCTION(pfpro_process_raw)
+{
+       pval ***args;
+
+       char *parmlist;
+       char *address = NULL;
+       int port = 443;
+       int timeout = 30;
+       char *proxyAddress = NULL;
+       int proxyPort = 0;
+       char *proxyLogon = NULL;
+       char *proxyPassword = NULL;
+
+       int freeaddress = 0;
+
+       /* No, I don't like that Signio tell you to use a
+          fixed length buffer either */
+
+       char response[512];
+
+       if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 8) {
+               WRONG_PARAM_COUNT;
+       }
+
+       args = (pval ***) emalloc(sizeof(pval **) * ZEND_NUM_ARGS());
+
+       if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+        php_error(E_WARNING, "Unable to read parameters in pfpro_process_raw()");
+               efree(args);
+               RETURN_FALSE;
+       }
+
+       switch (ZEND_NUM_ARGS()) {
+               case 8:
+                       convert_to_string_ex(args[7]);
+                       proxyPassword = (*args[7])->value.str.val;
+                       /* fall through */
+
+               case 7:
+                       convert_to_string_ex(args[6]);
+                       proxyLogon = (*args[6])->value.str.val;
+                       /* fall through */
+
+               case 6:
+                       convert_to_long_ex(args[5]);
+                       proxyPort = (*args[5])->value.lval;
+                       /* fall through */
+
+               case 5:
+                       convert_to_string_ex(args[4]);
+                       proxyAddress = (*args[4])->value.str.val;
+                       /* fall through */
+
+               case 4:
+                       convert_to_long_ex(args[3]);
+                       timeout = (*args[3])->value.lval;
+                       /* fall through */
+
+               case 3:
+                       convert_to_long_ex(args[2]);
+                       port = (*args[2])->value.lval;
+                       /* fall through */
+
+               case 2:
+                       convert_to_string_ex(args[1]);
+                       address = (*args[1])->value.str.val;
+       }
+
+       convert_to_string_ex(args[0]);
+       parmlist = (*args[0])->value.str.val;
+
+       efree(args);
+
+       /* Default to signio's test server */
+
+       if (address == NULL) {
+               address = estrdup("test.signio.com");
+               freeaddress = 1;
+       }
+
+#if 0
+       printf("Address: >%s<\n", address);
+       printf("Port: >%d<\n", port);
+       printf("Parmlist: >%s<\n", parmlist);
+       printf("Timeout: >%d<\n", timeout);
+       printf("Proxy address: >%s<\n", proxyAddress);
+       printf("Proxy port: >%d<\n", proxyPort);
+       printf("Proxy logon: >%s<\n", proxyLogon);
+       printf("Proxy password: >%s<\n", proxyPassword);
+#endif
+
+       /* Blank the response buffer */
+
+       memset(response, 0, sizeof(response));
+
+       /* Perform the transaction */
+
+       ProcessPNTransaction(address, port, proxyAddress, proxyPort, proxyLogon, proxyPassword, parmlist, strlen(parmlist), timeout, response);
+
+       if (freeaddress) {
+               efree(address);
+       }
+
+       RETURN_STRING(response, 1);
+}
+/* }}} */
+
+
+
+/* {{{ proto array pfpro_process(array parmlist [, string hostaddress [, int port, [, int timeout [, string proxyAddress [, int proxyPort [, string proxyLogon [, string proxyPassword]]]]]]])
+   Payflow Pro transaction processing using arrays */
+PHP_FUNCTION(pfpro_process)
+{
+       pval ***args;
+
+       HashTable *target_hash;
+       ulong lkey;
+       char *varname;
+       zval **entry;
+       int pass;
+
+       char *address = NULL;
+       int port = 443;
+       int timeout = 30;
+       char *proxyAddress = NULL;
+       int proxyPort = 0;
+       char *proxyLogon = NULL;
+       char *proxyPassword = NULL;
+       int freeaddress = 0;
+
+       char *parmlist = NULL;
+       int parmlength = 0;
+
+       /* No, I don't like that Signio tell you to use a
+          fixed length buffer either */
+
+       char response[512];
+
+       char tmpbuf[128];
+       char *rsppos, *valpos;
+
+
+       if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 8) {
+               WRONG_PARAM_COUNT;
+       }
+
+       args = (pval ***) emalloc(sizeof(pval **) * ZEND_NUM_ARGS());
+
+       if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
+        php_error(E_WARNING, "Unable to read parameters in pfpro_process()");
+               efree(args);
+               RETURN_FALSE;
+       }
+
+       if ((*args[0])->type != IS_ARRAY) {
+               php_error(E_WARNING, "First parameter to pfpro_process() must be an array");
+               efree(args);
+               RETURN_FALSE;
+       }
+
+       switch (ZEND_NUM_ARGS()) {
+               case 8:
+                       convert_to_string_ex(args[7]);
+                       proxyPassword = (*args[7])->value.str.val;
+                       /* fall through */
+
+               case 7:
+                       convert_to_string_ex(args[6]);
+                       proxyLogon = (*args[6])->value.str.val;
+                       /* fall through */
+
+               case 6:
+                       convert_to_long_ex(args[5]);
+                       proxyPort = (*args[5])->value.lval;
+                       /* fall through */
+
+               case 5:
+                       convert_to_string_ex(args[4]);
+                       proxyAddress = (*args[4])->value.str.val;
+                       /* fall through */
+
+               case 4:
+                       convert_to_long_ex(args[3]);
+                       timeout = (*args[3])->value.lval;
+                       /* fall through */
+
+               case 3:
+                       convert_to_long_ex(args[2]);
+                       port = (*args[2])->value.lval;
+                       /* fall through */
+
+               case 2:
+                       convert_to_string_ex(args[1]);
+                       address = (*args[1])->value.str.val;
+       }
+
+       /* Concatenate the passed array as specified by signio.
+          Basically it's all key=value&key=value, the only exception
+          being if the value contains = or &, in which case we also
+          encode the length, e.g. key[5]=bl&ah */
+
+       target_hash = HASH_OF(*args[0]);
+
+       for (pass = 0; pass <= 1; pass ++) {
+
+               parmlength = 0;
+               /* we go around the array twice. the first time to calculate
+                  the string length, the second time to actually store it */
+
+               zend_hash_internal_pointer_reset(target_hash);
+
+               while (zend_hash_get_current_data(target_hash, (void **)&entry) == SUCCESS) {
+                       if (zend_hash_get_current_key(target_hash, &varname, &lkey) == HASH_KEY_IS_STRING) {
+                               if (parmlength > 0) {
+                                       if (pass == 1)
+                                               strcpy(parmlist + parmlength, "&");
+                                       parmlength += 1;
+                               }
+
+                               if (pass == 1)
+                                       strcpy(parmlist + parmlength, varname);
+                               parmlength += strlen(varname);
+
+                               if ((*entry)->type == IS_STRING) {
+                                       if (strchr((*entry)->value.str.val, '&') ||
+                                               strchr((*entry)->value.str.val, '=')) {
+                                               sprintf(tmpbuf, "[%d]=", (*entry)->value.str.len);
+                                               if (pass == 1)
+                                                       strcpy(parmlist + parmlength, tmpbuf);
+                                               parmlength += strlen(tmpbuf);
+                                       }
+                                       else {
+                                               if (pass == 1)
+                                                       strcpy(parmlist + parmlength, "=");
+                                               parmlength += 1;
+                                       }
+                                       if (pass == 1)
+                                               strcpy(parmlist + parmlength, (*entry)->value.str.val);
+                                       parmlength += (*entry)->value.str.len;
+                               }
+                               else if ((*entry)->type == IS_LONG) {
+                                       sprintf(tmpbuf, "=%d", (*entry)->value.lval);
+                                       if (pass == 1)
+                                               strcpy(parmlist + parmlength, tmpbuf);
+                                       parmlength += strlen(tmpbuf);
+                               }
+                               else if ((*entry)->type == IS_DOUBLE) {
+                                       sprintf(tmpbuf, "=%.2f", (*entry)->value.dval);
+                                       if (pass == 1)
+                                               strcpy(parmlist + parmlength, tmpbuf);
+                                       parmlength += strlen(tmpbuf);
+                               }
+                               else {
+                                       php_error(E_WARNING, "pfpro_process() array values should be strings, ints or floats");
+                               }
+                               efree(varname);
+                       }
+                       else {
+                               php_error(E_WARNING, "pfpro_process() array keys must be strings");
+                               efree(args);
+                               RETURN_FALSE;
+                       }
+                       zend_hash_move_forward(target_hash);
+               }
+
+               if (pass == 0) {
+                       parmlist = emalloc(parmlength + 1);
+               }
+       }
+
+       efree(args);
+
+       /* Default to signio's test server */
+
+       if (address == NULL) {
+               /* is it safe to just do address = "test.signio.com"; here? */
+               address = estrdup("test.signio.com");
+               freeaddress = 1;
+       }
+
+#if 0
+       printf("Address: >%s<\n", address);
+       printf("Port: >%d<\n", port);
+       printf("Parmlist: >%s<\n", parmlist);
+       printf("Timeout: >%d<\n", timeout);
+       printf("Proxy address: >%s<\n", proxyAddress);
+       printf("Proxy port: >%d<\n", proxyPort);
+       printf("Proxy logon: >%s<\n", proxyLogon);
+       printf("Proxy password: >%s<\n", proxyPassword);
+#endif
+
+       /* Allocate the array for the response now - so we catch any errors
+          from this BEFORE we knock it off to the bank */
+
+       if (array_init(return_value) == FAILURE) {
+               php_error(E_WARNING, "pfpro_process() unable to create array");
+               RETURN_FALSE;
+       }
+
+       /* Blank the response buffer */
+
+       memset(response, 0, sizeof(response));
+
+       /* Perform the transaction */
+
+       ProcessPNTransaction(address, port, proxyAddress, proxyPort, proxyLogon, proxyPassword, parmlist, parmlength, timeout, response);
+
+       if (freeaddress) {
+               efree(address);
+       }
+
+       /* Decode the response back into a PHP array */
+
+       rsppos = strtok(response, "&");
+
+       do {
+               valpos = strchr(rsppos, '=');
+               if (valpos) {
+                       strncpy(tmpbuf, rsppos, valpos - rsppos);
+                       tmpbuf[valpos - rsppos] = 0;
+                       add_assoc_string(return_value, tmpbuf, valpos + 1, 1);
+               }
+               
+       } while (rsppos = strtok(NULL, "&"));
+}
+/* }}} */
+
+
+
+#endif /* HAVE_PFPRO */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/pfpro/php_pfpro.h b/ext/pfpro/php_pfpro.h
new file mode 100644 (file)
index 0000000..5992c2d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP version 4.0                                                      |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group                   |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 2.02 of the PHP license,      |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available at through the world-wide-web at                           |
+   | http://www.php.net/license/2_02.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: David Croft <david@infotrek.co.uk>                           |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef _PHP_PFPRO_H
+#define _PHP_PFPRO_H
+
+#if HAVE_PFPRO
+
+extern zend_module_entry pfpro_module_entry;
+#define phpext_pfpro_ptr &pfpro_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_PFPRO_API __declspec(dllexport)
+#else
+#define PHP_PFPRO_API
+#endif
+
+PHP_MINIT_FUNCTION(pfpro);
+PHP_MSHUTDOWN_FUNCTION(pfpro);
+PHP_RINIT_FUNCTION(pfpro);
+PHP_RSHUTDOWN_FUNCTION(pfpro);
+PHP_MINFO_FUNCTION(pfpro);
+
+PHP_FUNCTION(pfpro_version);           /* Return library version */
+PHP_FUNCTION(pfpro_init);
+PHP_FUNCTION(pfpro_cleanup);
+PHP_FUNCTION(pfpro_process_raw);
+PHP_FUNCTION(pfpro_process);
+
+/* Fill in this structure and use entries in it
+   for thread safety instead of using true globals.
+*/
+typedef struct {
+       /* You can use the next one as type if your module registers any
+          resources. Oh, you can of course rename it to something more
+          suitable, add list entry types or remove it if it not needed.
+          It's just an example.
+       */
+       int le_pfpro;
+} php_pfpro_globals;
+
+/* In every function that needs to use variables in php_pfpro_globals,
+   do call PFPROLS_FETCH(); after declaring other variables used by
+   that function, and always refer to them as PFPROG(variable).
+   You are encouraged to rename these macros something shorter, see
+   examples in any other php module directory.
+*/
+
+#ifdef ZTS
+#define PFPROG(v) (pfpro_globals->v)
+#define PFPROLS_FETCH() php_pfpro_globals *pfpro_globals = ts_resource(gd_pfpro_id)
+#else
+#define PFPROG(v) (pfpro_globals.v)
+#define PFPROLS_FETCH()
+#endif
+
+#else
+
+#define phpext_pfpro_ptr NULL
+
+#endif
+
+#endif /* _PHP_PFPRO_H */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/pfpro/test.output b/ext/pfpro/test.output
new file mode 100644 (file)
index 0000000..29e13f7
--- /dev/null
@@ -0,0 +1,29 @@
+X-Powered-By: PHP/4.0.2-dev
+Content-type: text/html
+
+<pre>
+
+Payflow Pro library is version L211
+Payflow Pro init returned 1
+Signio response code was 0, which means: Approved
+
+Dump of the transaction request Array
+(
+    [USER] => mylogin
+    [PWD] => mypassword
+    [TRXTYPE] => S
+    [TENDER] => C
+    [AMT] => 1.5
+    [ACCT] => 4111111111111111
+    [EXPDATE] => 0900
+)
+
+Dump of the response Array
+(
+    [RESULT] => 0
+    [PNREF] => P40111660030
+    [RESPMSG] => Approved
+    [AUTHCODE] => 251PNI
+    [AVSADDR] => X
+    [AVSZIP] => X
+)
diff --git a/ext/pfpro/test.php b/ext/pfpro/test.php
new file mode 100644 (file)
index 0000000..712cc07
--- /dev/null
@@ -0,0 +1,43 @@
+<?
+
+if (!extension_loaded('pfpro')) {
+  die("pfpro module is not compiled in PHP\n");
+}
+
+echo "<pre>\n\n";
+
+echo "Payflow Pro library is version ".pfpro_version()."\n";
+
+echo "Payflow Pro init returned ".pfpro_init()."\n";
+
+$transaction = array(USER      => 'mylogin',
+                    PWD        => 'mypassword',
+                    TRXTYPE    => 'S',
+                    TENDER     => 'C',
+                    AMT        => 1.50,
+                    ACCT       => '4111111111111111',
+                    EXPDATE    => '0900'
+                    );
+
+$response = pfpro_process($transaction);
+
+if (!$response) {
+  die("Couldn't establish link to signio software.\n");
+}
+
+echo "Signio response code was ".$response[RESULT];
+echo ", which means: ".$response[RESPMSG]."\n";
+
+echo "\n";
+
+echo "Dump of the transaction request ";
+print_r($transaction);
+
+echo "\n";
+
+echo "Dump of the response ";
+print_r($response);
+
+pfpro_cleanup()
+
+?>