Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/recipe-fiddle.git
<?php
namespace com\whitemagicsoftware;

require_once( 'stripe/lib/Stripe.php' );

use Stripe;
use Stripe_Charge;

use Stripe_ApiConnectionError;
use Stripe_AuthenticationError;
use Stripe_CardError;
use Stripe_Error;
use Stripe_InvalidRequestError;

/**
 * Abstracts the payment process.
 */
class Payment extends Obj {
  // Secure token obtained client-side.
  private $token;

  // Email address used for the transaction.
  private $email;

  // Number of recipes selected by the user.
  private $tally;

  // Amount owing calculated by client (insecure).
  private $clientTotal;

  /**
   * Configures the payment system.
   */
  function __construct() {
    parent::__construct();

    global $PURCHASE_KEY_PRIVATE;
    global $PURCHASE_KEY_PUBLIC;

    $stripe = array(
      "secret_key"      => $PURCHASE_KEY_PRIVATE,
      "publishable_key" => $PURCHASE_KEY_PUBLIC
    );

    Stripe::setApiKey( $stripe['secret_key'] );
  }

  /**
   * Accepts a payment using a given token.
   *
   * @return true iff the charge went through successfully.
   */
  public function accept() {
    global $PURCHASE_PRICE_BASE;
    global $PURCHASE_PRICE_PROVIDER_BASE;

    $baseCost = $PURCHASE_PRICE_BASE + $PURCHASE_PRICE_PROVIDER_BASE;

    // Assume the charge failed.
    $result = false;

    $tally = $this->getTally();

    // Must have selected at least one recipe...
    if( isset( $tally ) && is_int( $tally ) && $tally > 0 ) {
      // These are set client-side from the Stripe callback.
      $token = $this->getToken();
      $email = $this->getEmail();

      // This is also set client-side and is insecure.
      $price = $this->getClientTotal();

      if( isset( $token ) && isset( $email ) && isset( $price ) ) {
        global $PURCHASE_PRICE_MULTIPLIER;

        $total = $baseCost + ($PURCHASE_PRICE_MULTIPLIER * $tally);

        // All the parameters indicate the payment should proceed.
        if( $price == $total ) {
          $result = $this->charge( $token, $email, $total );
        }
      }
    }

    return $result;
  }

  /**
   * Called to charge a credit card. The values must be validated prior
   * to calling this method.
   *
   * @param $token A token supplied by the payment service provider.
   * @param $token An email address supplied by the user.
   * @param $amount The total amount to charge (in pennies).
   */
  private function charge( $token, $email, $amount ) {
    global $PURCHASE_PRICE_CURRENCY;
    $result = false;

    //$this->log( "token: $token; email: $email; amount: $amount" );

    try {
      $charge = Stripe_Charge::create(
        array(
          "amount" => $amount,
          "currency" => $PURCHASE_PRICE_CURRENCY,
          "card" => $token,
          "description" => "$email"
        )
      );

      $result = true;
    }
    catch( Stripe_CardError $ex ) {
      $this->log( $ex );
    }
    catch( Stripe_InvalidRequestError $ex ) {
      $this->log( $ex );
    }
    catch( Stripe_AuthenticationError $ex ) {
      $this->log( $ex );
    }
    catch( Stripe_ApiConnectionError $ex ) {
      $this->log( $ex );
    }
    catch( Stripe_Error $ex ) {
      $this->log( $ex );
    }
    catch( Exception $ex ) {
      // Not Stripe-related...
      $this->log( $ex );
    }

    return $result;
  }

  /**
   * Sets the token.
   */
  public function setToken( $token ) {
    $this->token = $token;
  }

  private function getToken() {
    return $this->token;
  }

  /**
   * Sets the email address used in the payment.
   *
   * @param $email The user's email address (will receive a receipt).
   */
  public function setEmail( $email ) {
    $this->email = $email;
  }

  /**
   * Returns the email address used when making the payment.
   */
  private function getEmail() {
    return $this->email;
  }

  /**
   * Sets a count of the number of recipes (this must come from the server,
   * not the client).
   */
  public function setTally( $tally ) {
    $this->tally = $tally;
  }

  /**
   * Returns the number of recipes (calculated server-side from HTTP POST
   * data).
   */
  private function getTally() {
    return $this->tally;
  }

  /**
   * Sets the amount that the client imagines the book will cost. This
   * is insecure data and must match the calculated server total.
   */
  public function setClientTotal( $clientTotal ) {
    $this->clientTotal = $clientTotal;
  }

  /**
   * Returns the total amount set by the client. This is insecure.
   *
   * @return An insecure amount that must be checked against the server
   * calculation.
   */
  private function getClientTotal() {
    return $this->clientTotal;
  }
}