Jump to content
a-ok

Submitting form data to an 'entries' page on the CMS (without FormBuilder)

Recommended Posts

I'm a fan of FormBuilder, but it's a bit overkill for what I need to do.

I'm looking to have a simple email and password form set on a page; the password would be tied to a field in the CMS. It would just be a plain text field. Upon submission a file would automatically download (file located on the same page where the plain text password is set) and then the email address and timestamp would be sent to an entries list (similar to FormBuilder's).

My question is... how possible is this without FormBuilder? If I was to create an 'entries' list of the submitted data on a page in the CMS; what's the best field to hook into to allow for this? Repeater seems a bit over the top? PageTable? Exporting? Or would you just use the FormBuilder? Or is there a way to have a custom form but send the data to a form within FormBuilder?

Any advice would be great.

Share this post


Link to post
Share on other sites

I have built little forms like this manually a couple of times! It's definitely fun, though building complex forms is a lot more work than one might think, but for small forms you'll be fine.

Quote

My question is... how possible is this without FormBuilder?

No problem at all - you just need to handle the things that FormBuilder will do. In your example, most notably:

  • Write the HTML for the form. You can try to dynamically generate this, but building exhaustive options for form fields is much work, so for a simple form static HTML will be fine.
  • Handle the result. I'd do that within the template file of the template where your form is output. For a normal form you'd need some form of Spam protection, CSRF protection and other stuff but since in your case you require a password that won't be necessary, since you can just throw out submission that don't match the password.
  • Store the submission, more on that below.
  • Submit the file. For a simple solution, you can just redirect to the URL of the file. I have built something where I wanted to make sure the file can ONLY be accessed through the form. For this, you can put your file in a safe location (outside your webroot) and stream it through PHP once you have checked if the password is correct. Make sure to output the correct header to instruct the browser to start a download. Quick and dirty, based on the readfile documentation:
if ($input->post('password_field') === $page->my_secret_password) {
	$file = '/path/to/file.pdf';
	header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
    header('Content-Length: ' . filesize($file));
    header('Cache-Control: private');
    readfile($file);
    exit;
}
Quote

If I was to create an 'entries' list of the submitted data on a page in the CMS; what's the best field to hook into to allow for this? Repeater seems a bit over the top? PageTable?

Honestly, don't overthink this bit. Unless you are expecting thousands of request an hour, you don't need to optimise it. Depending on what you plan to do with this data I might go with a ProFields Table field or a regular template. Those are nice because all content is stored in a single, simple table. This gives you a bit more room to optimise if and when you need to. But if you are really getting so many requests that the server can't handle them, you will probably yield more improvements by building a seperate endpoint that doesn't load ProcessWire at all and instead writes to the database directly. This will be a bit easier with a ProFields Table field, though it really doesn't matter that much.

If you are using a ProFields Table, make sure you are not loading the field on your form page, because that will load ALL it's data, that might in fact get out of hand quickly if you have lots of submissions.

  • Like 5

Share this post


Link to post
Share on other sites

@MoritzLost Thank you! I really appreciate your help and advice here. This all sounds good. I'll begin!

  • Like 1

Share this post


Link to post
Share on other sites

I'm looking to try to use the Processwire API to download the file:

$pressDownload = $pages->get(1078)->pressDownload->filename();
wireSendFile($pressDownload, array('forceDownload' => true, 'exit' => false));

Is this possible or do I need to use the PHP method as demonstrated by @MoritzLost?

Share this post


Link to post
Share on other sites

@a-ok I didn't know that method existed, look like it does pretty much the same as my example code above, so absolutely yes, use it! I would only change the default headers: Since your file is password-protected, you want to set 'Cache-Control: no-store' (or private) so it can't be cached on the network / CDN layer. The method also sets 'Pragma: public' by default, so this should be changed to 'Pragma: no-store' as well (or better yet, removed entirely).

Share this post


Link to post
Share on other sites
23 minutes ago, MoritzLost said:

@a-ok I didn't know that method existed, look like it does pretty much the same as my example code above, so absolutely yes, use it! I would only change the default headers: Since your file is password-protected, you want to set 'Cache-Control: no-store' (or private) so it can't be cached on the network / CDN layer. The method also sets 'Pragma: public' by default, so this should be changed to 'Pragma: no-store' as well (or better yet, removed entirely).

Thanks 🙂 I'm trying to use it but getting some odd errors/returns. Been testing it directly in TracyDebugger's console and it doesn't download anything. Code has been failing for me all over the place today though; lockdown meltdown.

1463369429_Screenshot2020-04-01at16_19_32.thumb.jpg.3156ef9e54c3e02edefa11c145d32ff5.jpg

Share this post


Link to post
Share on other sites

It works perfectly fine if you just put the code inside a template. I guess using such functions as wireSendFile() inside Tracy aren't meant to work exactly the same (or not at all) as when you are viewing a PW page in the frontend. (I used an image file for testing instead of PDF, but that doesn't matter)

Share this post


Link to post
Share on other sites
13 minutes ago, dragan said:

It works perfectly fine if you just put the code inside a template. I guess using such functions as wireSendFile() inside Tracy aren't meant to work exactly the same (or not at all) as when you are viewing a PW page in the frontend. (I used an image file for testing instead of PDF, but that doesn't matter)

I did think this. Need to try again shortly. I’m basically posting form data to a page /ajax/ which is returning wireSendFile() if it meets the right requirements. Would it work in this respect? I’m assuming so?

Share this post


Link to post
Share on other sites
46 minutes ago, a-ok said:

I did think this. Need to try again shortly. I’m basically posting form data to a page /ajax/ which is returning wireSendFile() if it meets the right requirements. Would it work in this respect? I’m assuming so?

Probably not. If you look at the source code of WireHttp::send (wireSendFile is basically an alias for this), it sends the file by sending the correct HTTP headers for file transfers (Content-Disposition: attachment) and then streaming the raw binary data. JavaScript can trigger downloads but it's a bit more involved and doesn't work in all browsers. It will be way easier to use a normal form submission without AJAX, then it should work as intended.

Share this post


Link to post
Share on other sites
1 hour ago, MoritzLost said:

Probably not. If you look at the source code of WireHttp::send (wireSendFile is basically an alias for this), it sends the file by sending the correct HTTP headers for file transfers (Content-Disposition: attachment) and then streaming the raw binary data. JavaScript can trigger downloads but it's a bit more involved and doesn't work in all browsers. It will be way easier to use a normal form submission without AJAX, then it should work as intended.

Ah okay. In my /ajax/ I am doing some server side stuff (adding the form data to a ProTable as we discussed) so this is why I was initially confused.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...