浏览代码

Initial Commit

Ben 7 年之前
当前提交
d4e24fea1a
共有 5 个文件被更改,包括 252 次插入0 次删除
  1. 8 0
      .gitignore
  2. 69 0
      PHP/TOTP.php
  3. 89 0
      PHP/dancecampsPayment.class.php
  4. 77 0
      PHP/payment-test.php
  5. 9 0
      readme.md

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
1
+.idea
2
+.settings
3
+.buildpath
4
+.project
5
+/**/._*
6
+/**/.DS_Store
7
+/**/[Tt]humbs.db
8
+/**/*~

+ 69 - 0
PHP/TOTP.php

@@ -0,0 +1,69 @@
1
+<?php
2
+/*
3
+    TOTP v0.2.1 - a simple TOTP (RFC 6238) class using the SHA1 default
4
+    (c) 2014 Robin Leffmann <djinn at stolendata dot net>
5
+    https://github.com/stolendata/totp/
6
+    Licensed under CC BY-NC-SA 4.0 - http://creativecommons.org/licenses/by-nc-sa/4.0/
7
+*/
8
+class TOTP
9
+{
10
+    private static $base32Map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
11
+    private static function base32Decode( $in )
12
+    {
13
+        $out = "";
14
+        $l = strlen( $in );
15
+        $n = $bs = 0;
16
+        for( $i = 0; $i < $l; $i++ )
17
+        {
18
+            $n <<= 5;
19
+            $n += stripos( self::$base32Map, $in[$i] );
20
+            $bs = ( $bs + 5 ) % 8;
21
+            $out .= $bs < 5 ? chr( ($n & (255 << $bs)) >> $bs ) : null;
22
+        }
23
+        return $out;
24
+    }
25
+    public static function getOTP( $secret, $digits = 6, $period = 30, $offset = 0 )
26
+    {
27
+        if( strlen($secret) < 16 || strlen($secret) % 8 != 0 )
28
+            return [ 'err'=>'length of secret must be a multiple of 8, and at least 16 characters' ];
29
+        if( preg_match('/[^a-z2-7]/i', $secret) === 1 )
30
+            return [ 'err'=>'secret contains non-base32 characters' ];
31
+        $digits = intval( $digits );
32
+        if( $digits < 6 || $digits > 8 )
33
+            return [ 'err'=>'digits must be 6, 7 or 8' ];
34
+        $seed = self::base32Decode( $secret );
35
+        $time = str_pad( pack('N', intval($offset + time() / $period)), 8, "\x00", STR_PAD_LEFT );
36
+        $hash = hash_hmac( 'sha1', $time, $seed, false );
37
+        $otp = ( hexdec(substr($hash, hexdec($hash[39]) * 2, 8)) & 0x7fffffff ) % pow( 10, $digits );
38
+        return [ 'otp'=>sprintf("%'0{$digits}u", $otp) ];
39
+    }
40
+    public static function genSecret( $length = 24 )
41
+    {
42
+        if( $length < 16 || $length % 8 !== 0 )
43
+            return [ 'err'=>'length must be a multiple of 8, and at least 16' ];
44
+        $secret = "";
45
+        while( $length-- )
46
+        {
47
+            $c = @gettimeofday()['usec'] % 53;
48
+            while( $c-- )
49
+                mt_rand();
50
+            $secret .= self::$base32Map[mt_rand(0, 31)];
51
+        }
52
+        return [ 'secret'=>$secret ];
53
+    }
54
+    public static function genURI( $account, $secret, $digits = null, $period = null, $issuer = null )
55
+    {
56
+        if( empty($account) || empty($secret) )
57
+            return [ 'err'=>'you must provide at least an account and a secret' ];
58
+        if( mb_strpos($account . $issuer, ':') !== false )
59
+            return [ 'err'=>'neither account nor issuer can contain a colon (:) character' ];
60
+        $account = rawurlencode( $account );
61
+        $issuer = rawurlencode( $issuer );
62
+        $label = empty( $issuer ) ? $account : "$issuer:$account";
63
+        return [ 'uri'=>'otpauth://totp/' . $label . "?secret=$secret" .
64
+            (is_null($digits) ? '' : "&digits=$digits") .
65
+            (is_null($period) ? '' : "&period=$period") .
66
+            (empty($issuer) ? '' : "&issuer=$issuer") ];
67
+    }
68
+}
69
+?>

