Construction de base de données avec Perl/MySQL - exemple d'une petite base de données d'interactions protéines-protéines

Olivier Elemento

Attention : ce document est loin d'être complet, et évolue selon le temps que j'ai a y consacrer. Si vous avez une question particulière liée au contenu de ce document, ou plus généralement au domaine de la Bioinformatique, vous pouvez la poser sur le forum de Bioinformatique associé.


Table of Contents

1. Construction de base de données
Choix technologiques
Pourquoi Apache ?
Pourquoi Perl ?
Pourquoi MySQL ?
Création de la base de données
Conception Merise et diagrammes
Création de la base de données et des tables
Entrer des données dans la base
Entrer de nouvelles données via SQL
Entrer de nouvelles données via Perl et SQL
Définir un formulaire HTML d'entrée de donnée
Construire le script Perl correspondant
Constrôle des données entrées via le formulaire
Interroger la base
Bonus : utilisation des logs Apache et Perl
Comment trouver les erreurs dans les scripts Perl ?
Qui consulte votre base de données ?
Interfacer des outils externes : BLAST

Chapter 1. Construction de base de données

Avant de commencer la construction d'une base de données d'objets biologiques, il est nécessaire de se poser un certain nombre de questions. Par exemple :

ce type de base existe-t-il deja? si oui, quel avantage y a-t-il à proposer une nouvelle base de données?

Comment se déroulera le recueil de l'information et l'entrée de ces informations dans la base ? d'ou viennent les données et qui va les rentrer? cela va-t-il se faire de manière automatique, ou bien faudra-t-il une armée d'annotateurs aux connaissances pointues? L'expérience montre que le tout automatique ne fournit pas des résultats de qualité, du fait de manque de standardisation, des imprécisions, ou des erreurs dans la chaîne de saisie. D'une manière générale, l'annotation automatique est aujourd'hui difficile voire impossible.

Quelles requètes et quels types de sorties seront nécéssaires ? à quel public se destine cette base de données? il faut pour cela étudier des interfaces utilisateurs conviviales, faciles à utiliser, et adaptées au public visé.

Pour illustrer , nous allons construire une simple base de données de protéines et d'interactions protéine-protéine. Ce type de base de données existe bien évidemment déjà (ProNet par exemple). Néanmoins, une telle base peut avoir un interet dans un domaine spécifique.

Une telle base de données définit un type principal d'objet : la protéine. Une protéine peut être décrite par un très grand nombre de critères. Dans le cadre de cette base, nous décrirons une protéine comme possédant un nom complet et un nom raccourci, une fonction sous la forme d'un texte descriptif, une séquence d'acides aminés, un code PDB correspondant à une structure associée dans la base de données PDB, ainsi qu'un numéro d'accès SWISSPROT.

Nous considérerons également qu'une protéine peut se voir associer un nombre variable de publications, représentées par leur numéro d'accès dans PUBMED.

Enfin, nous considérerons que les protéines peuvent interagir deux à deux, et que cette interaction peut faire l'objet d'une description ou commentaire dans la base.

Choix technologiques

  • le système de gestion de base de données : il s'agit du coeur des bases de données. Il existe trois types de bases de données: les bases de données relationnelles, les bases de données purement objet (ozone), et les bases de données relationnel-objet. Un quatrième type de base de données est néanmoins en train d'emerger, il s'agit de bases permettant de stocker des données au format XML de manière native.
  • la plateforme ou système d'exploitation
  • le serveur web, si cette base de données doit être accessible au travers d'un interface web (soumission de données ou interrogation)
  • le serveur d'application, dont le role est de permettre l'extraction de données à partir de la base en fonction des requètes effectuées par l'utilisateur, puis la construction automatique de pages HTML à partir de ces mêmes données.

Figure 1.1. PROTDB

Nous utiliserons, dans l'exemple qui suit, un serveur web Apache, le serveur applicatif Perl, ainsi qu'une base de données MySQL. Ces logiciels sont gratuits, très performants et utilisés dans de très nombreux projets de base de données. Autre argument important, tous ces logiciels sont disponibles pour les plateformes courantes (Windows, Linux, etc.).

Pourquoi Apache ?

En ce qui concerne le serveur web, le choix est plutot restreint. Outre sa gratuité et sa disponibilité, Apache a depuis longtemps fait les preuves de sa robustesse, de sa rapidité et de sa stabilité. En outre, il offre une sécurité maximale sous Windows comme sous Unix.

