Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

integrer un script python a une page web

16 réponses
Avatar
Lulu
[XP : fr.comp.lang.php,fr.comp.lang.python,fr.comp.infosystemes.www.serveurs,fr.comp.infosystemes.www.auteurs]
[fu2 : fr.comp.lang.python ]

Salut,

J'ai écrit un très beau script python qui permet de tracer le spectre
lumineux d'un ou plusieurs éléments chimiques. Il requiert une
interaction avec l'utilisateur pour sélectionner longueur d'onde
initiale et finale, largeur en pixels, continu, émission ou absorption,
et élément(s) chimique(s) à choisir dans une liste.

Bref, ça ro><e sa mère...

Mais j'aimerais bien permettre aux visiteurs de mon site web (sous
apache2) de produire l'image de ce script sans être contraint de
reprogrammer tout ça en php... (je saurais faire, mais ça me semble un
peu stupide et l'occasion d'interfacer un script python avec une page
web me semble une opportunité d'apprendre des choses intéressantes).
(sans compter que j'aurais le script python et le script php à
maintenir...)

Dans mes rêves, je créé une page web avec 4 zones de saisie, 3 boutons
radios, une dizaine de cases à cocher, un morceau de php pour récupérer
tout ça et appeler mon script en python qui fabrique l'image, image qui
serait affichée une seconde plus tard dans la page web.

Oui, mais comment interfacer un script python (exécuté côté serveur)
avec une page web permettant de saisir les paramètres et de récupérer
l'image tracée ?

Partage de code:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

# Auteur : <h.fertin@ac-rouen.fr>, Lycée Jules Siegfried, Le Havre
# Creative Commons : https://creativecommons.org/licenses/by-nc-sa/2.0/fr/
# Attribution :: Pas d'utilisation commerciale :: Partage dans les mêmes conditions

#################### MODE D'EMPLOI #####################################
# on obtient un spectre continu (saisir 1 quand c'est demandé),
# d'émission (saisir 2) ou d'absorption (saisir 3 ou rien).
#
# On peut saisir la longueur d'onde de départ et celle de fin, ce qui
# permet de "zoomer" pour séparer des raies.
#
# On peut choisir la largeur et la hauteur de l'image en pixels.
#
# On peut choisir d'afficher le spectre d'un ou plusieurs éléments.
#
# Le script permet d'enregistrer l'image calculée au format PNG.
#
# les constantes ci-dessous permettent de ne pas saisir à chaque fois
# les mêmes données : ce sont des valeurs par défaut aisées à modifier.
#
# Toute idée d'amélioration est bienvenue !!
#
# samedi 8 février 2020, 14:34:11 (UTC+0100)
# ajout d'un test pour n'ajouter à la liste_de_toutes_les_raies que les
# raies comprises entre WL_start et WL_end.
# Tri de cette liste dans l'ordre croissant.
# Ajout des accents au nom des éléments.

CONST_WL_START = 380
CONST_WL_END = 800
CONST_NB_PIXELS_LARGEUR = 1260
CONST_NB_PIXELS_HAUTEUR = 160
# Le fichier de fonte doit être présent dans le répertoire du script !
CONST_FONTE = 'courbd.ttf'
# CONST_IMPRIME_NOM_ELEMENT vaut soit True soit False
CONST_IMPRIME_NOM_ELEMENT = True


import sys
from datetime import datetime
from PIL import Image, ImageDraw, ImageFont


def color_of_ray( WL ):
rouge = int( 0 )
vert = int( 0 )
bleu = int( 0 )
if WL >=380 and WL < 420:
diviseur = 60
amplification = 0.3 + 0.7 * ( WL - 380) /40
rouge = int( amplification * 255 * ( 440 - WL ) / diviseur )
vert = int( 0 )
bleu = int( amplification * 255 )

elif WL >=420 and WL < 440:
diviseur = 60
rouge = int( 255 * ( 440 - WL ) / diviseur )
vert = int( 0 )
bleu = int( 255 )

elif WL >= 440 and WL < 490:
diviseur = 50
rouge = int( 0 )
vert = int( 255 * ( WL - 440 ) / diviseur )
bleu = int( 255 )

elif WL >= 490 and WL < 510:
diviseur = 20
rouge = int( 0 )
vert = int( 255 )
bleu = int( 255 * ( 510 - WL ) / diviseur )

elif WL >= 510 and WL < 580:
diviseur = 70
rouge = int( 255 * ( WL - 510 ) / diviseur )
vert = int( 255 )
bleu = int( 0 )

elif WL >= 580 and WL < 645:
diviseur = 65
rouge = int( 255 )
vert = int( 255 * ( 645 - WL ) / diviseur )
bleu = int( 0 )

elif WL >= 645 and WL < 700:
rouge = int( 255 )
vert = int( 0 )
bleu = int( 0 )

elif WL >= 700 and WL < 800:
amplification = 0.3 + 0.7 * ( 800 - WL) / 100
rouge = int( amplification * 255 )
vert = int( 0 )
bleu = int( 0 )

return (rouge, vert, bleu)


print('\n ******************************')
print(' * Tracé de spectres lumineux *')
print(' ******************************\n')


# WL_start et WL_end sont les deux valeurs de longueur d'onde du spectre
# (demandées à l'utilisateur), exprimées en nanomètres (nm)
# test pour vérifier que l'utilisateur saisi bien un nombre entier
while True:
x = input( "Longueur d'onde initiale (en nanomètre) ? " )
if x == "":
x = CONST_WL_START
try:
WL_start = int(x)
break
except ValueError:
print( " Saisir un nombre ENTIER !!!")
pass

while True:
x = input( "Longueur d'onde finale (en nanomètre) ? " )
if x == "":
x = CONST_WL_END
try:
WL_end = int(x)
break
except ValueError:
print( " Saisir un nombre ENTIER !!!" )
pass

if WL_end < WL_start:
swap = WL_start
WL_start = WL_end
WL_end = swap
print( " --> bourriquot !" )

# on se limite évidemment au spectre visible
if WL_start < 380:
WL_start = 380
if WL_end > 800:
WL_end = 800

print(" -->", WL_start, "nm à", WL_end, "nm")
WL_range = WL_end - WL_start
print(" --> range :", WL_range, "nm")

# nb_pixels_largeur est une valeur (entière !!) demandée à l'utilisateur,
# typiquement 400, 800 ou 1200 px
# les pixels seront numérotés de pixel(0) à pixel(nb_pixels_largeur - 1)
while True:
x = input( "Largeur du spectre (en pixel) ? " )
if x == "":
x = CONST_NB_PIXELS_LARGEUR
try:
nb_pixels_largeur = int(x)
break
except ValueError:
print( " Saisir un nombre ENTIER !!!" )
pass

while True:
x = input( "Hauteur du spectre (en pixel) ? " )
if x == "":
x = CONST_NB_PIXELS_HAUTEUR
try:
nb_pixels_hauteur = int(x)
break
except ValueError:
print( " Saisir un nombre ENTIER !!!" )
pass

s = nb_pixels_largeur * nb_pixels_hauteur
print(" --> taille de l'image :", nb_pixels_largeur, "px x", nb_pixels_hauteur ,"px =", s, "px²")

# WL_resolution est le nombre de nanomètre que représente un pixel
WL_resolution = ( WL_range ) / ( nb_pixels_largeur )
print(" --> Résolution : {0:.2e}".format(WL_resolution), "nm/pixel")

# une fois connue la largeur du spectre en pixels, création de deux listes
# contenant la valeur en nanomètres du début du pixel et de la fin du pixel
WL_list_start = []
WL_list_end = []
for i in range(nb_pixels_largeur):
WL_list_start.append( WL_start + i * WL_resolution )
WL_list_end.append( WL_start + ( i + 1 ) * WL_resolution )


print("")
while True:
print( "1 --> spectre continu ;" )
print( "2 --> spectre d'émission ;" )
print( "3 --> spectre d'absorption." )
choix = input( "Choix ? " )
if choix == "":
choix = "3"
try:
if choix == "1" or choix == "2" or choix == "3":
break
except ValueError:
print(' Saisir un nombre ENTIER !!!')
pass

if choix == "1":
element = ""
choix_spectre = "continu"
couleur_graduation = ( 0, 0, 0 )
print( " --> Spectre continu\n" )
if choix == "2":
choix_spectre = "emission"
couleur_graduation = ( 255, 255, 255 )
print( " --> Spectre d'émission\n" )
if choix == "3":
choix_spectre = "absorption"
couleur_graduation = ( 0, 0, 0 )
print( " --> Spectre d'absorption\n" )


# raies trouvées sur
# https://media4.obspm.fr/public/ressources_lu/pages_tp-spectre-soleil/identification.html
liste_de_toutes_les_raies=[]
liste_elements=[]
if not choix == "1":
print( "Éléments chimiques disponibles : H,He,Li,Na,Mg,Ar,Ca,Ti,Mn,Fe,Hg")
print( "(il est possible de saisir plusieurs éléments en les séparant par des")
print( "virgules, sans espace)")
saisie_elements = input( "Symbole de l'élément chimique ? " )
# le cas d'une liste qui comporterait un élément inconnu n'est pas traité car la seule
# conséquence est que cet élément inconnu apparaîtra dans le nom du fichier : c'est
# donc une "feature" qui permet d'ajouter un commentaire dans le nom du fichier.
if ',' in saisie_elements:
liste_elements = saisie_elements.split(",")
else:
liste_elements.append(saisie_elements)

if saisie_elements == "":
liste_elements = ["Ca"]

nom_element = ""
for ze_element in liste_elements:
# Pas d'intensité de raies (pour l'instant)
if ze_element == "H":
nom_element = "Hydrogène "
liste_raies = [ 388.9, 397, 410.2, 434.1, 486.1, 656.3 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "He":
nom_element = nom_element + "Hélium "
liste_raies = [ 447, 468.5, 471.5, 492, 501.5, 587.5, 668 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Li":
nom_element = nom_element + "Lithium "
liste_raies = [ 496, 549, 610, 671 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Na":
nom_element = nom_element + "Sodium "
liste_raies = [ 568.8, 589, 589.6, 615.4 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Mg":
nom_element = nom_element + "Magnésium "
liste_raies = [ 516.7, 517.3, 518.4 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Ar":
nom_element = nom_element + "Argon "
liste_raies = [ 452, 472, 562, 605, 644, 670 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Ca":
nom_element = nom_element + "Calcium "
liste_raies = [ 393.3, 396.9, 425, 433, 447, 588, 589, 614, 618, 646, 648, 674, 717, 735 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Ti":
nom_element = nom_element + "Titane "
liste_raies = [ 466.8, 469.1, 498.2 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Mn":
nom_element = nom_element + "Manganèse "
liste_raies = [ 402.1, 403.1, 403.6 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Fe":
nom_element = nom_element + "Fer "
liste_raies = [ 389.9, 404.6, 423.4, 425.1, 426, 427.2, 438.3, 452.9, 459.3, 489.1, 491.9, 495.7, 501.2, 508, 527, 532.8, 536.7, 536.9, 543, 543.4, 544.7, 545.6, 561.6 ]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

elif ze_element == "Hg":
nom_element = nom_element + "Hydrargyrum"
liste_raies = [ 404.7, 435.8, 546.1, 577, 579.1]
for raie in liste_raies:
if raie >= WL_start - 1 and raie <= WL_end +1 :
liste_de_toutes_les_raies.append(raie)

# tri de la liste de toutes les raies par ordre croissant
x = liste_de_toutes_les_raies.sort()

else:
# j'imprime le nom de l'élément sur le spectre, donc rien
# s'il s'agit d'un spectre continu
element = ""
nom_element = ""


#creation en mémoire de l'image du spectre
try:
spectre_image = Image.new( "RGB", ( nb_pixels_largeur, nb_pixels_hauteur) )
except:
print('\n' * 2)
print(" Erreur, impossible de créer une image de ", nb_pixels_largeur, "pixels de large et", nb_pixels_hauteur, "pixels de haut")
print('\n' * 2)
sys.exit(1)

now = datetime.now()
timestamp_debut = datetime.timestamp(now)

draw = ImageDraw.Draw(spectre_image)

if choix_spectre == "continu":
for i in range(nb_pixels_largeur):
WL_middle = ( WL_list_start[i] + WL_list_end[i] ) / 2
draw.line(( i, 0, i, nb_pixels_hauteur ), fill = color_of_ray( WL_middle ))
else:
print( " --> Liste des raies pour ", liste_elements, ": ", end='')
for i in liste_de_toutes_les_raies:
print( i, "nm ; ", end = '')

print('')
print(" -->", len(liste_de_toutes_les_raies), "raies à tracer")


# La largeur d'une raie dépend de la valeur de WL_resolution de manière
# à séparer les raies mitoyennes quand on "zoome" en demandant une
# étendue faible en nanomètre mais élevée en pixels.
# Mais je voudrais qu'une raie soit large d'un nombre impair de pixels...
# Sur la TODO list !
if choix_spectre == "emission":
for i in range(nb_pixels_largeur):
WL_middle = ( WL_list_start[i] + WL_list_end[i] ) / 2
for raie in liste_de_toutes_les_raies:
# if abs( WL_middle - raie ) <= 0.5:
if abs( WL_middle - raie ) <= ( 2 * WL_resolution ):
draw.line(( i, 0, i, nb_pixels_hauteur ), fill = color_of_ray( WL_middle ))


if choix_spectre == "absorption":
for i in range(nb_pixels_largeur):
WL_middle = ( WL_list_start[i] + WL_list_end[i] ) / 2
draw_the_ray = True
for raie in liste_de_toutes_les_raies:
# if abs( WL_middle - raie ) <= 0.5:
if abs( WL_middle - raie ) <= ( 2 * WL_resolution ):
draw_the_ray = False # on est à moins de 0,5 nm d'une raie : laisser noir

if draw_the_ray:
draw.line(( i, 0, i, nb_pixels_hauteur ), fill = color_of_ray( WL_middle ))


font = ImageFont.truetype(CONST_FONTE, 14)
draw = ImageDraw.Draw(spectre_image)
Comment = "from " + str( WL_start ) + " nm to " + str( WL_end ) + " nm"

if choix_spectre == "emission":
# fond noir
draw.text((10.0, 10.0), Comment, couleur_graduation, font=font)
if CONST_IMPRIME_NOM_ELEMENT:
draw.text((10.0, 22.0), nom_element, couleur_graduation, font=font)
else:
# fond coloré
draw.text((9.0, 9.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((9.0, 10.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((9.0, 11.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((10.0, 9.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((10.0, 11.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((11.0, 9.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((11.0, 10.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((11.0, 11.0), Comment, ( 255, 255, 255 ), font=font)
draw.text((10.0, 10.0), Comment, couleur_graduation, font=font)

if CONST_IMPRIME_NOM_ELEMENT:
draw.text((9.0, 21.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((9.0, 22.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((9.0, 22.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((10.0, 21.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((10.0, 23.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((11.0, 21.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((11.0, 22.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((11.0, 23.0), nom_element, ( 255, 255, 255 ), font=font)
draw.text((10.0, 22.0), nom_element, couleur_graduation, font=font)


# tracé des graduations
hauteur_dizaine = nb_pixels_hauteur // 16 # un trait court pour 10 nm
hauteur_cinquantaine = nb_pixels_hauteur // 8 # un trait moyen pour 50 nm
hauteur_centaine = nb_pixels_hauteur // 4 # un trait long pour 100 nm
base = nb_pixels_hauteur # base du trait
# couleur_graduation a été déterminée au moment du choix de type de spectre

# largeur d'un trait de graduation en pixel :
# impair
# peu ou prou égal à un nanomètre donc (presque égal à 1 / WL_resolution)

WL_res_inverse = 1 / WL_resolution
if int( WL_res_inverse ) % 2 == 0: # pair
largeur_graduation = int( WL_res_inverse ) + 1
else: # impair
largeur_graduation = int( WL_res_inverse )

# graduation sur le premier pixel ? (donc i = 0)
if WL_start % 100 == 0:
draw.line(( 0,base,0,base-hauteur_centaine),fill=couleur_graduation)
draw.rectangle(((0, base),(((largeur_graduation-1)/2),base-hauteur_centaine+1)), fill=couleur_graduation )
elif WL_start % 50 == 0:
draw.line((0,base,0,base-hauteur_cinquantaine),fill=couleur_graduation)
draw.rectangle(((0,base),(((largeur_graduation-1)/2),base-hauteur_cinquantaine+1)),fill=couleur_graduation)
elif WL_start % 10 == 0:
draw.line((0,base,0,base-hauteur_dizaine),fill=couleur_graduation )
draw.rectangle(((0,base),(((largeur_graduation-1)/2),base-hauteur_dizaine+1)),fill=couleur_graduation)


for i in range(nb_pixels_largeur):
# un trait vertical quand passer de WL_list_start[i] à WL_list_end[i] fait
# changer de dizaine sur les nanomètres...
if int( WL_list_start[i] // 100 ) != int( WL_list_end[i] // 100 ):
# changement de centaine sur les nanomètres
draw.line((i,base,i,base-hauteur_centaine),fill=couleur_graduation)
draw.rectangle(((i-((largeur_graduation-1)/2),base),(i+((largeur_graduation-1)/2),base-hauteur_centaine+1)),fill=couleur_graduation)

elif int( WL_list_start[i] // 50 ) != int( WL_list_end[i] // 50 ):
# changement de cinquantaine sur les nanomètres
draw.line((i,base,i,base-hauteur_cinquantaine),fill=couleur_graduation)
draw.rectangle(((i-((largeur_graduation-1)/2),base),(i+((largeur_graduation-1)/2),base-hauteur_cinquantaine+1)),fill=couleur_graduation)

elif int( WL_list_start[i] // 10 ) != int( WL_list_end[i] // 10 ):
# changement de dizaine sur les nanomètres
draw.line((i,base,i,base-hauteur_dizaine),fill=couleur_graduation)
draw.rectangle(((i-((largeur_graduation-1)/2),base),(i+((largeur_graduation-1)/2),base-hauteur_dizaine+1)),fill=couleur_graduation)


now = datetime.now()
timestamp_fin = datetime.timestamp(now)
duree = timestamp_fin - timestamp_debut
print('\ndone in =',"{:0.3f}".format(duree),"seconde(s)")

spectre_image.show()

x = input( "Enregistrer l'image ? (Y/n) ")
if x == "":
x = "Y"

if x[0] == "Y" or x[0] == "y" or x[0] == "O" or x[0] == "o":
nom_image = "Spectre_" + choix_spectre + "_" + str(WL_start) + "_to_" + str(WL_end)

if choix_spectre == "emission" or choix_spectre == "absorption":
for ze_element in liste_elements:
nom_image = nom_image + "_" + ze_element

year = now.year
month = now.month
if month < 10:
month = "0" + str( month )
day = now.day
if day < 10:
day = "0" + str( day )
hour = now.hour
if hour < 10:
hour = "0" + str( hour )
minute = now.minute
if minute < 10:
minute = "0" + str( minute )
second = now.second
if second < 10:
second = "0" + str( second)
nom_image = nom_image + "_" + str(year) + "-" + str(month) + "-" + str(day)
nom_image = nom_image + "_" + str(hour) + str(minute) + str(second) + str(".png")

spectre_image.save( nom_image, "PNG" )
print("Enregistré sous :", nom_image)

6 réponses

1 2
Avatar
Lulu
Le 14-02-2020, Nicolas a écrit :
Il ne te reste plus qu'à mettre la page en question en ligne pour
qu'on puisse jouer avec :)

Avec le trou de sécurité qu'il vient d'introduire dans sa machine, il
vaudrait mieux pas.

Peux-tu préciser ?
Avatar
Nicolas
Le 14/02/2020 à 08:42, Lulu a écrit :
Le 14-02-2020, Nicolas a écrit :
Il ne te reste plus qu'à mettre la page en question en ligne pour
qu'on puisse jouer avec :)

Avec le trou de sécurité qu'il vient d'introduire dans sa machine, il
vaudrait mieux pas.

Peux-tu préciser ?

La fonction system() permet de lancer n'importe quelle commande dans un
bash.
En programmation classique, elle est à éviter autant que possible (il y
a d'autres solutions).
En programmation WEB, elle est à proscrire.
Un exemple simple : Ton script PHP récupère les informations saisies sur
la page WEB et appelle system("python mon_script %d, %d, %s" % (param_x,
param_y, param_titre)
Sauf que moi, je suis un vilain et je fais un appel à ton script avec
les paramètres x, y et titre="Mon_titre; commande_malicieuse"
(dans la requête http).
Résultat, tu as un appel système avec :
python mon_script 10 20 Mon_titre; commande_malicieuse
Ton script sera exécuté et commande_malicieuse aussi.
Je ne suis absolument pas un spécialiste de ce genre de choses. Il y a
sûrement beaucoup plus de possibilités. Ce qui est sûr, c'est que
system() est à proscrire. D'ailleurs, dans la documentation, c'est bien
précisé dans les notes : https://www.php.net/manual/fr/function.system.php
Nicolas
Avatar
Lulu
Le 09-02-2020, Jo Engo a écrit :
Le Sat, 08 Feb 2020 21:54:18 +0100, Lulu a écrit :
Creative Commons

Pourquoi choisir cc plutôt que la GPL pour un programme ?

Je te retourne la question :
quels avantages auraient-je pu tirer d'une publication sous GPL ?
Avatar
Lulu
Le 14-02-2020, Nicolas a écrit :
Le 14/02/2020 à 08:42, Lulu a écrit :
Le 14-02-2020, Nicolas a écrit :
Il ne te reste plus qu'à mettre la page en question en ligne pour
qu'on puisse jouer avec :)

Avec le trou de sécurité qu'il vient d'introduire dans sa machine,
il vaudrait mieux pas.

Peux-tu préciser ?

La fonction system() permet de lancer n'importe quelle commande dans
un bash.

Ah ? <mode naïf=on>
La fonction system ne contient pourtant que les variables sélectionnées
par mon formulaire.
En programmation classique, elle est à éviter autant que possible (il y
a d'autres solutions).

Qu'elles sont-elles ?
En programmation WEB, elle est à proscrire.

Je veux bien te croire.
Un exemple simple : Ton script PHP récupère les informations saisies sur
la page WEB et appelle system("python mon_script %d, %d, %s" % (param_x,
param_y, param_titre)
Sauf que moi, je suis un vilain et je fais un appel à ton script avec
les paramètres x, y et titre="Mon_titre; commande_malicieuse"
(dans la requête http).

Mon script n'utilise pas le passage de paramètres par requête http.
(Moi newbie : excuser que je ne comprenne pas)
Résultat, tu as un appel système avec :
python mon_script 10 20 Mon_titre; commande_malicieuse
Ton script sera exécuté et commande_malicieuse aussi.

Je comprends bien qu'un indélicat pourrait saisir du code malicieux dans
les zones de saisie, mais je ne comprends pas comment ce code envoyé en
paramètre à mon script python fonctionnerait et comme mon script PHP
vérifie que ce qui est saisi est une valeur entière, je ne vois pas
comment on pourrait y injecter du code pourrave.
(Mais je ne demande qu'à apprendre)
Je ne suis absolument pas un spécialiste de ce genre de choses. Il y
a sûrement beaucoup plus de possibilités. Ce qui est sûr, c'est que
system() est à proscrire. D'ailleurs, dans la documentation, c'est
bien précisé dans les notes :
https://www.php.net/manual/fr/function.system.php

Chouette !! De la lecture.
Merci de ton intervention.
Nicolas

Hugues.
Avatar
Lulu
Le 14-02-2020, Lulu a écrit :
Le 14-02-2020, Nicolas a écrit :
Je ne suis absolument pas un spécialiste de ce genre de choses. Il y
a sûrement beaucoup plus de possibilités. Ce qui est sûr, c'est que
system() est à proscrire. D'ailleurs, dans la documentation, c'est
bien précisé dans les notes :
https://www.php.net/manual/fr/function.system.php

Chouette !! De la lecture.
Merci de ton intervention.

Ouébof...
Il faudrait utiliser la fonction "passthru()" plutôt que system() selon
"https://www.php.net/manual/fr/function.passthru.php"...
Par quel mystère passthru() serait "invulnérable" quand system()
serait une passoire ?
Nicolas

Hugues.

Hugues
Avatar
Nicolas
Le 14/02/2020 à 22:13, Lulu a écrit :
Le 14-02-2020, Nicolas a écrit :
Le 14/02/2020 à 08:42, Lulu a écrit :
Le 14-02-2020, Nicolas a écrit :


Il ne te reste plus qu'à mettre la page en question en ligne pour
qu'on puisse jouer avec :)

Avec le trou de sécurité qu'il vient d'introduire dans sa machine,
il vaudrait mieux pas.

Peux-tu préciser ?

La fonction system() permet de lancer n'importe quelle commande dans
un bash.

Ah ? <mode naïf=on>
La fonction system ne contient pourtant que les variables sélectionnées
par mon formulaire.

C'est ce que tu penses parce que tu as conçu ton script PHP pour
fonctionner avec ta page WEB. Mais une personne mal intentionnée peut
appeler ton script PHP avec ses propres données.
En programmation classique, elle est à éviter autant que possible (il y
a d'autres solutions).

Qu'elles sont-elles ?

https://docs.python.org/3/library/os.html#os.system
En programmation WEB, elle est à proscrire.

Je veux bien te croire.
Un exemple simple : Ton script PHP récupère les informations saisies sur
la page WEB et appelle system("python mon_script %d, %d, %s" % (param_x,
param_y, param_titre)
Sauf que moi, je suis un vilain et je fais un appel à ton script avec
les paramètres x, y et titre="Mon_titre; commande_malicieuse"
(dans la requête http).

Mon script n'utilise pas le passage de paramètres par requête http.
(Moi newbie : excuser que je ne comprenne pas)

Et toi comment faire pour passer des infos de ta page WEB à ton script ?
Par une requête http.
Résultat, tu as un appel système avec :
python mon_script 10 20 Mon_titre; commande_malicieuse
Ton script sera exécuté et commande_malicieuse aussi.

Je comprends bien qu'un indélicat pourrait saisir du code malicieux dans
les zones de saisie, mais je ne comprends pas comment ce code envoyé en
paramètre à mon script python fonctionnerait et comme mon script PHP
vérifie que ce qui est saisi est une valeur entière, je ne vois pas
comment on pourrait y injecter du code pourrave.
(Mais je ne demande qu'à apprendre)

Je ne suis pas un spécialiste. J'ai juste quelques bases.
Disons que si tu fais un spawn() (ou autre joyeuseté) seul le programme
lancé peut être exécuté. La dangerosité dépend de ce que fait le
programme lancé (associé aux paramètres).
Avec system(), TOUS les programmes du système (d'où le nom de la
fonction) peuvent être exécutés. La moindre faille peut devenir
catastrophique.
Je ne suis absolument pas un spécialiste de ce genre de choses. Il y
a sûrement beaucoup plus de possibilités. Ce qui est sûr, c'est que
system() est à proscrire. D'ailleurs, dans la documentation, c'est
bien précisé dans les notes :
https://www.php.net/manual/fr/function.system.php

Chouette !! De la lecture.
Merci de ton intervention.

Pas de quoi :)
Nicolas

Hugues.
1 2