Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 31 mai 2015, 11:22

Et ça, il n'y a qu'un seul fautif, ce n'est ni Windows, ni Linux, ni la décompression de Wordpress => c'est la faute de ton éditeur de code.
Désolé faux, je ne dis pas ça.

Je dis que lors du chargement d'un plugin depuis une machine windows vers une machine Linux, les fichiers textes contiennent exportés l'ont été en mode binaire et les fins de ligne sont des CRLF. Alors après le téléchargement vers windows les fins de ligne sont marquées par CRCRLF. Il n'y a pas d'éditeur impliqué, uniquement deux procédures :
- Upload WordPress
- Filezilla

A noter
Il est rapporté en notes sur le site Filezilla :
Filezilla : Data_Type
Note in Filezilla project https://wiki.filezilla-project.org/Data_Type
FileZilla does not analyse files uploaded as ASCII in any way. So if you have mixed line endings, somewhat "unexpected" things can happen. The native line ending for Windows is CR+LF. As this is what the FTP server expects when transferring files in ASCII, FileZilla on Windows does not apply any line ending translation at all. Now, imagine there is a text file with mixed Windows (CR+LF) and Unix (LF) line endings. Uploading that file from a Windows-based system to a Unix-based system will result in all CR+LF translated to LF only. Downloading that file again will make the FTP server convert all LF to CR+LF while sending it to FileZilla. As a result, all LF effectively are converted to CR+LF.
Another example is a text file with mixed line endings. FileZilla on Windows uploads that file to an FTP server running on Windows - no line ending conversion is done at all. Some text editors transparently handle mixed line endings so in such a text editor, the text file looks fine. However, other programs do not handle these cases and the text file might not work as expected in programs running on the server consuming that text file because they are confused by the still embedded Unix-style line endings (LF).
In yet another example, a Windows (CR+LF) text file was uploaded to a Unix-based FTP server in binary. If that file is downloaded in ASCII, the FTP server translates LF to CR+LF so the CR+LF line endings will be converted to CR+CR+LF. FileZilla on Windows does expect the file to already use CR+LF line encoding (per FTP specification), so no more translation is done. Depending on the text editor used, lines might be separated by an additional empty line now.
La seule chose que tu as trouvée si je comprends bien ton message, c'est qu'il y avait des problèmes de retours à la ligne incorrects dans ton code.
Faux : j'explique que plus de 1000 fichiers texte de l'installation wordpress (plugins chargés) contiennent le problème : fins de lignes CRLF sous Linux devenant normalement CRCRLF après importation vers windows. Et justement ce n'est pas le cas du code que j'ai créé parce que lors de son chargement vers linux les CRLF (windows correctement gérés pas mon éditeur) deviennent naturellement LF seul (convention Unix) comme il convient.