+ 89 - 0
PHP/dancecampsPayment.class.php

@@ -0,0 +1,89 @@
1
+<?php
2
+namespace DANCECAMPS;
3
+include_once 'TOTP.php';
4
+
5
+class dancecampsPayment {
6
+    private $postdata = array();
7
+    private $url = "";
8
+    private $response = "";
9
+    private $lastError;
10
+
11
+    public function __construct($CampURL)
12
+    {
13
+        // Set the URL
14
+        $this->url=$CampURL."/payment-receive.php";
15
+    }
16
+
17
+    public function getLastError()
18
+    {
19
+        return $this->lastError;
20
+    }
21
+
22
+    public function sendPaymentToDanceCamps($BookingID, $APIToken, $Secret, $Result, $Amount, $Fee, $Currency, $TxnID, $Notes, $EmailNotes) {
23
+
24
+        // Get the token
25
+        $token=\TOTP::getOTP($Secret);
26
+
27
+        if (isset($token['error'])){
28
+            $this->setLastError("The secret is not valid");
29
+            return false;
30
+        }
31
+        if (!isset($token['otp']))
32
+        {
33
+            $this->setLastError("An error occurred getting the TOTP token");
34
+            return false;
35
+        }
36
+        else $token=$token['otp'];
37
+        
38
+        // Set the post data
39
+        
40
+        $this->postdata["BookingID"]=$BookingID;
41
+        $this->postdata["APIToken"]=$APIToken;
42
+        $this->postdata["Token"]=$token;
43
+        $this->postdata["Status"]=$Result;
44
+        $this->postdata["Amount"]=$Amount;
45
+        $this->postdata["Currency"]=$Currency;
46
+        $this->postdata["TxnID"]=$TxnID;
47
+        $this->postdata["FeeAmount"]=$Fee;
48
+        $this->postdata["Notes"]=$Notes;
49
+        $this->postdata["EmailNotes"]=$EmailNotes;
50
+
51
+        // Send
52
+        return $this->sendWithCURL();
53
+
54
+    }
55
+
56
+    public function getResponse()
57
+    {
58
+        return $this->response;
59
+    }
60
+
61
+    private function sendWithCURL() {
62
+        $ch = curl_init();
63
+
64
+        //curl_setopt($ch, CURLOPT_HEADER, true);
65
+        curl_setopt($ch, CURLOPT_URL,$this->url);
66
+        curl_setopt($ch, CURLOPT_POST, true);
67
+        curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($this->postdata));
68
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
69
+
70
+        $this->response = curl_exec($ch);
71
+        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
72
+
73
+
74
+        curl_close ($ch);
75
+        
76
+        if ($httpcode!=200) return false;
77
+        else {
78
+            $arr=json_decode($this->response, true);
79
+            if (isset($arr['status']) && $arr['status']==="success") return true;
80
+            else return false;
81
+        }
82
+    }
83
+
84
+    private function setLastError($msg)
85
+    {
86
+        $this->lastError=$msg;
87
+    }
88
+}
89
+?>

+ 77 - 0
PHP/payment-test.php