Pourquoi Perl ?

Très utilisé dans le domaine de la bioinformatique, Perl est certainement l'un langage de programmation les plus simples à apprendre. Il existe de nombreux modules Perl (Ex : BioPerl) dont le but est de simplifier les taches routinières du bioinformaticien. Perl possède également des modules permettant d'interroger la plupart des bases de données

Pourquoi MySQL ?

MySQL (ou son principal concurrent PostgreSQL) est à ce jour suffisament élaboré pour être utilisé dans de très nombreux cas. Leur fiabilité est généralement excellente, leur disponibilité totale, et en plus ils sont gratuits. MySQL permet de créer des tables contenant plusieurs milliards d'enregistrements.

Création de la base de données

Conception Merise et diagrammes

La méthodologie MERISE fournit un cadre pour la conception efficace de bases de données. Cette méthodologie s'articule autour de trois grandes étapes :

  • établir un modèle conceptuel de données ou MCD
  • établir un modèle logique de données ou MLD
  • établir un modèle physique ou MP
Le MCD est un formalisme permettant de décrire les données intervenant dans le problème et les liens existant entre ces informations de façon claire, simple, complète et non ambiguë. Les formalismes utilisés se situent délibérément en dehors de considérations techniques de stockage informatique des données. Un MCD comprend des entités, des relations, des propriétés, des cardinalités, des identifiants. Une relation peut etre nommée (ex : etre, avoir, represente, etc.). Certaines clés sont plus faciles a manipuler (numéros, codes, etc.). De même, pour une seule entité, plusieurs attributs peuvent avoir le statut de clé.

Le MCD se représente habituellement à l'aide de diagrammes, qu'il est possible de dessiner grace au programme dia. Par exemple :

Figure 1.2. PROTDB

Le modèle logique des données (MLD) consiste à décrire la structure de données utilisée sans faire référence à un langage de programmation. Il s'agit donc de préciser le type de données utilisées lors des traitements. Ainsi, le modèle logique est dépendant du type de base de données utilisé.

Le MP correspond à la traduction du MLD en langage comprehensible par la machine (ex : SQL). C'est ce que nous ferons dans la prochaine section.

Ressources:
  • Initiation aux bases de données http://www.grappa.univ-lille3.fr/polys/access-1997/access.html Dominique Gonzalez
  • Conception de base de données http://www.commentcamarche.net/merise/concintro.php3

Création de la base de données et des tables

Créons la base de données :

$ mysql 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 21 to server version: 3.23.36

Type 'help;' or '\h' for help. Type '\c' to clear the buffer

mysql> CREATE DATABASE protdb
Voici les tables devant être créées : les principaux types de données :
  • INT
  • FLOAT
  • VARCHAR
  • CHAR
  • TEXT
  • ENUM
Remarque : il n'existe pas de type BOOLEAN. Pour cela, on utilise généralement TINYINT ou ENUM('true', 'false')

CREATE TABLE PROTEINES (
PROTEINE_ID            int not null auto_increment,
PROTEINE_NOM           varchar(100),
PROTEINE_DESCRIPTION   varchar(255),
PROTEINE_FONCTION      text,
PROTEINE_AASEQUENCE    text,
PROTEINE_PDBID         varchar(20),
PROTEINE_SPID          varchar(10),
primary key(PROTEINE_ID)
);

CREATE TABLE INTERACTIONS (
INTER_ID		int not null auto_increment primary key,
INTER_PROTEINEID1    int,
INTER_PROTEINEID2    int,
INTER_COMMENTAIRE  text
);

CREATE TABLE PUBLICATIONS (
PUBLI_PROTEINEID    int,
PUBLI_PUBMEDID      varchar(10)
);

Avec votre éditeur de texte favori, créez un fichier nommé protdb.sql (par exemple), puis insérez-y les commandes SQL ci-dessus. La création physique des tables se fait alors au moyen de la commande :
$ mysql protdb < protdb.sql
Remarque : il peut être utile, si le schéma de la base est appelé à être modifié souvent de préceder les instructions CREATE TABLE XXX par la commande DROP TABLE IF EXISTS XXX; permettant de supprimer la table. Par exemple :
DROP TABLE IF EXISTS PUBLICATIONS;
CREATE TABLE PUBLICATIONS (
PUBLI_PROTEINEID    int,
PUBLI_PUBMEDID      varchar(10) not null primary key
);

