Un echo + flush ne fait pas le job malheureusement

Hello,

Le commit 0a11c22556 sur ecrire/inc/actions.php ne fonctionne pas pour moi. En remplaçant le die() par ob_end_flush(), je n’ai plus le menu de rubriques.

La page spip.php?action=menu_rubriques&date=
Ne vient pas (ou alors pétée avec un message d’erreur au bout de du max exécution time.

C’est le problème que le die() résolvait, et qui ne fonctionne donc plus avec la nouvelle alternative.

=> Accessoirement, je ne sais pas comment on fait pour commenter directement une révision de Git. Sur git.spip.net, il n’y a pas un bouton qui permettrait de faire un ticket directement depuis une révision?

ARNO*

Plusieurs remarques alors :

  • Je me demande pourquoi le problème ne se pose que chez toi a priori. Tu n’aurais pas un fichier qui echo quelque chose avant ? genre une ligne vide avant <?php dans un fichier d’option ?
  • Si ça ne marche pas, exit serait plus élégant que die (au sens où c’est le terme utilisé ailleurs dans SPIP)
  • mais si le problème vient du Fatal Error… ? qu’est-ce que ça corrige du coup de mettre un die ? Tu veux dire que le traitement est fini, mais quelque chose fait que le résultat ne part pas et conserve la transaction ouverte jusqu’au timeout ? Ce ne serait pas autre chose qui conserverait la transaction ouverte ? C’est assez étonnant qu’on ne reproduise pas ce souci.

Si tu penses que ça vient des spécificités du serveur, tu as des détails plus précis ? des pistes de pourquoi ?

Je viens de refaire l’essai:

  • désactivé les plugins
  • renommé le dossier plugin
  • renommé mon dossier squelettes
  • renommé mon fichier config/mes_options

Et la page:
spip.php?action=menu_rubriques&date=
ne vient encore qu’à la fin du timeout avec un fatal error.

Apparemment la boucle:
while (ob_get_level()) ob_end_flush();
ne sort jamais chez moi. Si j’ajoute un echo « A » dans la boucle, j’obtiens une infinité de A… (une fois atteint le max_execution_time)

Tu peux tester de voir ce que donne :

	$level = ob_get_level();
	while ($level) {
		echo $level . ':' . ob_get_level() . " ";
		echo ob_end_flush() ? ' OK ' : ' NOK ';
		$level--;
		echo $level . ':' . ob_get_level() . " ";
		echo " | ";
	}

Chez moi : 1:1 OK 0:0 |

Chez moi:
2:2

Rien d’autre ? tu disais que tu avais que des A si te mettait dans la boucle ? Je ne comprends pas… Il ne t’affiche ni OK ni NOK ? hum.

PS: Tu réponds avec 2 comptes emails différents ; je crois qu’on peut les fusionner dans Discourse si tu veux.

Les AAA, c’est quand je modifie inc/actions.php. Là j’ai juste fait tourner ton script dans un fichier indépendant (donc sans aucun lien avec SPIP). Et non, rien d’autre après 2:2. Même pas un message d’erreur.

(Pour les adresses email, oui on peut fusionner: comme arno@rezo.net est un reroutage d’un compte gmail, je me faisais jeter mes emails à la liste.)

Si j’ajoute le ob_start() en début de fichier, ainsi:

<?php

ob_start();
$level = ob_get_level();
	while ($level) {
		echo $level . ':' . ob_get_level() . " ";
		echo ob_end_flush() ? ' OK ' : ' NOK ';
		$level--;
		echo $level . ':' . ob_get_level() . " ";
		echo " | ";
	}

J’obtiens la réponse:
3:3 OK 2:2 | 2:2

Si j’installe ton code à la fin de inc/actions.php, ainsi:

	echo $debut.$corps.$fin.$e;
	$level = ob_get_level();
	while ($level) {
		echo $level . ':' . ob_get_level() . " ";
		echo ob_end_flush() ? ' OK ' : ' NOK ';
		$level--;
		echo $level . ':' . ob_get_level() . " ";
		echo " | ";
	}

Alors j’ai bien mon affichage des rubriques, et l’affichage attendu est:
3:3 OK 2:2 | 2:2 NOK 1:2 | 1:2 NOK 0:2 |

Voilà c’est ça. Tu as un ob_end_flush() qui retourne false, c’est à dire qu’il n’arrive pas à le faire, et du coup ob_get_level() reste à la même valeur.

Du coup tu vois une solution propre à ce problème?

Peut être que tu peux afficher la liste des handlers pour avoir une idée de qui bloque ? :

	echo $debut.$corps.$fin.$e;
	print_r(ob_list_handlers());

Qui me donne Array ( [0] => default output handler )

J’obtiens:

Array ( 
     [0] => default output handler 
     [1] => zlib output compression 
     [2] => cache_cool_flush 
)

Du coup j’essaie en désactivant Cache_cool. Ça me supprime le [2], mais ça ne fonctionne pas plus…

Alors si j’ajoute:

if ($_GET["action"]) ini_set("zlib.output_compression", "off");

dans mes_options.php, je récupère bien mon menu_rubriques.

Mais je ne sais pas si c’est une bonne idée d’insérer ce genre de choses dans le core, ni où…

Si je l’ajoute au début de la fonction ajax_retour() de inc/actions.php, ça fonctionne nickel:

function ajax_retour($corps, $content_type = null) {
	@ini_set("zlib.output_compression", "off");

Mais je suppose que ça ne fonctionne que si ini_set est autorisé sur le serveur.

@arno j’ai donc fusionné tes deux comptes, en laissant celui avec chez rezo que tout le monde connait, et j’ai modifié ce compte pour t’y remettre le pseudo et le nom technique « arno » (pour les ping)

Je relance: est-ce que vous avez une idée de solution?

Moi ce qui fonctionne, c’est l’ajout de

	@ini_set("zlib.output_compression", "off");

au début de la fonction Ajax_retour.

Hello,

déjà j’ai envoyé un patch pour éviter la boucle infinie sur la tentative de flush :

J’essaye de reproduire le problème mais même si j’active le
zlib.output_compression, avec ou sans cache_cool je n’arrive pas à reproduire le defaut de flush.

J’ai bien la même configuration de buffer dans mon print_r(ob_list_handlers()); mais ça ne bloque jamais la sortie.

Tu utilises quelles versions de PHP et Apache, et est-ce que tu n’as pas un autre plugin qui ferait une action en fin de hit et retarderait la sortie ?

Est-ce que tu peux aussi essayer l’URL ecrire/?action=menu_rubriques&date= et voir si elle se comporte pareil ?

Est-ce que tu peux aussi essayer d’ajouter un

ob_implicit_flush(true);

avant le echo ?

On peut toujours mettre un ini_set dans ajax_retour, mais je crains que ce ne soit qu’un patch hyper local qui résolve pas le vrai soucis (et de facto il va sauter un jour ou l’autre parce que inexplicable)

C’est pas mieux - mais c’est différent…

Là la réponse est immédiate: le menu se déplie, et rien du tout ne vient (mais pas de timeout).

Si j’essaie d’entrer l’URL de ?action=menu_rubriques directement dans le navigateur, ça ne semble charger aucune page.

Par contre, si je fais un wget sur cette même URL, ça me télécharge bien le fichier HTML complet du menu.

Le ob_implicit_flush ne change rien. Et au début de ce thread, j’avais essayé en désactivant tout sur mon site, et même résultat.


C’est un hébergement Infomaniak, php 7.4.16, pour Apache je ne trouve pas l’info dans php_info.