How to save a base64 image from javascript with php | Our Code World

Bon, on ne m'enlèvera pas de la tête que c'est pas super intuitif, ni super simple, mais bon, je n'ai trouvé que ça qui fonctionne...

Mon souci

  1. Je crée une image côté navigateur avec canvas
  2. je veux l'envoyer à mon serveur pour stockage

On pourrait croire que c'est simple, hein... ben j'ai pas trouvé, personnellement.

J'ai essayé

  1. de transformer le canvas en blob et de l'envoyer via un formdata
  2. de transformer le canvas en blob et de l'envoyer comme un objet simple
  3. de transformer le canvas en DataURL et de l'envoyer via un formdata
  4. de transformer le canvas en DataURL et de l'envoyer comme un objet simple

Mais à chaque fois, j'ai pas été foutu de récupérer les données côté PHP (bon, je me doute qu'il doit y avoir un pacson de trucs que j'ignore encore, hein...)

Ensuite, j'ai pensé

«et si je passais les données au format base64, je devrais pouvoir les récupérer facilement...» car je pratique couramment un optimisme ridicule au sujet duquel il m'arrive encore de sombrer dans la stupéfaction à grand fracas...

Dont acte: je recommence à farfouiller avec des fetch, des posts pis tout mais sans succès: les données décodées font une image invalide.

en désespoir de cause

Je décide de procéder moins élégamment: je copie les données vers un formulaire caché que je poste en target blank pour pas perdre ma page de travail... Oui, je sais, c'est sale, c'est moche, c'est pas secure, j'en ai conscience, c'est pas la peine de m'enfoncer, j'ai déjà assez honte comme ça...

Je reçois bien de la base 64, je décode... Et l'image n'est toujours pas valide. Puis une recherche m'apprend qu'il faut virer l'en-tête base64 côté serveur avant de décoder pour que ça fonctionne...

Je teste et... ça marche.

SUPER INTUITIF MERCI

Advent of Code 2020 - 10 enseignements et bonnes pratiques en PHP

Un excellent article, très simple d'accès. Résumé pour mémoire mais je vous conseille d'aller lire le tout tant c'est clair et bien documenté:

1.Tout typer

... pour pouvoir compter sur le type des données

  • Les paramètres des fonctions function moncul(string $str) pour éviter de vérifier les paramètres puisqu'un type erroné provoquera une erreur
  • Les valeurs de retour des fonctions function moncul(string $str): int car en cas de retour d'un autre type, il y aura erreur. (pour les fonctions ne retournant rien, :void )
  • Les propriétés de classe : private int $mon_cul; pour qu'une erreur se déclenche en cas d'initialisation d'un type erroné.