Entrer des données dans la base

Entrer de nouvelles données via SQL

La commande SQL pour insérer de nouvelles données dans une table est la commande INSERT. Par exemple, pour insérer la protéine GADD45a dans notre base de données :

INSERT INTO PROTEINES (PROTEINE_NOM, 
                       PROTEINE_DESCRIPTION, 
                       PROTEINE_FONCTION, 
		       PROTEINE_AASEQUENCE, 
                       PROTEINE_PDBID, 
                       PROTEINE_SPID) VALUES (
                       'GADD45a',
		       'growth arrest and DNA damage inducible protein GADD45, alpha',
		       'MTLEEFSAGEQKTERMDKVGDALEEVLSKALSQRTITVGVYEAAKLLNVDPDNVVLCLLAADEDDDRDVALQIHFTLIQAFCCENDINILRVSNPGRLAELLLLETDAGPAASEGAEQPPDLHCVLVTNPHSSQWKDPALSQLICFCRESRYMDQWVPVINLPER*',
		       'BINDS TO PROLIFERATING CELL NUCLEAR ANTIGEN. MIGHT AFFECT PCNA INTERACTION WITH SOME CDK (CELL DIVISION PROTEIN KINASE) COMPLEXES; STIMULATES DNA EXCISION REPAIR IN VITRO AND INHIBITS ENTRY OF CELLS INTO S PHASE',
		       '',
		       'P24522');

Maintenant, interrogeons la base de données pour voir l'effet de cette commande :

mysql> select * from PROTEINES\G 
*************************** 1. row ***************************
         PROTEINE_ID: 1
        PROTEINE_NOM: GADD45a
PROTEINE_DESCRIPTION: growth arrest and DNA damage inducible protein GADD45, alpha
   PROTEINE_FONCTION: MTLEEFSAGEQKTERMDKVGDALEEVLSKALSQRTITVGVYEAAKLLNVDPDNVVLCLLAADEDDDRDVALQIHFTLIQAFCCENDINILRVSNPGRLAELLLLETDAGPAASEGAEQPPDLHCVLVTNPHSSQWKDPALSQLICFCRESRYMDQWVPVINLPER*
 PROTEINE_AASEQUENCE: BINDS TO PROLIFERATING CELL NUCLEAR ANTIGEN. MIGHT AFFECT PCNA INTERACTION WITH SOME CDK (CELL DIVISION PROTEIN KINASE) COMPLEXES; STIMULATES DNA EXCISION REPAIR IN VITRO AND INHIBITS ENTRY OF CELLS INTO S PHASE
      PROTEINE_PDBID: 
       PROTEINE_SPID: P24522
1 row in set (0.00 sec)

mysql> 


On notera que la requète INSERT précédente ne portais pas sur le champ PROTEINE_ID, de type INT NOT NULL AUTO_INCREMENT. Or nous voyons bien que celui-ci a automatiquement mis à 1 pour la protéine GADD45a. Insérons maintenant les données suivantes :

INSERT INTO PROTEINES (PROTEINE_NOM, 
                       PROTEINE_DESCRIPTION, 
                       PROTEINE_FONCTION, 
		       PROTEINE_FONCTION, 
                       PROTEINE_AASEQUENCE, 
                       PROTEINE_PDBID, 
                       PROTEINE_SPID) VALUES (
                       'PCNA',
		       'proliferating cell nuclear antigen',
		       'MFEARLVQGSILKKVLEALKDLINEACWDISSSGVNLQSMDSSHVSLVQLTLRSEGFDTYRCDRNLAMGVNLTSMSKILKCAGNEDIITLRAEDNADTLALVFEAPNQEKVSDYEMKLMD LDVEQLGIPEQEYSCVVKMPSGEFARICRDLSHIGDAVVISCAKDGVKFSASGELGNGNI KLSQTSNVDKEEEAVTIEMNEPVQLTFALRYLNFFTKATPLSSTVTLSMSADVPLVVEYKIADMGHLKYYLAPKIEDEEGS*',
		       'THIS PROTEIN IS AN AUXILIARY PROTEIN OF DNA POLYMERASE DELTA AND IS INVOLVED IN THE CONTROL OF EUKARYOTIC DNA REPLICATION BY INCREASING THE POLYMERASE'S PROCESSIBILITY DURING ELONGATION OF THE LEADING STRAND',
		       '1AXC',
		       'P12004');


