lorderich
Goto Top

PHP Variable in String finden und ersetzen

Hallo zusammen,

da eval() sowohl aus Sicherheitsgründen als auch aus Performancegründen keine Option zu sein scheint, würde ich gern ein Problem wie folgt lösen:

Es gibt einen String, der in der Datenbank samt PHP Variablen gespeichert ist. Wenn ich diesen nun wieder aus der DB auslese und per Echo ausgebe, werden nachvollziehbarer Weise die Variablen als String interpretiert. Lässt sich theoretisch mit eval () lösen, jedoch kostet das eine Menge Zeit.

Als andere Alternative gilt das arbeiten mit str_replace.

Jetzt würde ich das gern von der Logik her wie folgt auflösen:

1. Suche einen String nach einem Text mit dem Muster $Variablenname ab.
2. str_replace ($Variablenname, $Variablenname, $Text)

Allerdings stellt sich mir die Frage, ob es nicht einen besseren Weg gibt, als alle möglichen Variablen die in den Strings vorkommen können als array zu führen, sondern einfach in den jeweiligen Strings danach suchen zu lassen.

Ja, an könnte natürlich auch Platzhalter in die Datenbank schreiben und diese dann mittels "str_replace" durch die dazugehörende Variable ersetzen, ist aus meiner Sicht allerdings einfach mehr Code für das gleiche Ergebnis.

Habt ihr da eine Idee.

PS: Die Variablennamen sind natürlich mit unterschiedliche Länge vorhanden.

Danke und Grüße

René

Content-ID: 374034

Url: https://administrator.de/contentid/374034

Ausgedruckt am: 22.11.2024 um 04:11 Uhr

Arano
Arano 16.05.2018 um 09:55:50 Uhr
Goto Top
Hallo.

Wie wäre es mit preg_recplace-callback() - PHP-Manual
Mit einem RegEx nach möglichen Variablen suchen ala "\$[a-zA-Z_-]+" und in der Callback-Funktion überprüfen ob diese gefundene Variable tatsächlich existieret/einenWertHat oder sie in einem Whitelist-Array steht und dann ersetzen oder nicht.

~Arano
Thomas2
Thomas2 16.05.2018 um 12:05:01 Uhr
Goto Top
Hi,

rein aus Interesse, warum macht man sowas?

Gruß,
Thomas
Pedant
Pedant 16.05.2018 um 12:14:05 Uhr
Goto Top
Hallo René,

Zitat von @Lorderich:
Es gibt einen String, der in der Datenbank samt PHP Variablen gespeichert ist. Wenn ich diesen nun wieder aus der DB auslese und per Echo ausgebe, werden nachvollziehbarer Weise die Variablen als String interpretiert.
Gib uns bitte mal ein Beispiel wie "String samt Variablen" in der DB aussieht damit das tatsächlich nachvollziehbar wird.

Gruß Frank
manuel-r
manuel-r 16.05.2018 um 12:28:57 Uhr
Goto Top
Mahlzeit face-wink

Hab ich richtig verstanden? Du hast einen String nach dem Schema var1=inhalt1&var2=inhalt2&var3=inhalt3 und hättest im weiteren Verlauf des Scripts gerne die Variablen so, als wären Sie direkt per GET übergeben worden. Dann sollte parse_str() eigentlich das machen was du willst.

Manuel
Pedant
Pedant 16.05.2018 um 14:52:24 Uhr
Goto Top
Hallo Manuel,

parse_str() kann ich bisher nicht. Danke für den Hinweis und den Link.

Bei dem von Dir genannten Beispiel wäre ich bisher in dieser Art vorgegangen:
<?php

// Vorgabe
$zeichenfolge = "var1=inhalt1&var2=inhalt2&var3=inhalt3";  

// Am &-Zeichen auftrennen
$paare = explode("&", $zeichenfolge);  