2.Protéger ses classes par défaut

  • ajouter «final» à la déclaration de classe final class monCul(){ pour éviter tout héritage, même fortuit.
  • laisser ses propriétés en private par défaut
  • laisser ses méthodes en private par défaut jusqu'à ce qu'on ait besoin de les appeler de l'extérieur

3.Utiliser les comparaisons strictes

... pour éviter les confusions false/0 etc

4.Se passer des «if»

En utilisant l'opérateur ternaire condition ? valeur retournée si true : valeur retournée si false;

Pourquoi ? Parce que c'est plus court mais aussi parce qu'on peut placer la condition directement dans une assignation ou à la place d'un paramètre: $count += ($value === CONTROL_VALUE) ? 1 : 0;

Par contre, je trouve qu'on y perd BEAUCOUP en lisibilité et en organisation.

5.La fonction « sscanf »

Pour analyser une chaîne selon un format (et à la place d'un explode plus lourd). C'est l'inverse de printf(). ( https://www.php.net/manual/fr/function.sscanf.php )

6.L'inversion de valeurs en une ligne

et avec autant de valeurs qu'on veut

[$var1, $var2, $var3, $var4] = [$var4, $var3, $var2, $var1];

7. L’opérateur de décomposition « … »

$intersection = array_intersect(...$bigArray); au lieu de $intersection = array_intersect($bigArray[0], $bigArray[1], $bigArray[2]); // Etc.

8. Toujours ajouter un compteur de boucle pour sortir des while

Ça m'a rappelé un épisode de BigBang Theory dans lequel Sheldon est prisonnier d'une boucle dans son algorithme HowToMakeANewFriend... (c'est Howard qui l'en sort en implémentant un compteur comme condition de sortie).

$block++;
    if ($block > 1000) {
        break;
    }

9.Utiliser les fonctions liées aux tableaux

Je plussoie vigoureusement ce point particulier

Avant de se lancer dans un traitement de tableau en créant une fonction ou une méthode exprès, relisez la doc de toutes les fonctions commençant par Array_ ... histoire de ne pas réinventer la roue.

joebarteam6p43.jpg

10.Manipuler les tableaux avec les callbacks et les Collections

Pour manipuler un tableau, penser à utiliser array_map plutôt que foreach si c'est possible:

  • utilisation simple array_map('trim',$tableau)
  • fonction anonyme ```array_map(function($k){ code de traitement },$tableau);
  • avec une méthode array_map(array($instance, 'methode'), $tableau)

Le code de samedi: une API mematic

Au menu du jour une API qui permet de memiser une image du ouebe en une ligne...

Vous allez me ressortir   Et allez donc  une autre API à la mords-moi le zboub  codée à l arrache en mode sitotditsitotfait    .jpg

Ce à quoi je vous répondrai  avec une éloquence qui  pour être coutumière chez moi  ne saurait manquer de provoquer une légitime admiration .jpg

 OUI  .jpg

Koitesce

Ben, je viens de vous le dire ! vous m'écoutez ou pas quand je parle ?!

Il s'agit de pouvoir fabriquer un meme en un minimum de temps: une image glanée sur le net et pouf, c'est parti.

Comment que ça marche-t-il ?

Les arguments GET sont les suivants:

  • t: le texte à afficher (on peut mettre des /n pour sauter des lignes)
  • i: l'url de l'image et c'est tout.

Comme pour fancytation et les autres API:

  • help: affiche une aide
  • download: permet de télécharger le script php de l'api

Cerise sur le cageot

Vous pouvez générer un bookmarklet destiné à utiliser l'API en utilisant l'argument $_GET bookmarklet ce qui donnera :

Copier ce lien de bookmarklet: Mematic

Ainsi, il suffit d'utiliser la fonction «afficher l'image» de votre navigateur puis de cliquer sur le bookmarklet pour entrer le texte du meme et récupérer l'image générée.

1.jpg

2.jpg

3.jpeg

 Exemples   .jpg

Quand ton pote sort un sscript PHP tout pété, qu'il l'appelle pompeusement API mais que tu l'aimes quand même...

t'As vU cOmMeNt jE kOd tRo bI1 ?! C oUf !

Allez dans le pet du saigneur

GitHub - josephernest/void: Void is a blogging platform.

MMMouaip... Oui, c'est minimaliste, mais ce n'est pas un CMS: il ne permet pas du tout de gérer le contenu, il se contente de mettre en HTML des fichiers txt écrits en MD et collés sur le serveur via FTP...

En gros, c'est un simple script php qui liste le contenu d'un dossier à l'aide d'un glob, parse le contenu à la recherche de balises normailsées (author etc) et génère le HTML à l'aide de la lib parsedown.

Alors, ce n'est pas pour autant que c'est nul, hein: c'est simple et uber minimaliste, en effet... C'est bien que ça existe.

Mais ce n'est pas un CMS, on ne peut RIEN gérer sans accès FTP, on ne peut pas utiliser de plugins, de configuration etc...

Via https://valentin.tomasso.fr/liens/


Le code du dimanche: Iconeleon

Comme je le disais dans le billet précédent à propos de SVGBox, l'idée était bonne mais le poids était rédhibitoire.

Pourtant, ça peut être sympa d'avoir un catalogue d'icônes prêtes à servir et dont on puisse altérer la couleur, sans compter que ce serait une bonne alternative aux webfonts tout en étant plus accessible.

Donc, j'ai récupéré le pack d'icônes de fontAwesome et j'ai bidouillé une API qui permette de faire la même chose que SVGBox.net, à savoir obtenir une icône svg dans la couleur que l'on souhaite.

Par exemple:

api.warriordudimanche.net/iconeleon/?i=headphones donne:

et si on ajoute le paramètre c on peut changer la couleur: api.warriordudimanche.net/iconeleon/?i=headphones&c=red

La couleur peut-être au format HTML, un nom de couleur css ou un rgba quelconque...

api.warriordudimanche.net/iconeleon/?i=headphones&c=rgba(255,0,255,0.5)

Comme pour fancytation

Toute icône modifiée est sauvegardée en cache pour éviter une surcharge du serveur

  • help: affiche une aide
  • iconlist: renvoie la liste des icones au format json
  • search=string: renvoie le résultat de la recherche au format json
  • download: permet de télécharger le script php de l'api
  • Et en plus

    Je vous ai ajouté un frontend minimaliste pour rechercher les icones dans les 1615 du pack.

    liens

    Voilà

    Du coup, si ça peut être utile, n'hésitez pas à vous servir voire à proposer un frontend plus... comment dire ? abouti ?

    Nouvelle version: Unicode

    En passant, j'ai mis à jour ma page sur les caractères unicode...

    Il y a plus de rubriques et j'ai ajouté un moteur de recherche qui accepte plusieurs mots séparés par des espaces.

    par exemple: http://unicode.warriordudimanche.net/?search=aubergine

    Allez, bisou !

    Getlib: ramener des bibliotheques & frameworks en local en une ligne [Edité]

    Certains se souviennent peut-être de goofi, pour récupérer des google fonts en local; sur la base de ce script, j'ai bricolé une version qui permettra de faire la même chose avec les bibliothèques et frameworks (notamment js) que tout un chacun utilise et dont l'appel participe aux stats de google et consorts à chaque requête sur leur serveur.

    Donc, en gros, il suffit de remplacer l'appel du script dans le en ajoutant getlib.php?url= devant.

    Ainsi

     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    deviendra

    <script src="http://monserveur/getlib.php?url=https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    Le fichier est récupéré une seule fois et seule la vertsion locale sera renvoyée par la suite.

    Au cas où vous voulez que le script récupère une éventuelle mise à jour, il suffit d'ajouter update dans l'url:

    <script src="http://monserveur/getlib.php?update&url=https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

    Getlib vérifiera alors si le fichier distant a changé et le retéléchargera si c'est nécessaire.

    Comme avec Goofi, seule l'IP du serveur qui héberge le script est connue du serveur distant, jamais celle du visiteur.

    C'est tout! Je n'ai pas testé à fond encore et les erreurs ne sont pas gérées pour le moment, mais ça fonctionne quand même pas mal !

    <?php 
    # get libs from distant servers to local (& avoid unnecessary requests to servers who can log user's connections)
    # ex:  
    # https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
    # becomes
    # getlib.php?url=https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
    # if you want to update local file if the distant one changes, just add "update" 
    # getlib.php?update&url=https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
    # author: warriordudimanche.net
    # 
    $lib_folder='libs/';
    $check_updates=isset($_GET['update']);
    
    if (!empty($_GET['url'])){
        if (!is_dir($lib_folder)){mkdir($lib_folder);}
    
        $url=strip_tags($_GET['url']);
        define('LOCAL_FILENAME',$lib_folder.basename($url));
        $ext=pathinfo(LOCAL_FILENAME)['extension'];
        //$flag='non';
        if (
            !is_file(LOCAL_FILENAME)
            ||
            ($check_updates && !isSameFile($url))
    
        ){
            $lib=file_get_contents($url,false,null,0,1000000);
            file_put_contents(LOCAL_FILENAME,$lib);
            $head = array_change_key_case(get_headers($url, TRUE));
            file_put_contents(LOCAL_FILENAME.'.info', $head['last-modified']);
            //$flag='oui';
        }
        if ($ext=='css'){
            $mime='text/css';
        }elseif ($ext=='js'){
            $mime='text/javascript';
        }else{
            $mime=mime_content_type(LOCAL_FILENAME);
        }
    
        header('Content-Type: '.$mime);
        exit(file_get_contents(LOCAL_FILENAME));
    }
    
    
    function isSameFile($url){
        $head = array_change_key_case(get_headers($url, TRUE));
        $local=file_get_contents(LOCAL_FILENAME.'.info');
        $distant=$head['last-modified'];
        return $distant==$local;
    }

    getlib.zip le dépôt

    Comme toujours,
    c'est aux autres de débugger
    les scripts que tu commets, heu... commit...
    super.
    🗦

    Et je vais t avouer un truc  j ai même pas honte   C est même ma marque de fabrique  une genre de  Bronco s touch .jpg

    Googol résiste (et ça fait du boulot)

    imgbin-computer-icons-avatar-deadpool-desktop-deadpool-pixel-art-x5Gc4h4YnvARncaJgpPeGT2bw.png
    La version 4.2 «unban» de Googol est en phase de test et elle m'a pris le pack premium de chez MaximumEffort. Toutefois, ça valait le coup: plutôt que de me contenter de rediriger vers duckduckgo lors du bannissement par google - ce qui arrivait de plus en plus souvent - j'ai opté pour l'utilisation temporaire d'un moteur alternatif à la place de google...

    (...)

    Plugin pluxml: reposter vers mastodon directement.

    icone
    Si ça intéresse quelqu'un, voici un plugin dont le but est de reposter automatiquement les billets de pluxml vers un compte mastodon.

    pluxml2mastodon utilise le chapô ou le contenu (si le chapô est vide) comme corps de message en le retaillant si nécessaire.

    Dans les options, il faudra compléter l'url de votre instance et le jeton de sécurité; vous pouvez également ajouter un message d'en-tête et de pied, si vous le souhaitez.

    (...)

    RoR - un générateur d'avatars auto-hébergeable en un script

    Bon, j'ai un peu tout dit dans le titre... Toutefois, je peux préciser que ce script permet de générer un avatar à partir d'une chaîne de caractères (genre un pseudo, quoi )

    Le script utilise les variables $_GET suivantes:

    • str : la chaîne de caractères (obligatoire)
    • sz : la taille souhaitée (par défaut:128)
    • c1 : couleur d'avatar (optionnel, par défaut le script déterminera une couleur en fonction de la chaîne)
    • c2 : pareil que c1 mais pour la couleur de fond.

    Du coup Par conséquent, la requête suivante:

    index.php?str=Bronco&sz=128&c1=ff0000&c2=00ff00

    donnera

    avatar généré

    et

    index.php?str=Bronco

    donnera

    avatar généré

    A noter que lorsque l'avatar est généré, il est sauvegardé dans un dossier avatars/ afin d'éviter de le régénérer à chaque demande.

    «Mais comment t'as fait ?» allez-vous me demander d'un ton péremptoire autant que fébrile
    Non,non... on s'en fout... en fait.
    🗦
    PAN
    🗦

    Donc, le premier problème était d'avoir une pattern pour chaque lettre sur une grille qui ne soit pas trop étendue. Après avoir réfléchi un bon moment, je me suis frappé le front en me disant que la pattern était toute trouvée: l'ordre en binaire de la lettre à encoder...

    Second problème, le nombre de lettres et de caractères potentiels m'obligeaient à avoir une grille trop grande (minuscules/majuscules/nombres -> 62 caractères !) 62 en binaire 111110, soient 6 cases x2 pour la symétrie, on se retrouve avec une matrice de 12 x 12... trop à mon goût.

    Troisième problème, la taille variable des chaînes potentiellement fournies par l'utilisateur. Il faudrait normaliser ces chaînes avant traitement... pfff.

    Illumination: le hash d'une chaîne est toujours de la même longueur... et hash('crc32','blabla'); donne toujours une chaîne de 8 caractères hexadécimaux \o/ : tous les problèmes sont résolus:

    • encodage de 16 caractères (0 à F) : 0000 à 1111.
    • chaîne de longueur fixe quelle que soit les données fournies
        $h1=hash('crc32',$_GET['str']); # pour la génération du dessin et de la couleur 1
        $h2=hash('crc32b',$_GET['str']);#pour la génération de la couleur 2

    Il ne reste plus qu'à tracer des carrés de la couleur d'avatar à l'emplacement des 1 et de la couleur de fond à la place des 0.

    function drawLine($linenb,$pattern,$size){
        global $image,$couleur_avatar,$couleur_fond;
        for ($i=0;$i<9;$i++){
            $x=$i*$size;
            $y=$linenb*$size;
            if ($pattern[$i]==1){
                imagefilledrectangle ( $image , $x,$y  , $x+$size ,$y+$size , $couleur_avatar );
            }else{
                imagefilledrectangle ( $image , $x,$y  , $x+$size ,$y+$size ,$couleur_fond);
            }
        }
    }

    Le reste est relativement simple à saisir, je vous mets donc le script complet

    <?php 
    ########################
    #                      #
    # █████   ████   █████  #
    # ██  ██ ██  ██ ██  ██ #
    # ██  ██ ██  ██ ██  ██ #
    # █████  ██  ██  █████  #
    # ██  ██ ██  ██ ██  ██ #
    # ██  ██ ██  ██ ██  ██ #
    # ██  ██  ████  ██  ██ #
    #                      #
    ########################
    # Ror: avatar generator
    # @author: bronco@warriordudimanche.net
    # howto: use get vars to generate an avatar (once generated, it'll be saved in avatars/ folder)
    # ?str=[string] (required)
    # ?sz= [integer] avatar's size (opt.) 
    # ?c1= [string] avatar's color (opt.)
    # ?c2= [string] avatar's background color (opt.)
    
    ###############################
    #                             #
    #  ░░░░  ░   ░░  ░░░░  ░░░░░░ #
    #   ░░   ░░  ░░   ░░   ░ ░░ ░ #
    #   ░░   ░░░ ░░   ░░     ░░   #
    #   ░░   ░░░░░░   ░░     ░░   #
    #   ░░   ░░ ░░░   ░░     ░░   #
    #   ░░   ░░  ░░   ░░     ░░   #
    #  ░░░░  ░░   ░  ░░░░   ░░░░  #
    #                             #
    ###############################
    
    if (!is_dir('avatars')){
        mkdir('avatars');
    }
    $avatar_filename='';
    
    if (!empty($_GET['c1'])){
        $c1=strip_tags($_GET['c1']);
        $avatar_filename.='-c1='.$c1;
        $c1=separatRGB($c1);
    }
    if (!empty($_GET['c2'])){
        $c2=strip_tags($_GET['c2']);
        $avatar_filename.='-c2='.$c2;
        $c2=separatRGB($c2);
    }
    if (!empty($_GET['sz'])){
        $size=intval(strip_tags($_GET['sz']));
    }
    if (empty($size)){$size=128;}
    $avatar_filename='x'.$size.$avatar_filename.'.png';
    $dotsize=$size/9;
    
    
    ##################################################################
    #                                                                #
    # ░░░░░░ ░░  ░░ ░   ░░  ░░░░  ░░░░░░  ░░░░   ░░░░  ░   ░░  ░░░░  #
    # ░░     ░░  ░░ ░░  ░░ ░░  ░░ ░ ░░ ░   ░░   ░░  ░░ ░░  ░░ ░░  ░░ #
    # ░░     ░░  ░░ ░░░ ░░ ░░       ░░     ░░   ░░  ░░ ░░░ ░░  ░░    #
    # ░░░░░  ░░  ░░ ░░░░░░ ░░       ░░     ░░   ░░  ░░ ░░░░░░   ░░   #
    # ░░     ░░  ░░ ░░ ░░░ ░░       ░░     ░░   ░░  ░░ ░░ ░░░    ░░  #
    # ░░     ░░  ░░ ░░  ░░ ░░  ░░   ░░     ░░   ░░  ░░ ░░  ░░ ░░  ░░ #
    # ░░      ░░░░  ░░   ░  ░░░░   ░░░░   ░░░░   ░░░░  ░░   ░  ░░░░  #
    #                                                                #
    ##################################################################
    
    function separatRGB($color){
        $color=str_replace('#','',$color);
        if (strlen($color)==3){
            $color=$color[0].$color[0].$color[1].$color[1].$color[2].$color[2];
        }
        $RGB=array();
        $RGB['r']=hexdec(substr($color, 0,2));
        $RGB['g']=hexdec(substr($color, 2,2));
        $RGB['b']=hexdec(substr($color, 4,2));  
        return $RGB;
    }
    
    function drawLine($linenb,$pattern,$size){
        global $image,$couleur_avatar,$couleur_fond;
        for ($i=0;$i<9;$i++){
            $x=$i*$size;
            $y=$linenb*$size;
            if ($pattern[$i]==1){
                imagefilledrectangle ( $image , $x,$y  , $x+$size ,$y+$size , $couleur_avatar );
            }else{
                imagefilledrectangle ( $image , $x,$y  , $x+$size ,$y+$size ,$couleur_fond);
            }
        }
    }
    
    
    
    ###########################################################
    #                                                         #
    #  ░░░░  ░░░░░░ ░   ░░ ░░░░░░ ░░░░░   ░░░░  ░░░░░░ ░░░░░░ #
    # ░░  ░░ ░░     ░░  ░░ ░░     ░░  ░░ ░░  ░░ ░ ░░ ░ ░░     #
    # ░░     ░░     ░░░ ░░ ░░     ░░  ░░ ░░  ░░   ░░   ░░     #
    # ░░ ░░░ ░░░░░  ░░░░░░ ░░░░░  ░░░░░  ░░░░░░   ░░   ░░░░░  #
    # ░░  ░░ ░░     ░░ ░░░ ░░     ░░  ░░ ░░  ░░   ░░   ░░     #
    # ░░  ░░ ░░     ░░  ░░ ░░     ░░  ░░ ░░  ░░   ░░   ░░     #
    #  ░░░░  ░░░░░░ ░░   ░ ░░░░░░ ░░  ░░ ░░  ░░  ░░░░  ░░░░░░ #
    #                                                         #
    ###########################################################
    if (!empty($_GET['str'])){
        $h1=hash('crc32',$_GET['str']);
        $h2=hash('crc32b',$_GET['str']);
    
        if (empty($c1)){$c1 = separatRGB($h1);}
        if (empty($c2)){$c2 = separatRGB($h2);}
    
        $s=$h1.$h2[0];
        $file='avatars/'.$s.$avatar_filename;
        if (is_file($file)){
            header ("Content-type: image/png");
            exit(file_get_contents($file));
    
        }
    
        $image = @ImageCreate ($size, $size) or die ("Erreur lors de la création de l'image");
        $couleur_fond   = ImageColorAllocate ($image, $c1['r'], $c1['g'], $c1['b']);
        $couleur_avatar = ImageColorAllocate ($image, $c2['r'], $c2['g'], $c2['b']);
    
        $a[dechex(0)]='000010000';
        $a[dechex(16)]='111111111';
    
        for ($i=1;$i<=15;$i++){
            $bin=decbin($i);
            $bin=str_repeat('0', 4-strlen($bin)).$bin;
            $a[dechex($i)]=$bin.'1'.strrev($bin);
        }
    
    
    
        for ($i=0;$i<9;$i++){
            drawLine($i,$a[$s[$i]],$dotsize);
        }
    
        header ("Content-type: image/png");
    
        ImagePng($image,$file);
        chmod($file,0644);
        ImagePng($image);
    }
    
    
    ?>

    Le script est téléchargeable ici

    (...)

    C'est con, j'ai ri 4

    Pour celles et ceux qui en ont marre de leur semaine, de la météo, de la politique, des affaires, des gens qui tuent leurs conjoints alors qu'ils faisaient genre «chuis trop inquiet sur la vie de ma reum», du code du travail, des inondations, qu'on leur parle de la Seine ou des nichons de la famille Kardachiants, voici un Dump du Dredi: attention, c'est con (mais j'ai ri )

    (...)

    Fil RSS des articles
    Caching time 0.052972 s