mysql> select * from PROTEINES\G
*************************** 1. row ***************************                                                          
         PROTEINE_ID: 1
        PROTEINE_NOM: GADD45a
PROTEINE_DESCRIPTION: growth arrest and DNA damage inducible protein GADD45, alpha
   PROTEINE_FONCTION: MTLEEFSAGEQKTERMDKVGDALEEVLSKALSQRTITVGVYEAAKLLNVDPDNVVLCLLAADEDDDRDVALQIHFTLIQAFCCENDINILRVSNPGRLAELLLLETDAGPAASEGAEQPPDLHCVLVTNPHSSQWKDPALSQLICFCRESRYMDQWVPVINLPER*
 PROTEINE_AASEQUENCE: BINDS TO PROLIFERATING CELL NUCLEAR ANTIGEN. MIGHT AFFECT PCNA INTERACTION WITH SOME CDK (CELL DIVISION PROTEIN KINASE) COMPLEXES; STIMULATES DNA EXCISION REPAIR IN VITRO AND INHIBITS ENTRY OF CELLS INTO S PHASE
      PROTEINE_PDBID: 
       PROTEINE_SPID: P24522
*************************** 2. row ***************************
         PROTEINE_ID: 2
        PROTEINE_NOM: PCNA
PROTEINE_DESCRIPTION: proliferating cell nuclear antigen
   PROTEINE_FONCTION: MFEARLVQGSILKKVLEALKDLINEACWDISSSGVNLQSMDSSHVSLVQLTLRSEGFDTYRCDRNLAMGVNLTSMSKILKCAGNEDIITLRAEDNADTLALVFEAPNQEKVSDYEMKLMD LDVEQLGIPEQEYSCVVKMPSGEFARICRDLSHIGDAVVISCAKDGVKFSASGELGNGNI KLSQTSNVDKEEEAVTIEMNEPVQLTFALRYLNFFTKATPLSSTVTLSMSADVPLVVEYKIADMGHLKYYLAPKIEDEEGS*
 PROTEINE_AASEQUENCE: THIS PROTEIN IS AN AUXILIARY PROTEIN OF DNA POLYMERASE DELTA AND IS INVOLVED IN THE CONTROL OF EUKARYOTIC DNA REPLICATION BY INCREASING THE POLYMERASE'S PROCESSIBILITY DURING ELONGATION OF THE LEADING STRAND
      PROTEINE_PDBID: 1AXC
       PROTEINE_SPID: P12004
2 rows in set (0.47 sec)

mysql>

Tout comme pour GADD45a, nous voyons bien que le champ PROTEINE_ID de PCNA a automatiquement mis à 2.

Insérons maintenant une interaction entre ces deux protéines :


INSERT INTO INTERACTIONS (INTER_PROTEINEID1, INTER_PROTEINEID2, INTER_COMMENTAIRE)
                          VALUES ('1', '2', 'Using complementary in vivo and in vitro interaction assays the N-terminal (1-46) and middle (100-127) regions of PCNA were identified as harboring MyD118- and Gadd45 interacting domains, whereas PCNA interacting domains within MyD118 and Gadd45 were localized to the C termini of these proteins (amino acids 114-156 and 137-165, respectively)');




Entrer de nouvelles données via Perl et SQL

Le script suivant permet de rentrer la description d'une protéine (contenue dans le script) dans la BD :
#!/usr/bin/perl

use DBI();

$dbh = DBI->connect(    "DBI:mysql:database=protdb;host=localhost", 
                        "", 
                        "",
                        {'RaiseError' => 1}
                );

my %data = ();

