Smarty Engine rendert wit scherm bij upgrade naar PHP8.1 i.c.m. block functions

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Maarten Baars

Maarten Baars

25/05/2022 16:27:00
Quote Anchor link
Goedemiddag allemaal

Wat. Een. Gedoe.

Ik ben bezig met het upgraden van de applicatie die hier intern gebruikt wordt. We gaan van PHP7.2 naar PHP8.1. Daarnaast maakt het systeem gebruik van Smarty Templating. Bij het genereren van een template waarin Block Functions worden gebruikt, loopt het vast. Resultaat is géén error, maar een wit scherm.

Ik heb een test template met deze code:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<div>Een of andere tekst</div>


Deze wordt gerenderd. Geen probleem. Maar dan deze:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<div>{translate}Een of andere tekst{/translate}</div>


Wit scherm. Het 'registeren' van deze blockfunctie gaat goed. Want als ik de bedoelde method
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
smarty_waf_translate
hernoem, dan gaat die registry niet goed. Dus Smarty vindt de plugin wel degelijk.

Zo'n wit scherm had ik hier al eerder geplaatst. De functie
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
class_exists()
zorgt ervoor dat de autoload wordt afgevuurd en resulteerde óók in een wit scherm. Ik heb deze opgelost met een workaround. Maar nu zit ik dus vast aan een wit scherm bij het afvuren van block functions.

Ik heb xDebug in PHPStorm aan de praat gekregen en kan de code helemaal tot diep in smartyview code volgen. En dáár gaat het ergens fout. Dit, terwijl Smarty compatible zou moeten zijn met PHP8.1. Daarnaast, áls het überhaupt al ligt aan de code van Smarty, dan zou de hele wereld met het probleem moeten komen.

Dus wat nu dan?

Ik heb het gevoel dat het aan serverinstellingen ligt. Heb al de php.ini van de server met PHP 7.2 op mijn lokale PHP 8.1 server gezet. Dat gaf het verrassende resultaat dat mysqli_report() niet gedefinieerd was. Maar dit was een false flag. Dus daar kwam ik geen stap verder mee.

Bedankt voor enige input in dit.

Maarten
 
PHP hulp

PHP hulp

25/11/2024 05:04:12
 
- Ariën  -
Beheerder

- Ariën -

25/05/2022 17:11:27
Quote Anchor link
Tja, wat meldt de error_log precies?
 
Maarten Baars

Maarten Baars

30/05/2022 10:07:14
Quote Anchor link
Ik heb de logs bekeken:

/var/log/php8.1-fpm.log
/var/log/apache2/error.log
/var/log/apache2/[projecturi]-error.log

Alle logs worden niet aangevuld met errors als ik de betreffende pagina bezoek. Als ik een error zie op een andere pagina, dan zie ik die errors wél in die logs verschijnen. Meaning: de logs worden succesvol aangevuld bij errors. En dus: geen errors bij die witte pagina's.

Toch heb ik nog wat andere notifies en warnings gevonden en weggewerkt. Al kwamen die warnings niet naar voren op die witte pagina. Dit had geen effect.

Evengoed dacht ik wel in die richting en heb dus
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
error_reporting(0);
en
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
ini_set('display_errors', 0);
ingesteld. Ook dit had geen effect.

Kortom, ik ben helemaal verblind door die witte pagina en weet niet meer waar ik moet kijken.
 
- Ariën  -
Beheerder

- Ariën -

30/05/2022 10:09:52
Quote Anchor link
Welke versie van Smarty gebruik je?
En hoe haal je Smarty binnen?
Gewijzigd op 30/05/2022 10:10:26 door - Ariën -
 
Maarten Baars

Maarten Baars

30/05/2022 11:27:08
Quote Anchor link
Versie Smarty is 4.x. Enkele weken geleden de laatste versie geïnstalleerd. Stond expliciet bij dat het PHP8.1 compatible was.

Smarty templates worden met fetch() binnengehaald.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if (@file_exists($modTemplate)) {
    $smarty     = $this->getSmartyObject();
    $this->html = $smarty->fetch($modTemplate);
    return $this->html;
}


De method *getSmartyObject()* doet in principe een *new Smarty()* en voegt wat variabelen toe met *->assign()*. Niet heel bijzonder denk ik. Of zie jij of iemand anders een verouderde manier van Smarty binnenhalen in de code hierboven?

Dank!

Toevoeging op 30/05/2022 11:53:25:

Dit lijkt ook niet te werken:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
$orders = new ordersDataObject();
$smarty->registerObject('testObject', $orders, null, false);


