> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://help.hodi.host/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# Comment créer un formulaire avec Hodifly ?

Un formulaire de contact, c'est vite ajouté à une page. Le recevoir, c'est une autre histoire : il faut habituellement un service externe, un abonnement, ou du code côté serveur. Les **formulaires Hodifly** vous évitent les trois.

Vous créer un formulaire dans votre HTML, indiquez que Hodifly doit le gérer, vous déployez, et les messages arrivent dans **cPanel → Hodifly → Formulaires**, avec un e-mail à chaque envoi. Rien d'autre à installer.

**Et pour vous, concrètement ?** Les entrées sont enregistrées **sur votre propre compte**, et il n'y a **aucune limite d'envois** autre que votre quota disque. Pas de forfait à surveiller, pas de données chez un tiers.

> **⚠️ À savoir d'emblée :** les formulaires Hodifly fonctionnent sur les **sites statiques** uniquement. Une application Node ou Python gère ses propres envois dans son code.

---

## 1. Comment créer un formulaire ?

Ajoutez l'attribut `hodifly` à votre balise `<form>`, et donnez-lui un `name` :

```html
<form name="contact" data-hodifly method="POST">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button>Envoyer</button>
</form>
```

Quatre écritures fonctionnent indifféremment : **`hodifly`**, **`data-hodifly`**, **`netlify`** et **`data-netlify="true"`**. Un site déjà prévu pour Netlify fonctionne donc **sans aucune modification** : vous le déployez tel quel.

### Ce qui se passe au déploiement

Hodifly détecte vos formulaires pendant la compilation et, automatiquement :

1. injecte un champ caché `form-name` — c'est lui qui identifie le formulaire à la réception ;
2. injecte un **piège à robots** invisible (*honeypot*) : un champ que seul un robot remplit ;
3. génère un petit script dans le site publié ;
4. route les requêtes POST vers ce script.

Vous n'avez rien à configurer. Le formulaire apparaît dans **Formulaires** dès le déploiement, **même sans aucune entrée,** pratique pour vérifier qu'il est bien détecté.

### Que voit le visiteur après l'envoi ?

Il est renvoyé sur la page d'où il a posté, avec `?hf=ok` ajouté à l'URL. À vous d'afficher le message de remerciement :

```html
<p id="merci" style="display:none">Merci, votre message est bien arrivé.</p>
<script>
  if (/[?&]hf=ok/.test(location.search)) document.getElementById('merci').style.display = '';
</script>
```

Pour atterrir sur une **autre page**, pointez l'`action` du formulaire dessus (`action="/merci/"`) : le visiteur y sera redirigé après l'enregistrement.

En cas de refus, l'URL reçoit `?hf=err&hf_why=<raison>` (voir la table des raisons plus bas).

### Et en AJAX ?

Si votre formulaire est envoyé en arrière-plan par JavaScript, ajoutez l'en-tête `Accept: application/json` à la requête : vous recevez `{"ok":true}` au lieu d'une redirection, ou `{"ok":false,"error":"captcha"}` en cas de refus.

---

## 2. Où retrouver les messages reçus ?

Dans cPanel, ouvrez **Hodifly → Formulaires**. Vous y trouvez :

* **la liste de tous vos formulaires**, tous projets confondus : nom, projet, nombre d'entrées, date de la dernière ;
* pour chaque ligne : **Voir** (les entrées), **Réglages**, **Exporter en CSV** ;
* dans une fiche : **← Formulaires** pour revenir à la liste, puis **← Projets** pour revenir aux projets ;
* **Tout effacer** pour vider un formulaire : attention, c'est irréversible.

---

## 3. Quels réglages puis-je modifier ?

Cliquez sur **Réglages** en face d'un formulaire. Bonne nouvelle : les réglages sont lus **à chaque envoi**. Une modification prend donc effet immédiatement, **sans redéployer votre site**.

### E-mails

* **M'envoyer chaque entrée par e-mail** : activé par défaut. Décochez pour ne plus rien recevoir. Les entrées restent enregistrées, et le webhook continue de partir.
* **Envoyer les entrées à** : une ou plusieurs adresses séparées par des virgules. Laissé vide, Hodifly utilise l'adresse de notification du projet (ou, à défaut, le contact cPanel).

L'e-mail reprend la mise en forme des notifications de déploiement. Son champ **Répondre à** pointe vers l'adresse du visiteur dès que le formulaire contient un champ e-mail : vous répondez directement depuis votre messagerie, sans copier-coller.

### Captcha

Choisissez **Cloudflare Turnstile**, **hCaptcha** ou **reCAPTCHA v2**, puis collez la **clé secrète** du fournisseur.

Le partage des rôles est simple : **vous ajoutez le widget** du fournisseur dans votre formulaire, **Hodifly vérifie le jeton** côté serveur. Si la vérification échoue, l'entrée est refusée (`hf_why=captcha`). En cas de doute, Hodifly refuse : un captcha configuré est toujours appliqué.

### Envoi de fichiers

Activez **Autoriser l'envoi de fichiers**, puis définissez une **taille maximale** (en Mo) et une **liste d'extensions** autorisées (`pdf, png, jpg`).

Votre formulaire doit comporter `enctype="multipart/form-data"` : c'est l'attribut HTML qui permet à un formulaire de transporter des fichiers :

```html
<form name="contact" data-hodifly method="POST" enctype="multipart/form-data">
  <input type="file" name="piece-jointe" accept=".pdf,.png,.jpg">
  ...
</form>
```

Les fichiers sont enregistrés **hors de la racine web** - donc jamais accessibles publiquement - et se téléchargent depuis la fiche du formulaire. Une extension non autorisée renvoie `hf_why=filetype`, un fichier trop gros `hf_why=filesize`.