foreach($paare AS $paar)
	{
	// Am =-Zeichen auftrennen
	$paarteile = explode("=", $paar);  
	// optionale Ausgabe zur Kontrolle
	// echo $paarteile . " = " . $paarteile[1] . "<br>\n"; 
	// Zuweisung von Wert zu variablem Variablenname
	$$paarteile = $paarteile[1];
	};

// Ergebnisausgabe zur Kontrolle
echo "Ermittelte Variablen und ihre Werte:<br>\n";  
echo "var1: " . $var1 . "<br>\n";  
echo "var2: " . $var2 . "<br>\n";  
echo "var3: " . $var3 . "<br>\n";  
?>

Der Fokus liegt hier auf der Syntax von Zeile 16 (Zuweisung per $$).

Ausgabe
Ermittelte Variablen und ihre Werte:
var1: inhalt1
var2: inhalt2
var3: inhalt3

Gruß Frank
bloodstix
bloodstix 16.05.2018 um 14:59:06 Uhr
Goto Top
Du könntest einen Template-Parser wie twig dafür nutzen. Dann brauchst du nicht selber str_replace-Code schreiben sondern in der DB Templates ablegen und die dann mit twig unter dreingabe der Variablenwerte rendern lassen.
manuel-r
manuel-r 16.05.2018 um 15:03:31 Uhr
Goto Top
Bei dem von Dir genannten Beispiel wäre ich bisher in dieser Art vorgegangen

Mit parse_str() sieht das dann so aus:
<?php
	$zeichenfolge = "var1=inhalt1&var2=inhalt2&var3=inhalt3";  
	parse_str($zeichenfolge);
	if (isset($var1)) {
		echo $var1 . "<br>\n";  
	}
	if (isset($var2)) {
		echo $var2 . "<br>\n";  
	}
	if (isset($var3)) {
		echo $var3 . "<br>\n";  
	}
?>

Als Ausgabe erhälst du damit
inhalt1
inhalt2
inhalt3

Manuel
Lorderich
Lorderich 16.05.2018 um 15:38:08 Uhr
Goto Top
Hallo zusammen,

also ein Beispiel aus der DB sieht z.B. so aus:

<div class='panel-heading'><h1>Vielen Dank für deine Registrierung.</h1></div><div class='panel-body'>Deine Mitgliedsnummer ist: <span class='success'>“. $ID.“ </span> und Du wurdest <span class='success'> mit den ausgewählten Rollen</span> registriert!<p><p></div>

Das Problem ist ja, dass ohne eval die PHP Variablen wie Text ausgegeben werden.

Ohne eval() sieht der Text dann so aus:
Vielen Dank für deine Registrierung. Deine Mitgliedsnummer ist: $ID und Du wurdest mit den ausgewählten Rollen registriert!

Allerdings ist die Variable definiert und auch im entsprechenden Geltungsbereich verfügbar, sodass im Ziel folgendes herauskommen soll:
Vielen Dank für deine Registrierung. Deine Mitgliedsnummer ist: 12 und Du wurdest mit den ausgewählten Rollen registriert!

Man könnte jetzt aus meiner Sicht mehrere Möglichkeiten zur Lösung ohne eval() bauen.

1. Suche den String nach einer "Variablen ab", str_replace ($Variablennamen, $Variablenname, $string).
2. Variante 2, wäre den String mit eval() so zu parsen, dass der entsprechende Variableninhalt ausgegeben wird.

Danke und Grüße

René
Pedant
Pedant 16.05.2018 um 16:22:50 Uhr
Goto Top
Hallo René,

ich sehe keinen Grund nicht str_replace einzusetzen.
Was Du aber bei 1. mit "Variablen ab" meinst ist unklar.
Hast Du die Anführungszeichen falsch gesetzt?

Was Du damit meinst ist auch unklar:
$Variablennamen, $Variablenname, $string

  • $Variablennamen (Mehrzahl) ?
  • $Variablenname (Einzahlzahl) ?

Die Syntax für str_replace ist diese hier:
str_replace ($suchfolge, $ersatzfolge, $quellfolge)

