AAAApayzen/elements/payzenlabel.php000066600000002144151374055400012716 0ustar00attributes('class') ? 'class="'.$node->attributes('class').'"' : 'class="text_area"' ); return ''; } }payzen/elements/payzenmultilist.php000066600000004552151374055400013672 0ustar00children() as $option) { $val = $option->attributes('value'); $text = $option->data(); $options[] = JHTML::_('select.option', $val, JText::_($text)); } // Construct the various argument calls that are supported. $attribs = ' '; if ($v = $node->attributes( 'size' )) { $attribs .= 'size="'.$v.'"'; } if ($v = $node->attributes( 'class' )) { $attribs .= 'class="'.$v.'"'; } else { $attribs .= 'class="inputbox"'; } if ($m = $node->attributes( 'multiple' )) { $attribs .= ' multiple="multiple"'; $ctrl .= '[]'; } // Render the HTML SELECT list. return JHTML::_('select.genericlist', $options, $ctrl, $attribs, 'value', 'text', $value, $control_name.$name ); } }payzen/elements/payzenurl.php000066600000003030151374055400012434 0ustar00attributes('class') ? 'class="'.$node->attributes('class').'"' : 'class="text_area"' ); if ($node->attributes( 'default' ) == $value) { $value = JURI::root(). $value; } if ($node->attributes( 'editable' ) == 'true') { $size = ( $node->attributes('size') ? 'size="'.$node->attributes('size').'"' : '' ); return ''; } else { return ''; } } }payzen/elements/.htaccess000066600000000177151374055400011501 0ustar00 Order allow,deny Deny from all payzen/elements/index.html000066600000000000151374055400011661 0ustar00payzen/payzen_api.php000066600000124646151374055400010747 0ustar00 * @copyright Lyra-network.com * PHP classes to integrate an e-commerce solution with the payment platform supported by lyra-network. */ /** * Class managing parameters checking, form and signature building, response analysis and more * @package VadsApi * @version 2.1 */ class VadsApi { // ************************************** // PROPERTIES // ************************************** /** * The fields to send to the vads platform * @var array[string]VadsField * @access private */ var $requestParameters; /** * Certificate to send in TEST mode * @var string * @access private */ var $keyTest; /** * Certificate to send in PRODUCTION mode * @var string * @access private */ var $keyProd; /** * Url of the payment page * @var string * @access private */ var $platformUrl; /** * Set to true to send the redirect_* parameters * @var boolean * @access private */ var $redirectEnabled; /** * SHA-1 authentication signature * @var string * @access private */ var $signature; /** * Raw response sent by the platform * @var VadsResponse * @access private */ var $response; /** * The original data encoding. * @var string * @access private */ var $encoding; /** * The list of categories for payment with bank accord. To be sent with the products detail if you use this payment mean. * @static * @var array * @access public */ var $ACCORD_CATEGORIES = array("FOOD_AND_GROCERY","AUTOMOTIVE","ENTERTAINMENT","HOME_AND_GARDEN","HOME_APPLIANCE","AUCTION_AND_GROUP_BUYING","FLOWERS_AND_GIFTS","COMPUTER_AND_SOFTWARE","HEALTH_AND_BEAUTY","SERVICE_FOR_INDIVIDUAL","SERVICE_FOR_BUSINESS","SPORTS","CLOTHING_AND_ACCESSORIES","TRAVEL","HOME_AUDIO_PHOTO_VIDEO","TELEPHONY"); // ************************************** // CONSTRUCTOR // ************************************** /** * Constructor. * Initialize request fields definitions. */ function VadsApi($encoding="UTF-8") { //TODO success n'est pas utilisé $success = true; // Initialize encoding $supported_encodings = array("UTF-8", "ASCII", "Windows-1252", "ISO-8859-15", "ISO-8859-1", "ISO-8859-6", "CP1256"); $this->encoding = in_array(strtoupper($encoding), $supported_encodings) ? strtoupper($encoding) : "UTF-8"; /* * Définition des paramètres de la requête */ // Common or long regexes $ans = "[^<>]"; // Any character (except the dreadful "<" and ">") $an63 = '#^[A-Za-z0-9]{0,63}$#'; $an255 = '#^[A-Za-z0-9]{0,255}$#'; $ans255 = '#^' . $ans . '{0,255}$#'; $ans127 = '#^' . $ans . '{0,127}$#'; $supzero = '[1-9]\d*'; $regex_payment_cfg = '#^(SINGLE|MULTI:first=\d+;count=' . $supzero . ';period=' . $supzero . ')$#'; $regex_trans_date = '#^\d{4}' . '(1[0-2]|0[1-9])' . '(3[01]|[1-2]\d|0[1-9])' . '(2[0-3]|[0-1]\d)' . '([0-5]\d){2}$#';//AAAAMMJJhhmmss $regex_mail = '#^[^@]+@[^@]+\.\w{2,4}$#'; //TODO plus restrictif $regex_params = '#^([^&=]+=[^&=]*)?(&[^&=]+=[^&=]*)*$#'; //name1=value1&name2=value2... // Déclaration des paramètres, de leur valeurs par défaut, de leur format... // $this->_addRequestField('raw_signature', 'DEBUG Signature', '#^.+$#', // false); $this->_addRequestField('signature', 'Signature', "#^[0-9a-f]{40}$#", true); $this->_addRequestField('vads_action_mode', 'Action mode', "#^INTERACTIVE|SILENT$#", true, 11); $this->_addRequestField('vads_amount', 'Amount', '#^' . $supzero . '$#', true); $this->_addRequestField('vads_available_languages', 'Available languages', "#^(|[A-Za-z]{2}(;[A-Za-z]{2})*)$#", false, 2); $this->_addRequestField('vads_capture_delay', 'Capture delay', "#^\d*$#"); $this->_addRequestField('vads_contracts', 'Contracts', $ans255); $this->_addRequestField('vads_contrib', 'Contribution', $ans255); $this->_addRequestField('vads_ctx_mode', 'Mode', "#^TEST|PRODUCTION$#", true); $this->_addRequestField('vads_currency', 'Currency', "#^\d{3}$#", true, 3); $this->_addRequestField('vads_cust_antecedents', 'Customer history', "#^NONE|NO_INCIDENT|INCIDENT$#"); $this->_addRequestField('vads_cust_address', 'Customer address', $ans255); $this->_addRequestField('vads_cust_country', 'Customer country', "#^[A-Za-z]{2}$#", false, 2); $this->_addRequestField('vads_cust_email', 'Customer email', $regex_mail, false, 127); $this->_addRequestField('vads_cust_id', 'Customer id', $an63, false, 63); $this->_addRequestField('vads_cust_name', 'Customer name', $ans127, false, 127); $this->_addRequestField('vads_cust_cell_phone', 'Customer cell phone', $an63, false, 63); $this->_addRequestField('vads_cust_phone', 'Customer phone', $an63, false, 63); $this->_addRequestField('vads_cust_title', 'Customer title', '#^'.$ans.'{0,63}$#', false, 63); $this->_addRequestField('vads_cust_city', 'Customer city', '#^' . $ans . '{0,63}$#', false, 63); $this->_addRequestField('vads_cust_state', 'Customer state/region', '#^'.$ans.'{0,63}$#', false, 63); $this->_addRequestField('vads_cust_zip', 'Customer zip code', $an63, false, 63); $this->_addRequestField('vads_language', 'Language', "#^[A-Za-z]{2}$#", false, 2); $this->_addRequestField('vads_order_id', 'Order id', "#^[A-za-z0-9]{0,12}$#", false, 12); $this->_addRequestField('vads_order_info', 'Order info', $ans255); $this->_addRequestField('vads_order_info2', 'Order info 2', $ans255); $this->_addRequestField('vads_order_info3', 'Order info 3', $ans255); $this->_addRequestField('vads_page_action', 'Page action', "#^PAYMENT$#", true, 7); $this->_addRequestField('vads_payment_cards', 'Payment cards', "#^[A-Za-z0-9;]{0,127}$#", false, 127); $this->_addRequestField('vads_payment_config', 'Payment config', $regex_payment_cfg, true); $this->_addRequestField('vads_payment_src', 'Payment source', "#^$#", false, 0); $this->_addRequestField('vads_redirect_error_message', 'Redirection error message', $ans255, false); $this->_addRequestField('vads_redirect_error_timeout', 'Redirection error timeout', $ans255, false); $this->_addRequestField('vads_redirect_success_message', 'Redirection success message', $ans255, false); $this->_addRequestField('vads_redirect_success_timeout', 'Redirection success timeout', $ans255, false); $this->_addRequestField('vads_return_mode', 'Return mode', "#^NONE|GET|POST?$#", false, 4); $this->_addRequestField('vads_return_get_params', 'GET return parameters', $regex_params, false); $this->_addRequestField('vads_return_post_params', 'POST return parameters', $regex_params, false); $this->_addRequestField('vads_ship_to_name', 'Shipping name', '#^' . $ans . '{0,127}$#', false, 127); $this->_addRequestField('vads_ship_to_phone_num', 'Shipping phone', $ans255, false, 63); $this->_addRequestField('vads_ship_to_street', 'Shipping street', $ans127, false, 127); $this->_addRequestField('vads_ship_to_street2', 'Shipping street (2)', $ans127, false, 127); $this->_addRequestField('vads_ship_to_state', 'Shipping state', $an63, false, 63); $this->_addRequestField('vads_ship_to_country', 'Shipping country', "#^[A-Za-z]{2}$#", false, 2); $this->_addRequestField('vads_ship_to_city', 'Shipping city', '#^' . $ans . '{0,63}$#', false, 63); $this->_addRequestField('vads_ship_to_zip', 'Shipping zip code', $an63, false, 63); $this->_addRequestField('vads_shop_name', 'Shop name', $ans127); $this->_addRequestField('vads_shop_url', 'Shop url', $ans127); $this->_addRequestField('vads_site_id', 'Site id', "#^\d{8}$#", true, 8); $this->_addRequestField('vads_theme_config', 'Theme', $ans255); $this->_addRequestField('vads_trans_date', 'Transaction date', $regex_trans_date, true, 14); $this->_addRequestField('vads_trans_id', 'Transaction id', "#^[0-8]\d{5}$#", true, 6); $this->_addRequestField('vads_url_success', 'Success url', $ans127, false, 127); $this->_addRequestField('vads_url_referral', 'Referral url', $ans127, false, 127); $this->_addRequestField('vads_url_refused', 'Refused url', $ans127, false, 127); $this->_addRequestField('vads_url_cancel', 'Cancel url', $ans127, false, 127); $this->_addRequestField('vads_url_error', 'Error url', $ans127, false, 127); $this->_addRequestField('vads_url_return', 'Return url', $ans127, false, 127); $this->_addRequestField('vads_user_info', 'User info', $ans255); $this->_addRequestField('vads_validation_mode', 'Validation mode', "#^[01]?$#", false, 1); $this->_addRequestField('vads_version', 'Gateway version', "#^V2$#", true, 2); // Enable / disable 3D Secure $this->_addRequestField('vads_threeds_mpi', 'Enable / disable 3D Secure', '#^[0-2]$#', false); // Declaration of parameters for Oney payment $this->_addRequestField('vads_cust_first_name', 'Customer first name', $an63, false, 63); $this->_addRequestField('vads_cust_last_name', 'Customer last name', $an63, false, 63); $this->_addRequestField('vads_cust_status', 'Customer status (private or company)', "#^PRIVATE|COMPANY$#", false, 7); $this->_addRequestField('vads_ship_to_first_name', 'Shipping first name', $an63, false, 63); $this->_addRequestField('vads_ship_to_last_name', 'Shipping last name', $an63, false, 63); $this->_addRequestField('vads_ship_to_status', 'Shipping status (private or company)', "#^PRIVATE|COMPANY$#", false, 7); $this->_addRequestField('vads_ship_to_delivery_company_name', 'Name of the delivery company', $ans127, false, 127); $this->_addRequestField('vads_ship_to_speed', 'Speed of the shipping method', "#^STANDARD|EXPRESS$#", false, 8); $this->_addRequestField('vads_ship_to_type', 'Type of the shipping method', "#^RECLAIM_IN_SHOP|RELAY_POINT|RECLAIM_IN_STATION|PACKAGE_DELIVERY_COMPANY|ETICKET$#", false, 24); $this->_addRequestField('vads_insurance_amount', 'The amount of insurance', '#^' . $supzero . '$#', false, 12); $this->_addRequestField('vads_tax_amount', 'The amount of tax', '#^' . $supzero . '$#', false, 12); $this->_addRequestField('vads_shipping_amount', 'The amount of shipping', '#^' . $supzero . '$#', false, 12); $this->_addRequestField('vads_nb_products', 'Number of products', '#^' . $supzero . '$#', false); // Set some default parameters $success &= $this->set('vads_version', 'V2'); $success &= $this->set('vads_page_action', 'PAYMENT'); $success &= $this->set('vads_action_mode', 'INTERACTIVE'); $success &= $this->set('vads_payment_config', 'SINGLE'); $timestamp = time(); $success &= $this->set('vads_trans_id', $this->_generateTransId($timestamp)); $success &= $this->set('vads_trans_date', gmdate('YmdHis', $timestamp)); } /** * Generate a trans_id. * To be independent from shared/persistent counters, we use the number of 1/10seconds since midnight, * which has the appropriate format (000000-899999) and has great chances to be unique. * @return string the generated trans_id * @access private */ function _generateTransId($timestamp) { list($usec, $sec) = explode(" ", microtime()); // microseconds, php4 compatible $temp = ($timestamp + $usec - strtotime('today 00:00')) * 10; $temp = sprintf('%06d', $temp); return $temp; } /** * Shortcut function used in constructor to build requestParameters * @param string $name * @param string $label * @param string $regex * @param boolean $required * @param mixed $value * @return boolean true on success * @access private */ function _addRequestField($name, $label, $regex, $required = false, $length = 255, $value = null) { $this->requestParameters[$name] = new VadsField($name, $label, $regex, $required, $length); if($value !== null) { return $this->set($name, $value); } else { return true; } } // ************************************** // INTERNATIONAL FUNCTIONS // ************************************** /** * Returns the iso codes of language accepted by the payment page * @static * @return array[int]string */ function getSupportedLanguages() { return array('fr', 'de', 'en', 'es', 'zh', 'it', 'ja', 'pt', 'nl'); } /** * Return the list of currencies recognized by the vads platform * @static * @return array[int]VadsCurrency */ function getSupportedCurrencies() { return array( new VadsCurrency('ARS', 32), new VadsCurrency('AUD', 36), new VadsCurrency('KHR', 116, 0), new VadsCurrency('CAD', 124), new VadsCurrency('CNY', 156, 1), new VadsCurrency('HRK', 191), new VadsCurrency('CZK', 203), new VadsCurrency('DKK', 208), new VadsCurrency('EKK', 233), new VadsCurrency('HKD', 344), new VadsCurrency('HUF', 348), new VadsCurrency('ISK', 352, 0), new VadsCurrency('IDR', 360, 0), new VadsCurrency('JPY', 392, 0), new VadsCurrency('KRW', 410, 0), new VadsCurrency('LVL', 428), new VadsCurrency('LTL', 440), new VadsCurrency('MYR', 458), new VadsCurrency('MXN', 484), new VadsCurrency('NZD', 554), new VadsCurrency('NOK', 578), new VadsCurrency('PHP', 608), new VadsCurrency('RUB', 643), new VadsCurrency('SGD', 702), new VadsCurrency('ZAR', 710), new VadsCurrency('SEK', 752), new VadsCurrency('CHF', 756), new VadsCurrency('THB', 764), new VadsCurrency('GBP', 826), new VadsCurrency('USD', 840), new VadsCurrency('TWD', 901, 1), new VadsCurrency('RON', 946), new VadsCurrency('TRY', 949), new VadsCurrency('XOF', 952, 0), new VadsCurrency('XPF', 953, 0), new VadsCurrency('BGN', 975), new VadsCurrency('EUR', 978), new VadsCurrency('PLN', 985), new VadsCurrency('BRL', 986)); } /** * Return a currency from its iso 3-letters code * @static * @param string $alpha3 * @return VadsCurrency */ function findCurrencyByAlphaCode($alpha3) { $list = VadsApi::getSupportedCurrencies(); foreach ($list as $currency) { /** @var VadsCurrency $currency */ if ($currency->alpha3 == $alpha3) { return $currency; } } return null; } /** * Returns a currency form its iso numeric code * @static * @param int $num * @return VadsCurrency */ function findCurrencyByNumCode($numeric) { $list = VadsApi::getSupportedCurrencies(); foreach ($list as $currency) { /** @var VadsCurrency $currency */ if ($currency->num == $numeric) { return $currency; } } return null; } /** * Returns a currency numeric code from its 3-letters code * @static * @param string $alpha3 * @return int */ function getCurrencyNumCode($alpha3) { $currency = VadsApi::findCurrencyByAlphaCode($alpha3); return is_a($currency, 'VadsCurrency') ? $currency->num : null; } // ************************************** // GETTERS/SETTERS // ************************************** /** * Shortcut for setting multiple values with one array * @param array[string]mixed $parameters * @return boolean true on success */ function setFromArray($parameters) { $ok = true; foreach ($parameters as $name => $value) { $ok &= $this->set($name, $value); } return $ok; } /** * General getter. * Retrieve an api variable from its name. Automatically add 'vads_' to the name if necessary. * Example : get('site_id'); ?> * @param string $name * @return mixed null if $name was not recognised */ function get($name) { if (!$name || !is_string($name)) { return null; } // V1/shortcut notation compatibility $name = (substr($name, 0, 5) != 'vads_') ? 'vads_' . $name : $name; if ($name == 'vads_key_test') { return $this->keyTest; } elseif ($name == 'vads_key_prod') { return $this->keyProd; } elseif ($name == 'vads_platform_url') { return $this->platformUrl; } elseif ($name == 'vads_redirect_enabled') { return $this->redirectEnabled; } elseif (array_key_exists($name, $this->requestParameters)) { return $this->requestParameters[$name] ->getValue(); } else { return null; } } /** * General setter. * Set an api variable with its name and the provided value. Automatically add 'vads_' to the name if necessary. * Example : set('site_id', '12345678'); ?> * @param string $name * @param mixed $value * @return boolean true on success */ function set($name, $value) { if (!$name || !is_string($name)) { return false; } // V1/shortcut notation compatibility $name = (substr($name, 0, 5) != 'vads_') ? 'vads_' . $name : $name; // Convert the parameters if they are not encoded in utf8 if($this->encoding !== "UTF-8") { $value = iconv($this->encoding, "UTF-8", $value); } // Search appropriate setter if ($name == 'vads_key_test') { return $this->setCertificate($value, 'TEST'); } elseif ($name == 'vads_key_prod') { return $this->setCertificate($value, 'PRODUCTION'); } elseif ($name == 'vads_platform_url') { return $this->setPlatformUrl($value); } elseif ($name == 'vads_redirect_enabled') { return $this->setRedirectEnabled($value); } elseif (array_key_exists($name, $this->requestParameters)) { return $this->requestParameters[$name] ->setValue($value); } else { return false; } } /** * Set target url of the payment form * @param string $url * @return boolean */ function setPlatformUrl($url) { if (!preg_match('#https?://([^/]+/)+#', $url)) { return false; } $this->platformUrl = $url; return true; } /** * Enable/disable redirect_* parameters * @param mixed $enabled false, '0', a null or negative integer or 'false' to disable * @return boolean */ function setRedirectEnabled($enabled) { $this->redirectEnabled = !(!$enabled || $enabled == '0' || strtolower($enabled) == 'false'); return true; } /** * Set TEST or PRODUCTION certificate * @param string $key * @param string $mode * @return boolean true if the certificate could be set */ function setCertificate($key, $mode) { // Check format if (!preg_match('#\d{16}#', $key)) { return false; } if ($mode == 'TEST') { $this->keyTest = $key; } elseif ($mode == 'PRODUCTION') { $this->keyProd = $key; } else { return false; } return true; } /** * Add product infos as request parameters. * @param string $label * @param int $amount * @param int $qty * @param string $ref * @param string $type * @return boolean true if product infos are set correctly */ function addProduct($label, $amount, $qty, $ref, $type) { $index = $this->get("nb_products") ? $this->get("nb_products") : 0; $ok = true; // Add product infos as request parameters $ok &= $this->_addRequestField("vads_product_label" . $index, "Product label", '#^[^<>"+-]{0,255}$#', false, 255, $label); $ok &= $this->_addRequestField("vads_product_amount" . $index, "Product amount", '#^[1-9]\d*$#', false, 12, $amount); $ok &= $this->_addRequestField("vads_product_qty" . $index, "Product quantity", '#^[1-9]\d*$#', false, 255, $qty); $ok &= $this->_addRequestField("vads_product_ref" . $index, "Product reference", '#^[A-Za-z0-9]{0,64}$#', false, 64, $ref); $ok &= $this->_addRequestField("vads_product_type" . $index, "Product type", "#^".implode("|", $this->ACCORD_CATEGORIES)."$#", false, 30, $type); // Increment the number of products $ok &= $this->set("nb_products", $index + 1); return $ok; } /** * Return certificate according to current mode, false if mode was not set * @return string|boolean * @access private */ function _getCertificate() { switch ($this->requestParameters['vads_ctx_mode'] ->getValue()) { case 'TEST': return $this->keyTest; break; case 'PRODUCTION': return $this->keyProd; break; default: return false; break; } } /** * Generate signature from a list of VadsField * @param array[string]VadsField $fields * @return string * @access private */ function _generateSignatureFromFields($fields = null, $hashed = true) { $params = array(); $fields = ($fields !== null) ? $fields : $this->requestParameters; foreach ($fields as $field) { if ($field->isRequired() || $field->isFilled()) { $params[$field->getName()] = $field->getValue(); } } return $this->sign($params, $this->_getCertificate(), $hashed); } /** * Public static method to compute a vads signature. Parameters must be in utf-8. * @param array[string]string $parameters payment gateway request/response parameters * @param string $key shop certificate * @param boolean $hashed set to false to get the raw, unhashed signature * @access public * @static */ function sign($parameters, $key, $hashed= true) { $signContent = ""; ksort($parameters); foreach ($parameters as $name => $value) { if (substr($name, 0, 5) == 'vads_') { $signContent .= $value . '+'; } } $signContent .= $key; $sign = $hashed ? sha1($signContent) : $signContent; return $sign; } // ************************************** // REQUEST PREPARATION FUNCTIONS // ************************************** /** * Unset the value of optionnal fields if they are unvalid */ function clearInvalidOptionnalFields() { $fields = $this->getRequestFields(); foreach ($fields as $field) { if (!$field->isValid() && !$field->isRequired()) { $field->setValue(null); } } } /** * Check all payment fields * @param array $errors will be filled with the name of invalid fields * @return boolean */ function isRequestReady(&$errors = null) { $errors = is_array($errors) ? $errors : array(); $fields = $this->getRequestFields(); foreach ($fields as $field) { if (!$field->isValid()) { $errors[] = $field->getName(); } } return sizeof($errors) == 0; } /** * Return the list of fields to send to the payment gateway * @return array[string]VadsField a list of VadsField or false if a parameter was invalid * @see VadsField */ function getRequestFields() { $fields = $this->requestParameters; // Filter redirect_parameters if redirect is disabled if (!$this->redirectEnabled) { $redirectFields = array( 'vads_redirect_success_timeout', 'vads_redirect_success_message', 'vads_redirect_error_timeout', 'vads_redirect_error_message'); foreach ($redirectFields as $fieldName) { unset($fields[$fieldName]); } } foreach ($fields as $fieldName => $field) { if (!$field->isFilled() && !$field->isRequired()) { unset($fields[$fieldName]); } } // Compute signature $fields['signature']->setValue($this->_generateSignatureFromFields($fields)); // Return the list of fields return $fields; } /** * Return the url of the payment page with urlencoded parameters (GET-like url) * @return boolean|string */ function getRequestUrl() { $fields = $this->getRequestFields(); $url = $this->platformUrl . '?'; foreach ($fields as $field) { if ($field->isFilled()) { $url .= $field->getName() . '=' . rawurlencode($field->getValue()) . '&'; } } $url = substr($url, 0, -1); // remove last & return $url; } /** * Return the html form to send to the payment gateway * @param string $enteteAdd * @param string $inputType * @param string $buttonValue * @param string $buttonAdd * @param string $buttonType * @return string */ function getRequestHtmlForm($enteteAdd = '', $inputType = 'hidden', $buttonValue = 'Aller sur la plateforme de paiement', $buttonAdd = '', $buttonType = 'submit') { $html = ""; $html .= '
'; $html .= "\n"; $html .= $this->getRequestFieldsHtml('type="' . $inputType . '"'); $html .= ''; $html .= "\n"; $html .= '
'; return $html; } /** * Return the html code of the form fields to send to the payment page * @param string $inputAttributes * @return string */ function getRequestFieldsHtml($inputAttributes = 'type="hidden"') { $fields = $this->getRequestFields(); $html = ''; $format = '\n"; foreach ($fields as $field) { if ($field->isFilled()) { // Convert special chars to HTML entities to avoid data troncation $value = htmlspecialchars($field->getValue(), ENT_QUOTES, 'UTF-8'); $html .= sprintf($format, $field->getName(), $value); } } return $html; } // ************************************** // RESPONSE ANALYSIS FUNCTIONS // ************************************** /** * Prepare to analyse check url or return url call * @param array[string]string $parameters $_REQUEST by default * @param string $ctx_mode * @param string $key_test * @param string $key_prod */ function loadResponse($parameters = null, $ctx_mode = null, $key_test = null, $key_prod = null) { $parameters = is_null($parameters) ? $_REQUEST : $parameters; $parameters = VadsApi::uncharm($parameters); // Load site credentials if provided if (!is_null($ctx_mode)) { $this->set('vads_ctx_mode', $ctx_mode); } if (!is_null($key_test)) { $this->set('vads_key_test', $key_test); } if (!is_null($key_prod)) { $this->set('vads_key_prod', $key_prod); } $this->response = new VadsResponse(); $this->response->load($parameters, $this->_getCertificate()); } /** * Return a VadsResponse object representing the result of the payment. * You can provide arguments to load data as in loadResponse. * @see VadsApi::loadResponse * @return VadsResponse */ function getResponse($parameters = null, $ctx_mode = null, $key_test = null, $key_prod = null) { //TODO ? redondance avec loadResponse if (is_null($this->response)) { $this->loadResponse($parameters, $ctx_mode, $key_test, $key_prod); } return $this->response; } /** * PHP is not yet a sufficiently advanced technology to be indistinguishable from magic... * so don't use magic_quotes, they mess up with the gateway response analysis. * * @param array $potentiallyMagicallyQuotedData */ function uncharm($potentiallyMagicallyQuotedData) { if (get_magic_quotes_gpc()) { $sane = array(); foreach ($potentiallyMagicallyQuotedData as $k => $v) { $saneKey = stripslashes($k); $saneValue = is_array($v) ? VadsApi::uncharm($v) : stripslashes($v); $sane[$saneKey] = $saneValue; } } else { $sane = $potentiallyMagicallyQuotedData; } return $sane; } } /** * Class representing the result of a transaction (sent by the check url or by the client return) * @package VadsApi */ class VadsResponse { /** * Raw response parameters array * @var array * @access private */ var $raw_response = array(); /** * Certificate used to check the signature * @see VadsApi::sign * @var boolean * @access private */ var $certificate; /** * Value of vads_result * @var string * @access private */ var $code; /** * Translation of $code (vads_result) * @var string * @access private */ var $message; /** * Value of vads_extra_result * @var string * @access private */ var $extraCode; /** * Translation of $extraCode (vads_extra_result) * @var string * @access private */ var $extraMessage; /** * Value of vads_auth_result * @var string * @access private */ var $authCode; /** * Translation of $authCode (vads_auth_result) * @var string * @access private */ var $authMessage; /** * Value of vads_warranty_result * @var string * @access private */ var $warrantyCode; /** * Translation of $warrantyCode (vads_warranty_result) * @var string * @access private */ var $warrantyMessage; /** * Associative array containing human-readable translations of response codes. Initialized to french translations. * @var array * @access private */ var $translation = array( 'no_code' => '', 'no_translation' => '', 'results' => array( '00' => 'Paiement réalisé avec succès', '02' => 'Le commerçant doit contacter la banque du porteur', '05' => 'Paiement refusé', '17' => 'Annulation client', '30' => 'Erreur de format de la requête', '96' => 'Erreur technique lors du paiement'), 'extra_results_default' => array( 'empty' => 'Pas de contrôle effectué', '00' => 'Tous les contrôles se sont déroulés avec succès', '02' => 'La carte a dépassé l’encours autorisé', '03' => 'La carte appartient à la liste grise du commerçant', '04' => 'Le pays d’émission de la carte appartient à la liste grise du commerçant', '05' => 'L’adresse IP appartient à la liste grise du commerçant', '99' => 'Problème technique rencontré par le serveur lors du traitement d’un des contrôles locaux'), 'extra_results_30' => array( '00' => 'signature', '01' => 'version', '02' => 'merchant_site_id', '03' => 'transaction_id', '04' => 'date', '05' => 'validation_mode', '06' => 'capture_delay', '07' => 'config', '08' => 'payment_cards', '09' => 'amount', '10' => 'currency', '11' => 'ctx_mode', '12' => 'language', '13' => 'order_id', '14' => 'order_info', '15' => 'cust_email', '16' => 'cust_id', '17' => 'cust_title', '18' => 'cust_name', '19' => 'cust_address', '20' => 'cust_zip', '21' => 'cust_city', '22' => 'cust_country', '23' => 'cust_phone', '24' => 'url_success', '25' => 'url_refused', '26' => 'url_referral', '27' => 'url_cancel', '28' => 'url_return', '29' => 'url_error', '30' => 'identifier', '31' => 'contrib', '32' => 'theme_config', '34' => 'redirect_success_timeout', '35' => 'redirect_success_message', '36' => 'redirect_error_timeout', '37' => 'redirect_error_message', '38' => 'return_post_params', '39' => 'return_get_params', '40' => 'card_number', '41' => 'expiry_month', '42' => 'expiry_year', '43' => 'card_cvv', '44' => 'card_info', '45' => 'card_options', '46' => 'page_action', '47' => 'action_mode', '48' => 'return_mode', '50' => 'secure_mpi', '51' => 'secure_enrolled', '52' => 'secure_cavv', '53' => 'secure_eci', '54' => 'secure_xid', '55' => 'secure_cavv_alg', '56' => 'secure_status', '60' => 'payment_src', '61' => 'user_info', '62' => 'contracts', '70' => 'empty_params', '99' => 'other'), 'auth_results' => array( '00' => 'transaction approuvée ou traitée avec succès', '02' => 'contacter l’émetteur de carte', '03' => 'accepteur invalide', '04' => 'conserver la carte', '05' => 'ne pas honorer', '07' => 'conserver la carte, conditions spéciales', '08' => 'approuver après identification', '12' => 'transaction invalide', '13' => 'montant invalide', '14' => 'numéro de porteur invalide', '30' => 'erreur de format', '31' => 'identifiant de l’organisme acquéreur inconnu', '33' => 'date de validité de la carte dépassée', '34' => 'suspicion de fraude', '41' => 'carte perdue', '43' => 'carte volée', '51' => 'provision insuffisante ou crédit dépassé', '54' => 'date de validité de la carte dépassée', '56' => 'carte absente du fichier', '57' => 'transaction non permise à ce porteur', '58' => 'transaction interdite au terminal', '59' => 'suspicion de fraude', '60' => 'l’accepteur de carte doit contacter l’acquéreur', '61' => 'montant de retrait hors limite', '63' => 'règles de sécurité non respectées', '68' => 'réponse non parvenue ou reçue trop tard', '90' => 'arrêt momentané du système', '91' => 'émetteur de cartes inaccessible', '96' => 'mauvais fonctionnement du système', '94' => 'transaction dupliquée', '97' => 'échéance de la temporisation de surveillance globale', '98' => 'serveur indisponible routage réseau demandé à nouveau', '99' => 'incident domaine initiateur'), 'warranty_results' => array( 'YES' => 'Le paiement est garanti', 'NO' => 'Le paiement n\'est pas garanti', 'UNKNOWN' => 'Suite à une erreur technique, le paiment ne peut pas être garanti')); //TODO not tested. not used. // /** // * Replace current translation entries with provided ones // * @param array $translation // */ // function loadTranslation($translation) { // return $this->translation = $this->_recurseLoadTranslation($this->translation, $translation); // } // // /** // * Recursively load a $loaded translation array into the $original translation array // * @param array $original // * @param array $loaded // */ // function _recurseLoadTranslation($original, $loaded) { // foreach ($original as $key => $value) { // if (is_array($value)) { // $original[$key] = $this->_recurseLoadTranslation($original[$key], $array[$key]); // } // else if(array_key_exists($value, $loaded)) { // $original[$key] = $loaded[$value]; // } // } // return $original; // } /** * Load response codes and translations from a parameter array. * @param array[string]string $raw * @param boolean $authentified */ function load($raw, $certificate) { $this->raw_response = is_array($raw) ? $raw : array(); $this->certificate = $certificate; // Get codes $code = $this->_findInArray('vads_result', $raw, null); $extraCode = $this->_findInArray('vads_extra_result', $raw, null); $authCode = $this->_findInArray('vads_auth_result', $raw, null); $warrantyCode = $this->_findInArray('vads_warranty_code', $raw, null); // Common translations $noCode = $this->translation['no_code']; $noTrans = $this->translation['no_translation']; // Result and extra result if ($code == null) { $message = $noCode; $extraMessage = ($extraCode == null) ? $noCode : $noTrans; } else { $message = $this->_findInArray($code, $this->translation['results'], $noTrans); if ($extraCode == null) { $extraMessage = $noCode; } elseif ($code == 30) { $extraMessage = $this->_findInArray($extraCode, $this->translation['extra_results_30'], $noTrans); } else { $extraMessage = $this->_findInArray($extraCode, $this->translation['extra_results_default'], $noTrans); } } // auth_result if ($authCode == null) { $authMessage = $noCode; } else { $authMessage = $this->_findInArray($authCode, $this->translation['auth_results'], $noTrans); } // warranty_result if ($warrantyCode == null) { $warrantyMessage = $noCode; } else { $warrantyMessage = $this->_findInArray($warrantyCode, $this->translations['warranty_results'], $noTrans); } $this->code = $code; $this->message = $message; $this->authCode = $authCode; $this->authMessage = $authMessage; $this->extraCode = $extraCode; $this->extraMessage = $extraMessage; $this->warrantyCode = $warrantyCode; $this->warrantyMessage = $warrantyMessage; } /** * Check response signature * @return boolean */ function isAuthentified() { return VadsApi::sign($this->raw_response, $this->certificate) == $this->get('signature'); } /** * Return the signature computed from the received parameters, for log/debug purposes. * @param boolean $hashed apply sha1, false by default * @return string */ function getComputedSignature($hashed = false) { return VadsApi::sign($this->raw_response, $this->certificate, $hashed); } /** * Check if the payment was successful (waiting confirmation or captured) * @return boolean */ function isAcceptedPayment() { return $this->code == '00'; } /** * Check if the payment is waiting confirmation (successful but the amount has not been transfered and is not yet guaranteed) * @return boolean */ function isPendingPayment() { return $this->get('auth_mode') == 'MARK'; } /** * Check if the payment process was interrupted by the client * @return boolean */ function isCancelledPayment() { return $this->code == '17'; } /** * Return the value of a response parameter. * @param string $name * @return string */ function get($name) { // Manage shortcut notations by adding 'vads_' if (!array_key_exists($name, $this->raw_response)) { $name = 'vads_' . $name; } return @$this->raw_response[$name]; } /** * Return the paid amount converted from cents (or currency equivalent) to a decimal value * @return float */ function getFloatAmount() { $currency = VadsApi::findCurrencyByNumCode($this->get('currency')); return $currency->convertAmountToFloat($this->get('amount')); } /** * Return a short description of the payment result, useful for logging * @return string */ function getLogString() { $log = $this->code . ' : ' . $this->message; if ($this->code == '30') { $log .= ' (' . $this->extraCode . ' : ' . $this->extraMessage . ')'; } return $log; } /** * Return a formatted string to output as a response to the check url call * @param string $case shortcut code for current situations. Most useful : payment_ok, payment_ko, auth_fail * @param string $extraMessage some extra information to output to the payment gateway * @return string */ function getOutputForGateway($case = '', $extraMessage = "") { $success = false; $message = ''; // Messages prédéfinis selon le cas $cases = array( 'payment_ok' => array(true, 'Paiement valide traité'), 'payment_ko' => array(true, 'Paiement invalide traité'), 'payment_ok_already_done' => array( true, 'Paiement valide traité, déjà enregistré'), 'order_not_found' => array(false, 'Impossible de retrouver la commande'), 'payment_ko_on_order_ok' => array( false, 'Code paiement invalide reçu pour une commande déjà validée'), 'auth_fail' => array(false, 'Echec authentification'), 'ok' => array(true, ''), 'ko' => array(false, '')); if (array_key_exists($case, $cases)) { $success = $cases[$case][0]; $message = $cases[$case][1]; } $message .= ' ' . $extraMessage; $message = str_replace("\n", '', $message); $response = ''; $response .= ''; $response .= $success ? "OK-" : "KO-"; $response .= $this->get('hash'); $response .= ($message === ' ') ? "\n" : "=$message\n"; $response .= ''; return $response; } /** * Private shortcut function * @param string $value * @param array[string]string $translations * @param string $defaultTransation * @access private */ function _findInArray($key, $array, $default) { if (is_array($array) && array_key_exists($key, $array)) { return $array[$key]; } return $default; } } /** * Class representing a field of the form to send to the payment gateway * @package VadsApi */ class VadsField { /** * Field's name. Matches the html input attribute * @var string * @access private */ var $name; /** * Field's label in english, to be used by translation systems * @var string * @access private */ var $label; /** * Field's maximum length. Matches the html text input attribute * @var int * @access private */ var $length; /** * PCRE regular expression the field value must match * @var string * @access private */ var $regex; /** * Whether the form requires the field to be set (even to an empty string) * @var boolean * @access private */ var $required; /** * Field's value. Null or string * @var string * @access private */ var $value = null; /** * Constructor * @param string $name * @param string $label * @param string $regex * @param boolean $required * @param string $value * @return VadsField */ function VadsField($name, $label, $regex, $required = false, $length = 255) { $this->name = $name; $this->label = $label; $this->regex = $regex; $this->required = $required; $this->length = $length; } /** * Setter for value * @param mixed $value * @return boolean true if the value is valid */ function setValue($value) { $value = ($value === null) ? null : (string) $value; // We save value even if invalid (in case the validate function is too restrictive, it happened once) ... $this->value = $value; if (!$this->validate($value)) { // ... but we return a "false" warning return false; } return true; } /** * Checks the current value * @return boolean false if the current value is invalid or null and required */ function isValid() { return $this->validate($this->value); } /** * Check if a value is valid for this field * @param string $value * @return boolean */ function validate($value) { if ($value === null && $this->isRequired()) { return false; } if ($value !== null && !preg_match($this->regex, $value)) { return false; } return true; } /** * Setter for the required attribute * @param boolean $required */ function setRequired($required) { $this->required = (boolean) $required; } /** * Is the field required in the payment request ? * @return boolean */ function isRequired() { return $this->required; } /** * Return the current value of the field. * @return string */ function getValue() { return $this->value; } /** * Return the name (html attribute) of the field. * @return string */ function getName() { return $this->name; } /** * Return the english human-readable name of the field. * @return string */ function getLabel() { return $this->label; } /** * Return the maximum length of the field's value. * @return number */ function getLength() { return $this->length; } /** * Has a value been set ? * @return boolean */ function isFilled() { return !is_null($this->getValue()); } } /** * Class representing a currency, used for converting alpha/numeric iso codes and float/integer amounts * @package VadsApi * */ class VadsCurrency { var $alpha3; var $num; var $decimals; function VadsCurrency($alpha3, $num, $decimals = 2) { $this->alpha3 = $alpha3; $this->num = $num; $this->decimals = $decimals; } function convertAmountToInteger($float) { $coef = pow(10, $this->decimals); return round(intval($float) * $coef); } function convertAmountToFloat($integer) { $coef = pow(10, $this->decimals); return floatval($integer) / $coef; } } // No closing tagpayzen/.htaccess000066600000000177151374055400007665 0ustar00 Order allow,deny Deny from all payzen/index.html000066600000000000151374055400010045 0ustar00index.html000066600000000000151374055400006537 0ustar00payzen.php000066600000077353151374055400006612 0ustar00_loggable = TRUE; $this->tableFields = array_keys ($this->getTableSQLFields ()); $this->_tablepkey = 'id'; //virtuemart_payzen_id'; $this->_tableId = 'id'; //'virtuemart_payzen_id'; $varsToPush = $this->getVarsToPush (); $this->setConfigParameterable ($this->_configTableFieldName, $varsToPush); //self::$_this = $this; } protected function getVmPluginCreateTableSQL () { return $this->createTableSQL ('Payment ' . $this->_name . ' Table'); } function getTableSQLFields () { $SQLfields = array( 'id' => 'int(11) UNSIGNED NOT NULL AUTO_INCREMENT', 'virtuemart_order_id' => 'int(1) UNSIGNED', 'order_number' => 'char(64)', 'virtuemart_paymentmethod_id' => 'mediumint(1) UNSIGNED', 'payment_name' => 'varchar(5000)', 'payment_order_total' => 'decimal(15,5) NOT NULL DEFAULT \'0.00000\'', 'payment_currency' => 'char(3)', 'cost_per_transaction' => 'decimal(10,2)', 'cost_percent_total' => 'decimal(10,2)', 'tax_id' => 'smallint(1)', 'payzen_custom' => 'varchar(255)', 'payzen_response_payment_amount' => 'char(15)', 'payzen_response_auth_number' => 'char(10)', 'payzen_response_payment_currency' => 'char(3)', 'payzen_response_payment_mean' => 'char(255)', 'payzen_response_payment_date' => 'char(20)', 'payzen_response_payment_status' => 'char(3)', 'payzen_response_payment_message' => 'char(255)', 'payzen_response_card_number' => 'char(50)', 'payzen_response_trans_id' => 'char(6)', 'payzen_response_expiry_month' => 'char(2)', 'payzen_response_expiry_year' => 'char(4)', ); return $SQLfields; } function getCosts (VirtueMartCart $cart, $method, $cart_prices) { if (preg_match ('/%$/', $method->cost_percent_total)) { $cost_percent_total = substr ($method->cost_percent_total, 0, -1); } else { $cost_percent_total = $method->cost_percent_total; } return ($method->cost_per_transaction + ($cart_prices['salesPrice'] * $cost_percent_total * 0.01)); } /** * Reimplementation of vmPaymentPlugin::checkPaymentConditions() * * @param array $cart_prices all cart prices * @param object $payment payment parameters object * @return bool true if conditions verified */ function checkConditions ($cart, $method, $cart_prices) { $this->convert ($method); $amount = $cart_prices['salesPrice']; $amount_cond = ($amount >= $method->min_amount && $amount <= $method->max_amount || ($amount >= $method->min_amount && empty($method->max_amount))); return $amount_cond; } function convert ($method) { $method->min_amount = (float)$method->min_amount; $method->max_amount = (float)$method->max_amount; } /** * Prepare data and redirect to PayZen payment platform * * @param string $order_number * @param object $orderData * @param string $return_context the session id * @param string $html the form to display * @param bool $new_status false if it should not be changed, otherwise new staus * @return NULL */ function plgVmConfirmedOrder ($cart, $order) { if (!($method = $this->getVmPluginMethod ($order['details']['BT']->virtuemart_paymentmethod_id))) { return NULL; // Another method was selected, do nothing } if (!$this->selectedThisElement ($method->payment_element)) { return FALSE; } $this->_debug = $method->debug; // enable debug $session = JFactory::getSession (); $return_context = $session->getId (); $this->logInfo ('plgVmConfirmedOrder -- order number: ' . $order['details']['BT']->order_number, 'message'); if (!class_exists ('VadsApi')) { require(JPATH_VMPAYMENTPLUGIN . DS . 'payzen' . DS . 'payzen_api.php'); } $api = new VadsApi('UTF-8'); // set config parameters $paramNames = array( 'platform_url', 'key_test', 'key_prod', 'capture_delay', 'ctx_mode', 'site_id', 'validation_mode', 'redirect_enabled', 'redirect_success_timeout', 'redirect_success_message', 'redirect_error_timeout', 'redirect_error_message', 'return_mode' ); foreach ($paramNames as $name) { $api->set ($name, $method->$name); } // Set urls $url_return = JROUTE::_ (JURI::root () . 'index.php?option=com_virtuemart&view=pluginresponse&task=pluginresponsereceived'); $uri = JURI::getInstance ($url_return); //$uri->setVar('pelement', $this->payment_element); $uri->setVar ('pm', $order['details']['BT']->virtuemart_paymentmethod_id); $uri->setVar ('Itemid', JRequest::getInt ('Itemid')); $api->set ('url_return', $uri->toString ()); $url_success = JROUTE::_ (JURI::root () . 'index.php?option=com_virtuemart&view=pluginresponse&task=pluginresponsereceived'); $uri = JURI::getInstance ($url_success); //$uri->setVar('pelement', $this->payment_element); $uri->setVar ('Itemid', JRequest::getInt ('Itemid')); $uri->setVar ('pm', $order['details']['BT']->virtuemart_paymentmethod_id); $api->set ('url_success', $uri->toString ()); $url_cancel = JROUTE::_ (JURI::root () . 'index.php?option=com_virtuemart&view=pluginresponse&task=pluginUserPaymentCancel'); $uri = JURI::getInstance ($url_cancel); $uri->setVar ('on', $order['details']['BT']->order_number); $uri->setVar ('pm', $order['details']['BT']->virtuemart_paymentmethod_id); $uri->setVar ('Itemid', JRequest::getInt ('Itemid')); $api->set ('url_cancel', $uri->toString ()); // Set the language code $lang = JFactory::getLanguage (); $lang->load ('plg_vmpayment_' . $this->_name, JPATH_ADMINISTRATOR); $tag = substr ($lang->get ('tag'), 0, 2); $language = in_array ($tag, $api->getSupportedLanguages ()) ? $tag : ($method->language ? $method->language : 'fr'); $api->set ('language', $language); // Set currency if (!class_exists ('VirtueMartModelCurrency')) { require(JPATH_VM_ADMINISTRATOR . DS . 'models' . DS . 'currency.php'); } $currencyModel = new VirtueMartModelCurrency(); $currencyObj = $currencyModel->getCurrency ($order['details']['BT']->order_currency); $currency = $api->findCurrencyByNumCode ($currencyObj->currency_numeric_code); if ($currency == NULL) { $this->logInfo ('plgVmConfirmedOrder -- Could not find currency numeric code for currency : ' . $currencyObj->currency_numeric_code, 'error'); vmInfo (JText::_ ('VMPAYMENT_' . $this->_name . '_CURRENCY_NOT_SUPPORTED')); return NULL; } $api->set ('currency', $currency->num); // payment_cards may be one value or array $cards = $method->payment_cards; $cards = !is_array ($cards) ? $cards : (in_array ("", $cards) ? "" : implode (";", $cards)); $api->set ('payment_cards', $cards); // available_languages may be one value or array $available_languages = $method->available_languages; $available_languages = !is_array ($available_languages) ? $available_languages : (in_array ("", $available_languages) ? "" : implode (";", $available_languages)); $api->set ('available_languages', $available_languages); $api->set ('contrib', 'VirtueMart2.0.12f'); // Set customer info // $usr = JFactory::getUser(); $usrBT = $order['details']['BT']; $usrST = ((isset($order['details']['ST'])) ? $order['details']['ST'] : $order['details']['BT']); $api->set ('cust_email', $usrBT->email); // $api->set('cust_id', ''); $api->set ('cust_title', @$usrBT->title); $api->set ('cust_first_name', $usrBT->first_name); $api->set ('cust_last_name', $usrBT->last_name); $api->set ('cust_address', $usrBT->address_1 . ' ' . $usrBT->address_2); $api->set ('cust_zip', $usrBT->zip); $api->set ('cust_city', $usrBT->city); $api->set ('cust_state', @ShopFunctions::getStateByID ($usrBT->virtuemart_state_id)); $api->set ('cust_country', @ShopFunctions::getCountryByID ($usrBT->virtuemart_country_id, 'country_2_code')); $api->set ('cust_phone', $usrBT->phone_1); $api->set ('cust_cell_phone', $usrBT->phone_2); $api->set ('ship_to_first_name', $usrST->first_name); $api->set ('ship_to_last_name', $usrST->last_name); $api->set ('ship_to_city', $usrST->city); $api->set ('ship_to_street', $usrST->address_1); $api->set ('ship_to_street2', $usrST->address_2); $api->set ('ship_to_state', @ShopFunctions::getStateByID ($usrST->virtuemart_state_id)); $api->set ('ship_to_country', @ShopFunctions::getCountryByID ($usrST->virtuemart_country_id, 'country_2_code')); $api->set ('ship_to_phone_num', $usrST->phone_1); $api->set ('ship_to_zip', $usrST->zip); // Set order_id $api->set ('order_id', $order['details']['BT']->order_number); // Set the amount to pay $api->set ('amount', round ($order['details']['BT']->order_total * 100)); // Prepare data that should be stored in the database $dbValues['order_number'] = $order['details']['BT']->order_number; $dbValues['payment_name'] = $this->renderPluginName ($method, $order); $dbValues['virtuemart_paymentmethod_id'] = $cart->virtuemart_paymentmethod_id; $dbValues[$this->_name . '_custom'] = $return_context; $this->storePSPluginInternalData ($dbValues); $this->logInfo ('plgVmConfirmedOrder -- payment data saved to table ' . $this->_tablename, 'message'); // echo the redirect form $form = 'Redirection
'; $form .= '

' . JText::_ ('VMPAYMENT_' . $this->_name . '_PLEASE_WAIT') . '

'; $form .= '

' . JText::_ ('VMPAYMENT_' . $this->_name . '_CLICK_BUTTON_IF_NOT_REDIRECTED') . '

'; $form .= '
'; $form .= ''; $form .= $api->getRequestFieldsHtml (); $form .= '
'; $form .= ''; $this->logInfo ('plgVmConfirmedOrder -- user redirected to ' . $this->_name, 'message'); echo $form; $cart->_confirmDone = FALSE; $cart->_dataValidated = FALSE; $cart->setCartIntoSession (); die(); // not save order, not send mail, do redirect } /** * Check PayZen response, save order if not done by server call and redirect to response page * when client comes back from payment platform. * * @param int $virtuemart_order_id virtuemart order primary key concerned by payment * @param string $html message to show as result * @return */ function plgVmOnPaymentResponseReceived (&$html) { if (!class_exists ('VirtueMartCart')) { require(JPATH_VM_SITE . DS . 'helpers' . DS . 'cart.php'); } // the payment itself should send the parameter needed. $virtuemart_paymentmethod_id = JRequest::getInt ('pm', 0); //vmDebug($this->_name.' plgVmOnPaymentResponseReceived',$virtuemart_paymentmethod_id); $vendorId = 0; if (!($method = $this->getVmPluginMethod ($virtuemart_paymentmethod_id))) { return NULL; // Another method was selected, do nothing } //vmDebug($this->_name.' plgVmOnPaymentResponseReceived',$method); if (!$this->selectedThisElement ($method->payment_element)) { return FALSE; } //$this->_debug = true; // enable debug $this->logInfo ('plgVmOnPaymentResponseReceived -- user returned back from ' . $this->_name, 'message'); $data = JRequest::get ('request'); // Load API if (!class_exists ('VadsApi')) { require(JPATH_VMPAYMENTPLUGIN . DS . 'payzen' . DS . 'payzen_api.php'); } $api = new VadsApi(); $resp = $api->getResponse ( $data, $method->ctx_mode, $method->key_test, $method->key_prod ); if (!$resp->isAuthentified ()) { $this->logInfo ('plgVmOnPaymentResponseReceived -- suspect request sent to plgVmOnPaymentResponseReceived, IP : ' . $_SERVER['REMOTE_ADDR'], 'error'); $html = $this->_getHtmlPaymentResponse ('VMPAYMENT_' . $this->_name . '_ERROR_MSG', FALSE); return NULL; } // Retrieve order info from database if (!class_exists ('VirtueMartModelOrders')) { require(JPATH_VM_ADMINISTRATOR . DS . 'models' . DS . 'orders.php'); } // $resp->get ('order_id') is the virtuemart order_number $virtuemart_order_id = VirtueMartModelOrders::getOrderIdByOrderNumber ($resp->get ('order_id')); // Order not found if (!$virtuemart_order_id) { // vmdebug('plgVmOnPaymentResponseReceived ' . $this->_name, $data, $resp->get('order_id')); $this->logInfo ('plgVmOnPaymentResponseReceived -- payment check attempted on non existing order : ' . $resp->get ('order_id'), 'error'); $html = $this->_getHtmlPaymentResponse ('VMPAYMENT_' . $this->_name . '_ERROR_MSG', FALSE); // JRequest::setVar('paymentResponseHtml', $html, 'post'); return NULL; } $order = VirtueMartModelOrders::getOrder ($virtuemart_order_id); $order_status_code = $order['items'][0]->order_status; if ($resp->isAcceptedPayment ()) { $currency = $api->findCurrencyByNumCode ($resp->get ('currency'))->alpha3; $amount = ($resp->get ('amount') / 100) . ' ' . $currency; $html = $this->_getHtmlPaymentResponse ('VMPAYMENT_' . $this->_name . '_SUCCESS_MSG', TRUE, $resp->get ('order_id'), $amount); //JRequest::setVar('paymentResponseHtml', $html, 'post'); $new_status = $method->order_success_status; } else { $html = $this->_getHtmlPaymentResponse ('VMPAYMENT_' . $this->_name . '_FAILURE_MSG', FALSE); // JRequest::setVar('paymentResponseHtml', $html, 'post'); $new_status = $method->order_failure_status; } // Order not processed yet if ($order_status_code == 'P') { $this->logInfo ('plgVmOnPaymentResponseReceived -- check url does not work.', 'warning'); if ($method->site_id == '56790135') { // Mode TEST DEFAULT VALUE: The plugin use default value. vmWarn (JText::_ ('VMPAYMENT_' . $this->_name . '_CHECK_URL_WARN_VIRTUEMART'), ''); } elseif ($method->ctx_mode == 'TEST') { //Mode TEST warning : Check URL not correctly called. vmWarn (JText::_ ('VMPAYMENT_' . $this->_name . '_CHECK_URL_WARN'), ''); } $this->managePaymentResponse ($virtuemart_order_id, $resp, $new_status); } //We delete the old stuff // get the correct cart / session $cart = VirtueMartCart::getCart (); $cart->emptyCart (); return NULL; } /** * Process a PayZen payment cancellation. * * @param int $virtuemart_order_id virtuemart order primary key concerned by payment * @return */ function plgVmOnUserPaymentCancel () { if (!class_exists ('VirtueMartModelOrders')) { require(JPATH_VM_ADMINISTRATOR . DS . 'models' . DS . 'orders.php'); } $order_number = JRequest::getString ('on'); if (!$order_number) { return FALSE; } if (!$virtuemart_order_id = VirtueMartModelOrders::getOrderIdByOrderNumber ($order_number)) { return NULL; } if (!($paymentTable = $this->getDataByOrderId ($virtuemart_order_id))) { return NULL; } $session = JFactory::getSession (); $return_context = $session->getId (); $field = $this->_name . '_custom'; if (strcmp ($paymentTable->$field, $return_context) === 0) { $this->handlePaymentUserCancel ($virtuemart_order_id); } //JRequest::setVar('paymentResponse', $returnValue); return TRUE; } /** * Check PayZen response, save order and empty cart (if payment success) when server notification is received from payment platform. * * @param string $return_context session id * @param int $virtuemart_order_id virtuemart order primary key concerned by payment * @param string $new_status new order status * @return */ function plgVmOnPaymentNotification () { // platform params and payment data $data = JRequest::get ('post'); $this->logInfo ('plgVmOnPaymentNotification START ', 'error'); if (!array_key_exists ('vads_order_id', $data) || !isset($data['vads_order_id'])) { $this->logInfo ('plgVmOnPaymentNotification -- Another method was selected, do nothing : ', 'error'); return NULL; // Another method was selected, do nothing } // Retrieve order info from database if (!class_exists ('VirtueMartModelOrders')) { require(JPATH_VM_ADMINISTRATOR . DS . 'models' . DS . 'orders.php'); } $virtuemart_order_id = VirtueMartModelOrders::getOrderIdByOrderNumber ($data['vads_order_id']); // Order not found /* if (!$virtuemart_order_id) { $this->logInfo('plgVmOnPaymentNotification -- payment check attempted on non existing order : ' . $resp->get('order_id'), 'error'); $response .= 'OK-'; $response .= $data['vads_hash']; $response .= "=Impossible de retrouver la commande\n"; $response .= ''; die($response); } */ // Payment params $payment_data = $this->getDataByOrderId ($virtuemart_order_id); /* if (!$payment_data || !($payment = $this->getPaymentMethod($payment_data->payment_method_id))) { $this->logInfo('plgVmOnPaymentNotification -- payment data not found: exit ', 'ERROR'); $response .= 'OK-'; $response .= $data['vads_hash']; $response .= "=Méthode de paiement introuvable\n"; $response .= ''; die($response); } */ $method = $this->getVmPluginMethod ($payment_data->virtuemart_paymentmethod_id); if (!$this->selectedThisElement ($method->payment_element)) { return FALSE; } $this->_debug = $method->debug; $custom = $this->_name . '_custom'; $return_context = $payment_data->$custom; // Load API if (!class_exists ('VadsApi')) { require(JPATH_VMPAYMENTPLUGIN . DS . 'payzen' . DS . 'payzen_api.php'); } $api = new VadsApi(); $resp = $api->getResponse ( $data, $method->ctx_mode, $method->key_test, $method->key_prod ); if (!$resp->isAuthentified ()) { $this->logInfo ('plgVmOnPaymentNotification -- suspect request sent to plgVmOnPaymentNotification, IP : ' . $_SERVER['REMOTE_ADDR'], 'error'); die($resp->getOutputForGateway ('auth_fail')); } $order = VirtueMartModelOrders::getOrder ($virtuemart_order_id); $order_status_code = $order['items'][0]->order_status; // Order not processed yet if ($order_status_code == 'P') { if ($resp->isAcceptedPayment ()) { $currency = $api->findCurrencyByNumCode ($resp->get ('currency'))->alpha3; $amount = ($resp->get ('amount') / 100) . ' ' . $currency; $new_status = $method->order_success_status; $this->logInfo ('plgVmOnPaymentNotification -- payment process OK, ' . $amount . ' paid for order ' . $resp->get ('order_id') . ', new status ' . $new_status, 'message'); echo ($resp->getOutputForGateway ('payment_ok')); } else { $new_status = $method->order_failure_status; $this->logInfo ('plgVmOnPaymentNotification -- payment process error ' . $resp->message . ', new status ' . $new_status, 'ERROR'); echo ($resp->getOutputForGateway ('payment_ko')); } // Save platform response $this->managePaymentResponse ($virtuemart_order_id, $resp, $new_status, $return_context, $data['vads_order_id']); } else { // Order already processed if ($resp->isAcceptedPayment ()) { echo ($resp->getOutputForGateway ('payment_ok_already_done')); } else { echo ($resp->getOutputForGateway ('payment_ko_on_order_ok')); } } die(); } /** * Display stored payment data for an order * * @see components/com_virtuemart/helpers/vmPaymentPlugin::plgVmOnShowOrderPaymentBE() */ function plgVmOnShowOrderBEPayment ($virtuemart_order_id, $payment_method_id) { if (!$this->selectedThisByMethodId ($payment_method_id)) { return NULL; // Another method was selected, do nothing } if (!($paymentTable = $this->getDataByOrderId ($virtuemart_order_id))) { return NULL; } $html = '' . "\n"; $html .= $this->getHtmlHeaderBE (); $html .= $this->getHtmlRowBE (strtoupper ($this->_name) . '_PAYMENT_NAME', $paymentTable->payment_name); $payment_status = $this->_name . '_response_payment_status'; $payment_response_trans_id = $this->_name . '_response_trans_id'; $payment_response_card_number = $this->_name . '_response_card_number'; $payment_response_payment_mean = $this->_name . '_response_payment_mean'; $payment_response_payment_message = $this->_name . '_response_payment_message'; $payment_response_expiry_month = $this->_name . '_response_expiry_month'; $payment_response_expiry_year = $this->_name . '_response_expiry_year'; $result = $paymentTable->$payment_response_payment_message . '(' . $paymentTable->$payment_status . ')'; $expiry = str_pad ($paymentTable->$payment_response_expiry_month, 2, '0', STR_PAD_LEFT) . ' / ' . $paymentTable->$payment_response_expiry_year; $html .= $this->getHtmlRowBE ($this->_name . '_RESULT', $result); $html .= $this->getHtmlRowBE ($this->_name . '_TRANS_ID', $paymentTable->$payment_response_trans_id); $html .= $this->getHtmlRowBE ($this->_name . '_CC_NUMBER', $paymentTable->$payment_response_card_number); $html .= $this->getHtmlRowBE ($this->_name . '_CC_EXPIRY', $expiry); $html .= $this->getHtmlRowBE ($this->_name . '_CC_TYPE', $paymentTable->$payment_response_payment_mean); $html .= '
' . "\n"; return $html; } function _getHtmlPaymentResponse ($msg, $is_success = TRUE, $order_id = NULL, $amount = NULL) { if (!$is_success) { return '

' . JText::_ ($msg) . '

'; } else { $html = '' . "\n"; $html .= ''; $html .= $this->getHtmlRow ($this->_name . '_ORDER_NUMBER', $order_id, 'style="width: 90px;" class="key"'); $html .= $this->getHtmlRow ($this->_name . '_AMOUNT', $amount, 'style="width: 90px;" class="key"'); $html .= '
' . JText::_ ($msg) . '
' . "\n"; return $html; } } function savePaymentData ($virtuemart_order_id, $resp) { //vmdebug($this->_name . ' response', $resp->raw_response); $response[$this->_tablepkey] = $this->_getTablepkeyValue ($virtuemart_order_id); $response['virtuemart_order_id'] = $virtuemart_order_id; $response[$this->_name . '_response_payment_amount'] = $resp->get ('amount'); $response[$this->_name . '_response_payment_currency'] = $resp->get ('currency'); $response[$this->_name . '_response_auth_number'] = $resp->get ('auth_number'); $response[$this->_name . '_response_payment_mean'] = $resp->get ('card_brand'); $response[$this->_name . '_response_payment_date'] = gmdate ('Y-m-d H:i:s', time ()); $response[$this->_name . '_response_payment_status'] = $resp->code; $response[$this->_name . '_response_payment_message'] = $resp->message; $response[$this->_name . '_response_card_number'] = $resp->get ('card_number'); $response[$this->_name . '_response_trans_id'] = $resp->get ('trans_id'); $response[$this->_name . '_response_expiry_month'] = $resp->get ('expiry_month'); $response[$this->_name . '_response_expiry_year'] = $resp->get ('expiry_year'); $this->storePSPluginInternalData ($response, $this->_tablepkey, TRUE); } function _getTablepkeyValue ($virtuemart_order_id) { $db = JFactory::getDBO (); $q = 'SELECT ' . $this->_tablepkey . ' FROM `' . $this->_tablename . '` ' . 'WHERE `virtuemart_order_id` = ' . $virtuemart_order_id; $db->setQuery ($q); if (!($pkey = $db->loadResult ())) { JError::raiseWarning (500, $db->getErrorMsg ()); return ''; } return $pkey; } function emptyCart ($session_id = NULL, $order_number = NULL) { if ($session_id != NULL) { $session = JFactory::getSession (); $session->close (); // Recover session in wich the payment is done session_id ($session_id); session_start (); } $cart = VirtueMartCart::getCart (); //vmDebug('emptyCart', $cart); $cart->emptyCart (); return TRUE; } function managePaymentResponse ($virtuemart_order_id, $resp, $new_status, $return_context = NULL, $order_number=NULL) { // Save platform response data $this->savePaymentData ($virtuemart_order_id, $resp); if (!class_exists ('VirtueMartModelOrders')) { require(JPATH_VM_ADMINISTRATOR . DS . 'models' . DS . 'orders.php'); } // save order data $modelOrder = new VirtueMartModelOrders(); $order['order_status'] = $new_status; $order['virtuemart_order_id'] = $virtuemart_order_id; $order['customer_notified'] = 1; $date = JFactory::getDate (); $order['comments'] = JText::sprintf ('VMPAYMENT_' . $this->_name . '_NOTIFICATION_RECEVEIVED', $date->toFormat ('%Y-%m-%d %H:%M:%S')); //vmdebug($this->_name . ' - managePaymentResponse', $order); // la fonction updateStatusForOneOrder fait l'envoie de l'email à partir de VM2.0.2 $modelOrder->updateStatusForOneOrder ($virtuemart_order_id, $order, TRUE); if (!class_exists ('VirtueMartCart')) { require(JPATH_VM_SITE . DS . 'helpers' . DS . 'cart.php'); } if ($resp->isAcceptedPayment ()) { // Empty cart in session $this->emptyCart ($return_context, $order_number); } } /** * We must reimplement this triggers for joomla 1.7 */ /** * Create the table for this plugin if it does not yet exist. * This functions checks if the called plugin is active one. * When yes it is calling the standard method to create the tables * * @author Valérie Isaksen * */ function plgVmOnStoreInstallPaymentPluginTable ($jplugin_id) { return $this->onStoreInstallPluginTable ($jplugin_id); } /** * This event is fired after the payment method has been selected. It can be used to store * additional payment info in the cart. * * @author Max Milbers * @author Valérie isaksen * * @param VirtueMartCart $cart: the actual cart * @return null if the payment was not selected, true if the data is valid, error message if the data is not vlaid * */ public function plgVmOnSelectCheckPayment (VirtueMartCart $cart, &$msg) { return $this->OnSelectCheck ($cart); } /** * plgVmDisplayListFEPayment * This event is fired to display the pluginmethods in the cart (edit shipment/payment) for exampel * * @param object $cart Cart object * @param integer $selected ID of the method selected * @return boolean True on succes, false on failures, null when this plugin was not selected. * On errors, JError::raiseWarning (or JError::raiseError) must be used to set a message. * * @author Valerie Isaksen * @author Max Milbers */ public function plgVmDisplayListFEPayment (VirtueMartCart $cart, $selected = 0, &$htmlIn) { return $this->displayListFE ($cart, $selected, $htmlIn); } /* * plgVmonSelectedCalculatePricePayment * Calculate the price (value, tax_id) of the selected method * It is called by the calculator * This function does NOT to be reimplemented. If not reimplemented, then the default values from this function are taken. * @author Valerie Isaksen * @cart: VirtueMartCart the current cart * @cart_prices: array the new cart prices * @return null if the method was not selected, false if the shiiping rate is not valid any more, true otherwise * * */ public function plgVmonSelectedCalculatePricePayment (VirtueMartCart $cart, array &$cart_prices, &$cart_prices_name) { return $this->onSelectedCalculatePrice ($cart, $cart_prices, $cart_prices_name); } /** * plgVmOnCheckAutomaticSelectedPayment * Checks how many plugins are available. If only one, the user will not have the choice. Enter edit_xxx page * The plugin must check first if it is the correct type * * @author Valerie Isaksen * @param VirtueMartCart cart: the cart object * @return null if no plugin was found, 0 if more then one plugin was found, virtuemart_xxx_id if only one plugin is found * */ function plgVmOnCheckAutomaticSelectedPayment (VirtueMartCart $cart, array $cart_prices = array(), &$paymentCounter) { return $this->onCheckAutomaticSelected ($cart, $cart_prices, $paymentCounter); } /** * This method is fired when showing the order details in the frontend. * It displays the method-specific data. * * @param integer $order_id The order ID * @return mixed Null for methods that aren't active, text (HTML) otherwise * @author Max Milbers * @author Valerie Isaksen */ public function plgVmOnShowOrderFEPayment ($virtuemart_order_id, $virtuemart_paymentmethod_id, &$payment_name) { $this->onShowOrderFE ($virtuemart_order_id, $virtuemart_paymentmethod_id, $payment_name); } /** * This event is fired during the checkout process. It can be used to validate the * method data as entered by the user. * * @return boolean True when the data was valid, false otherwise. If the plugin is not activated, it should return null. * @author Max Milbers public function plgVmOnCheckoutCheckDataPayment($psType, VirtueMartCart $cart) { return null; } */ /** * This method is fired when showing when priting an Order * It displays the the payment method-specific data. * * @param integer $_virtuemart_order_id The order ID * @param integer $method_id method used for this order * @return mixed Null when for payment methods that were not selected, text (HTML) otherwise * @author Valerie Isaksen */ function plgVmonShowOrderPrintPayment ($order_number, $method_id) { return $this->onShowOrderPrint ($order_number, $method_id); } /** * Save updated order data to the method specific table * * @param array $_formData Form data * @return mixed, True on success, false on failures (the rest of the save-process will be * skipped!), or null when this method is not actived. public function plgVmOnUpdateOrderPayment( $_formData) { return null; } */ /** * Save updated orderline data to the method specific table * * @param array $_formData Form data * @return mixed, True on success, false on failures (the rest of the save-process will be * skipped!), or null when this method is not actived. public function plgVmOnUpdateOrderLine( $_formData) { return null; } */ /** * plgVmOnEditOrderLineBE * This method is fired when editing the order line details in the backend. * It can be used to add line specific package codes * * @param integer $_orderId The order ID * @param integer $_lineId * @return mixed Null for method that aren't active, text (HTML) otherwise public function plgVmOnEditOrderLineBE( $_orderId, $_lineId) { return null; } */ /** * This method is fired when showing the order details in the frontend, for every orderline. * It can be used to display line specific package codes, e.g. with a link to external tracking and * tracing systems * * @param integer $_orderId The order ID * @param integer $_lineId * @return mixed Null for method that aren't active, text (HTML) otherwise public function plgVmOnShowOrderLineFE( $_orderId, $_lineId) { return null; } */ function plgVmDeclarePluginParamsPayment ($name, $id, &$data) { return $this->declarePluginParams ('payment', $name, $id, $data); } function plgVmSetOnTablePluginParamsPayment ($name, $id, &$table) { return $this->setOnTablePluginParams ($name, $id, $table); } } // No closing tagpayzen.xml000066600000023142151374055400006606 0ustar00 VM - Payment, PayZen July 04 2012 Lyra Network support@payzen.eu http://www.lyra-network.com Copyright Lyra Network. http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL 2.0.8c PayZen is a multi bank payment provider. ]]> payzen.php payzen languageBE/en-GB.plg_vmpayment_payzen.ini languageBE/fr-FR.plg_vmpayment_payzen.ini PayZen.png /> .htaccess000066600000000177151374055400006357 0ustar00 Order allow,deny Deny from all elements/payzenlabel.php000066600000002144151374267730011423 0ustar00attributes('class') ? 'class="'.$node->attributes('class').'"' : 'class="text_area"' ); return ''; } }elements/payzenmultilist.php000066600000004552151374267730012377 0ustar00children() as $option) { $val = $option->attributes('value'); $text = $option->data(); $options[] = JHTML::_('select.option', $val, JText::_($text)); } // Construct the various argument calls that are supported. $attribs = ' '; if ($v = $node->attributes( 'size' )) { $attribs .= 'size="'.$v.'"'; } if ($v = $node->attributes( 'class' )) { $attribs .= 'class="'.$v.'"'; } else { $attribs .= 'class="inputbox"'; } if ($m = $node->attributes( 'multiple' )) { $attribs .= ' multiple="multiple"'; $ctrl .= '[]'; } // Render the HTML SELECT list. return JHTML::_('select.genericlist', $options, $ctrl, $attribs, 'value', 'text', $value, $control_name.$name ); } }elements/payzenurl.php000066600000003030151374267730011141 0ustar00attributes('class') ? 'class="'.$node->attributes('class').'"' : 'class="text_area"' ); if ($node->attributes( 'default' ) == $value) { $value = JURI::root(). $value; } if ($node->attributes( 'editable' ) == 'true') { $size = ( $node->attributes('size') ? 'size="'.$node->attributes('size').'"' : '' ); return ''; } else { return ''; } } }elements/.htaccess000066600000000177151374267730010206 0ustar00 Order allow,deny Deny from all elements/index.html000066600000000000151374267730010366 0ustar00payzen_api.php000066600000124646151374267730007454 0ustar00 * @copyright Lyra-network.com * PHP classes to integrate an e-commerce solution with the payment platform supported by lyra-network. */ /** * Class managing parameters checking, form and signature building, response analysis and more * @package VadsApi * @version 2.1 */ class VadsApi { // ************************************** // PROPERTIES // ************************************** /** * The fields to send to the vads platform * @var array[string]VadsField * @access private */ var $requestParameters; /** * Certificate to send in TEST mode * @var string * @access private */ var $keyTest; /** * Certificate to send in PRODUCTION mode * @var string * @access private */ var $keyProd; /** * Url of the payment page * @var string * @access private */ var $platformUrl; /** * Set to true to send the redirect_* parameters * @var boolean * @access private */ var $redirectEnabled; /** * SHA-1 authentication signature * @var string * @access private */ var $signature; /** * Raw response sent by the platform * @var VadsResponse * @access private */ var $response; /** * The original data encoding. * @var string * @access private */ var $encoding; /** * The list of categories for payment with bank accord. To be sent with the products detail if you use this payment mean. * @static * @var array * @access public */ var $ACCORD_CATEGORIES = array("FOOD_AND_GROCERY","AUTOMOTIVE","ENTERTAINMENT","HOME_AND_GARDEN","HOME_APPLIANCE","AUCTION_AND_GROUP_BUYING","FLOWERS_AND_GIFTS","COMPUTER_AND_SOFTWARE","HEALTH_AND_BEAUTY","SERVICE_FOR_INDIVIDUAL","SERVICE_FOR_BUSINESS","SPORTS","CLOTHING_AND_ACCESSORIES","TRAVEL","HOME_AUDIO_PHOTO_VIDEO","TELEPHONY"); // ************************************** // CONSTRUCTOR // ************************************** /** * Constructor. * Initialize request fields definitions. */ function VadsApi($encoding="UTF-8") { //TODO success n'est pas utilisé $success = true; // Initialize encoding $supported_encodings = array("UTF-8", "ASCII", "Windows-1252", "ISO-8859-15", "ISO-8859-1", "ISO-8859-6", "CP1256"); $this->encoding = in_array(strtoupper($encoding), $supported_encodings) ? strtoupper($encoding) : "UTF-8"; /* * Définition des paramètres de la requête */ // Common or long regexes $ans = "[^<>]"; // Any character (except the dreadful "<" and ">") $an63 = '#^[A-Za-z0-9]{0,63}$#'; $an255 = '#^[A-Za-z0-9]{0,255}$#'; $ans255 = '#^' . $ans . '{0,255}$#'; $ans127 = '#^' . $ans . '{0,127}$#'; $supzero = '[1-9]\d*'; $regex_payment_cfg = '#^(SINGLE|MULTI:first=\d+;count=' . $supzero . ';period=' . $supzero . ')$#'; $regex_trans_date = '#^\d{4}' . '(1[0-2]|0[1-9])' . '(3[01]|[1-2]\d|0[1-9])' . '(2[0-3]|[0-1]\d)' . '([0-5]\d){2}$#';//AAAAMMJJhhmmss $regex_mail = '#^[^@]+@[^@]+\.\w{2,4}$#'; //TODO plus restrictif $regex_params = '#^([^&=]+=[^&=]*)?(&[^&=]+=[^&=]*)*$#'; //name1=value1&name2=value2... // Déclaration des paramètres, de leur valeurs par défaut, de leur format... // $this->_addRequestField('raw_signature', 'DEBUG Signature', '#^.+$#', // false); $this->_addRequestField('signature', 'Signature', "#^[0-9a-f]{40}$#", true); $this->_addRequestField('vads_action_mode', 'Action mode', "#^INTERACTIVE|SILENT$#", true, 11); $this->_addRequestField('vads_amount', 'Amount', '#^' . $supzero . '$#', true); $this->_addRequestField('vads_available_languages', 'Available languages', "#^(|[A-Za-z]{2}(;[A-Za-z]{2})*)$#", false, 2); $this->_addRequestField('vads_capture_delay', 'Capture delay', "#^\d*$#"); $this->_addRequestField('vads_contracts', 'Contracts', $ans255); $this->_addRequestField('vads_contrib', 'Contribution', $ans255); $this->_addRequestField('vads_ctx_mode', 'Mode', "#^TEST|PRODUCTION$#", true); $this->_addRequestField('vads_currency', 'Currency', "#^\d{3}$#", true, 3); $this->_addRequestField('vads_cust_antecedents', 'Customer history', "#^NONE|NO_INCIDENT|INCIDENT$#"); $this->_addRequestField('vads_cust_address', 'Customer address', $ans255); $this->_addRequestField('vads_cust_country', 'Customer country', "#^[A-Za-z]{2}$#", false, 2); $this->_addRequestField('vads_cust_email', 'Customer email', $regex_mail, false, 127); $this->_addRequestField('vads_cust_id', 'Customer id', $an63, false, 63); $this->_addRequestField('vads_cust_name', 'Customer name', $ans127, false, 127); $this->_addRequestField('vads_cust_cell_phone', 'Customer cell phone', $an63, false, 63); $this->_addRequestField('vads_cust_phone', 'Customer phone', $an63, false, 63); $this->_addRequestField('vads_cust_title', 'Customer title', '#^'.$ans.'{0,63}$#', false, 63); $this->_addRequestField('vads_cust_city', 'Customer city', '#^' . $ans . '{0,63}$#', false, 63); $this->_addRequestField('vads_cust_state', 'Customer state/region', '#^'.$ans.'{0,63}$#', false, 63); $this->_addRequestField('vads_cust_zip', 'Customer zip code', $an63, false, 63); $this->_addRequestField('vads_language', 'Language', "#^[A-Za-z]{2}$#", false, 2); $this->_addRequestField('vads_order_id', 'Order id', "#^[A-za-z0-9]{0,12}$#", false, 12); $this->_addRequestField('vads_order_info', 'Order info', $ans255); $this->_addRequestField('vads_order_info2', 'Order info 2', $ans255); $this->_addRequestField('vads_order_info3', 'Order info 3', $ans255); $this->_addRequestField('vads_page_action', 'Page action', "#^PAYMENT$#", true, 7); $this->_addRequestField('vads_payment_cards', 'Payment cards', "#^[A-Za-z0-9;]{0,127}$#", false, 127); $this->_addRequestField('vads_payment_config', 'Payment config', $regex_payment_cfg, true); $this->_addRequestField('vads_payment_src', 'Payment source', "#^$#", false, 0); $this->_addRequestField('vads_redirect_error_message', 'Redirection error message', $ans255, false); $this->_addRequestField('vads_redirect_error_timeout', 'Redirection error timeout', $ans255, false); $this->_addRequestField('vads_redirect_success_message', 'Redirection success message', $ans255, false); $this->_addRequestField('vads_redirect_success_timeout', 'Redirection success timeout', $ans255, false); $this->_addRequestField('vads_return_mode', 'Return mode', "#^NONE|GET|POST?$#", false, 4); $this->_addRequestField('vads_return_get_params', 'GET return parameters', $regex_params, false); $this->_addRequestField('vads_return_post_params', 'POST return parameters', $regex_params, false); $this->_addRequestField('vads_ship_to_name', 'Shipping name', '#^' . $ans . '{0,127}$#', false, 127); $this->_addRequestField('vads_ship_to_phone_num', 'Shipping phone', $ans255, false, 63); $this->_addRequestField('vads_ship_to_street', 'Shipping street', $ans127, false, 127); $this->_addRequestField('vads_ship_to_street2', 'Shipping street (2)', $ans127, false, 127); $this->_addRequestField('vads_ship_to_state', 'Shipping state', $an63, false, 63); $this->_addRequestField('vads_ship_to_country', 'Shipping country', "#^[A-Za-z]{2}$#", false, 2); $this->_addRequestField('vads_ship_to_city', 'Shipping city', '#^' . $ans . '{0,63}$#', false, 63); $this->_addRequestField('vads_ship_to_zip', 'Shipping zip code', $an63, false, 63); $this->_addRequestField('vads_shop_name', 'Shop name', $ans127); $this->_addRequestField('vads_shop_url', 'Shop url', $ans127); $this->_addRequestField('vads_site_id', 'Site id', "#^\d{8}$#", true, 8); $this->_addRequestField('vads_theme_config', 'Theme', $ans255); $this->_addRequestField('vads_trans_date', 'Transaction date', $regex_trans_date, true, 14); $this->_addRequestField('vads_trans_id', 'Transaction id', "#^[0-8]\d{5}$#", true, 6); $this->_addRequestField('vads_url_success', 'Success url', $ans127, false, 127); $this->_addRequestField('vads_url_referral', 'Referral url', $ans127, false, 127); $this->_addRequestField('vads_url_refused', 'Refused url', $ans127, false, 127); $this->_addRequestField('vads_url_cancel', 'Cancel url', $ans127, false, 127); $this->_addRequestField('vads_url_error', 'Error url', $ans127, false, 127); $this->_addRequestField('vads_url_return', 'Return url', $ans127, false, 127); $this->_addRequestField('vads_user_info', 'User info', $ans255); $this->_addRequestField('vads_validation_mode', 'Validation mode', "#^[01]?$#", false, 1); $this->_addRequestField('vads_version', 'Gateway version', "#^V2$#", true, 2); // Enable / disable 3D Secure $this->_addRequestField('vads_threeds_mpi', 'Enable / disable 3D Secure', '#^[0-2]$#', false); // Declaration of parameters for Oney payment $this->_addRequestField('vads_cust_first_name', 'Customer first name', $an63, false, 63); $this->_addRequestField('vads_cust_last_name', 'Customer last name', $an63, false, 63); $this->_addRequestField('vads_cust_status', 'Customer status (private or company)', "#^PRIVATE|COMPANY$#", false, 7); $this->_addRequestField('vads_ship_to_first_name', 'Shipping first name', $an63, false, 63); $this->_addRequestField('vads_ship_to_last_name', 'Shipping last name', $an63, false, 63); $this->_addRequestField('vads_ship_to_status', 'Shipping status (private or company)', "#^PRIVATE|COMPANY$#", false, 7); $this->_addRequestField('vads_ship_to_delivery_company_name', 'Name of the delivery company', $ans127, false, 127); $this->_addRequestField('vads_ship_to_speed', 'Speed of the shipping method', "#^STANDARD|EXPRESS$#", false, 8); $this->_addRequestField('vads_ship_to_type', 'Type of the shipping method', "#^RECLAIM_IN_SHOP|RELAY_POINT|RECLAIM_IN_STATION|PACKAGE_DELIVERY_COMPANY|ETICKET$#", false, 24); $this->_addRequestField('vads_insurance_amount', 'The amount of insurance', '#^' . $supzero . '$#', false, 12); $this->_addRequestField('vads_tax_amount', 'The amount of tax', '#^' . $supzero . '$#', false, 12); $this->_addRequestField('vads_shipping_amount', 'The amount of shipping', '#^' . $supzero . '$#', false, 12); $this->_addRequestField('vads_nb_products', 'Number of products', '#^' . $supzero . '$#', false); // Set some default parameters $success &= $this->set('vads_version', 'V2'); $success &= $this->set('vads_page_action', 'PAYMENT'); $success &= $this->set('vads_action_mode', 'INTERACTIVE'); $success &= $this->set('vads_payment_config', 'SINGLE'); $timestamp = time(); $success &= $this->set('vads_trans_id', $this->_generateTransId($timestamp)); $success &= $this->set('vads_trans_date', gmdate('YmdHis', $timestamp)); } /** * Generate a trans_id. * To be independent from shared/persistent counters, we use the number of 1/10seconds since midnight, * which has the appropriate format (000000-899999) and has great chances to be unique. * @return string the generated trans_id * @access private */ function _generateTransId($timestamp) { list($usec, $sec) = explode(" ", microtime()); // microseconds, php4 compatible $temp = ($timestamp + $usec - strtotime('today 00:00')) * 10; $temp = sprintf('%06d', $temp); return $temp; } /** * Shortcut function used in constructor to build requestParameters * @param string $name * @param string $label * @param string $regex * @param boolean $required * @param mixed $value * @return boolean true on success * @access private */ function _addRequestField($name, $label, $regex, $required = false, $length = 255, $value = null) { $this->requestParameters[$name] = new VadsField($name, $label, $regex, $required, $length); if($value !== null) { return $this->set($name, $value); } else { return true; } } // ************************************** // INTERNATIONAL FUNCTIONS // ************************************** /** * Returns the iso codes of language accepted by the payment page * @static * @return array[int]string */ function getSupportedLanguages() { return array('fr', 'de', 'en', 'es', 'zh', 'it', 'ja', 'pt', 'nl'); } /** * Return the list of currencies recognized by the vads platform * @static * @return array[int]VadsCurrency */ function getSupportedCurrencies() { return array( new VadsCurrency('ARS', 32), new VadsCurrency('AUD', 36), new VadsCurrency('KHR', 116, 0), new VadsCurrency('CAD', 124), new VadsCurrency('CNY', 156, 1), new VadsCurrency('HRK', 191), new VadsCurrency('CZK', 203), new VadsCurrency('DKK', 208), new VadsCurrency('EKK', 233), new VadsCurrency('HKD', 344), new VadsCurrency('HUF', 348), new VadsCurrency('ISK', 352, 0), new VadsCurrency('IDR', 360, 0), new VadsCurrency('JPY', 392, 0), new VadsCurrency('KRW', 410, 0), new VadsCurrency('LVL', 428), new VadsCurrency('LTL', 440), new VadsCurrency('MYR', 458), new VadsCurrency('MXN', 484), new VadsCurrency('NZD', 554), new VadsCurrency('NOK', 578), new VadsCurrency('PHP', 608), new VadsCurrency('RUB', 643), new VadsCurrency('SGD', 702), new VadsCurrency('ZAR', 710), new VadsCurrency('SEK', 752), new VadsCurrency('CHF', 756), new VadsCurrency('THB', 764), new VadsCurrency('GBP', 826), new VadsCurrency('USD', 840), new VadsCurrency('TWD', 901, 1), new VadsCurrency('RON', 946), new VadsCurrency('TRY', 949), new VadsCurrency('XOF', 952, 0), new VadsCurrency('XPF', 953, 0), new VadsCurrency('BGN', 975), new VadsCurrency('EUR', 978), new VadsCurrency('PLN', 985), new VadsCurrency('BRL', 986)); } /** * Return a currency from its iso 3-letters code * @static * @param string $alpha3 * @return VadsCurrency */ function findCurrencyByAlphaCode($alpha3) { $list = VadsApi::getSupportedCurrencies(); foreach ($list as $currency) { /** @var VadsCurrency $currency */ if ($currency->alpha3 == $alpha3) { return $currency; } } return null; } /** * Returns a currency form its iso numeric code * @static * @param int $num * @return VadsCurrency */ function findCurrencyByNumCode($numeric) { $list = VadsApi::getSupportedCurrencies(); foreach ($list as $currency) { /** @var VadsCurrency $currency */ if ($currency->num == $numeric) { return $currency; } } return null; } /** * Returns a currency numeric code from its 3-letters code * @static * @param string $alpha3 * @return int */ function getCurrencyNumCode($alpha3) { $currency = VadsApi::findCurrencyByAlphaCode($alpha3); return is_a($currency, 'VadsCurrency') ? $currency->num : null; } // ************************************** // GETTERS/SETTERS // ************************************** /** * Shortcut for setting multiple values with one array * @param array[string]mixed $parameters * @return boolean true on success */ function setFromArray($parameters) { $ok = true; foreach ($parameters as $name => $value) { $ok &= $this->set($name, $value); } return $ok; } /** * General getter. * Retrieve an api variable from its name. Automatically add 'vads_' to the name if necessary. * Example : get('site_id'); ?> * @param string $name * @return mixed null if $name was not recognised */ function get($name) { if (!$name || !is_string($name)) { return null; } // V1/shortcut notation compatibility $name = (substr($name, 0, 5) != 'vads_') ? 'vads_' . $name : $name; if ($name == 'vads_key_test') { return $this->keyTest; } elseif ($name == 'vads_key_prod') { return $this->keyProd; } elseif ($name == 'vads_platform_url') { return $this->platformUrl; } elseif ($name == 'vads_redirect_enabled') { return $this->redirectEnabled; } elseif (array_key_exists($name, $this->requestParameters)) { return $this->requestParameters[$name] ->getValue(); } else { return null; } } /** * General setter. * Set an api variable with its name and the provided value. Automatically add 'vads_' to the name if necessary. * Example : set('site_id', '12345678'); ?> * @param string $name * @param mixed $value * @return boolean true on success */ function set($name, $value) { if (!$name || !is_string($name)) { return false; } // V1/shortcut notation compatibility $name = (substr($name, 0, 5) != 'vads_') ? 'vads_' . $name : $name; // Convert the parameters if they are not encoded in utf8 if($this->encoding !== "UTF-8") { $value = iconv($this->encoding, "UTF-8", $value); } // Search appropriate setter if ($name == 'vads_key_test') { return $this->setCertificate($value, 'TEST'); } elseif ($name == 'vads_key_prod') { return $this->setCertificate($value, 'PRODUCTION'); } elseif ($name == 'vads_platform_url') { return $this->setPlatformUrl($value); } elseif ($name == 'vads_redirect_enabled') { return $this->setRedirectEnabled($value); } elseif (array_key_exists($name, $this->requestParameters)) { return $this->requestParameters[$name] ->setValue($value); } else { return false; } } /** * Set target url of the payment form * @param string $url * @return boolean */ function setPlatformUrl($url) { if (!preg_match('#https?://([^/]+/)+#', $url)) { return false; } $this->platformUrl = $url; return true; } /** * Enable/disable redirect_* parameters * @param mixed $enabled false, '0', a null or negative integer or 'false' to disable * @return boolean */ function setRedirectEnabled($enabled) { $this->redirectEnabled = !(!$enabled || $enabled == '0' || strtolower($enabled) == 'false'); return true; } /** * Set TEST or PRODUCTION certificate * @param string $key * @param string $mode * @return boolean true if the certificate could be set */ function setCertificate($key, $mode) { // Check format if (!preg_match('#\d{16}#', $key)) { return false; } if ($mode == 'TEST') { $this->keyTest = $key; } elseif ($mode == 'PRODUCTION') { $this->keyProd = $key; } else { return false; } return true; } /** * Add product infos as request parameters. * @param string $label * @param int $amount * @param int $qty * @param string $ref * @param string $type * @return boolean true if product infos are set correctly */ function addProduct($label, $amount, $qty, $ref, $type) { $index = $this->get("nb_products") ? $this->get("nb_products") : 0; $ok = true; // Add product infos as request parameters $ok &= $this->_addRequestField("vads_product_label" . $index, "Product label", '#^[^<>"+-]{0,255}$#', false, 255, $label); $ok &= $this->_addRequestField("vads_product_amount" . $index, "Product amount", '#^[1-9]\d*$#', false, 12, $amount); $ok &= $this->_addRequestField("vads_product_qty" . $index, "Product quantity", '#^[1-9]\d*$#', false, 255, $qty); $ok &= $this->_addRequestField("vads_product_ref" . $index, "Product reference", '#^[A-Za-z0-9]{0,64}$#', false, 64, $ref); $ok &= $this->_addRequestField("vads_product_type" . $index, "Product type", "#^".implode("|", $this->ACCORD_CATEGORIES)."$#", false, 30, $type); // Increment the number of products $ok &= $this->set("nb_products", $index + 1); return $ok; } /** * Return certificate according to current mode, false if mode was not set * @return string|boolean * @access private */ function _getCertificate() { switch ($this->requestParameters['vads_ctx_mode'] ->getValue()) { case 'TEST': return $this->keyTest; break; case 'PRODUCTION': return $this->keyProd; break; default: return false; break; } } /** * Generate signature from a list of VadsField * @param array[string]VadsField $fields * @return string * @access private */ function _generateSignatureFromFields($fields = null, $hashed = true) { $params = array(); $fields = ($fields !== null) ? $fields : $this->requestParameters; foreach ($fields as $field) { if ($field->isRequired() || $field->isFilled()) { $params[$field->getName()] = $field->getValue(); } } return $this->sign($params, $this->_getCertificate(), $hashed); } /** * Public static method to compute a vads signature. Parameters must be in utf-8. * @param array[string]string $parameters payment gateway request/response parameters * @param string $key shop certificate * @param boolean $hashed set to false to get the raw, unhashed signature * @access public * @static */ function sign($parameters, $key, $hashed= true) { $signContent = ""; ksort($parameters); foreach ($parameters as $name => $value) { if (substr($name, 0, 5) == 'vads_') { $signContent .= $value . '+'; } } $signContent .= $key; $sign = $hashed ? sha1($signContent) : $signContent; return $sign; } // ************************************** // REQUEST PREPARATION FUNCTIONS // ************************************** /** * Unset the value of optionnal fields if they are unvalid */ function clearInvalidOptionnalFields() { $fields = $this->getRequestFields(); foreach ($fields as $field) { if (!$field->isValid() && !$field->isRequired()) { $field->setValue(null); } } } /** * Check all payment fields * @param array $errors will be filled with the name of invalid fields * @return boolean */ function isRequestReady(&$errors = null) { $errors = is_array($errors) ? $errors : array(); $fields = $this->getRequestFields(); foreach ($fields as $field) { if (!$field->isValid()) { $errors[] = $field->getName(); } } return sizeof($errors) == 0; } /** * Return the list of fields to send to the payment gateway * @return array[string]VadsField a list of VadsField or false if a parameter was invalid * @see VadsField */ function getRequestFields() { $fields = $this->requestParameters; // Filter redirect_parameters if redirect is disabled if (!$this->redirectEnabled) { $redirectFields = array( 'vads_redirect_success_timeout', 'vads_redirect_success_message', 'vads_redirect_error_timeout', 'vads_redirect_error_message'); foreach ($redirectFields as $fieldName) { unset($fields[$fieldName]); } } foreach ($fields as $fieldName => $field) { if (!$field->isFilled() && !$field->isRequired()) { unset($fields[$fieldName]); } } // Compute signature $fields['signature']->setValue($this->_generateSignatureFromFields($fields)); // Return the list of fields return $fields; } /** * Return the url of the payment page with urlencoded parameters (GET-like url) * @return boolean|string */ function getRequestUrl() { $fields = $this->getRequestFields(); $url = $this->platformUrl . '?'; foreach ($fields as $field) { if ($field->isFilled()) { $url .= $field->getName() . '=' . rawurlencode($field->getValue()) . '&'; } } $url = substr($url, 0, -1); // remove last & return $url; } /** * Return the html form to send to the payment gateway * @param string $enteteAdd * @param string $inputType * @param string $buttonValue * @param string $buttonAdd * @param string $buttonType * @return string */ function getRequestHtmlForm($enteteAdd = '', $inputType = 'hidden', $buttonValue = 'Aller sur la plateforme de paiement', $buttonAdd = '', $buttonType = 'submit') { $html = ""; $html .= '
'; $html .= "\n"; $html .= $this->getRequestFieldsHtml('type="' . $inputType . '"'); $html .= ''; $html .= "\n"; $html .= '
'; return $html; } /** * Return the html code of the form fields to send to the payment page * @param string $inputAttributes * @return string */ function getRequestFieldsHtml($inputAttributes = 'type="hidden"') { $fields = $this->getRequestFields(); $html = ''; $format = '\n"; foreach ($fields as $field) { if ($field->isFilled()) { // Convert special chars to HTML entities to avoid data troncation $value = htmlspecialchars($field->getValue(), ENT_QUOTES, 'UTF-8'); $html .= sprintf($format, $field->getName(), $value); } } return $html; } // ************************************** // RESPONSE ANALYSIS FUNCTIONS // ************************************** /** * Prepare to analyse check url or return url call * @param array[string]string $parameters $_REQUEST by default * @param string $ctx_mode * @param string $key_test * @param string $key_prod */ function loadResponse($parameters = null, $ctx_mode = null, $key_test = null, $key_prod = null) { $parameters = is_null($parameters) ? $_REQUEST : $parameters; $parameters = VadsApi::uncharm($parameters); // Load site credentials if provided if (!is_null($ctx_mode)) { $this->set('vads_ctx_mode', $ctx_mode); } if (!is_null($key_test)) { $this->set('vads_key_test', $key_test); } if (!is_null($key_prod)) { $this->set('vads_key_prod', $key_prod); } $this->response = new VadsResponse(); $this->response->load($parameters, $this->_getCertificate()); } /** * Return a VadsResponse object representing the result of the payment. * You can provide arguments to load data as in loadResponse. * @see VadsApi::loadResponse * @return VadsResponse */ function getResponse($parameters = null, $ctx_mode = null, $key_test = null, $key_prod = null) { //TODO ? redondance avec loadResponse if (is_null($this->response)) { $this->loadResponse($parameters, $ctx_mode, $key_test, $key_prod); } return $this->response; } /** * PHP is not yet a sufficiently advanced technology to be indistinguishable from magic... * so don't use magic_quotes, they mess up with the gateway response analysis. * * @param array $potentiallyMagicallyQuotedData */ function uncharm($potentiallyMagicallyQuotedData) { if (get_magic_quotes_gpc()) { $sane = array(); foreach ($potentiallyMagicallyQuotedData as $k => $v) { $saneKey = stripslashes($k); $saneValue = is_array($v) ? VadsApi::uncharm($v) : stripslashes($v); $sane[$saneKey] = $saneValue; } } else { $sane = $potentiallyMagicallyQuotedData; } return $sane; } } /** * Class representing the result of a transaction (sent by the check url or by the client return) * @package VadsApi */ class VadsResponse { /** * Raw response parameters array * @var array * @access private */ var $raw_response = array(); /** * Certificate used to check the signature * @see VadsApi::sign * @var boolean * @access private */ var $certificate; /** * Value of vads_result * @var string * @access private */ var $code; /** * Translation of $code (vads_result) * @var string * @access private */ var $message; /** * Value of vads_extra_result * @var string * @access private */ var $extraCode; /** * Translation of $extraCode (vads_extra_result) * @var string * @access private */ var $extraMessage; /** * Value of vads_auth_result * @var string * @access private */ var $authCode; /** * Translation of $authCode (vads_auth_result) * @var string * @access private */ var $authMessage; /** * Value of vads_warranty_result * @var string * @access private */ var $warrantyCode; /** * Translation of $warrantyCode (vads_warranty_result) * @var string * @access private */ var $warrantyMessage; /** * Associative array containing human-readable translations of response codes. Initialized to french translations. * @var array * @access private */ var $translation = array( 'no_code' => '', 'no_translation' => '', 'results' => array( '00' => 'Paiement réalisé avec succès', '02' => 'Le commerçant doit contacter la banque du porteur', '05' => 'Paiement refusé', '17' => 'Annulation client', '30' => 'Erreur de format de la requête', '96' => 'Erreur technique lors du paiement'), 'extra_results_default' => array( 'empty' => 'Pas de contrôle effectué', '00' => 'Tous les contrôles se sont déroulés avec succès', '02' => 'La carte a dépassé l’encours autorisé', '03' => 'La carte appartient à la liste grise du commerçant', '04' => 'Le pays d’émission de la carte appartient à la liste grise du commerçant', '05' => 'L’adresse IP appartient à la liste grise du commerçant', '99' => 'Problème technique rencontré par le serveur lors du traitement d’un des contrôles locaux'), 'extra_results_30' => array( '00' => 'signature', '01' => 'version', '02' => 'merchant_site_id', '03' => 'transaction_id', '04' => 'date', '05' => 'validation_mode', '06' => 'capture_delay', '07' => 'config', '08' => 'payment_cards', '09' => 'amount', '10' => 'currency', '11' => 'ctx_mode', '12' => 'language', '13' => 'order_id', '14' => 'order_info', '15' => 'cust_email', '16' => 'cust_id', '17' => 'cust_title', '18' => 'cust_name', '19' => 'cust_address', '20' => 'cust_zip', '21' => 'cust_city', '22' => 'cust_country', '23' => 'cust_phone', '24' => 'url_success', '25' => 'url_refused', '26' => 'url_referral', '27' => 'url_cancel', '28' => 'url_return', '29' => 'url_error', '30' => 'identifier', '31' => 'contrib', '32' => 'theme_config', '34' => 'redirect_success_timeout', '35' => 'redirect_success_message', '36' => 'redirect_error_timeout', '37' => 'redirect_error_message', '38' => 'return_post_params', '39' => 'return_get_params', '40' => 'card_number', '41' => 'expiry_month', '42' => 'expiry_year', '43' => 'card_cvv', '44' => 'card_info', '45' => 'card_options', '46' => 'page_action', '47' => 'action_mode', '48' => 'return_mode', '50' => 'secure_mpi', '51' => 'secure_enrolled', '52' => 'secure_cavv', '53' => 'secure_eci', '54' => 'secure_xid', '55' => 'secure_cavv_alg', '56' => 'secure_status', '60' => 'payment_src', '61' => 'user_info', '62' => 'contracts', '70' => 'empty_params', '99' => 'other'), 'auth_results' => array( '00' => 'transaction approuvée ou traitée avec succès', '02' => 'contacter l’émetteur de carte', '03' => 'accepteur invalide', '04' => 'conserver la carte', '05' => 'ne pas honorer', '07' => 'conserver la carte, conditions spéciales', '08' => 'approuver après identification', '12' => 'transaction invalide', '13' => 'montant invalide', '14' => 'numéro de porteur invalide', '30' => 'erreur de format', '31' => 'identifiant de l’organisme acquéreur inconnu', '33' => 'date de validité de la carte dépassée', '34' => 'suspicion de fraude', '41' => 'carte perdue', '43' => 'carte volée', '51' => 'provision insuffisante ou crédit dépassé', '54' => 'date de validité de la carte dépassée', '56' => 'carte absente du fichier', '57' => 'transaction non permise à ce porteur', '58' => 'transaction interdite au terminal', '59' => 'suspicion de fraude', '60' => 'l’accepteur de carte doit contacter l’acquéreur', '61' => 'montant de retrait hors limite', '63' => 'règles de sécurité non respectées', '68' => 'réponse non parvenue ou reçue trop tard', '90' => 'arrêt momentané du système', '91' => 'émetteur de cartes inaccessible', '96' => 'mauvais fonctionnement du système', '94' => 'transaction dupliquée', '97' => 'échéance de la temporisation de surveillance globale', '98' => 'serveur indisponible routage réseau demandé à nouveau', '99' => 'incident domaine initiateur'), 'warranty_results' => array( 'YES' => 'Le paiement est garanti', 'NO' => 'Le paiement n\'est pas garanti', 'UNKNOWN' => 'Suite à une erreur technique, le paiment ne peut pas être garanti')); //TODO not tested. not used. // /** // * Replace current translation entries with provided ones // * @param array $translation // */ // function loadTranslation($translation) { // return $this->translation = $this->_recurseLoadTranslation($this->translation, $translation); // } // // /** // * Recursively load a $loaded translation array into the $original translation array // * @param array $original // * @param array $loaded // */ // function _recurseLoadTranslation($original, $loaded) { // foreach ($original as $key => $value) { // if (is_array($value)) { // $original[$key] = $this->_recurseLoadTranslation($original[$key], $array[$key]); // } // else if(array_key_exists($value, $loaded)) { // $original[$key] = $loaded[$value]; // } // } // return $original; // } /** * Load response codes and translations from a parameter array. * @param array[string]string $raw * @param boolean $authentified */ function load($raw, $certificate) { $this->raw_response = is_array($raw) ? $raw : array(); $this->certificate = $certificate; // Get codes $code = $this->_findInArray('vads_result', $raw, null); $extraCode = $this->_findInArray('vads_extra_result', $raw, null); $authCode = $this->_findInArray('vads_auth_result', $raw, null); $warrantyCode = $this->_findInArray('vads_warranty_code', $raw, null); // Common translations $noCode = $this->translation['no_code']; $noTrans = $this->translation['no_translation']; // Result and extra result if ($code == null) { $message = $noCode; $extraMessage = ($extraCode == null) ? $noCode : $noTrans; } else { $message = $this->_findInArray($code, $this->translation['results'], $noTrans); if ($extraCode == null) { $extraMessage = $noCode; } elseif ($code == 30) { $extraMessage = $this->_findInArray($extraCode, $this->translation['extra_results_30'], $noTrans); } else { $extraMessage = $this->_findInArray($extraCode, $this->translation['extra_results_default'], $noTrans); } } // auth_result if ($authCode == null) { $authMessage = $noCode; } else { $authMessage = $this->_findInArray($authCode, $this->translation['auth_results'], $noTrans); } // warranty_result if ($warrantyCode == null) { $warrantyMessage = $noCode; } else { $warrantyMessage = $this->_findInArray($warrantyCode, $this->translations['warranty_results'], $noTrans); } $this->code = $code; $this->message = $message; $this->authCode = $authCode; $this->authMessage = $authMessage; $this->extraCode = $extraCode; $this->extraMessage = $extraMessage; $this->warrantyCode = $warrantyCode; $this->warrantyMessage = $warrantyMessage; } /** * Check response signature * @return boolean */ function isAuthentified() { return VadsApi::sign($this->raw_response, $this->certificate) == $this->get('signature'); } /** * Return the signature computed from the received parameters, for log/debug purposes. * @param boolean $hashed apply sha1, false by default * @return string */ function getComputedSignature($hashed = false) { return VadsApi::sign($this->raw_response, $this->certificate, $hashed); } /** * Check if the payment was successful (waiting confirmation or captured) * @return boolean */ function isAcceptedPayment() { return $this->code == '00'; } /** * Check if the payment is waiting confirmation (successful but the amount has not been transfered and is not yet guaranteed) * @return boolean */ function isPendingPayment() { return $this->get('auth_mode') == 'MARK'; } /** * Check if the payment process was interrupted by the client * @return boolean */ function isCancelledPayment() { return $this->code == '17'; } /** * Return the value of a response parameter. * @param string $name * @return string */ function get($name) { // Manage shortcut notations by adding 'vads_' if (!array_key_exists($name, $this->raw_response)) { $name = 'vads_' . $name; } return @$this->raw_response[$name]; } /** * Return the paid amount converted from cents (or currency equivalent) to a decimal value * @return float */ function getFloatAmount() { $currency = VadsApi::findCurrencyByNumCode($this->get('currency')); return $currency->convertAmountToFloat($this->get('amount')); } /** * Return a short description of the payment result, useful for logging * @return string */ function getLogString() { $log = $this->code . ' : ' . $this->message; if ($this->code == '30') { $log .= ' (' . $this->extraCode . ' : ' . $this->extraMessage . ')'; } return $log; } /** * Return a formatted string to output as a response to the check url call * @param string $case shortcut code for current situations. Most useful : payment_ok, payment_ko, auth_fail * @param string $extraMessage some extra information to output to the payment gateway * @return string */ function getOutputForGateway($case = '', $extraMessage = "") { $success = false; $message = ''; // Messages prédéfinis selon le cas $cases = array( 'payment_ok' => array(true, 'Paiement valide traité'), 'payment_ko' => array(true, 'Paiement invalide traité'), 'payment_ok_already_done' => array( true, 'Paiement valide traité, déjà enregistré'), 'order_not_found' => array(false, 'Impossible de retrouver la commande'), 'payment_ko_on_order_ok' => array( false, 'Code paiement invalide reçu pour une commande déjà validée'), 'auth_fail' => array(false, 'Echec authentification'), 'ok' => array(true, ''), 'ko' => array(false, '')); if (array_key_exists($case, $cases)) { $success = $cases[$case][0]; $message = $cases[$case][1]; } $message .= ' ' . $extraMessage; $message = str_replace("\n", '', $message); $response = ''; $response .= ''; $response .= $success ? "OK-" : "KO-"; $response .= $this->get('hash'); $response .= ($message === ' ') ? "\n" : "=$message\n"; $response .= ''; return $response; } /** * Private shortcut function * @param string $value * @param array[string]string $translations * @param string $defaultTransation * @access private */ function _findInArray($key, $array, $default) { if (is_array($array) && array_key_exists($key, $array)) { return $array[$key]; } return $default; } } /** * Class representing a field of the form to send to the payment gateway * @package VadsApi */ class VadsField { /** * Field's name. Matches the html input attribute * @var string * @access private */ var $name; /** * Field's label in english, to be used by translation systems * @var string * @access private */ var $label; /** * Field's maximum length. Matches the html text input attribute * @var int * @access private */ var $length; /** * PCRE regular expression the field value must match * @var string * @access private */ var $regex; /** * Whether the form requires the field to be set (even to an empty string) * @var boolean * @access private */ var $required; /** * Field's value. Null or string * @var string * @access private */ var $value = null; /** * Constructor * @param string $name * @param string $label * @param string $regex * @param boolean $required * @param string $value * @return VadsField */ function VadsField($name, $label, $regex, $required = false, $length = 255) { $this->name = $name; $this->label = $label; $this->regex = $regex; $this->required = $required; $this->length = $length; } /** * Setter for value * @param mixed $value * @return boolean true if the value is valid */ function setValue($value) { $value = ($value === null) ? null : (string) $value; // We save value even if invalid (in case the validate function is too restrictive, it happened once) ... $this->value = $value; if (!$this->validate($value)) { // ... but we return a "false" warning return false; } return true; } /** * Checks the current value * @return boolean false if the current value is invalid or null and required */ function isValid() { return $this->validate($this->value); } /** * Check if a value is valid for this field * @param string $value * @return boolean */ function validate($value) { if ($value === null && $this->isRequired()) { return false; } if ($value !== null && !preg_match($this->regex, $value)) { return false; } return true; } /** * Setter for the required attribute * @param boolean $required */ function setRequired($required) { $this->required = (boolean) $required; } /** * Is the field required in the payment request ? * @return boolean */ function isRequired() { return $this->required; } /** * Return the current value of the field. * @return string */ function getValue() { return $this->value; } /** * Return the name (html attribute) of the field. * @return string */ function getName() { return $this->name; } /** * Return the english human-readable name of the field. * @return string */ function getLabel() { return $this->label; } /** * Return the maximum length of the field's value. * @return number */ function getLength() { return $this->length; } /** * Has a value been set ? * @return boolean */ function isFilled() { return !is_null($this->getValue()); } } /** * Class representing a currency, used for converting alpha/numeric iso codes and float/integer amounts * @package VadsApi * */ class VadsCurrency { var $alpha3; var $num; var $decimals; function VadsCurrency($alpha3, $num, $decimals = 2) { $this->alpha3 = $alpha3; $this->num = $num; $this->decimals = $decimals; } function convertAmountToInteger($float) { $coef = pow(10, $this->decimals); return round(intval($float) * $coef); } function convertAmountToFloat($integer) { $coef = pow(10, $this->decimals); return floatval($integer) / $coef; } } // No closing tag