Im trying to make a contact form with attachments.
Im following the great tutorial in the cookbook: Forms with attachments | Kirby CMS
But I dont want jobs or something, I only want a contact page where I can upload an attachment and send it to a configured mail address.
So here is what I did / changed:
/site/controllers/kontakt.php
<?php
return function($kirby, $page) {
if ($kirby->request()->is('POST') && get('submit')) {
// initialize variables
$alerts = null;
$attachments = [];
// check the honeypot
if (empty(get('website')) === false) {
go($page->url());
exit;
}
// get the data and validate the other form fields
$data = [
'name' => get('name'),
'email' => get('email'),
'message' => get('message')
];
$rules = [
'name' => ['required', 'min' => 3],
'email' => ['required', 'email'],
'message' => ['required', 'min' => 10, 'max' => 3000],
];
$messages = [
'name' => 'Please enter a valid name.',
'email' => 'Please enter a valid email address.',
'message' => 'Please enter a text between 10 and 3000 characters.'
];
// some of the data is invalid
if ($invalid = invalid($data, $rules, $messages)) {
$alerts = $invalid;
}
// get the uploads
$uploads = $kirby->request()->files()->get('file');
// we want no more than 3 files
if (count($uploads) > 3) {
$alerts[] = 'You may only upload up to 3 files.';
}
// 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;
}
}
// the data is fine, let's send the email with attachments
if (empty($alerts)) {
try {
$kirby->email([
'template' => 'email',
'from' => 'sprachenservice-ortwein@swelp.de',
'replyTo' => $data['email'],
'to' => 'thomas.oppolzer@swelp.de',
'subject' => esc($data['name']) . ' hat ihnen eine Nachricht gesendet.',
'data' => [
'message' => esc($data['message']),
'name' => esc($data['name']),
],
'attachments' => $attachments
]);
} catch (Exception $error) {
// we only display a general error message, for debugging use `$error->getMessage()`
$alerts[] = "The email could not be sent";
}
// no exception occurred, let's send a success message
if (empty($alerts) === true) {
// store reference and name in the session for use on the success page
$kirby->session()->set([
'name' => esc($data['name'])
]);
// redirect to the success page
go('success');
}
}
}
// return data to template
return [
'alerts' => $alerts ?? null,
'data' => $data ?? false,
];
};
there I deleted reference, because I dont need a reference for that.
after that I modified kontakt.php in site/templates/kontakt.php
<?php snippet('header') ?>
<?= css('assets/css/templates/kontakt.css') ?>
<main class="main">
<h1 class="note-header h1"><?= $page->title() ?></h1>
<?php
// if the form input does not validate, show a list of alerts
if($alerts): ?>
<div class="alert">
<ul>
<?php foreach($alerts as $message): ?>
<li><?= kirbytext($message) ?></li>
<?php endforeach ?>
</ul>
</div>
<?php endif ?>
<?php snippet('kontakt-snippet', compact('data')); ?>
</div>
</main>
<?php snippet('footer') ?>
and here the kontakt-snippet.php
<form method="post" action="<?= $page->url() ?>">
<div class="honeypot">
<label for="website">Website <abbr title="required">*</abbr></label>
<input type="url" id="website" name="website" tabindex="-1">
</div>
<div class="field">
<label for="name">
Name <abbr title="required">*</abbr>
</label>
<input type="text" id="name" name="name" value="<?= esc($data['name'] ?? '', 'attr') ?>" required>
<?= isset($alert['name']) ? '<span class="alert error">' . esc($alert['name']) . '</span>' : '' ?>
</div>
<div class="field">
<label for="email">
Email <abbr title="required">*</abbr>
</label>
<input type="email" id="email" name="email" value="<?= esc($data['email'] ?? '', 'attr') ?>" required>
<?= isset($alert['email']) ? '<span class="alert error">' . esc($alert['email']) . '</span>' : '' ?>
</div>
<div id="inputtext" class="field">
<label for="text">
Text <abbr title="required">*</abbr>
</label>
<textarea id="text" name="text" required>
<?= esc($data['text'] ?? '') ?>
</textarea>
<?= isset($alert['text']) ? '<span class="alert error">' . esc($alert['text']) . '</span>' : '' ?>
</div>
<div>
<label> </label>
<input name="file[]" type="file" multiple required>
</div>
<div>
<label> </label>
<label id="filelabel" for="file">Dateien anhängen
<span class="help">Max. 3 Dateien (max. Dateigröße 2MB pro Datei)</span>
</label>
</div>
<div class="field">
<label for="submit">
</label>
<input id="submit" type="submit" name="submit" value="Submit">
</div>
</form>
Somewhere im missing something which connects the uploaded file in the kontakt-snippet and the controller uploads array.
I tried the original jobkit, there everything is working fine.
for testing I deleted the plugin/application/index.php
and it still works fine.
in my modified email form I dont have a plugin.
then I tried it with plugin but it still errors at the same line.
TypeError
count(): Argument #1 ($value) must be of type Countable|array, null given