Je dis que j'ai vérifié que le simple fait de remplacer par les moyens adaptés des codes invalides CRCRLF par CRLF suffit (sur un code qui n'est pas le mien) à faire disparaitre un plantage d'exécution php.
Tous les éditeurs de code décents permettent de gérer correctement les retours à la ligne et n'insèrent pas des CRCRLF en caractère de retour à la ligne.
Je n'ai jamais laissé supposer une pareille chose, j'ai décrit avec précision le mécanisme en cause qui n'impliquer pas l'éditeur.
Maintenant il est possible avec un éditeur de texte, paramétré pour nettoyer le code (remplacer CRCRLF par CRLF lors de la sauvegarde ou au chargement, peu importe), de réaliser l'opération, Mais au lieu d'éditer à la suite plus de dix mille fichiers j'ai préféré utiliser WinGrep (seul utilitaire permettant d'effectuer le traitement) qui a traité le problème en quelques secondes. Néanmoins un éditeur binaire (Code affiché en Hexa) est capable de faire l'opération, mais fichier par fichier, et il faut avoir ouvert le fichier pour constater l'anomalie, ou soupçonner quand Scite ou PhpStorm ou PSPad affiche des doubles lignes (interprète par défaut CRCRLF comme CRLFCRLF pour l'affichage)
Bien sur, ensuite ne plus utiliser le processus d'importation de plugin utilisant un Fichier zip téléchargé.

Quand a "phpstorm" que j'utilise majoritairement c'st un excellent éditeur parfaitement fiable, et j'ai je crois signalé que j'ai testé divers éditeurs, dont la liste principale est : "Eclipse", "Scite", "PSPad", "PhpStorm" et vérifié leur comportement lorsque l'on leur donne à traiter des fichiers "anormaux".

Oui, je peux montrer un site qui plante, mais pas comment dans le détail. Par contre le remplacement généralisé des fins de ligne en anomalie fait que le code se met à fonctionner.

Maintenant, je ne suis pas en mesure de présenter un exemple "simple" qui le montre, la réponse est non. Parce que c'est économiquement impossible sauf à avoir beaucoup de chance, ceci en l'absence de moyen de détecter dans l'anomalie (250 000 lignes de code concernées) l'instance ou les instances qui créent la conséquence observée et par quel mécanisme. C'est à dire avoir résolu tout le problème.
Pour l'instant je me contente d'avoir un code qui à un comportement prévisible et le moyen de le déboguer quand l y a lieu.

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par @rthur » 31 mai 2015, 02:25

Je vais encore te répondre la même chose mais tant pis...
:arrow: Donne nous 1 exemple de code qui fait buguer PHP de façon "anormale" sans log.


Moi je veux bien accuser PHP, Linux, Windows, les moteurs d'exécution Javascript, CSS ou même Wordpress de mal gérer certains trucs, mais force est de constater que pour l'instant à aucun moment, tu n'as été capable de fournir un seul exemple concret qu'on puisse regarder.


La seule chose que tu as trouvée si je comprends bien ton message, c'est qu'il y avait des problèmes de retours à la ligne incorrects dans ton code.
Et ça, il n'y a qu'un seul fautif, ce n'est ni Windows, ni Linux, ni la décompression de Wordpress => c'est la faute de ton éditeur de code.

Tous les éditeurs de code décents permettent de gérer correctement les retours à la ligne et n'insèrent pas des CRCRLF en caractère de retour à la ligne.
Utilise Sublimetext ou Scite par exemple et tu pourras voir les caractères de fin de ligne et les gérer proprement.

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 30 mai 2015, 17:20

Bonjour,

La désactivation de tous les plugins en même temps, puis une réactivation aléatoire, a fait disparaître deux problèmes : le ob_get_content et un blocage clavier sur l'édition d'une "page"...
Et le plugin contenant le ob_get_content s'est mis à se comporter parfaitement normalement.

J'ai rapproché le problème d'une bizarrerie intervenue il y un a deux mois : écran blanc après une modif d'un plugin -> pas d'erreur détectable, j'avais découvert en éditant en Hexa que des doubles lignes injustifiées étaient en fait des CRCRLF que j'ai remplacé par CRLF, le plantage avait disparu.

Le bug est en fait le suivant :
Wordpress, lors de l'importation de plugin zippés, recopie les fichiers texte (php, js, css) en environnement Linux comme des binaires en maintenant les fins de lignes en CRLF. Ces fichiers s'il sont modifiés en environnement Windows voient les eol devenir au minimum CRCRLF, et de manière variable suivant l'éditeur vont se trouver avec des fins de lignes hétérogènes parfois multiples.

php qui ne bronche pas sur des CRLF inattendus en environnement Linux semble, après avoir rencontré certaines suites de fin lignes peu orthodoxes avoir un comportement aléatoire dont le ob_get_content() est un exemple, ainsi que le retour avec écran blanc (un plantage sec restant en cause inconnue sans outil de debug actif) et probablement d'autres cas de dysfonctionnements. Le fait fait de modifier simplement de manière masquée des CRCRLF ou CRLFCRCRLF etc. anormaux entre les lignes "sensibles" fait disparaître les phénomènes (une fois la première hétérogénéité introduite on peut avoir à peu près n'importe quoi au fur et à mesure des mises à jour et transferts).

Pourtant le principe même de la syntaxe devrait, en éliminant ces caractères quels qu'ils soient, quelque soit la plateforme, rendre php insensible à ce problème (une comparaison binaire automatique de tous les fichiers concernés plus de 5000 et que je n'ai pas pu effectuer : outil ? devrait permettre de voir s'il y a ou non d'autres anomalies, une interaction avec UTF-8 ?).

