Les Web Services

Fiche


Niveau de difficulté : Expert.
Recommandations : n/c.
A lire aussi : n/c


Inspirez-vous aussi des plugins déjà existants.

«Ou comment externaliser des données de PhpWebGallery»

Cet article se veut le plus abordable possible pour s'adresser au plus grand nombre mais il est tout de même conseillé de disposer de bases sérieuses en PHP


  • Attention ! Les Web Services (WS) sont plus complexes à mettre en œuvre dans la branche 1.7 que “external_random” existant dans les branches précédentes. Plus complexes mais aussi beaucoup plus puissants.
  • Le but de WS : Pouvoir externaliser (présenter sur une page / un site distant de PWG lui-même) des données et informations de la galerie PWG. Exemple : Afficher tout ou partie des dernières images ajoutées à la galerie dans un blog, un échantillon aléatoire d'images sur une page d'index de site, les derniers commentaires déposés avec les images concernées, etc…
  • La description d'emploi de WS ci-dessous est basée sur un exemple permettant d'afficher aléatoirement des images ou leur version miniature dans une page web externe à la galerie (page d'index de site par exemple) selon différents critères.

Génération des requêtes

  • Pour parvenir au résultat désiré, la première étape consiste à trouver la bonne requête à appeler dans la page externalisée. Pour cela, on utilisera un outil spécifique, livré en standard dans la distribution de PWG sous 'http:\\www.monsite.com\magalerie\tools\ws.htm'.

1 - Lancer la page ws.htm dans votre navigateur préféré.

2 - Une page vous demande de préciser la position du script WS (ws.php). Normalement, il doit se trouver sous 'http:\\www.monsite.com\magalerie\ws.php'.

3 - Cliquez alors sur “GO!”

4 - Il s'agit maintenant de choisir la bonne méthode en fonction du résultat désiré. Voici une traduction des termes :

  • pwg.categories.getImages → Méthode pour récupérer des images à partir des catégories
  • pwg.categories.getList → Méthode pour récupérer une liste de catégories
  • pwg.getVersion → Méthode pour récupérer la version utilisée de PWG
  • pwg.images.addComment → Méthode pour ajouter des commentaires
  • pwg.images.getInfo → Méthode pour récupérer des informations sur des images
  • pwg.images.search → Méthode pour effectuer une recherche d'images
  • pwg.session.getStatus → Méthode pour connaître l'identité et le profil en cours
  • pwg.session.login → Méthode pour s'identifier (se connecter)
  • pwg.session.logout → Méthode pour retourner en simple visiteur
  • pwg.tags.getImages → Méthode pour récupérer des images via des Tags
  • pwg.tags.getList → Méthode pour récupérer des Tags

Pour information:

  • reflection.getMethodDetails → Méthode pour obtenir des détails sur les méthodes employées
  • reflection.getMethodList → Méthode pour obtenir la liste des méthodes

5 - Votre choix fait, il suffit de cliquer sur la méthode pour obtenir le panneau de requêtes associé. Il serait trop long et fastidieux de détailler chaque méthode. Aussi, pour notre exemple, nous choisirons ici la méthode “pwg.categories.getImages” qui nous permettra de d'afficher aléatoirement des images ou leur version miniature selon différents critères.

6 - En utilisant la méthode “pwg.categories.getImages”, nous avons tout d'abord 2 paramètres à renseigner : Le format de la requête (Request format) et le format de la réponse (Response format)

  • Le premier paramètre concerne la fonction (POST ou GET) à employer avec la méthode. Typiquement, POST serait utilisé pour envoyer le résultat de la requête et GET pour le recevoir. On choisira ici la fonction GET.

Petit aparté : La méthode pwg.session.login n'accepte que la fonction POST. Par ce biais, on peut envisager d'utiliser une ouverture de session sur un blog (un forum ou autres…) pour s'identifier automatiquement sur la galerie. En partageant les tables contenant les informations des inscrits sur chaque application, on pourrait aussi gérer les nouvelles inscriptions.

  • Le second paramètre concerne la manière de formater les données issues de la requête. Nous avons le choix entre REST (xml), JSON, PHP serial et XML (RPC). Le choix du formatage de sortie dépend de la destination des informations extraites. Par exemple, pour générer un flux RSS spécifique, on utilisera REST (xml) car les lecteurs de flux comprennent ce format. Toujours dans le cadre de notre exemple, nous choisirons PHP serial car nous souhaitons afficher les informations dans une page web et un script PHP fera très bien l'affaire.

FIXME : S'il y en a qui se sentent pour traiter le sujet des XML et autres… ;-)

7 - Dans la partie de droite, nous avons un tableau récapitulant tous les paramètres utilisables pour la méthode sélectionnée. Chaque méthode a un tableau de paramètre différent. Il serait trop long de tout détailler ici. Dans le cadre de notre exemple (méthode “pwg.categories.getImages”), voici les explications des différents filtres :

  • cat_id → Filtre de type numérique sur les identifiants de catégories (peut être unique ou multiple dans le cadre d'un tableau - Array)
  • recursive → Paramètre booléen (vrai / faux) précisant si la requête doit être récursive (recherche dans les sous-dossiers) - Attention ! Ne concerne que les catégories publiques !
  • per_page → Nombre d'éléments maximum à remonter par page
  • page → Nombre de pages maximum
  • order → Paramètre de tri des informations.
  • f_min_rate → Valeur de note minimale attribuée aux éléments
  • f_max_rate → Valeur de note maximale attribuée aux éléments
  • f_min_hit → Nombre de visualisation minimum des éléments
  • f_max_hit → Nombre de visualisation maximum des éléments
  • f_min_date_available → Date d'ajout minimale
  • f_max_date_available → Date d'ajout maximale
  • f_min_date_created → Date de création minimale
  • f_max_date_created → Date de création maximale
  • f_min_ratio → Rapport minimal de largeur/hauteur de l'image
  • f_max_ratio → Rapport maximal de largeur/hauteur de l'image
  • f_with_thumbnail → Paramètres booléen (vrai / faux) précisant si la requête ne concerne que les images avec miniatures.

Dans le cas de catégories multiples la syntaxe est la suivante :

http://fr.piwigo.org/demo/ws.php?method=pwg.categories.getImages&cat_id[]=27&cat_id[]=50

8 - Avec tous ces éléments, il nous est maintenant possible de “jouer” avec l'outil pour tenter d'obtenir le résultat souhaité. La vérification du résultat produit se fait en cliquant sur les liens “Invoke” ou “Invoke (New window)”. Le premier lien affiche le résultat dans le cadre en dessous du tableau de paramètres quant au second, il l'affiche dans une nouvelle fenêtre du navigateur. En poursuivant notre exemple, nous utiliserons les paramètres suivants :

  • cat_id → vide
  • recursive → true
  • per_page → 5
  • page → 0 (car nous ne souhaitons pas gérer l'affichage de plusieurs pages de résultats dans la page web de destination)
  • order → random (aléatoire)
  • f_min_rate → vide
  • f_max_rate → vide
  • f_min_hit → vide
  • f_max_hit → vide
  • f_min_date_available → vide
  • f_max_date_available → vide
  • f_min_date_created → vide
  • f_max_date_created → vide
  • f_min_ratio → 1.2
  • f_max_ratio → vide
  • f_with_thumbnail → true

Traduction : “Récupérer, sur une page, 5 images au hasard dans toutes les catégories et sous catégories dont le rapport largeur/hauteur est au moins 1.2 (donc plus larges que hautes). Ceci n'étant bien sur qu'un exemple. On pourrait fixer également f_max_ratio à 1.4, ce qui permettrait d'obtenir les images présentées en mode paysage (en excluant les images carrées, les images de diaporama et les image en mode portrait.”

Autre exemple :

  • cat_id → vide
  • recursive → true
  • per_page → 5
  • page → 0 (car nous ne souhaitons pas gérer l'affichage de plusieurs pages de résultats dans la page web de destination)
  • order → random (aléatoire)
  • f_min_rate → vide
  • f_max_rate → vide
  • f_min_hit → 500
  • f_max_hit → vide
  • f_min_date_available → vide
  • f_max_date_available → vide
  • f_min_date_created → vide
  • f_max_date_created → vide
  • f_min_ratio → vide
  • f_max_ratio → vide
  • f_with_thumbnail → true

Traduction : “Récupérer, sur une page, 5 images au hasard, vues au moins 500 fois, dans toutes les catégories et sous catégories.” Ce qui permet d'afficher un nombre limité d'images “Les plus regardées”. A l'inverse, on peut ne mettre qu'un f_max_hit à 50 et tant que des images n'auront pas été regardées au moins 50 fois, elles seront présentées, ce qui permet de présenter “Les plus récentes” en y intégrant “Les moins regardées”.

9 - Un clic sur “Invoke” et on obtient un tableau sérialisé des données trouvées par la requête. Comme on a spécifié “Random” dans le paramètre “order”, on ne devrait pas retrouver deux fois le même résultat. Sauf, bien entendu, s'il n'y a pas assez d'images répondant aux critères. Le tableau est représenté sous la forme :

a:2:{s:4:"stat";s:2:"ok";s:6:"result";a:1:{s:6:"images";
(...)
"page_url";s:72:"http://www.monsite.com/magalerie/picture.php?/[id]/category/[id]";}}}}}}}

