$id,
'label' => $id === 'contact' ? 'Kontaktformular' : ucfirst(str_replace('-', ' ', $id)),
'description' => '',
'enabled' => true,
'submit' => [
'store' => true,
'email' => true,
'subject' => '{form}: {name}',
'successText' => 'Vielen Dank für deine Nachricht.',
],
'fields' => [
['key' => 'name', 'type' => 'text', 'label' => 'Name', 'required' => true, 'width' => 6],
['key' => 'email', 'type' => 'email', 'label' => 'E-Mail', 'required' => true, 'width' => 6],
['key' => 'phone', 'type' => 'tel', 'label' => 'Telefon', 'required' => false, 'width' => 12],
['key' => 'message', 'type' => 'textarea', 'label' => 'Nachricht', 'required' => true, 'width' => 12],
],
];
}
function raijuFormNormalizeField(array $field, int $index = 0): array
{
$allowedTypes = ['text', 'email', 'tel', 'textarea', 'select', 'radio', 'checkbox', 'date', 'time', 'hidden', 'heading', 'note'];
$key = preg_replace('/[^a-zA-Z0-9_-]+/', '_', (string)($field['key'] ?? 'field_' . ($index + 1)));
$key = trim((string)$key, '_-') ?: 'field_' . ($index + 1);
$type = in_array(($field['type'] ?? 'text'), $allowedTypes, true) ? $field['type'] : 'text';
$width = (int)($field['width'] ?? 12);
if (!in_array($width, [3, 4, 6, 8, 12], true)) {
$width = 12;
}
$options = [];
if (is_array($field['options'] ?? null)) {
foreach ($field['options'] as $option) {
if (is_array($option)) {
$value = (string)($option['value'] ?? $option['label'] ?? '');
$label = (string)($option['label'] ?? $value);
} else {
$value = (string)$option;
$label = (string)$option;
}
if ($value !== '' || $label !== '') {
$options[] = ['value' => $value, 'label' => $label];
}
}
}
return [
'key' => $key,
'type' => $type,
'label' => (string)($field['label'] ?? $key),
'placeholder' => (string)($field['placeholder'] ?? ''),
'help' => (string)($field['help'] ?? ''),
'required' => !empty($field['required']),
'width' => $width,
'options' => $options,
'value' => (string)($field['value'] ?? ''),
];
}
function raijuFormNormalize(array $form, string $fallbackId = 'form'): array
{
$id = raijuFormIdClean((string)($form['id'] ?? $fallbackId));
$normalized = [
'id' => $id,
'label' => trim((string)($form['label'] ?? '')) ?: ucfirst(str_replace('-', ' ', $id)),
'description' => (string)($form['description'] ?? ''),
'enabled' => !array_key_exists('enabled', $form) || !empty($form['enabled']),
'submit' => array_replace([
'store' => true,
'email' => true,
'subject' => '{form}: {name}',
'successText' => 'Vielen Dank für deine Nachricht.',
], is_array($form['submit'] ?? null) ? $form['submit'] : []),
'fields' => [],
];
foreach (($form['fields'] ?? []) as $index => $field) {
if (is_array($field)) {
$normalized['fields'][] = raijuFormNormalizeField($field, (int)$index);
}
}
if (!$normalized['fields']) {
$normalized['fields'] = raijuFormDefaultDefinition($id)['fields'];
}
return $normalized;
}
function raijuFormExists(string $id): bool
{
return is_file(raijuFormPath($id));
}
function raijuFormLoad(string $id): ?array
{
$path = raijuFormPath($id);
if (!is_file($path)) {
return null;
}
return raijuFormNormalize(raijuFormsReadJson($path), $id);
}
function raijuFormSave(array $form): array
{
$normalized = raijuFormNormalize($form, (string)($form['id'] ?? 'form'));
raijuFormsEnsureDir();
raijuFormsWriteJson(raijuFormPath($normalized['id']), $normalized);
return $normalized;
}
function raijuFormsList(): array
{
raijuFormsEnsureDir();
$forms = [];
foreach (glob(RAIJU_FORMS_DIR . '/*.json') ?: [] as $file) {
$form = raijuFormNormalize(raijuFormsReadJson($file), pathinfo($file, PATHINFO_FILENAME));
$forms[] = [
'id' => $form['id'],
'label' => $form['label'],
'description' => $form['description'],
'enabled' => $form['enabled'],
'store' => !empty($form['submit']['store']),
'fieldCount' => count($form['fields']),
];
}
usort($forms, fn($a, $b) => strcasecmp((string)$a['label'], (string)$b['label']));
return $forms;
}
function raijuFormEscape(string $value): string
{
return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}
function raijuFormRenderField(array $field, string $formId): string
{
$key = (string)$field['key'];
$id = 'raiju-form-' . $formId . '-' . $key;
$label = raijuFormEscape((string)$field['label']);
$required = !empty($field['required']);
$requiredAttr = $required ? ' required' : '';
$requiredMark = $required ? ' *' : '';
$placeholder = raijuFormEscape((string)($field['placeholder'] ?? ''));
$width = (int)($field['width'] ?? 12);
$type = (string)($field['type'] ?? 'text');
$help = trim((string)($field['help'] ?? ''));
if ($type === 'hidden') {
return '';
}
if ($type === 'heading') {
return '
' . $label . '
';
}
if ($type === 'note') {
return '';
}
$html = '';
return $html;
}
function raijuFormRender(string $formId, array $options = []): string
{
$form = raijuFormLoad($formId);
if (!$form || empty($form['enabled'])) {
return '';
}
$basePath = raijuSafeFormBasePath((string)($options['basePath'] ?? ($GLOBALS['basePath'] ?? '')));
$lang = (string)($options['lang'] ?? ($GLOBALS['currentLang'] ?? 'en'));
$lazy = array_key_exists('lazy', $options) ? !empty($options['lazy']) : true;
if ($lazy && !raijuIsLazyFormRender()) {
return raijuLazyFormPlaceholder($form['id'], [
'basePath' => $basePath,
'params' => [
'lang' => $lang,
'basePath' => $basePath,
],
]);
}
$html = '';
return $html;
}
function raijuForm(string $formId, array $options = []): string
{
return raijuFormRender($formId, $options);
}
function raijuFormSubmittedValue(array $field): string
{
$key = (string)$field['key'];
if (($field['type'] ?? '') === 'checkbox') {
return !empty($_POST[$key]) ? '1' : '';
}
$value = $_POST[$key] ?? '';
if (is_array($value)) {
$value = implode(', ', array_map('strval', $value));
}
return trim((string)$value);
}
function raijuFormValidateSubmission(array $form, string $lang = 'en'): array
{
$errors = [];
$values = [];
foreach ($form['fields'] as $field) {
$type = (string)($field['type'] ?? 'text');
if (in_array($type, ['heading', 'note', 'hidden'], true)) {
continue;
}
$value = raijuFormSubmittedValue($field);
$values[$field['key']] = $value;
if (!empty($field['required']) && $value === '') {
$errors[] = ($field['label'] ?? $field['key']) . ($lang === 'de' ? ' ist erforderlich' : ' is required');
continue;
}
if ($type === 'email' && $value !== '' && !filter_var($value, FILTER_VALIDATE_EMAIL)) {
$errors[] = $lang === 'de' ? 'Gültige E-Mail ist erforderlich' : 'Valid email is required';
}
}
return [$errors, $values];
}
function raijuFormsApplySubjectTemplate(string $template, array $form, array $values): string
{
$subject = $template ?: '{form}';
$replacements = [
'{form}' => (string)$form['label'],
'{name}' => (string)($values['name'] ?? ''),
'{email}' => (string)($values['email'] ?? ''),
];
return trim(strtr($subject, $replacements)) ?: (string)$form['label'];
}
function raijuFormsSaveSubmission(array $submission): bool
{
return raijuJsonUpdate(RAIJU_MAILS_PATH, function (array &$mails) use ($submission): void {
array_unshift($mails, $submission);
$mails = array_slice($mails, 0, 500);
});
}
function raijuFormsLoadEmailSettings(): array
{
$settingsPath = dirname(__DIR__) . '/content/settings.json';
$settings = raijuFormsReadJson($settingsPath);
return is_array($settings['email'] ?? null) ? $settings['email'] : [];
}
function raijuFormsParseEmailList($value): array
{
$items = is_array($value) ? $value : explode(',', (string)$value);
$emails = [];
foreach ($items as $item) {
foreach (explode(',', (string)$item) as $email) {
$email = trim(str_replace(["\r", "\n", "\t"], '', (string)$email));
if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL)) {
$emails[] = $email;
}
}
}
return array_values(array_unique($emails));
}
function raijuFormsSendNotification(array $form, array $values, string $subject, string $body): bool
{
$emailConfig = raijuFormsLoadEmailSettings();
$method = $emailConfig['method'] ?? 'inactive';
$toRecipients = raijuFormsParseEmailList($emailConfig['recipientEmail'] ?? '');
if ($method === 'inactive' || !$toRecipients) {
return false;
}
require_once dirname(__DIR__) . '/api/SmtpMailer.php';
$fromEmail = trim((string)($emailConfig['fromEmail'] ?? '')) ?: ($toRecipients[0] ?? '');
$fromName = trim(str_replace(["\r", "\n", "\t"], '', (string)($emailConfig['fromName'] ?? '')));
$replyTo = filter_var(($values['email'] ?? ''), FILTER_VALIDATE_EMAIL) ? (string)$values['email'] : '';
$bccRecipients = raijuFormsParseEmailList($emailConfig['bccEmail'] ?? '');
if ($method === 'smtp') {
$mailer = new SmtpMailer(
$emailConfig['smtpHost'] ?? '',
(int)($emailConfig['smtpPort'] ?? 587),
$emailConfig['smtpUsername'] ?? '',
$emailConfig['smtpPassword'] ?? '',
$emailConfig['smtpEncryption'] ?? 'tls'
);
return $mailer->send($toRecipients, $subject, $body, $fromEmail, $fromName, $replyTo, $bccRecipients);
}
if ($method === 'sendmail') {
$headers = [];
$headers[] = 'From: ' . ($fromName ? "=?UTF-8?B?" . base64_encode($fromName) . "?= <$fromEmail>" : $fromEmail);
if ($replyTo) {
$headers[] = 'Reply-To: ' . $replyTo;
}
$headers[] = 'Content-Type: text/plain; charset=UTF-8';
$headers[] = 'X-Mailer: raiju CMS';
$sent = @mail(implode(', ', $toRecipients), '=?UTF-8?B?' . base64_encode($subject) . '?=', $body, implode("\r\n", $headers));
foreach ($bccRecipients as $bccRecipient) {
$sent = @mail($bccRecipient, '=?UTF-8?B?' . base64_encode($subject) . '?=', $body, implode("\r\n", $headers)) && $sent;
}
return $sent;
}
return false;
}
function raijuFormsBuildBody(array $form, array $values): string
{
$body = 'Neue Einsendung über Formular: ' . $form['label'] . "\n";
$body .= str_repeat('-', 40) . "\n\n";
foreach ($form['fields'] as $field) {
if (in_array(($field['type'] ?? ''), ['heading', 'note', 'hidden'], true)) {
continue;
}
$body .= ($field['label'] ?? $field['key']) . ': ' . ($values[$field['key']] ?? '') . "\n";
}
return $body;
}