La taille reste bornée par ce que PHP accepte sur le serveur : la limite réelle est affichée sous le réglage.

### Webhook sortant

Un *webhook*, c'est une notification automatique envoyée à une autre application dès qu'un événement survient — ici, à chaque entrée de formulaire. Utile pour alimenter un CRM, un canal d'équipe ou un outil interne.

Renseignez une **URL** (`https://…`) et, si vous le souhaitez, une **clé de signature**. Chaque entrée y est envoyée en JSON.

---

## 4. Quel est le format du webhook ?

Hodifly envoie une requête `POST` avec `Content-Type: application/json` et une charge utile proche de celle de Netlify :

```json
{
  "payload": {
    "id": "93ee97f9f1769bea",
    "form_name": "contact",
    "site_url": "https://exemple.re/",
    "created_at": "2026-07-15T04:11:11+00:00",
    "data": {
      "email": "jeanne@exemple.com",
      "message": "Bonjour",
      "ip": "203.0.113.10",
      "user_agent": "Mozilla/5.0 …"
    },
    "human_fields": {
      "Email": "jeanne@exemple.com",
      "Message": "Bonjour"
    },
    "ordered_human_fields": [
      { "title": "Email",   "name": "email",   "value": "jeanne@exemple.com" },
      { "title": "Message", "name": "message", "value": "Bonjour" }
    ],
    "files": [
      { "field": "piece-jointe", "name": "cv.pdf", "size": 20481, "stored": "20260715-041111-a1b2c3d4-cv.pdf" }
    ]
  }
}
```

| Champ | Contenu |
| ---- |
| `id` | Identifiant unique de l'entrée |
| `form_name` | Le `name` de votre formulaire |
| `site_url` | L'URL du site qui a reçu l'envoi |
| `created_at` | Date/heure UTC (ISO 8601) |
| `data` | Les champs bruts, plus `ip` et `user_agent` |
| `human_fields` | Les mêmes champs avec un libellé lisible |
| `ordered_human_fields` | Idem, en conservant l'ordre du formulaire |
| `files` | Les fichiers envoyés (le contenu reste sur votre compte) |

### Vérifier la signature

Si vous avez renseigné une clé, la requête porte l'en-tête suivant :

```
X-Hodifly-Signature: sha256=<HMAC-SHA256 du corps brut, avec votre clé>
```

Cette signature vous permet de vérifier que la requête vient bien de votre site, et non d'un tiers. Vérifiez-la sur le **corps brut** de la requête, **avant** tout décodage JSON. Exemple en PHP :

```php
$brut    = file_get_contents('php://input');
$attendu = 'sha256=' . hash_hmac('sha256', $brut, 'VOTRE_CLE');
if (!hash_equals($attendu, $_SERVER['HTTP_X_HODIFLY_SIGNATURE'] ?? '')) {
    http_response_code(403); exit('signature invalide');
}
$entree = json_decode($brut, true)['payload'];
```

---

## 5. Pourquoi un envoi a-t-il été refusé ? (`hf_why`)

| Valeur | Signification |
| ---- |
| `captcha` | Le captcha n'a pas été validé |
| `filetype` | Extension de fichier non autorisée |
| `filesize` | Fichier au-delà de la taille maximale du formulaire |
| `toolarge` | Envoi au-delà de ce que PHP accepte sur le serveur |
| `upload` | Échec de l'envoi du fichier |

---

## 6. Mes données sont-elles protégées ?

* **Anti-robots.** Un champ *honeypot* invisible est injecté automatiquement. Un robot qui le remplit reçoit une réponse normale, mais rien n'est enregistré ni envoyé — il ne sait pas qu'il a été écarté.
* **CSRF.** Un envoi provenant d'un autre site est refusé : Hodifly vérifie l'origine de la requête, ce qui empêche un tiers de poster à votre place.
* **Pas de relais ouvert.** Le gestionnaire n'accepte que les formulaires réellement détectés lors du dernier déploiement.
* **Stockage.** Entrées et fichiers sont enregistrés hors de la racine web, en permissions `0600`, et survivent aux déploiements comme aux restaurations.
* **Confidentialité.** Tout reste sur votre compte. Les entrées ne transitent jamais par Hodifly.

---

## 7. Quelles sont les limites ?

* **Sites statiques uniquement.** Une application Node ou Python gère ses propres envois dans son code.
* Un formulaire retiré de votre HTML n'accepte plus d'envoi, mais **conserve** les entrées déjà reçues.
* Le contenu des fichiers n'est pas joint aux e-mails : ils se téléchargent depuis cPanel.
* Pas de filtrage anti-spam de type Akismet : le honeypot et le captcha couvrent l'essentiel des besoins.

---

## 8. En cas de problème

| Symptôme | À vérifier |
| ---- |
| Le formulaire n'apparaît pas dans **Formulaires** | L'attribut `hodifly`/`netlify` est-il bien présent ? Le `<form>` a-t-il un `name` ? Le site a-t-il été redéployé ? Le déploiement doit être **statique**. |
| « Unknown form » | Le formulaire n'existait pas au dernier déploiement : redéployez. |
| Le fichier n'est pas enregistré | Les envois de fichiers sont-ils activés dans **Réglages** ? L'extension est-elle autorisée ? Le formulaire porte-t-il `enctype="multipart/form-data"` ? |
| Aucun e-mail | La case **M'envoyer chaque entrée par e-mail** est-elle cochée ? L'adresse est-elle valide ? |
| Le webhook ne reçoit rien | L'URL doit être en `http(s)://` et joignable depuis le serveur. |
