New Form with attachments validation

Hello, i’m trying to use the new Form class, but i am stuck on the attachment validation, i don’t know how to replicate the one that is explained in the cookbook for previous method.

// Initialize the form with defined fields
$form = new Form(
    fields: [
        'name' => [
            'label'     => 'Name',
            'placeholder'     => 'Name',
            'type'      => 'text',
            'required'  => true,
            'minlength' => 2,
        ],
        'email' => [
            'label'     => 'Email address',
            'placeholder'     => 'Email address',
            'type'      => 'email',
            'required'  => true,
        ],
        'file' => [
            'label'     => 'Upload your CV',
            'help'      => '(max size: 20 MB)',
            'type'      => 'files',
            'required'  => true,
            'multiple'  => false,
        ],
    ]
);

Printing $form->toFormValues() show me that file is an array, with the uploaded file name inside of it, but i don’t know how to access it to validate its size.

I’d be grateful if anyone has thoughts on this issue. Thanks for your time!

The cookbook article you link isn’t using the Form class, so not sure how you ended there. I don’t think the files field in the form class will let you validate file size as the field itself only stores the name of the files and things like required, min, max.

The cookbook article you link isn’t using the Form class, so not sure how you ended there

I understand that, but the resource linked is the only one that explains how to handle file attachments with forms and their validation. What I’d like is to achieve the same file validation shown in the cookbook, but using the new Form class.

I don’t think the files field in the form class will let you validate file size as the field itself only stores the name of the files and things like required, min, max.

So, is there no way to validate file uploads with the new Form class in the same way it’s shown in the cookbook example?

        // get the uploads
        $uploads = $kirby->request()->files()->get('file');

        // loop through uploads and check if they are valid
        foreach ($uploads as $upload) {
            // make sure the user uploads at least one file
            if ($upload['error'] === 4) {
                $alerts[] = 'You have to attach at least one file';
            //  make sure there are no other errors
            } elseif ($upload['error'] !== 0) {
                $alerts[] = 'The file could not be uploaded';
            // make sure the file is not larger than 2MB…
            } elseif ($upload['size'] > 2000000)  {
                $alerts[] = $upload['name'] . ' is larger than 2 MB';
            // …and the file is a PDF
            } elseif ($upload['type'] !== 'application/pdf') {
                $alerts[] = $upload['name'] . ' is not a PDF';
            // all valid, try to rename the temporary file
            } else {
                $name     = $upload['tmp_name'];
                $tmpName  = pathinfo($name);
                // sanitize the original filename
                $filename = $tmpName['dirname']. '/'. F::safeName($upload['name']);

                if (rename($upload['tmp_name'], $filename)) {
                    $name = $filename;
                }
                // add the files to the attachments array
                $attachments[] = $name;
            }
        }
  1. The Form class is not new
  2. The Form class doesn’t handle uploads and their validation, it only validates field values.

@texnixe I think that impression comes from the v5 release page where we announced that we refactored the Form class a lot.

@giorgiodare The files field deals with already uploaded files and in that case also really file objects in the Kirby sense (not any front-end uploaded file). In the Panel, we use the Kirby\Api\Upload class to handle the file upload and related validations: kirby/src/Api/Upload.php at main · getkirby/kirby · GitHub

But also here keep in mind that this is designed to handle uploads that get turned into Kirby file objects with file blueprints etc. - this probably currently then still has limitations to re-use it for your frontend form.

@giorgiodare You can do this in the front end with JavaScript BEFORE anything has been transferred. Try out this simple example:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Contact Form with File Upload</title>
  <style>
    #file-message {
      margin-top: 5px;
      font-size: 0.9em;
    }
    .error {
      color: red;
    }
    .ok {
      color: green;
    }
  </style>
</head>
<body>

  <form id="contact-form" method="post" enctype="multipart/form-data">
    <label for="file">Upload file (max. 2 MB):</label><br>
    <input type="file" id="file" name="file"><br>
    <div id="file-message"></div><br>
    <button type="submit">Submit</button>
  </form>

  <script>
    const fileInput = document.getElementById('file');
    const message = document.getElementById('file-message');
    const maxSize = 2 * 1024 * 1024; // 2 MB

    fileInput.addEventListener('change', function () {
      message.textContent = "";

      if (fileInput.files.length > 0) {
        const file = fileInput.files[0];
        if (file.size > maxSize) {
          message.textContent = "The file is too large. Maximum allowed size is 2 MB.";
          message.className = "error";
          fileInput.value = "";
        } else {
          message.textContent = "The file is valid and ready to upload.";
          message.className = "ok";
        }
      }
    });
  </script>

</body>
</html>

While using JavaScript in the frontend has advantages like immediate reaction without backend calls, it should always only be a first step, and final validation be done in the backend.

@texnixe I agree with you. What solution do you suggest for server-side verification without having to upload 100 MB in advance, for example?

Exactly, I was under the impression that there would be a replacement on the best practices about forms.

Yeah now i understand, I’ll return to use the logic from the cookbook for more complex forms!

A combination of HTML attributes (accept param), JS and backend validation.