我是Drupal的全新手,我花了大部分时间和Joomla在一起!我有一个使用Web表单组件的Drupal 7站点。它的步骤定义为:
现在分页符组件如下所示:
如果我在优惠券文本字段(我添加)中填写GOMEZ后正确理解了事情,则不应该中断,用户应该转到下一页。但事实并非如此,用户必须通过PayPal进行操作。
我想要发生的是用户输入优惠券代码并跳过PayPal步骤,用户可以填写表格。看来这可以通过使用webform_paypal_permission()任何想法吗?
我很高兴如果我必须修改PHP代码但是如果可以的话我想避免使用它,而是使用我认为存在的功能。
我还在PHP下面包含了用于调试PayPal步骤的PHP:
<?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;
}
答案 0 :(得分:2)
首先,您似乎正在使用带有webform_conditional模块的Webform 3。我建议您升级到包含webform_conditional的Webform 4,并在同一页面上的组件上工作。 Webform 4相当稳定,我个人认为它比webform 3 + webform_conditional更稳定。
其次,最好是创建一个新的webform_paypal组件,而不是改变分页符组件,因为它可能会破坏其他内容。例如,webform_paypal module是您添加/编辑代码的良好开端。
不幸的是,webform_paypal模块开箱即用,既没有分页符也没有Webform 3和4的条件:https://drupal.org/node/1413182。 我甚至试图将webform_paypal组件放在一个字段集中,并在字段集上设置条件但是失败了。
对不起,我无法帮助更多。我希望我提供的一些小信息能让你朝着正确的方向前进。