%data = ("PROTEINE_NOM"           => "MTK1",
         "PROTEINE_DESCRIPTION"   => "protein kinase, mitogen-activated, kinase kinase 1",
	 "PROTEINE_FONCTION"      => "ACTIVATES THE CSBP2, P38 AND JNK MAPK PATHWAYS, BUT NOT THE ERK PATHWAY. SPECIFICALLY PHOSPHORYLATES AND ACTIVATES MAP2K4 AND MAP2K6",
	 "PROTEINE_AASEQUENCE"    => "
 MREAAAALVPPPAFAVTPAAAMEEPPPPPPPPPPPPEPETESEPECCLAARQEGTLGDSA
 CKSPESDLEDFSDETNTENLYGTSPPSTPRQMKRMSTKHQRNNVGRPASRSNLKEKMNAP
 NQPPHKDTGKTVENVEEYSYKQEKKIRAALRTTERDHKKNVQCSFMLDSVGGSLPKKSIP
 DVDLNKPYLSLGCSNAKLPVSVPMPIARPARQTSRTDCPADRLKFFETLRLLLKLTSVSK
 KKDREQRGQENTSGFWLNRSNELIWLELQAWHAGRTINDQDFFLYTARQAIPDIINEILT
 FKVDYGSFAFVRDRAGFNGTSVEGQCKATPGTKIVGYSTHHEHLQRQRVSFEQVKRIMEL
 LEYIEALYPSLQALQKDYEKYAAKDFQDRVQALCLWLNITKDLNQKLRIMGTVLGIKNLS
 DIGWPVFEIPSPRPSKGNEPEYEGDDTEGELKELESSTDESEEEQISDPRVPEIRQPIDN
 SFDIQSRDCISKKLERLESEDDSLGWGAPDWSTEAGFSRHCLTSIYRPFVDKALKQMGLR
 KLILRLHKLMDGSLQRARIALVKNDRPVEFSEFPDPMWGSDYVQLSRTPPSSEEKCSAVS
 WEELKAMDLPSFEPAFLVLCRVLLNVIHECLKLRLEQRPAGEPSLLSIKQLVRECKEVLK
 GGLLMKQYYQFMLQEVLEDLEKPDCNIDAFEEDLHKMLMVYFDYMRSWIQMLQQLPQASH
 SLKNLLEEEWNFTKEITHYIRGGEAQAGKLFCDIAGMLLKSTGSFLEFGLQESCAEFWTS
 ADDSSASDEIIRSVIEISRALKELFHEARERASKALGFAKMLRKDLEIAAEFRLSAPVRD
 LLDVLKSKQYVKVQIPGLENLQMFVPDTLAEEKSIILQLLNAAAGKDCSKDSDDVLIDAY
 LLLTKHGDRARDSEDSWGTWEAQPVKVVPQVETVDTLRSMQVDNLLLVVMQSAHLTIQRK
 AFQQSIEGLMTLCQEQTSSQPVIAKALQQLKNDALELCNRISNAIDRVDHMFTSEFDAEV
 DESESVTLQQYYREAMIQGYNFGFEYHKEVVRLMSGEFRQKIGDKYISFARKWMNYVLTK
 CESGRGTRPRWATQGFDFLQAIEPAFISALPEDDFLSLQALMNECIGHVIGKPHSPVTGL
 YLAIHRNSPRPMKVPRCHSDPPNPHLIIPTPEGFSTRSMPSDARSHGSPAAAAAAAAAVA
 ASRPSPSGGDSVLPKSISSAHDTRGSSVPENDRLASIAAELQFRSLSRHSSPTEERDEPA
 YPRGDSSGSTRRSWELRTLISQSKDTASKLGPIEAIQKSVRLFEEKRYREMRRKNIIGQV
 CDTPKSYDNVMHVGLRKVTFKWQRGNKIGEGQYGKVYTCISVDTGELMAMKEIRFQPNDH
 KTIKETADELKIFEGIKHPNLVRYFGVELHREEMYIFMEYCDEGTLEEVSRLGLQEHVIR
 LYSKQITIAINVLHEHGIVHRDIKGANIFLTSSGLIKLGDFGCSVKLKNNAQTMPGEVNS
 TLGTAAYMAPEVITRAKGEGHGRAADIWSLGCVVIEMVTGKRPWHEYEHNFQIMYKVGMG
 HKPPIPERLSPEGKDFLSHCLESDPKMRWTASQLLDHSFVKVCTDEE*",

	 "PROTEINE_PDBID"        => "",
	 "PROTEINE_SPID"         => "Q9Y6R4");

$query = "INSERT INTO PROTEINES (
                       PROTEINE_NOM, 
                       PROTEINE_DESCRIPTION, 
                       PROTEINE_FONCTION, 
		       PROTEINE_AASEQUENCE, 
                       PROTEINE_PDBID, 
                       PROTEINE_SPID) VALUES (
                       '$data{"PROTEINE_NOM"}',
		       '$data{"PROTEINE_DESCRIPTION"}',
		       '$data{"PROTEINE_FONCTION"}',
		       '$data{"PROTEINE_AASEQUENCE"}',
		       '$data{"PROTEINE_PDBID"}',
		       '$data{"PROTEINE_SPID"}');";

$sth = $dbh->do($query);

