#20414 - Note PHP, encore une optimisation à la con
https://lehollandaisvolant.net/?mode=links&id=20210926181502Je suis en train de refaire des optimisations en tout genre dans un script.
L’une concerne un tableau associatif qui liste les #tags associés à mes posts.
Donc je récupère ça de la BDD, concatène tout, explode() et j’ai un tableau.
Je trie le tableau avec ksort(), puis compte les occurrences de chaque valeur dans le tableau (avec array_count_values), pour avoir un tableau associatif :
(
#tag1 => nombre_d'occurences1,
#tag2 => nombre_d'occurences1,
…
)
Ça me prend 50-70 ms.
J’ai pu réduire ça à 30-50 ms très facilement
En fait, j’ai simplement inversé les étapes ksort() et array_count_values().
Avant :
$tableau = …
ksort($tableau);
$tableau = array_count_values($tableau);
Après :
$tableau = …
$tableau = array_count_values($tableau);
ksort($tableau);
Pourquoi c’est plus rapide ?
Parce qu’au début, le tableau contient tous les #tags, y compris les doublons : il y a 10 000 environ. Trier ça prend du temps.
Mais après le array_count_values(), le tableau est dédoublonné et ne compte que 400 entrées. Trier ça prend moins de temps.
Il suffit qu’il y ait 4 ou 5 optimisations comme ça et on gagne 200 ms sur la page. C’est bête hein, mais ça marche.
Je ne sais pas si on apprend ça à l’école (j’ai jamais eu de prog à l’école), mais une règle :
Sur les tableaux, faire le tri après les filtres.
(PS : oui, beaucoup de posts de prog() en ce moment. Pas désolé du tout par contre :p)
#20413 - PHP: hrtime - Manual
https://www.php.net/manual/fr/function.hrtime.php— microtime() retourne un temps précis à la microseconde.
— hrtime() c’est à la nanoseconde (« high resolution time »).
C’est recommandé pour faire des tests de performances.
À noter que hrtime() ne retourne pas un timestamp plus précis, mais un instant « t » compté depuis une origine arbitraire donné par le système.
Le but est de mesurer des durées, pas de donner l’heure. On l’utilise donc deux fois et on calcule la différence, pour trouver le temps mis entre les deux (temps de faire une procédure PHP par exemple).
#20339 - Note : optimisation PHP
https://lehollandaisvolant.net/?mode=links&id=20210906184412Mon site est régulièrement sujet à des ralentissements. C’est pas nouveau mais c’est un peu chiant.
Je ne sais toujours pas si ça vient de moi (mon site) ou un autre, car je suis en mutualisé. J’essaie tout de même d’optimiser un peu.
Une des pages les plus vue de mon site, c’est la page du Gravatar local.
Dans les commentaires, plutôt que votre navigateur accède à Gravatar (service externe), il demande à mon serveur d’aller chercher sur Gravatar. Ensuite, le serveur stocke l’image récupérée pour la prochaine fois.
À chaque fois que les commentaires s’affichent, une requête est faite sur le fichier /favatar.php, avec en paramètres le hash de l’image à récupérer.
C’est bien un script PHP qui est lancée à chaque fois. Si le fichier du hash existe sur le serveur, il le read() et l’envoi. Sinon, il le récupère, le sauvegarde et l’envoie.
Je viens de trouver une autre méthode.
Plutôt que de faire une requête sur le fichier /favatar.php, je fais une requête sur l’image directement : /cache/gravatar/hash.png.
Là, si le fichier existe, le serveur l’envoie et ça s’arrête là. Pas de PHP à lancer.
Si le fichier n’existe pas, en revanche, ça devrait envoyer un 404. Sauf que j’utilise un .htaccess pour rediriger sur le /favatar.php et récupérer l’image.
C’est bien mieux : dans la grande majorité des cas, la requêtes est désormais une simple image sur le disque, plus un fichier PHP à lancer, qui va regarder si le fichier existe, qui va le lire, et l’envoyer au navigateur.
J’aurais dû faire ça depuis le début, je sais, je sais, mais on va voir si ça aide.
~
Pour mettre ça en place, faire directement la requête sur /dossier/fichier.png
Dans /dossier/, mettre un .htaccess avec le code suivant :
# If requested resource doesn't exists as a file redirects to the PHP script
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) relative/path/to/script.php?q=$1 [L]
La première ligne est la condition nécessaire à l’application de la seconde. Elle teste « le fichier demandé n’est pas un fichier sur le disque (!-f) ». Si le fichier est absent, il renvoie "true" et exécute la ligne suivante, à savoir une réécriture (pas redirection) vers script.php, avec comme paramètre "q", le $1 qui contient le nom du fichier demandé (on peut y rajouter d’autres paramètres si besoin :
RewriteRule (.*) relative/path/to/script.php?s=search&format=png&q=$1 [L]
[/code]
Ensuite dans script.php, on fait ce qu’on a à faire avec les paramètres (wget sur le fichier, imagemagic pour créer une image, etc., puis on read() le fichier, pour éviter une redirection et une autre requête :
// send file to browser
header('Content-Type: image/png');
header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($target_file)).' GMT');
header('Content-Length: ' . filesize($target_file));
header('Cache-Control: public, max-age=2628000');
readfile($target_file);
exit;
~
Sinon, en aparté : j’ai modifié le thème pour https://couleur-science.eu/ . Le thème est désormais clair ou sombre en fonction du paramétrage de votre navigateur.
#20213 - What are the differences in die() and exit() in PHP? - Stack Overflow
https://stackoverflow.com/questions/1795025/what-are-the-differences-in-die-and-exit-in-phpAu niveau de PHP, aucune différence.
Au niveau des requêtes client/serveur, par contre :
// die():
HTTP/1.1 304 Not Modified
Connection: close
// exit():
HTTP/1.1 304 Not Modified
Connection: Keep-Alive
Keep-Alive: timeout=5, max=100
die() ferme la connexion.
exit() ne ferme pas la connexion.
#18777 - GitHub - moonmoon/moonmoon: moonmoon is a simple feed aggregator (planet like)
https://github.com/moonmoon/moonmoonUn petit aggrégateur RSS.
Mouais, ça peut servir si on a 4 ou 5 flux. Je viens de tester avec mes ~180 flux et c’est leeeeeent.
En local (quadricore dédié avec 20 Go de Ram) la page met 48 secondes à charger.
Ça semble mettre à jour les flux à chaque chargement de la page (bien qu’il semble utiliser un cache du fichier RSS). Si c’est pour avoir des perfs de merde, je vois pas l’intérêt de faire du « sans BDD ».
Au début, quand je codais, je me faisais plaisir en codant des trucs sans SGBD (juste du XML), ou sans JS, simplement histoire de prouver (je ne sais pas à qui) que c’était possible.
Et après on découvre que c’est quand-même nettement plus rapide/pratique/fonctionnel quand on utilise des outils fait exprès pour ce qu’on veut faire.
Ce n’est pas mal de réinventer la roue (au contraire), mais parfois il faut quand même reconnaître qu’il existe des outils mieux que ce qu’on pourra jamais faire soi-même.
On peut faire un aggrégateur RSS juste en HTML/CSS (mettez des iframe et du XSLT et on peut faire un truc, je pense), et ça serait une jolie prouesse, mais inutilisable en soi.
#18472 - 10 bonnes pratiques PHP pour améliorer son code
https://www.arthurweill.fr/guide-des-bonnes-pratiques-php/Pas forcément fan de tout, mais il y a néanmoins de bonnes astuces et conseils.
#18207 - Note
https://lehollandaisvolant.net/?mode=links&id=20190122172625Dans PHP, si vous avez un tableau associatif dont les clés sont numériques, certaines fonctions comme array_reverse() font réindexer le tableau une fois le reverse() effectué.
Si les clés sont une chaîne, elles sont conservées (le tableau est simplement inversé).
Donc si vous avez ça :
array(4 => "quatre", 8 => "huit");
Vous obtiendrez ça :
array(0 => "huit", 1 => "quatre");
Et non pas :
array(8 => "huit", 4 => "quatre");
Je me suis fait avoir : je voulais une clé unique pour un tableau. Pour ça, j’utilise parfois crc32(), une fonction de hashage relativement rapide.
Sauf que en PHP, crc32() retourne un entier. Mes index ont donc disparus après le reverse().
J’ai dû me rabattre sur md5() pour le hash unique.
J’aurais aussi pu prendre hash('crc32', $i), qui lui retourne une chaîne en hexa.
Fin bref, soyez vigilants.
#18041 - [PHP] Note : virer tous les accents d’une chaîne unicode (latin)
https://lehollandaisvolant.net/?mode=links&id=20181208140630Pour enlever les accents, tildes, trémas, cédilles de toutes les lettres diacritiques latines, en PHP :
$texte = htmlentities($texte, ENT_QUOTES, 'UTF-8');
$texte = preg_replace('#&([a-z]{1,2})(acute|grave|circ|uml|cedil|tilde|ring|slash|caron|lig);#', '$1', $texte);
On commence par transformer les lettres accentuées en entités HTML : « é » devient « é ».
Ensuite, on remplace cette chaîne la par la première lettre après le « & ».
Ces entités sont toutes formées de la même façon :
à => à
è => è
ò => ò
ä => ä
ö => ö
ü => ü
Pour les ligatures, c’est pareil :
œ => œ
æ => æ
ß => $szlig;
Par contre ça ne fait que les minusucles, les majuscules ne marchent pas comme ça.
#17662 - Note : PHP, curl_multi et barre de progression
https://lehollandaisvolant.net/?mode=links&id=20180807154339Ok… donc en PHP dans mon lecteur RSS qui doit récupérer en parallèle 170 URL, j’affiche un petit compteur.
Le truc, c’est que c’est forcément dans une boucle while, et que cette boucle se fait aussi rapidement que le CPU le peu.
Donc si PHP envoie au navigateur un « +1 » à chaque fois qu’un flux est récupéré, il l’envoie quelques millions de fois par seconde : impensable, donc, ce qui fera des dizaines de Mo de données juste pour ça.
Du coup, j’avais mis un usleep(100000) dans la boucle… ça marchait. Par contre, ça bloquait également la récupération des flux ! Certains flux posaient donc problème…
Du coup j’ai remplacé ça par un test sur microtime(). Par contre, je maintiens un tout petit usleep() : la différence est flagrante : le sleep est assez faible pour pas que cURL coupe la requête, mais assez long pour éviter que le CPU ne fasse 1 milliard de tests par seconde :
$running = 0;
$utime = microtime(true);
do {
curl_multi_exec($master, $running);
usleep(500);
// echoes the nb of feeds remaining
if ($utime + 1 < microtime(true)) {
echo ($total_feed-$running).'/'.$total_feed.' '; ob_flush(); flush();
$utime = microtime(true);
}
} while ($running > 0);
#16855 - Date.prototype.getTimezoneOffset() - JavaScript | MDN
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/getTimezoneOffsetgnîîîîî !
Encore ces incohérences entre JS et PHP.
Ici sur la sortie d’une date en une chaîne au format ISO 8601 : en PHP, la chaîne prend en compte le décalage par rapport à l’UTC. En JS, il n’y a pas de décalage : tout est en UTC.
Quant à calculer ce décalage : un UTC+2 (correspondant à Paris en été, par exemple), il est positif pour PHP (logique) mais négatif en JS (probablement car UTC est 120 minutes de moins que l’heure locale).
#16800 - Date.prototype.getMonth() - JavaScript | MDN
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/getMonthDonc…
En JS, les mois vont de 0 à 11.
En PHP, les mois vont de 1 à 12.
Et les jours ?
En JS, les jours vont de 1 à 31.
En PHP, les jours vont de 1 à 31.
Le JS c’est à se taper la tête contre les murs, vraiment. Et là c’est juste une broutille (suffit de faire un −1 entre les deux langages [oui car mon PHP écrit du JS]). Mais parfois c’est bien plus chiant à corriger…
#16452 - Exécuter une requête asynchrone avec PHP et cURL - Max-Koder
http://max-koder.fr/2017/05/11/executer-une-requete-asynchrone-avec-php-et-curl/cURL est très pratique !
Perso je m’en sers aussi pour faire 150 requêtes HTTP simultanées (dans mon lecteur RSS). La durée totale de l’opération est alors la durée de la plus longue des requêtes, et non pas la somme des durées de toutes les requêtes (comme avec file_get_contents()).
#15892 - How we broke PHP, hacked Pornhub and earned $20,000 | Bug Bounties - Evonide
https://www.evonide.com/how-we-broke-php-hacked-pornhub-and-earned-20000-dollar/Oops, PHP qui présente des problèmes dans les données serializé.
J'ai le sentiment que l'implémentation de la gestion des fichiers est assez bancale dans PHP, j'avais déjà vu des étrangetés avec le .ini...
#15790 - PHP: Possible modifiers in regex patterns - Manual
http://php.net/manual/en/reference.pcre.pattern.modifiers.phpDonc pour faire en sorte que les caractéristiques accentués soient pris en compte dans \w, il faut ajouter le flag "u" (en minuscule).
Retourne false :
preg_match('#\w#', 'é')
Retourne true :
preg_match('#\w#u', 'é')