Mon interrogation est de faire un cryptage compatible avec ce que Apache sait décoder.

Autant que je comprenne en lisant la documentation il y a une certaine latitude dans ce domaine, mais je ne suis pas arrivé à utiliser un autre moyen de générer un mot de passe crypté utilisable par Apache que ma fameuse fonction
$crypt = '$apr1$' . crypt($pw, base64_encode($pw));

Si je comprends bien, le deuxième paramètre de la fonction crypt est le "salt", on pourrait donc mettre autre chose que l'encodage du mot passe en base64, mais pourquoi pas?
Toutes les autres façons de créer un mot de passe codé reconnu par Apache que j'ai essayées ont échoué.

Dans le cas de ce site, il n’y a pas de données réellement sensibles, la partie privée est là pour éviter que certains fichiers soient de fait en accès public à tout un chacun, par exemple si je fais un fichier musical d’une œuvre qui a été écrite il y a moins de 80 ans.
Le problème est comme toujours que les gens utilisent le même mot de passe partout, malgré les recommandations : si on trouve un mot de passe sur mon site, il pourrait être récupéré pour hacher le compte de la personne sur un autre site.
Modifié par PapyJP (25 Sep 2021 - 11:19)
PapyJP a écrit :
Merci de ta réponse
Il y a quelque chose que je ne comprends pas: une fois que l’utilisateur a donné son mot de passe, on en fait quoi?
.

Tu l'encrypte et tu stocke cette nouvelle chaine illisible. Ce mot de passe ne sera connu que de l'utilisateur.
pour se loguer, l'utilisateur tape son mot de passe, il est récupéré et cryptée (même méthode qu'à l'enregistrement), la chaine illisible alors produite est comparée à celle qui est stockée. Elles seront identiques si le mot de passe est le bon (le cryptage n'est pas aléatoire).

L'exemple utilise un grain de sel, lui aléatoire mais, conservé pour être réutilisé . utilité: même si deux chaines sont identiques, avec le grain de sel, ce ne sera plus le cas. (crypté ou pas).

PapyJP a écrit :

Actuellement je transforme le mot de passe par la fonction expliquée plus haut et je mets dans le fichier de contrôle une ligne "pseudo:mot-de-passe-transformé" dans le fichier de contrôle.
Je suppose que je vais devoir faire la même chose, ce qui me va très bien.
La fonction de transformation que j’ai trouvée je ne sais où donne un résultat qui convient à Apache, c’est le principal. Je suis d’accord que c’est faible comme protection, mais je n’ai pas pour le moment connaissance d’une meilleure fonction de transformation.

C'est toi qui choisi ta méthode Smiley cligne
PapyJP a écrit :

Par ailleurs je ne tiens pas à demander aux inscrits actuels de renouveler leur mot de passe parce que j’ai changé mon programme.


Si tes mots de passes sont actuellement stockés en clair, alors tu peut les cryptés en lot , le mot de passe à saisir sera le même. Il y aura une étape supplémentaire dans le programme pour le crypté avant de comparer les deux chaines cryptées. Si il y a fuites de données, ce sera des mots de passe cryptés , c'est principalement l'idée.

L'exemple fait mumuse en tournant en rond avec une génération de lien à durée limité et une seule utilisation, en utilisant la date du jour cryptée , cela n'a aucune incidence sur la façon dont tu stockerait le mot de passe. Mais je n'ai peut-être pas compris ton interrogation.

Dans l'exemple, la date limite est injectée dans l'url et cryptée et avec : $limit=sha1($salt.md5($lastValidDate));
et ensuite comparée a $check=sha1($line[0].md5($end)); $line['0'] c'est le grain de sel et $end la date limite . $limit et $check sont les deux chaines illisible à comparer , l'une vient de L’URL, l'autre des données stockées Smiley smile


Cdt,
GC
Merci de ta réponse
Il y a quelque chose que je ne comprends pas: une fois que l’utilisateur a donné son mot de passe, on en fait quoi?
Actuellement je transforme le mot de passe par la fonction expliquée plus haut et je mets dans le fichier de contrôle une ligne "pseudo:mot-de-passe-transformé" dans le fichier de contrôle.
Je suppose que je vais devoir faire la même chose, ce qui me va très bien.
La fonction de transformation que j’ai trouvée je ne sais où donne un résultat qui convient à Apache, c’est le principal. Je suis d’accord que c’est faible comme protection, mais je n’ai pas pour le moment connaissance d’une meilleure fonction de transformation.
Par ailleurs je ne tiens pas à demander aux inscrits actuels de renouveler leur mot de passe parce que j’ai changé mon programme.
Bonsoir,

Attention, base64_encode() ne crypte pas, il encode et base64_decode() te redonne en clair ce qui est encoder. Cela peut te servir a cacher visuellement une URL, mais pour un mot de passe ça revient à le stocké en clair.

Pour crypter en php tu as plusieurs pistes :

https://www.php.net/manual/fr/book.password.php / https://www.php.net/manual/fr/faq.passwords.php
https://www.php.net/manual/en/function.hash.php
https://www.php.net/manual/fr/function.sha1.php
https://www.php.net/manual/fr/function.md5.php
_____________________________________________________________
https://www.php.net/manual/fr/function.base64-encode.php
https://www.php.net/manual/fr/function.base64-decode.php
il y a aussi https://www.php.net/manual/fr/function.urlencode.php