10 - Pas très évident de vérifier le bon fonctionnement de la requête sous cette forme, je vous l'accorde. Mais vous pouvez faire des essais en réduisant, par exemple, le nombre d'images à retourner. Vous pouvez passer en présentation “REST (xml)” ce sera plus simple à contrôler. Mais dans notre cas, il faut formater le résultat pour y comprendre quelque chose. Avant tout, quelques définitions :

- a:x -> "a" pour "array" ou tableau suivi par x représentant le nombre d'éléments dans le tableau.
    Exemple : a:2 = "tableau de 2 éléments"

- s:x:"$" -> "s" pour "String" ou chaine suivi par x représentant le nombre de caractères de la chaine et $, le contenu de la chaine.
    Exemple : s:4:"stat" = "Chaine de 4 caractères qui sont "stat"

- i:x -> "i" pour "Integer" ou entier suivi de la valeur de l'entier.
    Exemple : i:100 = "Un entier de valeur 100"

- N -> équivalent à NULL.

- Les tableaux sont délimités par "{}".

- Les champs du tableau sont délimités par ";".

- Une donnée complète du tableau est composée du nom de la donnée et de sa valeur.
    Exemples : s:4:"stat";s:2:"ok";
               s:4:"page";i:0;

* Ci-dessous, un exemple de ce que cela donne avec les explications qui vont bien.

a:2:{
	s:4:"stat";s:2:"ok"; <- le statut de la requête est OK
	s:6:"result";a:1:{ <- le résultat commence ici
		s:6:"images";a:4:{ <- le tableau des images qui contient 4 éléments
			s:4:"page";i:0; <- élément #1 : le nombre de pages pour afficher les éléments (images)
			s:8:"per_page";i:100; <- élément #2 : le nombre d'éléments (images) par page
			s:5:"count";i:11; <- élément #3 : le compte du nombre d'éléments (images) trouvés.
			s:8:"_content";a:11:{ <- élément #4 : Qui ouvre aussi un tableau de 11 éléments détaillant le contenu de la requête, c'est çà dire les images proprement dites
				i:0;a:10:{ <- Première image trouvée dont les données sont dans un tableau de 10 éléments
					s:2:"id";i:4460; <- l'identifiant (ID) de l'image #1 en base de données
					s:5:"width";i:504; <- la largeur de l'image #1
					s:6:"height";i:699; <- la hauteur de l'image #1
					s:3:"hit";i:35; <- le nombre de fois que l'image #1 a été vue
					s:4:"file";s:38:"image1.jpg"; <- le fichier phyqique de l'image #1
					s:4:"name";s:23:"nom_image_1"; <- le nom représentant l'image #1
					s:7:"comment";N; <- le commentaire associé à l'image #1 (IPTC). Il ne s'agit pas des commentaires déposés par les visiteurs de la galerie.
					s:6:"tn_url";s:116:"http://www.monsite.com/magalerie/./galleries/Catégorie1/thumbnail/TN-image1.jpg";  <- le chemin complet pour accéder à la miniature de l'image #1
					s:11:"element_url";s:103:"http://www.monsite.com/magalerie/./galleries/Catégorie1/image1.jpg"; <- Le chemin complet pour accéder à l'image #1
					s:10:"categories";a:1:{ <- les informations sur la (les) catégorie(s) hébergeant l'image #1.
							i:0;a:3:{ <- Ici une seule catégorie donc 1 élément qui ouvre un tableau de 3 éléments
								s:2:"id";i:227; <- l'identifiant (ID) de la catégorie
								s:3:"url";s:65:"http://www.monsite.com/magalerie/index.php?/category/227"; <- le chemin complet pour accéder à racine de la catégorie
								s:8:"page_url";s:72:"http://www.monsite.com/magalerie/picture.php?/4460/category/227"; <- le chemin complet pour accéder aux pages de la catégorie (cas où il y aurait plusieurs pages)
								}
							}
						}
				i:1;a:10:{ <- Et c'est reparti pour l'image #2 - Même principe - Et ainsi de suite jusqu'à l'image #11 puisque c'est le nombre d'éléments retournés par la requête.
					s:2:"id";i:4458;
					s:5:"width";i:432;
					s:6:"height";i:653;
					s:3:"hit";i:30;
					s:4:"file";s:28:"image2.jpg";
					s:4:"name";s:13:"nom_image_2";
					s:7:"comment";N;
					s:6:"tn_url";s:106:"http://www.monsite.com/magalerie/./galleries/Catégorie1/thumbnail/TN-image2.jpg";
					s:11:"element_url";s:93:"http://www.monsite.com/magalerie/./galleries/Catégorie1/image2.jpg";
					s:10:"categories";a:1:{
						i:0;a:3:{
							s:2:"id";i:227;
							s:3:"url";s:65:"http://www.monsite.com/magalerie/index.php?/category/227";
							s:8:"page_url";s:72:"http://www.monsite.com/magalerie/picture.php?/4458/category/227";
								}
							}
						}
(...)

Pas très évident de lire directement un tel résultat, il est vrai.
Vous pouvez passer en présentation “REST (xml)” ce sera plus simple à contrôler. Toutefois essayez donc la présentation JSON (un grand standard des Web Services):

{"stat":"ok","result": 
{"images": {"page":0,"per_page":"100","count":11,"_content": 
[ {"id":4460, "width":504, "height":699, "hit":35, "file":"image1.jpg",
"name":"nom_image_1", "comment":null,
"tn_url":"http:\/\/www.monsite.com/magalerie\/.\/galleries\/Catégorie1\/thumbnail\/TN-image1.jpg",
"element_url":"http:\/\/www.monsite.com/magalerie\/.\/galleries\/Catégorie1\/image1.jpg",
"categories": [ {"id":227,
"url":"http:\/\/www.monsite.com/magalerie\/index.php?\/category\/227",
"page_url":"http:\/\/www.monsite.com/magalerie\/picture.php?\/4460\/category\/227" 
} ] } 
...

Juste un tout petit peu plus facile à lire, peut-être.
Ainsi pour retrouver l'élément_url dans une variable php (format=php) en supposant que le résultat de la requête soit dans $thumbc. Nous aurons:
$image_address = $thumbc[“result”][“images”][“_content”][0][“element_url”];
0 correspondra à la première image, 1 à la seconde comme dans tout tableau php.
En savoir plus sur la syntaxe JSON.

11- Lorsque la requête est au point, notez les paramètres pour qu'ils puissent être appelés par un script PHP dans la page externe destinée à recevoir le résultat de la requête. Pour notre exemple, nous aurons :

http://www.monsite.com/magalerie/ws.php?method=pwg.categories.getImages&format=php&recursive=true&order=random&f_min_ratio=1.2&f_with_thumbnail=true&per_page=5&page=0
  • Explications :
Lien vers ws.php -> http://www.monsite.com/magalerie/ws.php
Passage en paramètre de la méthode ->                      ?method=pwg.categories.getImages

Définition du format de sortie ->                          &format=php

Paramètres de la requête ->                                &recursive=true
                                                           &order=random
                                                           &f_min_ratio=1.2
                                                           &f_with_thumbnail=true
                                                           &per_page=5
                                                           &page=0

Utilisation des webservices

Dans une page PHP externe

  • Il s'agit maintenant d'intégrer la requête WS dans une page externe à PWG et de n'afficher que les informations nécessaires. Ce qui suit nécessite un minimum de connaissances en PHP mais je vais tenter de faire au plus simple pour que chacun, quelque soit son niveau en PHP, puisse réaliser son propre service web.
  • Pour rappel, nous partons d'une requête WS élaborée dans le paragraphe précédent, destinée à afficher des 5 images aléatoires ou leur version miniature avec un critère de note moyenne minimum de 1.2.

1 - Je passe sur la position d'insertion du code PHP dans la page ou du script devant accueillir le résultat de la requête WS. Chacun trouvera l'endroit idéal qui lui conviendra selon ses besoins. Pour notre exemple, nous envisagerons le cas simple d'une page HTML formatée ou non avec des CSS et accueillant dans une partie x l'affichage de nos 5 images.

2 - Voici un exemple de code utilisable. Il sera documenté et expliqué à la suite. Ce code est modulable et n'est en aucune façon une référence en soit. Ce n'est que pour illustrer l'exemple WS considéré (merci à VDigital pour cette solution dont il est l'auteur):

<?php
// initialisation de la session
$session = curl_init(); /* (a) */
 
// configuration des options
/* (b) */
curl_setopt($session, CURLOPT_URL,
"http://www.monsite.com/magalerie/ws.php?method=pwg.categories.getImages&format=php&recursive=true&order=random&f_min_ratio=1.2&f_with_thumbnail=true&per_page=5&page=0");
curl_setopt($session, CURLOPT_HEADER, 0);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
 
// exécution de la session
$response = curl_exec($session); /* Ici nous réceptionnons le tableau sérialisé de la requête (c) */
$thumbc = unserialize($response);/* que nous "désérialisons" (d) */
 
curl_close($session); /* fermeture des ressources (e) */
 
if ($thumbc["stat"]=='ok') /* Réponse correcte ? (f) */
 {
  for ($i=0;$i<$thumbc["result"]["images"]["count"];$i++) /* (g) */
   {
    $picture = $thumbc["result"]["images"]["_content"][$i]; /* (h) */
 
    // dans picture nous avons :  id, width, height, hit, file, name, comment, tn_url, element_url
/* (i) */
 
    $HTML_txt = '<a href="http://www.monsite.com/magalerie/picture.php?/'
        . $picture['id'].'" title="'.$picture['name'].'">'.'<img src="'
        . $picture['tn_url'].'" alt="'.$picture['name']
        . '" /></a><span class="caption">['.$picture['width'].'x'
        . $picture['height'].'] &nbsp; - &nbsp;'.'Hits : '
        . $picture['hit'].'</span><br/>';
    echo $HTML_txt;
    }
  }
?>

3 - Explications du code ci-dessus :

Pour obtenir le résultat de la requête WS, nous devons utiliser le jeu de fonctions curl. Il est néanmoins possible d'arriver au même résultat en utilisant file_get_contents() mais cette fonction n'est pas admise par tous les hébergeurs. Pour plus de détails sur ces fonctions, se reporter à la doc de PHP.

a) On commence par initialiser une variable de session sur la fonction curl…

b) … Et on établit les options relatives dont, notamment, l'URL de la requête élaborée dans le paragraphe précédent.

c) Le résultat de la requête est récupéré par curl_exec($session) et stocké dans une variable…

d) … Mais il s'agit d'un tableau de valeurs en série qu'il faut remettre en forme. La fonction unserialize($response) se charge de cela et stocke le tableau dans une nouvelle variable.

e) Pour continuer les traitements, on ferme la session de la requête initiale.

f) Pour être certain de ne pas afficher n'importe quoi si la requête ne retourne rien, on teste si le champ “stat” est bien à “OK”.

g) On isole chaque élément du tableau des résultats (comprendre les images)…

h) … Et pour chaque élément, on “charge” une variable $picture qui contiendra toutes les infos relatives à chaque image.

i) Il ne reste plus qu'à “partir à la pêche” aux infos et à les placer sous format HTML dans une variable d'affichage.

Simple, non ?… Non, pas simple, mais très puissant ! En jouant avec les différentes requêtes WS et en arrangeant le code PHP à ses besoins, on peut afficher à peu près n'importe quelle information présente dans la galerie.

Dans un script Perl

Je vous propose un script Perl, en ligne de commande, qui va récupérer la liste des tags et les affiche dans la sortie standard.

Première version du script, sans être connecté.

#!/usr/bin/perl
 
use strict;
use warnings;
 
use JSON;
use LWP::UserAgent;
use Text::ASCIITable;
 
our $ua = LWP::UserAgent->new;
$ua->cookie_jar({});
 
my %conf;
$conf{limit} = 10;
$conf{base_url} = 'http://demo.phpwebgallery.net/ws.php';
$conf{partner_key} = undef;
$conf{response_format} = 'json';
$conf{username} = 'plegall';
$conf{password} = 'secret_password';
 
my $result = undef;
my $query = undef;
 
binmode STDOUT, ":encoding(utf-8)";
 
$query = pwg_ws_get_query(
    method => 'pwg.tags.getList',
    sort_by_counter => 'true',
);
 
$result = $ua->get($query);
my $tag_result = from_json($result->content);
my $t = Text::ASCIITable->new({ headingText => 'Tags' });
$t->setCols('id','counter','name');
 
my $tag_number = 1;
foreach my $tag_href (@{ $tag_result->{result}{tags} }) {
    $t->addRow(
        $tag_href->{id},
        $tag_href->{counter},
        $tag_href->{name}
    );
 
    last if $tag_number++ >= $conf{limit};
}
print $t;
 
sub pwg_ws_get_query {
    my %params = @_;
 
    my $query = $conf{base_url}.'?format='.$conf{response_format};
 
    if (defined $conf{partner_key}) {
        $query .= '&partner='.$conf{partner_key};
    }
 
    foreach my $key (keys %params) {
        $query .= '&'.$key.'='.$params{$key};
    }
 
    return $query;
}

The result is:

$ time perl piwigo_remote_disconnected.pl 
.---------------------------------------.
|                  Tags                 |
+-----+---------+-----------------------+
| id  | counter | name                  |
+-----+---------+-----------------------+
|  17 |     116 | Nature                |
|  34 |      83 | Architecture          |
|  24 |      63 | Culture & Communities |
|  23 |      55 | Flowers               |
| 124 |      53 | Square                |
|   8 |      53 | Animals               |
| 135 |      42 | Ref. Wikipedia        |
|  12 |      37 | Styles                |
| 114 |      34 | Islands               |
|  58 |      30 | Celebrations          |
'-----+---------+-----------------------'

real    0m1.554s
user    0m0.288s
sys     0m0.004s

J'utilise JSON comme format de réponse, car il existe un module CPAN qui se charge de transformer une chaîne JSON en une structure de données Perl. LWP::UserAgent s'occupe de simuler un navigateur, c'est un robot qui parcourt une page web. Text::ASCIITable sert à afficher les informations de manière convenable sans se fatiguer.

Maintenant je souhaite voir la liste des tags telle que je la vois lorsque je suis connecté sur mon site personnel. Il va donc falloir que le script soit authentifié avant de faire la demande de la liste des tags.

#!/usr/bin/perl
 
use strict;
use warnings;
 
use JSON;
use LWP::UserAgent;
use Text::ASCIITable;
 
our $ua = LWP::UserAgent->new;
$ua->cookie_jar({});
 
my %conf;
$conf{base_url} = 'http://localhost/~pierrick/piwigo/trunk/ws.php';
$conf{partner_key} = 'youhou';
$conf{response_format} = 'json';
$conf{username} = 'pierrick';
$conf{password} = 'very_secret_password';
$conf{limit} = 10;
 
my $result = undef;
my $query = undef;
 
binmode STDOUT, ":encoding(utf-8)";
 
# TODO : don't connect at each script call, use the session duration instead.
my $form = {
    method => 'pwg.session.login',
    username => $conf{username},
    password => $conf{password},
};
 
$result = $ua->post(
    $conf{base_url}.'/ws.php?partner=youhou&format=json',
    $form
);
 
# print "\n", $ua->cookie_jar->as_string, "\n";
 
$query = pwg_ws_get_query(
    method => 'pwg.tags.getList',
    sort_by_counter => 'true',
);
 