# le champ PROTEINE_ID, automatiquement affecté par MySQL est stocké dans $sth->{'mysql_insertid'};

print "Protéine " . $sth->{'mysql_insertid'} . " insérée dans la base!\n";
        
Insérons maintenant une interaction entre GADD45a et MTK1, toujours grace à Perl.

#!/usr/bin/perl

$query = "SELECT PROTEINE_ID FROM PROTEINES WHERE PROTEINE_NOM = 'GADD45a' OR PROTEINE_NOM = 'MTK1'";

$sth = $dbh->prepare($query);
$res = $sth->execute;
        
$row = $sth->fetchrow_hashref;
$protein1 = $row->{"PROTEINE_ID"};

$row = $sth->fetchrow_hashref;
$protein2 = $row->{"PROTEINE_ID"};

$query = "INSERT INTO INTERACTIONS (
                       INTER_PROTEINEID1, INTER_PROTEINEID2, INTER_COMMENTAIRE)
          VALUES ('$protein1',
	          '$protein2',
		  'commentaire ...');   

Définir un formulaire HTML d'entrée de donnée

Ce formulaire doit permettre de rentrer une nouvelle protéine, et de lui affecter une interaction avec une ou plusieurs protéines déjà présentes dans la base.

Figure 1.3. PROTDB



#!/usr/bin/perl

#
# Perl (traitement de données)
#

use DBI();
use CGI;

$cgi =new CGI;

$dbh = DBI->connect(    "DBI:mysql:database=protdb;host=localhost", 
                        "", 
                        "",
                        {'RaiseError' => 1}
                );

$query = "SELECT PROTEINE_NOM, PROTEINE_ID FROM PROTEINES";

$sth = $dbh->prepare($query);
$res = $sth->execute;
        
my $select = '<select name="INTERACTIONS" multiple="true">'
;
while ($row = $sth->fetchrow_hashref) {
      $select .= '<option value="' . $row->{PROTEINE_ID} . '">' . $row->{PROTEINE_NOM} . "</option>\n"; 
}

$select .= "</select>";
      


#
# HTTP header
#
print $cgi->header;

#
# HTML (affichage)
# 
print <<STOP;
<html>
<body bgcolor="white">


<form action="/perl/insert.pl">
<table>

<tr>
<td align="right">
Nom
</td>
<td>
<input type="text" name="PROTEINE_NOM" value="">
</td>
</tr>

<tr>
<td align="right">
Description
</td>
<td>
<input type="text" name="PROTEINE_DESCRIPTION" value="" size="30">
</td>
</tr>

<tr>
<td align="right">
Fonction
</td>
<td>
<input type="text" name="PROTEINE_FONCTION" value="" size="30">
</td>
</tr>

<tr>
<td align="right">
Séquence
</td>
<td>
<textarea name="PROTEINE_AASEQUENCE" cols="40" rows="10"></textarea>
</td>
</tr>


<tr>
<td align="right">
code PDB
</td>
<td>
<input type="text" name="PROTEINE_PDBID" value="" size="30">
</td>
</tr>

<tr>
<td align="right">
code SWISSPROT
</td>
<td>
<input type="text" name="PROTEINE_SPID" value="" size="30">
</td>
</tr>


<tr>
<td align="right">
Interagit avec
</td>
<td>
$select
</td>
</tr>



<tr>
<td align="right">
</td>
<td>
<input type="submit" name="" value="Valider">

</td>
</tr>

</table>

</form>

</body>
</html>

STOP




Ce script perl doit être placé dans le répertoire cgi-bin ou celui correspondant à mod_perl, puis rendu éxécutable grâce à la commande :
chmod +x protdb_input.pl

Construire le script Perl correspondant

Cas le plus fréquent et le plus pratique : utiliser le même script pour l'affichage du formulaire et l'insertion des données.

#!/usr/bin/perl

#
# Perl (traitement de données)
#

use DBI();
use CGI;

$cgi =new CGI;

$dbh = DBI->connect(    "DBI:mysql:database=protdb;host=localhost", 
                        "", 
                        "",
                        {'RaiseError' => 1}
                );

my $select = "";