Dein Code könnte dann so aussehen:
$string = "<div class='panel-heading'><h1>Vielen Dank für deine Registrierung.</h1></div><div class='panel-body'>Deine Mitgliedsnummer ist: <span class='success'>“. $ID.“ </span> und Du wurdest <span class='success'> mit den ausgewählten Rollen</span> registriert!<p><p></div>"  

$string = str_replace ("$ID", $ID, $string);  
Zuvor musst Du die Variable namens ID noch irgendwie mit dem Wert 12 belegen.
Ich gehe davon aus, dass die 12 auch irgendwo in der DB steht und Du mit einer entsprechenden Abfrage dynamisch $ID = "12"; setzen kannst.

Gruß Frank
Lorderich
Lorderich 16.05.2018 um 16:32:04 Uhr
Goto Top
Ich suche einen eher allgemeineren Weg für das ersetzen.

In diesem Beispiel müsste ich ja immer wenn eine Variable in einem DB Eintrag vorkommt, die entsprechende str_replace Anweisung manuell schreiben.
$string = str_replace ("$ID", $ID, $string);

Mein gedanklicher Ansatz, an dem ich gerade hänge ist ja folgender:

Schaue nach, ob irgendwo in dem gegebenen String ein oder mehrere "Variablen" mit folgenden Aufbau sind:
$Variablenname

Wenn ja, dann bau das str_replace zusammen aus
$string = ("$Variablenname", $Variablenname, $string)
Pedant
Pedant 16.05.2018 um 17:09:58 Uhr
Goto Top
Hallo René,

Zitat von @Lorderich:
Ich suche einen eher allgemeineren Weg für das ersetzen.
...
Wenn ja, dann bau das str_replace zusammen aus
$string = ("$Variablenname", $Variablenname, $string)
...dann schreib das doch bitte auch gleich.

Eine Lösung wäre dann relativ umständlich und/oder eventuell fehleranfällig.

Es müsste dabei eindeutig definierbar sein wo eine Variable anfängt und wo sie auffhört.
Das $-Zeichen dürfte beispielsweise nie Teil des Ausgangstextes sein, ausser wenn es tatsächlich den Beginn einer auszuwertenden Variablen kennzeichnet.
Ebenso darf das $-Zeichen nicht Inhalt einer Variabel sein, damit Du es Dir nicht beim Ersetzen in den Text einfügst.

Hier etwas Pseudocode, der je nach erforderlichen Fallunterscheidungen beliebig komplex werden kann.:
While (pos von "$" >= 0 in $string)  
{
$anfang = pos von "$"  
$ende = pos von "." oder " " oder ...  
$Variabelname = teilstring (von $anfang, bis $ende, aus $string)
$string =  ("$Variablenname", $Variablenname, $string)  
};

Gruß Frank
136166
136166 16.05.2018 aktualisiert um 19:05:44 Uhr
Goto Top
Ich suche einen eher allgemeineren Weg für das ersetzen.
Na dann:
// variables
$var1 = "Max";  
$var2 = "Ball";  
$var3 = "blauen";  

// replace function 
function ReplaceVariablesInString($str){
	// search all variables in string
	if ($result = preg_match_all('/\$([a-z_\x7f-\xff][a-z0-9_\x7f-\xff]*)/i',$str,$matches,PREG_SET_ORDER)){  
		// itterate over all vars
		foreach($matches as $match){
			// replace variables with content
			$str = preg_replace('/' . preg_quote($match) .'/',$GLOBALS[$match[1]],$str);  
		}
	}
	//return new string
	return $str;
}
// original string
$stringFromDB = 'Hallo mein Name ist $var1 und ich habe einen $var3 $var2.';  
// replaced string
echo ReplaceVariablesInString($stringFromDB);

Zitat von @Pedant:
Eine Lösung wäre dann relativ umständlich und/oder eventuell fehleranfällig.
face-smile.
Es müsste dabei eindeutig definierbar sein wo eine Variable anfängt und wo sie auffhört.
Das ist definiert, einfacher Regex genügt face-smile. => http://php.net/manual/de/language.variables.basics.php
Arano
Arano 16.05.2018 um 20:05:18 Uhr
Goto Top
Nabend.

