Solved

How does this login script produce the view that you see after everything is validated (Part II)?

Posted on 2016-08-18
1
54 Views
Last Modified: 2016-08-18
Here's the login page:

login screen
...and here's the code behind it:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class PatientPortal extends MY_Controller {

	private $debug = false; 		 	//Setting this to true will trigger a krumo of the session in a small console window at the bottom of your screen.
	private $payment_threshold = 30; 	// The minimum payment we will take through the portal

	public function index(){
		//$this->pay();
		//$this->login();
	}








	/** Login Function ----------------------------------------------------------------------------------------------------------
		*
		*
		*	This endpoint serves the login form of the patient portal.
		*

			|	In the case that there is no session variable 'guarantor_session' set (and we're not accessing via an admin subdomain),
			|	this becomes the root endpoint

		*
		*	Posting in all of these variables will treat this as a login attempt and will try to validate the data:
		*		pin - The Statement Pin / Accountid associated with an account.
		*		lastfour - The last four digits of the guarantor OR patient associated with the account or with a charge
		*		year - The birth year of the guarantor OR patient associated with the account or with a charge
		*
		*	Sending in a pin variable in your access assumes that you've clicked this link from an email and will autopopulate and lock the statement pin field.
		*
		*
	-----------------------------------------------------------------------------------------------------------------------------*/

	public function login($pin = ''){
		//Start with client colors
		$h = explode('.',$_SERVER['HTTP_HOST']);
		$clientcode = $h[0];
		$client = Clients::getByCode($clientcode);
		$clientid = '-1';
        session_start();
		if($client) $clientid = $client['ClientID'];

		$_SESSION['colors'] = ClientPreferences::getClientColors($clientid);

		//$this->setSessionData($accountid);
		//if(isset($_SESSION['guarantor_session'])) redirect('/patientportal/pay'); //On the offchance this is accessed directly with a session, reroute to pay.
		$lockpin = (isset($_REQUEST['lockpin']) && $_REQUEST['lockpin'] === "0")?false:($pin?true:false);
		$pin = $pin?$pin:(isset($_REQUEST['pin'])? $_REQUEST['pin'] : false);
		$lastfour = isset($_REQUEST['lastfour'])? $_REQUEST['lastfour'] : false;
		$year = isset($_REQUEST['year'])? $_REQUEST['year'] : false;
		$redirect = isset($_REQUEST['uri'])?$_REQUEST['uri']:'/';

		$data = array(
			'lockpin' => $lockpin,
			'pin' => $pin,
			'lastfour' => $lastfour,
			'year' => $year,
			'redirect' => $redirect,
			'debug' => $this->debug,
            'new_statement' => ClientPreferences::getClientPreference($clientid, 'NewStatements')
			);

		if($pin && $lastfour && $year){
			//If these variables are all set, assume validation attempt.

			//1 -> get accountid from pin
			if(strpos($pin,'T') !==false || strpos($pin,'t') !==false){
				$statementid = ltrim($pin,"Tt");
				$_SESSION['statementid'] = $statementid;
				$accountid = Accounts::getAccountidFromStatementid($statementid);
			}else{
				$accountid = $pin;
			}

			//2 -> use accountid to get accountdetails
			$accounts = Accounts::getAccountInfoFromPin($accountid);
			//krumo($accounts); exit();
			$ssns = array();
			$dobs = array();

			if($accounts)foreach($accounts as $account){
				//NOTE the getAccountInfoFromPin function returns 3 records, trying to coalesce
				//the information from Patient, Claim, and txn tables.
				//I'm organizing the data here so I can run an in_array on the fields.
				if($account['SSN'] && !in_array($account['SSN'], $ssns)) array_push($ssns, $account['SSN']);
				if($account['PatientDOB'] && !in_array($account['PatientDOB'], $dobs)) array_push($dobs, substr($account['PatientDOB'], 0,4));
			}
	  		//$details = Accounts::getDetails($accountid); <-- Might not need this
	  		//3 -> Check to see if account CAN be verified
	  		if($accounts && count($ssns) && count($dobs)){

	  			//4 -> Check to make sure our data = the provided data
	  			if(in_array($lastfour, $ssns)  && in_array($year, $dobs)){

	  				//Validated!!!
	  				
	  				//Guarantor Session
	  				$this->setSessionData($accountid);
	  				$data['clientcode'] = $_SESSION['guarantor_session']['clientcode'];

	  				//Are we on the right domain?
	  				$host = explode('.',$_SERVER['SERVER_NAME']);
	  				$sub = $host[0];

	  				if(strtolower($sub) == strtolower($data['clientcode']) || base_url() == 'https://dig.local/' || base_url() == 'https://localhost:8080/' || base_url() == 'https://digdev.patientfocus.com/' || base_url() == 'https://dig2.patientfocus.com/' || base_url() == 'https://staging.patientfocus.com/'){
	  					//This is the correct domain.
		              	redirect($redirect);

	  				} else {
	  					//Destroy existing session.
	  					unset($_SESSION['guarantor_session']);
						unset($_SESSION['userdata']);
						unset($_SESSION['roles']);
						unset($_SESSION['rights']);
						unset($_SESSION['colors']);
						unset($_SESSION['statementid']);
	  					session_destroy();

	  					//Post into the correct subdomain.
	  					$this->load->view('patientportal/subdomaingate',$data);
	  				}

	  				
	  				//exit();
	  			}

	  		} else if($accounts) {
	  			//Account cannot be verified, Give a specific call to action.
	  			$data['errorheader'] = 'Account Incomplete';
	  			$data['errormessage'] = 'There is not enough information in your account to verify your identity through the online portal. If you would like to access your account online, please <a class="cantlogin">let us know</a>, and one of our Patient Account Representatives will help you complete your account.';
	  		}

		}
		if($client){
			$data['clientcode'] = $clientcode;
			$data['clientname'] = $client['ClientName'];
		}
        session_write_close();
		$this->load->view('patientportal/login', $data);
	}







	/** Pay Function ----------------------------------------------------------------------------------------------------------
		*
		*
		*	This endpoint serves the ad hoc payment form of the patient portal.
		*

			|	In the case that there IS a session variable 'guarantor_session' set (and we're not accessing via an admin subdomain),
			|	this becomes the root endpoint

		*
		*	Posting in all of these variables will treat this as a payment attempt and will try to process the data:
		*
			REQUIRED (for any form processing)
		*
		*		paymentamount - This is either a dollar amount or a 'specialamount' flag, which then looks to the 'specialamount' manually entered field for the payment amount.
		*		specialamount - Should paymentamount = the string 'specialamount', this process pulls the value from the specialamount variable.
		*		email - the email address of the user, required for sending a receipt.
		*		cardorbank - Set to the string 'card' if this is a credit card process. Set to 'bank' if it's an echeck
		*
			REQUIRED FOR CREDIT CARD (if cardorbank = 'card')
		*		
		*		cardnum - The number on the front of your card. IF THIS BEGINS WITH A * then we process the payment off the stored BRIC if it is available
		*		cvcode - The 3-4 digit security code on the back of the card.
		*		cardname - The name on the front of the card
		*		cardmonth - the two digit card expiration month
		*
			REQUIRED FOR E CHECK (if cardorbank = 'bank')
		*		
		*		accountnum - the bank account number (in the case that this starts with *, use the associated bank BRIC.
		*		routingnumb - the routing number of the bank. If we're using a brick, Use the bric's associated routing number.
		*		accname - The name on the account.
		*
		*

			ON FAILED FORM PROCESSING,
		*		Reload the form view, populated where you left off, and provide an error that states the problem clearly.
		*
			ON SUCCESS,
		*		Load the payment success view.
		*
		*
	---------------------------------------------------------------------------------------------------------------------------*/


	public function pay($refreshdata = true){

		$data = $this->getData($refreshdata);

		if(isset($_REQUEST['paymentamount'])){

			//Process the payment
			$success = false;
			$amount = $_REQUEST['paymentamount'] == 'specialamount' ? str_replace('$', '', $_REQUEST['specialamount']) : $_REQUEST['paymentamount'];
			$amount = number_format($amount,2,'.','');
			$email = isset($_REQUEST['email'])? $_REQUEST['email'] : false;

			$createdby = $_SESSION['userdata']['id'];

			if($amount >= $data['minpayment']){
				if($amount <= $data['lefttopay']){	
					if($_REQUEST['cardorbank'] == "card"){
						$cardinfo = $data['cardinfo'];

						//Process as Credit Card
						$cardnum = isset($_REQUEST['cardnum'])? $_REQUEST['cardnum'] : false; //ACCOUNT FOR ************XXXX STYLE ENTRIES - IMPLYING TO USE THE CARD ON FILE.
						$bric = substr($cardnum,0,1) == '*' && $cardinfo?$cardinfo['bric']:false;
						$cv = isset($_REQUEST['cvcode'])? $_REQUEST['cvcode'] : false;
						$cardname = $bric?$cardinfo['cardname']:(isset($_REQUEST['name'])? $_REQUEST['name'] : false);
						$cardmonth = isset($_REQUEST['cardmonth'])? $_REQUEST['cardmonth'] : false;
						$cardyear = isset($_REQUEST['cardyear'])? $_REQUEST['cardyear'] : false;
						$cardexp = $this->getEPXExpirationString($cardmonth, $cardyear);					

							//Ensure that the pieces are all available.
							if( ($bric || $cardnum) && $cv && $amount && $cardname && $cardexp && $data['accountid'] && $email){
								if(!$bric || ($cardexp == $cardinfo['cardexp'] && $cv == $cardinfo['cardcv'])){

									if(filter_var($email,FILTER_VALIDATE_EMAIL)){
										if(strtolower($email) != strtolower($data['email'])) Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));

										//PROCESS THE EPX TRANSACTION AND TURN THE RESULTING XML INTO AN ARRAY
										$xmlstr = '';

										if($bric){
											//PROCESS FROM BRIC
											$xmlstr = $this->epx->processCreditCardBRIC($bric, $cv, $amount, $cardname, $cardexp,array('AccountID'=>$data['accountid']),$data['dbanbr']);
										} else {
											//PROCESS FROM CARD NUMBER
											$xmlstr = $this->epx->processCreditCard($cardnum, $cv, $amount, $cardname, $cardexp,array('AccountID'=>$data['accountid']),$data['dbanbr'],$data['address']);
										}
										$xmlobj = simplexml_load_string($xmlstr);
										$xmlarr = array();
										if($xmlobj) foreach($xmlobj->FIELDS->FIELD as $field){
							              $xmlarr[(string)$field->attributes()->KEY] = (string)$field;
							            }
							           	
							           	if(isset($xmlarr['AUTH_RESP']) && $xmlarr['AUTH_RESP'] == '00'){
							           		/**
							           			Successfully paid on card
							           		**/
							           		//This is for the paymentmethodcode.
							           		$this->load->library('CreditCard');
							           		$card = $bric?array('abbr'=>$cardinfo['cardabbr'],'name' => 'card'):$this->creditcard->cardNameFromNumber($cardnum);
							           		$cardfour = substr($cardnum, strlen($cardnum)-4);

							           		$description = 'Credit card ending in ' . $cardfour;

							           		//Create the paymentpending entry.
							           		$paymentpending = PaymentPendings::addPaymentPending(date('Y-m-d H:i:s'), $xmlarr['AMOUNT'],$card['abbr'], $data['accountid'], $data['patientid'], 'PR', 'PT', $createdby, $xmlarr['AUTH_GUID'], $xmlarr['AUTH_CODE'],$xmlarr['AUTH_RESP'],$description);
								            if($paymentpending){
								            	$success = true;
								            	$data['successcardtype'] = $card['name'];
								            	$data['successemail'] = $email;
								            	$data['successcardlastfour'] = $cardfour;
								            	$data['confirmation'] = $paymentpending['PaymentPendingID'];
								            }

							           	} else {
							           		//Error -> epx response
							           		$data['errorcode'] = isset($xmlarr['AUTH_RESP'])? $xmlarr['AUTH_RESP'] : 'PF4';
						           			$data['errormsg'] = isset($xmlarr['AUTH_RESP_TEXT'])?ucfirst($xmlarr['AUTH_RESP_TEXT']):'No response from EPX.';

							           	}
							        } else {
							        	$data['errorcode'] = 'PF8';
										$data['errormsg'] = 'Email invalid.';
							        }
							    } else {
					           		//Error -> CARDEXP DOESN'T MATCH ONE ON FILE OR CCV DOESN'T MATCH
					           		$data['errorcode'] = 'PF5';
				           			$data['errormsg'] = 'Card validation mismatch.';

					           	}
							} else {
								//Error Incomplete Form.
								$data['errorcode'] = 'PF3';
								$data['errormsg'] = 'Payment form incomplete.';
							}

						//$this->epx->processCreditcard();

					} else if ($_REQUEST['cardorbank'] == "bank"){
						$bankinfo = $data['bankinfo'];

						//Process as E Check
						$accnum = isset($_REQUEST['accountnum'])? $_REQUEST['accountnum'] : false; //ACCOUNT FOR ************XXXX STYLE ENTRIES - IMPLYING TO USE THE CARD ON FILE.
						$bric = substr($accnum,0,1) == '*' && $bankinfo?$bankinfo['bric']:false;
						$name = $bric?$bankinfo['accname']:(isset($_REQUEST['account_name'])? $_REQUEST['account_name'] : false);
						$routing = $bric?$bankinfo['accrouting']:(isset($_REQUEST['routingnumb'])? $_REQUEST['routingnumb'] : false);
						//$bankname = $bric?$bankinfo['accbankname']:(isset($_REQUEST['cardmonth'])? $_REQUEST['cardmonth'] : false);

						//Ensure that the pieces are all available.
						if(($bric || $accnum) && $routing && $amount && $name && $data['accountid'] && $email){
							if(filter_var($email,FILTER_VALIDATE_EMAIL)){
								if(strtolower($email) != strtolower($data['email'])) Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));
								//PROCESS THE EPX TRANSACTION AND TURN THE RESULTING XML INTO AN ARRAY
								$xmlstr = '';
								if($bric){
									//PROCESS FROM BRIC
									$xmlstr = $this->epx->processCheckBRIC($bric, $routing, $amount, $name, array('AccountID'=>$data['accountid']),$data['dbanbr']);
								} else {
									//PROCESS FROM ACC NUMBER
									$xmlstr = $this->epx->processCheck($accnum, $routing, $amount, $name, array('AccountID'=>$data['accountid']),$data['dbanbr'],$data['address']);
								}
								$xmlobj = simplexml_load_string($xmlstr);
								$xmlarr = array();
								if($xmlobj) foreach($xmlobj->FIELDS->FIELD as $field){
					              $xmlarr[(string)$field->attributes()->KEY] = (string)$field;
					            }
					           	
					           	if(isset($xmlarr['AUTH_RESP']) && $xmlarr['AUTH_RESP'] == '00'){
					           		/**
					           			Successfully paid from bank
					           		**/
					           		$description = 'Bank account ending in ' . substr($accnum,-4);
					           		//Create the paymentpending entry.
					           		$paymentpending = PaymentPendings::addPaymentPending(date('Y-m-d H:i:s'), $xmlarr['AMOUNT'],'EF', $data['accountid'], $data['patientid'], 'PR', 'PT', $createdby, $xmlarr['AUTH_GUID'], $xmlarr['AUTH_CODE'],$xmlarr['AUTH_RESP'], $description);
						            if($paymentpending){
						            	$success = true;
						            	$data['successcardtype'] = 'bank account';
						            	$data['successemail'] = $email;
						            	$data['successcardlastfour'] = substr($accnum,-4);
						            	$data['confirmation'] = $paymentpending['PaymentPendingID'];
						            }

					           	} else {
					           		//Error -> epx response
					           		$data['errorcode'] = isset($xmlarr['AUTH_RESP'])? $xmlarr['AUTH_RESP'] : 'PF4';
					           		$data['errormsg'] = isset($xmlarr['AUTH_RESP_TEXT'])?ucfirst($xmlarr['AUTH_RESP_TEXT']):'No response from EPX.';

					           	}
					        } else {
						        	$data['errorcode'] = 'PF8';
									$data['errormsg'] = 'Email invalid.';
						    }
						} else {
							//Error Incomplete Form.
							$data['errorcode'] = 'PF3';
							$data['errormsg'] = 'Payment form incomplete.';
						}

					} else {
						//Error as unrecognized type
						$data['errorcode'] = 'PF1';
						$data['errormsg'] = 'Could not process transaction type';
					}
				} else {

					//Error as Amount above Maximum
					$data['errorcode'] = 'PF2';
					$data['errormsg'] = 'Can\'t pay more than you owe.';
				}
			} else {

				//Error as Amount Below Minimum
				$data['errorcode'] = 'PF2';
				$data['errormsg'] = 'Amount below the minimum ' . $data['minpaymentformatted'] . ' payment.';
			}

			if($success){
				//On Success load the next view.
				$data['successamount'] = $amount;
				$data = array_merge($data, $this->getData());
				$this->load->library('Mandrill');

				$message['html'] = $this->load->view('email/receipt',$data,true);
				$message['text'] = "Thank you! Your payment of \$$amount was successfully charged to your $data[successcardtype] ending in $data[successcardlastfour]. Your confirmation number is $data[confirmation].";
				$message['subject'] = "Your payment has been received!";
				$message['from_email'] = 'noreply@patientfocus.com';
				$message['from_name'] = $data['clientname'];
				$message['to'][0] = array('email' => $email);

				$mandrill_response = $this->mandrill->sendemail($message);
				if($mandrill_response){

					$e['templateid'] = 0;
					$e['content'] = pfsql::scrub($message['html']);
					$e['email'] = pfsql::scrub($email);
					$e['systememail'] = $message['from_email'];
					$e['response'] = pfsql::scrub(json_encode($mandrill_response));
					$e['direction'] = 'outbound';
					$e['accountid'] = $data['accountid'];
					$data['receiptemailed'] = true;

					$f = Emails::create($e);

				} else $data['receiptemailed'] = false;

				//echo json_encode($mandrill_response); exit();


				$data['view'] = 'paymentsuccess';
			} else {
				//On Fail load same view.
				$data['view'] = 'makeapayment';
			}			

		} else if($data['lefttopay'] <= 0){
			$data['view'] = 'creditbalance';
		}else{
			$data['view'] = 'makeapayment';
		}

		$this->loadView($data);

	}

    protected function getEPXExpirationString($month, $year) {
        
        $exp = false;
        //Month should be 2 digits.
        if($month && $year) {

            $month = str_pad($month, 2, '00', STR_PAD_LEFT);
            $year = substr($year, -2);
        
            if (strlen($year) === 2 && strlen($month) === 2) {
                $exp = $year . $month;
            }

        }
        
        return $exp;
    
    }





	/** PaymentPlan ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This function handles Payment Plans
		*
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */

	public function paymentplan(){

		$data = $this->getData();

		if(!$data['paymentplan'] && $data['lefttopay'] < 90){
			
			//This is only accessible if you have an active payment plan OR if you have a balance >= 90 dollars.
			//redirect home
			header ("location: /");

		}else{

			//are we processing a form?
			if(isset($_REQUEST['cardorbank'])){ //we are processing a form.

				//Declare Needed Vars
				$payment_amount; 				//NUMBER - The amount of the monthly payment. Must be greater or equal to the minimum payment.
				$is_new_plan;					//BOOL   - If there is an existing paymentplan, this is false. Otherwise this is true.
				$is_autodraft; 					//BOOL 	 - If this is true we are autodrafting.
				$autodraft_type; 				//STRING - either "card" or "bank"
				$bank = array();			//ARRAY
					$bank['name']		= null; //STRING - The name on the account
					$bank['accountnum'] = null;	//NUMBER - The account number
					$bank['acclastfour']= null; //NUMBER - The last four of the account number
					$bank['routingnum'] = null;	//NUMBER - The routing number
				$card = array();			//ARRAY
					$card['name']		= null; //STRING - The name on the card
					$card['number']		= null; //NUMBER - The number on the front of the card
					$card['lastfour']	= null; //NUMBER - The last four of the card number
					$card['exp']		= null; //NUMBER - The expiration date in YYMM format
					$card['cv']			= null; //NUMBER - The three or four digit security code on the back of the card
				$bric;							//STRING - The AUTH GUID provided by EPX
				$plan_date; 					//NUMBER - Between 1 and 28 (inclusive), the date the payment is owed or autodrafted
				$email;							//STRING - User submitted email
				$plan_starting_balance;			//NUMBER - The balance at the start of this particular payment plan. In the case that there is an
				$number_of_payments;			//NUMBER - The number of payments there should be.
				$payment_method_code;			//STRING - EF for check, PP for promise to pay, Card specific versions for card autodrafts.
				$pmtdetails = array();			//ARRAY  - Formatted for payment plan creation function.

				//Collect Data and validate form.
				try	{
					$is_new_plan = $data['paymentplan'] === false ?
						true
					  : false;

					$payment_amount = $is_new_plan ?
						$_REQUEST['paymentplanamount']
					  : $data['paymentplan']['paymentamount'];
					if($payment_amount < $data['minpayment'])
						throw new Exception('Payment Plan amount below minimum '. $data['minpaymentformatted'] . ' payment amount.',1);

					$plan_starting_balance = $is_new_plan ?
						$data['lefttopay']
					  : $data['paymentplan']['startingbalance'];

					$number_of_payments = ceil( $data['lefttopay'] / floatval($payment_amount) );
					$pmtdetails['NbrOfPayments'] = $number_of_payments;

					$is_autodraft = isset($_REQUEST['autodraft']) ?
						true
					  : false;

					$plan_date = $is_autodraft ?
						$_REQUEST['autodraftdate']
					  : (
					  	$is_new_plan ? // If it IS NOT AN AUTODRAFT and it IS A NEW PLAN, set it to today, otherwise if it IS NOT A NEW PLAN, set it to the stored value.
					  		(
					  			intval(Date('d')) > 28? 1 : Date('d')
					  		)
					  	  : $data['paymentplan']['duedate']
					  	);
					if(intval($plan_date) > 28 or intval($plan_date) < 1)
						throw new Exception('Plan date out of range', 2);

					if($is_autodraft){
						if(isset($_REQUEST['email'])){
							$email = $_REQUEST['email'];
						} else throw new Exception('Incomplete Form', 4);
						if(filter_var($email,FILTER_VALIDATE_EMAIL)) Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));
						else throw new Exception('Email Invalid', 8);
					}

					if($is_autodraft){
						switch($_REQUEST['cardorbank']){
							case 'card':
								$autodraft_type = 'card';
								//collect card values
								if(substr($_REQUEST['cardnum'],0,1) == '*' && $data['cardinfo']){
									//assume stored number
									$cardinfo = $data['cardinfo'];

									$card['name'] 		 = $cardinfo['cardname'];
									$card['lastfour'] 	 = $cardinfo['cardlastfour'];
									$card['exp'] 		 = $cardinfo['exp'];
									$card['cv'] 		 = $cardinfo['cardcv'];
									$bric				 = $cardinfo['bric'];
									$payment_method_code = $cardinfo['cardabbr'];

								} else {
									//Check credit card entries
									if(
										isset($_REQUEST['name']) 	 && $_REQUEST['name']
									 && isset($_REQUEST['cardnum'])  && $_REQUEST['cardnum']
									 && isset($_REQUEST['cardmonth'])&& $_REQUEST['cardmonth']
									 && isset($_REQUEST['cardyear']) && $_REQUEST['cardyear']
									 && isset($_REQUEST['cvcode']) 	 && $_REQUEST['cvcode']
									) {
										//use provided number, preauth required.
										$card['name'] 		= $_REQUEST['name'];
										$card['number'] 	= $_REQUEST['cardnum'];
										$card['lastfour']	= substr($card['number'],strlen($card['number'])-4);
										$card['exp'] 		= substr($_REQUEST['cardyear'],2,2) . $_REQUEST['cardmonth'];
										$card['cv'] 		= $_REQUEST['cvcode'];

										$this->load->library('CreditCard');
										$exp = $this->parseEPXResponse($this->epx->preAuthCreditCard($card['number'],$card['cv'],'.01',$card['name'],$card['exp'],$data['accountid'],$data['dbanbr'],$data['address']));
										if(isset($exp['AUTH_RESP']) && $exp['AUTH_RESP'] == '00'){

											//SUCCESSFULLY PREAUTHED!
											$extra = $this->creditcard->cardNameFromNumber($card['number']);
											$payment_method_code = $extra['abbr'];
											$bric = $exp['AUTH_GUID'];

										} else {
											throw new Exception (
												isset($exp['AUTH_RESP_TEXT'])?ucfirst($exp['AUTH_RESP_TEXT']).'.':'Communication error, unable to preauthorize your card.',
												isset($exp['AUTH_RESP'])?intval('90'.$exp['AUTH_RESP']):5
												);
										}

									} else throw new Exception('Incomplete Form', 4);
								}

								//pmtdetails object.

								$pmtdetails['ccname'] = pfsql::scrub($card['name']);
								$pmtdetails['cclast4']= pfsql::scrub($card['lastfour']);
								$pmtdetails['ccv2']	  = pfsql::scrub($card['cv']);
								$pmtdetails['ccyear'] = pfsql::scrub(substr($card['exp'],0,2));
								$pmtdetails['ccmonth']= pfsql::scrub(substr($card['exp'],2));

								break;
							case 'bank':
								$autodraft_type = 'bank';
								$payment_method_code = 'EF';
								//collect bank values
								if(substr($_REQUEST['accountnum'],0,1) == '*'){
									//assume stored number
										$bankinfo = $data['bankinfo'];

									$bank['name']		= $bankinfo['accname'];
									$bank['acclastfour']= $bankinfo['acclastfour'];
									$bank['routingnum'] = $bankinfo['accroutingnum'];
									$bank['bank']		= $bankinfo['accbankname'];
									$bric				= $bankinfo['bric'];

								} else {
									//assume provided number, preauth required.
									if(
										isset($_REQUEST['account_name']) && $_REQUEST['account_name']
									 && isset($_REQUEST['routingnumb'])  && $_REQUEST['routingnumb']
									 && isset($_REQUEST['accountnum'])	 && $_REQUEST['accountnum']
									) {
										//use provided number, preauth required.
										$bank['name'] 		= $_REQUEST['account_name'];
										$bank['accountnum'] = $_REQUEST['accountnum'];
										$bank['acclastfour']= substr($bank['accountnum'],strlen($bank['accountnum'])-4);
										$bank['routingnum'] = $_REQUEST['routingnumb'];
										$bank['bank'] 		= '';

										$exp = $this->parseEPXResponse($this->epx->preAuthCheck($bank['accountnum'],$bank['routingnum'],'.01',$bank['name'],$data['accountid'],$data['dbanbr'],$data['address']));
										if(isset($exp['AUTH_RESP']) && $exp['AUTH_RESP'] == '00'){

											//SUCCESSFULLY PREAUTHED!
											$bric = $exp['AUTH_GUID'];

										} else {
											throw new Exception (
												isset($exp['AUTH_RESP_TEXT'])?ucfirst($exp['AUTH_RESP_TEXT']).'.':'Communication error, unable to preauthorize your card.',
												isset($exp['AUTH_RESP'])?intval('90'.$exp['AUTH_RESP']):5
												);
										}

									} else throw new Exception('Incomplete Form', 4);
								}

								//pmtdetails object.

								$pmtdetails['BankName'] 	= pfsql::scrub($bank['bank']);
								$pmtdetails['accountname']  = pfsql::scrub($bank['name']);
								$pmtdetails['accountlast4'] = pfsql::scrub($bank['acclastfour']);
								$pmtdetails['routingnum'] 	= pfsql::scrub($bank['routingnum']);

								break;
							default:
								throw new Exception('Autodraft source unrecognized.', 3);
								break;
						}
					} else {
						$payment_method_code = 'PP';
						$bric = false;
					}

					//Create paymentplan.
					if(PaymentPlans::endAllPlansForPatient($data['patientid'])){
					} else throw new Exception('Failed closing old payment plan.',6);

					$createdby = $_SESSION['userdata']['id'];
					if(PaymentPlans::create($data['patientid'], $payment_method_code, $pmtdetails, $bric, $plan_starting_balance, $createdby, $plan_date, $payment_amount)){
					} else throw new Exception('Failed starting new payment plan.',7);

					//refresh data.
					$data = $this->getData();

				} catch (Exception $e) {
					$code = $e->getCode();
					$data['errorcode'] = $code >= 90 ? substr($code, 2):'PF'.$code;
					$data['errormsg']	= $e->getMessage();
				}

			}

			//IS THERE AN EXISTING PAYMENTPLAN?
			if($data['paymentplan']){
				//YES
				$data['view'] = 'editpaymentplan';
			} else {
				//NO
				$data['view'] = 'setuppaymentplan';
			}
			//Load the view	

			$this->loadView($data);
		} 
		
		
	}





	/** Details---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This is a read only view, that lets you see your existing account activity. That's all.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */

	public function details(){

		$data = $this->getData();
		$data['details'] = Accounts::patientPortalBalanceDetails($data['accountid']);
		//krumo($data['details']); exit();
		$data['view'] = 'balancedetails';
		$this->loadView($data);

	}




	/** Statements ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This is a read only view, that lets you access your existing statements.
		*
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function statements(){

		$data = $this->getData();
		$data['statements'] = Statements::getStatements($data['accountid'],'S', false, true);
		$data['view'] = 'viewstatements';

		$this->loadView($data);

	}



	/** Statement ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	NOTE:: THIS IS ROUTED TO THE /statements/XXXXXXX URI,
		*	This endpoint, when accessed with a statementid, compares the accountid on the statement entry
		*	with the accountid in the current session, and should they match and the file exists, serves the pdf to the browser.
		*
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function statement($statementid){
		$statement = Statements::getStatementByID($statementid);
		//krumo($_SESSION);exit();
		if($statement && $_SESSION['guarantor_session']['accountid'] == $statement['AccountID']){
			$data['path'] = '/p/' . (ENVIRONMENT === "production" ? "prod" : "dev") . '/statements/'.$statement['ExportID'].'/'.$statement['AccountID'].'-'.$statement['StatementID'].'.pdf';
     		if(file_exists($data['path'])){
     			$this->load->view('olddig/viewstatement', $data);
     		} else if ($_SESSION['guarantor_session']['clientcode'] == 'demo') {
     			//Generate statement on-the-fly for demo accounts
     			$data2['accountid'] = $_SESSION['guarantor_session']['accountid'];
			    $data2['templateid'] = 4;
			    $_REQUEST = $data2;

     			$template = Templates::getTemplate($data2['templateid']);
			   
     			$this->load->view($template['content'], $data); 
     		} else {
     			show_404();
     		}
		} else {
			show_404();
		}
	}



	/** Contact ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This is a read only view, it uses the practice the current session is associated with to 
		*	deliver the TwilioPhone entry to the view.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function contact(){

		$data = $this->getData();

		$data['view'] = 'contactus';

		$this->loadView($data);

	}
/**
---------------------------------------------------------------------------------------------------------------------------
	



		THESE ARE PRIVATE (and therefore URL inaccessable) FUNCTIONS VVVVV
		(...beyond here monsters be)




---------------------------------------------------------------------------------------------------------------------------
*/

	/** Settings ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	THIS ENDPOINT IS CURRENTLY INACTIVE
		*
		*	The intention of this endpoint is to provide an interface for an account to manage their account preferences
		*	and contact information. Currently there is a data model change required to ensure there will be no loss
		*	of data by using this endpoint.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */


	public function settings(){
		//This will be public when:
		//1 - The statement backend respects prefs while the account is active (Default behavior if a preference HAS NOT BEEN SET is to respect the CCE choice).
		//2 - When we have a data structure in place that will ensure that Phone Numbers and Mailing Addresses cannot be deleted by the patient ( an email table and an address table ).

        $data = $this->getData();
        if(pf::post('action') === 'save') {
            
            $results = array();

            if(pf::post('email')) array_push($results,$this->saveEmail());

            $data['results'] = $results;
        }
		$data['settings'] = Accounts::getGuarantorControllableValues($data['accountid']);
		$data['view'] = 'settings';

		$this->loadView($data);

	}

    protected function saveEmail(){

        $email = pf::post('email');
        $gogreen = pf::post('gogreen') ? 1 : 0;

        $data = $this->getData();


        if (filter_var($email,FILTER_VALIDATE_EMAIL)) {
            if(strtolower($email) != strtolower($data['email'])) {
                $result = Accounts::update($data['accountid'], array(array('field'=>'email','newvalue'=>$email)));
                if($result) $email = $result[0]['email'];
                else $email = false;
            }
        } else {
            $email = false;
        }

        $success = false;
        if( $email ) {
            $success = true;
            $data['settings'] = Accounts::getGuarantorControllableValues($data['accountid']);
            if ($gogreen !== $data['settings']['gogreen']) {
                $success = false;
                //Make sure this person is pref E
                $this->load->model('Communications');
                if ($gogreen) {
                    if ($this->Communications->prefin($data['accountid'], 'E')) {
                        $success = true;
                    }
                } else {
                    if ($this->Communications->prefout($data['accountid'], 'E')) {
                        $success = true;
                    }
                }
            }

        }

        return array('success'=>$success, 'reason' => $email ? ($success ? 'Everything updated successfully!' : 'There was an error saving your go green preference. Please try again later or <a href="/contact">call us</a> if you continue to experience problems.') : 'There was a problem processing your email... Please make sure you\'re providing a valid email address, and <a href="/contact">call us</a> if you continue to experience problems.');


    }


	/** loadView ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This processes the $data object that we build before loading our views.
		*	(Any nested views use the $_ci_vars object, which represents the same information, for consistant variables)
		*	It's basically a controller-specific template function.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */
	private function loadView($data){
		//utility patientportal view loader, takes care of templating.
		$this->load->view('patientportal/include/header', $data);
		$this->load->view('patientportal/'.$data['view'], $data);
		$this->load->view('patientportal/include/footer');
	}


	/** getData ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This snags and returns the data from the session (and from any controller constants).
		*		If $refresh is set to true (default behavior)
		*		Then it uses the accountid in the session to refresh the data from the database.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */

	private function getData($refresh = true){
		//Retrieves the appropriate data from the session, formated nicely and ready to go.
		$data;
		if(isset($_SESSION['guarantor_session']) && $_SESSION['guarantor_session']){

			//Refreshes the data
			if($refresh) $this->setSessionData($_SESSION['guarantor_session']['accountid']);
			$data = $_SESSION['guarantor_session'];
			
		}
		$data['view'] = '';
		$data['debug'] = $this->debug;

		return $data;
	}

	/** setSessionData ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	This unsets any existing session, then reaches out to the database and creates a nicely formatted session object
		*	with all sorts of account information. This is usually called once per request.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */
	private function setSessionData($accountid){

		//Refreshes session data from the database.
		//In the case that there is no session data, it creates the object.

		//Call to the database
		$sess = Accounts::getGuarantorSession($accountid);

		if($sess){

			//Check to see if this patient can use the patient portal first and foremost.
			$can_login = ($sess['status1'] != 'RT' && ClientPreferences::getClientPreference($sess['clientid'], 'PatientsCanLoginToPatientPortal'));

			if($can_login === true){

				//Get Parameters for this client
				$this->load->model('ClientParameters');
				$params = $this->ClientParameters->read(array('name','value'), array('clientid'=>$sess['clientid'], 'voideddate'=>null));
				$sess['parameters'] = array();
				if($params) foreach($params as $p){
					$sess['parameters'][$p['name']][] = $p['value'];
				}

                $sess['preferences'] = array();
                $sess['preferences']['DisplayCreditBalancesInPatientPortal'] = $this->ClientPreferences->getClientPreference($sess['clientid'], 'DisplayCreditBalancesInPatientPortal');

				//Additional fields not needed from the database
                if($sess['preferences']['DisplayCreditBalancesInPatientPortal'] || $sess['lefttopay'] >= 0){
                    $sess['lefttopayformatted'] = pfmoney::toFromCents($sess['lefttopay']);
                } else {
                    $sess['lefttopayformatted'] = pfmoney::toFromCents(0);
                }
				//Sets what the "Default" make-a-payment amount is. If there is no payment plan active, it defaults to the full amount
				$sess['defaultpayment'] = min((($sess['paymentplan']&&$sess['paymentplan']['paymentamount'])?$sess['paymentplan']['paymentamount']:$sess['lefttopay']),$sess['lefttopay']);
				//payment_threshold is the minimum payment we will accept through the portal (assuming the patient owes more than the threshold)
				$sess['paythresh'] = $this->payment_threshold;
				$sess['paythreshformatted'] = pfmoney::toFromCents($this->payment_threshold);

                //Is left to pay representative of the full amount owed?
                if($sess['lefttopay'] != $sess['totalbalance']){
                    $sess['balancesmatch'] = false;
                } else {
                    $sess['balancesmatch'] = true;
                }

				//Minimum payment
				$sess['minpayment'] = ($sess['lefttopay'] < $this->payment_threshold ? $sess['lefttopay'] : $this->payment_threshold);
					//If the default payment is less than this ^^ set it to the default payment instead.
					if($sess['defaultpayment'] < $sess['minpayment']) $sess['defaultpayment'] = $sess['minpayment'];

				//Minimum payment formatted
				$sess['minpaymentformatted'] = pfmoney::toFromCents($sess['minpayment']);

				//Color Scheme
				$sess['colors'] = ClientPreferences::getClientColors($sess['clientid']);

				//Unset any potentially remaining patient session.
				//Might be a bit heavy handed... May want to account for spoofs.
				if(isset($_SESSION['guarantor_session'])){
					unset($_SESSION['guarantor_session']);
					unset($_SESSION['userdata']);
					unset($_SESSION['rights']);
					unset($_SESSION['roles']);
					//unset($_SESSION['colors']);
					//unset($_SESSION['statementid']);
				}
				$_SESSION['guarantor_session'] = $sess;
				//Userdata object
				$ud = Users::getUserByEmail('patient@patientfocus.com');
				$_SESSION['userdata'] = $ud;
				$_SESSION['userdata']['accountid'] = $sess['accountid'];
				//Roles n rights
	          	$_SESSION['roles'][]= array('id'=>'14', 'name' => 'Patient');       
	          	$_SESSION['rights'] = Rights::getRightsForRolesArray($_SESSION['roles']);

	        } else {

	        	//Destroy session
				unset($_SESSION['guarantor_session']);
				unset($_SESSION['userdata']);
				unset($_SESSION['roles']);
				unset($_SESSION['rights']);
				unset($_SESSION['colors']);
				unset($_SESSION['statementid']);
				session_destroy();

				//Get forwarding Message
				$data = array();
				$data['forwarding_message'] = $this->Clients->getForwardingMessageForPortal($sess['clientid']);

				//Show forwarding Message and break the current flow.
				echo $this->load->view('patientportal/forwardingmessage',$data, true);
				//NOTE:: Echoing this here ensures that this doesn't enter the CI output buffer
				// and writes straight to the output, so we can exit on the next line.
				exit();

	        }

		}

	}

	/** parseEPXResponse ---------------------------------------------------------------------------------------------------------------------------

		*
		*
		*	Converts an xml response string from EPX to an associated array.
		*
		*

	--------------------------------------------------------------------------------------------------------------------------- */
	private function parseEPXResponse($xmlstr){

		$xmlobj = simplexml_load_string($xmlstr);
		$xmlarr = array();
		if($xmlobj) foreach($xmlobj->FIELDS->FIELD as $field){
              $xmlarr[(string)$field->attributes()->KEY] = (string)$field;
        }
        return $xmlarr;

	}

}