@@ -0,0 +1,77 @@
1
+<?php
2
+    /*
3
+     * This is a script for testing payments.
4
+     * Users will arrive here after having completed a booking.
5
+     * Depending on the config, this will simulate a completed or a failed payment
6
+     * and then return the user to their booking.
7
+     */
8
+
9
+    if ($_POST['Result'])
10
+    {
11
+
12
+        // This is the API key from the main setup page
13
+        define('API_TOKEN', '[paste your payment api token here]');
14
+
15
+        // This is the secret key from the payments API setup page on dancecamps.org
16
+        define('SECRET', '[paste your secret key here]');
17
+
18
+        // Include the PHP SDK
19
+        include_once 'dancecampsPayment.class.php';
20
+
21
+        $BookingID=$_POST['BookingID'];
22
+        $Amount=$_POST['Amount'];
23
+        $CampURL=$_POST['CampURL'];
24
+
25
+        // This is where a real payment would be made.
26
+        // Here will we just simulate the results
27
+        $Result=$_POST['Result'];
28
+        $Currency=$_POST['Currency'];
29
+        $TxnID=$_POST['TxnID'];
30
+        $Fee=$_POST['FeeAmount'];
31
+
32
+        // The payment was made, send the info to dancecamps.org
33
+        $obj = new \DANCECAMPS\dancecampsPayment($CampURL);
34
+        $apiSendResult = $obj->sendPaymentToDanceCamps($BookingID, API_TOKEN, SECRET, $Result, $Amount, $Fee, $Currency, $TxnID, "This is a simulated payment", "Your payment has been processed");
35
+
36
+        // Was the payment successful and was it succesfully sent to dancecamps.org?
37
+        // If so, send the user on to the success page. If not, send them to the fail
38
+        // page. In a real application, if the payment send to dancecamps.org failed,
39
+        // you may want to also send yourself an alert
40
+        if ($Result==="Completed" && $apiSendResult) header("Location: ".$CampURL."/payment-success.php");
41
+        else
42
+        {
43
+            // Maybe send an email to let me know something went wrong and let me fix it manually!
44
+            header("Location: ".$CampURL."/payment-fail.php?message=Simulated-Payment+Failed");
45
+        }
46
+        exit();
47
+    }
48
+    else
49
+    {
50
+        ?>
51
+<html>
52
+    <head>
53
+        <title>Test dancecamps payment via API</title>
54
+        <style>
55
+            label {
56
+                display: inline-block;
57
+                width: 130px;
58
+            }
59
+            </style>
60
+    </head>
61
+    <body>
62
+        <h1>Test dancecamps payment via API</h1>
63
+        <form action='payment-test.php' method='post'>
64
+            <input type="hidden" name="CampURL" value="<?php echo htmlentities($_POST['CampURL']); ?>">
65
+            <input type="hidden" name="BookingID" value="<?php echo $_POST['BookingID']; ?>">
66
+            <label for="Result">Result : </label><input name="Result" id="Result" value="Completed"><br>
67
+            <label for="Currency">Currency : </label><input name="Currency" id="Currency" value="USD"><br>
68
+            <label for="Amount">Amount : </label><input name="Amount" id="Amount" value="<?php echo $_POST["Amount"]; ?>"><br>
69
+            <label for="FeeAmount">Fee : </label><input name="FeeAmount" id="FeeAmount" value="<?php echo $_POST["Amount"]*0.02; ?>"><br>
70
+            <label for="TxnID">Transaction ID : </label><input name="TxnID" id="TxnID" value="<?php echo substr(base64_encode(hash("sha256", mt_rand(0,99999).microtime())), 0, 16); ?>"><br>
71
+            <input type="submit" value="Simulate Transaction">
72
+        </form>
73
+    </body>
74
+</html>
75
+<?php
76
+    }
77
+?>

+ 9 - 0
readme.md

@@ -0,0 +1,9 @@
1
+# dancecamps.org Payment API
2
+
3
+This repository contains SDKs and sample code for developers who wish to integrate new payment systems with dancecamps.org via the payment API.
4
+
5
+The repository is divided by language, currently PHP is the only language with an SDK and example. If you create SDKs in other langauges, please contribute to this repository to help other events. Make sure you don't include any tokens, keys or secrets!
6
+
7
+Additionally, please contribute any code that you create for specific payment processors. This should be placed in a folder with the processor name, within the relevant language folder. Make sure you don't include any tokens, keys or secrets!
8
+
9
+Integration instructions can be found on the Payment API setup page for your event.