ProcessWire Upload Formular

Aus Wikizone
Wechseln zu: Navigation, Suche

Siehe auch[Bearbeiten]

ProcessWire Upload Formular mit AJAX
https://gist.github.com/somatonic/5233338
ProcessWire UploadFormular Dropzone Enhanced
ProcessWire - File Upload mit Blueimp jQueryFileUpload

Übersicht[Bearbeiten]

Ein einfaches Upload Formular mit dem der Benutzer Dateien übermitteln kann. Für das Formular kommen aus ProcessWire der Sanitizer, die WireUpload Klasse und Session Tokens zum Einsatz. Das Formular wird validiert. Das Markup für das Formular steht direkt im Template, wird also nicht über die Formularfunktionen von ProcessWire erzeugt. Das ist oft die schnellere Variante, vor allem wenn das Markup sehr individuell ist.

Der Code basiert auf Somatonics Beispiel (s.o.) und wurde leicht angepasst.

Features:

  • Dateiupload (Bilder)
  • Formulareingaben als Seiten speichern (inkl. Bilder)
  • Verhindert CRSF Attacken und doppelte Posts durch neu Laden
  • Formular validierung mit Inline Messages
  • Feldvariablen werden durch den Sanitizer bereinigt
  • Kleines jQuery Beispiel um den Submit Button nach Absenden zu deaktivieren.

Aufbau[Bearbeiten]

TEMPLATES
basic-upload
  FELDER: title
basic-upload-entry
  FELDER: title, fullname, email, message, newsletter_subscribe, images
SEITEN
/basic-upload/
/basic-upload/[automatisch-erzeugte-seiten]

Das Formular liegt in der Seite

/basic-upload/ 

Mit dem Template 'basic-upload' (basic-upload.php)

Beim Absenden eines gültigen Formulars werden unterhalb der Formularseite weitere Seiten generiert. Diese erhalten das Template basic-upload-entry. Wenn man die erzeugten Seiten im Frontend anzeigen möchte braucht man natürlich noch ein PHP File für basic-upload-entry. Ansonsten kann man sich die Seiten im Backend anzeigen.

Code[Bearbeiten]

templates/partials/basic-upload/form-process.php

<?php namespace ProcessWire;

// ------------------------------ 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();
						print_r($template);
						//var_dump($parent);
            $uploadpage->template = $template;
            $uploadpage->parent = $parent;

            // add title/name and make it unique with time and uniqid
            $uploadpage->title = date("Y-m-d_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();
            }
        }
    }
}


templates/basic-upload.php

<?php namespace ProcessWire;

/**
 * ### 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>";
$success = false;

// --- 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    = 2*1024*1024; // make sure PHP's upload and post max size is also set to a reasonable size
$overwrite          = false;

// --- Page creation settings ---
$template           = "basic-upload-entry"; // the template used to create the page
$parent             = $pages->get("/basic-upload/");
$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("./partials/basic-upload/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>
		<p>Creates Pages in Backend from Form including upload field.</p>
		
<?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.js (jQuery)

<!-- ========================= FORM jQuery Script  ================================== -->

<script>
    $(function(){
        // Avoid double posts by disabling submit button on form submit
        $('#myform').submit(function(){
            $("#submit").attr('disabled','disabled');
            return true;
        });

    });
</script>