en dan...

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
{testObject->getLinkTo}



Toevoeging op 30/05/2022 13:08:03:

Plus:

De template_c file wordt inderdaad gecreëerd. Dus schrijfrechten is het ook niet.

Toevoeging op 30/05/2022 13:15:30:

Om preciezer te zijn:

1. Als ik {translate}Vertaal iets{/translate} toevoeg wordt de template NIET aangemaakt.
2. Als ik alleen maar <div>Vertaal iets</div toevoeg, wordt de template wél aangemaakt en wordt de pagina wel gerenderd.

Dus ja, het probleem zit hem niet in schrijfrechten, maar registerObject() en registerPlugin() genereren bij gebruik zelf géén foutmelding, maar zorgen er wel voor dat tijdens de rendering van de templates ik een witte pagina krijg.
 
- Ariën  -
Beheerder

- Ariën -

30/05/2022 13:57:18
Quote Anchor link
En gebeurt dit ook op de 3x branch?
Heb je dit al als issue doorgegeven bij Smarty?
 
Maarten Baars

Maarten Baars

30/05/2022 16:11:37
Quote Anchor link
Wat is de
Quote:
3x Branch
?

Ik zie niet waar ik ze kan benaderen behalve dan voor promotie of reclame. Op Reddit is hun community, maar die is niet heel actief. Het duurt soms maanden eer je een reactie krijgt.

Maar ik heb daar ook maar een bericht neergezet. Wellicht komt daar toch nog iemand langs. Ondertussen ga ik nog maar even graven. Mocht ik het weten, dan zet ik de oplossing hier neer. Mocht er iemand hier langskomen die het weet: please, do tell!

Dank jullie.
Gewijzigd op 30/05/2022 16:12:35 door Maarten Baars
 
Ozzie PHP

Ozzie PHP

30/05/2022 16:40:14
Quote Anchor link
Maarten Baars op 30/05/2022 11:27:08:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
if (@file_exists($modTemplate)) {
    $smarty     = $this->getSmartyObject();
    $this->html = $smarty->fetch($modTemplate);
    return $this->html;
}

Met @ voor file_exists onderdruk je een mogelijke foutmelding. Ik zeg niet dat dit de oplossing is, maar wellicht is er sprake van een niet-bestaand bestand of is de inhoud van de variabele onjuist. De foutmelding die dit normaal gesproken zou opleveren krijg je nu niet te zien. Ik zou die @ daar dus sowieso even weghalen.
 
Maarten Baars

Maarten Baars

30/05/2022 17:08:27
Quote Anchor link
Hey Ozzie.

Super dat je meekijkt met me. Dank.

Helaas is dit het niet. Overigens staat de app wel vol met oude en wankele code. Dus elke opmerking is wel handig, want inderdaad...dat zou het zomaar eens kunnen zijn.

Alleen juist in dit geval - en door jou ben ik gaan zoeken - is de code die ik gaf nou net niet de code die wordt uitgevoerd voor déze smarty problemen. Door de hele applicatie heen staan dezelfde van dit soort codes. En juist op de pagina waar het mis gaat is het net even anders:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
$smarty->assign('buttons', $this->buttons);
$this->html = $smarty->fetch($modTemplate);


Dus nu zónder die @file_exists!

Let ook op *fetch()*. Ik zag dat Smarty een DEBUG functie heeft. Wauw! De oplossing is nabij! Maar hij rendert het niet. Je kunt $debugging = true ergens instellen en dan zou hij een debug-scherm moeten toveren. Doet ie niet. Komt door onder andere die fetch. Je moet display() gebruiken.

Maar helaas, als ik daar *display()* van maak doet ie niks nieuws. Maar wellicht is dit wel een optie om te onderzoeken en die debug temp aan de praat te krijgen.

Andere ideeën blijven welkom. Bedankt!
 
Ozzie PHP

Ozzie PHP

30/05/2022 17:56:56
Quote Anchor link
Doe eens dit:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
<?php

exit('*****');

$smarty->assign('buttons', $this->buttons);
$this->html = $smarty->fetch($modTemplate);

?>

Zie je nu iets op je scherm?
 
Maarten Baars

Maarten Baars

31/05/2022 08:55:03
Quote Anchor link
Hey Ozzie PHP.

Ja, dan zie ik die 5 sterretjes.

Ik heb de PHP Storm debug aan de praat gekregen door de applicatie lokaal te draaien. Dus met Xampp en de professionele serverinstellingen krijg je exact hetzelfde probleem. Op zich ook interessant, want dan lijkt het niet aan serverinstellingen te liggen.

