HEX
Server: Apache
System: Linux host60.registrar-servers.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User: wwwrenee (3804)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /home/wwwrenee/public_html/wp-content/plugins/mpesa-woo-rene/src/Mpesa/STK.php
<?php

namespace Osen\Woocommerce\Mpesa;

/**
 * @package MPesa For WooCommerce
 * @subpackage C2B Library
 * @author Osen Concepts < hi@osen.co.ke >
 * @version 2.0.0
 * @since 0.18.01
 */

/**
 *
 */
class STK
{
	/**
	 * @param string  | Environment in use    | live/sandbox
	 */
	public $env = 'sandbox';

	/**
	 * @param string | Daraja App Consumer Key   | lipia/validate
	 */
	public $appkey;

	/**
	 * @param string | Daraja App Consumer Key   | lipia/validate
	 */
	public $rate;

	/**
	 * @param string | Daraja App Consumer Secret   | lipia/validate
	 */
	public $appsecret;

	/**
	 * @param string | Online Passkey | lipia/validate
	 */
	public $passkey;

	/**
	 * @param string  | Head Office Shortcode | 123456
	 */
	public $headoffice;

	/**
	 * @param string  | Business Paybill/Till | 123456
	 */
	public $shortcode;

	/**
	 * @param integer | Identifier Type   | 1(MSISDN)/2(Till)/4(Paybill)
	 */
	public $type = 4;

	/**
	 * @param string | Validation URI   | lipia/validate
	 */
	public $validate;

	/**
	 * @param string  | Confirmation URI  | lipia/confirm
	 */
	public $confirm;

	/**
	 * @param string  | Reconciliation URI  | lipia/reconcile
	 */
	public $reconcile;

	/**
	 * @param string  | Timeout URI   | lipia/reconcile
	 */
	public $results;

	/**
	 * @param string  | Timeout URI   | lipia/reconcile
	 */
	public $timeout;

	/**
	 * @param string  | Timeout URI   | lipia/reconcile
	 */
	public $username;

	/**
	 * @param string  | Timeout URI   | lipia/reconcile
	 */
	public $credentials;

	/**
	 * @param string  | Encryption Signature
	 */
	public $signature;

	/**
	 * @param array $config - Key-value pairs of settings
	 */
	public function __construct()
	{
		$c2b = get_option('woocommerce_mpesa_settings', []);
		$config = array(
			'env'        => $c2b['env'] ?? 'sandbox',
			'appkey'     => $c2b['key'] ?? 'bclwIPkcRqw61yUt',
			'appsecret'  => $c2b['secret'] ?? '9v38Dtu5u2BpsITPmLcXNWGMsjZRWSTG',
			'headoffice' => $c2b['headoffice'] ?? '174379',
			'shortcode'  => $c2b['shortcode'] ?? '174379',
			'type'       => $c2b['idtype'] ?? 4,
			'rate'       => $c2b['rate'] ?? 124,
			'passkey'    => $c2b['passkey'] ?? 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919',
			'validate'   => home_url('lipwa/validate/'),
			'confirm'    => home_url('lipwa/confirm/'),
			'reconcile'  => home_url('lipwa/reconcile/'),
			'timeout'    => home_url('lipwa/timeout/'),
			'signature'  => $c2b['signature'] ?? md5(random_bytes(8)),
		);

		foreach ($config as $key => $value) {
			$this->$key = $value;
		}
	}

	/**
	 * Function to generate access token
	 * @return string/mixed
	 */
	public function token()
	{
		$endpoint = ($this->env == 'live')
			? 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials'
			: 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';

		$credentials = base64_encode($this->appkey . ':' . $this->appsecret);
		$response    = wp_remote_get(
			$endpoint,
			array(
				'headers' => array(
					'Authorization' => 'Basic ' . $credentials,
				),
			)
		);

		$return = is_wp_error($response) ? 'null' : json_decode($response['body']);

		return is_null($return) ? '' : (isset($return->access_token) ? $return->access_token : '');
	}

	/**
	 * Function to process response data for validation
	 * @param callable $callback - Optional callable function to process the response - must return boolean
	 * @return array
	 */
	public function validate($callback = null, $data = [])
	{
		if (is_null($callback) || empty($callback)) {
			return array(
				'ResultCode' => 0,
				'ResultDesc' => 'Success',
			);
		} else {
			if (!call_user_func_array($callback, array($data))) {
				return array(
					'ResultCode' => 1,
					'ResultDesc' => 'Failed',
				);
			} else {
				return array(
					'ResultCode' => 0,
					'ResultDesc' => 'Success',
				);
			}
		}
	}

	/**
	 * Function to process response data for confirmation
	 * @param callable $callback - Optional callable function to process the response - must return boolean
	 * @return array
	 */
	public function confirm($callback = null, $data = [])
	{
		if (is_null($callback) || empty($callback)) {
			return array(
				'ResultCode' => 0,
				'ResultDesc' => 'Success',
			);
		} else {
			if (!call_user_func_array($callback, array($data))) {
				return array(
					'ResultCode' => 1,
					'ResultDesc' => 'Failed',
				);
			} else {
				return array(
					'ResultCode' => 0,
					'ResultDesc' => 'Success',
				);
			}
		}
	}

	/**
     * Function to query stkpush payment
     *
     * @param string|int $checkoutRequestID - Checkout Request
     *
     * @return array
     */
    public function query($checkoutRequestID)
    {
        $timestamp = date('YmdHis');
				$endpoint = ($this->env == 'live')
					? 'https://api.safaricom.co.ke/mpesa/stkpushquery/v1/query'
					: 'https://sandbox.safaricom.co.ke/mpesa/stkpushquery/v1/query';
        $password  = base64_encode($this->headoffice . $this->passkey . $timestamp);
        $post_data = array(
            'BusinessShortCode' => $this->headoffice,
            'Password'          => $password,
            'Timestamp'         => $timestamp,
            'CheckoutRequestID' => $checkoutRequestID
        );

        $data_string = wp_json_encode($post_data);
        $response    = wp_remote_post(
            $endpoint,
            array(
                'headers' => array(
                    'Content-Type'  => 'application/json',
                    'Authorization' => 'Bearer ' . $this->token(),
                ),
                'body'    => $data_string,
            )
        );

        if (is_wp_error($response)) {
            return array('errorCode' => 1, 'errorMessage' => $response->get_error_message());
        } else {
            $body = json_decode($response['body'], true);
            return $body;
        }
    }

	/**
	 * Function to process request for payment
	 * @param string $phone     - Phone Number to send STK Prompt Request to
	 * @param string $amount    - Amount of money to charge
	 * @param string $reference - Account to show in STK Prompt
	 * @param string $trxdesc   - Transaction Description(optional)
	 * @param string $remark    - Remarks about transaction(optional)
	 * @return array
	 */
	public function request($phone, $amount, $reference, $trxdesc = 'WooCommerce Payment', $remark = 'WooCommerce Payment', $request = null)
	{
		$phone = preg_replace('/^0/', '254', str_replace("+", "", $phone));

		$endpoint = ($this->env == 'live')
			? 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest'
			: 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';

		$timestamp = date('YmdHis');
		$password  = base64_encode($this->headoffice . $this->passkey . $timestamp);
		$amount = $amount * intval($this->rate);

		$post_data = array(
			'BusinessShortCode' => $this->headoffice,
			'Password'          => $password,
			'Timestamp'         => $timestamp,
			'TransactionType'   => ($this->type == 4) ? 'CustomerPayBillOnline' : 'CustomerBuyGoodsOnline',
			'Amount'            => round($amount),
			'PartyA'            => $phone,
			'PartyB'            => $this->shortcode,
			'PhoneNumber'       => $phone,
			'CallBackURL'       => "{$this->reconcile}?sign={$this->signature}",
			'AccountReference'  => $reference,
			'TransactionDesc'   => $trxdesc,
			'Remark'            => $remark,
		);

		$data_string = json_encode($post_data);
		$response    = wp_remote_post(
			$endpoint,
			array(
				'headers' => array(
					'Content-Type'  => 'application/json',
					'Authorization' => 'Bearer ' . $this->token(),
				),
				'body'    => $data_string,
			)
		);

		if (is_wp_error($response)) {
			return array('errorCode' => 1, 'errorMessage' => wp_remote_retrieve_response_message($response));
		} else {
			$body = json_decode($response['body'], true);
			return is_null($request)
				? $body
				: array_merge($body, ['requested' => $post_data]);
		}
	}

	/**
	 * Function to process response data for reconciliation
	 * @param callable $callback - Optional callable function to process the response - must return boolean
	 * @return bool/array
	 */
	public function reconcile($callback = null, $data = null)
	{
		$response = is_null($data) ? json_decode(file_get_contents('php://input'), true) : $data;

		return is_null($callback)
			? array('resultCode' => 0, 'resultDesc' => 'Reconciliation successful')
			: call_user_func_array($callback, array($response));
	}

	/**
	 * Function to process response data if system times out
	 * @param callable $callback - Optional callable function to process the response - must return boolean
	 * @return bool/array
	 */
	public function timeout($callback = null, $data = null)
	{
		if (is_null($data)) {
			$response = json_decode(file_get_contents('php://input'), true);
			$response = isset($response['Body']) ? $response['Body'] : array();
		} else {
			$response = $data;
		}

		if (is_null($callback)) {
			return true;
		} else {
			return call_user_func_array($callback, array($response));
		}
	}

	public function status($transaction, $command = 'TransactionStatusQuery', $remarks = 'Transaction Status Query', $occasion = '')
	{
		$token    = $this->token();
		$endpoint = ($this->env == 'live')
			? 'https://api.safaricom.co.ke/mpesa/transactionstatus/v1/query'
			: 'https://sandbox.safaricom.co.ke/mpesa/transactionstatus/v1/query';

		$post_data = array(
			'Initiator'          => $this->username,
			'SecurityCredential' => $this->credentials,
			'CommandID'          => $command,
			'TransactionID'      => $transaction,
			'PartyA'             => $this->shortcode,
			'IdentifierType'     => $this->type,
			'ResultURL'          => $this->results,
			'QueueTimeOutURL'    => $this->timeout,
			'Remarks'            => $remarks,
			'Occasion'           => $occasion,
		);

		$data_string = json_encode($post_data);
		$response    = wp_remote_post(
			$endpoint,
			array(
				'headers' => array(
					'Content-Type'  => 'application/json',
					'Authorization' => 'Bearer ' . $this->token(),
				),
				'body'    => $data_string,
			)
		);

		return is_wp_error($response)
			? array('errorCode' => 1, 'errorMessage' => wp_remote_retrieve_response_message($response))
			: json_decode($response['body'], true);
	}
}