Kinners...

<?php

$gVar1="Hallo";  
$gVar2="ich";  
$gVarX="UNUSED";  
$gVar14="Arano";  

$strFromDBOrig='$gVar1, $gVar2 kenne meinen Namen: $gVar14<br>und hier eine falsche: $Bazinga';  
$strFromDBManip=preg_replace_callback( '/\$([a-zA-Z0-9-_]+)/', 'cb_replace_if_exist', $strFromDBOrig );  

echo $strFromDBOrig;
echo "<br><br>";  
echo $strFromDBManip;

function cb_replace_if_exist( $inp )
{
	if( isset( $GLOBALS[$inp[1]] ) )
		return $GLOBALS[$inp[1]];
	
	// Error handling
	return ' ### Unknown Variable: $'.$inp[1].' ### ';  
	# Ein `trigger_error()` könnte man auch nehmen oder
	# return '';   # nichts 
}
?>
Und die Passende Ausgabe dieses:
$gVar1, $gVar2 kenne meinen Namen: $gVar14
und hier eine falsche: $Bazinga

Hallo, ich kenne meinen Namen: Arano
und hier eine falsche: ### Unknown Variable: $Bazinga ### 

Die Handbuchseite zu preg_replace_callback ist in der ersten Antwort verlinkt ;)


~Arano
Pedant
Pedant 16.05.2018 um 21:48:08 Uhr
Goto Top
@Kabelbruch,

Zitat von @136166:
Es müsste dabei eindeutig definierbar sein wo eine Variable anfängt und wo sie auffhört.
Das ist definiert, einfacher Regex genügt face-smile. => http://php.net/manual/de/language.variables.basics.php
Der Punkt geht an Dich.

Zitat von @136166:
Zitat von @Pedant:
Eine Lösung wäre dann relativ umständlich und/oder eventuell fehleranfällig.
face-smile.
...bezogen auf die Lösung basierend auf str_replace

Deine Lösung mit preg_replace ist hingegen hübsch und hat auch kein Problem, wenn Variablen ein Dollarzeichen im Wert enthalten, was bei str_replace in While-Schleife zu Problemen führen würde.


@Arano,

Dein Code funktioniert auch wunderbar.

Den Returnwert hattest Du schon wahlfrei angeboten.
Wie wäre es mit diesem Return?
// Error handling
return '$'.$inp[1];
Die Ein- und Ausgabe wären dann diese hier:
$gVar1, $gVar2 kenne meinen Namen: $gVar14 
und hier eine falsche: $Bazinga

Hallo, ich kenne meinen Namen: Arano
und hier eine falsche: $Bazinga
Variablen, die nicht belegt sind erscheinen im Ergebnis unersetzt.
So könnte ich Arano heißen und meinen 1000$anzug tragen.
(... ist etwas konstuiert da es eingentlich Tausenddollaranzug oder 1000-Dollar-Anzug heißen müsste und es ohnehin nur 50-Euro-Hose und T-Shirt sind und ich nicht Arano heiße.)

Gruß Frank
Arano
Arano 16.05.2018 um 22:29:00 Uhr
Goto Top
Hallo,
joar klar, alles machbar und neben der Geschmackssache seinen Kosten-Nutzungs-Faktor hat.
Und natürlich steht es auch jedem frei die Details zu verfeinern/anzupassen
Variablen, die nicht belegt sind erscheinen im Ergebnis unersetzt.
In PHP gibt das immerhin eine Notice: Undefined variable: Bazinga in /srv/vhosts/test/www/lorderich/index.php on line 25 (darum der Hinweis auf trigger_error() )
Darüber hinaus kann es schwer sein einen Tippfehler in der Pseudo-Variable zu finden wenn einem kein Fehler oder Ähnliches angezeigt wird, daher return '### ERROR ###'

1000$anzug
Ja stimmt, hier wird "$anzug" gefunden aber so schreibt das doch auch keiner...1000$ Anzug
Allerdings kann man den RegEx auch dahingehend anpassen,
  • das vor dem $-Zeichen kein Buchstabe/Ziffer stehen darf
  • oder ein Leerzeichen/Tabulator/Zeilenbeginn/Zeilenumbruch davor zu stehen hat was wiederum Verkettungsprobleme mit sich bringt
  • oder kein \-Zeichen davor sein darf Maskierungszeichen
  • oder bestimmen das "&#36;" zu verwenden ist um sicher zu gehen das zwischen Variable-$ und Zeichen-$ differenziert wird !
  • oder , oder, ...


~Arano
Thomas2
Thomas2 17.05.2018 um 07:36:10 Uhr
Goto Top
Hi,

wie wäre es denn, Code und Gestaltung sauber von einander zu trennen? Schreibe anstelle der Variablen Platzhalter rein und diese Platzhalter füllst du dann mit den Werten. Die Template Klasse hast du dir in 10 Minuten selbst geschrieben und macht nichts anderes als Platzhalter mit den Variablenwerten zu füllen. Codemäßig sieht das dann etwa so aus (lange kein PHP mehr geschrieben):

$Webpage = new Template("index.html");  
$Webpage->Parse("MEMBERNAME", $Username);  
$Webpage->Parse("LASTLOGIN", $LastLoginDate);  
echo $Webpage->Show();

Gruß,
Thomas
Arano
Arano 17.05.2018 um 09:01:17 Uhr
Goto Top
Tach

wie wäre es denn, Code und Gestaltung sauber von einander zu trennen?
Hat er doch, darum steht der Text doch auch in der Datenbank.
Es gibt einen String, der in der Datenbank samt PHP Variablen gespeichert ist.

Schreibe anstelle der Variablen Platzhalter rein und diese Platzhalter füllst du dann mit den Werten.
Ist eine Variable kein Platzhalter !? Oder anders: Warum soll "PLATZHALTER" besser sein als "$PLATZHALTER" oder "#PLATZHALTER#" oder "{PLATZHALTER}" oder "$PLATZHALTER$".

Die Template Klasse hast du dir in 10 Minuten selbst geschrieben
Wie du im Verlauf sehen kannst: 09:37-22:29Uhr = 12:52h
Wobei! Eine Templatesystem wirklich praktisch sein kann face-smile

Aus der anderen Seite, kommt der Content hier aus der DB und müsste dennoch geparst werden BEVOR er in das Template eingefügt werden kann...


~Arano
Pedant
Pedant 17.05.2018 um 12:01:20 Uhr
Goto Top
Hallo Arano,

Zitat von @Arano:
...aber so schreibt das doch auch keiner
Ich schrieb ja schon dazu, dass es eingentlich Tausenddollaranzug oder 1000-Dollar-Anzug heißen müsste.
Zitat von @Arano:
1000$ Anzug
Das wirft im Duden eine zweifache Errormeldung aus:
Syntax error: unexpected '' on line 1
Syntax error: missing '-' on line 1

1000-$-Anzug kompiliert ohne Error.
Handbuch: Da es sich um ein Wort handelt, muss es auch als ein Wort geschrieben werden (1000$anzug), aber wegen der Zahl und des $-Zeichens mit Bindestrichen (1000-$-Anzug).

Zitat von @Arano:
Allerdings kann man den RegEx auch dahingehend anpassen,...
Dazu sollte sich der TO äußern. Vielleicht trägt er ja gar keine Anzüge und die Aufgabe wäre ohne weitere Fallunterscheidung erledigt.

Gruß Frank
136166
136166 17.05.2018 aktualisiert um 13:18:20 Uhr
Goto Top
Seht euch doch oben einfach meinen Regex an, der inkludiert nur per Definition gültige Variablen, steht auch in meinem Link.

'/\$([a-z_\x7f-\xff][a-z0-9_\x7f-\xff]*)/i'

Ansonsten einfach einmalige Platzhalter definieren, fertig Affe tot.