et puis tu peux aussi générer "un grain de sel" pour rendre le plus unique possible cette chaine de caractère que tu veut crypter.

Il existe des dictionnaires de mots et leurs équivalent cryptés qui ne cessent de s'agrandir au fil du temps.
Ce qui fait qu'en utilisant une méthode seule, une chaine de caractères retournera toujours la même chaine cryptée. En lançant en boucle un programme qui génère des chaines de mots ou caractères aléatoires qui sont stockée avec leur équivalent crypté, le supermotdepassekamoi finira par apparaitre dans ce foutu dico.

L'ajout d'une chaine de caractères aléatoires (l’assaisonnement) à la chaine crypté rend la probabilité de voir ce mot figuré au dico s’amoindrir.

Tu peut par exemple faire un mix : ajouté un grain de sel a la chaine a cryptée et imbriqué 2 modes de cryptage moyen pour obtenir un cryptage suffisamment costaud.

En faisant cela, il te faudra stocké le grain de sel et la chaine crypté.
Pour vérifier la chaine , il faut réutiliser son grain de sel et le cryptage et comparé ce résultat avec la chaine cryptée déjà stockée .

En cas de mot de passe perdu, il est impossible de retrouvé le mot de passe, il faut en généré un nouveau. Ce lien temporaire envoyé sur une adresse mail , donnée au moment de l'inscription ou figurant dans les données de l'utilisateur peut-être encode en base64 pour y cacher quelque données utiles à reconnaitre le membre et une valeur cryptée de référence , ou bien seule la valeur cryptée enregistrée dans les données du membre que l'on recherchera en bdd.

Voici un exemple (A NE PAS UTILISER TEL QUEL) qui utilise encode64()/decode64() pour le lien d'activation/récupération qui sera visible encodé dans le mail mais au final en clair , et la génération d'un grain de sel ajouter à une date cryptée en imbriquant sha1( 'grain_de_sel'. md5('la_date_a_cacher')) . Ce n'est pas incraquable, mais les ressources à mettre en œuvre n'en valent vraiment pas le coup, c'est pas les coffres de forknox Smiley smile .

Voici donc l'exemple qui se base sur un fichier texte (au lieu d'une bdd) pour une démo.
! Ce n'est qu'une démo sans bonnes pratiques, juste pour montrer l'idée évoquée précédemment à propos d'un lien temporaire , je crois que ça couvre pas trop mal un déroulé possible.
<?php  // NE pas utiliser en vrai - methode obsolete et codage à l'arrache, c'est juste une démo d'exemple / voir  https://www.php.net/manual/fr/function.password-verify.php  une fois l'intêret du stockage d'un mot passe crypté
if(isset($_GET['monCompte'])) {
	$seeyou = base64_decode($_GET['monCompte']);
	header("location:   http://".$_SERVER['SERVER_NAME'].$_SERVER['PHP_SELF'].$seeyou  );
}
?>
<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8">
  <title>  test</title>
  <meta name="description" content=" test valid connexion ">
  <meta name="author" content="MyPc">
  <link rel="stylesheet" href="css/styles.css?v=1.0">
</head>
<style>
body{display:grid;justify-content:center;}
</style>
<body>
	<h1 style="width:max-content;margin:1em auto;max-width:80%;">test generation lien connexion temporaire</h1>
<?php