if ($cgi->param) {
    
    # insere la description de la proteine dans la BD
    $query = "INSERT INTO PROTEINES (
                       PROTEINE_NOM, 
                       PROTEINE_DESCRIPTION, 
                       PROTEINE_FONCTION, 
		       PROTEINE_AASEQUENCE, 
                       PROTEINE_PDBID, 
                       PROTEINE_SPID) VALUES (
                       '" . $cgi->param("PROTEINE_NOM") . "',
		       '" . $cgi->param("PROTEINE_DESCRIPTION") . "',
		       '" . $cgi->param("PROTEINE_FONCTION") . "',
		       '" . $cgi->param("PROTEINE_AASEQUENCE") . "',
		       '" . $cgi->param("PROTEINE_PDBID") . "',
		       '" . $cgi->param("PROTEINE_SPID") . "');";

    $sth = $dbh->do($query);

    # insere les interaction

    # redirige le navigateur vers une autre page
    print $cgi->redirect("ok.html");
    
    
} else {
    $query = "SELECT PROTEINE_NOM, PROTEINE_ID FROM PROTEINES";
    
    $sth = $dbh->prepare($query);
    $res = $sth->execute;
    
    $select = '<select name="INTERACTIONS" multiple="true">'
	;
    while ($row = $sth->fetchrow_hashref) {
	$select .= '<option value="' . $row->{PROTEINE_ID} . '">' . $row->{PROTEINE_NOM} . "</option>\n"; 
    }
    
    $select .= "</select>";
}   

    
#
# HTTP header
#
print $cgi->header;

#
# HTML (affichage)
# 

 
print <<STOP;
<html>
<body bgcolor="white">


<form action="/perl/protdb_input.pl">
<table>

<tr>
<td align="right">
Nom
</td>
<td>
<input type="text" name="PROTEINE_NOM" value="">
</td>
</tr>

<tr>
<td align="right">
Description
</td>
<td>
<input type="text" name="PROTEINE_DESCRIPTION" value="" size="30">
</td>
</tr>

<tr>
<td align="right">
Fonction
</td>
<td>
<input type="text" name="PROTEINE_FONCTION" value="" size="30">
</td>
</tr>

<tr>
<td align="right">
Séquence
</td>
<td>
<textarea name="PROTEINE_AASEQUENCE" cols="40" rows="10"></textarea>
</td>
</tr>


<tr>
<td align="right">
code PDB
</td>
<td>
<input type="text" name="PROTEINE_PDBID" value="" size="30">
</td>
</tr>

<tr>
<td align="right">
code SWISSPROT
</td>
<td>
<input type="text" name="PROTEINE_SPID" value="" size="30">
</td>
</tr>


<tr>
<td align="right">
Interagit avec
</td>
<td>
$select
</td>
</tr>



<tr>
<td align="right">
</td>
<td>
<input type="submit" name="" value="Valider">

</td>
</tr>

</table>

</form>

</body>
</html>

STOP


Constrôle des données entrées via le formulaire

Quelques lignes de code Javascript permettent d'être sur que certains champs seront systématiquement remplis, et qu'ils seront remplis de la bonne manière. Par exemple, il est possible de s'assurer que le champ PROTEINE_NOM contient au moins 4 caractères (aucun nom de protéine ne possède moins de 4 caractères).

Interroger la base

Il importe évidemment de bien définir le type de requète pouvant être soumises a la base. Exemple : fiche de protéine avec ses interactions Exemple de lien vers SWISSPROT : http://www.expasy.ch/cgi-bin/sprot-search-ac?P24522

#!/usr/bin/perl

#
# Perl (traitement de données)
#

use DBI();
use CGI;

$cgi =new CGI;

$dbh = DBI->connect(    "DBI:mysql:database=protdb;host=localhost", 
                        "", 
                        "",
                        {'RaiseError' => 1}
                );

my $select = "";