La question qui reste néanmoins posée, (puisque les manifestations existent d'une différence de comportement de php en fonction de fins de lignes hétérogènes) : quelle est la protection de php contre ces caractères de fin de ligne hétérogènes outre le cas des chaînes Heredoc Nowdoc (que je dois vérifier).

Le problème semble exister aussi avec javascript (là en exécution locale) et même les css (cas totalement inexpliqué de blocage de l'accès clavier pour tous les champs textes d'une page).

Je chercherai à retrouver un exemple (j'ai une version des fichiers générant l'anomalie).

Je n'ai plus d'anomalie, mais cela m'aura coûté un mois à devenir dingue.

La détection , l'alerte et la correction de ces anomalies devrait, à mon sens, être intégrée aux outils mis en jeu dans ces processus. En effet, si Filezilla documente son comportement avec précision, les éditeurs de fichier font de tout et en général sans alerte tant à l'affichage qu'à la sauvegarde quand ils sont en mode "auto" pour la reconnaissance des formats.

Merci de votre réactivité.

Le sujet pourrait être clos si l'on considère le cas particulier, mais il reste cependant pas mal de questions générales en suspend.

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par Saian » 23 mai 2015, 13:17

Je pense que tout le monde a compris qu'il y avait une erreur dans la mise en forme du message il fallait lire "après" dans le code que j'avais un tout petit peu mis en forme avec un copier coller alors que le code comprend des notes.
Ce n'est pas ça que je soulignais trebly, oui je me doutais bien que tu voulais écrire "après", ce que je soulignais c'est que dans ton html généré tu n'as pas mit la trace d'après le ob_get_contents et ce que je disais, c'est que cette trace s'affiche belle et bien.

Bref j'imagine que tu voulais illustrer le cas de plantage afin de démontrer que ton hypothèse est fondée... ceci dit, sans connaitre le code qui s'exécute après, ça ne prouve aucunement que le ob_get_contents provoque une sortie de la fonction. C'est une déduction précipitée si l'on a pas attentivement épluché le code venant après. Ce n'est qu'une fois qu'on s'est clairement assuré que le problème ne vient pas du code d'après que l'on peut éventuellement en venir à ta conclusion.

Tu dis que tu as 2 cas différents, un cas avec un article et un cas avec une liste d'articles et que le plantage se produit dans le cas avec liste d'articles. Ne penses tu donc pas qu'il pourrait y avoir un problème avec ton code dans le cas de la liste d'articles ?

Je ne comprends pas bien où tu en es, es tu toujours sur l'idée du ob_get_contents qui provoque une sortie de la fonction ou es tu parti sur une autre hypothèse ?

Si ton hypothèse est toujours la même (ob_get_contents provoquant une sortie de fonction) je vais te proposer quelque chose de très simple pour nous en assurer : ajoute un exit(); juste après le ob_get_contents et assure toi que l'exit n'est pas appelé dans le cas de plantage. Si l'exit se fait, tu pourras alors en conclure que ton hypothèse est erronée et que le problème vient probablement du code qui suit et si effectivement le exit() ne se fait pas, alors déplace le avant le ob_get_contents. Si l'exit se fait alors ok, il y a visiblement une sortie de la fonction lors du ob_get_contents mais s'il ne se fait pas on pourra alors en conclure que lors du cas de plantage la fonction n'est pas appelée et que le problème est ailleurs (mais d'après ce que tu nous a dis cette hypothèse est à priori invraisemblable).

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 23 mai 2015, 03:51

Bonsoir,

Je reviens vers vous pour vous tenir au courant. Le problème n'est pas résolu.

Remarque:
En revanche ton exemple n'imprime pas ce que tu dis, il imprime ceci (le commentaire après ob_get_contents s'affiche aussi) :

Code : Tout sélectionner

<div><!-- avant ob_get_content par a() --><!-- avant ob_get_content par a() --><!-- début de b() --></div>
Je pense que tout le monde a compris qu'il y avait une erreur dans la mise en forme du message il fallait lire "après" dans le code que j'avais un tout petit peu mis en forme avec un copier coller alors que le code comprend des notes.

Ceci étant, après installation sur le serveur dans un premier temps j'ai obtenu sur les mêmes données sur le serveur OVH l'erreur et sur mon serveur un fonctionnement correct. Mais après quelque chose d'inconnu il se sont mis à avoir un comportement identique avec le même défaut.

Les différences de config :
  • Le serveur OVh fonctionne en mode "developpement" et WP est configuré en mode debug php 5.5.22 (mais le pb est identique avec 5.4 en changeant de moteur grâce ovhconfig), mémoire 512Mo
  • Le serveur local de developpement est avec xDEBUG actif et le mode WP debug tourne en php 5.4.6, mémoire 375Mo
xDEBUG ne donne pas d'erreur.

J'ai complété le test avant exécution avec les fonctions ob_get_level() et ob_status(true) (trace avec commentaire ou var_dump) qui rapportent la même chose dans tous les cas et aucune anomalie.
Je teste et trace aussi les variables amont (paramètres passés et d'environnement), il n'y a rien.

La taille mémoire utilisée sur OVH est de 27Mo et de 57 sur le serveur de développement, donc RAS.
Quand ob_get_contents() fonctionne le besoin mémoire supplémentaire est de 2Mo donc RAS.
Il y a 4 niveaux de buffer, le dernier, celui des données HTML principales qui est celui que j'analyse et que je récupère et modifie quand ça marche, contient de manière variable environ de 60 à 100Ko (ce n'est que du texte, les images et d'autres éléments sont en href chargées par les requêtes générées par le navigateur après le premier chargement par les href ou ajax).

Donc rien à creuser.
Demain je teste avec ob_get_clean() et si ça fonctionne il n'y aura qu'à réécrire le contenu, c'est le seul contournement possible et auquel je viens de penser. Dans l'exécution normale c'est après avoir traité correctement la copie du buffer récupérée par bo_get_contents() que je fais un clean avant d'écrire le contenu modifié.

La différence entre les cas de bon fonctionnement et celui du défaut d'exécution est la nature des traitements.
En effet, dans le cas du fonctionnement correct on affiche un article unique.
Dans le cas du plantage il y a une boucle qui génère une liste d'articles, mais ce travail est terminé quand l'incident se produit et le code html généré fait apparaître les DIV successives sans anomalies. par contre c'est bien là la différence déterminante.
Donc c'est toujours le seule piste valide.

@rthur me conseille de faire un code simple, c'est vrai, c'est souvent la solution quand certains traitement posent problème. C'est ce que je fais très fréquemment et que j'ai fait là pour mettre au point le traitement du buffer (qui suit quand il est exécuté) avec des expressions régulières un peu complexes que j'ai fait tourner en simulation sur des jeux test les plus tordus possible.
Mais là, quand l'incident se produit c'est sur une fonction qui, réduite, n'a qu'une seule instruction et la pile d'appel est identique entre le cas du défaut et celui du bon fonctionnement. On en est au même stade d'exécution. Je ne vois vraiment pas comment isoler la procédure et recréer un environnement (buffers, utilisation mémoire etc...) identique, mais variable, extensible, avec l'espoir qu'en reconstruisant WP progressivement autour on verra apparaître le problème, dans dix ans... peut-être.
Reproduire un incident de ce type à partir de zéro, en complexifiant autour d'une seule instruction est à mon avis impossible et les chances de produire l'effet sont nulles. Seule une explication rationnelle du comportement observé pourrait permettre de connaitre la nature du problème.

Par contre, comme je l'ai rappelé plus haut, il y a sans aucun doute quelque chose qui se passe mal sans erreur signalée lorsque la boucle de parcours de la liste est exécutée, ceci même si le résultat est correct, et ça je ne l'ai pas encore vu. Faire un trace détaillée et l'analyser pour espérer voir quelque chose est aussi une piste ?
Je peux aussi déshabiller les fonctions qui interviennent dans la boucle effectuée pour produire la liste d'articles, c'est peut-être bien la meilleure piste. Et ensuite produire et analyser un trace d'exécution concernant uniquement cette partie. Si le problème a disparu en ré-habillant les quelques centaines de ligne de code concerné, le phénomène peut peut-être réapparaître.

Une autre piste est d'avoir un cas similaire que personne malheureusement n'a jamais vu pour comparer et trouver les points communs, réduire la variété, on ne l'a pas.

Merci de votre aide, elle me force à réfléchir, en particulier en m'exprimant ici.

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par @rthur » 21 mai 2015, 21:41

On en revient toujours au même point : il faut que tu réussisses à isoler ton problème dans un code PHP le + simple possible pour le mettre en évidence et qu'on puisse faire des tests dessus.

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par Saian » 21 mai 2015, 20:08

Je ne vois pas en quoi ce que je dis est faux. A côté peut être, mais c'est dur de proposer des pistes avec le peu d'éléments et je n'ai aucune piste concernant ob_get_contents qui provoquerait une sortie de fonction.
<?php
echo '-- BEFORE ob_get_contents() --<br/>';
$str = ob_get_contents();
echo '-- AFTER  ob_get_contents() --<br/>';

echo $str;
Affiche :
-- BEFORE ob_get_contents() --
-- AFTER ob_get_contents() --
-- BEFORE ob_get_contents() --
Cet exemple illustre l'effet du ob_end_clean (il produit bien un affichage similaire au cas de plantage, on a la sortie qui précède le ob_get_contents mais pas la sortie qui suit) :
<?php
echo '-- BEFORE ob_get_contents() --<br/>';
$str = ob_get_contents();
echo '-- AFTER  ob_get_contents() --<br/>';

ob_end_clean();
echo $str;
Affiche :
-- BEFORE ob_get_contents() --
Et cet exemple pour montrer que c'est bien le echo $str qui produit l'affichage :
<?php
echo '-- BEFORE ob_get_contents() --<br/>';
$str = ob_get_contents();
echo '-- AFTER  ob_get_contents() --<br/>';

ob_end_clean();
N'affiche rien.

En revanche ton exemple n'imprime pas ce que tu dis, il imprime ceci (le commentaire après ob_get_contents s'affiche aussi) :
<div><!-- avant ob_get_content par a() --><!-- avant ob_get_content par a() --><!-- début de b() --></div>

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 21 mai 2015, 19:42

Je ne suis persuadé de rien, je constate :

Code : Tout sélectionner

function appel() { echo '<div ..>'; A(); B(); echo "</div>"; } function a() { echo "<!-- avant ob_get_content par a() -->"; ob_get_content(); echo "<!-- avant ob_get_content par a() -->"; ..... } function b() {echo "<!-- début de b() -->"; .... }
Html généré

Code : Tout sélectionner

<html précédent la fonction puis le tag précédent généré par appel() : <div...> <!-- avant ob_get_content par a() --> <!-- début de b() -->"; < HTML code généré ensuite par fonction suivante B > etc... </div>
Il suffirait d'un ob_get_clean() ou ob_end_clean() mal placé pour obtenir le "cas de plantage".
Désolé c'est à coté de la question et faux
1- le buffer est ouvert puisque l'echo "avant" est bien écrit, et il le reste puisqu'on le retrouve dans la sortie finale.
2- s'il était fermé, son contenu, à la suite d'une ouverture implicite générée par la commande echo serait le commentaire lui-même et je le récupérerai dans la variable et s'il n'est pas ouvert (et en l'absence du commentaire qui est volontairement écrit là) ob_get_contents renverrait false ce que j'ai, bien sur, testé.

C'est évidemment déroutant. L'aide, c'est d'aller à la pêche ou d'ouvrir des pistes, même de tenter d'en ouvrir.
Il est important de savoir que des données accidentellement erronées passant des filtres peuvent provoquer des effets totalement inattendus et bien avant que l'accident final intervienne.
Et la il n'y a pourtant rien d'anormal nulle part, c'est à dire détectable avec les meilleurs moyens existants.

L'affichage final est sans aucun défaut sauf l'absence dans certains cas de data du résultat d'exécution de a()...

A oui au fait, j'ai transféré data et soft sur mon serveur, tout se passe bien exécution parfaite.
La même requête avec les mêmes data et le même code produisent l'anomalie chez OVH.

Parfaitement reproductible avec les mêmes data, je rappelle qu'avec certaines data on passe et pas avec d'autres : A creuser avec des variantes (les journées n'ont que 16 à 20h utilisables).

xDebug ne donne pas d'anomalies. Deux erreurs mineures détectés, corrigées, mais non impliquées (aucun changement sur les deux plateformes)
Test effectué avec php 5.4.6 (ma plateforme sous windows) et 5.5.x et 5.4.x chez OVH : même résultat.

Je penche maintenant pour un pb de config.php avec une erreur sans trace chez OVH, il n'y a pas de piste à suivre sauf contrôler ce qui aurait pu changer sur la plateforme OVH depuis un mois environ et essayer des jeux de données différents.

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par Saian » 21 mai 2015, 11:43

Re trebly, je n'ai personnellement jamais vu un ob_get_contents() provoquer une sortie de fonction et je dois avouer que je suis plutôt sceptique à cette idée.

Mais si tu es persuadé que c'est ce qui se passe, je ne vois pas en quoi nous pourrions t'aider ?

Il suffirait d'un ob_get_clean() ou ob_end_clean() mal placé pour obtenir le "cas de plantage".

EDIT
Sans voir le code qui s'exécute avant et le code qui s'exécute après c'est impossible de déterminer avec certitude d'où peut précisément venir le problème mais ce qui est sur c'est que la ligne <!-- Widget_toc begin --> fait partie du buffer retourné par le ob_get_contents qui vient juste après et que cette ligne s'affiche bien (ainsi que tout ce qui précède apparemment). Il semble donc qu'il n'y ait pas de problème avec ce buffer étant donné qu'il est bien affiché.

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 20 mai 2015, 21:40

Salut,

En résumé et pas dans l'ordre :
J'ai encadré le ob_get_content() entre deux commentaires html comme je l'indique.
J'ai le premier, pas celui qui suit.
Mais pas toujours, avec des données différentes tout s'exécute normalement, conclusion : c'est l'exécution qui précède sur ces données différentes qui conduit à un comportement anormal de ob_get_contents() (j'ai vu des programmes s'arrêter sur un $i.='tata'; ou d'autres instructions anodines).
As tu essayé d'afficher le buffer après l'appel à ob_get_contents ? à la fin de la fonction widget_toc ?
Désolé mais comme c'est l'instruction de base d'affectation à une variable du contenu du buffer qui plante et qui fait sortir de la procédure comme je l'indique, il est vérifié qu'aucune instruction de la fonction ne s'exécute après le ob_get_content(); qui s'avère terminal.

Et, bien sur, comme je récupère, in fine, la page complète sauf le widget, tout s'exécute normalement sauf le widget dès le ob_get_contents().
Le contenu est affiché et sans aucune anomalie, à l'exception du widget vide...

Donc après être sorti du widget l'exécution reprend son cours normalement.

Le buffer reste ouvert, j'ai écrit mon commentaire dedans et il est dans la page (examen du code html généré), et d'autres widgets qui suivent continuent ensuite à écrire, tout va bien, sauf que ob_get_contents() dont le rôle n'est que de lire le contenu du buffer se comporte comme un return... c'est pour moi la preuve qu'il travaille sur quelque chose de pas bien propre résultant de ce qui précède (des erreurs non récupérées et non terminales n'ayant probablement rien à voir).

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par Saian » 20 mai 2015, 16:36

Salut, peut être qu'un code vide le buffer après l'appel de widget_toc mais avant les widgets suivants.
Mais dans ce cas je pense que la ligne <!-- Widget_toc begin --> devrait également être absente car n'ayant pas de ob_start, elle est dans le même tampon que ce qui vient après le ob_get_contents().

As tu essayé d'afficher le buffer après l'appel à ob_get_contents ? à la fin de la fonction widget_toc ?

As tu regardé, débogué le code du générateur de widget ? tu pourrais probablement vérifier le buffer après chaque génération de widget.

PS : en tout cas pour moi, avec les éléments que j'ai, le problème viendrait à priori plutôt du code après le ob_get_contents de la fonction widget_toc. Pas forcément dans la fonction, mais dans ce qui se passe après.

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 20 mai 2015, 14:53

Bonjour,
Si tu ne veux pas parler d'erreur, parlons à défaut d'un comportement inattendu mais dans tous les cas, il y a bien un problème quelque part sinon tu ne serais pas là.
Nous sommes parfaitement d'accord.
La seule cause possible me semble d'avoir donné à manger au code des données indigestes quelque part avant dans l'exécution.
Il y a, je l'espère bien une "erreur" détectable, sinon je suis mal parti si je veux avoir une appli stable.

Pour la petite histoire j'ai eu un cas sévère qui m'a coûté une entreprise, que j'ai trouvée plus de dix ans plus tard... de mémoire, je relisais le code sans objectif précis quand j'ai constaté un absence de contrôle sur des données... C'était ça le client donnait à manger des données totalement improbables et la limitation d'un code que je n'avais pas écrit n'était pas spécifiée. C'est un peu mon autre message sur le format ligne batard (x0D0D0A mélange Windows Unix) mais là j'ai trouvé très vite.

Ton code s'appuie sur du code de Wordpress, il t'appartient de bien vérifier que toutes les données que tu récupères en entrée soient conformes à ce que tu attends et il faut que tu remontes les appels de fonctions pour valider que l'architecture dans laquelle tu t'inscris fait bien les bons appels aux bons moments tels que tu l'as conçu.
Si tu es en train de me dire qu'un utilisateur de WordPress, je ne le crois pas, doit vérifier le code quand s'il écrit : "Jean est allé à l'école", "Claude est allée à l'école", passe mais que "Jean-Michel est allé à l'école" est une erreur parce que le code ne sait pas traiter le noms composés... On ne peut pas être d'accord.

Dans le cas où une pile d'appels serait en cause, comme d'une part ce qui précède ne sollicite pas mon développement et que j'ai pris de plus soin de rajouter (depuis) un test sur les paramètres de la fonction (qui ne sont, de plus, pas encore utilisés), je ne pense pas que la question soit là. Ceci étant je peux faire une extraction sur les deux array d'options reçues en paramètres. Je n'y crois pas du tout (trop long à expliquer). Tout ce qui se passe avant est du standard WordPress mais ce qui est exécuté est plus complexe dans le cas du plantage. C'est la piste mais pas dans mon code. Ce que je récupère est sain ou bien, le contenu du buffer ne pas pouvoir agir sur l'exécution de ob_get_content() qui devrait pouvoir retourner une chaîne binaire quelconque (inutilisable certes), mais elle l'est puisque c'est bien sont contenu, auquel l’accès ne peut avoir lieu qui génère ensuite la sortie dans laquelle il n'y a aucune anomalie.

Tu dis :
En l’occurrence, avec les quelques lignes que tu nous as donné, tu fait un appel à ob_get_contents() mais tu ne sembles pas maitriser le moment où ob_start() est déclenché ni qu'il n'y aurais pas un ob*_flush() ou ob*_clean() ou équivalent qui viderait le buffer et t’empêcherait de l'exploiter.
Sauf que, j'ai donné le code d'origine mais pas les test, avant d'écrire j'ai tout vérifié (du moins je crois) et si le buffer était vide ou non ouvert il retournerait une chaîne vide ou false. Ceci étant comme le commentaire qui précède fait bien partie de la page HTML générée il n'y a pas de question a se poser.
En informatique, rien n'est magique, il y a donc forcément eu une modification quelque part, que ce soit une mise à jour de wordpress (qui peut se faire automatiquement), d'un de ses plugin ou une mise à jour de la plateforme qui t'héberge...
Mais si, dans les données, le cas que je cite plus haut le produit fonctionnait depuis des années et puis un jour quelqu'un a créé un jeu de données "invraisemblable" pour l'homme de l'art... ou bien une combinaison théorique valide mais... mais où
Il est aussi possible qu'une mise à jour de plugin ou du noyau de WP soit à l'origine de problème. Et là il est presque totalement impossible de rembobiner, sauf vérifier que cela fonctionnait, et faire de comparaison de traces...
A un moment il va peut être quand même falloir se remettre en question... et arrêter les "je sais que c'est impossible", "je sais que *mon* code est bon..."
Mais le plantage arrive avant que mon code ne s'exécute. A moins que l'exécution future ne lu fasse peur...

Je dis :
Mais je sais qu'il il n'y aucune chance que je trouve une erreur qui "implique" le plantage, et je suis quasi certain que les logs Apache-Php et surtout les traces que pourra produire XDebug ne donneront aucun lien entre une erreur et le plantage.
Je ne dis pas que je ne vais rien trouver, mais qu'il n'y aura pas d' "implication" directe. Autrement dit ob_get_content() arrête la fonction parce qu'il y a eu un "accident" en amont. J'ai eu le cas ou la zone mémoire lue (une string) avait été écrasée par une instruction précédente, bien plus haut dans le code. C'est donc en éliminant des erreurs possibles ou certaines mais sans conséquences immédiates que le problème disparaîtra. Je te donne rendez-vous.
Si tu procède à un débogage méthodique en comprenant ce que tu fais, il n'y a pas de raison que le problème disparaisse sans savoir pourquoi... :D
Mais si, je saurais qu'il y a une relation de cause à effet (même reproductible) mais je n'aurai pas d'explication de la causalité : Si x alors y, est vrai mais pourquoi ?
D'où l'importance de bien valider en entrée les données reçues de l'extérieur et de comprendre le fonctionnement du code dans lequel tu t'insères.
C'est vrai mais c'est un voeux pieux, avec 12000 modules et 1000000 de lignes de code...

Il y a presque sans aucun doute un problème de "solidité" de code, peu détectable à la simple lecture, qui fait faire à php quelque chose d'imprévu dont la conséquence est un comportement anormal plus tard, comme un trou dans une chaussée, tant qu'on en passe pas dedans on peut ne pas savoir qu'il existe.

Je bosse et je te tiens au courant.

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par @rthur » 20 mai 2015, 09:02

Il n'y strictement rien qui puisse produire une erreur.
Si tu ne veux pas parler d'erreur, parlons à défaut d'un comportement inattendu mais dans tous les cas, il y a bien un problème quelque part sinon tu ne serais pas là.
Maintenant, qu'il y ait une anomalie précédente qui ne génère pas d'erreur signalée à l'exécution ou conduisant à un crash, mais perturbant l'exécution de Php de sorte que l'appel de ob_get_contents() produise un effet inattendu, ça je suis tenté de le croire.
Mais ce code n'est pas le mien.
Ton code s'appuie sur du code de Wordpress, il t'appartient de bien vérifier que toutes les données que tu récupères en entrée soient conformes à ce que tu attends et il faut que tu remontes les appels de fonctions pour valider que l'architecture dans laquelle tu t'inscris fait bien les bons appels aux bons moments tels que tu l'as conçu.

En l’occurrence, avec les quelques lignes que tu nous as donné, tu fait un appel à ob_get_contents() mais tu ne sembles pas maitriser le moment où ob_start() est déclenché ni qu'il n'y aurais pas un ob*_flush() ou ob*_clean() ou équivalent qui viderait le buffer et t’empêcherait de l'exploiter.
cela fonctionnait depuis quatre mois sans broncher. Et puis sans crier gare et aucune modification nouvelle, l'exécution se plante... sur la lecture alors qu'aucun code modifié n'a encore été exécuté.
En informatique, rien n'est magique, il y a donc forcément eu une modification quelque part, que ce soit une mise à jour de wordpress (qui peut se faire automatiquement), d'un de ses plugin ou une mise à jour de la plateforme qui t'héberge...
J'entreprends donc, puisqu'il est impossible de trouver de cas de plantage de cette fonction, le rapatriement de l'application sur ma plateforme de développement.

Mais je sais qu'il il n'y aucune chance que je trouve une erreur qui "implique" le plantage, et je suis quasi certain que les logs Apache-Php et surtout les traces que pourra produire XDebug ne donneront aucun lien entre une erreur et le plantage.
A un moment il va peut être quand même falloir se remettre en question... et arrêter les "je sais que c'est impossible", "je sais que *mon* code est bon..."
Par contre en éliminant des erreurs ou alertes non fatales (générées par le code de WordPress ou d'autres plugins précédents dans l'exécution), je pense qu'il est à peu près certain que le problème disparaîtra sans que jamais on ne découvre pourquoi, ni surtout que le délai pour le traiter soit maîtrisable.
Si tu procède à un débogage méthodique en comprenant ce que tu fais, il n'y a pas de raison que le problème disparaisse sans savoir pourquoi... :D

Ceci étant j'ai déjà connu plusieurs cas de plantages (pas en php mais en langage compilé) du à des données non (mal) contrôlées, et en fait de contenu invalide, générant des défaillances aléatoires générant en cascade des erreurs ultérieures à des emplacements imprévisibles (en général les données invalides entraînaient un débordement mémoire sans conséquence immédiate...).
D'où l'importance de bien valider en entrée les données reçues de l'extérieur et de comprendre le fonctionnement du code dans lequel tu t'insères.

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par trebly » 20 mai 2015, 04:41

Bonsoir,

Code : Tout sélectionner

Le générateur de widget à écrit <div id='widgets'> et lance widget_toc function widget_toc ($args=array(), $instance=array() ) { echo '<!-- Widget_toc begin -->'; $str_ob = ob_get_contents(); echo '<!-- Widget_toc begin : got output buffer (ob_get_content) -->'; ... }
Dans certain cas d'exécution ce code produit (le widget est le premier) :

Code : Tout sélectionner

<div id='widgets' > <!-- Widget_toc begin --> <!-- Widget_toc begin : got output buffer (ob_get_content) --> puis tout le code html correct du widget puis les autres widgets suivants </div>
Dans le cas de plantage :

Code : Tout sélectionner

<div id='widgets' ...> <!-- Widget_toc begin --> puis les autres widgets suivants </div>
Il n'y strictement rien qui puisse produire une erreur.

Maintenant, qu'il y ait une anomalie précédente qui ne génère pas d'erreur signalée à l'exécution ou conduisant à un crash, mais perturbant l'exécution de Php de sorte que l'appel de ob_get_contents() produise un effet inattendu, ça je suis tenté de le croire.
Mais ce code n'est pas le mien.

Pour information, indépendamment de certains développements que je réalise depuis longtemps, j'au eu besoin d'un outil pour publier un blog. Je l'ai pris standard sur étagère. Malheureusement le générateur de table des matières, un plugin existant, a une insuffisance assez rédhibitoire que j'ai corrigée (ne traite pas dans sa version courante distribuée pas les documents dits "multipages" découpés en sections avec des url chargées successivement. Pour cela j'ai du, tout de suite au début du widget lire le buffer, et il s'ensuit du code certes, mais postérieur dans l'exécution à l'endroit du plantage, et cela fonctionnait depuis quatre mois sans broncher. Et puis sans crier gare et aucune modification nouvelle, l'exécution se plante... sur la lecture alors qu'aucun code modifié n'a encore été exécuté.

J'entreprends donc, puisqu'il est impossible de trouver de cas de plantage de cette fonction, le rapatriement de l'application sur ma plateforme de développement.

Mais je sais qu'il il n'y aucune chance que je trouve une erreur qui "implique" le plantage, et je suis quasi certain que les logs Apache-Php et surtout les traces que pourra produire XDebug ne donneront aucun lien entre une erreur et le plantage.

Par contre en éliminant des erreurs ou alertes non fatales (générées par le code de WordPress ou d'autres plugins précédents dans l'exécution), je pense qu'il est à peu près certain que le problème disparaîtra sans que jamais on ne découvre pourquoi, ni surtout que le délai pour le traiter soit maîtrisable.

Et en l'occurence il n'y a pas de contournement possible.

Ceci étant j'ai déjà connu plusieurs cas de plantages (pas en php mais en langage compilé) du à des données non (mal) contrôlées, et en fait de contenu invalide, générant des défaillances aléatoires générant en cascade des erreurs ultérieures à des emplacements imprévisibles (en général les données invalides entraînaient un débordement mémoire sans conséquence immédiate...).

Evidemment le problème est qu'il n'y a pas de limite ni d'effort ni de temps prévisible à consacrer à ce type de problème.

Cordialement

Trebly

Re: Crash php sur ob_get_contents() conditions difficiles à déterminer, aucune piste : help

par @rthur » 20 mai 2015, 00:28

L'installation de WordPress a été considérée comme un outil de production qui ne nécessitait pas de développement. Les développements sont relativement mineurs et ne nécessitaient pas d'avoir à déboguer
Considéré par qui ? :shock: Car c'est contraire à toutes les best practices existantes...
Avant de faire un déploiement en prod, on doit toujours passer par une phase de dev et/ou de préprod... surtout quand ce n'est pas juste un Wordpress "out of the box" mais bien un plug-in dont tu es l'auteur.
Et dans le cas présent tu as bel et bien un bug quelque part qu'il est nécessaire de déboguer...

La nature du plantage ne me laisse que très peu d'espoir de reproduction après un changement d'environnement.
Pour avancer, il faut que l'on ait le code problématique, la config de la plateforme et les logs.

Il est donc d'abord nécessaire que tu isoles la partie problématique pour la réduire au minimum afin de reproduire le problème.
Ensuite pour les logs, soit tu peux les avoir via OVH, ou sinon tu peux reproduire l'environnement (par exemple dans une machine virtuelle) pour être le plus proche possible de ton environnement de prod.
Je maintiens que si tu n'as pas accès au log de ton serveur, il est très difficile de faire un debugage ou même une remontée de bug au PHP group qui soit efficace.
Cette fonction de bas niveau sans paramètre ne peut pas se planter sauf sur une défaillance système, pas sur un problème de développement.
D'expérience, 99.9% des développeurs qui mettent en cause le moteur PHP plutôt que leur code se trompe.
PHP est une plateforme ultra-mature avec plusieurs dizaines de millions d'utilisateurs et un nombre de retours d'expérience hallucinant que ce soit dans la doc officielle, les forums ou même le bugtracker officielle, donc si tu n'as rien trouvé en cherchant sur internet, il est fort probable que le problème vienne de ton code ou d'une spécificité de ton hébergeur.