I am trying to create an AJAX form with Zend_Form. It all works, except when the form is returned invalid, the ReCaptcha scripts are "filtered" out by jQuery. I have tried several different methods, but to no avail.
Zend Form:
<?php
class Application_Form_Login extends Zend_Form
{
public function init()
{
$this->setName('loginfrm')
->setOptions(array('class' => 'niceform', 'action' => 'login/index'));
$username = $this->addElement('text', 'username', array(
'filters' => array(
'StringTrim',
'StringToLower'
),
'validators' => array(
'Alnum',
array('StringLength', false, array(3,20))
),
'required' => true,
'label' => 'Your Username:'
));
$password = $this->addElement('password', 'password', array(
'filters' => array('StringTrim'),
'validators' => array(
'Alnum',
array('StringLength', false, 6, 32)
),
'required' => true,
'label' => 'Your Password:'
));
$config = new Zend_Config_Ini( APPLICATION_PATH . '/configs/config.ini', 'auth' );
$recaptcha = new Zend_Service_ReCaptcha(
$config->keys->recaptcha->public , $config->keys->recaptcha->private , null, array( 'theme' => 'clean' )
);
$captcha = $this->addElement('captcha', 'captcha', array(
'label' => 'Type the characters you see in the picture below',
'captcha' => 'ReCaptcha',
'captchaOptions' => array(
'captcha' => 'ReCaptcha',
'service' => $recaptcha
)
));
$this->addElement('button', 'submit', array(
'label' => 'Login',
'ignore' => true,
'class' => 'submit'
));
$this->setDecorators(array(
'FormElements',
array('HtmlTag', array('tag' => 'dl', 'class' => 'form')),
array('Description', array('placement' => 'prepend', 'class' => 'errors')),
'Form'
));
}
}
Javascript file: (removed some code to save you time)
//
// Namespace - Module Pattern.
//
var first = (function ($, window, document, undefined) {
// Expose innards of first.
return {
go: function () {
for (var i in first.init) {
first.init[i]();
}
},
init: {
partofcode: function() {
var d = $(document);
// support form submits
d.on('click', 'button', function(ev) {
var form = $(this).closest("form");
first.util.ajax(
form.attr("action"),
form.serialize(),
function(data) {
if(window.debug){ alert(data); }
var topDiv = form.closest(".window_main_full");
topDiv.html(data);
},
"html"
);
});
}
},
util: {
ajax: function(location, data, success, dataType) {
$.ajax({
dataType: dataType,
type: 'POST',
url: location,
data: data,
beforeSend: function() {
// show the loading image
var panel = $('#ajax_panel').show();
panel.html('Loading...');
// center the ajax_panel
panel.css({
'width' : (panel.width() + 25) + 'px',
'margin-left' : (($(window).width() / 2) - (panel.width() / 2 )) + 'px'
});
if(window.debug){ alert("before"); }
},
success: function(data){
if(window.debug){ alert("Before function..."); }
success(data);
$('#ajax_panel').html('').hide();
if(window.debug){ alert("after"); }
},
error: function(xhr, status, error) {
$('#ajax_panel').html('<span class="error"><strong>Oops!</strong> Try that again in a few moments.</span>');
if(window.debug){
alert('XHR: ' + xhr.status + '\nStatus:' + status + '\nError: ' + error);
setTimeout(function() {
$('#ajax_panel').slideUp(500, function() {
$('#ajax_panel').hide();
});
}, 2000);
}
}
});
}
}
};
// Pass in jQuery.
})(jQuery, this, this.document);
//
// Kick things off.
//
jQuery(document).ready(function () {
first.go();
});
I know the whole .html() filtering out scripts has been asked lots of times, but I just can't seem to find a solution.
Related
TL;DR: I'm trying to implement subscription to my store, but the "paypalobjects.com/api/checkout.js" redirects to "sandbox.paypal.com/webapps/hermes/error". Regular payments work as intended. I'm using Express Checkout advanced server integrations.
My Paypal.Button:
paypal.Button.render({
env: 'sandbox', // Optional: specify 'sandbox' environment
payment: function(resolve, reject) {
const token = localStorage.getItem('_token').split(' ')[1];
if(!subscribe){
var CREATE_PAYMENT_URL = `/store/${store}/paypal/create-payment/${orderId}?token=${token}`;
}else{
var CREATE_PAYMENT_URL = `/store/${store}/subscribe/paypal/create-payment/${orderId}?token=${token}`;
}
paypal.request.post(CREATE_PAYMENT_URL)
.then(function(data) { resolve(data.id); })
.catch(function(err) { console.log(err); });
},
onAuthorize: function(data) {
const token = localStorage.getItem('_token').split(' ')[1];
if(!subscribe){
var EXECUTE_PAYMENT_URL = `/store/${store}/paypal/execute-payment?token=${token}`;
}else{
var EXECUTE_PAYMENT_URL = `/store/${store}/subscribe/paypal/execute-payment?token=${token}`;
}
paypal.request.post(EXECUTE_PAYMENT_URL,
{ paymentID: data.paymentID, payerID: data.payerID })
.then(function(data) {
})
.catch(function(err) { console.log("error " + err);});
},
onCancel: function(data){
cancel();
this.destroy();
},
onError: function (err) {
console.log("ERROR OCCURRED!");
console.log(err);
}
}, '#paypal-button');
Not really relevant, but my backend looks like this(with testdata):
public function createPaypalOrder(Request $request, $store, $orderId){
$order = Order::with(['user', 'whitelabel'])->where('id', $orderId)->first();
$amout = array(
'value' => (string) $order->price/100,
'currency' => 'NOK',
);
$shippingandtax = array(
'value' => '0',
'currency' => 'NOK',
);
$charge_models = array([
'type'=> 'SHIPPING',
'amount'=> $shippingandtax,
],
[
'type'=> 'TAX',
'amount'=> $shippingandtax,
]);
$payment_definitions_creation = array();
array_push($payment_definitions_creation,[
'name' => 'Regular Payment Definition',
'type' => 'REGULAR',
'frequency' => 'MONTH',
'frequency_interval'=> '2',
'amount' => $amout,
'cycles' => '12',
'charge_models' => $charge_models
]);
$format = Config::get('constants.FRONTEND_URL')[env('APP_ENV')];
$redirectBase = sprintf($format, $order->whitelabel->subdomain, 'orders/?order=' . $order->id);
$merchant_preferences_temp = array(
'value' => '0',
'currency' => 'NOK'
);
$merchant_preferences = array(
"setup_fee" => $merchant_preferences_temp,
'return_url' => "http://www.vg.no",
'cancel_url' => "http://www.yahoo.no",
'auto_bill_amount' => 'YES',
'initial_fail_amount_action' => 'CONTINUE',
'max_fail_attempts' => '0'
);
$payment_definitions = array();
array_push($payment_definitions, $payment_definitions_creation);
$name = 'Monthly subscription to ' . (string)$order->whitelabel->title;
$body = array(
'name' => $name,
'description' => 'Subscribtion.',
'type' => 'fixed',
'payment_definitions' => $payment_definitions_creation,
"merchant_preferences"=> $merchant_preferences,
);
$token = $this->getPaypalToken($order);
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.sandbox.paypal.com/v1/payments/billing-plans', [
'headers' => ['Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $token],
'json' => $body,
]);
$paypalOrderCreation = json_decode($response->getBody());
// add stuff to db
$order->setTransactionId($paypalOrderCreation->id);
return json_encode($paypalOrderCreation);
}
My backend returns a valid response from paypal with the id of the order and the state "CREATED". (And lots of other data..)
{"id":"P-0SE01606VF925501Y2UAKG3Y","state":"CREATED","name":"Monthly subscription to Paypal","description":"Subscribtion.","type":"FIXED","payment_definitions":[{"id":"PD-35U317461H38251442UAKG4A","name":"Regular Payment Definition","type":"REGULAR","frequency":"Month","amount":{"currency":"NOK","value":"500"},"cycles":"12","charge_models":[{"id":"CHM-7T021625H451740052UAKG4A","type":"SHIPPING","amount":{"currency":"NOK","value":"0"}},{"id":"CHM-313690493W320615U2UAKG4A","type":"TAX","amount":{"currency":"NOK","value":"0"}}],"frequency_interval":"2"}],"merchant_preferences":{"setup_fee":{"currency":"NOK","value":"0"},"max_fail_attempts":"0","return_url":"http:\/\/www.vg.no","cancel_url":"http:\/\/www.yahoo.no","auto_bill_amount":"YES","initial_fail_amount_action":"CONTINUE"},"create_time":"2017-01-25T09:41:45.967Z","update_time":"2017-01-25T09:41:45.967Z","links":[{"href":"https:\/\/api.sandbox.paypal.com\/v1\/payments\/billing-plans\/P-0SE01606VF925501Y2UAKG3Y","rel":"self","method":"GET"}]}
Now my problem is that when my paypal.button receives this response it processes the information and redirects me to "sandbox.paypal.com/webapps/hermes/error", which is somewhat hard to debug.
Thanks :)
The problem was an internal issue at Paypal. Works now.
I have developed ajax drupal and add a form (textfield and button) in it using #ajax key and callback function where I do my process and return my form new element.
So when I starts adding my data form, it works fine for me and form_state['values'] are updated fine.
The problem here is when I reload my form and I add some data, form_state['values'] are not the same in my form fields.
Here is my code:
function my_horoscope_menu() {
$items = array();
$items['admin/horoscopes'] = array(
'title' => 'Horoscopes',
'page callback' => 'drupal_get_form',
'page arguments' => array('my_horoscope_admin_form'),
'access arguments' => array('Administer site configuration '),
//'type' => MENU_LOCAL_TASK,
);
return $items;
}
function my_horoscope_admin_form($form, &$form_state) {
$form['settings']['horoscopes']['add_horoscopes'] = array(
'#type' => 'fieldset',
'#title' => t('Add horoscopes'),
'#collapsible' => TRUE,
'#collaspsed' => TRUE,
);
$form['settings']['horoscopes']['add_horoscopes']['name'] = array(
'#type' => 'textfield',
'#title' => t('Horoscope name'),
'#default_value' => t('Horoscope name'),
'#size' => 20,
'#maxlength' => 60,
'#required' => FALSE,
);
$form['settings']['horoscopes']['add_horoscopes']['beginning_date_rang'] = array(
'#type' => 'date',
'#title' => t('Horoscope beginning date rang'),
'#description' => t('Set the beginning date rang of this horoscope.'),
'#required' => FALSE,
);
$form['settings']['horoscopes']['add_horoscopes']['ending_date_rang'] = array(
'#type' => 'date',
'#title' => t('Horoscope ending date rang'),
'#description' => t('Set the ending date rang of this horoscope.'),
'#required' => FALSE,
);
$form['settings']['horoscopes']['add_horoscopes']['add_button'] = array(
'#type' => 'button',
'#value' => t('Add this horoscope'),
'#submit' => array(''),
'#ajax' => array(
'event' => 'click',
'callback' => 'add_horoscope_ajax_process',
'wrapper' => 'add_horoscope_wrapper',
),
);
$form['settings']['horoscopes']['add_horoscopes']['adding_horoscope_wrapper'] = array(
'#type' => 'markup',
'#prefix' => '<div id="add_horoscope_wrapper">',
'#suffix' => '</div>',
);
return $form;
}
function add_horoscope_ajax_process ($form, &$form_state) {
if (isset($form_state['values'])) {
if (isset($form_state['values']['name']) AND $form_state['values']['name'] != '') {
$name = $form_state['values']['name'];
}
if (isset($form_state['values']['beginning_date_rang']) AND $form_state['values']['beginning_date_rang'] != '') {
$beginning_date_rang = $form_state['values']['beginning_date_rang'];
$beginning_date_rang1 = sprintf("%04d-%02d-%02d", $beginning_date_rang['year'], $beginning_date_rang['month'], $beginning_date_rang['day']);
}
if (isset($form_state['values']['ending_date_rang']) AND $form_state['values']['ending_date_rang'] != '') {
$ending_date_rang = $form_state['values']['ending_date_rang'];
$ending_date_rang1 = sprintf("%04d-%02d-%02d", $ending_date_rang['year'], $ending_date_rang['month'], $ending_date_rang['day']);
}
// Prepare record to add
$record = array(
'h_name' => $name,
'h_date_begin' => $beginning_date_rang1,
'h_date_end' => $ending_date_rang1,
);
// Add the record
$res = drupal_write_record('my_horoscope_structure', $record);
if($res != FALSE) {
drupal_set_message(t('Horoscope #name is inserted successfully!', array('#name' => $name)));
}
}
// return $form
return $form['settings']['horoscopes']['add_horoscopes']['adding_horoscope_wrapper'];
}
In ZF2, how do you create multiple submit buttons that each lead to different routes? In the Forms and actions chaper of the ZF2 tutorial, a form is created with a single submit button with the label “Go” that processes the input data and returns to the index page (route). Where do we put the pertinent scripts if we wanted four buttons:
Save action: saves user input, route: return to current page
Save and Close action: saves user input, route: return to index (Album)
Clear action: no action, route: return to current page
Close action: no action, route: return to index (Album)
I assume the buttons are created like this:
namespace Album\Form;
class AlbumForm extends Form
{
public function __construct($name = null)
{
// ... //
$this->add(array(
'name' => 'savebutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Save',
'id' => 'savebutton',
),
));
$this->add(array(
'name' => 'save_closebutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Save & Close',
'id' => 'save_closebutton',
),
));
$this->add(array(
'name' => 'clearbutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Clear',
'id' => 'clearbutton',
),
));
$this->add(array(
'name' => 'closebutton',
'attributes' => array(
'type' => 'submit',
'value' => 'Close',
'id' => 'closebutton',
),
));
}
}
This is what the edit action looks like with only one submit button:
// module/Album/src/Album/Controller/AlbumController.php:
//...
// Add content to this method:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album', array(
'action' => 'add'
));
}
$album = $this->getAlbumTable()->getAlbum($id);
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getAlbumTable()->saveAlbum($form->getData());
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
//...
Since pairs of buttons have the same form action and pairs of buttons have the same route, I image we want to add two if statements somewhere here, unless a switch statement is better.
Quick 'n dirty way to do what you need:
public function editAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album', array(
'action' => 'add'
));
}
$album = $this->getAlbumTable()->getAlbum($id);
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$input = $form->getData();
if (!empty($input['save_closebutton'])) {
return $this->redirect()->toRoute('album', array(
'controller' => 'AlbumController',
'action' => 'index',
));
}
}
}
return array(
'id' => $id,
'form' => $form,
);
}
i have a strange Problem with one of my Zend_Forms: isValid() correctly states that my form isn't valid but i do not get any error messages. How could that happen?
Heres the code, nothing special here. $data is an array of post data. The problem occurs when no file is sended.
$form = $this->getForm('Foto');
if(!$form->isValid($data)) {
var_dump( $form->getErrors() ); die;
return false;
}
getForm() initializes the form if not allready done. The form itself is pretty straight forward.
class Media_Forms_Foto extends Zend_Form
{
/**
* Initializer function. Setup forms fields.
*/
public function init()
{
$this->setName('add Image');
$this->setAction('media/gallery/addImage');
$this->addElement('Hidden', 'gallery', array(
'filters' => array(),
'validators' => array('Digits'),
'required' => false,
'label' => '',
));
$this->addElement('File', 'foto', array(
'required' => true,
'destination' => ROOT_PATH .'public/upload/tmp/',
'label' => 'Foto',
'validators' => array(
new Zend_Validate_File_IsImage(array(
'image/jpeg', 'image/gif', 'image/png'
))
),
'maxFileSize' => 2097152,
));
$this->addElement('Submit', 'add', array(
'required' => false,
'ignore' => true,
'label' => 'add Foto',
));
$this->setAttrib('enctype', 'multipart/form-data');
}
}
Output:
array(3) {
["gallery"]=>
array(0) {
}
["foto"]=>
array(0) {
}
["add"]=>
array(0) {
}
}
Are you using the jquery form plugin by any chance? if so, try using the iframe mode to upload files:
var options = {
url: '/test/upload',
success: function(response) {
},
beforeSubmit: disableSubmitButtons,
iframe: true,
dataType : 'json'
};
$('#testForm').ajaxForm(options);
So I have created a form below with Zend Framework which I'm then going to customise. My first issue is that with the csrf hash security I get an application error. However, when I remove them lines all I get is a blanks screen which is only resolved when I remove the CPATCHA protection. Can anyone explain to me why?
My Form:
class Application_Form_Clips extends Zend_Form
{
public function init()
{
// Set the method for the display form to POST
$this->setMethod('post');
// Add an email element
$this->addElement('text', 'email', array(
'label' => 'Your email address:',
'required' => true,
'filters' => array('StringTrim'),
'validators' => array(
'EmailAddress',
)
));
// Add the comment element
$this->addElement('textarea', 'comment', array(
'label' => 'Please Comment:',
'required' => true,
'validators' => array(
array('validator' => 'StringLength', 'options' => array(0, 20))
)
));
// Add a captcha
$this->addElement('captcha', 'captcha', array(
'label' => 'Please enter the 5 letters displayed below:',
'required' => true,
'captcha' => array(
'captcha' => 'Figlet',
'wordLen' => 5,
'timeout' => 300
)
));
// Add the submit button
$this->addElement('submit', 'submit', array(
'ignore' => true,
'label' => 'Sign Guestbook',
));
// And finally add some CSRF protection
$this->addElement('hash', 'csrf', array(
'ignore' => true,
));
}
}
My Controller:
class AdminController extends Zend_Controller_Action
{
public function init()
{
// get doctrine and the entity manager
$this->doctrine = Zend_Registry::get('doctrine');
$this->entityManager = $this->doctrine->getEntityManager();
// get the users repository
$this->indexVideos = $this->entityManager->getRepository('\ZC\Entity\Videos');
$this->indexClips = $this->entityManager->getRepository('\ZC\Entity\Clips');
}
public function indexAction()
{
// action body
}
public function clipsAction()
{
// get a form
$form = new Application_Form_Clips();
$this->view->form = $form;
}
public function videosAction()
{
// action body
}
}
My View:
<?php echo $this->form; ?>
Basic error, I hadn't uncommented session.pat in my php.ini