if(isset($_POST['pwd1'])) {
	$mdp = $_POST['pwd1'];
	$mdp64         = base64_encode($mdp);
	$mdpdec64      = base64_decode($mdp64);
	
	$mdp_md5        = md5($mdp);
	
	$mdp_sha1       = sha1($mdp);
	
	$clef_de_sel   = 'UneChaineAuHasard'; // soit generation aléatoire ou par exemple prit dans les infos fournit par le membre (date d'inscription,pseudo,nbre de connexions,n] d'enregistrement , mail, etc  selon votre imagination)
	
	
	$mdp64_sel         = base64_encode($mdp.$clef_de_sel);
	$mdpdec64_sel      =str_replace($clef_de_sel, '',base64_decode( $mdp64_sel));
	
	
	$mdp_md5_sel    = md5($mdp.$clef_de_sel);
	
	$mdp_sha1_sel   = sha1($mdp.$clef_de_sel);	
	
	$mdp_sha1_md5_sel =sha1(md5($mdp).$clef_de_sel); // ou sha1($clef_de_sel.md5($mdp)) ou sha1($clef_de_sel.md5($mdp$clef_de_sel.)) ....
	
	$mdp_md5_sha1_sel =md5(sha1($mdp).$clef_de_sel); // ou md5($clef_de_sel.sha1($mdp)) ou md5($clef_de_sel.sha1($mdp$clef_de_sel.)) ....
	echo '<style>table,td ,th {border:solid 1px;text-align:center;padding:0.15em;} th {background:lightgray}.oups{color:crimson;background:yellow}</style>
	<p><b>Il n\'y a rien eu d\'enregistrer durant cette étape de l\'exemple</b>, mais voici quelques possibilités , <b>pour sécuriser un mot de passe il ne faut pas utiliser une méthode reversible</b>.</p>
	<table>
		<thead>
			<tr><th>   mot de passe</th>     <th> hachoir                       </th><th>chaine modifiée à stockée</th><th> decodage natif  disponible                       </th><th>résultat          </th><th>grain de sel                  </th></tr>
		</thead>
		<tbody>
			<tr><th rowspan="8">'.$mdp.'</td><td>base64_encode("pwd")           </td><td>'.$mdp64.'               </td><td> base64_decode()                                  </td><td class="oups">'.$mdpdec64.'     </td><td> non                          </td></tr>
			<tr>                             <td>base64_encode("pwd + sel" )    </td><td>'.$mdp64_sel.'           </td><td> str_replace(sel, "",base64_decode(chainee salée))</td><td class="oups">'.$mdpdec64_sel.' </td><td rowspan="  ">'.$clef_de_sel.' </td></tr>
			<tr>                             <td>md5("pwd")                     </td><td>'.$mdp_md5.'             </td><td>  non                                             </td><td>aucun sans hachage             </td><td rowspan="  ">non              </td></tr>
			<tr>                             <td>sha1("pwd")                    </td><td>'.$mdp_sha1.'            </td><td>  non                                             </td><td>aucun sans hachage             </td><td rowspan=" 5 ">'.$clef_de_sel.'</td></tr>
			<tr>                             <td>md5("pwd + sel")               </td><td>'.$mdp_md5_sel.'         </td><td>  non                                             </td><td>aucun sans hachage             </td>                                       </tr>
			<tr>                             <td>sha1("pwd + sel")              </td><td>'.$mdp_sha1_sel.'        </td><td>  non                                             </td><td>aucun sans hachage             </td>                                       </tr>
			<tr>                             <td>sha1(md5("pwd + sel")          </td><td>'.$mdp_sha1_md5_sel.'    </td><td>  non                                             </td><td>aucun sans hachage             </td>                                       </tr>
			<tr>                             <td>md5(sha1("pwd + sel")          </td><td>'.$mdp_md5_sha1_sel.'    </td><td>  non                                             </td><td>aucun sans hachage             </td>                                       </tr>
		</tbody>
	</table>
	<p>Si grain de sel, il vaut mieux que celui-ci soit unique à chaque enregistrement , il faut donc le stocker avec la chaine modifié</p>
	<p><a href="http://'.$_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'].'">Retour au formulaire</a></p>
</body>
</html>';
exit;
}


$date=date("Y-m-d");
$duree ="+2day";
if(isset($_POST['duree'])){$duree=$_POST['duree'];}
$lastValidDate = strtotime($duree, strtotime($date));

if(isset($_POST['name'])) { 
 echo '<p>demande enregistrée en attente d\'activation</p>';		
	$salt = '';
	$chaine = 'abcdefghijklmnpqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
	mt_srand((float)microtime()*1000000);
	
		for($i=0; $i<10; $i++) $salt .= $chaine[ mt_rand()%strlen($chaine) ];
		
	$limit=sha1($salt.md5($lastValidDate));
	
	
	$filelimit=$date;
	$nom =$_POST['name'];
	$prenom =$_POST['nickname'];
	
	$fileMember= $prenom.'.'.$nom.'.quand';
	$fileMemberContent= $salt.','.$date .','.$duree;
	
	$open = fopen($fileMember, "w") ;
	fwrite($open, $fileMemberContent);
	fclose($open);
	
	$lien = '?p='.$nom.'&pr='.$prenom.'&val='.$limit ;
	$secret=  base64_encode($lien);
	
	$lienValidationEnAttente = $_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'].'?monCompte='.$secret  ;
				
	echo '<p> Pour finaliser votre inscription veuillez créer votre mot de passe en suivant ce lien:<br> <a href="http://'.$lienValidationEnAttente.'">Activer mon espace personnel</a>.</p>';
	
	
	
}


if(isset($_GET['p']) && isset($_GET['pr']) && isset($_GET['val']) ) {
	echo '<p>Bienvenue <b style="text-transform:uppercase">'.$_GET['pr'].' '.$_GET['p'].'</b>.</p>';

	if(@$open = fopen($_GET['pr'].'.'.$_GET['p'].'.quand', "r")) {
    while (($data = fgetcsv($open, 100, ",")) !== FALSE)     {        
      $array[] = $data; 
    }  
    fclose($open);
	
		foreach($array as $i => $line){ 
		 $end = strtotime($line[2], strtotime($line[1]));
		 $check=sha1($line[0].md5($end)); 
		 //verif de la date de validité
			if ($check == $_GET['val']) {
				// la date est elle dépasée ?
				$dnow = strtotime($date);
				if (($dnow < $end) || ($dnow == $end)) {
					echo '<form action="" method="post"  style="display:grid;justify-content:center;">
					<fieldset>
						<legend style="text-transform:uppercase">Mise à jour du mot de passe</legend>
							<div style="display:grid;grid-template-columns:auto auto;gap:0.5em;justify-content:center;">
								<label>Votre nouveau mot de passe</label>
								<input name="pwd1">
								<label>Retaper votre mot de passe</label>
								<input name="pwd2">
								<input type="submit">
							</div>
						</fieldset>
					</form>';
					unlink($_GET['pr'].'.'.$_GET['p'].'.quand');
					}
					else { echo 'Ce lien a expiré, veuillez renouveler votre demande d\'inscription';}
				
			}
		}
	} 	else { 		echo '<p style="color:orange">Il n`y a actuellement aucune demande au nom de <b style="text-transform:uppercase"> '.$_GET['pr'].' '.$_GET['p'].' </b> en attente de finalisation. </p>';	}
}

?>
<?php if((empty($_POST)) && (empty($_GET))) {?>
	<form action="" method="post"  style="display:grid;justify-content:center;">
		<fieldset>
			<legend style="text-transform:uppercase">Demande d'nscription</legend>
			<div style="display:grid;grid-template-columns:auto auto;gap:0.5em;justify-content:center;">
			<label for="name">Nom</label>
			<input type="text" name="name">
			<label for="nickname">Prénom</label>
			<input type="text" name="nickname">
			<label for="mail">Courriel</label>
			<input type="email" name="mail">
			<label for="duree">validité</label>
			<select name="duree">
				<option value="-1 month">test date expirée</option>
				<option value="+1 day">1 journée</option>
				<option value="+2 day" selected>2 jours</option>
				<option value="+10 day">10 jours</option>
				<option value="+1 month">1 mois</option>
				<option value="+1 year">1 ans</option>
			</select>
			<input type="submit">
			</div>
		</fieldset>
	</form>
<?php } ?>
	<p><a href="http://<?php echo $_SERVER['SERVER_NAME'].$_SERVER['SCRIPT_NAME'].'">Retour au formulaire</a></p>'; ?>
</body>
</html>


Cdt
Modifié par gcyrillus (25 Sep 2021 - 14:25)
Bonjour à tous,

Etant passionné de programmation depuis très jeune, je me pose aujourd'hui la question si devenir professionnel du métier me conviendrai/plairai.

C'est pourquoi j'aimerais avoir un retour d'expérience des professionnels qui peuvent trainer sur ce forum Smiley smile

Mon plaisir, c'est la création, développer des applications ou des programmes que je n'ai encore jamais fait. Faire fonctionner mon cerveau.
Je suis conscient que dans tous les métiers, la répétition des taches est inévitable et surtout la rentabilité est souvent prioritaire sur le bon sens ou la qualité.

Afin de préciser, je développe (à titre personnel) des applications en PHP OO, liés à des bdd mysql. Je suis limité à cela car je n'ai jamais eu le courage de me mettre au python ou java, sachant que j'ai toujours réussi à faire ce que je voulais avec du php.

Ce dont j'ai réellement peur, c'est d'être réduit à faire des copier/coller de projets similaire, les adapter légèrement, changer quelques textes et livrer ça au client. L'usine en quelque sorte.

De plus, j'ai l'impression (peut-être fausse), que de nos jours, tout le monde utilise des framework, et qu'il faut donc déjà commencer par apprendre à s'en servir.
Utiliser un framework, signifie pour moi, utiliser du code existant afin de ne pas s'embêter à le développer soi même. Encore une fois, question de rentabilité.

Pire encore, créer des sites web avec un CMS type wordpress, me terrifie réellement. Observer le code source html généré par wordpress me rend malade rien que d'y penser.

Je voudrais donc savoir, messieurs les pro du web dév, qu'en est-t-il réellement de votre métier ? Est-ce que mes craintes sont justifiées, ou suis-je totalement à côté de la plaque ?

J'imagine également que selon l'entreprise dans laquelle on travaille, les types de projets sont différents.

Je vous remercie d'avance pour vos réponses et les éventuels conseils que vous pourriez m'apporter.

Bonne journée à tous
Merci, c'est ce que je suis en train de coder.

J'ai découvert que le mot de passe crypté utilisé par Apache sur mon site est correctement obtenu par la formule

$cryptPW = '$apr1$' . crypt($pw, base64_encode($pw))

Je ne me souviens plus comment j'ai trouvé ça, mais bon! ça marche.
Je vais donc prendre le mot de passe fourni par l'utilisateur et mettre dans le fichier de contrôle la valeur retournée par cette fonction.

Question:
Dans le code actuel, j'ai une fonction "changer de mot de passe" dans laquelle je demande à l'utilisateur
- son mot de passe actuel
- son nouveau mot de passe
- retaper son nouveau mot de passe

Si je voulais faire la même chose dans le nouveau code, où je ne dispose plus du mot de passe en clair, il faudrait que je puisse vérifier que le mot de passe actuel est cohérent avec le mot de passe crypté calculé par l'algorithme ci-dessus.

Je trouve plein de choses dans la doc pour vérifier la validité d'un mot de passe, mais ça n'a pas l'air de correspondre à ce que je fais pour Apache.

Savez vous comment faire ça, l'alternative étant de remplacer la fonction "changer de mot de passe" par "j'ai perdu mon mot de passe", c'est à dire sans vérification initiale du mot de passe actuel ?
Bonjour,

Tu peux utiliser le système proposé par niuxe en conservant la gestion des utilisateurs dans l'administration du site.
1 / Tu ajoutes un champ token (nullable) dans ta table des utilisateurs,
2 / Quand tu crées un utilisateur, un token (unique, avec durée de validité, etc.) lui est généré et un mail avec un lien de validation contenant le token lui est envoyé
3 / Quand ton user clique sur le lien, il entre son e-mail et peut choisir son mot de passe, le token de l'utilisateur est remis à 'null' et le lien n'est plus utilisable.

ça pourra te permettre par la suite de garder le même système pour la fonctionnalité "mot de passe perdu".
Bonsoir,

Whaou , ton message d'erreur fait référence à la ligne
imagecolorallocate($this->img, 255,255,255);

dans class.image.php si je compte bien. mais le message d'erreur parle du fichier graph.class.php et $tabs a aussi disparu de l’horizon !?

je n'arrive pas à te suivre ni a reproduire ton soucis, c'est comme regarder au travers d'un trou de serrure ... on voit pas tout Smiley cligne

Bonne soirée.
Salut @Niuxe,

Je viens de vérifier depuis mon iPhone, et désormais c'est nickel sous Safari... Je n'ai rien fait depuis. Après avoir vidé les caches du navigateur, ça n'avait pas fonctionné (après 15 rafraichissements), mais après quitté Safari et ré-affiché la page plus tard, mon -webkit-appearance: none; semble fonctionner et pris en compte.

Bizarre ! à ma connaissance, pas besoin de relancer le navigateur après un vidage de caches pour que ça marche, ou alors je n'ai pas bien vidé les caches de Safari ? (je suis allé dans Réglages > Safari >Effacer historique, données de site pour info, je pense que c'est la bonne façon - peut-être même la seule)

Merci pour ta réponse, je garde ton astuce sous le coude pour une petite séance de tests car je trouve que Safari iOS est régulièrement assez embêtant avec les CSS "modernes" Smiley lol
Si je comprends bien tunes dans le mode "l’utilisateur s’inscrit lui-même", quitte à ce que l’administrateur le supprime. Dans mon cas c’est l’administrateur qui inscrit les utilisateurs. On doit donc envoyer un lien à l’utilisateur pour qu’il entre son mot de passe. Dans l’état actuel de la discussion je pense effectivement que je vais envoyer un message sans mot de passe. Le problème maintenant est de rédiger un message de bienvenue sexy.
L'erreur :
upload/1632418145-82440-erreur.png
La classe image :

<?php

/**
 * A NE PAS MODIFIER
 * image.class.php
 */

class Image
{
        protected $img;
        protected $couleurs;
        protected $w,$h;

        
       /**
       * Constructeur 
       * @param int $w largeur
       * @param int $h hauteur
       */
        public function __construct($w,$h)
        {
            $this->w = $w;
            $this->h = $h;
            $this->img=imagecreate($w,$h);
            imagecolorallocate($this->img, 255,255,255);

            $this->couleurs = array();
        }
        
        /**
         * Affiche l'image lorsqu'on est pas en mode DEBUG
         */
        public function afficher() 
        {
			if (!constant('DEBUG')) {
				header("Content-type: image/png");
				imagepng($this->img);
				imagedestroy($this->img);
			} else {
				echo '<hr/>DEBUG MODE<hr/>';
			}
        }
        

		/**
		 * Ajoute une couleur au panel de l'image sous le nom saisi en entrée
		 * @param int $r composante r
		 * @param int $v composante v
		 * @param int $b composante b
		 * @param string $nom le nom de la couleur
		 */
        public function ajouterCouleur($r,$v,$b,$nom) 
        {
                $this->couleurs[$nom] = imagecolorallocate($this->img, $r,$v,$b);
        }
        

        /**
         * Définit la couleur de fond de l'image (la couleur doit être présente dans le panel de l'image)
         * @param string $couleur nom de la couleur dans le panel
         */
        public function couleurFond($couleur) {
                imagefill($this->img,0,0,$this->couleurs[$couleur]);
        }
        
      
        /**
         * Dessine un trait sur l'image (la couleur doit être présente dans le panelde l'image)
         * @param int $x1 abscisse du point premier point
         * @param int $y1 ordonnée du premier point
         * @param int $x2 abscisse du point second point
         * @param int $y2 ordonnée du second point
         * @param string $couleur nom de la couleur dans le panel
         */
        public function tracerTrait($x1,$y1,$x2,$y2,$couleur) {
                imageline($this->img,$x1,$y1,$x2,$y2,$this->couleurs[$couleur]);
        }
        
        //
        /**
         * Ecrit un texte sur l'image (la couleur doit être présente dans le panel de l'image)
         * @param int $x coordonnée X du coin en haut, à gauche
         * @param int $y coordonnée Y du coin en haut, à gauche.
         * @param int $font 1, 2, 3, 4, 5 pour les polices internes (+ d'info sur la doc de imagestring )
         * @param string $texte la chaîne de caractères à écrire. 
         * @param string $couleur
         */
        public function ecrireTexte($x,$y,$font,$texte,$couleur)
        {
                imagestring($this->img,$font,$x,$y,$texte,$this->couleurs[$couleur]);
        }
        
        /**
         * Dessine un rectangle sur l'image (la couleur doit être présente dans le panel de l'image)
         * @param int $x1 abscisse du point haut, à gauche
         * @param int $y1 ordonnée du haut, à gauche
         * @param int $x2 abscisse du point bas, à droite
         * @param int $y2 ordonnée du point bas, à droite
         * @param string $couleur nom de la couleur dans le panel
         */
        public function tracerRectangle($x1,$y1,$x2,$y2,$couleur)
        {
                imagefilledrectangle($this->img,$x1,$y1,$x2,$y2,$this->couleurs[$couleur]);
        }
        
}


?>


Fichier qui instancie mon graph:

<?php

/**
 * A NE PAS MODIFIER
 * graph.img.php
 */

//**GESTION DU DEBUG MODE **//

//Gestion automatisé de l'affichage d'erreurs
error_reporting(E_ALL);
ini_set('display_errors', 'On');
set_error_handler("customError",E_ALL);
function customError($errno, $errstr)
{
	$GLOBALS['debug'] = true;
	echo "<b>Error:</b> [$errno] $errstr<br>";


}

//On peut forcer le debug avec un $_GET['debug'] non vide à l'appel du script
$debug = (!empty($_GET['debug']));


//**INCLUSIONS**//

//La classe Image sur laquelle s'appuiera votre travail (à ne pas modifier)
include 'image.class.php';

//La classe Graph que vous aurez à modifier (elle hérite de la class Image)
include 'graph.class.php';


//**CREATION DU GRAPH**//

//On définit les valeurs
$tab = array(21,42,35,0);

//On instancie un graph
$obj = new Graph(500,500);


//On lui ajoute les valeurs renseignées dans $tab
$obj->addVals($tab);


//**PERSONNALISATION**//

//On ajoute un gris au panel de couleurs du graph
$obj->ajouterCouleur(200,200,200,'gris');

//on applique un fond gris au graph
$obj->couleurFond('gris');


//**IMPRESSION**//

//la constante DEBUG commiquera avec la classe Image
define ('DEBUG',$debug);

//on lance l'affichage du graph
$obj->afficher();


?>


Et ma version de PHP est 5.6.25
De mon côté, je gère comme ceci :
- formulaire d'inscription avec mot de passe et confirmation de mot de passe. (8 caractères minimum : majuscule/minuscule, chiffre, caractères "spéciaux", pas de mot courant (!). Le hashage se fait en sha256 avec clef de sécurité
- confirmation inscription
- mécanique formulaire login et redirection logout
- formulaire mot de passe oublié
- confirmation reset password (mail envoyé)

*Tous les formulaires ont un token anti csrf
Modifié par niuxe (23 Sep 2021 - 17:57)
Et l'eau Laurent, Smiley smile

Un wp avec un système de paiement, un gros bof. Le problème ne vient pas forcément de ce cms, mais des plugins mal développés.

Tourne-toi plutôt vers Drupal ou même Joomla (Joomla s'est bien amélioré depuis ces dernières années). Mais dans l'absolu, je te conseille un :
- code igniter
- cakephp
- symfony
- phalcon ( Smiley cligne )
- fuelphp
- laravel
- etc.
- framework php (si tu fais du php)

Pour un système de paiement, regarde du côté de paypal. Il y a une très bonne api à ce sujet.
Modifié par niuxe (23 Sep 2021 - 15:44)
Merci de ta réponse
C'est en gros ce à quoi je pensais pour la solution 2.

Tu peux de donner un exemple de message à envoyer avec le lien temporaire?

Ce que j'ai essayé de faire ne me parait pas suffisamment sexy:

<div style="margin:6pt 0;max-width:600px;">
    <p>Bonjour et bienvenue %firstName%</p>
    <p>Vous êtes inscrit dans la liste des personnes ayant accès à la partie privée du site Alma Musica</p>
    <p>Pour compléter cette inscription, cliquez sur le lien ci-dessous.</p>
    <a  style="display:table;margin:4pt auto;
 	background-color:gold;color:black;font-weigth:bold;text-align:center;
	border-radius:6pt;padding:6pt;"				
	href="https://www.alma-musica.net/inscription.php?code=%renewCode%">Complétez mon inscription</a>
</div>

Par expérience, j'évite de mettre une feuille de style dans les mails, de nombreux outils de messagerie ne les supportent pas.
Modifié par PapyJP (23 Sep 2021 - 15:37)
Bonjour,

L'on voit aujourd'hui plutôt un lien avec une valeur générée aléatoirement et une validité de quelques heures (12/24/48/...) qui accueil le nouvel inscrit sur la page de config de son profile où il doit au moins indiquer et enregistrer un mot de passe + d'autres infos essentielles selon ..) avant qu'il puisse accéder à la partie privée (en repassant éventuellement par un lien de validation , envoyer sur son mail , si besoin et pas trop barbant pour l'utilisateur.)

Cela évite un mot de passe en clair, mais donne quand même un lien éphémère.
On peut en profiter pour placer un mot sympa et y expliquer le fonctionnement du site, regle de conduite, etc...

Cdt
Modifié par gcyrillus (23 Sep 2021 - 14:35)
Bonjour à tous

Je gère le site d’une association où il y a une partie privée réservée aux membres de l’association. C’est l’administrateur du site qui inscrit les nouveaux membres. Un message est envoyé automatiquement aux nouveaux membres avec un mot de passe temporaire généré aléatoirement.
A l’époque où cela a été créé (il y a une vingtaine d’années) ça ne choquait personne de voir circuler un mot de passe (temporaire ou non) en clair par courriel.

Je voudrais votre avis sur la méthode à employer à savoir:
1 - conserver la méthode actuelle en renforçant le contrôle sur ce que peuvent accéder les membres tant qu’ils n’ont pas changé leur mot de passe
2 - envoyer un message d’inscription avec un lien vers une page où ils peuvent déclarer leur mot de passe, sachant que le mot de passe n’est de toute façon pas stocké en clair sur le site
3 - tout autre mécanisme dont vous auriez l’expérience dans une situation similaire

Merci de bien vouloir partager votre expérience
Salut,

pour mettre le contenu du fichier sélectonné, tu peux ajouter cette fonction js
export default class customFile{
static init(){
this.showFile();
}
static showFile(){
$('.custom-file-input').on('change', function (event) {
let inputFile = event.currentTarget;
$(inputFile).parent()
.find('.custom-file-label')
.html(inputFile.files[0].name);
});
}
}

et pour le browser, c'est du css, pa exemple si c'est du bootstrap 4 horizontal
label.custom-file-label{
&:after{
content: "Parcourir";
}
}
Loraga a écrit :
Hello,

À première vue j'aurais tendance à dire que $response n'est ni vide, ni null, c'est pourquoi ta condition retourne systématiquement false.

Du coup, que contient $response à cette étape du script ? Un petit var_dump($response) à ce moment pourrait sans doute aider Smiley smile


Merci pour cette réponse rapide !

j'ai bien un retour avec "var_dump($response);"

En cas de succès (token Google valide) :
1


En cas d'échec (token Google invalide ou déjà utilisé) :

/home/ifvm6740/dev/dev2/index.php:27:
object(stdClass)[1]
  public 'success' => boolean false
  public 'error-codes' => 
    array (size=1)
      0 => string 'timeout-or-duplicate' (length=20)
Bonjour à tous,

Sur un site web, j'ai une sidebar dans lequel j'ai ajouté une barre de recherche. Sur tous les principaux navigateurs et OS, son apparence est nickel, mais sous Safari avec iOS, le input search est arrondi, c'est affreux !

Voilà à quoi ressemble mon input sous Safari iOS :
upload/1632390113-68566-img4962.jpg

Et voilà à quoi ressemble mon input sous tous les autres navigateurs :
upload/1632390175-68566-capturedaeacran2021-09-23aa11.png

Il semblerait qu'on puisse palier à cette apparence par défaut, liée à iOS, avec les CSS suivants :
.sidebar-search-bar {
  border-radius: 0;
  -webkit-appearance: none;
}


Dans mon CSS, le border radius étant déjà déclaré, j'ai simplement ajouté le webkit-appearance: none puis vidé le cache de mon iPhone : rien n'y fait, c'est toujours pareil. Je ne pense pas être le seul à avoir rencontré ce souci, avez-vous donc une idée de quoi faire pour que mon input ait la même apparence sous Safari iOS que sur les autres navigateurs ?

Si cela peut aider, voici le CSS actuel de mon input :
.sidebar-search .sidebar-search-bar {
  padding: 10px;
  border: 1px solid #C0C0C0;
  border-radius: 4px 0 0 4px;
  float: left;
  width: 80%;
  background: #f1f1f1;
  margin-top: 0;
  height: 42px;
  -webkit-appearance: none;
}


Merci d'avance pour votre précieuse aide, comme d'habitude Smiley smile
Hello !

J'ai un script PHP qui permet de déterminer si un utilisateur est un robot ou non en vérifiant un token
$captcha_reponse;
à l'aide de Google reCAPTCHA v3.

Ce script fonctionne très bien, je l'utilise depuis déjà quelques mois.

Aujourd'hui j'aimerais l'utiliser par l'intermédiaire d'une fonction.

Ma fonction ne fonctionne pas; elle retourne systématiquement "false" résultat de la condition :
if(empty($response) || is_null($response)) { return false; }


Je l'impression que le problème viendrait de la portée d'une fonction/variable.

Voici la fonction :


function Captcha($captcha_reponse) {
    global $captcha_secret;
    if(empty($captcha_reponse)) {
        return false;
    } else {
        $url = "https://www.google.com/recaptcha/api/siteverify?secret={$captcha_secret}&response={$captcha_reponse}";
        if(function_exists("curl_version")) {
            $curl = curl_init($url);
            curl_setopt($curl, CURLOPT_HEADER, false);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl, CURLOPT_TIMEOUT, 1);
            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
            $response = curl_exec($curl);
        } else {
            $response = file_get_contents($url);
        }
            if(empty($response) || is_null($response)) {
            return false;
        } else {
            $data = json_decode($response);
            $score_captcha = $data->score;
            if($data->success) {
                return true;
            }
        }
    }
}


Voilà Smiley cligne
Maël
Modifié par maelstaudt (23 Sep 2021 - 11:50)
salut,
si tu cherches encore, pour faire une form de recherche dans la navbar, il faut faire un service qui retourne la vue de ton form ($form->createView()) si pas utilisé et ta page de résultat si utilisé
ex
class SearchFormService extends AbstractController
{
public function getSearchForm()
{
$form = $this->createForm(SearchType::class);
return $form->createView();
}
}

et dans twig extension

new TwigFunction('getSearchForm', [$this->searchFormService, 'getSearchForm']),
et dans ta navbar
{% set searchForm = getSearchForm() %}
Du coup j'ai ça:

public function addVals($tabs)
	{
		$i=0;
		foreach ($tabs as $value) {
			this->$vals[$i] = $value[$i];
			$i++;
		}
		return this->$vals;
	}

	/**
	 * Définit les valeurs du graph
	 * @param array $tabs tableau de valeur
	 */
	public function afficher() {

		/** --------------EXEMPLE-------------- **/

		
		// Définition des couleurs
		$this->ajouterCouleur(255,0,0,	'rouge');
		$this->ajouterCouleur(0,0,0,	'noir');

		// On trace les traits
		$j=0;
		for ($i=0; $i < count($vals); $i++) { 
			//taille du graph = 500, 500. Divisé par 4(4 valeurs du tableau) = 125
			$this->tracerTrait($j*125, $vals[$i], $j*125, $vals[$i], 'rouge');
			$j++;
		}
		/*
		$this->tracerTrait(0, 21, 0, 21, 'rouge');
		$this->tracerTrait(125, 42, 125, 42, 'rouge');
		$this->tracerTrait(250, 35, 250, 35, 'rouge');
		$this->tracerTrait(375, 0, 375, 0, 'rouge');*/

		$this->tracerTrait(0+5,500-5,0+5,10-5,'noir');
		$this->tracerTrait(0+5,500-5,490+5,500-5,'noir');

		/** ---------------------------------- **/

		// Affichage de l'image
		parent::afficher();
	}
}


et ça me met une erreur à cause du this->$vals
j'ai fait la même sans le this->, pas d'erreurs mais ça ne fonctionne pas pour autant
Merci pour ton retour.

Disons que ce n'est pas réellement un soucis. C'est simplement que je dois auditer l'accessibilité du seul site que mon groupe avait fait en externe, et je n'arrive pas à déterminer si, avoir le <footer role="contentinfo"> à l'intérieur du <main role="main"> faisait que le critère 9.2 du RGAA4 devenait Non Conforme :
https://www.numerique.gouv.fr/publications/rgaa-accessibilite/methode-rgaa/criteres#crit-9-2

Pourquoi il est dedans, je n'ai pas la réponse du coup sur le fait pourquoi ils ont fait ça (surement des devs qui n'ont pas de notions par rapport à la sémantique html à respecter).
Dans tous les cas, en action à mener je vais faire corriger ça Smiley ravi
Modifié par Tominside (23 Sep 2021 - 10:05)
Bonjour,

