PB sélection de données MySQL

PB sélection de données MySQL - PHP - Programmation

Marsh Posté le 22-11-2005 à 16:59:04    

Bonjour,
 
Je poursuit la progra de mon espace client et je suis un peu bloqué sur un truc basique.
Le client se connecte avec son login et password de la manière suivante:
 
<?
mysql_connect("localhost", "root", "" ); // Connexion à MySQL
mysql_select_db("mysql" ); // Sélection de la base mateo21
$table = mysql_query("SELECT * FROM clients_tbl WHERE LOGIN='$_POST[login]' AND PASSWORD='$_POST[motdepasse]'" );
$utilisateur = mysql("SELECT NOM FROM client-tbl WHERE LOGIN='$_POST[login]'" );
if(mysql_num_rows($table) == 1)
{
echo "Bienvenue $utilisateur";
}
else
{
?>
 
Mais la partie $utilisateur ne fonctionne pas et renvoi Warning: Wrong parameter count for mysql() in c:\wamp\www\omusic\php\login.php on line 5
 
Ma question est:
Lorsque que quelqu'un se logg, comment ensuite sélectionner les données qui ne corresponde qu'à son compte.
En fait je voudrais faire un compte client ou il puisse visualiser tous les détails de son compte.
 
Question sans doute con mais j'ai mal à la tête et suis un vrai amateur donc...
 
Merci d'avance

Reply

Marsh Posté le 22-11-2005 à 16:59:04   

Reply

Marsh Posté le 22-11-2005 à 17:02:10    

je viens trouver la première erreur: mysql => mysql_QUERY (putain je l'avais pas vu).
 
Bon n'empêche que ça ne sélectionne pas le nom de mon client quand même ?
 
Une idée ?

Reply

Marsh Posté le 22-11-2005 à 17:04:55    

Peut etre à cause de ' vu que en php il n'interprete les $ que entre " " et non entre ' ' mais vu que c'est de ' dans des " je ne sais pas ce que ca donne. Enfin si tu m a suivit dans les ' " ;-)

Reply

Marsh Posté le 22-11-2005 à 17:12:03    

J'ai revu le code et corriger quelques burnes mais bon ça change pas grand chose :
 
<?
mysql_connect("localhost", "root", "" ); // Connexion à MySQL
mysql_select_db("mysql" ); // Sélection de la base mysql
$table = mysql_query("SELECT * FROM clients_tbl WHERE LOGIN='$_POST[login]' AND PASSWORD='$_POST[motdepasse]'" );
$utilisateur = mysql_query("SELECT NOM FROM clients_tbl WHERE LOGIN='$_POST[login]'" );
if(mysql_num_rows($table) == 1)
{
echo "Bienvenue $utilisateur";
}
else
{
?>
 
Au final il renvoit Bienvenue Resource id#4
Tu connais pas la ligne standard pour sélectionner une donnée dans un dB d'un utilisateur qui vient de se logger ?
Peut-on le faire sans session ou cookie ?

Reply

Marsh Posté le 22-11-2005 à 17:15:33    

[:rtfm] http://www.nexen.net/docs/php/annotee/ref.mysql.php
mysql_fetch_array
mysql_fetch_assoc  
mysql_fetch_field  
mysql_fetch_object  
mysql_fetch_row
 
Tu vois, en cherchant un peu t'as le choix.

Reply

Marsh Posté le 22-11-2005 à 18:08:29    

Merci beaucoup. Ca fonctrionne effectivement pas mal.
Voici ma solution:
 
<?
mysql_connect("localhost", "root", "" ); // Connexion à MySQL
mysql_select_db("mysql" ); // Sélection de la base mysql
$table = mysql_query("SELECT ID, NOM, DEVIS, FACTURES, MAQUETTES, DOCS, MISE_A_JOUR FROM clients_tbl WHERE LOGIN='$_POST[login]' AND PASSWORD='$_POST[motdepasse]'" );
while ($row = mysql_fetch_array($table, MYSQL_ASSOC)) {
?>
 
puis j'affiche
 
<?
printf("%s ", $row["NOM"]);
?>
 
pour afficher le nom dans ma page.
 
Bon maintenant va falloir améliorer la sécurité mais merci pour votre aide.
 

Reply

Marsh Posté le 22-11-2005 à 18:20:26    

youp,
 
 
je crois que c'est mieux de vérifier le password dans le script (pas de la query sql):

Code :
  1. <?
  2. mysql_connect("localhost", "root", "" ); // Connexion à MySQL
  3. mysql_select_db("mysql" ); // Sélection de la base mysql
  4. $table = mysql_query("SELECT * FROM clients_tbl WHERE LOGIN='$_POST[login]'" );
  5. $row = mysql_fetch_array($table, MYSQL_ASSOC));
  6. if($_POST[motdepasse] == $row['PASSWORD']) {
  7.    echo $row['nom'];
  8. }
  9. else {
  10.   echo 'pas bien';
  11. }
  12. ?>

Reply

Marsh Posté le 22-11-2005 à 19:27:35    

Ouais pas mal effectivement pour la sécurité.
Le pb c que j'avais commencé à faire une protection au cas où un visiteur arrive directement sur la page et du coup je sais plus trop comment m'y prendre.
 
Pour l'instant, j'ai ça:
<?
// si le visteur est passé par la page connexion.php ou s'il s'est identifié en tombant directement sur cette page, on lui renvoit ses infos.
mysql_connect("localhost", "root", "" ); // Connexion à MySQL
mysql_select_db("mysql" ); // Sélection de la base mysql
 
// on vérifie que le login et le mot de passe rentrés sont correct
$table = mysql_query("SELECT * FROM clients_tbl WHERE LOGIN='$_POST[login]'" );
 
// $row = colonne de l'utilisateur dans la base
$row = mysql_fetch_array($table, MYSQL_ASSOC);
 
if($_POST[motdepasse] == $row['PASSWORD'])
{
?>
 
 
<!-- Début du squelette de la page html -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Espace Client
</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
<!--
body,td,th {
 font-family: Arial, Helvetica, sans-serif;
 font-size: 12px;
}
body {
 margin-left: 5px;
 margin-top: 0px;
}
a:link {
 color: #333333;
 text-decoration: underline;
}
a:visited {
 color: #333333;
 text-decoration: underline;
}
a:hover {
 color: #006699;
 text-decoration: none;
}
a:active {
 color: #333333;
 text-decoration: underline;
}
.Style1 {
 color: #FFFFFF;
 font-weight: bold;
}
-->
</style>
</head>
 
<body>
<p><strong><img src="file:///C|/wamp/images/titre_accueil.gif" height="30"></strong></p>
<p>Bienvenue
 
<?
// affichage du Nom du visiteur
echo $row['nom'];
?>
 
dans votre espace client, la zone priv&eacute;e des clients de O'MUSIC.
 
</p>
<p align="center" style="margin-bottom:0; margin-top:0 "><a href="../php/devisfactures.htm"><img src="file:///C|/wamp/images/btn_devis.jpg" width="181" height="100" border="0"></a><a href="../php/maquettes.htm"><img src="file:///C|/wamp/images/btn_maquettes.jpg" width="181" height="100" border="0"></a><a href="../php/docs.htm"><img src="file:///C|/wamp/images/btn_documents.jpg" width="181" height="100" border="0"></a><a href="../php/contact.htm"><img src="file:///C|/wamp/images/btn_contact.jpg" width="181" height="100" border="0"></a></p>
<p><strong>TABLEAU DE BORD</strong></p>
<table border="0" bgcolor="#CCCCCC">
  <tr bgcolor="#006699">
    <td><div align="center"><span class="Style1"> DEVIS</span></div></td>
    <td><div align="center"><span class="Style1">FACTURES</span></div></td>
    <td><div align="center" class="Style1">
      <div align="center">MAQUETTES</div>
    </div></td>
    <td><div align="center"><span class="Style1">DOCUMENTS</span></div></td>
    <td><div align="center"><span class="Style1">Derni&egrave;re mise &agrave; jour </span></div></td>
  </tr>
  <tr valign="top" bgcolor="#FFFFFF">
    <td> <div align="center">
 
<?
// affichage nbr de DEVIS
echo $row['DEVIS'];
?>
 
</div></td>
    <td><div align="center">
 
<?
// affichage nbr de FACTURES
echo $row['FACTURES'];
?>
 
 </div></td>
    <td><div align="center">
 
<?
// affichage nbr de MAQUETTES
echo $row['MAQUETTES'];
?>
 
 </div></td>
    <td><div align="center">
 
<?
// affichage nbr de DOCS
echo $row['DOCS'];
?>
 
 </div></td>
    <td><div align="center">
 
<?
// affichage de la dernière mise à jour dans la base de données
echo $row['MISE_A_JOUR'];
?>
    </div></td>
  </tr>
</table>
</body>
</html>
 
<?
}
 
 
else
{
?>
 
<!-- Début du formulaire de connexion -->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Document sans titre</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css">
<!--
body,td,th {
 font-family: Verdana, Arial, Helvetica, sans-serif;
 font-size: x-small;
}
-->
</style></head>
 
<body>
Veuillez entrer votre login
<form action="login.php" method="post">
  <p>LOGIN  
    <input name="login" type="text">
</p>
  <p>MOT DE PASSE
    <input name="motdepasse" type="text">
    <input name="Connexion" type="submit">
    </p>
</form>
</body>
</html>
<!-- Fin du formulaire de connexion -->
 
<?
}
mysql_close(); // Déconnexion de MySQL
?>
 
Mais ca marche pas super car ca n'affiche pas le renvoi du ELSE

Reply

Marsh Posté le 22-11-2005 à 19:31:48    

J'ai résolu mon truc en faisant:
 
if(isset($_POST['login']) AND $_POST['motdepasse'] AND $_POST['motdepasse'] == $row['PASSWORD'])
{
 
est-ce la bonne méthode ?

Reply

Marsh Posté le 22-11-2005 à 22:19:37    

Personellement, je ne stocke jamais le mot de passe en clair dans la base de donnée : en cas d'erreur de programmation, de trou de sécurité ou d'accés externe à la base, n'importe qui risquerait de se retrouver en possession de tous les mots de passes de tout le monde et même si c'est fortement déconseillé, beaucoup de gens utilisent le même mot de passe pour beaucoup de sites.
 
En bref, toujours coder le mot de passe dans la base de donnée, aprés, certain laissent la base de donnée s'occuper du codage (fonction password() dans la requette en général pour mysql) et d'autre le font faire par php (en génral, à l'aide de la fonction md5() de php)
 
Pour finir, afin de savoir si le mot de passe est valide, il suffit de comparer la version codé créé au moment de l'inscription (ou du changement du mot de passe) avec celle calculé au moment de la tentative de connection. Là on peut trés bien laisser faire la base de donnée et donc faire la comparaison dans la requette. C'est un peu plus sécurisé vu que la version du mot de passe codé ne transitera pas sur le réseau à chaque tentative de connection et en plus on a généralement pas besoin de savoir si c'est l'identifiant ou le mot de passe qu'est mauvais.

Reply

Marsh Posté le 22-11-2005 à 22:19:37   

Reply

Marsh Posté le 22-11-2005 à 22:53:04    

J'ai vu que la fct password de MySQL ne permet pas de revenir en arrireè donc de retrouver le code non crypté.
Donc il semblerait que le mieux soit ta fonction md5(). Mais ça marche comment?
Sur nexen.net ils parlent que de mail pour md5().
 
Je suis pas super balaise en code alors si tu peux m'en dire (notamment quelques lignes de code) ça m'arrange.
 
Merki

Reply

Marsh Posté le 22-11-2005 à 23:12:00    

omega2 a écrit :

Personellement, je ne stocke jamais le mot de passe en clair dans la base de donnée : en cas d'erreur de programmation, de trou de sécurité ou d'accés externe à la base, n'importe qui risquerait de se retrouver en possession de tous les mots de passes de tout le monde et même si c'est fortement déconseillé, beaucoup de gens utilisent le même mot de passe pour beaucoup de sites.
 
En bref, toujours coder le mot de passe dans la base de donnée, aprés, certain laissent la base de donnée s'occuper du codage (fonction password() dans la requette en général pour mysql) et d'autre le font faire par php (en génral, à l'aide de la fonction md5() de php)
 
Pour finir, afin de savoir si le mot de passe est valide, il suffit de comparer la version codé créé au moment de l'inscription (ou du changement du mot de passe) avec celle calculé au moment de la tentative de connection. Là on peut trés bien laisser faire la base de donnée et donc faire la comparaison dans la requette. C'est un peu plus sécurisé vu que la version du mot de passe codé ne transitera pas sur le réseau à chaque tentative de connection et en plus on a généralement pas besoin de savoir si c'est l'identifiant ou le mot de passe qu'est mauvais.


 
ca m'a l'air sensé :jap:  
 
(changeage de ma fonction d'identification :o )
 

wewen1 a écrit :

J'ai vu que la fct password de MySQL ne permet pas de revenir en arrireè donc de retrouver le code non crypté.
Donc il semblerait que le mieux soit ta fonction md5(). Mais ça marche comment?
Sur nexen.net ils parlent que de mail pour md5().
 
Je suis pas super balaise en code alors si tu peux m'en dire (notamment quelques lignes de code) ça m'arrange.
 
Merki


 

Code :
  1. $coucou = "midi";
  2. $coucou_md5 = md5($coucou);
  3. echo $coucou_md5;


 
 
donc tu mets la valeur md5 dans ta base de donnée et après tu compares avec md5($_POST[mot_de(passe)]) comme tu l'avais fait au début (dans la requete sql)


---------------
oui oui
Reply

Marsh Posté le 22-11-2005 à 23:12:57    

en fait, tu n'as pas besoin de revenir en arrière puisque tu compares les deux versions "codées" de ton mot de passe.
 
si  
 
pozurnpoznroaucrauzr"'"'é"'c"' == pozurnpoznroaucrauzr"'"'é"'c"'
 
alors c'est bon.


---------------
oui oui
Reply

Marsh Posté le 22-11-2005 à 23:17:48    

au fait j'aurais une question un peu tordue:
 
il n'y aurait pas un mot tel que le md5(ce mot) donne un truc utilisable pour une injection sql ?


---------------
oui oui
Reply

Marsh Posté le 22-11-2005 à 23:19:50    

wewen1 a écrit :

J'ai vu que la fct password de MySQL ne permet pas de revenir en arrireè donc de retrouver le code non crypté.
Donc il semblerait que le mieux soit ta fonction md5(). Mais ça marche comment?
Sur nexen.net ils parlent que de mail pour md5().
 
Je suis pas super balaise en code alors si tu peux m'en dire (notamment quelques lignes de code) ça m'arrange.
 
Merki

En général, on a pas besoin que ca soit réversible. Si t'as une colone motdepasse, à l'intérieur tu mettras

Code :
  1. password("saisie" )

et quand tu voudras comparer le mot de passe saisie pour l'identification à celui contenu dans la base de donnée, tu mettras dans la requette :

Code :
  1. where motdepasse=password("saisie" )


Bon, c'est vrai que le fait que ca soit pas réversible, ca a deux inconvénients :

  • si un visiteur à perdu son mot de passe, il faudra lui en généré automatiquement un nouveau et lui envoyer par mail
  • si on veut passer à une autre base de donnée, (passage de mysql à pgsql par exemple) il faudra regénéré tous les mots de passes et envoyé à chaque inscrit son nouveau mot de passe.


Pour md5, c'est simple :

Code :
  1. $passwordcrypte=md5($post["password"])

à l'inscription, on envoyé $passwordcrypte à la base de donnée, et à l'identification, on demande à la base de donné de comparer $passwordcrypte avec la valeur contenu dans la table.
 
PS : Pour md5, il y a aussi la variante

Code :
  1. $passwordcrypte=md5($post["password","cledecryptage"])

qui complique la récupération du mot de la valeur initiale à partir de la version codé.


Message édité par omega2 le 22-11-2005 à 23:21:26
Reply

Marsh Posté le 22-11-2005 à 23:27:56    

art_dupond a écrit :

au fait j'aurais une question un peu tordue:
 
il n'y aurait pas un mot tel que le md5(ce mot) donne un truc utilisable pour une injection sql ?


non, il y a aucun risque. :) le résultat d'un codage en md5 donne un résultat qu'est toujours de la même forme et c'est une forme qui ne ressemblera jamais à un bout de code sql.
En fait, même un md5("((update mysql.user set password=password('toto'), host="%" )=0) macol " ) ne pose aucun danger côté sql alors que si md5 n'était pas là, ca serait l'ouverture à un accés total au serveur mysql pour le pirate dés la prochaine relecture des droits d'accés et un blocage total pour toi dés ce moment là sauf en passant par le programme de réparation de mysql.
 
EDIT : requette non testé mais je dois pas être loin de la modif d'une requette permettant de modifier les droits d'utilisateurs.

Message cité 1 fois
Message édité par omega2 le 22-11-2005 à 23:31:00
Reply

Marsh Posté le 22-11-2005 à 23:34:05    

Oula, Oula, les gars!
 
Je reformule pour être spur d'avoir bien compris.
 
Je créé une page qui code mes mots de passe.
 
Du genre
<?
$motdepassenoncode = "dudul"
 
$motdepassecrypte = md5($motdepassenoncode)
?>
 
J'affiche ensuite la page, je récupère le mot de passe codé que je colle ensuite dans ma Bdd.
C'est pas un peu compliqué ça ?
 
Ca veut dire qu'à chaque fois que j'ai un nouveau client, je doit mettre le mot de passe "simple" dans ma variable $motdepassenoncode pour en connaitre la version md5.
Ca parait sécurisé mais pas super hergo.
 
Ai-je mal compris un truc ?

Reply

Marsh Posté le 22-11-2005 à 23:36:30    

En vous relisant, je me rend compte d'un truc:
en fait mon système est un espace client >> y a pas d'inscription.
j'ai trouvé une page sur le web donne automatiquement des mots de passe complexes.
En fait, je les copie et j'envois un mail à mon client pour lui donner son mot de passe.
Lui ne s'inscrit pas via l'espace.

Reply

Marsh Posté le 22-11-2005 à 23:44:38    

omega2 a écrit :

non, il y a aucun risque. :) le résultat d'un codage en md5 donne un résultat qu'est toujours de la même forme et c'est une forme qui ne ressemblera jamais à un bout de code sql.
En fait, même un md5("((update mysql.user set password=password('toto'), host="%" )=0) macol " ) ne pose aucun danger côté sql alors que si md5 n'était pas là, ca serait l'ouverture à un accés total au serveur mysql pour le pirate dés la prochaine relecture des droits d'accés et un blocage total pour toi dés ce moment là sauf en passant par le programme de réparation de mysql.
 
EDIT : requette non testé mais je dois pas être loin de la modif d'une requette permettant de modifier les droits d'utilisateurs.


 
oui bien sur que md5("((update mysql.user set password=password('toto'), host="%" )=0) macol " ) ne me donnera pas quelque chose d'utilisable mais je voulais savoir si par exemple
 
md5('tartempion') pouvait donner '' OR 1 ou un truc du genre, ce qui n'est apparemment pas possible.
 
 
sinon pour l'histoire des mots de passe qui transitent sur le réseau, en fait, dans aucun des deux cas ca ne transite sur le réseau non ?
 
enfin juste entre le serveur php et le serveur sql mais pas sur le ninternet. Je me trompe ?


---------------
oui oui
Reply

Marsh Posté le 22-11-2005 à 23:47:56    

@wewen1:
 
ce n'est pas vraiment compliqué.
 
en résumé, chaque fois que tu veux faire password, tu fais md5(password)
 
 
en gros...


---------------
oui oui
Reply

Marsh Posté le 22-11-2005 à 23:48:32    

Heu, là, je pige plus, comment tu fais pour savoir à qui envoyer des mails s'ils se sont inscrit nulle part?
 
Et si j'ai bien compris ce que tu fais :

  • premier script tu crés la valeur md5 du mot de passe et l'affiche dans une page
  • cette page apelle un second script qui inscrira le mot de passe dans la base de donnée.


Question : pourquoi ne pas envoyer directement la version codé dans la base de donnée depuis le premier script? D'autant plus que ta méthode telle que je l'ai comprise ouvre un énorme trou de sécurité possible vu que tu ne peux pas être sur que la valeur reçu par le second script ne soit pas une tentative d'attaque de type "sql injection".

Reply

Marsh Posté le 22-11-2005 à 23:58:31    

Vous avez raison mais en fait je ne fonctionne pas comme ça.
 
Je vend du service en communication (mais pas on line. l'espace c juste pour rendre la relation client plus interactive)
J'ai environ 20 clients pour l'instant.
J'en ai 1 ou 2 de nouveaux par mois.
Donc je rentre manuellement leur coordonnées dans ma base avec phpMyadmin.
C'est moi qui détermine le mot de passe et tout.
Et les mails je les connais car se sont des clients donc je traite déjà avec eux par mail avant de vendre.
 
Quand je serai grand (en php), je ferai un page d'enregistrement pour moi qui me permettra de rentrer des nouvelles données de manières plus hergo.
A ce moment là je ferai un script qui codera les mots de passe.
 
Pour l'instant je fais un peu d'artisannat et suis surtout en train d'apprendre le codage php.
 

Reply

Marsh Posté le 23-11-2005 à 00:02:18    

tu peux faire un md5() directement dans phpmyadmin ;)
 
tu rentres ta valeur puis tu choisis dans la drop box à gauche du champ: md5, et voilà :)
 
 


---------------
oui oui
Reply

Marsh Posté le 23-11-2005 à 00:06:33    

art_dupond a écrit :

oui bien sur que md5("((update mysql.user set password=password('toto'), host="%" )=0) macol " ) ne me donnera pas quelque chose d'utilisable mais je voulais savoir si par exemple
 
md5('tartempion') pouvait donner '' OR 1 ou un truc du genre, ce qui n'est apparemment pas possible.

le md5, tel que je l'ai dans ma base c'est une suite de 32 caractéres alphanumérique appartenant aux intervales [0-9][a-f]. DOnc pas de caractéres de ponctuation, pas d'espace et aucune lettre supérieure à "f". La fonction password de mysql 4.0.x et inférieur respectait la même régle mais sur 16 caractéres. Pour la fonction password de mysql 4.1 et supérieur, c'est sur 41 caractére, le premier est une étoile et les autres semblent répondre à la même norme que pour les autres (pas assez de codes différents en base pour êtrer sur à 100%)

art_dupond a écrit :


sinon pour l'histoire des mots de passe qui transitent sur le réseau, en fait, dans aucun des deux cas ca ne transite sur le réseau non ?
 
enfin juste entre le serveur php et le serveur sql mais pas sur le ninternet. Je me trompe ?

En fait, entre le navigateur et le serveur web, le mot de passe transitera de la même maniére. pour sécurisé cette partie là, il faut une liaison ssl (serveur https) Mais entre le serveur web (et donc le script php ) et la base de donnée, là, c'est sécurisable depuis le script php et avec les versions récentes de mysql, il est possible de crypter les échanges entre un client sql et le serveur mysql. mais je sais pas si php supporte cette possibilité. En tout cas, ce qui transite entre les deux, ca sera ce qu'on envéra à la base de donnée et ce qu'on lui demande comme retour.

Reply

Marsh Posté le 23-11-2005 à 00:09:26    

lol, j'ai du retard dans la discution. art_dupond a bien répondu.

Reply

Marsh Posté le 23-11-2005 à 01:01:54    

omega2 a écrit :


En fait, entre le navigateur et le serveur web, le mot de passe transitera de la même maniére. pour sécurisé cette partie là, il faut une liaison ssl (serveur https) Mais entre le serveur web (et donc le script php ) et la base de donnée, là, c'est sécurisable depuis le script php et avec les versions récentes de mysql, il est possible de crypter les échanges entre un client sql et le serveur mysql. mais je sais pas si php supporte cette possibilité. En tout cas, ce qui transite entre les deux, ca sera ce qu'on envéra à la base de donnée et ce qu'on lui demande comme retour.


 
ce que je voulais dire c'est que si les deux serveurs sont distants, ca transite par le réseau. Si c'est sur la meme machine, on s'en fout un peu. Mais bien sur, vaut mieux prendre des bonnes habitudes, toussa... :)


---------------
oui oui
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed