Maison > interface Web > tutoriel CSS > % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé

% CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé

Linda Hamilton
Libérer: 2025-01-18 06:10:09
original
388 Les gens l'ont consulté

Il s'agit d'un suivi direct de l'Obtention de données de réponse API 32 bits en CSS

En CSS, 16 bits de données de réponse, placés à la fois dans la largeur intrinsèque et dans la hauteur intrinsèque, constituaient une énorme amélioration par rapport à l'impossibilité d'obtenir du tout les données de réponse de l'API (sans JavaScript)...

Cependant, dans les jours qui ont suivi, mon esprit s'est penché dans une direction :
Ce serait bien plus amusant si c'était 16 bits 32 fois au lieu de seulement deux fois.

Gif recording of a harsh terminal app setting several integer values to an array of variables one at a time

Emballer 512 bits dans un SVG pour l'exfiltration

Je méditais avant de me coucher et j'ai été frappé par une autre pensée inspirée -

"Et s'il était possible au document image lui-même d'animer sa propre taille intrinsèque ?"

La chaîne habituelle de réalisations après une pensée inspirée, chacune a montré une compréhension de la façon dont cela pouvait être accompli... J'avais juste besoin de comprendre si un tel type d'image existait.

J'ai attrapé mon téléphone et j'ai cherché parmi tous les formats d'images animées que je connaissais, pour voir si l'un d'entre eux en était capable. svg, webp, apng, gif, peut-être des formats vidéo bizarres ? Je n'en ai pas trouvé.

Le matin, quelque chose en moi m'a dit de continuer à creuser sur SVG.

J'ai essayé le CSS intégré, les requêtes multimédias, les définitions utilisées, les définitions davantage utilisées, en plongeant dans les nombreux documents d'animation SVG, en essayant de les tromper et en lisant d'autres idées et propriétés liées à l'animation - rien ne pouvait me laisser définir la hauteur ou la largeur.

Mais ce dernier lien m'a fait réfléchir...

... et viewBox ? J'aurais d'autres obstacles à surmonter mais... Est-ce que possible d'animer ?

vvv
C'EST !!
^^^

Trier l’espace des solutions

Maintenant, le problème est que si vous ne définissez pas les attributs de largeur et de hauteur sur l'élément racine svg, puis essayez d'utiliser le svg comme contenu sur un pseudo, il restitue 0px x 0px car c'est un document vectoriel et n'a plus de taille intrinsèque.

J'ai donc recherché et ajouté préservationAspectRatio... Toujours 0x0... mais ensuite dans mon CSS, j'ai épinglé la largeur à 10px et laissé le rapport hauteur/largeur préservé de la viewBox déterminer la hauteur (que je peux modifier avec un animation intégrée dans le SVG) aaet... l'élément html le contenant a atteint la hauteur attendue.

:3

S'il n'y avait qu'une seule image, cela prenait mes 32 bits d'origine et les coupait en deux ; puisqu'une seule dimension peut être exfiltrée tandis que l'autre est statique.

MAIS ! Maintenant, ma 2ème dimension était le temps et la première est à la merci du temps, donc il y a plus qu'assez de données disponibles.

Comme c'est excitant !

J'ai appris tout ce que je pouvais sur la façon de contrôler l'animation dans les SVG et j'ai créé un script côté serveur pour générer mon premier SVG animé :

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

(pourquoi php ?! - parce que j'avais déjà un serveur pour lequel je payais depuis des années, configuré pour exécuter php dès le départ.... Et même si j'ai gagné merveilleusement ma vie en connaissant JavaScript et node très bien, parfois c'est amusant de rechercher chaque fonction, opérateur et syntaxe pour progresser dans quelque chose que vous savez que vous pouvez faire sans connaître les détails. mdr)

Maintenant, passons à mon premier % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé de l'article précédent pour voir CSS répondre et changer de taille --vars au fur et à mesure que le SVG avance :

Confirmé ! On peut lire le changement de taille. Comme dans l'article précédent, au final, il utilisera la technique de mesure view-timeline à la place de cette technique tan(atan2()).

Il cuit mon processeur, nous voudrons donc le supprimer du contenu une fois l'exfiltration terminée.

Conceptuellement, comment exfiltrer le temps 1D de manière procédurale

La démo ci-dessus n'est pas très utile en elle-même. Il rapporte une copie de la hauteur chaque fois qu'elle est là, mais nous devons la sauvegarder... et à quoi sert un tas de valeurs de 16 bits si vous ne savez pas et ne pouvez pas faire confiance à la commande ?

Je sais que je peux accumuler des valeurs en CSS avec le CPU Hack et déterminer mathématiquement quel --var met à jour les valeurs entrantes au lieu de simplement conserver sa valeur précédente, donc je ne m'inquiéterai pas spécifiquement du CSS. Comment, de manière générale, pourrait-on exfiltrer 1D au fil du temps ?

Les valeurs Sentinelles à la rescousse !

La taille de la zone de mesure que nous utilisons ne DOIT pas être limitée à 16 bits même si je souhaite limiter les paquets de données eux-mêmes à 16 bits. Nous pouvons donc y emmener aussi des sentinelles. css-api-fetch est livré avec la capacité de gérer des valeurs allant jusqu'à 99999, ce qui est bien au-dessus de 65535 (le plafond de 16 bits).

Alors, que devons-nous savoir ?

Quels problèmes pourrions-nous rencontrer ?

Si deux valeurs de nos données sont identiques dos à dos, nous avons besoin d'une interruption pour savoir qu'il s'agit de deux paquets distincts. J'ai déjà décidé que nous visions 512 bits, nous avons donc besoin que l'animation du SVG ait un maximum de 32 images de données de 16 bits, avec des images sentinelles entre les deux...

Si le processeur semble lourd, l'animation SVG peut sembler ignorer entièrement des étapes discrètes. Cela signifie que nous avons besoin d’un moyen de toujours savoir à quelle étape nous nous trouvons. Ainsi, plutôt qu'une seule sentinelle « entre les trames de données », utilisons l'index de données (basé sur 1 comme les sélecteurs CSS nth-*) comme valeur sentinelle, ce qui en fait sa propre étape discrète avant l'étape discrète affichant les données pour cet index.

Indice Sentinelle -> données -> indice sentinelle -> données...

Cela nous permet également de savoir quand il boucle, potentiellement lorsque nous atteignons la sentinelle 1.

Mais comment savoir qu'il n'est pas passé à une trame de données différente et nous a accidentellement fait l'enregistrer dans le mauvais emplacement ?

Nous devons le laisser boucler et continuer jusqu'à ce que ce soit correct, et la meilleure façon de savoir si les données sont correctes est une somme de contrôle ! Nous avons donc besoin d'une autre trame de données et d'une sentinelle pour cette valeur.

Création de l'algorithme de somme de contrôle

Je pourrais utiliser css-bin-bits pour XOR toutes les données, mais c'est assez lourd et n'est nécessaire nulle part ailleurs - optons pour une alternative simple à faire en CSS.

Mathématiquement, si vous prenez une valeur de 16 bits, la divisez par 256 (plancher en entier), et reprenez la valeur de 16 bits modulo par 256, vous obtenez les octets hauts et bas. Ajoutez ces valeurs de 8 bits ensemble et vous êtes à 9 bits. Cela semble être une approche de somme de contrôle raisonnable, revenons-y cependant.

Nous n'avons pas besoin de rester dans la plage de 16 bits pour calculer la somme de contrôle tant que la somme de contrôle finale est de 16 bits, alors résumons tout (jusqu'à) 32 valeurs.

Nous devons cependant faire attention aux écritures de stockage incorrectes dues à des images sautées, alors ajoutons les valeurs d'index paires deux fois pour qu'il y ait un semblant d'ordre.

Cette somme, 16 valeurs de bits, 32 fois, plus 16 fois supplémentaires, équivaut à environ 22 bits. Divisez et modulez 11 bits de chaque côté en revenant à la pensée précédente, puis additionnez-les ensemble, donnant 12 bits comme réponse de somme de contrôle.

Cela semble raisonnable... Ce n'est pas complètement à l'abri des erreurs, mais le SVG devrait sauter plusieurs étapes pour le gâcher de manière à PEUT-ÊTRE générer la même somme de contrôle maintenant... Dans tous les cas, renvoyons également les données length et incluez-le également dans la somme de contrôle, simplement en l'ajoutant comme dernière étape de notre somme de contrôle. La longueur maximale des données (nombre de valeurs de 16 bits que nous voulons gérer) n'est que de 32, donc l'ajout de la valeur de longueur aux 12 bits ne nous pousse pas loin de 16 bits. Ouais !

spoiler : c'est c'est ce que j'ai fait, mais CSS est devenu avec perte quelque part autour de 21 bits, donc je l'ai divisé et j'ai effectivement fait le même algorithme mais en plus petits morceaux à la fois. Le côté serveur utilise l'alg exactement comme décrit.

Techniquement, avec la configuration que nous avons décrite, peu importe l'ordre dans l'animation tant que chaque sentinelle vous indique quel index l'image suivante est censée être dans le données.

Encore une chose, mettons la valeur de longueur des données en premier dans la réponse et ajoutons également une sentinelle pour cela (sentinelle dans l'animation SVG avant la valeur, comme pour le reste des données).

Cela fait 34 sentinelles. La hauteur de la viewBox SVG ne peut pas être 0 et CSS bénéficiera du fait de permettre à 0 de ne représenter aucune donnée en interne, alors disons que nous avons 35 sentinelles avec 0 délibérément inutilisé.

Toutes les trames de données sont désormais intégrées dans le SVG avec 35 ajoutées à leur valeur. Les valeurs des données de longueur et de somme de contrôle sont ÉGALEMENT ajoutées à 35 à la valeur de la boîte de visualisation. Les hauteurs de viewBox dans l'animation SVG représentant les sentinelles auront des valeurs 0 à 34 (en sautant 0) et chacune nous indiquera exactement ce que représente l'image suivante dans l'animation SVG.

Côté CSS, on vérifie juste si la mesure brute est supérieure à 34, c'est de la donnée donc soustrayez-lui 35, si elle est inférieure à 35, c'est une sentinelle.

A meme picture of Charlie Day from It's Always Sunny in Philadelphia with a crazed look standing in front of a board covered in paper with red lines connecting them hectically

Commencer à exfiltrer les 512 bits avec CSS

Après avoir terminé le côté PHP pour générer l'animation SVG comme détaillé, j'ai réfléchi à des manières spécifiques de commencer le CSS pour ce processus d'exfiltration.

Voici le code PHP !
<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Il existe plusieurs façons d'y parvenir en CSS et potentiellement bien d'autres à venir avec les ajouts récents de spécifications.

Ma première approche est conceptuellement la plus simple : utiliser une chronologie de vue pour chaque élément de données et faire la même chose encore et encore. Cela fonctionnait mais je gémissais à travers mes progrès, mécontent de voir à quel point c'était dégoûtant. Cela fera près de 40 animations sur :root si je continue.

Alors je me suis endormi.

Quand je me suis réveillé, je suis resté allongé là plusieurs instants à regarder par la fenêtre en souriant avec ce sentiment de bourdonnement qui vient de se réveiller ou de méditer, puis un feu de pensées s'est précipité dans ma tête. Je me suis retourné, j'ai attrapé mon cahier et le stylo le plus proche, je me suis assis dans mon lit et j'ai commencé à écrire l'algorithme pour l'exfiltrer avec seulement 6 animations CSS.

my chicken scratch handwriting on a single piece of lined notebook paper with arrows pointing to a couple of nested boxes detailing the method described below

Littéralement résolu sur papier ; C’est EXACTEMENT comment il est mis en œuvre.

Je me suis levé, j'ai ouvert mon ordinateur, j'ai ignoré mon travail précédent et j'ai ouvert un nouveau % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé.

J'y ai mis en place les 4 éléments html indiqués parmi les scratch de poulet, puis j'ai inondé le panneau CSS de notes autour de 4 sélecteurs de classes vides leur correspondant. Il ne sera plus sur :root maintenant mais nous pouvons placer tout ce qui en dépend à l'intérieur.

Aucune fonctionnalité n'a été ajoutée jusqu'à ce que les notes soient copiées à partir du papier et écrites de manière plus précise dans % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé.

Quand j'ai eu fini, j'ai juste lu les notes et j'ai commencé à mettre en œuvre ce qu'elles disaient, jusqu'au résultat final.

(J'ai écrit "20" au lieu de "35" car j'allais tester avec 256 bits)

Je vais expliquer comment cela fonctionne. En raison de la vue-chronologie et de la portée de la chronologie, vous pouvez configurer les données pour qu'elles circulent sous la forme d'une bouteille de Klein si vous pouvez imaginer la surface s'animant et étant aspirée dans le "trou", remontant vers le haut étroit jusqu'au bas. sur la surface, gagnant en taille et en complexité à travers les couches de dom, puis remontant à travers le trou noir jusqu'à la conscience supérieure (:root).

Il est principalement cyclique verticalement (plutôt que principalement horizontalement ou statiquement cyclique)

Exfiltrer les 512 bits avec CSS

Les notes que nous avons légèrement modifiées et rendues plus claires :

Test 256 -> 512 finale

et j'ai ajouté un nœud de présentation à l'intérieur, ce qui est génial car je peux également montrer les éléments internes pendant l'exécution de l'algorithme.

mais voici les notes finales sans tout le bruit d'implémentation et de présentation. Cela décrit exactement comment tout cela fonctionne.

Ce n'est peut-être pas une bonne chose pour un article d'avoir autant de détails intégrés en externe, mais je vais décomposer chaque morceau pour montrer comment il est mis en œuvre.

Contrôleur principal

En haut de cette structure se trouvent 4 valeurs de timeline et leurs animations. Alors mettons-les dedans.

L'élément clé du flux de données que cela permet est que cela nous donne la possibilité de remonter les données imbriquées profondément dans le DOM vers un hôte (portée de la chronologie). Ce n'est pas efficace, nous voulons donc limiter la fréquence à laquelle nous le faisons. Chaque propriété enregistrée et son animation peuvent héberger verticalement une seule donnée. La valeur des données est déterminée par la position en ligne ou en bloc d'un élément quelque part au plus profond de la structure - nous y reviendrons plus tard.

(voir l'exemple de boucle précédemment intégré ci-dessus pour une image plus claire du flux de données)

Les quatre éléments de données que nous récupérons ici sont :

--xfl-cpu-phase - il s'agit d'une valeur numérique de 0 à 4 qui signale quelle phase du CPU Hack est actuellement en cours d'exécution. (une seule « image » du CPU Hack correspond à 4 à 5 images de rendu CSS, une boucle des phases « coche » le CPU Hack) Je le démontrerai plus spécifiquement plus tard dans cet article.

--xfl-raw-data - ceci héberge la hauteur du SVG partout où se trouve le SVG dans son cycle d'animation. Nos données brutes. Comme dit précédemment, si cette valeur est inférieure à 35, cette étape discrète de l'animation SVG est une valeur sentinelle. S'il est supérieur à 34, ce pas discret de l'animation SVG est notre valeur 16 bits 35, ce qui correspond à ce qu'indiquait la sentinelle précédente.

--xfl-data-type - il s'agit de la valeur sentinelle la plus récente. Cette valeur ne change pas jusqu'à ce que la prochaine sentinelle soit rencontrée. Il y a un délai d'une image CSS entre la définition de --xfl-raw-data et la définition de cette valeur.

--xfl-data-value - c'est la valeur actuelle des données après que 35 ait été soustraite de la valeur brute, ou 0 si nous n'avons pas encore atteint cette étape de la séquence. Il y a un délai d'une image CSS entre la définition de --xfl-data-type et la définition de cette valeur.

J'ai également enveloppé de manière préventive svg-animation-current-state-reporter dans une condition qui n'a que des fonctionnalités et ne charge que le SVG animé lorsque le processus est incomplet. (donc tous les éléments internes sont supprimés de la mémoire et le lourd svg animé est supprimé du rendu lorsque nous avons terminé)

Les valeurs des images clés vont d'une valeur maximale pour cette donnée à 0. J'expliquerai plus tard pourquoi elles sont à l'envers - recherchez l'image des cartes Uno Reverse.

Exfiltrateur de processeur

Ensuite, nous mettons en place le passe-partout de base pour un CPU Hack

Le modèle CPU Hack suit simplement un modèle de nom de variable pour configurer les animations de capture et de levage.

Si nous avons 1 entier --xfl\1 que nous voulons faire défiler horizontalement (dans le temps), nous l'enregistrons et nous mettons en place des animations de capture et de levage comme ceci :

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Terminez ensuite l'affectation cyclique sur l'élément .cpu-exfiltrator où sont hébergées les deux animations CPU. Je vais le faire pour une seule des valeurs pour l'instant :

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans Chrome, ils ne feront pas de cycle statique (deviendront la valeur initiale) à moins que les deux animations ne s'exécutent en même temps. Ce qui est un effet secondaire FANTASTIQUE de ce qui est probablement une optimisation des animations en pause définissant des propriétés numériques.

Enfin, puisque nous utilisons une nouvelle version automatique du CPU Hack (vous n'avez pas besoin de :survoler pour cycler les phases comme dans le hack original), nous câblé dans la var --xfl-cpu-phase du précédent (hébergé sur l'élément parent ici, afin que nous puissions utiliser des requêtes de style pour y répondre) et contrôler l'état de lecture de nos animations.

Nous produisons également --cpu-next-phase qui sera ensuite remonté vers le haut et définirons la valeur suivante pour --xfl-cpu-phase en utilisant sa position d'affichage et sa portée de chronologie.

J'ai ajouté une phase supplémentaire pour maintenir le CPU Hack en pause jusqu'à ce que la mesure de l'animation SVG soit verrouillée avec succès dans le prochain --xfl-data-type

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

(comme c'est le cas maintenant, le type de données est toujours 0, donc une fois la phase suivante connectée, cela bouclera déjà le CPU Hack. Une fois que nous aurons une sentinelle de type de données, elle ne bouclera pas tant que nous n'aurons pas l'a effacé délibérément avec la sentinelle 0)

Plus tard, nous ajouterons également la condition notée pour empêcher le démarrage de la phase 1 du processeur jusqu'à ce que toutes les données soient en place. Cela garantira qu'entre le type de données (sentinelle) verrouillé et la valeur des données (brutes - 35) verrouillée, nous voulons laisser le CPU Hack dans sa phase de capture. C'est donc "prêt à être prêt" comme pourrait le dire Abraham Hicks.

Je vais continuer et enregistrer les 32 valeurs plus la somme de contrôle et la longueur que nous attendons de l'animation SVG.

Étant donné que l'enregistrement de --xfl\1 à --xfl\32 est un gros bloc et que les animations du processeur ne sont également que des passe-partout, je vais déplacer toutes celles-ci au bas de la configuration du hack pour qu'elles soient ignorées à l'avenir.

Piratage automatique du processeur

Cela câble la phase suivante du processeur jusqu'à la valeur --xfl-cpu-phase

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Il y a ici un passe-partout CSS pour faire de l'élément un conteneur de défilement et le mettre hors écran. La partie importante est :

view-timeline : --xfl-cpu-phase inline ;

qui indique où se situe le bord droit de ce pseudo-élément dans son parent de 100 px de large, connectez-le comme un "progrès" de la gauche à notre animation qui passe de 0 à 4... Donc 25 px est terminé à 25 %, qui correspond à 1 lorsque 25 % est compris entre 0 et 4.

picture of two 'reverse' cards from Uno image provenant d'une recherche Google menant à Twitter

TECHNIQUEMENT, l'animation est de 4 à 0 et TECHNIQUEMENT, elle mesure à partir du bord droit du pseudo au fur et à mesure que la vue progresse vers la droite. Ainsi, le pseudo de 25 px de large est à 75 % de la droite de son parent de défilement de 100 px de large et correspond à une valeur de 1 lorsque 75 % est compris entre 4 et 0.

Il est plus facile de comprendre si vous ne traitez pas cognitivement les mathématiques inverses et acceptez simplement que le résultat final est une simple progression de 0 à 4 car la valeur maximale dans l'animation est de 4 (en ignorant encore une fois que l'animation démarre à 4).

Écrivons également l'état prêt qui maintient le CPU en phase 0 jusqu'à ce que les données soient prêtes. La note est à la ligne 64 de nos démos :

Données prêtes = type de données > 0 && données de trame brutes - 35 === valeur de données

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Attendez, === en CSS ?

Ceux-ci sont assez obsolètes maintenant et je les ferais différemment aujourd'hui, écrits avant que clamp() ne soit la référence, mais j'ouvre toujours ce vieux codepen pour copier sans réfléchir des comparateurs numériques lorsque j'en ai besoin. Ce serait un bon article pour les mettre à jour et les expliquer mais voilà en attendant : https://codepen.io/propjockey/pen/YzZMNaz

Lecture de l'animation SVG

C'est initialement TRÈS similaire à la section CPU Exfiltrator car c'est la même technique, mesurant et déplaçant les données d'ici vers le haut du DOM jusqu'à l'endroit où elles sont hébergées (portée).

Nous mesurerons et rapporterons les 3 dernières valeurs de l'élément de base que nous avons configuré initialement.

Le ::avant, nous rendrons le SVG et définirons --xfl-raw-data en utilisant la position de vue en bloc qui est la mesure de la hauteur du SVG animé. (rappelez-vous, nous épinglerons la largeur à 10px)

Sur ::after, nous définirons --xfl-data-type en ligne (valeurs sentinelles 0 à 34) et --xfl-data-value block (valeurs 16 bits).

Le parent devra être suffisamment large pour restituer le SVG (au moins 10 px) et fournir avec précision des mesures pour les valeurs sentinelles (0 à 34).

Le parent devra également être suffisamment grand pour mesurer des valeurs de 16 bits (35). Puisque nous avons défini une valeur maximale dans la première étape de 100 000, nous l'utiliserons simplement même si elle est environ 30 % plus grande que ce dont nous avons besoin.

Et déplacez-le hors de l'écran vers le haut et la gauche pour ne pas provoquer de barres de défilement.

Par conséquent,

.svg-animation-current-state-reporter

obtient

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion

et avant devient

@keyframes capture {
  0%, 100% {
    --xfl\1-captured: var(--xfl\1);
  }
}

@keyframes hoist {
  0%, 100% {
    --xfl\1-hoist: var(--xfl\1-captured, 0);
  }
}
Copier après la connexion

et ::after obtient

  --xfl\1: calc(
    var(--xfl\1-hoist, 0) + 1
  );
Copier après la connexion

Essentiellement, le support de stockage ici pour ces valeurs après est la position d'affichage d'un pseudo carré de 1 px par rapport à son conteneur de défilement parent. Nous soustrayons 1px dans les calculs de gauche et du haut car le pseudo lui-même est 1x1 et nous voulons qu'il rapporte 0 lorsque la valeur correspondante est 0.

Tout cela est très similaire à ce qui a été fait précédemment.

La façon dont nous calculons ces valeurs présente plusieurs complexités, comme l'indique la note :

  @container style(--xfl-cpu-phase: 4) {
    animation-play-state: paused, paused;
    --cpu-next-phase: calc(
      min(1, var(--xfl-data-type)) * 4
    );
  }
Copier après la connexion

La clé pour comprendre comment résoudre ce problème est que toute valeur de comparateur est définie sur 0 ou 1. 1 si c'est vrai, 0 si c'est faux. Ensuite, multipliez-le par une valeur. Si c'est faux, le résultat reste 0, sinon il devient quelle que soit la valeur.

Ana Tudor explique en profondeur comment cette idée fonctionne ici

Ensuite, si nous faisons cette comparaison deux fois, avec une comparaison différente ou opposée pour la deuxième valeur, et que nous les additionnons (en nous assurant qu'au plus un des comparateurs est 1), alors l'ajout de deux d'entre eux revient simplement à dire "sinon si".

si ce n'est pas prêt * utilisez l'ancienne valeur sinon
si est prêt * utilisez cette nouvelle valeur

C'est ainsi que nous conservons la valeur sentinelle pendant toute la durée de l'étape discrète de l'animation SVG pour la valeur une fois que le type a déjà été signalé.

Le code CSS l'implémentant commence ici à la ligne 191, juste au-dessus du gros bloc de --xfl\... les enregistrements de propriété que nous mettons vers le bas
@property --xfl\1 { syntaxe : ""; valeur initiale : 0 ; hérite de : vrai ; >
...
et il contient des notes supplémentaires :

Définition de valeurs CSS --var spécifiques (affectations adressées)

La logique que nous venons d'aborder est exactement le même concept que nous utilisons pour toutes les valeurs --xfl\1, 2, 32.

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion
Copier après la connexion

Vous lisez --xfl-set\1 comme si --xfl-data-type était égal à 1, utilisez --xfl-data-is-ready avec un implicite else 0

--xfl-data-is-ready a été établi plus tôt comme un drapeau nous maintenant dans la phase 0 jusqu'à ce qu'il soit temps de passer à la phase 1.

Cela signifie que notre condition est && logique. Les deux drapeaux doivent être à 1 pour passer.

Ensuite, vous continuez à lire --xfl\1 comme si --xfl-set\1 utilisait --xfl-data-value (la valeur actuelle de l'animation SVG), sinon si NON --xfl-set\1 utilisait -- xfl\1-hoist (la valeur précédente que le hack CPU détenait pour --xfl1)

Ceci est très répétitif, et décrit la quasi-intégralité du reste de cette exfiltration.

Les dernières étapes consistent à exécuter les mathématiques de base calc() et mod() pour construire la somme de contrôle comme décrit précédemment, puis à ajouter si la somme de contrôle calculée === la somme de contrôle intégrée dans l'animation SVG au CPU Hack afin que nous sachions quand c'est complet. C'est toujours la même chose.

Alors maintenant, il est temps. :)

Présentation : Le hack d'exfiltration SVG animé CSS

Parce que je voulais montrer à chaque élément de ce hack une valeur par élément, la présentation est odieusement lourde. Plus de 2000 lignes de HTML et plus de 400 lignes de CSS. De plus, j'utilise css-bin-bits pour convertir chaque registre en binaire, etc.

(Cliquez sur Réexécuter en bas à droite du cadre du codepen pour voir cela se produire en temps réel !)

Pas de JavaScript !


Ouvrir contact ?

N'hésitez pas à nous contacter si vous pensez que c'est intéressant et que vous souhaitez en savoir plus ! Toujours heureux de répondre aux questions.

% CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé DEV Blog % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé
% CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé DEV Blog % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé % CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé

?@JaneOri.% CSS : récupérer et exfiltrer des bits de données générées par le serveur intégrées dans un SVG animé

?@Jane0ri

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal