[PHP] template vullen met str_replace vertoont kuren

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik heb een heleboel code, met een hoop afhankelijkheden. Ik heb een probleem en hoop dat ik hier de goede code online zet om jullie het probleem uit te kunnen leggen.

In de code van mijn CMS'je bouw vul ik gaandeweg een aantal variabelen: $body, $trail, $footer, etc. met de betreffende html.

Onderaan de code (in de laatste include file), trek ik een template bestand uit de database, welke gevuld is met tokens als {body}, {trail}, etc.

Je snapt, ik vervang deze {tokens} door de betreffende $variabelen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  $result   = db_query('SELECT main FROM templates WHERE tid = %s', $id);
  $temp = db_result($result, 0);

  $tags = array(
                '{login}',
                '{header}', 
                '{tagline}', 
                '{menu}', 
                '{footer}', 
                '{body}', 
                '{trail}'
               );
  
  $repl = array(
                $login,
                $header, 
                setting_get('title', 'title'), 
                $menu, 
                setting_get('footer', 'footer'), 
                $body, 
                $trail
               );
  
  $html = str_replace($tags, $repl, $temp);

En $html echo ik vervolgens naar die client. Dat is de enige echo dit ik in alle code uitvoer. Een voorbeeld van een template bestandje is
HTML:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<html>
<head><title>{title}</title>
{header}
</head>
<body>
<table border="1" width="100%">
<tr>
  <td colspan="2">{trail}</td>
</tr>
<tr>
  <td valign="top" width="30%">{menu}</td>
  <td valign="top" width="70%">{body}</td>
</tr>
<tr>
  <td colspan="2">{footer} : {login}</td>
</tr>
</table>
</body>
</html>


De variabele $body wordt gevuld met een artikel dat ik uit een database trek. De $body variabele wordt gevuld lang voordat deze template acties plaatsvinden.

Als ik een artikel aanmaak met daar in de volgende string: "{login}, {header}, {menu}", dan wordt hier niets mee gedaan. Logisch, want ik vervang ze alleen in de template, welke uit een heel andere tabel komt.

Nu het bizarre: als $body de string "{trail}" bevat, wordt deze wel vervangen door de inhoud van $trail! Na enig uitzoeken blijkt dat dit altijd gebeurt voor het laatste element in de array hierboven. Met andere woorden als ik het volgende script run:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  $result   = db_query('SELECT main FROM templates WHERE tid = %s', $id);
  $temp = db_result($result, 0);

  $tags = array(
                '{trail}',  //<--- trail en login omgedraaid!
                '{header}', 
                '{tagline}', 
                '{menu}', 
                '{footer}', 
                '{body}', 
                '{login}'
               );
  
  $repl = array(
                $trail,
                $header, 
                setting_get('title', 'title'), 
                $menu, 
                setting_get('footer', 'footer'), 
                $body, 
                $login
               );
  
  $html = str_replace($tags, $repl, $temp);

en de $body variabele is onder andere gevuld met de string "{trail}", dan laat hij dat weer gewoon staan. Maar als ik in dit geval ergens in $body de string "{login}" heb staan, vervangt hij deze weer door de inhoud van $login. Met andere woorden: hij laat alle {tokens} in $body (of $footer of wat dan ook) keurig met rust, behalve de token die als laatste in de array staat.

Heeft iemand enig idee hoe dit kan? Ikzelf niet meer namelijk :'(

[ Voor 12% gewijzigd door Reveller op 08-08-2004 01:23 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 15:29

crisp

Devver

Pixelated

eenvoudig voorbeeld:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$trail = 'dit is de trail';
$body = 'dit is de body met een {trail}';

$temp = '{trail} en {body}';

$tags = array(
        '{trail}',
        '{body}'
    );
$repl = array(
        $trail,
        $body
    );

$html = str_replace($tags, $repl, $temp);

echo $html;

{trail} is al vervangen voordat {body} vervangen wordt - de {trail} daarin wordt dus niet meer meegenomen; draai je het om:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$trail = 'dit is de trail';
$body = 'dit is de body met een {trail}';

$temp = '{trail} en {body}';

$tags = array(
        '{body}',
        '{trail}'
    );
$repl = array(
        $body,
        $trail
    );

$html = str_replace($tags, $repl, $temp);

echo $html;

dan krijg je dus logischerwijs ook een ander resultaat.

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Kuhlie
  • Registratie: December 2002
  • Niet online
Een redelijk eenvoudige manier om dit te voorkomen is om net voordat je het vervangen start, de tags van de template te vergroten met randomtekens net zolang tot die tag niet meer voorkomt in de content.

Heb je dus een template:

"{Body} en {Trail}"

en merkt je code dat er in de content van Body toevallig het woord "{Trail}" voorkomt, dan vervang je in de template het woord {Trail} door {Trail347}.

Wel smerig :)