Pour faire ce que tu demandes (c'était pas très clair), je pense qu'il faut que tu fasses une fonction js pour changer la source de ton iframe avec une fonction js, un truc simple:
<script>
function changeSource(url){
let iframe = document.getElementById('ViRuS');
iframe.src = url;
}
</script>
et un bouton simple pour appeler la fonction (sans balise a)

<button onclick="changeSource('page 02.html')">test</button>

Si c'est bin ce que tu souhaite faire
Salut,

a priori il faudrait que tu suives un cours de Programmation Orienté Objet (POO) pour comprendre ce que tu fais Smiley ohwell

En gros $this cela fait référence à l'objet que tu as instancié et qui va te permettre d’accéder aux méthodes ou attributs de ton objets.

A priori dans ta fonction addVals, il faudra que tu fasses du push de tes valeurs dans $this->vals (même si je trouve bizarre qu'il ne soit pas définit comme un tableau mais bon)
Bonjour,
une question me taraude pour améliorer l'accessibilité d'un site internet dont je deviens responsable, cela concerne ce critère du RGAA 4.1, Critère 9.2. Dans chaque page web, la structure du document est-elle cohérente (hors cas particuliers) ?

Mon cas, le footer avec son
role="contentinfo"
se trouve dans le main role="main", du coup, est-ce que le critère devient Non Conforme car il devrait être après le
<main role="main">
ou est-ce que malgré tout Conforme ?

Lors de ma formation en accessibilité, j'avais pris ça comme note : Il faut que ce soit cohérent : si le main est dans le header, c’est un problème.
Mais dans ce cas, le footer qui se trouve dans le main... ?

Merci pour vos retours éclairés Smiley smile
Modifié par Tominside (22 Sep 2021 - 17:55)

<?php
	$root = $_SERVER['DOCUMENT_ROOT'];
	include_once "$root/html/common.php";
	$to = 'xxx@yyy.net';

$subject = 'Website Change Reqest';

$headers = "From: aaaa@zzz.net";
$headers .= "Reply-To: bbbb@zzz.net\r\n";
$headers .= "CC: dddd@zzz.net\r\n";
$headers .= "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: text/html; charset=UTF-8\r\n";

$message = '<p><strong>This is strong text</strong> while this is not.</p>';


$mailsent = mail($to, $subject, $message, $headers);
dump($mailsent);
?>

Réponse 'false'
50 Dernières réponses