Uniform + phpmailer with file attachment

I have a uniform with phpmailer and file attachment.

Problems:

  1. It is working when i fill all inputs and push submit but the file in the mail is not the file i attached (even the success message appears)
  2. If i push the submit button without filling the inputs no error message appears. Why?

Last but not least my code:

phpmailer-driver.php

<?php
use PHPMailer\PHPMailer\PHPMailer;

email::$services['phpmailer'] = function($email) {
    require_once(__DIR__ . DS . 'PHPMailer.php');

    $mail = new PHPMailer();

    $mail->CharSet = 'UTF-8';
    $mail->setFrom($email->from);
    $mail->addReplyTo($email->replyTo);
    $mail->addAddress($email->to);

    if (array_key_exists('attachment', $email->options)) {
       $mail->addAttachment($email->options['attachment']['tmp_name'], $email->options['attachment']['file']);
    }

    $mail->addAttachment($_FILES['filefield']['tmp_name'], $_FILES['filefield']['file']);

    $mail->isHTML(true);
    $mail->Subject = $email->subject;
    $mail->Body = $email->body;

    if (!$mail->send()) {
        throw new Error('PHPMailer error: ' . $mail->ErrorInfo);
    }
}
?>

request.php template

<div class="wrap">
  <form method="post" action="<?= $page->url() . "/v:" . array_slice(explode('/', $job->uri()), -1)[0]; ?>" class="request" enctype="multipart/form-data">

    <input id="name" name="name" type="text" value="<?php echo $form->old('name') ?>" class="input" placeholder="Name">
    <input<?php if ($form->error('email')): ?> class="error"<?php endif; ?> name="email" type="email" value="<?php echo $form->old('email'); ?>"class="input" placeholder="E-Mail">
    <textarea<?php if ($form->error('message')): ?> class="error"<?php endif; ?> name="message" class="input" placeholder="Nachricht"><?php echo $form->old('message') ?></textarea>
    <input type="file" id="file" name="filefield" class="upload" required />
    <label for="file" class="input">Datei auswählen</label>
    <p aria-hidden="true" class="visually-hidden" id="pot">
      <?php echo csrf_field() ?>
      <?php echo honeypot_field() ?>
    </p>
    <input type="submit" value="Absenden" class="button button-big button-default" />
    <?php if ($form->success()): ?>
       <p class="success">Danke für deine Bewerbung!<br/>
       Wir werden uns umgehend bei dir melden.</p>
    <?php else: ?>
      <?php snippet('uniform/errors', ['form' => $form]) ?>
    <?php endif; ?>
  </form>
</div>

request.php controller

<?php

use Uniform\Form;

return function ($site, $pages, $page) {

    if (param('v') != null) {
        $jobUri  = param('v');
        $job = $pages->find("career/jobs/" . $jobUri);
    } else {
        // no job passed via URL -> run your exception code here
    }

    $form = new Form([
        'email' => [
            'rules' => ['required', 'email'],
            'message' => 'E-Mail scheint ungültig zu sein.',
        ],
        'name' => [],
        'message' => [
            'rules' => ['required'],
            'message' => 'Nachricht fehlt.',
        ],
        'filefield' => [
            'rules' => [
                'required',
                'file',
                'mime' => ['application/pdf'],
                'filesize' => 6000,
            ],
            'message' => [
                'Please choose a file.',
                'Please choose a file.',
                'Please choose a PDF.',
                'Please choose a file that is smaller than 5 MB.',
            ],
        ],
    ]);

    if (r::is('POST')) {
        $to = $site->apply();

        $form->emailAction([
            'to' => $to,
            'from' => $to,
            'subject' => 'Bewerbung von {name}',
            'service' => 'phpmailer',
            'service-options' => [
                 'attachment' => $_FILES['filefield'],
           ],
        ]);
    }

    return compact('form', 'job');
};

Maybe someone can help me.

EDIT
This is how the mail body looks. On the picture you can see the actual file name and the attached one.

mail-body

No ideas what the problem is?

Sorry for the cross post. But i am desperated …

Any help?

I’m a bit surprised you don’t get any errors. Your driver is not quite correct, I think. Try this:

<?php
use PHPMailer\PHPMailer\PHPMailer;

email::$services['phpmailer'] = function($email) {
    require_once(__DIR__ . DS . 'PHPMailer.php');

    $mail = new PHPMailer();

    $mail->CharSet = 'UTF-8';
    $mail->setFrom($email->from);
    $mail->addReplyTo($email->replyTo);
    $mail->addAddress($email->to);
    if (array_key_exists('attachment', $email->options)) {
       $mail->addAttachment($email->options['attachment']['tmp_name'], $email->options['attachment']['name']);
    }


    $mail->isHTML(true);
    $mail->Subject = $email->subject;
    $mail->Body = $email->body;

    if (!$mail->send()) {
        throw new Error('PHPMailer error: ' . $mail->ErrorInfo);
    }
};

Now the attachment is right. Thanks!

If I do not enter anything still comes no error message … but if I fill all fields and submit the form the success message appears correctly.

Do the snippets exist in the uniform/snippetsfolder?

Yes, there is an snippet named errors.php.

You could try to put the snippet into the site/snippetsfolder, and then call it without the uniform path.

On top of that, to increase usability, I’d add the required attribute to the input fields as well where. applicable, to let HTML do its job before the server kicks in.

Maybe i found the issue. When i choose a file and submit the form, the error message appears as defined in my controller. Why the error message is only shown when the filefield is filled?

Did you mean to add the required attribute to the inputs in my html?

Yes, you have only added it to the. file field, not the other inputs. But for testing the error messages, better leave the required attribute away until everything works as expected.

Hm, don’t know.

What. browser are you using, still wondering why you can send the form at all if the required file field is not. filled. in.

I am using Google Chrome (Version 68) on Mac.

Since you have a required attribute on the file input field, Chrome should actually prevent sending of the form if there is no file?

Yeah, it shows an popup.

I delete the required attribute on all inputs and it seems to work now :beers: It looks like my code and the required attribute got a conflict.

Another question: How i can change the body of the mail? For now it isn’t pretty.

You can use a custom snippet for the body, it should be described in the Uniform readme, check out the snippet option on this page: https://kirby-uniform.readthedocs.io/en/kirby-2/actions/email/

You can either use the alternative provided by the plugin (email-table.php), or create your own.

Thank you very much!