This is an old revision of the document!
CakePHP Setup and Configuration
Configure for Use
- Edit
[cakephp]/app/Config/core.php
and modify the following:// A random string used in security hashing methods. Configure::write('Security.salt', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi'); // A random numeric string (digits only) used to encrypt/decrypt strings. Configure::write('Security.cipherSeed', '76859309657453542496749683645');
- For system-wide user-defined variables, edit
[cakephp]/app/Config/core.php
and add the following:/** //####################################################### //# User-defined system strings. //####################################################### Configure::write('Company.Name', 'Acme Inc.'); // Company Name Configure::write('Company.Email', 'info@acme.com'); // Company Email
Read a config variable using:
Configure::read('Company.Name')
Database Configuration
Edit file [cakephp]/app/Config/database.php
:
public $default = array( 'datasource' => 'Database/Mysql', 'persistent' => false, 'host' => 'localhost', 'port' => '', 'login' => 'acmeusr', 'password' => 'c4k3-rUl3Z', 'database' => 'acme_cakephp_db', 'schema' => '', 'prefix' => '', 'encoding' => 'utf8' );
Email Configuration
Edit file [cakephp]/app/Config/email.php
:
class EmailConfig { public $default = array( 'transport' => 'Mail', //'from' => Configure::read('Company.Email'), 'from' => 'info@acme.com', 'charset' => 'utf-8', 'headerCharset' => 'utf-8', ); public $smtp = array( 'transport' => 'Smtp', //'from' => array('site@localhost' => 'My Site'), //'from' => array(Configure::read('Company.Email') => Configure::read('Company.Name')), 'from' => array('info@acme.com' => 'Acme Inc'), 'host' => 'localhost', 'port' => 25, 'timeout' => 30, //'username' => 'user', //'password' => 'secret', 'username' => null, 'password' => null, 'client' => null, 'log' => false, 'charset' => 'utf-8', 'headerCharset' => 'utf-8', ); public $fast = array( //'from' => 'you@localhost', //'from' => Configure::read('Company.Email'), 'from' => 'info@acme.com', 'sender' => null, 'to' => null, 'cc' => null, 'bcc' => null, 'replyTo' => null, 'readReceipt' => null, 'returnPath' => null, 'messageId' => true, 'subject' => null, 'message' => null, 'headers' => null, 'viewRender' => null, 'template' => false, 'layout' => false, 'viewVars' => null, 'attachments' => null, 'emailFormat' => null, 'transport' => 'Smtp', 'host' => 'localhost', 'port' => 25, 'timeout' => 30, //'username' => 'user', //'password' => 'secret', 'username' => null, 'password' => null, 'client' => null, 'log' => true, 'charset' => 'utf-8', 'headerCharset' => 'utf-8', ); /* // To use this feature, you will need to have the SSL configured in your PHP install. public $gmail = array( 'host' => 'ssl://smtp.gmail.com', 'port' => 465, 'username' => 'my@gmail.com', 'password' => 'secret', 'transport' => 'Smtp' ); // or using TLS SMTP public $gmail = array( 'host' => 'smtp.gmail.com', 'port' => 465, 'username' => 'my@gmail.com', 'password' => 'secret', 'transport' => 'Smtp', 'tls' => true ); */ }
Setup AppController
Edit file [cakephp]/app/Controller/AppController.php
:
App::uses('Controller', 'Controller'); App::uses('SessionComponent', 'Controller/Component'); App::uses('SessionHelper', 'Controller/Component'); App::uses('AuthHelper ', 'Controller/Component'); class AppController extends Controller { public $components = array( 'Session', 'Auth' => array( //'loginRedirect' => array('controller' => 'articles', 'action' => 'index'), // at login, go to Articles list 'loginRedirect' => array('controller' => 'pages', 'action' => 'display', 'home'), // at login, go to Home //'logoutRedirect' => array('controller' => 'users', 'action' => 'login'), 'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home'), // at logout, go to Home 'authError' => 'You must be logged in to view this page.', 'loginError' => 'Invalid Username or Password entered, please try again.', 'authorize' => array('Controller') ), 'DebugKit.Toolbar', // see https://github.com/cakephp/debug_kit for more details ); // only allow the login controllers only public function beforeFilter() { $this->Auth->allow('login'); } public function isAuthorized($user) { // Here is where we should verify the role and give access based on role //return true; // Admin can access every action if (isset($user['role']) && $user['role'] === 'admin') { return true; } // Default deny return false; } }
Setup UserController
Edit file [cakephp]/app/Config/routes.php
to include custome routes:
// ###--- Custom Routes ---### // Let us modify the core components of CakePHP to support the UserController login module. // First, we need to modify routes.php so that we can have a custom link for login, logout // and the dashboard. This step is not required but I do it so that the URLs look clean. Router::connect('/dashboard', array('controller' => 'users', 'action' => 'index')); Router::connect('/login', array('controller' => 'users', 'action' => 'login')); Router::connect('/logout', array('controller' => 'users', 'action' => 'logout')); // We also need to modify the home page so that it now points to the UserController login action. //Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); // default Router::connect('/', array('controller' => 'users', 'action' => 'login'));
Install Basic Components/Plugins
DebugKit
- Download
DebugKit
from here: https://github.com/cakephp/debug_kit - Unpack to
[cakephp]/app/Plugin
directory. - Edit
[cakephp]/app/Config/bootstrap.php
and uncomment the following:CakePlugin::loadAll(); // Loads all plugins at once (optional) CakePlugin::load('DebugKit');
- Edit
[cakephp]/app/Config/core.php
and uncomment one of the following://Configure::write('debug', 0); // for production mode Configure::write('debug', 1); // for development mode //Configure::write('debug', 2); // for development mode (with sql dump)
- Include the toolbar component in your
[cakephp]/app/Controller/AppController.php
:class AppController extends Controller { public $components = array('DebugKit.Toolbar', ...); ... }
Articles
- Articles Component: http://book.cakephp.org/2.0/en/getting-started.html#blog-tutorial
Authentication
- Authentication Component: http://book.cakephp.org/2.0/en/tutorials-and-examples/blog-auth-example/auth.html
AuthorizeNetComponent
- Include the following file
[cakephp/app/Controller/Component/AuthorizeNetComponent.php]
:<?php // Source: http://bakery.cakephp.org/articles/gstoner/2008/03/12/authorize-net-aim-integration-component //class AuthorizeNetComponent extends Object // used in cakephp 1.x class AuthorizeNetComponent extends Component { // Created by: Graydon Stoner - www.getstonered.com // Upgraded to CakePHP 2.x by: Siegwart Mayr // Added functionality: Siegwart Mayr //////////// Controller Usage \\\\\\\\\\\\\ /* class MyController extends AppController { var $name = 'MyController'; $components = array('AuthorizeNet', ...); ... function chargeCard() { // You would need to add in necessary information here from your data collector $billinginfo = array("fname" => "First", "lname" => "Last", "company" => "Acme Inc.", "address" => "123 Fake St. Suite 0", "city" => "City", "state" => "ST", "zip" => "90210", "country" => "USA"); $shippinginfo = array("fname" => "First", "lname" => "Last", "company" => "Acme Inc.", "address" => "123 Fake St. Suite 0", "city" => "City", "state" => "ST", "zip" => "90210", "country" => "USA"); $response = $this->AuthorizeNet->chargeCard('########', '##############', '4111111111111111', '01', '2010', '123', true, 110, 5, 5, "Purchase of Goods", $billinginfo, "customeremail@example.com", "555-555-5555", $shippinginfo, 'INV123', false); $response:Array = $this->AuthorizeNet->chargeCard($loginid:String, $trankey:String, $ccnum:String, $ccexpmonth:String, $ccexpyear:String, $ccver:String, $live:Boolean, $amount:Number, $tax:Number, $shipping:Number, $desc:String, $billinginfo:Array, $email:String, $phone:String, $shippinginfo:Array, $invoicenum:String, $testmode:Boolean); } } ////////// USAGE NOTES \\\\\\\\\\\\ PARAMETERS $loginid : Your Authorize.net Login ID $trankey : Your Authorize.net Transaction Key $ccnum : The system removes any spaces in the string to meet Authorize.net requirements $ccexpmonth : 2 digit month string $ccexpyear : 2 or 4 digit year string $ccver : The 3 or 4 digit card verificaton code found on the back of Visa/Mastercard and the front of AmEx $live : Whether to process as a live or test transaction - true : Live Transcation - false : Test Transaction $amount : Total amount of the transaction. This must include both tax and shipping if applicable. $tax : Tax amount charged (if any) $shipping : Shipping cost (if any) $desc : Description of the transaction to be logged into Authorize.net system $billinginfo : Associative Array containing values for customer billing details $email : Customer email $phone : Customer phone $billinginfo : Associative Array containing values for customer shipping details $invoicenum : The merchant-assigned invoice number for the transaction $testmode : transaction is a test (true) or not (false). Use Visa test credit card number “4222222222222”, and to test the AVS response reason code (eg. number 27), submit the test transaction with the credit card number “4222222222222” and the amount matching the AVS code (eg “27.00.”) RESPONSE $response : Array (1 based) containing the Payment Gateway Reasons fields // Important Response Values $response[1] = Response Code (1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review) $response[2] = Response Subcode (Code used for Internal Transaction Details) $response[3] = Response Reason Code (Code detailing response code) $response[4] = Response Reason Text (Text detailing response code and response reason code) $response[5] = Authorization Code (Authorization or approval code - 6 characters) $response[6] = AVS Response (Address Verification Service response code - A, B, E, G, N, P, R, S, U, W, X, Y, Z) (A, P, W, X, Y, Z are default AVS confirmation settings - Use your Authorize.net Merchant Interface to change these settings) (B, E, G, N, R, S, U are default AVS rejection settings - Use your Authorize.net Merchant Interface to change these settings) $response[7] = Transaction ID (Gateway assigned id number for the transaction) $response[8] = Transaction Invoice Number (Merchant assigned invoice number for the transaction) $response[9] = Transaction Description (Merchant assigned description for the transaction) $response[10] = Transaction Amount (Merchant assigned amount for the transaction) $response[11] = Payment method (CC, ECHECK) $response[12] = Transaction type (AUTH_CAPTURE, AUTH_ONLY, CAPTURE_ONLY, CREDIT, PRIOR_AUTH_CAPTUREVOID) $response[13] = Customer ID (Merchant-assigned) $response[14] = First name associated with the customer’s billing address $response[15] = Last name associated with the customer’s billing address $response[16] = Company associated with the customer’s billing address $response[17] = Street for customer’s billing address $response[18] = City for customer’s billing address $response[19] = State for customer’s billing address $response[20] = ZIP Code for customer’s billing address $response[21] = Country for customer’s billing address $response[22] = Phone for customer’s billing address $response[23] = Fax for customer’s billing address $response[24] = Email $response[25] = First name for shipping address $response[26] = Last name for shipping address $response[27] = Company name for shipping address $response[28] = Street for shipping address $response[29] = City for shipping address $response[30] = State for shipping address $response[31] = ZIP Code for shipping address $response[32] = Country for shipping address $response[33] = Tax $response[34] = Duty $response[35] = Freight $response[36] = Tax Exempt $response[37] = Purchase Order Number $response[38] = MD5 Hash (Gateway generated MD5 has used to authenticate transaction response) $response[39] = Card Code Response (CCV Card Code Verification response code: M = Match, N = No Match, P = No Processed, S = Should have been present, U = Issuer unable to process request) $response[40] = Cardholder Authentication Verification Response $response[51] = Account Number (Last 4-digits Cr Card Number with XXXX prefix) $response[52] = Card Type (Visa, MasterCard, American Express, Discover) $response[53] = Split Tender ID $response[54] = Requested Amount $response[55] = Balance on card For more information about the Authorize.net AIM response consult their AIM Implementation Guide at http://developer.authorize.net/guides/AIM/ and go to Section Four : Fields in the Payment Gateway Response for more details. NOTES This component is meant to abstract payment processing on a website. As varying sites require different requirements for information, security, or card processing (like changing Address Verification requirement) the component does not try to provide any logic to determine if a transaction was successful. It is up to the user implementing this code to process the response array and provide response accordingly. */ // class variables go here public $arrLastResponse = array(); //--------------------------------------------------------------------------------------------- // description: // parameters : // return : //--------------------------------------------------------------------------------------------- // function startup(&$controller) // used in cakephp 1.x function startup(Controller $controller) { parent::startup($controller); // This method takes a reference to the controller which is loading it. // Perform controller initialization here. $this->arrLastResponse = array(); } //--------------------------------------------------------------------------------------------- // description: Charge credit card with the specified data. // parameters : $loginid, $trankey, $ccnum, $ccexpmonth, $ccexpyear, $ccver, $live, // $amount, $tax, $shipping, $desc, $billinginfo, $email, $phone, $shippinginfo, $invoicenum, $testmode // return : $responsearray //--------------------------------------------------------------------------------------------- function chargeCard($loginid, $trankey, $ccnum, $ccexpmonth, $ccexpyear, $ccver, $live, $amount, $tax, $shipping, $desc, $billinginfo, $email, $phone, $shippinginfo, $invoicenum, $testmode) { // setup variables $ccexp = $ccexpmonth . '/' . $ccexpyear; $DEBUGGING = 1; # Display additional information to track down problems $TESTING = 1; # Set the testing flag so that transactions are not live $ERROR_RETRIES = 2; # Number of transactions to post if soft errors occur $auth_net_login_id = $loginid; $auth_net_tran_key = $trankey; ### Uncomment the appropriate line for test or live merchant accounts //$auth_net_url = "https://certification.authorize.net/gateway/transact.dll"; // test account $auth_net_url = "https://secure.authorize.net/gateway/transact.dll"; // live account $authnet_values = array( "x_login" => $auth_net_login_id, "x_version" => "3.1", "x_delim_char" => "|", "x_delim_data" => "TRUE", "x_url" => "FALSE", "x_type" => "AUTH_CAPTURE", "x_method" => "CC", "x_tran_key" => $auth_net_tran_key, "x_relay_response" => "FALSE", "x_card_num" => str_replace(" ", "", $ccnum), "x_card_code" => $ccver, "x_exp_date" => $ccexp, "x_description" => $desc, "x_amount" => $amount, "x_tax" => $tax, "x_freight" => $shipping, "x_first_name" => $billinginfo["fname"], "x_last_name" => $billinginfo["lname"], "x_company" => $billinginfo["company"], "x_address" => $billinginfo["address"], "x_city" => $billinginfo["city"], "x_state" => $billinginfo["state"], "x_zip" => $billinginfo["zip"], "x_country" => $billinginfo["country"], "x_email" => $email, "x_phone" => $phone, "x_ship_to_first_name" => $shippinginfo["fname"], "x_ship_to_last_name" => $shippinginfo["lname"], "x_ship_to_company" => $shippinginfo["company"], "x_ship_to_address" => $shippinginfo["address"], "x_ship_to_city" => $shippinginfo["city"], "x_ship_to_state" => $shippinginfo["state"], "x_ship_to_zip" => $shippinginfo["zip"], "x_ship_to_country" => $shippinginfo["country"], "x_invoice_num" => $invoicenum, "x_test_request" => ($ccnum == '4222222222222' ? true : $testmode), // always set testmode on when using test cr card number ); $fields = ""; foreach ( $authnet_values as $key => $value ) $fields .= "$key=" . urlencode( $value ) . "&"; /////////////////////////////////////////////////////////// // Post the transaction (see the code for specific information) ### Uncomment the appropriate line BELOW for test or live merchant accounts //$ch = curl_init("https://certification.authorize.net/gateway/transact.dll"); // test account $ch = curl_init("https://secure.authorize.net/gateway/transact.dll"); // live account //curl_setopt($ch, CURLOPT_URL, "https://secure.authorize.net/gateway/transact.dll"); curl_setopt($ch, CURLOPT_HEADER, 0); // set to 0 to eliminate header info from response curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // Returns response data instead of TRUE(1) curl_setopt($ch, CURLOPT_POSTFIELDS, rtrim( $fields, "& " )); // use HTTP POST to send form data ### Go Daddy Specific CURL Options //curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, true); //curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); //curl_setopt($ch, CURLOPT_PROXY, 'http://proxy.shr.secureserver.net:3128'); //curl_setopt($ch, CURLOPT_TIMEOUT, 120); ### End Go Daddy Specific CURL Options curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // uncomment this line if you get no gateway response. ### $resp = curl_exec($ch); // execute post and get results curl_close ($ch); // Parse through response string $text = $resp; $h = substr_count($text, "|"); $h++; $responsearray = array(); for($j=1; $j <= $h; $j++) { $p = strpos($text, "|"); if ($p === false) // note: three equal signs { // x_delim_char is obviously not found in the last go-around // This is final response string $responsearray[$j] = $text; } else { $p++; // get one portion of the response at a time $pstr = substr($text, 0, $p); // This prepares the text and returns one value of the submitted // and processed name/value pairs at a time. // For AIM-specific interpretations of the responses, // please consult the AuthorizeNet AIM Guide, and look up // the section called Gateway Response API. $pstr_trimmed = substr($pstr, 0, -1); // removes "|" at the end if($pstr_trimmed=="") { $pstr_trimmed=""; } $responsearray[$j] = $pstr_trimmed; // remove the part that we identified and work with the rest of the string $text = substr($text, $p); } // end if $p === false } // end parsing for loop $this->arrLastResponse = $responsearray; //print_r($responsearray); // debug return $responsearray; } // end chargeCard function //--------------------------------------------------------------------------------------------- // description: // parameters : // return : //--------------------------------------------------------------------------------------------- function testChargeCard() { $billinginfo = array("fname" => "John", "lname" => "Doe", "company" => "Acme Inc.", "address" => "123 Fake St. Suite 0", "city" => "Longwood", "state" => "FL", "zip" => "32750", "country" => "United States"); $shippinginfo = array("fname" => "John", "lname" => "Doe", "company" => "Acme Inc.", "address" => "123 Fake St. Suite 0", "city" => "Longwood", "state" => "FL", "zip" => "32750", "country" => "United States"); //$loginid = '92a6ZYS8Mhn'; // AuthorizeNet API login ID //$trankey = '6CG8xU3ZB346WjhU'; // AuthorizeNet Transaction Key $loginid = Configure::read('Company.AuthorizeNetLoginID'); // AuthorizeNet API login ID $trankey = Configure::read('Company.AuthorizeNetTransKey'); // AuthorizeNet Transaction Key $ccnum = '4222222222222'; // Visa test number $ccexpmonth = '12'; $ccexpyear = '2014'; $ccver = '123'; $live = false; $amount = '1.00'; // amount to charge. NOTE: In testmode, the amount is the code to use for testing the response reason. // For example, for response reason code number 27 (AVS address mismatch), submit the test transaction with // the credit card number '4222222222222' and the amount '27.00.' $tax = '0.00'; // tax charge $shipping = '0.00'; // shipping charge $desc = 'Workshop Registration: FL_2014'; $email = Configure::read('Workshop.Payment.NotificationEmailRecipientsForTest'); // Eg: 'smayr@acme.com'; $phone = '407-333-4444'; $invoicenum = 'INV123'; $testmode = true; // Method (x_method): CC // Transaction Type (x_type): auth_capture // Customer ID (x_cust_id): FL0077 // Company (x_company): Acme $responsearray = $this->chargeCard($loginid, $trankey, $ccnum, $ccexpmonth, $ccexpyear, $ccver, $live, $amount, $tax, $shipping, $desc, $billinginfo, $email, $phone, $shippinginfo, $invoicenum, $testmode); //print_r($responsearray); // debug return $responsearray; } //--------------------------------------------------------------------------------------------- // description: // parameters : // return : //--------------------------------------------------------------------------------------------- function GetResponseStr($idx) { if ($this->arrLastResponse != null) { switch($idx) { case 1: // Response Code $msg = 'Credit Card Transaction Response: '; switch($this->arrLastResponse[1]) { case 1: $msg .= 'Approved'; break; case 2: $msg .= 'Declined'; break; case 3: $msg .= 'Error'; break; case 4: $msg .= 'Held for Review'; break; default: $msg .= 'Error'; break; } $msg .= ' (Reason Code ' . $this->arrLastResponse[3] . '). <br>' . $this->arrLastResponse[4]; // Response Reason Code (3) and Text (4) break; case 6: // Address Verification Service (AVS) response: // (A, P, W, X, Y, Z are default AVS confirmation settings) // (B, E, G, N, R, S, U are default AVS rejection settings) // A = Address (Street) matches, ZIP does not // B = Address information not provided for AVS check // E = AVS error // G = Non-U.S. Card Issuing Bank // N = No Match on Address (Street) or ZIP // P = AVS not applicable for this transaction // R = Retry—System unavailable or timed out // S = Service not supported by issuer // U = Address information is unavailable // W = Nine digit ZIP matches, Address (Street) does not // X = Address (Street) and nine digit ZIP match // Y = Address (Street) and five digit ZIP match // Z = Five digit ZIP matches, Address (Street) does not $msg = 'Address verification: '; switch($this->arrLastResponse[6]) { case 'A': $msg .= 'Address (Street) matches, ZIP does not.'; break; case 'B': $msg .= 'Address information not provided for AVS check.'; break; case 'E': $msg .= 'AVS error.'; break; case 'G': $msg .= 'Non-U.S. Card Issuing Bank.'; break; case 'N': $msg .= 'No Match on Address (Street) or ZIP.'; break; case 'P': $msg = ''; break; // Clear message since AVS is not applicable here //$msg .= 'AVS not applicable for this transaction.'; break; case 'R': $msg .= 'Retry—System unavailable or timed out.'; break; case 'S': $msg .= 'Service not supported by issuer.'; break; case 'U': $msg .= 'Address information is unavailable.'; break; case 'W': $msg .= 'Nine digit ZIP matches, Address (Street) does not.'; break; case 'X': $msg .= 'Address (Street) and nine digit ZIP match.'; break; case 'Y': $msg .= 'Address (Street) and five digit ZIP match.'; break; case 'Z': $msg .= 'Five digit ZIP matches, Address (Street) does not.'; break; default: $msg = ''; break; // clear message } break; case 39: // Card Code Verification (CCV) response code: // M = Match, N = No Match, P = No Processed, S = Should have been present, U = Issuer unable to process request $msg = 'Card Code Verification (CCV) Response: '; switch($this->arrLastResponse[39]) { case 'M': $msg = ''; break; // clear message since it is a match //$msg .= 'Match.'; break; case 'N': $msg .= 'No Match.'; break; case 'P': $msg .= 'Not Processed.'; break; case 'S': $msg .= 'Should have been present.'; break; case 'U': $msg .= 'Issuer unable to process request.'; break; default: $msg = ''; break; // clear message } break; case 40: // $response[40] = Cardholder Authentication Verification (CAVV) Response // Value: The cardholder authentication verification response code // Format: Blank or not present = CAVV not validated // - 0 = CAVV not validated because erroneous data was submitted // - 1 = CAVV failed validation // - 2 = CAVV passed validation // - 3 = CAVV validation could not be performed; issuer attempt incomplete // - 4 = CAVV validation could not be performed; issuer system error // - 5 = Reserved for future use // - 6 = Reserved for future use // - 7 = CAVV attempt – failed validation – issuer available (U.S.-issued card/non-U.S acquirer) // - 8 = CAVV attempt – passed validation – issuer available (U.S.-issued card/non-U.S. acquirer) // - 9 = CAVV attempt – failed validation – issuer unavailable (U.S.-issued card/non-U.S. acquirer) // - A = CAVV attempt – passed validation – issuer unavailable (U.S.-issued card/non-U.S. acquirer) // - B = CAVV passed validation, information only, no liability shift $msg = 'Cardholder Authentication Verification (CAVV) Response: '; switch($this->arrLastResponse[40]) { case '0': $msg .= 'CAVV not validated because erroneous data was submitted.'; break; case '1': $msg .= 'CAVV failed validation.'; break; case '2': $msg .= 'CAVV passed validation'; break; case '3': $msg .= 'CAVV validation could not be performed; issuer attempt incomplete'; break; case '4': $msg .= 'CAVV validation could not be performed; issuer system error'; break; case '5': $msg .= 'Reserved for future use'; break; case '6': $msg .= 'Reserved for future use'; break; case '7': $msg .= 'CAVV attempt – failed validation – issuer available (U.S.-issued card/non-U.S acquirer)'; break; case '8': $msg .= 'CAVV attempt – passed validation – issuer available (U.S.-issued card/non-U.S. acquirer)'; break; case '9': $msg .= 'CAVV attempt – failed validation – issuer unavailable (U.S.-issued card/non-U.S. acquirer)'; break; case 'A': $msg .= 'CAVV attempt – passed validation – issuer unavailable (U.S.-issued card/non-U.S. acquirer)'; break; case 'B': $msg .= 'CAVV passed validation, information only, no liability shift'; break; default: $msg = ''; break; // clear message } break; case 51: $msg = 'Credit Card Number: ' . $this->arrLastResponse[51] . '. '; break; default: $msg = ''; } } return $msg; } } ?>
Add component references to the controller using it:
<?php class MyController extends AppController { var $name = 'MyController'; $components = array('AuthorizeNet', ...); ... } ?>
Use it. Call the component from the controller needing it:
<?php class MyController extends AppController { ... function chargeCard() { // You would need to add in necessary information here from your data collector $billinginfo = array("fname" => "First", "lname" => "Last", "company" => "Acme Inc.", "address" => "123 Fake St. Suite 0", "city" => "City", "state" => "ST", "zip" => "90210", "country" => "USA"); $shippinginfo = array("fname" => "First", "lname" => "Last", "company" => "Acme Inc.", "address" => "123 Fake St. Suite 0", "city" => "City", "state" => "ST", "zip" => "90210", "country" => "USA"); $response = $this->AuthorizeNet->chargeCard('########', '##############', '4111111111111111', '01', '2010', '123', true, 110, 5, 5, "PurchaseofGoods", $billinginfo, "customeremail@example.com", 555-5555", $shippinginfo); } } ?>
The call to the component function chargeCard uses the following format:
$response:Array = $this->AuthorizeNet->chargeCard($loginid:String, $trankey:String, $ccnum:String, $ccexpmonth:String, $ccexpyear:String, $ccver:String, $live:Boolean, $amount:Number, $tax:Number, $shipping:Number, $desc:String, $billinginfo:Array, $email:String, $phone:String, $shippinginfo:Array);
PARAMETERS
- $loginid : Your Authorize.net Login ID
- $trankey : Your Authorize.net Transaction Key
- $ccnum : The system removes any spaces in the string to meet Authorize.net requirements
- $ccexpmonth : 2 digit month string
- $ccexpyear : 2 or 4 digit year string
- $ccver : The 3 or 4 digit card verificaton code found on the back of Visa/Mastercard and the front of AmEx
- $live : Whether to process as a live or test transaction - true : Live Transcation - false : Test Transaction
- $amount : Total amount of the transaction. This must include both tax and shipping if applicable.
- $tax : Tax amount charged (if any)
- $shipping : Shipping cost (if any)
- $desc : Description of the transaction to be logged into Authorize.net system
- $billinginfo : Associative Array containing values for customer billing details
- $email : Customer email
- $phone : Customer phone
- $billinginfo : Associative Array containing values for customer shipping details
RESPONSE
- $response : Array (1 based) containing the Payment Gateway Resonse fields
The response is an array of all the response codes from Authorize.net's system. Details on all these responses is available at http://developer.authorize.net/guides/AIM/. Here are some of the most important fields:
$response[1] = Response Code (1 = Approved, 2 = Declined, 3 = Error, 4 = Held for Review) $response[2] = Response Subcode (Code used for Internal Transaction Details) $response[3] = Response Reason Code (Code detailing response code) $response[4] = Response Reason Text (Text detailing response code and response reason code) $response[5] = Authorization Code (Authorization or approval code - 6 characters) $response[6] = AVS Response (Address Verification Service response code - A, B, E, G, N, P, R, S, U, W, X, Y, Z) (A, P, W, X, Y, Z are default AVS confirmation settings - Use your Authorize.net Merchant Interface to change these settings) (B, E, G, N, R, S, U are default AVS rejection settings - Use your Authorize.net Merchant Interface to change these settings) $response[7] = Transaction ID (Gateway assigned id number for the transaction) $response[38] = MD5 Hash (Gateway generated MD5 has used to authenticate transaction response) $response[39] = Card Code Response (CCV Card Code Verification response code - M = Match, N = No Match, P = No Processed, S = Should have been present, U = Issuer unable to process request)
TCPDF
- Download TCPDF and unzip.
- Move folder to
[cakephp]/app/Vendor/tcpdf
- Create
[cakephp]/app/Vendor/xtcpdf.php
(see http://www.martin-schenk.es/en/cakephp-2-pdf-with-tcpdf):<?php App::import('Vendor','tcpdf/tcpdf'); class XTCPDF extends TCPDF { } ?>
- Create
[cakephp]app/View/Layouts/pdf/default.ctp
:<?php header("Content-type: application/pdf"); echo $content_for_layout; ?>
- In your Controller, for example in
[cakephp]/app/Controller/ArticlesController.php
, create a new action:public function create_pdf() { $users = $this->User->find('all'); $this->set(compact('users')); $this->layout = '/pdf/default'; $this->render('/Pdf/my_pdf_view'); }
- Create a new view file
[cakephp]/app/View/Pdf/my_pdf_view.ctp
:<?php App::import('Vendor','xtcpdf'); $pdf = new XTCPDF('L', PDF_UNIT, 'A4', true, 'UTF-8', false); $pdf--->AddPage(); $html = '</pre> <h1>hello world</h1> <pre>'; foreach ( $posts as $post ){ $html .= "\n<br/>" . $post['Post']['title']; } $pdf->writeHTML($html, true, false, true, false, ''); $pdf->lastPage(); echo $pdf->Output(APP . 'files/pdf' . DS . 'test.pdf', 'I' /* Dest: F = File to disk, I = Inline to browser */); ?>
For example:
- In controller, generate the data and call PDF generator:
//--------------------------------------------------------------------------------------------- // description: Generate packet labels form. // parameters : // return : //--------------------------------------------------------------------------------------------- public function GenFormPacketLabels($aWorkshopCode, $aContentType="attendees", $id=0) { $this->GenFormData($aWorkshopCode, $aContentType, $id); $this->SetFormDimensions("PacketLabels"); } //--------------------------------------------------------------------------------------------- // description: Generate course evaluation form. // parameters : // return : //--------------------------------------------------------------------------------------------- private function GenFormData($aWorkshopCode, $aContentType="attendees", $id=0) { $attendees = array(); $this->set('attendees', $attendees); // Get workshop data if (!empty($aWorkshopCode)) { $workshop = ClassRegistry::init('Workshop')->find('first', array( 'conditions' => array('Workshop.Code' => $aWorkshopCode), 'recursive' => 0, )); if (!$workshop) { throw new NotFoundException(__('Invalid workshop')); } } $this->set('workshop', $workshop); // Generate PDF report with custom data if ($this->request->is('post')) { if ($this->request->data) { // Get custom name tag data $attendees = $this->GenAttendeeRec($aWorkshopCode, $this->request->data); $this->set('attendees', $attendees); // Set Header Response to PDF content type $this->layout = '/pdf/default'; $this->response->type('application/pdf'); $this->render('/MyEntity/genlabels'); } } } //--------------------------------------------------------------------------------------------- // description: Set form dimensions. // parameters : $aTemplateType - Template type (string) to use: PacketLabels, MailingLabels, NameTags. // return : void //--------------------------------------------------------------------------------------------- private function SetFormDimensions($aTemplateType) { $this->set('topmargin', $this->GetAppSetting($aTemplateType.'TopMargin')); // mm $this->set('leftmargin', $this->GetAppSetting($aTemplateType.'LeftMargin')); // mm $this->set('rightmargin', $this->GetAppSetting($aTemplateType.'RightMargin')); // mm $this->set('bottommargin', $this->GetAppSetting($aTemplateType.'BottomMargin')); // mm $this->set('intercolmargin', $this->GetAppSetting($aTemplateType.'InterColMargin')); // mm $this->set('interrowmargin', $this->GetAppSetting($aTemplateType.'InterRowMargin')); // mm $this->set('colsperpage', $this->GetAppSetting($aTemplateType.'ColsPerPage')); // label cols $this->set('rowsperpage', $this->GetAppSetting($aTemplateType.'RowsPerPage')); // label rows $this->set('cellborder', $this->GetAppSetting($aTemplateType.'CellBorder')); // 0: no border //0: no border (default), 1: frame, L: left, T: top, R: right, B: bottom }
- Create view
/app/View/MyEntity/genlabels.ctp
:<!-- File: /app/View/MyEntity/genlabels.ctp --> <?php $headertitle = 'Annual Continuing Education Workshop'; $headersubtitle = 'Packet Labels'; require_once(APP . 'Lib' . DS . 'StringUtils.php'); // Write() defaults $defaultfont = 'helvetica'; $height = 0; $isbgfilled = false; $isnewline = true; $stretch = 0; $isfirstline = false; $isfirstblock = false; $heightmax = 0; // Label defaults $unitsperpagewidth = 216; // mm for US Letter size (8.5 x 11 inches (216 mm x 279 mm)), Portrait orient. $unitsperpageheight = 279; // mm for US Letter size (8.5 x 11 inches (216 mm x 279 mm)), Portrait orient. // Avery 88395/5395 (8 per page) // $leftmargin = 18; // mm // $topmargin = 18; // mm // $rightmargin = 18; // mm // $bottommargin = 15; // mm // $intercolmargin = 12; // mm // $interrowmargin = 10; // mm // $colsperpage = 2; // label columns // $rowsperpage = 4; // label rows // Avery 5264 (6 per page) // $leftmargin = 5; // mm // $topmargin = 15; // mm // $rightmargin = 5; // mm // $bottommargin = 15; // mm // $intercolmargin = 5; // mm // $interrowmargin = 5; // mm // $colsperpage = 2; // label columns // $rowsperpage = 3; // label rows //###---- User Modifiable Variables ----### //# //$topmargin = 5; // mm //$leftmargin = 5; // mm //$rightmargin = 5; // mm //$bottommargin = 5; // mm //$intercolmargin = 0; // mm //$interrowmargin = 0; // mm //$colsperpage = 2; // label columns //$rowsperpage = 4; // label rows //$cellborder = 1; // 0: no border (default), 1: frame, L: left, T: top, R: right, B: bottom $cellfill = false; // true: painted, false: transparent //# //################################ $labelsperpage = ($colsperpage * $rowsperpage); $cellwidth = ($unitsperpagewidth - $leftmargin - ($intercolmargin * ($colsperpage-1)) - $rightmargin) / $colsperpage; $cellheight = ($unitsperpageheight - $topmargin - ($interrowmargin * ($rowsperpage-1)) - $bottommargin) / $rowsperpage; // define barcode style $barcodestyle = array( 'position' => '', 'align' => 'C', 'stretch' => false, 'fitwidth' => true, 'cellfitalign' => '', 'border' => false, 'hpadding' => 'auto', 'vpadding' => 'auto', 'fgcolor' => array(0,0,0), 'bgcolor' => false, //array(255,255,255), 'text' => true, 'font' => 'helvetica', 'fontsize' => 8, 'stretchtext' => 4 ); //$aWorkshopName = $workshop['Workshop']['Code'] . ' - ' . $workshop['Workshop']['Name']; $aWorkshopName = $this->Text->truncate( $workshop['Workshop']['Code'] . ' - ' . $workshop['Workshop']['Name'], 120 /* max chars per line */ / $colsperpage /* max chars */, array('ellipsis' => '...', 'exact' => false ) ); $aWorkshopLocation = $workshop['Workshop']['Address']; ?> <?php // Include the main TCPDF library App::import('Vendor','xtcpdf'); // create new PDF document $pdf = new XTCPDF('P' /* Page orientation (P=portrait, L=landscape) */, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false); // set document information $pdf->SetCreator(PDF_CREATOR); $pdf->SetAuthor(Configure::read('Company.Name')); $pdf->SetTitle($headertitle); $pdf->SetSubject($headersubtitle); $pdf->SetKeywords(''); // set default header data $pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, $headertitle, $headersubtitle); // set header and footer fonts $pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN)); $pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA)); $pdf->setPrintHeader(false); // do not print footer $pdf->setPrintFooter(false); // do not print footer // set default monospaced font $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED); // set margins //$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT); $pdf->SetMargins($leftmargin, $topmargin, $rightmargin); $pdf->SetHeaderMargin(PDF_MARGIN_HEADER); $pdf->SetFooterMargin(PDF_MARGIN_FOOTER); // set auto page breaks //$pdf->SetAutoPageBreak(FALSE, PDF_MARGIN_BOTTOM); $pdf->SetAutoPageBreak(FALSE, $bottommargin); // set image scale factor $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO); // set some language-dependent strings (optional) if (@file_exists(dirname(__FILE__).'/lang/eng.php')) { require_once(dirname(__FILE__).'/lang/eng.php'); $pdf->setLanguageArray($l); } // --------------------------------------------------------- // Add Page // --------------------------------------------------------- set_time_limit(0); // set execution time limit to None // --------------------------------------------------------- // Doc Content $pdf->SetFont($defaultfont, 'B', 18); $labelcount = 0; $isLineBreak = 0; $rowcount = 0; foreach($attendees as $row) { if (($labelcount % $labelsperpage) == 0) { $pdf->AddPage(); $rowcount = 0; } $colcount = ($labelcount % $colsperpage); if ($colcount == 0) { // First cell in row $Xoffset = $leftmargin; $Yoffset = $topmargin + (($cellheight + $interrowmargin) * $rowcount); $isLineBreak = 0; } else { // Any cell (except First cell) in row $Xoffset = $leftmargin + (($cellwidth + $intercolmargin) * $colcount); $Yoffset = $topmargin + (($cellheight + $interrowmargin) * $rowcount); $isLineBreak = 0; // Last cell in row if ($colcount == ($colsperpage-1)) { $isLineBreak = 1; $rowcount++; } } if (!empty($row['Registration']['LastName']) && !empty($row['Registration']['FirstName'])) { $aFullName = StringUtils::nameize($row['Registration']['LastName'] . ', ' . $row['Registration']['FirstName']); //require_once(APP . 'Lib' . DS . 'StringUtils.php'); } else { $aFullName = ""; } $aPacketID = $row['Registration']['PacketID']; $aPacketID = ( ($aPacketID > 0) ? (substr($aPacketID, 0, 4) . '-' . substr($aPacketID, 4, 4)) : 0); $pdf->SetFont($defaultfont, 'B', 18); //$aPacketLabel = "\n" . $aFullName . "\n" . $aPacketID . "\n" . $labelcount; // with counter (debug) $aPacketLabel = "\n" . $aFullName . "\n" . $aPacketID; // Barcode (print in X,Y coordinates of next cell) $x = $pdf->GetX(); // save X pos $y = $pdf->GetY(); // save Y pos $Xoffsetbarcode = $Xoffset + (($cellwidth - 50 /* barcode width */) / 2); $Yoffsetbarcode = $Yoffset + (($cellheight - 15 /* barcode height */) / 2) + 18 /* offset from ctr */; $pdf->write1DBarcode($aPacketID, 'C128', $Xoffsetbarcode, $Yoffsetbarcode, 50 /* width */, 15 /* height */, 0.4 /* bar resolution */, $barcodestyle, 'N'); // Workshop name $pdf->SetXY($Xoffset, $Yoffset); $pdf->SetFont($defaultfont, '', 8); $pdf->Write($height, $aWorkshopName, '', 0, 'L', 0 /*$isnewline*/, $stretch, $isfirstline, $isfirstblock, $heightmax); // Cell $pdf->SetXY($x, $y); // Reset X,Y so wrapping cell wraps around the barcode's cell. $pdf->SetFont($defaultfont, 'B', 22); $pdf->MultiCell($cellwidth, $cellheight, $aPacketLabel, $cellborder, 'C' /* align */, $cellfill, $isLineBreak, $Xoffset, $Yoffset, true /* reset height */, 'M'); if ($isLineBreak) { $pdf->Ln(1); } $labelcount++; } //$pdf->SetFont($defaultfont, '', 8); //date_default_timezone_set('America/New_York'); //$pdf->Write($height, 'Generated: ' . date("Y-m-d H:i:s"), '', $isbgfilled, 'L', true /* newline */, $stretch, $isfirstline, $isfirstblock, $heightmax); // Close and output PDF document ob_end_clean(); // Clean (erase) the output buffer and turn off output buffering ob_start(); // Turn on output buffering, to avoid errors $pdf->Output($workshop['Workshop']['Code'] . '-' . 'PacketLabels.pdf', 'I' /* Inline file dest */); //ob_end_flush(); // Turn off output buffering // --------------------- // End // --------------------- ?>
StringUtils
- Include this file in
[cakephp]/app/Lib/StringUtils.php
:<?php /** * String handling methods. * * CakePHP(tm) : Rapid Development Framework (http://cakephp.org) * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * * Licensed under The MIT License * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://cakephp.org CakePHP(tm) Project * @package Cake.Utility * @since CakePHP(tm) v 1.2.0.5551 * @license http://www.opensource.org/licenses/mit-license.php MIT License */ /** * String handling methods. * * * @package Cake.Utility */ class StringUtils { //--------------------------------------------------------------------------------------------- // description: Generate correct first letter uppercase names. // Usage: StringUtils::nameize($aName); //require_once(APP . 'Lib' . DS . 'StringUtils.php'); // parameters : $str, $delimiters // return : $str (formatted string) //--------------------------------------------------------------------------------------------- public static function nameize($str, $delimiters = array("'", "-", " ", "Mc")) { // Check if string is all lowercase/uppercase, which would then need processing. $requiresprocessing = false; $testdata = split(" ", $str); foreach($testdata as $s) { if (ctype_lower($s) || ctype_upper($s)) { $requiresprocessing = true; break; } } // Remove double spaces $str = trim(str_replace(" ", " ", $str)); // Change to uppercase first letter of each name, including special cases. // Eg: O'connell to O'Connell, Perez-morales to Perez-Morales, and Mcdonald to McDonald // Params: // $str Contains the complete raw name string. // $delimiters An array containing the characters used as separators for capitalization. // If you don't pass anything, there are four in there as default. if ($requiresprocessing) { $str = strtolower($str); foreach ($delimiters as $delimiter) { $pos = strpos($str, $delimiter); if ($pos) { // Found one of the special characters in the array, // so lets split it up into chunks and capitalize each one. $mend = ''; $a_split = explode($delimiter, $str); foreach ($a_split as $chunk) { // Capitalize each portion of the string which was separated at a delimiter $mend .= ucfirst($chunk) . $delimiter; } $str = substr($mend, 0, -strlen($delimiter)); // strip end delimiter } } return ucfirst($str); } else { return $str; } } } ?>
SVGGraph
- Get SVGGraph from http://www.goat1000.com/svggraph.php.
- Unpack files to
[cakephp]/app/Vendor/svggraph
. - Create file
[cakephp]/app/Vendor/xsvggraph.php
:<?php App::import('Vendor','svggraph/SVGGraph'); class XSVGGraph extends SVGGraph { } ?>
- Create a View to include graph (Eg:
[cakephp]/app/View/MyEntity/graphview.ctp
):<?php //require_once 'SVGGraph.php'; App::import('Vendor', 'xsvggraph'); $graph = new SVGGraph(500, 400); $graph->Values(1, 4, 8, 9, 16, 25, 27); $graph->Render('LineGraph'); ?>
- To include graph in a PDF, edit a View (using TCPDF) to include graph (Eg:
[cakephp]/app/View/MyEntity/pdfgraphview.ctp
):App::import('Vendor','xtcpdf'); $pdf = new XTCPDF('L' /* L=Letter, P=Portrait */, PDF_UNIT, 'Letter' /* Page Size */, true, 'UTF-8', false); $pdf->AddPage(); //------------------------------ // Graph (using SVGGraph) //------------------------------ //require_once 'svggraph/SVGGraph.php'; App::import('Vendor', 'xsvggraph'); $graph = new XSVGGraph(500, 400); $graph->Values(1, 4, 8, 9, 16, 25, 27); $output = $graph->fetch('LineGraph'); // Feed it to TCPDF (Since fetch without options generates the XML declaration and doctype). // This should generate $output of the format: // <svg style="overflow: hidden; position: relative;" // xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" // width="1226" version="1.1" height="826"> // <image transform="matrix(1.0364,-0.3305,0.3305,1.0364,-41.846,108.0143)" // preserveAspectRatio="none" x="10" y="10" width="205" height="154" // xlink:href="wallpaper.jpg" opacity="1" stroke-width="1"></image> // <rect transform="matrix(1.0364,-0.3305,0.3305,1.0364,-41.846,108.0143)" // x="165" y="114" width="50" height="50" r="0" rx="0" ry="0" // fill="#C0C0C0" stroke="#000" opacity="0" stroke-width="1"></rect> // <image transform="matrix(1.1575,0.2385,-0.2385,1.1575,-442.1395,-145.4163)" // preserveAspectRatio="none" x="500" y="10" width="205" height="154" // xlink:href="wallpaper.jpg" opacity="1" stroke-width="1"></image> // <rect transform="matrix(1.1575,0.2385,-0.2385,1.1575,-442.1395,-145.4163)" // x="655" y="114" width="50" height="50" r="0" rx="0" ry="0" fill="#C0C0C0" stroke="#000" // opacity="0" stroke-width="1"></rect> // </svg> // Feed it like this: $pdf->ImageSVG('@' . $output, $x=15, $y=30, $w='', $h='', $link='http://www.tcpdf.org', $align='', $palign='', $border=1, $fitonpage=false); // Of course you can also save the output in a file, and then provide the path to the file: //$pdf->ImageSVG($file='images/file.svg', $x=15, $y=30, $w='', $h='', // $link='', $align='', $palign='', $border=0, $fitonpage=false); $pdf->lastPage(); echo $pdf->Output(APP . 'files/pdf' . DS . 'articles.pdf', 'I' /* Dest: F = File saved to disk, I = Inline to browser */);