if ($cgi->param) {
    
    # recupere la description de la proteine dans la BD
    $query = "SELECT * FROM PROTEINES WHERE PROTEINE_ID = '" . $cgi->param("PROTEINE_ID") . "'";;
    $sth = $dbh->prepare($query);
    $res = $sth->execute;
    
    $proteine = $sth->fetchrow_hashref;
    
	
    # recupere les protéines qui interagissent avec celle-ci et en fait une liste
    $query = "SELECT t1.* FROM PROTEINES as t1, INTERACTIONS as t2 
              WHERE (t2.INTER_PROTEINEID2 = '". $cgi->param("PROTEINE_ID") . "' AND t1.PROTEINE_ID = t2.INTER_PROTEINEID1)
              OR    (t2.INTER_PROTEINEID1 = '". $cgi->param("PROTEINE_ID") . "' AND t1.PROTEINE_ID = t2.INTER_PROTEINEID2)";
    
    $sth = $dbh->prepare($query);
    $res = $sth->execute;
    
    # batit le tableau
    $select = "<table border=1>";
    $select .= "<tr><td>Nom</td><td>code SWWISPROT</td>\n";
    while ($inter = $sth->fetchrow_hashref) {
	$select .= "<tr><td>" . $inter->{PROTEINE_NOM} . "</td>
        <td><a href=\"http://www.expasy.ch/cgi-bin/sprot-search-ac?" . $inter->{PROTEINE_SPID} . "\">" . $inter->{PROTEINE_SPID} . "</a></td>\n";
    }
    $select .= "</table>";
    

        
    
} else {
    $query = "SELECT PROTEINE_NOM, PROTEINE_ID FROM PROTEINES";
    
    $sth = $dbh->prepare($query);
    $res = $sth->execute;
    
    $select = '<select name="PROTEINE_ID">'
	;
    while ($row = $sth->fetchrow_hashref) {
	$select .= '<option value="' . $row->{PROTEINE_ID} . '">' . $row->{PROTEINE_NOM} . "</option>\n"; 
    }
    
    $select .= "</select>";
}   

    
#
# HTTP header
#
print $cgi->header;

#
# HTML (affichage)
# 

if ($cgi->param) { 


    print <<STOP;

<html>
<body bgcolor="white">



<table border="1">

<tr>
<td align="right">
Nom
</td>
<td>
$proteine->{PROTEINE_NOM}
</td>
</tr>

<tr>
<td align="right">
Description
</td>
<td>
$proteine->{PROTEINE_DESCRIPTION}
</td>
</tr>

<tr>
<td align="right">
Fonction
</td>
<td>
$proteine->{PROTEINE_FONCTION}
</td>
</tr>

<tr>
<td align="right">
Séquence
</td>
<td>
$proteine->{PROTEINE_AASEQUENCE}
</td>
</tr>


<tr>
<td align="right">
code PDB
</td>
<td>
$proteine->{PROTEINE_PDBID}
</td>
</tr>

<tr>
<td align="right">
code SWISSPROT
</td>
<td>
$proteine->{PROTEINE_SPID}
</td>
</tr>


<tr>
<td align="right">
Interagit avec
</td>
<td>
$select
</td>
</tr>



<tr>
<td align="right">
</td>
<td>
<input type="submit" name="" value="Valider">

</td>
</tr>

</table>



</body>
</html>

STOP

} else {

    print <<STOP;
<html>
<body bgcolor="white">


<form action="/perl/protdb_query.pl">
    
$select
<input type="submit" value="GO!">    
</form>
STOP
} 


Figure 1.4. Liste des protéines à consulter

Figure 1.5. résultats : affichage d'une fiche protéine

Bonus : utilisation des logs Apache et Perl

Comment trouver les erreurs dans les scripts Perl ?

Si Perl est utilisé en CGI, les erreurs lancées par vos scripts se trouvent ajoutées au fichier d'erreurs du serveur web. Celui-ci peut se trouver à divers endroits selon les plateformes. Par exemple, pour Apache sous Linux Mandrake, le fichier contenant les erreurs est situé à /var/log/httpd/errors

Qui consulte votre base de données ?

La majorité des serveurs web (dont Apache) sont configurés par défaut de manière à conserver une trace des accès aux pages web et scripts associés. Par exemple, pour Apache sous Linux Mandrake, le fichier contenant les accès est situé à /var/log/httpd/access.

Interfacer des outils externes : BLAST

Le but de cette opération est de permettre a l'utilisateur de faire un blast d'une séquence inconnue (qu'il précisera) contre toutes les séquences protéiques de la base de données.

Cela nécessite bien sur d'installer BLAST sur le serveur. Cette étape est décrite au paragraphe XX. L'utilisation de BLAST en version "standalone" nécessite la création de bases de donnnées dont le format est propre à BLAST. Le programme formatdb permet ainsi recreer la base de données. Cette réindexation des données doit etre fait soit a intervalles regulier (par exemple grace a un cronjob), soit a chaque nouvelle entrée dans la base.

1ere étape : récuperation d'un fichier FASTA contenant toutes les séquences de la base

2eme étape : création d'une base de données utilisable par BLAST

3eme étape : définir un formulaire de saisie de séquence

4eme étape : appel de BLAST et affichage des résultats