Skip to content

Instantly share code, notes, and snippets.

@somatonic
Last active May 24, 2023 18:26
Show Gist options
  • Save somatonic/5233338 to your computer and use it in GitHub Desktop.
Save somatonic/5233338 to your computer and use it in GitHub Desktop.
ProcessWire example front-end form with file upload and fields
<?php
// ------------------------------ FORM Processing ---------------------------------------
$errors = null;
$success = false;
// helper function to format form errors
function showError($e){
return "<p class='error'>$e</p>";
}
// dump some variables
// var_dump($_FILES,$_POST,$_SESSION);
/**
* Cast and save field values in array $form_fields
* this is also done even form not submited to make populating the form later easier.
*
* Also used for pupulating page when form was valid
*/
$required_fields = array();
foreach($form_fields as $key => $f){
if($f['type'] == 'text'){
$form_fields[$key]['value'] = $sanitizer->text($input->post->$key);
}
if($f['type'] == 'textarea'){
$form_fields[$key]['value'] = $sanitizer->textarea($input->post->$key);
}
if($f['type'] == 'email'){
$form_fields[$key]['value'] = $sanitizer->email($input->post->$key);
}
if($f['type'] == 'checkbox'){
$form_fields[$key]['value'] = isset($input->post->$key) ? 1 : 0;
}
// store required fields in array
if($f['required']) $required_fields[] = $key;
}
/**
* form was submitted, start processing the form
*/
if($input->post->action == 'send'){
// validate CSRF token first to check if it's a valid request
if(!$session->CSRF->hasValidToken()){
$errors['csrf'] = "Form submit was not valid, please try again.";
}
/**
* Ceck for required fields and make sure they have a value
*/
foreach($required_fields as $req){
// required upload file field
if($form_fields[$req]['type'] == 'file'){
if(empty($_FILES[$req]['name'][0])){
$errors[$req] = "Select files to upload.";
}
// reqired checkbox fields
} else if($form_fields[$req]['type'] == 'checkbox'){
if($form_fields[$req]['value'] == 0){
$errors[$req] = "Field required";
}
// reqired text fields
} else if($form_fields[$req]['type'] == 'text'
|| $form_fields[$req]['type'] == 'textarea'
|| $form_fields[$req]['type'] == 'email'){
if(!strlen($form_fields[$req]['value'])){
$errors[$req] = "Field required";
}
// reqired email fields
if($form_fields[$req]['type'] == 'email'){
if($form_fields[$req]['value'] != $input->post->$req){
$errors[$req] = "Please enter a valid Email address.";
}
}
}
}
/**
* if no required errors found yet continue file upload form processing
*/
if(empty($errors)) {
// RC: create temp path if it isn't there already
if(!is_dir($upload_path)) {
if(!wireMkdir($upload_path)) throw new WireException("No upload path!");
}
// setup new wire upload
$u = new WireUpload($file_field);
$u->setMaxFiles($max_files);
$u->setMaxFileSize($max_upload_size);
$u->setOverwrite($overwrite);
$u->setDestinationPath($upload_path);
$u->setValidExtensions($file_extensions);
// start the upload of the files
$files = $u->execute();
// if no errors when uploading files
if(!$u->getErrors()){
// create the new page to add field values and uploaded images
$uploadpage = new Page();
$uploadpage->template = $template;
$uploadpage->parent = $parent;
// add title/name and make it unique with time and uniqid
$uploadpage->title = date("d-m-Y H:i:s") . " - " . uniqid();
// populate page fields with values using $page_fields array
foreach($page_fields as $pf){
if($templates->get($template)->hasField($pf)){
$uploadpage->$pf = $form_fields[$pf]['value'];
} else {
throw new WireException("Template '$template' has no field: $pf");
}
}
// RC: for safety, only add user uploaded files to an unpublished page, for later approval
// RC: also ensure that using v2.3+, and $config->pagefileSecure=true; in your /site/config.php
$uploadpage->addStatus(Page::statusUnpublished);
$uploadpage->save();
// Now page is created we can add images upload to the page file field
foreach($files as $filename) {
$uploadpage->$file_field = $upload_path . $filename;
// remove tmp file uploaded
unlink($upload_path . $filename);
}
$uploadpage->save();
// $success_message .= "<p>Page created: <a href='$uploadpage->url'>$uploadpage->title</a></p>";
$success = true;
// reset the token so no double posts happen
// also prevent submit button to from double clicking is a good pratice
$session->CSRF->resetToken();
} else {
// errors found
$success = false;
// remove files uploaded
foreach($files as $filename) unlink($upload_path . $filename);
// get the errors
if(count($u->getErrors()) > 1){ // if multiple error
foreach($u->getErrors() as $e) {
$errors[$file_field][] = $e;
}
} else { // if single error
$errors[$file_field] = $u->getErrors();
}
}
}
}
<?php
/**
* ### Example front-end form template with file upload and fields ###
*
* - with files (images) upload to page field
* - adds new page on the fly and adds uploaded images
* - prevents CRSF attacks, this also prevents double post by refresh page after submit
* - has required fields with error messages inline
* - sanitizing and saving values to a page
* - jquery example with disabled submit button on form submit
*
* Edit add or remove form markup below and configure this section according to what you need.
*
*/
// ------------------------------ FORM Configuration ---------------------------------------
// --- Some default variables ---
$success_message = "<p class='message'>Thanks for your message!</p>";
// --- All form fields as nested array ---
// using html form field name => template field nam, from the page you're going to create
$form_fields = array(
'fullname' => array('type' => 'text', 'value' => '', 'required' => true),
'email' => array('type' => 'email', 'value' => '', 'required' => true),
'message' => array('type' => 'textarea', 'value' => '', 'required' => true),
'newsletter_subscribe' => array('type' => 'checkbox', 'value' => 0, 'required' => false),
'images' => array('type' => 'file', 'required' => true)
);
// --- WireUpload settings ---
$upload_path = $config->paths->assets . "files/.tmp_uploads/"; // tmp upload folder
$file_extensions = array('jpg', 'jpeg', 'gif', 'png');
$max_files = 3;
$max_upload_size = 1*1024*1024; // make sure PHP's upload and post max size is also set to a reasonable size
$overwrite = false;
// --- Page creation settings ---
$template = "upload-entry"; // the template used to create the page
$parent = $pages->get("/uploads/");
$file_field = "images";
$page_fields = array('fullname','email','message','newsletter_subscribe');
// $page_fields = define the fields (except file) you want to save value to a page
// this is for the form process to populate page fields.
// Your page template must have the same field names existent
// ------------------------------ FORM Processing ---------------------------------------
include("./form-process.php");
?>
<!-- ========================= FORM HTML markup ================================== -->
<?php
/**
* Some vars used on the form markup for error and population of fields
*
* $errors[fieldname]; to get errors
* $form_fields[fieldname]['value'];
*
* Some helper function to get error markup
* echo showError(string);
*
* Prevent CSRF attacks by adding hidden field with name and value
* you an get by using $session->CSRF
* $session->CSRF->getTokenName();
* $session->CSRF->getTokenValue();
*
* $errors['csrf']; used to check for CSRF error
*
*/
?>
<div class="content">
<h2>Upload Images to Page Example Form</h2>
<?php if(!$success) : ?>
<?php if(!empty($errors)) echo showError("Form contains errors"); ?>
<?php if(!empty($errors['csrf'])) echo showError($errors['csrf']); ?>
<form name="myform" class="myform" id="myform" method="post" action="./" enctype="multipart/form-data">
<input type="hidden" name="<?php echo $session->CSRF->getTokenName(); ?>" value="<?php echo $session->CSRF->getTokenValue(); ?>"/>
<div class="row <?php if(isset($errors['fullname'])) echo "error";?>">
<label for="fullname">Name* </label><br/>
<input type="text" name="fullname" id="fullname" value="<?php echo $sanitizer->entities($form_fields['fullname']['value']); ?>"/>
<?php if(isset($errors['fullname'])) echo showError($errors['fullname']); ?>
</div>
<div class="row <?php if(isset($errors['email'])) echo "error";?>">
<label for="email">Email* </label><br/>
<input type="text" name="email" id="email" value="<?php echo $sanitizer->entities($form_fields['email']['value']); ?>"/>
<?php if(isset($errors['email'])) echo showError($errors['email']); ?>
</div>
<div class="row <?php if(isset($errors['message'])) echo "error";?>">
<label for="message">Message* </label><br/>
<textarea type="text" name="message" id="message"><?php echo $sanitizer->entities($form_fields['message']['value']); ?></textarea>
<?php if(isset($errors['message'])) echo showError($errors['message']); ?>
</div>
<div class="row <?php if(isset($errors['newsletter_subscribe'])) echo "error";?>">
<label for="newsletter_subscribe">Newsletter* </label><br/>
<input type="checkbox" name="newsletter_subscribe" id="newsletter_subscribe"
<?php echo $form_fields['newsletter_subscribe']['value'] ? "checked='checked'" : "" ; ?>
/>
<?php if(isset($errors['newsletter_subscribe'])) echo showError($errors['newsletter_subscribe']); ?>
</div>
<div class="row <?php if(isset($errors['images'])) echo "error";?>">
<label for="images">Images* </label><br/>
<input type="file" name="images[]" id="images" multiple="multiple" size="40" accept="image/jpg,image/jpeg,image/gif,image/png"/>
<?php
// show upload errors
if(isset($errors['images'])){
// if multiple errors
if(is_array($errors['images'])){
foreach($errors['images'] as $e){
echo showError($e);
}
} else { // if single error
echo showError($errors['images']);
}
}
?>
</div>
<div class="row">
<input type="hidden" name="action" id="action" value="send"/>
<input type="submit" name="submit" id="submit" value="Submit"/>
</div>
</form>
<?php else: ?>
<p><?php echo $success_message; ?></p>
<?php endif; ?>
</div>
<!-- ========================= FORM Styling ================================== -->
<style>
/* basic CSS styling */
.content { width: 30em; margin: 0 auto ;}
.error { color: red;}
.myform { padding: 1.618em 0; margin: 0 0 1em 0; border: 1px solid #bbb;}
.myform p.error { margin: 0.5em 0; border: 1px solid red; padding: 2px 5px;}
.myform .row { padding: 1.618em 0 0; margin: 0 1.618em 1.618em; border-top: 1px solid #aaa; }
.myform input[type="text"] { padding: 0.8em; background-color: #eee; border: none; width: 100%; }
.myform textarea { padding: 0.8em; background-color: #eee; border: none; width: 100%; }
</style>
<!-- ========================= FORM jQuery Script ================================== -->
<script src="<?php echo $config->urls->templates . "scripts/jquery-1.7.1.min.js"; ?>"></script>
<script>
$(function(){
// Avoid double posts by disabling submit button on form submit
$('#myform').submit(function(){
$("#submit").attr('disabled','disabled');
return true;
});
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment