Le WordPress d'aujourd'hui, décodé pour les développeurs

Astuces

Conditionner le téléchargement d’un plan à la confirmation d’un rendez-vous BTP

Une entreprise du bâtiment diffusait ses plans techniques sans contrôle. Un lien de téléchargement débloqué uniquement après confirmation d'un rendez-vous protège l'information sans complexifier le parcours client.

Par WordPress Développement • 11 août 2020 • 4 min de lecture • Aucun commentaire
Conditionner le téléchargement d'un plan à la confirmation d'un rendez-vous BTP

Un plan technique accessible par simple URL directe, sans le moindre contrôle d’accès : c’est ce qu’une entreprise de charpente-couverture a découvert après qu’un client concurrent eut mis la main sur un document censé rester réservé aux clients ayant réellement un projet engagé. Le fichier PDF était référencé par erreur dans un moteur de recherche d’images, sans qu’aucune condition n’en limite la diffusion.

Le vrai problème n’était pas la protection du fichier lui-même — cela reste un sujet distinct, souvent traité par un filigrane ou une restriction serveur — mais l’absence totale de condition d’accès. La solution retenue : un lien de téléchargement qui n’existe tout simplement pas tant qu’un rendez-vous n’a pas été confirmé par l’équipe commerciale.

Générer un jeton d’accès à la confirmation du rendez-vous

Le rendez-vous est un type de contenu personnalisé rendez_vous, avec un champ statut qui passe de en_attente à confirme lorsque l’équipe valide manuellement la demande depuis l’administration. C’est précisément ce changement de statut qui déclenche la génération du jeton de téléchargement.

add_action( 'ch_rendez_vous_confirme', function ( $rdv_id ) {
    $plan_id = get_post_meta( $rdv_id, 'plan_associe', true );
    if ( ! $plan_id ) {
        return;
    }

    $jeton = wp_generate_password( 32, false );
    $expiration = time() + ( 48 * HOUR_IN_SECONDS );

    update_post_meta( $rdv_id, 'jeton_telechargement', $jeton );
    update_post_meta( $rdv_id, 'jeton_expiration', $expiration );

    $lien = add_query_arg( array(
        'ch_plan' => $plan_id,
        'jeton'   => $jeton,
    ), home_url( '/telecharger-plan/' ) );

    // Envoi du lien par e-mail au client, dans une fonction séparée.
    ch_envoyer_lien_plan( $rdv_id, $lien );
} );
L'essentiel à retenir : Lien de téléchargement généré uniquement après confirmation ; Jeton signé avec expiration courte ; Journal des accès pour tracer les consultations

Vérifier le jeton avant de servir le fichier

La page /telecharger-plan/ ne sert jamais directement un fichier stocké dans la médiathèque publique. Elle vérifie le jeton, contrôle l’expiration, puis transmet le fichier en flux depuis un dossier hors de portée d’un accès direct par URL.

add_action( 'template_redirect', function () {
    if ( ! is_page( 'telecharger-plan' ) ) {
        return;
    }

    $jeton_recu = isset( $_GET['jeton'] ) ? sanitize_text_field( $_GET['jeton'] ) : '';
    $rdv = get_posts( array(
        'post_type'  => 'rendez_vous',
        'meta_key'   => 'jeton_telechargement',
        'meta_value' => $jeton_recu,
        'numberposts' => 1,
    ) );

    if ( empty( $rdv ) ) {
        wp_die( 'Lien invalide ou expiré.', 403 );
    }

    $expiration = get_post_meta( $rdv[0]->ID, 'jeton_expiration', true );
    if ( time() > $expiration ) {
        wp_die( 'Ce lien a expiré. Contactez votre conseiller pour un nouvel envoi.', 403 );
    }

    $chemin_fichier = get_attached_file( get_post_meta( $rdv[0]->ID, 'plan_associe', true ) );
    header( 'Content-Type: application/pdf' );
    header( 'Content-Disposition: attachment; filename="plan-technique.pdf"' );
    readfile( $chemin_fichier );
    exit;
} );

Tracer les consultations sans excès

L’entreprise souhaitait garder une trace des téléchargements, sans mettre en place un outil d’analyse complexe. Une simple ligne enregistrée à chaque accès réussi suffit, stockée comme métadonnée du rendez-vous concerné.

  • Date et heure du téléchargement effectif, différente de la date de confirmation du rendez-vous.
  • Adresse IP tronquée, conservée uniquement à des fins de diagnostic technique en cas de contestation.
  • Nombre de tentatives avec un jeton expiré, un indicateur utile pour repérer un lien qui circule au-delà du client concerné.
update_post_meta( $rdv[0]->ID, 'derniere_consultation', current_time( 'mysql' ) );

Pourquoi un jeton plutôt qu’une simple case protégée par mot de passe

Une protection par mot de passe partagé aurait été plus rapide à développer, mais elle repose sur la discrétion du client, qui n’a aucune obligation de garder l’information confidentielle. Le jeton, lui, est unique par rendez-vous, expire de lui-même, et ne dépend d’aucune vigilance humaine pour rester efficace après quarante-huit heures.

Un lien qui expire protège mieux qu’un mot de passe qu’on espère garder secret : la sécurité par défaut vaut toujours mieux que la sécurité par confiance.

En résumé

Un champ de statut, un jeton généré à la confirmation et une vérification stricte avant l’envoi du fichier : ce mécanisme a suffi à fermer une fuite qui aurait pu, à terme, coûter bien plus cher qu’un après-midi de développement. Il ne remplace pas une protection anti-copie du document une fois téléchargé, qui reste un enjeu distinct, mais il évite déjà l’essentiel des diffusions accidentelles.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi