L’API Filesystem : introduction

Mais c’est quoi cette bouteille de lait ?!!

Une « brique » de lait en fait, le genre de brique de code que WP a rajouté pour son propre usage et qui peut nous intéresser dans nos dévs. WP est très imparfait. Nous, en tant que communauté de dévs, sommes les premiers à le critiquer, à essayer de faire avancer les choses.

Cependant ses fonctions et classes sont bien souvent pratiques car elles font gagner du temps.

🔗 Points importants

Au plus court, au plus simple ça donne :

  • un utilisateur, au sens où on va l’entendre ici, est un compte qui a accès à une machine
  • un groupe d’utilisateurs, c’est la version serveur des rôles WP, on pourra donc retrouver un groupe admin
  • les permissions fichiers c’est qui à accès à quoi pour faire quoi. Une permission c’est par exemple 3 chiffres, le premier pour l’utilisateur, le deuxième pour le groupe et le troisième pour le reste du monde.

Donc pour illustrer ce dernier point, dans le cadre d’une application web qui ferait tourner des fichiers PHP, au hasard WordPress. Une permission 777 sur un des fichiers c’est l’open bar, tout le monde peut écrire, lire, exécuter le fichier ! En termes de sécurité c’est pas la joie.

644, à l’inverse, ça convient, le propriétaire peut lire et écrire et le reste peut seulement lire le fichier.

🔗 PHP Filesystem

Pour jouer avec le système de fichiers en PHP, on connaît tous les chmod(), copy(), fopen() et autres unlink().

Source

On s’en sert pour déplacer, copier, créer des fichiers, des répertoires à la volée, entre autres.

Ça marche à peu près correctement sauf quand les configs serveur font de la merde ce qui arrive trop souvent. S’ajoute qu’on doit blinder nos classes de méthodes à la con pour faire les vérifications et tutti quanti pour au final pas faire des trucs de folie quoi. C’est juste chiant !

Prenez maintenant la fonction request_filesystem_credentials() de WordPress, des lignes et des lignes de code épargnées et la fonction va grosso modo s’occuper de trouver la meilleur façon d’interagir avec le système de fichiers.

🔗 WP Filesystem

Parmi les apports de l’API, il y a le fait d’agir en tant qu’utilisateur propriétaire des fichiers de l’installation WP. Ne pas le faire, autrement dit « agir » en tant qu’utilisateur serveur, c’est source d’erreurs.

Cette erreur de permission et d’utilisateur est très fréquente lorsqu’on code des scripts.

🔗 D’où vient cette API ?

Partant d’un de ses propres besoins, forts, WP a donc mis en place toute une API pour s’adapter à la très grande variété de caractéristiques techniques des serveurs qui accueillent des installations WordPress.

Pour les dévs de plugins c’est essentiel car la config serveur est par définition inconnue. On publie des codes mais on ne sait pas qui et où ils seront utilisés. Une part importante des topics de support peut être alors évitée en utilisant les APIs WP car on est à peu près sûr qu’un grand nombre de cas, surtout ceux auxquels on ne pense pas, a déjà été prévu. De l’intérêt des patches produits sur le trac et qui viennent améliorer la compatibilité.

🔗 Que se passe-t-il ?

Oh mais qu’est-ce qui se passe ? L’API va gérer « le dialogue » avec le système de fichiers et si tout est fluide et direct parce que les configs sont standards par exemple, et bah tout roule et on a plus qu’à faire ce qu’on a à faire.

Si ça coince, l’UI est prévue. Le cas le plus connu, même de celles et ceux qui ne connaissent pas l’API, c’est ce fameux écran qui réclame des identifiants FTP au moment d’installer ou mettre à jour un plugin. Typiquement ici, l’API Filesystem a détecté qu’il lui manquait des informations essentielles pour écrire, supprimer ajouter des fichiers sur l’installation.

Je ferais le parallèle avec oAuth2, alors attention qui n’a rien à voir mais au niveau de l’intérêt. Je laisse WP gérer l’UI de manière standardisée. Pfiou, si je devais me coltiner les écrans, fatigue…

🔗 Le code ?

Dans une page d’options en administration, on imagine un formulaire avec un champ file qui enverrait un fichier.

Au moment du traitement, on va utiliser l’API pour savoir si c’est possible directement.

$url = wp_nonce_url('themes.php?page=example','example-theme-options');
if (false === ($creds = request_filesystem_credentials($url, '', false, false, null) ) ) {
	return; // stop processing here
}

Source

Mais la petite subtilité c’est qu’en fait ici on a pas encore utilisé l’API les enfants.

C’est pour ça que dans la doc on trouve plus loin :

if ( ! WP_Filesystem($creds) ) {
	request_filesystem_credentials($url, '', true, false, null);
	return;
}

Ce fameux $creds nous sert à initialiser l’API. Ici le code dit:

si ça coince bah demande les identifiants

Le code est beau car simple et lisible même si on ne voit pas la machinerie derrière, cinéma tchitcha ^^.

Une fois l’API initialisée, on récupère une globale :

global $wp_filesystem;

et des méthodes à base de put_content(), is_dir(), mdkir(), chmod(), copy(), etc.

Pareil, ici le gros de l’abstraction a déjà été fait. Pour nous c’est juste un put_content() mais derrière y a du taf… qu’on aura pas à refaire.

🔗 Alors la perfection sur Terre ?

🔗 Bien

Ça gère la sécurité de base et assure donc une grande compatibilité. Ces deux points sont essentiels dans le développement, en général, mais à plus forte raison pour des plugins opensource (ou pas d’ailleurs).

🔗 Mauvais

Y a des cas où l’utilisateur final va devoir entrer ses identifiants plusieurs fois.

Le réflexe Ux qu’on a tous c’est :

je me suis identifié une fois et basta !

et là le même écran qui apparaît plusieurs fois donne l’impression à l’utilisateur que le code foire alors que ce n’est pas le cas. D’ailleurs la doc est assez claire sur le sujet (merci au rédacteur).

Source

Ce mauvais point est pourtant un élément de sécurité car on veut s’assurer que l’utilisateur que l’on va utiliser pour écrire dans le système de fichiers est bien le propriétaire. C’est pas open bar quoi. WP ne stocke pas les credentials par défaut.

On peut toujours aller changer ça avec des constantes dans wp-config.php mais donc bien savoir ce qu’on fait à ce moment-là et je ne vous les listerai donc pas ici tongue

🔗 Mais quand ? comment ? où

C’est le genre de questions qu’on se pose quand on découvre. On voit à peu près comment ça marche, on teste, quand on est jeune on a envie de l’utiliser à toutes les sauces et de crier au monde à quel point on a tout compris mais la vie c’est pas vraiment ça en fait.

🔗 Maître-mot

Faut savoir ce qu’on fait. Si c’est pour l’utiliser partout sous prétexte que c’est une API WordPress, rentrez chez vous et fermez la porte SVP.

🔗 Lecture, écriture ?

Pour la lecture il y a une méthode get_contents() dans la globale. L’argument est logiquement le path vers le fichier en question.

Pour l’écriture, les méthodes is_dir() et mkdir() sont pratiques pour créer un répertoire par exemple.

🔗 Mot du maître

Je vous traduis Otto parce que sa réponse est complète, je fais du WP j’évite de réinventer la roue. Si on doit utiliser l’API Filesystem ce n’est probablement pas pour faire des trucs dans le dossier upload !

J’approuve ce message. Pour ce répertoire, on a déjà des fonctions définies et l’usage des uploads, a priori, c’est d’accueillir des uploads. Alors « téléversez » !

Source

🔗 Les trucs qui vont vous faire suer

🔗 Tâches indirectes

Si on repense à ce qu’on vient d’introduire, et bien j’ai des élements d’UI qui sont nécessaires pour faire marcher le bazar. J’ai besoin d’identifiants et c’est pas moi qui le dit c’est l’API de WP evilgrin

Donc ça veut dire que si je ne demande rien à mon utilisateur, comme quand je fais tourner une tâche de fond et qui ici se servirait de l’API Filesystem je peux être bloqué et si mon utilisateur n’est pas assez avancé pour savoir que les constantes évoquées plus haut sont nécessaires c’est foutu. Et admettons-le, ici, c’est quand même un tout petit peu technique.

Donc dans ce cas, à moi de faire une doc claire qui expliquera bien à l’utilisateur ce qu’il faut faire. Ou alors j’utilise pas cette putain d’API evil

🔗 La sécurité ne se fait pas complètement toute seule

J’ai écrit que la sécurité est gérée par l’API, certes, mais se méfier des articles avec pour titre « the right way to manage local files » => bim API Filesystem.

Les raccourcis, ça fonctionne jamais en matière de code, l’humain, la conception, les choix, c’est là que tout se joue. Si vous omettez cette étape, vous ne pensez pas par vous même et vous pouvez aboutir à des erreurs. Je dis ça comme un leitmotiv, je pense qu’on doit tous essayer de se le rappeler quel que soit son niveau.

Vous aurez peut-être remarqué qu’on couple avec l’utilisation des nonces. Vu qu’on demande des identifiants, on s’assure que la demande vient bien de l’utilisateur et pas d’un imitateur.

🔗 Paths

Vous devrez résister à la tentation d’utiliser l’existant. ABSPATH par exemple à oublier. L’API Filesystem vous proposera des méthodes de remplacement et ce sont elles qu’il faudra utiliser car vous ne serez pas sûrs que le contexte est le même dans tous vos appels à cause de la méthode de connexion retenue par l’API.

🔗 Conclusion

On a entre-aperçu ici le potentiel de cette API « haut-niveau » j’espère. On l’a aussi vu, c’est relativement simple de prime abord. La difficulté vient de l’abstraction nécessaire pour comprendre son intérêt véritable mais heureusement celle-ci est en grande partie « digérée » par l’API elle-même pour notre confort.

Ma manière d’aborder cette API est de raisonner en termes d’utilisateur mais au sens serveur. C’est la raison pour laquelle j’ai fait l’analogie avec les rôles WP. Je suis tel utilisateur, j’ai accès à telles permissions, et, en général pour une bonne raison.

Je suis dév de plugins et de thèmes, je suis le core de WP, j’ai besoin de faire certaines tâches administratives. Je dois être en mesure de supprimer et/ou créer des fichiers sans avoir à faire intervenir l’utilisateur final mais au besoin je demande les accès serveur. C’est transparent mais beaucoup de dévs n’implémenteront pas l’API à cause de ça justement. C’est trop contraignant pour l’utilisateur final d’avoir à remettre ses credentials parfois 4 fois de suite et aller modifier des constantes dans un wp-config.php faut forgetter twisted