$result = $ua->get($query);
my $tag_result = from_json($result->content);
my $t = Text::ASCIITable->new({ headingText => 'Tags' });
$t->setCols('id','counter','name');
 
my $tag_number = 1;
foreach my $tag_href (@{ $tag_result->{result}{tags} }) {
    $t->addRow(
        $tag_href->{id},
        $tag_href->{counter},
        $tag_href->{name}
    );
 
    last if $tag_number++ >= $conf{limit};
}
print $t;
 
$query = pwg_ws_get_query(
    method => 'pwg.session.logout'
);
$ua->get($query);
 
sub pwg_ws_get_query {
    my %params = @_;
 
    my $query = $conf{base_url}.'?format='.$conf{response_format};
 
    if (defined $conf{partner_key}) {
        $query .= '&partner='.$conf{partner_key};
    }
 
    foreach my $key (keys %params) {
        $query .= '&'.$key.'='.$params{$key};
    }
 
    return $query;
}

La différence avec le script précédent, c'est l'appel à la méthode pwg.session.login en début de script et à la méthode pwg.session.logout en fin de script (pour purger la session au niveau du serveur, mais idéalement, il faudrait réutiliser la session existante).

Le “user agent” a associé un cookie à la session lors de l'appel à la méthode pwg.session.login. Ce cookie ne persiste pas, à la fin du script, c'est perdu (il suffirait de le sauver, mais ce n'est pas l'objet de la présente démonstration).

Sécurisation des Web Services

Chapitre obsolète avec Piwigo 2.0.0 et +

Malheureusement, les WS peuvent permettre des accès indésirables à la galerie. Pour éviter de tels désagréments et autres effets de bord, on va mettre en œuvre des mesures de sécurisation du service.

1 - On commence par renommer son PWG/tools/ws.htm en autre chose : walouM-ws.htm ou en biquet9-ws.htm.

2 - Ensuite, il faut activer le fonctionnement sécurisé de WS. Pour cela:

  • on éditera (ou on créera si inexistant) le fichier PWG/include/config_local.inc.php pour lui ajouter les lignes suivantes :
// On Access control false / Admim Web Service need Php cURL extension
// Controls are done on public basis or 
// if connected on member authorization basis
$conf['ws_access_control'] = true;

Le fichier est, bien entendu, à “uploader” sur son serveur d'hébergement. A partir de ce moment, le WS établi précédemment ne fonctionnera plus. C'est normal !

3 - Se rendre dans le panneau d'administration de sa galerie. On y trouvera un nouveau menu “Services Web” dans le menu “Spéciales”. C'est là qu'il faut se rendre pour la suite des opérations.

4 - Le menu “Service Web” va nous permettre de générer une clé spécifique pour chaque WS en fonction. De plus, il est possible de partager un WS avec un site partenaire que l'on n'administre pas forcément. Une clé sera alors également générée et donnée au partenaire en question pour qu'il puisse faire fonctionner le WS sur son site. Voici un exemple simple et concret :

  • Clé confidentielle ⇒ Entrez une clé à votre convenance mais de préférence complexe. Par exemple : Cl3PourW3bSvc1
  • Cible ⇒ Ne rien mettre
  • Accès restreint à ⇒ Ne rien mettre
  • Limite de transmission ⇒ Le nombre maximum d'informations (images) à remonter par exécution de la requête. A positionner en fonction des besoins. Pour l'exemple des paragraphes précédents, on choisira 5.
  • Durée en jours ⇒ Parle de lui-même : On peut régler ici la durée de vie de la clé WS de 0 (clé inactive) à 3650 jours (soit 10 ans !).
  • Commentaire ⇒ Décrivez ici le rôle de cette clé, pour quel WS, sur quel site externe, etc…

On valide et la clé est active.

5 - Il faut maintenant reprendre le WS que nous avons créé dans les paragraphes précédents pour le rendre à nouveau opérationnel. Pour cela, il suffit d'ajouter le paramètre partner dans la requête. Dans la continuité de notre exemple, nous ajoutons &partner=Cl3PourW3bSvc1 :

<?php
// initialisation de la session
$session = curl_init();
 