En dan zie je dat hij tot heel diep in de Smarty engine komt. Tot aan het bestand 'smarty_internal_smartytemplatecompiler' waar hij de 'lexers' parset. In ieder geval zijn dat die {translate} items. En dan gaat het mis, maar waarom? Geen idee. Vandaag met frisse moed weer verder debuggen met méér breakpoints om te zien of ik echt nog dieper kan gaan tot het werkelijke punt waar het fout gaat.

**Saillant detail**
{translate}Vertaal dit{/translate} dat gaat fout.
Maar als je een variable wilt weergeven met {$foo}, dat lukt wel.
 
- Ariën  -
Beheerder

- Ariën -

31/05/2022 08:57:46
Quote Anchor link
Zo maar een idee: Gebruik je geen UTF-8? Hier had ik pas ook troubles mee i.c.m. de replace-modifier.
 
Maarten Baars

Maarten Baars

31/05/2022 09:37:43
Quote Anchor link
Goeie. Maar nee. Ik heb gekeken of in de PHP.ini de "default_charset" ingesteld stond op UTF-8. Dit was het geval.

Daarna gekeken of in de "httpd.conf" de regel "AddDefaultCharset UTF-8" stond. Dit was niet het geval. Dus toegevoegd en opnieuw opgestart, maar geen resultaat.

Dank evengoed voor het meedenken.
 
Ozzie PHP

Ozzie PHP

31/05/2022 11:53:36
Quote Anchor link
Maarten Baars op 31/05/2022 08:55:03:

Ja, dan zie ik die 5 sterretjes.

Oké, door die regel telkens op een 'verdere' plek in je code te zetten, kun je makkelijk bepalen op welk moment de fout ontstaat. Je volgende stap zou bijvoorbeeld dit kunnen zijn:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php

$smarty
->assign('buttons', $this->buttons);
exit('*****');
$this->html = $smarty->fetch($modTemplate);

?>

Zie je de sterretjes nog steeds? Dan gaat tot dat punt alles nog goed. Dan ga je weer een stap verder:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php

$smarty
->assign('buttons', $this->buttons);
$this->html = $smarty->fetch($modTemplate);
exit('*****');

?>

Zie je nu ineens de sterretjes niet meer? Dan zit de fout dus in:

$this->html = $smarty->fetch($modTemplate);

Vervolgens kun je dan in die fetch() functie weer hetzelfde 'trucje' toepassen en zo kom je steeds dichter bij het punt waar er iets niet goed gaat. Ongeveer hetzelfde wat jouw editor ook doet, alleen doe je dat nu handmatig. Ik vind het persoonlijk wat makkelijker werken, maar wellicht vind jij de debug-functie van de editor handiger. Je moet het maar eens proberen.
 
Maarten Baars

Maarten Baars

31/05/2022 14:43:54
Quote Anchor link
@OzziePHP, tnx!

Ik heb zelf ook zo aan debuggen gedaan en dat werkt inderdaad tot op zekere hoogte wel. Alleen niet in dit geval. Het probleem zit heel diep in de Smarty code en dan is het wel handig dat je breakpoints kan invoeren met één klik. Die breakpoints die je in PHP Storm invoert zijn eigenlijk ook exit() of die(). Maar dan met een volledige var_dump van alle variabelen.

Maar omdat je dus snel breakpoints kunt zetten en vanaf je breakpoint stapsgewijs de volgende regel kunt parsen totdat het fout gaat is het me dus na lang onderzoek gelukt om de bron van de ellende te achterhalen. De oplossing heb ik nog niet, maar het is wel een heel frappant iets en ik had er ook hier op deze site al eerder over geschreven.