?>

Open in new window


The login script begins on line 40. The "getbyCode" SQL looks like this:

select 
client.ClientID,
client.ClientName,
client.ClientTetrisId,
client.ClientPrimaryContact,
client.ClientBankAcctNumber,
client.ClientBankRoutingNumber,
client.ClientStatusCode,
client.Specialty,
client.Address,
client.PhoneNumber,
client.Email,
client.PaymentProcessingDBANbr,
client.CreatedDate,
client.LastModifiedDate,
client.ModifiedBy,
client.Address1,
client.Address2,
client.City,
client.State,
client.Zip,
client.clientcode,
cast(dbo.ufn_ClientPreference(clientid,'WithholdFeesOnInvoice') as bit) withhold,
client.phrase,
client.type,
client.ClientNotes,
client.SitePaymentFee
         from client where clienttetrisid = '$clientcode'"

Open in new window


So, it seems you're getting all of the data you need to validate the user from that SQL.

It's all routed to a specific domain based on lines 111 and 112, yet on line 126 you've got the $this->load->view('patientportal/subdomaingate) thing and that code looks like this:

<!DOCTYPE html>
<html>
	<head>
		<title>Redirecting...</title>
	</head>
	<body>
		<form action="https://<?=$clientcode?>.patientfocus.com/patientportal/login" method="post">
		<!--<form action="patientportal/login" method="post">-->
			<input type="hidden" name="pin" value="<?=$pin?>"/>
			<input type="hidden" name="lastfour" value="<?=$lastfour?>"/>
			<input type="hidden" name="year" value="<?=$year?>"/>
		</form>
		<script type="text/javascript">
			document.forms[0].submit();
		</script>
	</body>
</html>

Open in new window


So, the page is posting all of its data back to itself, but where does it go and how am I getting this page:

home page
How am I getting there?

Thanks!
0
Comment
Question by:brucegust
1 Comment
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 41760917
Probably line 462 in the top PHP script.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Router for PHP reqeusts 12 32
Multilanguage Database Design in MySQL 5 35
resizeing PHP image 2 22
Filter wordpress query 3 9
Popularity Can Be Measured Sometimes we deal with questions of popularity, and we need a way to collect opinions from our clients.  This article shows a simple teaching example of how we might elect a favorite color by letting our clients vote for …
This article will explain how to display the first page of your Microsoft Word documents (e.g. .doc, .docx, etc...) as images in a web page programatically. I have scoured the web on a way to do this unsuccessfully. The goal is to produce something …
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now