#20414

Note PHP, encore une optimisation à la con

Je 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)

https://lehollandaisvolant.net/?mode=links&id=20210926181502

#20413

PHP: hrtime - Manual

— 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).

https://www.php.net/manual/fr/function.hrtime.php

#20339

Note : optimisation PHP

Mon 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.

https://lehollandaisvolant.net/?mode=links&id=20210906184412

#20213

What are the differences in die() and exit() in PHP? - Stack Overflow

Au 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.

https://stackoverflow.com/questions/1795025/what-are-the-differences-in-die-and-exit-in-php

#18777

GitHub - moonmoon/moonmoon: moonmoon is a simple feed aggregator (planet like)

Un 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.

https://github.com/moonmoon/moonmoon

#18207

Note

Dans 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.

https://lehollandaisvolant.net/?mode=links&id=20190122172625

#18041

[PHP] Note : virer tous les accents d’une chaîne unicode (latin)

Pour 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 « &eacute ».
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.

https://lehollandaisvolant.net/?mode=links&id=20181208140630

#17662

Note : PHP, curl_multi et barre de progression

Ok… 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);

https://lehollandaisvolant.net/?mode=links&id=20180807154339

#16855

Date.prototype.getTimezoneOffset() - JavaScript | MDN

gnîîîîî !

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).

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/getTimezoneOffset

#16800

Date.prototype.getMonth() - JavaScript | MDN

Donc…
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…

https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/getMonth

#15790

PHP: Possible modifiers in regex patterns - Manual

Donc 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', 'é') 
http://php.net/manual/en/reference.pcre.pattern.modifiers.php

#15487

Note : PHP, file_get_contents et URL

Sur certains serveurs, file_get_contents(), copy() et quelques autres fonctions qui peuvent fonctionner avec des URL (chemins distants) ne marchent pas : la directive INI allow_url_fopen est mise à Off.

Pour palier à ça, on peut utiliser cURL pour récupérer le fichier. Sur les serveurs qui n’ont que cette directive mise à Off, cURL (s’il est installé) fonctionnera.

On utilisera alors ça :

// request
$curl_handle = curl_init();
curl_setopt($curl_handle, CURLOPT_URL, $url);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1); 
$file_content = curl_exec($curl_handle);
curl_close($curl_handle);
// saving
file_put_contents($file_name, $file_content);


Dans les cas où le serveur bloque toutes les connexions sortantes, il n’y a pas de solutions pour faire des requêtes externes.
http://lehollandaisvolant.net/?mode=links&id=20160528185414