Zusammenspiel php/JS bei Parameterübergabe von php zur JS Funktion
Andreas
- javascript
- php
Hallo Forum,
gibt es einen ganz sicheren Weg, aus php heraus Strings so zu escapen, dass mein javascript nicht wegen Sonderzeichen den "Scriptbetrieb" einstellt, ich die den String mit den escapeten Zeichen dann aber per JS wieder in den Ursprungstext zurück versetzen kann, um ihn in einem Formular zu verwenden?
Beispiel:
echo ("
<INPUT TYPE=submit VALUE=\"test\" onclick=\"einsetzen(`".aus_php_escape($bemerkung)."`)\">
");
function einsetzen(wert) {
document.myform.myInputField.value = in_javascript_unescape(wert);
}
Ich dachte eigentlich, man könnte das vielleicht mit json_encode()/JSON.parse() machen, aber das schlug bei mir fehl.
Andreas
Hallo Andreas,
nicht abschalten, ich gehe jetzt scheinbar auf eine Tangente, aber ich denke, dass es relevant für Dich ist. Deine eigentliche Frage mag beantwortbar sein, aber ich glaube, dass eine mögliche Lösung viele versteckte Komplexitäten besitzt und nicht der ideale Weg ist.
<input type="submit"> ist ein Submit-Button, d.h. das Formular wird zum Server gesendet. Diesem Button gibst Du einen click-Handler, der einem anderen input-Feld einen Wert zuweist. Da Du das Defaultverhalten des Buttons nicht abstellst, wird der Submit danach ausgeführt und der zugewiesene Wert geht sofort zum Server.
Das ganze ergibt nur dann einen Sinn, wenn Du mehr als einen Submit-Button hast. Ist das so?
Die eigentliche Frage, die ich mir stelle, ist, ob Du hierfür überhaupt clientseitig etwas tun musst. Wenn Du möchtest, dass beim Klick auf einen bestimmten Submit-Button ein bestimmtes Datenelement auf einen vorgegebenen Wert gesetzt wird, dann gib dem Submit-Button einen passenden name und value, frage serverseitig ab, ob das gePOSTet wurde (sprich: ob das Formular mit diesem Button abgeschickt wurde) und setze dann den gewünschten Vorgabewert serverseitig.
Wenn das nicht geht, d.h. wenn Du beim POST nicht mehr weißt, was im vorigen Request als $bemerkung ermittelt wurde, gibt es zwei Alternativen ohne JavaScript
Und wenn Du UNBEDINGT den Bemerkungstext im Submit-Button speichern willst, dann würde ich zu einem data-Attribut raten, um das PHP/JS Escaping zu vermeiden. Bei der Gelegenheit würde ich dann auch gleich von einem <input type="submit"> zu einem Button-Element wechseln. Ohne type-Attribut ist <button> automatisch ein Submit-Button. Vorteil von Button ist, dass angezeigter Text und Inhalt des value-Attributs nicht gleich sein müssen. Und das macht man in PHP dann auch nicht mit ECHO, sondern mit vorübergehendem Verlassen des PHP Modus - je nach Editor führt das zu deutlich erfreulicherem Syntaxhighlighting. Dann musst Du auch nicht jedes " escapen.
...PHP-Code...
?>
<button data-remark="<?= htmlspecialchars($bemerkung) ?>"
onclick="einsetzen(this)">Absenden mit Bemerkung</button>
<?php
...mehr PHP Code...
Natürlich muss man nicht für jedes HTML Element umschalten. In vielen Fällen kann man große Teile des Formulars im HTML-Modus ausgeben und nur gelegentlich mit dem Short Echo Tag <?= ?>
aus PHP benötigte Variablenwerte abrufen.
Die Einsetzen-Funktion im JS-Teil sieht dann so aus:
function einsetzen(button) {
document.myform.myInputField.value = button.dataset.remark;
}
Beim Auswerten eines on...-Attributs enthält this
das HTML-Elementobjekt, für das das Event gefeuert wird. Dieses this
übergebe ich an die einsetzen
-Funktion und nehme es im Parameter button
entgegen. Die dataset-Eigenschaft des Elementobjekts zum Button enthält die Werte aller data-Attribute.
Etwas, was Du Dir auch anschauen solltest, ist Unobtrusive JavaScript (unaufdringliches JavaScript). Die on-Attribute vermeidet man heute eigentlich, statt dessen registriert man im Script den Eventhandler mit addEventListener
Rolf
Hallo Rolf,
ja, das ist tatsächlich Uralt-Code, den ich mal neu aufräumen sollte.
Zu Deiner Frage: ja, es gibt ien Vielzahl dieser Buttons.
Eventhandler zu nutzen und die Werte per data-Attribut weitergeben, ok, das kann ich machen.
Für mich bleibt abe die Frage dennoch offen, wie ich mit Sonderzeichen in den Werten umgehe.
Weil die mir bisher immer wieder das JS zerschossen haben, was die Funktion (einsetzen der Werte in ein Formular) verhindert hat.
Die werte über einen Request und somit den Server ins Formular einzusetzen, würde ich deshalb gerne vermeiden, weil jeder Request bei schlechtem Netz (und das kann ich dieser Anwendung leider so sein) nicht optimal ist.
Da aber nur das halbe Formular ausgefüllt wird und der Rest dann manuell ausgefüllt werden soll, bietet sich die clientseitige Löung an.
Gruß, Andreas
Hallo Andreas,
Für mich bleibt abe die Frage dennoch offen, wie ich mit Sonderzeichen in den Werten umgehe.
Wenn Du mit htmlspecialchars ein data-Attribut erzeugst, dann SOLLTE das Problem gelöst sein. Solange Du der Funktion kein ENT_NOQUOTES mitgibst, ersetzt sie " durch " sowie < und > durch < und >, der Rest kann unbesehen in Attribute reingeschmissen werden. Hoffe ich jedenfalls, was bei Zeilenumbrüchen passiert, muss man gucken. Hast Du Zeilenumbrüche drin?
Update: Zeilenumbrüche in einem Attributwert sind unproblematisch, gerade probiert.
Rolf
Hallo Rolf,
na ok, dann probiere ich es mal aus.
Das onclick war mir auch schon ein Dorn im Auge.
Also dann jetzt mit Eventhandler, data-Attributen und htmlspecialchars.
Danke für Deine Hilfe, ich melde mich ggf. nochm al zurück, falls es doch Probleme gibt.
Andreas
@@Andreas
echo (" <INPUT TYPE=submit VALUE=\"test\" onclick=\"einsetzen(`".aus_php_escape($bemerkung)."`)\"> ");
Zunächst einmal: echo
ist keine Funktion, d.h. die (äußeren) Klammern sind überflüssig.
Das Escapen von Anführungszeichen macht den Code schlecht lesbar und ist unnötig, wenn man einfache und doppelte Anführungszeichen verwendet.
I.d.R. sollte man Markup aber gar nicht mit echo
ausgeben, sondern nur das, was wirklich dynamisch ist:
<input
type="submit"
value="test"
onclick="einsetzen(<?= aus_php_escape($bemerkung) ?>)"
>
Jolan tru
Hallo Gunnar,
Das Escapen von Anführungszeichen macht den Code schlecht lesbar und ist unnötig, wenn man einfache und doppelte Anführungszeichen verwendet.
Das ist Gewohnheitssache.
I.d.R. sollte man Markup aber gar nicht mit
echo
ausgeben, sondern nur das, was wirklich dynamisch ist:<input type="submit" value="test" onclick="einsetzen(<?= aus_php_escape($bemerkung) ?>)" >
Denn genau das ist für mich nahezu unlesbar. Einfach Gewohnheitssache.
Trotzdem danke für die Hinweise.
Andreas
Hallo Andreas,
Gewohnheitssache
"Ich bin das so gewöhnt" und "So ist es gut" sind Merkmale auf orthonalen Achsen (=hat miteinander nichts zu tun). Ja, du hast Uraltcode und der wird vermutlich eine ECHO-Wüste sein. Und es ist sicherlich nicht einfach, zwei Codestyles parallel zu führen.
Es ist für den Programmierer deutlich komplexer, HTML mit echo zusammenzubauen und dabei auf jedes Anführungszeichen einzeln aufpassen zu müssen, als den PHP Mode zu verlassen, das HTML einfach hinzuschreiben und nur bedarfsweise PHP Daten hinzuzufügen.
An <?= $foo ?> kann man sich auch gewöhnen. Vor allem, wenn man einen Editor verwendet, der ein PHP/HTML/CSS/JS-Gemisch sauber highlighten kann. Z.B. Visual Studio Code mit der Extension PHP Intelephense.
Welchen Editor verwendest Du, dass sich der Nutzen von Gunnars Empfehlung (die ich Dir übrigens auch gab) nicht aufdrängt?
Rolf
Lieber Andreas,
dass mein javascript nicht wegen Sonderzeichen den "Scriptbetrieb" einstellt,
ist das ein Problem mit der Kodierung, also Sonderzeichen im Sinne von ÄÖÜß usw., oder von passenden Anführungszeichen (doppelte und einfache)?
echo (" <INPUT TYPE=submit VALUE=\"test\" onclick=\"einsetzen(`".aus_php_escape($bemerkung)."`)\"> ");
Das sieht einfach falsch aus, wie Dir meine Vorposter auch schon zu verstehen gegeben haben. Warum kannst Du den Wert nicht so notieren, dass er von JavaScript ohne zusätzliches Escaping verwendet werden kann? Ist das der Kern Deiner Frage?
Beim Programmieren müssen wir beachten, wenn es Kontextwechsel gibt. Dich interessiert vor allem der Zusammenhang Programmcode und Daten.
Dein Beispiel oben forme ich ein Bisschen um:
printf(
'<button name="irgendwas" value="test" onclick="einsetzen(\'%s\')">',
htmlspecialchars($bemerkung)
);
Der Inhalt von $bemerkung
sollte nun für JavaScript direkt lesbar sein. Der Platzhalter %s
wird mit dem Rückgabewert der Funktion htmlspecialchars()
befüllt, die den Wert von $bemerkung
entsprechend verarbeitet.
Wenn Du nur einen quick fix gesucht hast, dann so weit so schlecht. Besser wäre, was Dir meine Vorposter auch schon empfohlen haben, dass Du den Wert in ein passendes data-*
-Attribut schreibst, weil dann die doppelte Maskierung mit den Anführungszeichen nicht sein muss:
printf('
<input
data-nimmdas="%s"
name="irgendwas"
value="test"
onclick="einsetzen(this.dataset.nimmdas)"
>
',
htmlspecialchars($bemerkung)
);
Es stellt sich aber allen Ernstes die Frage, warum diese Sache mit JavaScript in dieser Form überhaupt sein muss. Das riecht sehr stark danach, dass man sich das wesentlich erleichtern kann, indem man das JavaScript allgemeiner baut und z.B. mit data-Attributen die Verarbeitung durch JavaScript steuert:
printf('
<input
data-nimmdas="%s"
data-zielfeld="irgendwas-anderes"
name="irgendwas"
value="test"
>
',
htmlspecialchars($bemerkung)
);
const myForm = document.querySelector("form"); // eventuell eine ID verwenden?
form.addEventListener("click", event => {
if (event.target.tagName
&& "BUTTON" == event.target.tagName
&& event.target.hasAttribute("data-nimmdas")
&& event.target.hasAttribute("data-zielfeld")
) {
const button = event.target;
const zielfeld = form.querySelector('[name="' + button.dataset.zielfeld + '"]');
// input feld vorbelegen
if (zielfeld) {
zielfeld.value = button.dataset.nimmdas;
}
}
});
Aber dazu müsstest Du ein echtes Beispiel zeigen, gerne mit Fake-Daten, bei dem man die tatsächliche Mechanik verstehen kann.
Liebe Grüße
Felix Riesterer