Я новичок в Drupal, проведший большую часть своего времени с Joomla! У меня есть сайт Drupal 7, который использует компонент веб-формы. Это шаги определяется как:Как пропустить перерыв страницы
Теперь компонент разрыв страницы выглядит следующим образом:
Если я понимаю вещи правильно после заполнения Gomez в Купонный текстовом поле (я добавил) перерыв не должен происходить, и пользователь должен перейти на следующую страницу. Однако это не так, и пользователь должен пройти через PayPal.
Я хочу, чтобы пользователь вводил код купона, и шаг PayPal пропускается, и пользователь может заполнить форму. Похоже, это возможно с помощью webform_paypal_permission() Любые идеи?
Я счастлив, если мне нужно изменить PHP-код, но я хочу, чтобы избежать его, если я могу и вместо этого использовать функциональность, которая, я считаю, есть.
Я также включают в себя ниже PHP, который используется для стадии PayPal в случае, если это использовать для отладки это:
<?php
/**
* Implementation of hook_init
*
* A bit of a hack,Seems that session_id keeps changing for anon users and we need to track that through to the IPN to
* know if this session has paid or not.
*
* So store it in $_SESSION
*/
function webform_paypal_init() {
global $_SESSION;
if (empty($_SESSION['webform-session'])) {
// anonymous users wont have a session stick, so do it this way (session_id changes on each page)
$_SESSION['webform-session'] = session_id();
}
}
/**
* Implements hook_menu().
*/
function webform_paypal_menu() {
$items = array();
$items['webform_paypal_ipn/%/%/%'] = array(
'page callback' => 'webform_paypal_ipn_callback',
'page arguments' => array(1, 2, 3),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
$items['webform_paypal_lander/%/%'] = array(
'page callback' => 'webform_paypal_lander',
'page arguments' => array(1, 2),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_permission().
*/
function webform_paypal_permission() {
return array(
'bypass payment' => array(
'title' => t('Bypass payment'),
'description' => t('Complete the webform without payment.'),
),
);
}
/**
* This is the 'landing' or 'return' page that return= will return a user to from PayPal
* It's responsible for waiting for a paypal IPN notification then pushing the user onto the next
* page as its stored in $_SESSION, it does so by faking a HTTP POST, yuck!
*
* @param $nid - the NodeID to resubmit to (will be converted to full URL)
* @param $cid - the ComponentID that we need to wait to be paid by IPN callback
*
*/
function webform_paypal_lander($nid, $cid) {
$output = array();
// Just do some idle stuff until the IPN notification lands
$waits = 0;
while (!webform_paypal_ipn_submission_exists($cid, $nid)) {
sleep(1);
$waits++;
if ($waits > 15) {
watchdog('webform_paypal', "No IPN update was found from PayPal, cant allow user to continue.", array(), WATCHDOG_ERROR);
return t('No reply found from PayPal, unable to process your payment at this time.');
}
}
// Once it's here, resubmit the form with their stored previous form submission
// The IPN should then be registred in the DB by our callback
// And the #submit processor wont care about them anymore and they will continue on.
foreach ($_SESSION['page_store'] as $id => $row) {
if (is_array($row)) {
foreach ($row as $sub_id => $sub_row) {
$output[] = $id . "[$sub_id]=$sub_row";
}
}
else {
$output[] = "$id=$row";
}
}
$cookies = array();
foreach ($_COOKIE as $name => $value) {
$cookies[] = "$name=$value";
}
$options = array(
'method' => 'POST',
'data' => implode('&', $output),
'timeout' => 15,
'headers' => array('Content-Type' => 'application/x-www-form-urlencoded', 'Cookie' => implode('; ', $cookies)),
);
$url = url('node/' . $nid, array('absolute' => TRUE));
$result = drupal_http_request($url, $options);
// Everything should generally work out just fine here
if ($result->code == 200) {
print $result->data;
drupal_exit();
}
}
/**
* #submit processor
*
* Send the user to the PayPal payment page if neccessary
*
* @param $form
* @param $form_state
*/
function webform_paypal_pause_or_redirect($form, &$form_state) {
// Know which CID (Component ID) was clicked as part of the 'page_break'
// page_num would represent number of page_breaks to skip to know
$page_num = $form_state['webform']['page_num'];
$current_page = 1;
foreach ($form_state['webform']['component_tree']['children'] as $cid => $component) {
if ($component['type'] == 'pagebreak') {
if ($page_num == $current_page) {
break;
}
$current_page++;
}
}
// See if this component is in any mode to be redirected
$mode = variable_get('webform_paypal_button_mode_' . $cid, '');
if ($mode == 'live' || $mode == 'sandbox') {
// If so, redirect to PayPal if theres no IPN submission from PayPal
// This should only happen the first time because users returning from PayPal enter a sleep loop to wait
// for the IPN update.
// Bypass for users with the 'bypass payment' permission
if (!webform_paypal_ipn_submission_exists($cid, $form['#node']->nid) && !user_access('bypass payment')) {
$store = $_POST;
// Store the form in a session var, we will resubmit the form when we return from PayPal
// Which should make the user goto the next page if the payment has been received OK
$_SESSION['page_store'] = $store;
drupal_goto(webform_paypal_submit_url($form['#node']->nid, $cid));
}
}
}
function webform_paypal_ipn_submission_exists($cid, $nid) {
$result = db_select('webform_paypal_ipn', 'wp_ipn')
->fields('wp_ipn', array('extra'))
->condition('cid', $cid)
->condition('sessionID', $_SESSION['webform-session'])
->condition('nid', $nid)
->execute();
return $result->rowCount();
}
/**
* Implements of hook_form_alter().
*
* @todo there must be a better way to theme in the button than to use a form_alter
*/
function webform_paypal_form_alter(&$form, &$form_state, $form_id) {
// Handle a redirect to PayPal if neccessary
if (strpos($form_id, 'webform_client_form_') !== FALSE) {
$form['#submit'][] = 'webform_paypal_pause_or_redirect';
}
// Add the config to the pagebreak component
if ($form_id == 'webform_component_edit_form') {
$cid = arg(4);
if ($form['type']['#value'] == 'pagebreak') {
$form['webform_paypal'] = array(
'#type' => 'fieldset',
'#title' => t('Paypal Button integration'),
);
$form['webform_paypal']['webform_paypal_button_id'] = array(
'#type' => 'textfield',
'#title' => t('PayPal Button ID'),
'#default_value' => variable_get('webform_paypal_button_id_' . $cid, ''),
'#description' => t('If this is requires a PayPal Payment to continue, enter the Button ID here'),
'#weight' => -8
);
$form['webform_paypal']['webform_button_mode'] = array(
'#type' => 'select',
'#title' => t('PayPal Button Mode'),
'#default_value' => variable_get('webform_paypal_button_mode_' . $cid, ''),
'#options' => array('disabled' => t('DISABLED'), 'sandbox' => t('SANDBOX'), 'live' => t('LIVE')),
'#weight' => -9
);
$form['#submit'][] = 'webform_paypal_component_edit_submit';
}
}
}
function webform_paypal_component_edit_submit($form, &$form_state) {
$cid = $form_state['values']['cid'];
$id = $form_state['values']['webform_paypal']['webform_paypal_button_id'];
variable_set('webform_paypal_button_id_' . $cid, $id);
$id = $form_state['values']['webform_paypal']['webform_button_mode'];
variable_set('webform_paypal_button_mode_' . $cid, $id);
}
/**
* Get the URL for the user to connect to PayPal
*
* This special URL includes things like return URL's, IPN etc
*/
function webform_paypal_submit_url($nid, $cid, $tracking_url = "") {
global $base_url;
global $_SESSION;
$mode = variable_get('webform_paypal_button_mode_' . $cid, '');
if($mode == 'live') {
$url = 'https://www.paypal.com/cgi-bin/webscr';
}
else {
$url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
$post_data = array();
$post_data['cmd'] = '_s-xclick';
$post_data['return'] = $base_url . '/webform_paypal_lander/' . $nid . '/' . $cid;
$post_data['hosted_button_id'] = variable_get('webform_paypal_button_id_' . $cid, '');
//send return path to submission for better tracking
$post_data['custom'] = $tracking_url;
// setup IPN callback
$post_data['notify_url'] = $base_url . '/webform_paypal_ipn/' . $nid . '/' . $cid . '/' . $_SESSION['webform-session'];
// return the URL
$url = url($url, array('query' => $post_data, 'external' => TRUE));
return $url;
}
/**
* Menu callback for receving the PayPal IPN calls
* Arguments were handed to PayPal in the IPN link
*
* @param $nid Node ID
* @param $cid Component ID
* @param $sessionID Session ID from session_id() of the submitter
*/
function webform_paypal_ipn_callback($nid, $cid, $sessionID) {
// get the URL depending on the components configuration
$mode = variable_get('webform_paypal_button_mode_' . $cid, '');
if ($mode == 'live') {
$url = 'https://www.paypal.com/cgi-bin/webscr';
}
else {
$url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
if (webform_paypal_ipn_verify_message($url)) {
$key = array(
'nid' => $nid,
'cid' => $cid,
'sessionID' => $sessionID
);
db_merge('webform_paypal_ipn')
->key($key)
->fields(array_merge($key, array(
'extra' => serialize($_POST)
)))
->execute();
}
return 'OK';
}
/**
* Input IPN processor
* from https://developer.paypal.com/webapps/developer/docs/classic/ipn/ht_ipn/
*
* @return bool
*/
function webform_paypal_ipn_verify_message($url) {
// STEP 1: read POST data
// Reading POSTed data directly from $_POST causes serialization issues with array data in the POST.
// Instead, read raw POST data from the input stream.
$raw_post_data = file_get_contents('php://input');
$raw_post_array = explode('&', $raw_post_data);
$myPost = array();
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2) {
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
// read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
$req = 'cmd=_notify-validate';
if (function_exists('get_magic_quotes_gpc')) {
$get_magic_quotes_exists = TRUE;
}
foreach ($myPost as $key => $value) {
if ($get_magic_quotes_exists == TRUE && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
}
else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
// Step 2: POST IPN data back to PayPal to validate
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, variable_get('webform_paypal_verifypeer', TRUE));
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Connection: Close'));
// In wamp-like environments that do not come bundled with root authority certificates,
// please download 'cacert.pem' from "http://curl.haxx.se/docs/caextract.html" and set
// the directory path of the certificate as shown below:
if ($cacert = variable_get('webform_paypal_cacert', FALSE)) {
if (!file_exists($cacert)) {
watchdog('webform_paypal', "unable to open cert file", array(), WATCHDOG_ERROR);
}
curl_setopt($ch, CURLOPT_CAINFO, drupal_realpath($cacert));
}
if (!($res = curl_exec($ch))) {
watchdog('webform_paypal', curl_error($ch), array(), WATCHDOG_ERROR);
curl_close($ch);
exit;
}
curl_close($ch);
// inspect IPN validation result and act accordingly
if (strcmp($res, "VERIFIED") == 0) {
// The IPN is verified, process it:
// check whether the payment_status is Completed
// check that txn_id has not been previously processed
// check that receiver_email is your Primary PayPal email
// check that payment_amount/payment_currency are correct
// process the notification
// assign posted variables to local variables
$item_name = $_POST['item_name'];
$item_number = $_POST['item_number'];
$payment_status = $_POST['payment_status'];
$payment_amount = $_POST['mc_gross'];
$payment_currency = $_POST['mc_currency'];
$txn_id = $_POST['txn_id'];
$receiver_email = $_POST['receiver_email'];
$payer_email = $_POST['payer_email'];
if ($payment_status == 'Completed') {
watchdog('webform_paypal', "PayPal IPN success verification %id", array("%id" => $txn_id));
return TRUE;
}
else {
watchdog('webform_paypal', "PayPal IPN FAIL verification %id (not Completed)", array("%id" => $txn_id));
}
}
watchdog('webform_paypal', "PayPal IPN success FAIL (Not verified) - %msg", array("%msg" => $res));
return FALSE;
}
Спасибо за указатели. У меня есть +1 ваш ответ, чтобы вы получили часть награды, поскольку, к сожалению, она не решила мою проблему напрямую. – TheEdge
@ TheEdge Мне очень хотелось бы, чтобы я помог вам больше. Или, может быть, кому-то еще на StackOverflow на пути к ответу. – grim