Dit is de regel/code die de fout veroorzaakt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
$class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);
if (class_exists($class_name) ...


Wat Smarty hier doet is het volgende.

Ten eerste is het nodig de template te weten. In het kort is het dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<div>{translate}Vertaal dit naar het engels{/translate}</div>


Bij het parsen van de template ziet hij die {translate} en probeert éérst op de plek van de PHP code die ik aanwijs te achterhalen of er een SMARTY class van bestaat. Nu, die bestaat niet, want het is mijn eigen custom plugin.

Omdat de class niet bestaat, moet ie door met andere mogelijkheden, waaronder dus kijken of {translate} een plugin is. Maar daar komt ie niet.

class_exists()
Wat doet deze method? Die zegt ten eerste natuurlijk of de class bestaat. Bestaat ie niet, dan vuurt ie de autoload af om te zien of de class nadat de autoload is afgevuurd wél bestaat. En dáár gaat het mis. De autoload afvuren lukt niet waardoor hij hangt.

Maar waarom? Ik weet het niet. Ik heb dit al eerder gezien. Als ik een bestand in de root van de applicatie doe en een class_exists() uitvoer dan is er geen probleem. Maar staat het bestand in zeg maar /modules/orders/module.php, dan werkt het niet. Dan klapt ie eruit met een wit scherm. Ik heb dat destijds opgelost met een workaround, omdat de code van de applicatie zelf was. Maar nu is het van Smarty, een 3e partij, dus kan ik die code niet aanpassen.

Het is nu dus tijd om dat witte scherm na een class_exists() goed op te lossen. Maar waar ligt het aan? Ik weet dat het én op de server zelf gebeurt, maar ook op mijn lokale machine én ook op de lokale machine van een externe developer collega die ik heb ingehuurd.

Iedereen bedankt zover en bedankt voor het meedenken in het oplossen van de class_exists.
 
Ozzie PHP

Ozzie PHP

31/05/2022 15:03:27
Quote Anchor link
Maarten Baars op 31/05/2022 14:43:54:
Dit is de regel/code die de fout veroorzaakt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
$class_name = 'Smarty_Internal_Compile_' . implode('_', $_tag);
if (class_exists($class_name) ...

Dat zijn 2 regels :-) Ik kan je uitleg niet exact volgen, maar dat komt omdat ik de code niet bij de hand heb.

Doe eens:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php

$class_name
= 'Smarty_Internal_Compile_' . implode('_', $_tag);
var_dump($class_name);exit;

?>

Wat zie je nu?
 
Maarten Baars

Maarten Baars

31/05/2022 15:06:30
Quote Anchor link
Hij voert dit uit:


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
class_exists('Smarty_Internal_Compile_Translate');


Die class bestaat niet, want het is een plugin.
class_exists() voert dan een autoload uit en op het moment dat ie de autoload uitvoert hangt ie.
 
Ozzie PHP

Ozzie PHP

31/05/2022 15:08:27
Quote Anchor link
Wie voert de autoload uit? :-)

Heb je daar een eigen functie voor?
 
Maarten Baars

Maarten Baars

31/05/2022 15:12:08
Quote Anchor link
Quote:
Wie voert de autoload uit?

PHP8.1 zelf. Zo werkt class_exists() by default.
1. Class zoeken
2. Class niet gevonden?
3. Autoload!
4. Class nu wel gevonden?

Je kunt dat omzeilen door dit te doen:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
class_exists('classname', false);


Dan voert hij de autoload niet uit en kan in mijn geval de code wel door.

Maar zoals gezegd, dat kan ik niet, want dan pas ik 3rdparty code aan.

Quote:
Heb je daar een eigen functie voor?

Jep. Maar dat bereikt ie niet. Als ik daar een die() of exit() in zet zie ik 'm niet.
Gewijzigd op 31/05/2022 15:12:49 door Maarten Baars
 
Ozzie PHP

Ozzie PHP

31/05/2022 15:14:48
Quote Anchor link
Dus het enige probleem is dat ie een class niet kan laden, en die class is jouw eigen class? Begrijp ik het zo goed?
 
Maarten Baars

Maarten Baars

31/05/2022 15:22:00
Quote Anchor link
Bijna.

De class "Smarty_Internal_Compile_Translate" bestaat niet en dat is terecht. {translate} is een plugin die je toevoegt met

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
$smarty->registerPlugin('block', 'translate', 'smarty_waf_translate');


Als je dan in je template toevoegt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
<div>{translate}Vertaal dit{/translate}</div>


...dan moet ie de function 'smarty_waf_translate' uitvoeren. Dat weet ie, omdat je dat bij registerPlugin in de tweede parameter hebt toegekend aan de {translate} tag.

Smarty controleert echter eerst of er een betreffende class bestaat.
Bestaat die niet, dan gaat ie door met de rest van de code, waaronder kijken of het een plugin betreft zodat ie de 'smarty_waf_translate' function kan uitvoeren.

Maar dat is in feite niet van belang bij het oplossen van dit probleem. Het probleem is dat als je een class_exists uitvoert op een class die niet bestaat dan hangt de hele applicatie en doet ie verder niks meer. Je moet dan natuurlijk gewoon wel verder kunnen, al doe je class_exists('belachelijkeclassdienietbestaat'), dan moet je geen wit scherm krijgen.

Ik zoek dus een oplossing om class_exists() by default te laten werken. Dus dat ie blijft werken als ie de autoload ook afvuurt.
 

Pagina: 1 2 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.