// configuration des options
curl_setopt($session, CURLOPT_URL,
"http://www.monsite.com/magalerie/ws.php?method=pwg.categories.getImages&partner=Cl3PourW3bSvc1&format=php&recursive=true&order=random&f_min_ratio=1.2&f_with_thumbnail=true&per_page=5&page=0");
curl_setopt($session, CURLOPT_HEADER, 0);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
(...)
?>

Un rapide contrôle permettra de vérifier que tout est à nouveau opérationnel.

6 - Mais ce n'est pas tout. Le fait de passer en mode sécurisé a invalidé le fonctionnement de notre ex-fichier PWG/tools/ws.htm (renommé à l'étape 1). Il faut maintenant lui administrer quelques corrections pour qu'il soit de nouveau utilisable.

Mais avant cela, il conviendra de créer une nouvelle clé, distincte de celles déjà créées pour les différents WS en fonction, qui sera celle de l'administrateur (ne sera pas diffusée à des tiers). En effet, seul l'administrateur devrait pouvoir utiliser ws.htm qui, je le rappelle, est destiné à effectuer les recherches initiales pour élaborer la requête WS.

Ensuite on édite le fichier ws.htm (Insérer partner=##### en remplaçant # par la clé) :

Ligne 103 : parameters:'partner=#####&format=json&method=reflection.getMethodList'

Ligne 140 : parameters:'partner=#####&format=json&method=reflection.getMethodDetails&methodName='

Ligne 191 - Ajouter : reqUrl += ”&partner=#####”;

7 - Enfin, quelques recommandations :

  • Les clés doivent rester secrètes. Dans le cas d'un partenariat externe, c'est un accord de confiance entre vous et le partenaire. S'il y a dérive, ou compromission de la (les) clé(s) par le partenaire, il est toujours possible de supprimer la clé dans le panneau d'administration. Ce qui invalidera, de fait, le partenariat.
  • Le mode non sécurisé peut, malheureusement, permettre d'écrire un module qui testera des mots de passe avec les utilisateurs connus de votre site (visibles sur commentaires par exemple) dont le vôtre… Et ainsi tenter de devenir administrateur/webmaster de votre galerie.

Détails des paramètres de sécurisation

Nous venons de voir un exemple simple et concret, mais reprenons ces paramètres.

Condition de fonctionnement : $conf['ws_access_control']

Clé confidentielle (Obligatoire) : Cette clé est unique et à partager avec votre partenaire.
Notre conseil: La clé doit être assez longue ( 8 caractères par exemple), et être assez complexe (avec des chiffres, des majuscules et minuscules, et des caractères spéciaux). Par exemple: “P!32r!k L3 G@2l”. Ce champ est masqué de tout accès en mode conseillé actif (Adviser).
Pensez qu'un de vos partenaire peut avoir plusieurs clés, mais que seules les restrictions de la clé utilisée lors de l'appel seront actives.

Cible (Facultatif) : Soit une liste d'identifiants d'images comme ceci
list/277,275,142,235,178,190,204,236-238,253,268,276,285,41,73
ou une liste de catégories comme : cat/16,32,21
ou encore une liste de tags : tag/22,61,36
Tout liste d'identifiants sera réduite à sa plus simple expression : list/41,73,142,178,190,204,235-238,253,268,275-277,285
Notre conseil: Prévoir une catégorie pour chaque partenaire réel. Ce point sera réexpliqué ultérieurement.

Accès restreint (Facultatif) : Si vous souhaitez limiter votre partenaire à une méthode précise, c'est une liste pré-établie, donc simple à comprendre. Notre conseil: ne pas limiter les méthodes sauf pour des cas très particuliers. Le forum est là pour vous éclairer si nécessaire.

Limite de transmission : Nombre d'images maximum adressées à votre partenaire à chacune de ses requêtes.

Durée : A partir de maintenant, indiquez la disponibilité en jours.

Commentaire : Vous permet de décrire qui se trouve derrière ce Service Web, de façon plus claire pour vous. N'oubliez pas qu'un Administrateur en mode conseiller peut lire le contenu de ce commentaire.

FIXME : D'éventuelles autres recommandations ?

 
Haut de page
projet/developpement/web_services.txt · Dernière modification: 2010/02/22 15:12 par gotcha
 
 
github twitter facebook google+ newsletter Faire un don Piwigo.org © 2002-2017 · Contact