Multiple Forms on Single Page Hack (Signup Specific)

libsys - June 14, 2007 - 20:02
Project:Signup
Version:5.x-2.x-dev
Component:Code
Category:feature request
Priority:normal
Assigned:Unassigned
Status:active
Description

I put together quick hack to allow for multiple signup forms on a single page. I had to bypass the Forms API a bit in order to accomplish this (see http://www.gtrlabs.org/blog/dayre/drupal_5_how_to_process_multiple_insta...), but it will have to do for the moment (for me). Others seemed interested in this functionality (http://drupal.org/node/74004), so I thought I may as well post my draft in the event that it might be useful to someone else. Notice his first point under FormAPI Improvments:

It seems that this problem may be fixed in Drupal Version 6. Jeff Eaton, for example, has a nice summary of possible Forms API to-dos for v 6 here:

Right now, each form gets one _submit() callback to do its processing. This is fine for most forms, but forms with multiple buttons and multiple actions (save, delete, save-as-draft, etc) get complicated fast. All the handling has to be jammed into that one submit callback. Instead, each button should automatically get its own callback function. Chx put together a great patch for this late in the 5.0 cycle, but it didn't make it in: 6.0 needs it. '
http://jeff.viapositiva.net/node/466.

So, it could be that my hack will be made unnecessary by the next version. I'm curious though, is there any interest in patching the current version of this particular module to support multiple forms on a single page?

My use-case is that of a workshop registration system. When logged in users view our workshops listings, they also see their signup info right in the context of that page and can sign up or cancel their registration there as well.

Attached you'll find my quick and dirty hack in patch form. I'm posting the relevant bits below as well. - Please feel free to correct me or point me towards a better approach! It *seems* to work OK for me, but I'm new to the Form API so I could be missing a thing or two. Anyone making use of this patch should bear that in mind and have some coding skills of their own. You have been warned.

Finally, thank you for maintaining and developing this module. It has become a critical piece of one of my primary sites - thanks!!!

/*******************************************************************************/
//make the forms unique
/*******************************************************************************/


/**
* hook_nodeapi implementation
*
* @ingroup signup_nodeapi
*/
function signup_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {

...

//Make this form unique w/nid
$output = drupal_get_form('signup_form' . $node->nid, $node, $anon_signup_form);

...




function _signup_print_current_signup($node, $signup_info) {

/*******************************************************************************/
/Deliver the same form contents, regardless of particular form id
/*******************************************************************************/

/**
* Implementation of hook_forms().
*/
function signup_forms() {

...


if (strpos($form_id, "signup_form") === 0) {
  $forms[$form_id] = array('callback' => 'signup_form');
}
if (strpos($form_id, "signup_form_cancel") === 0) {
$who_what = array('nid'=> substr($_POST['form_id'], 18), 'uid' => $user->uid);
  $forms[$form_id] = array(
'callback' => 'signup_user_cancel_form',
     'callback arguments' => $who_what);
}

...


/*******************************************************************************/
//Work-around to call the _submit callback, regardless of form ID
/*******************************************************************************/

/**
* Implmentation of hook_menu()
* @ingroup signup_core
*/
function signup_menu($may_cache) {

...


//Work-Around for multiple forms on one page
if($_POST['op'] == 'Sign up'){
//ick, this should probably not be tied to the op name length, but will do for now
$who_what = array('nid'=> substr($_POST['form_id'], 11), 'uid' => $user->uid);
$merged = array_merge($_POST['signup_form_data'], $who_what);
signup_form_submit($form_id, $merged);
}
//Work-Around for multiple forms on one page
if($_POST['op'] == 'Cancel Signup'){
$nid = substr($_POST['form_id'], 18);
  signup_cancel_signup($user->uid, $nid, NULL);
}

...

AttachmentSize
signup_multiform.patch3.05 KB

#1

dww - June 15, 2007 - 00:06

yes, i've been thinking about adding a nice way to have a bunch of signup forms on a single page so my users can go through and reply to events in bulk. so, i'd certainly consider this if it was done right. however:

a) that's not a patch. please see http://drupal.org/patch

b) that's not secure. you're bypassing form validation by pulling stuff directly out of $_POST. :( that can lead to cross-site request forgeries at least, and potentially much worse things (i haven't audited the resulting functions that get called to see how careful they are with $nid, etc).

so, note to yourself and anyone else who sees this issue:
DON'T USE THAT CODE. ;)

when the D6 code freeze isn't hanging over my head, i'll have more time to give signup.module some lovin', and when i do, i'll try to get a secure version of this working. if you care to read up on how to really use FAPI properly in the meantime and roll a real patch, all the better.

cheers!
-derek

p.s. you might find preg_match() is a less brittle way to search for something you're looking for inside another string.

#2

libsys - June 15, 2007 - 20:32

Thanks for the heads-up on the vulnerability, rather obvious now that you mention it. I guess I was just focused on getting *something* to work right at that moment. Anyway, thanks. Perhaps there's a way to run this back through the forms API. I look forward to seeing any work that you may do in this area.

Cheers,
libsys

#3

libsys - June 26, 2007 - 21:55

Derek,

You've inspired me to finally sit down and learn the FAPI - or at least begin getting comfortable with it ;). I made some significant revisions to what I have listed above as a result. It did force me to make more small changes here and there, and you may well have other brilliant ideas as to how to better accomplish multiform signups on the whole. Perhaps what I've done here will help you in some small way as you move forward.

The attached file is another local patch and contains my latest revision. My last "patch" was done on a Solaris box that wouldn't let me issue the -p command - I got a bit lazy and left it out. Anyway, this one is by the book (diff -up original.php new.php > filename.patch).

One other thought I had regarding multiple updates on a single page would be to include the kind of functionality that we see in the views administration pages where users are taken right back to the form page locations from which they had submitted items. This wouldn’t be hard to accomplish and would be useful where pages contain many forms.

Finally, I’ll just mention that my “multiform page” is merely a view that I’ve added and set to output as a teaser list, hence my addition of the $teaser qualifier to the nodeapi view area.

Thanks again for your feedback and response; this has been a useful exercise for me. I appreciate the help!

AttachmentSize
signup_multiform_0.patch3.55 KB

#4

wedge - July 25, 2007 - 08:03

I ran into a similar problem today and this guide helped my fix it.

 
 

Drupal is a registered trademark of Dries Buytaert.