/** * Siteground Joomla Cache Plugin * * Flushes varnish cache when certain data change actions are invoked. Disables varnish cache * on SiteGround servers when users are logged in. * * @author George Penkov * @category Siteground Joomla Plugins * @package Siteground Joomla Cache Plugin */ defined('_JEXEC') or die(); JLoader::import('joomla.plugin.plugin'); JLoader::import('joomla.error.log'); /** * jSGCache Plugin * * @package jSGCache * @subpackage System */ class plgSystemjSGCache extends JPlugin { /** * JRegistry parameter object for the plugin. * @var JRegistry */ public $params = null; /** * Web path to the joomla application. * @var string */ private $_applicationPath = null; /** * Global cache flag. * @var bool */ private $_cacheEnabled = false; /** * Auto flush flag * @var bool */ private $_autoflush = false; /** * 3rd party auto flush flag * @var bool */ private $_autoflush3rdParty = false; /** * Client side auto flush flag * @var bool */ private $_autoflushClientSide = false; /** * Which tasks to ignore in the flush monitor * @var array */ private static $_ignoreTasks = array('login','logout','user.login','user.logout'); /** * Constructor * * @access public * @param object &$subject The object to observe */ public function __construct( &$subject ) { if(isset($_GET['sgCacheCheck']) && $_GET['sgCacheCheck'] == md5('joomlaCheck')) die('OK'); parent::__construct( $subject ); $plugin = JPluginHelper::getPlugin('system','jSGCache'); $this->params= new JRegistry(); $this->params->loadString($plugin->params, 'JSON'); $this->_cacheEnabled = $this->params->get('cache_enabled'); if ($this->_cacheEnabled === null) $this->_cacheEnabled == 1; $this->_autoflush = $this->params->get('autoFlush'); if ($this->_autoflush === null) $this->_autoflush = 1; $this->_autoflush3rdParty = $this->params->get('autoFlush-ThirdParty'); if ($this->_autoflush3rdParty === null) $this->_autoflush3rdParty = 1; $this->_autoflushClientSide = $this->params->get('autoFlush-ClientSide'); if ($this->_autoflushClientSide === null) $this->_autoflushClientSide = 0; } /** * Heartbeat cache checking function. Will also monitor $_GET for the jSGCache parameter * (pressing the purge cache button in admin) * * * @access public * @return null */ public function onAfterInitialise() { if (!$this->_cacheEnabled || $this->_isBlacklisted($this->_applicationPath)) { JResponse::setHeader('X-Cache-Enabled','False',true); return; } if ($this->_cacheEnabled) { JResponse::allowCache(true); JResponse::setHeader('X-Cache-Enabled','True',true); } //Init the application url $this->_applicationPath = str_replace(array('administrator/index.php','index.php'),'',str_replace($_SERVER['DOCUMENT_ROOT'],'',$_SERVER['SCRIPT_FILENAME'])); //Check for any admin action and proceed to flushMonitor and 3rd party plugins if ( isset($_POST['task']) || isset($_GET['task']) || isset($_GET['cart_virtuemart_product_id'])) { $this->_flushMonitor(); if ($this->_autoflush3rdParty) $this->_monitorThirdPartyPlugins(); } //Check if we have a logged in user and enable cache bypass cookie 'task' => string 'user.login' $user = JFactory::getUser(); if (!$user->guest || (isset($_POST['task']) && preg_match('/login/i', $_POST['task']))) { $_POST[JSession::getFormToken()] = 1; //Force the correct token, since the login box on the page is cached with the 1st visitors' token //Enable the cache bypass for logged users by setting a cache bypass cookie setcookie('jSGCacheBypass',1,time() + 6000,'/'); } if ($user->guest || (isset($_POST['task']) && $_POST['task'] == 'user.logout')) { //Remove the bypass cookie if not a logged user if (isset($_COOKIE['jSGCacheBypass'])) setcookie('jSGCacheBypass',0, time() - 3600,'/'); } // Handle purge button press when get has jSGCache=purge, but only in admin with a logged user if(isset($_GET['jSGCache']) && $_GET['jSGCache'] == 'purge' && JFactory::getApplication()->isAdmin() && !$user->guest ) $this->_purgeCache(true); } /** * Admin panel icon display * * @access public * @param string $context * @return array */ public function onGetIcons( $context ) { return array(array( 'link'=>'?jSGCache=purge', 'image'=>'refresh', 'text'=>JText::_('Purge jSGCache'), 'id'=>'jSGCache' )); } /** * Calls the cache server to purge the cache * * @access public * @param string|bool $message Message to be displayed if purge is successful. If this param is false no output would be done * @return null */ private function _purgeCache( $message = true ) { $purgeRequest = $this->_applicationPath . '(.*)'; // Construct the PURGE request $hostname = str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ); $purge_method = "PURGE"; $cacheServerSocket = fsockopen($hostname, 80, $errno, $errstr, 2); if(!$cacheServerSocket) { JError::raise(E_ERROR,500,JText::_('Connection to cache server failed!')); JError::raise(E_ERROR,500,JText::_($errstr ($errno))); return; } $request = "$purge_method {$purgeRequest} HTTP/1.0\r\nHost: {$_SERVER['SERVER_NAME']}\r\nConnection: Close\r\n\r\n"; if (preg_match('/^www\./',$_SERVER['SERVER_NAME'])) { $domain_no_www = preg_replace('/^www\./', '', $_SERVER['SERVER_NAME']); $request2 = "$purge_method {$purgeRequest} HTTP/1.0\r\nHost: {$domain_no_www}\r\nConnection: Close\r\n\r\n"; } else $request2 = "$purge_method {$purgeRequest} HTTP/1.0\r\nHost: www.{$_SERVER['SERVER_NAME']}\r\nConnection: Close\r\n\r\n"; fwrite($cacheServerSocket, $request); $response = fgets($cacheServerSocket); fclose($cacheServerSocket); $cacheServerSocket = fsockopen($hostname, 80, $errno, $errstr, 2); fwrite($cacheServerSocket, $request2); fclose($cacheServerSocket); if($message !== false) { if(preg_match('/200/',$response)) { if ($message === true) JFactory::getApplication()->enqueueMessage(JText::_('SG Cache Successfully Purged!')); else JFactory::getApplication()->enqueueMessage(JText::_( $message )); } else { JError::raise(E_NOTICE,501, JText::_('SG Cache: Purge was not successful!')); JError::raise(E_NOTICE,501, jText::_('Error: ' . $response)); } } } /** * Check if url is in caching blacklist * * @param string $applicationPath * * @return bool */ private function _isBlacklisted($applicationPath) { $blacklistArray = explode("\n",$this->params->get('blacklist')); $blacklistRegexArray = array(); $indexIsBlacklisted = false; foreach($blacklistArray as $key=>$row) { $row = trim($row); if ($row != '/' && $quoted = preg_quote($row,'/')) $blacklistRegexArray[$key] = $quoted; if ($row == '/') $indexIsBlacklisted = true; } if ($indexIsBlacklisted && $_SERVER['REQUEST_URI'] == $applicationPath) return true; if (empty($blacklistRegexArray)) return false; $blacklistRegex = '/('.implode('|',$blacklistRegexArray) . ')/i'; return preg_match($blacklistRegex, $_SERVER['REQUEST_URI']); } /** * 3rd party plugin monitor * * @access private * @return null */ private function _monitorThirdPartyPlugins() { // Kunena & K2 if ($this->params->get('autoFlush-ThirdParty') == 1 && isset($_POST['option']) && ($_POST['option']=='com_k2' || $_POST['option' ]== 'com_kunena')) { $this->_purgeCache(false); } // VirtueMart if ( (isset($_POST['option']) && $_POST['option'] == 'com_virtuemart') || ( isset($_GET['option']) && $_GET['option'] == 'com_virtuemart' ) || isset($_GET['cart_virtuemart_product_id']) ) { if($this->params->get('autoFlush-ThirdParty') == 1) $this->_purgeCache(false); } } /** * Action monitor * * @access private * @return null */ private function _flushMonitor() { $user = JFactory::getUser(); if ((!JFactory::getApplication()->isAdmin() && !$this->_autoflushClientSide) || $user->guest) return; $autoflush = $this->params->get('autoFlush'); if ($autoflush === null) $autoflush = 1; if (isset($_POST['task']) && $_POST['task'] && !in_array($_POST['task'],self::$_ignoreTasks) && $autoflush == 1) $this->_purgeCache(false); } }
You can download this documentation from here. You can also view this in the documentation section.
If you have any confusion you can contact us or hire us to this for you.
|-- forms/
|-- fields/
|-- rules/
|-- example_handler.xml
|-- images/
|-- example_handler.jpg
|-- language/
|-- en-GB/
|-- en-GB.plg_sellaciouspayment_example.ini
|-- en-GB.plg_sellaciouspayment_example.sys.ini
|-- libraries/
|-- tmpl/
|-- default.php
|-- example.php
|-- example.xml
$callbackUrl = $this->getCallbackUrl();
$feedbackUrl = $this->getCallbackUrl(array(), true);
$callbackUrl = $this->getCallbackUrl(array('status' => 'success'));
$feedbackUrl = $this->getCallbackUrl(array('status' => 'success'), true);
<?xml version="1.0" encoding="utf-8"?>
<form>
<fieldset name="payment">
<fields name="example_handler">
<!-- The form fields for payment information form goes here -->
</fields>
</fieldset>
</form>
<?xml version="1.0" encoding="utf-8"?>
<extension version="3.0" type="plugin" group="sellaciouspayment" method="upgrade">
<name>plg_sellaciouspayment_example</name>
<author>Izhar Aazmi</author>
<creationDate>November 06, 2017</creationDate>
<copyright>Copyright (C) 2017 Bhartiy Web Technologies. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>info@bhartiy.com</authorEmail>
<authorUrl>https://www.bhartiy.com</authorUrl>
<version>1.0.0</version>
<description>PLG_SELLACIOUSPAYMENT_EXAMPLE_XML_DESCRIPTION</description>
<files>
<folder>forms</folder>
<folder>images</folder>
<folder>language</folder>
<folder>libraries</folder>
<folder>tmpl</folder>
<filename plugin="example">example.php</filename>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="api_mode"
type="radio"
default="sandbox"
description="PLG_SELLACIOUSPAYMENT_EXAMPLE_API_MODE_DESC"
label="PLG_SELLACIOUSPAYMENT_EXAMPLE_API_MODE_LABEL"
>
<option value="live">PLG_SELLACIOUSPAYMENT_EXAMPLE_MODE_LIVE</option>
<option value="sandbox">PLG_SELLACIOUSPAYMENT_EXAMPLE_MODE_SANDBOX</option>
</field>
<field
name="merchant_code"
type="text"
required="true"
description="PLG_SELLACIOUSPAYMENT_EXAMPLE_MERCHANT_CODE_DESC"
label="PLG_SELLACIOUSPAYMENT_EXAMPLE_MERCHANT_CODE_LABEL"
class="inputbox"
/>
<field
name="merchant_key"
type="text"
required="true"
description="PLG_SELLACIOUSPAYMENT_EXAMPLE_MERCHANT_KEY_DESC"
label="PLG_SELLACIOUSPAYMENT_EXAMPLE_MERCHANT_KEY_LABEL"
class="inputbox"
/>
</fieldset>
</fields>
</config>
</extension>
/**
* Initiate the payment process
*
* @param stdClass $invoice The data required by the gateway
*
* @return void
*
* @throws Exception
*
* @since 1.0.0
*/
protected function initPayment($invoice)
{
$api = $this->getApiContext();
$callbackUrl = $this->getCallbackUrl(array('status' => 'success'));
$feedbackUrl = $this->getCallbackUrl(array(), true);
// You can perform the tasks relevant to the plugin's payment process.
// How to set the callback URLs depends on the gateway you are working for.
// Assuming $api->gateway_url is the gateway URL
$this->app->redirect($api->gateway_url);
}
/**
* Initiate the payment process
*
* @param stdClass $invoice The data required by the gateway
*
* @return void
*
* @throws Exception
*
* @since 1.0.0
*/
protected function initPayment($invoice)
{
$api = $this->getApiContext();
$callbackUrl = $this->getCallbackUrl(array('status' => 'success'));
$feedbackUrl = $this->getCallbackUrl(array(), true);
// You can perform the tasks relevant to the plugin's payment process.
// How to set the callback URLs depends on the gateway you are working for.
// If a redirection is not needed you can directly execute payment here.
$response = $this->executePayment();
$result = $this->handleResponse($response);
return $result;
}
<?php
/**
* @version 1.0.0
* @package Sellacious Payment - Example
*
* @copyright Copyright (C) 2017. Bhartiy Web Technologies. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
* @author Izhar Aazmi <info@bhartiy.com> - https://www.bhartiy.com
*/
// No direct access.
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
JLoader::import('sellacious.loader');
/**
* Plugin to manage payment via 'example' for sellacious shops checkout process
*
* @subpackage Example - Sellacious Payments
*
* @since 1.0.0
*/
class plgSellaciousPaymentExample extends SellaciousPluginPayment
{
/**
* Returns handlers to the payment methods that will be managed by this plugin
*
* @param string $context The calling context, must be 'com_sellacious.payment' to effect
* @param array &$handlers ByRef, associative array of handlers
*
* @return bool
*
* @since 1.0.0
*/
public function onCollectHandlers($context, array &$handlers)
{
if ($context == 'com_sellacious.payment')
{
$handlers['example_handler'] = JText::_('PLG_SELLACIOUSPAYMENT_EXAMPLE_API_EXAMPLE_HANDLER');
}
return true;
}
/**
* Validates given payment method against this filter.
* Used to check whether it is okay to show this payment method to user to choose for payment.
*
* @param string $context The context identifier:
* 'com_sellacious.paymentmethod.cart' OR 'com_sellacious.paymentmethod.addfund'
* @param Registry $method Registry object for the payment method to test against
* @param int $orderId The order id/transaction id etc, whatever is relevant for the said context
*
* @return bool
*
* @since 1.0.0
*/
public function onBeforeLoadPaymentMethod($context, Registry $method, $orderId = 0)
{
if ($context == 'com_sellacious.paymentmethod.cart' || $context == 'com_sellacious.paymentmethod.addfund')
{
if ($method->get('handler') == 'example_handler')
{
/**
* Decide whether all prerequisites to use this payment method is fulfilled,
* Such as API configuration set, user is authorised to use this method etc.
*
* Return true / false based on this decision
*/
}
}
return true;
}
/**
* This method is called when a user selects this payment method for making a payment.
* This will be the first thing to be called to handover the payment control to a payment plugin.
* Prior calling this method the order for which this payment is being made would be created in the database.
*
* @param string $context The calling context, must be 'com_sellacious.payment' to effect
*
* @return bool
*
* @throws Exception
*
* @since 1.0.0
*/
public function onRequestPayment($context)
{
// You should set the payment property at the very beginning of a call to avoid any collision.
$paymentId = $this->getState('id');
$this->payment = $this->helper->payment->getItem($paymentId);
// Get a list of supported handlers by this plugin
$handlers = array();
$this->onCollectHandlers($context, $handlers);
// Match the selected handler with the supported ones
if (!array_key_exists($this->payment->handler, $handlers))
{
return true;
}
// Collect all the required information for the payment processing
$invoice = $this->getInvoice();
if (!$invoice)
{
throw new Exception(JText::_('PLG_SELLACIOUSPAYMENT_EXAMPLE_CONTEXT_IS_NOT_VALID'));
}
// Execute the payment routine with the collected data
$this->initPayment($invoice);
return true;
}
/**
* Callback handler to execute after gateway approval callback (Authorisation)
*
* @param string $context The calling context, must be 'com_sellacious.payment' to effect
*
* @return bool
*
* @throws Exception
*
* @since 1.0.0
*/
public function onPaymentCallback($context)
{
// You should set the payment property at the very beginning of a call to avoid any collision.
$paymentId = $this->getState('id');
$this->payment = $this->helper->payment->getItem($paymentId);
$result = true;
if ($context == 'com_sellacious.payment' && $this->payment->handler == 'example_handler')
{
$response = $this->executePayment();
$result = $this->handleResponse($response);
}
return $result;
}
/**
* Feedback handler to execute after gateway approval (Authorisation) or on a payment notification from gateway
*
* @param string $context The calling context, must be 'com_sellacious.payment' to effect
*
* @return void
*
* @throws Exception
*
* @since 1.0.0
*/
public function onPaymentFeedback($context)
{
// You should set the payment property at the very beginning of a call to avoid any collision.
// This is a stateless call, therefore we cannot use getState()
$paymentId = $this->app->input->getInt('payment_id');
$this->payment = $this->helper->payment->getItem($paymentId);
// IMPORTANT: Set state value for stateless calls, else 'saveResponse' call would fail
$this->setState('id', $paymentId);
if ($context == 'com_sellacious.payment' && $this->payment->handler == 'example_handler')
{
/**
* Handle the response as appropriate.
* If needed and suitable you may call {@see executePayment()} and {@see handleResponse()}
*/
}
}
/**
* Sellacious do not bother about the details a plugin might need.
* Plugins are set free to fetch what they want. However basic data is directly accessible.
*
* @return stdClass All the required details for the transaction execution with the Payment Gateway
*
* @throws Exception
*
* @since 1.0.0
*/
protected function getInvoice()
{
$invoice = new stdClass;
// Implement this to gather all the information that is need for the payment.
// E.g. - Payment Amount, User information etc.
return $invoice;
}
/**
* Initialize SDK configurations using client key and secret with additional connection settings
*
* @return stdClass The API configuration values
*
* @throws Exception If the configuration is not set or is invalid
*
* @since 1.0.0
*/
protected function getApiContext()
{
$config = $this->getParams();
$sandbox = $config->get('api_mode') == 'sandbox';
$config->set('sandbox', $sandbox);
// Prepare and preprocess the configuration data as needed
$api = $config->toObject();
return $api;
}
/**
* Initiate the payment process
* The app will have to redirect the buyer to the gateway website, obtain their consent to the payment
* and subsequently execute the payment using the execute API call.
*
* @param stdClass $invoice The data required by the payment gateway to execute the transaction
*
* @return void
*
* @throws Exception
*
* @since 1.0.0
*/
protected function initPayment($invoice)
{
$api = $this->getApiContext();
$callbackUrl = $this->getCallbackUrl(array('status' => 'success'));
$feedbackUrl = $this->getCallbackUrl(array(), true);
// You can perform the tasks relevant to the plugin's payment process.
// How to set the callback URLs depends on the gateway you are working for.
$this->app->redirect($api->gateway_url);
}
/**
* Capture the authorized payment with the API.
*
* @return mixed
*
* @throws Exception
*
* @since 1.0.0
*/
protected function executePayment()
{
// Collect all response data returned by the gateway
$response = new stdClass;
// If a CAPTURE is needed do it here and obtain the final response
// Return the final response for response handler to evaluate
return $response;
}
/**
* Evaluate the final gateway response and update the payments table appropriately
*
* @param stdClass $response The response data returned by {@see executePayment()}
*
* @return bool
*
* @throws Exception
*
* @since 1.0.0
*/
protected function handleResponse($response)
{
$api = $this->getApiContext();
/**
* Call {@see saveResponse()} with the appropriate values either from response directly
* or creating the values logically based on response.
*/
$code = 'THE RESPONSE CODE';
$status = 'THE RESPONSE STATUS';
$message = 'THE RESPONSE MESSAGE';
$txn_id = 'THE GATEWAY TRANSACTION ID';
/**
* The data variable should contain the entire response except any sensitive information
* such as Credit Card information.
*/
$data = (array) $response;
/**
* The state variable should be set to one of the following constants as suitable.
*
* STATUS_PENDING | STATUS_ABORTED | STATUS_DECLINED | STATUS_AUTHORIZED |
* STATUS_APPROVAL_HOLD | STATUS_APPROVED
*/
$state = static::STATUS_APPROVED;
$this->saveResponse($code, $status, $message, $data, $txn_id, $state, $api->sandbox);
// Return true if transaction was approved or held for approval, else return false.
return $state == static::STATUS_APPROVED || $state == static::STATUS_APPROVAL_HOLD;
}
}
You can download this documentation from here. You can also view this in the documentation section.
If you have any confusion you can contact us or hire us to this for you.