PHP Code in externer Datei
WernerK
- javascript
0 dedlfix0 Auge0 hotti0 Camping_RIDER0 Camping_RIDER0 Camping_RIDER1 1UnitedPower0 hotti
Hallo zusammen,
ich hatte im August schon mal etwas ähnliches nachgefragt.
Wenn auf der PHP Seite der JS Code eingebaut ist, dann klappt alles.
Ich suche nun nach eine Möglichkeit, event. den ganzen JS Code in eine externe Datei auszulagern.
Es gibt allerdings ein paar Stellen wo z.b.eine JS Funktion eine PHP Variable benötigt.
Ich habe es mal so versucht:
In der PHP Hauptseite:
<script src="js/anzeige.js.php"></script>
In der anzeige.js.php dann:
<?php
header('Content-Type: application/javascript');
?>
$(document).ready(function(){
..
AnzeigeContent(<?php echo $userid ?>);
..
});
Allerdings kommt es nun zu einem Syntax Error weil die userid nicht übermittelt wird, bzw. die PHP Datei die ja eigentlich eine JS Datei ist, nicht interpretiert wird.
"SyntaxError: syntax error
AnzeigeContent(<br />.."
Wie kann man dies lösen?
Gruss
Werner
Tach!
Allerdings kommt es nun zu einem Syntax Error weil die userid nicht übermittelt wird, bzw. die PHP Datei die ja eigentlich eine JS Datei ist, nicht interpretiert wird.
Wenn das der Fall ist, dann hat dein Webserver keine Lust, aufgrund der Endung php die Datei an PHP weiterzureichen. Wenn er das jedoch für Dateien in übergeordneten Verzeichnissen macht, musst du ihm das ja per .htaccess oder ähnlichem abgewöhnt haben. Aber ...
"SyntaxError: syntax error
AnzeigeContent(<br />.."
... was kommt denn nach dem <br />? Das sieht mir doch eher so aus, als ob da eine PHP-Fehlermeldung steht.
dedlfix.
Danke euch.
Ihr habt mich auf die richtige Spur gebracht.
Nachträglich ist es klar.
In der Startseite wird ganz am Anfang die PHP Variable userid festgelegt.
Ich muss natürlich dann auch die externe PHP/JS Datei diese Variable mitgeben.
Habe es jetzt so gemacht:
<script src="js/anzeige.js.php?userid=<?php echo $userid; ?>"></script>
In der externen Datei dann:
<?php
header('Content-Type: application/javascript');
$userid = $_GET['userid'];
?>
$(document).ready(function(){
..
AnzeigeContent(<?php echo $userid ?>);
..
});
So klappt es dann:
Allerding habe ich mir gerade überlegt, ob ich es nicht ganz anders mache:
in der Hauptseite die userid an ein Cookie übergeben.
setcookie("useridcookie", $userid);
dann kann ich später ganz auf PHP code verzichten und das cookie aufrufen.
Gruss
Werner
Hallo
Allerding habe ich mir gerade überlegt, ob ich es nicht ganz anders mache:
in der Hauptseite die userid an ein Cookie übergeben.setcookie("useridcookie", $userid);
dann kann ich später ganz auf PHP code verzichten und das cookie aufrufen.
Du kannst in der aufzurufenden Seite per PHP auch einen JS-Abschnitt einfügen, der die gewünschten und benötigten Variablen und Infos enthält. Da die ID sowieso per GET übergeben und per JS ausgeliefert wird, vermutei ich dahinter keine sicherheitsrelevante Info, die nicht auch in der Seite stehen dürfte.
Tschö, Auge
Danke euch.
$userid = $_GET['userid'];
in der Hauptseite die userid an ein Cookie übergeben.
Bedenke den Sicherheitsaspekt: Sobald die User-ID über HTTP geschleift wird, ist sie manipulierbar. Das gilt auch für HTTPS, weil sie ab dem Browser (User-Agent) manipulierbar ist.
MfG
Hallo,
Bedenke den Sicherheitsaspekt: Sobald die User-ID über HTTP geschleift wird, ist sie manipulierbar. Das gilt auch für HTTPS, weil sie ab dem Browser (User-Agent) manipulierbar ist.
Danke für den Hinweis:
Was hälst du dann von der Idee, auf der PHP Haupseite die userid in ein hidden Field zu schreiben?
<input type="hidden" name="useridversteckt" id="useridversteckt" value="<?php echo $userid ?>" />
Später könnte man dann in der externen JS Datei per
var userid = document.getElementById('useridversteckt');
auch an die userid kommen.
Dann bräuchte man weder Cookie noch PHP Code.
Gruss
Werner
Hallo,
Bedenke den Sicherheitsaspekt: Sobald die User-ID über HTTP geschleift wird, ist sie manipulierbar. Das gilt auch für HTTPS, weil sie ab dem Browser (User-Agent) manipulierbar ist.
Danke für den Hinweis:
Was hälst du dann von der Idee, auf der PHP Haupseite die userid in ein hidden Field zu schreiben?
Das ist genauso manipulierbar.
Dann bräuchte man weder Cookie noch PHP Code.
Nutze den Cookie, dafür gibt es die. Das Einzige, was damit nach draußen sichtbar ist, ist die Session-ID und alle Daten, die an eine Session gebunden sind (User-ID, Warenkorb ...) kennt nur der serverseitige Prozess.
Gruß vom Krümelmonster :)
Hallo
Wenn auf der PHP Seite der JS Code eingebaut ist, dann klappt alles.
Ich suche nun nach eine Möglichkeit, event. den ganzen JS Code in eine externe Datei auszulagern.Es gibt allerdings ein paar Stellen wo z.b.eine JS Funktion eine PHP Variable benötigt.
Ich habe es mal so versucht:
In der PHP Hauptseite:
<script src="js/anzeige.js.php"></script>In der anzeige.js.php dann:
<?php
header('Content-Type: application/javascript');?>
$(document).ready(function(){
..
AnzeigeContent(<?php echo $userid ?>);
..
});Allerdings kommt es nun zu einem Syntax Error weil die userid nicht übermittelt wird, bzw. die PHP Datei die ja eigentlich eine JS Datei ist, nicht interpretiert wird.
Rufe dir den generierten Code im Browser mal testweise als Text auf. Generiert das PHP-Skript sauberen JavaScript-Code?
"SyntaxError: syntax error
AnzeigeContent(<br />.."
Sieht aus, als ob der Fehler woanders auftreten würde. Im JS-Code sollte doch kein „<br>“ zu finden sein, oder? Um das herauszufinden, reicht der gezeigte Code allerdings nicht. Gibt es einen Link zu der problematischen Seite?
Tschö, Auge
Hallo zusammen,
header('Content-Type: application/javascript');
text/javascript ist der richtige Content-Type.
Wie kann man dies lösen?
Für eine Handvoll Platzhalter sprintf(), da heißen alle Platzhalter %s. Wenns ein bischen mehr sein darf, nutze eine Templateengine.
MfG
Aloha ;)
Neben der schon erfolgreichen Lösung:
Ich frage mich gerade, warum du überhaupt das Javascript per php kreieren lassen willst. Es gibt imho eine einfachere Möglichkeit, php-Variablen an Javascript weiterzugeben. Zumindest wenn dein HTML auch durch php aufgebaut wird.
Dazu gehst du einfach her und hast in deiner HTML-PHP-Datei vor allen andern <script>
ein inline-script, in etwa so:
<script type="text/javascript">
var php = {
userid: '<!php echo $userid; !>',
var2: '<!php echo $var2; !>',
...
varx: '<!php echo $varx; !>'
};
</script>
Dann kannst du in allen eingebundenen JS-Dateien, die danach kommen, auf die von dir benötigten Dateien zugreifen (z.B. über php.userid
oder php['userid']
).
Das macht deine Arbeit imho sehr viel übersichtlicher. Ich liebe PHP für seine Möglichkeiten, versuche es aber spärlich (d.h. in so wenig Dateien wie möglich) einzusetzen, da die Übersichtlichkeit jedes Quelltextes unter php-Einsatz leidet... Außerdem: du hast ja schon selbst gemerkt, dass deine Lösung relativ viel redundanten Code benötigt, wenn du auch in der JS-Datei die Variablen zunächst ableiten musst. Don't repeat yourself. Außerdem benötigt jeder unnötige php-, also Präprozessor-Durchlauf wieder etwas Rechenkapazität und Zeit. Bei großen Projekten rächt sich das schätzungsweise.
Javascript in externen Dateien kann grundsätzlich imho immer statisch hinterlegt werden. Ein Usecase, in dem php-basierte Javascript-Erzeugung notwendig wäre, ist mir nicht bekannt (außer vielleicht um eine JS-Ausgabe per Bedingung an eine Anmeldung etc. zu knüpfen oder Ersetzen statischer Platzhalter-Strings - aber schon bei letzterem ist die eben genannte Variante eleganter...).
Grüße,
RIDER
Aloha ;)
Ein Usecase, in dem php-basierte Javascript-Erzeugung notwendig wäre, ist mir nicht bekannt (außer vielleicht um eine JS-Ausgabe per Bedingung an eine Anmeldung etc. zu knüpfen oder Ersetzen statischer Platzhalter-Strings - aber schon bei letzterem ist die eben genannte Variante eleganter...).
Okay - hotti kennt einen. Aber selbst dann, wenn Sicherheitsaspekte meinen Weg kritisch machen, würde ich eher JS statisch schreiben und bei der Ausgabe einen selbstgeschriebenen php-Loader bemühen (also Aufruf des Scripts etwa über src="loader.php?file=script.js"
), der einzelne Platzhalter ersetzt, anstatt mir den gesamten JS-Quelltext mit PHP zuzubauen ;)
Wenn die mögliche Manipulation / das Auslesen der Daten egal ist (wobei das Auslesen ja auch immer möglich ist, auch beim Platzhalter-Ersetzen und die JS-Manipulation nach dem zur Laufzeit der Seite auch immer möglich ist) halte ich meine Methode immer noch für schöner.
Es ist insgesamt fraglich, bei der Verarbeitung von Daten über Javascript einen Sicherheitsaspekt diskutieren zu wollen. Javascript ist NIE sicher. Vor allem nicht gegenüber Manipulationen.
Grüße,
RIDER
Aloha ;)
Es ist insgesamt fraglich, bei der Verarbeitung von Daten über Javascript einen Sicherheitsaspekt diskutieren zu wollen. Javascript ist NIE sicher. Vor allem nicht gegenüber Manipulationen.
Ich gebs auf, ich sehe den Usecase, es anders als von mir ursprrünglich vorgeschlagen machen zu wollen, offenbar immer noch nicht ;)
Neuer Rekord: Tripelposting :D ich führe Selbstgespräche. Ich sollte das Forum weniger frequentieren.
Grüße,
RIDER
@@Camping_RIDER:
nuqneH
Neuer Rekord: Tripelposting :D ich führe Selbstgespräche.
RIDER hat mit INGRID einen Buchstaben mehr gemein als GUNNAR.
Qapla'
Hallo,
RIDER hat mit INGRID einen Buchstaben mehr gemein als GUNNAR.
ich komme bei beiden auf vier?
Gruß
Kalk
@@Tabellenkalk:
nuqneH
ich komme bei beiden auf vier?
In INGRID ist nur ein N; das zählt nicht doppelt.
Qapla'
Aloha ;)
ich komme bei beiden auf vier?
In INGRID ist nur ein N; das zählt nicht doppelt.
Damit wären wir zwischen GUNNAR und RIDER bei einem Gleichstand von drei ;)
Spannend wirds erst, wenn du meinen vollen Namen ansiehst...
campINGRIDer
Damit hätten wirs: ich darf das, der Name ist Programm :D
Grüße,
RIDER
Hakuna matata!
Wenn die mögliche Manipulation / das Auslesen der Daten egal ist (wobei das Auslesen ja auch immer möglich ist, auch beim Platzhalter-Ersetzen und die JS-Manipulation nach dem zur Laufzeit der Seite auch immer möglich ist) halte ich meine Methode immer noch für schöner.
Du verstehst hotti einfach falsch. Die Sicherheitsbedenken, die er hat, richten sich nicht gegen das clientseitige Auslesen der Daten.
Das Problem ensteht, weil man Daten-Ping-Pong spielt. Der Server schickt dem Client die Nutzer-ID über ein Cookie, beim nächsten Request schickt der Client die Nutzer-ID an den Server zurück. Das selbe gilt für dei hidden-input-Variante: der Server schreibt die Nutzer-ID in ein hidden-input, beim Absenden des Formulars schickt der Client die Nutzer-ID zurück an den Server.
Für den Server besteht in der zweiten Runde keine Gewissheit mehr, dass es sich bei der Nutzer-ID, um die selbe handelt, die er vorher dem Client verraten hat. Der Server sollte sich deshalb nicht darauf verlassen und sollte zum Beispiel keine Authorisierung auf Basis dieses Cookies bauen.
Wenn der Server das Nutzer-ID Cookie immer nur schreibt und niemals liest und davon ausgehend weitere Logik startet, dann ist das Cookie in diesem Fall überhaupt kein sicherheitsrelevantes Problem. Ebensowenig das hidden-input-Feld.
Die JavaScript-Lösung von dir hat mit diesem potenziellen Sicherheitsrisiko sowieso nichts zu tun, weil die Daten nicht an den Server zurück geschickt werden. Es besteht also auch kein Grund zur Panik, dass der Server irgendwelche naiven Schritte unternimmt.
Aloha ;)
Ein Usecase, in dem php-basierte Javascript-Erzeugung notwendig wäre, ist mir nicht bekannt (außer vielleicht um eine JS-Ausgabe per Bedingung an eine Anmeldung etc. zu knüpfen oder Ersetzen statischer Platzhalter-Strings - aber schon bei letzterem ist die eben genannte Variante eleganter...).
Okay - hotti kennt einen. Aber selbst dann, wenn Sicherheitsaspekte meinen Weg kritisch machen, würde ich eher JS statisch schreiben und bei der Ausgabe einen selbstgeschriebenen php-Loader bemühen (also Aufruf des Scripts etwa über
src="loader.php?file=script.js"
), der einzelne Platzhalter ersetzt, anstatt mir den gesamten JS-Quelltext mit PHP zuzubauen ;)
Die Idee hat ja was. Den Header Last-Modified vorweg und die Browser cachen das. Mehrere Parameter laden mehrere JS-Ressourcen.
Was auch geht:
<script type="text/javascript" src="/xjs.js?/jquery.min.js" id="xjs"></script>
Also nicht PHP als Loader sondern eine JS-Datei. Der Hack: In der JS-Datei wird über die id der src ausgelesen und dem entsprechend werden weitere Ressourcen geladen. Einfach gesteuert über in der WebSite-Verwaltung gesetzte Attribute für eine jeweilige Seite.
Und wenn det Janze über Ajax looft, können serverseitig auch Platzhalter innerhaln JS interpoliert werden.
MfG
Hallo
also die Idee von RIDER
<script type="text/javascript">
var php = {
userid: '<!php echo $userid; !>',
var2: '<!php echo $var2; !>',
...
varx: '<!php echo $varx; !>'
};
</script>
versteh ich noch und finde ich auch ganz gut.
Die Sache aber mit dem loader
src="loader.php?file=script.js"
und auch die Info von hotti kapier ich leider nicht mehr wie das gemeint ist und wie man hier PHP Variablen an JS übergeben kann. Aber egal..
Danke trotzdem
Gruss
Werner
Hallo
Die Sache aber mit dem loader
src="loader.php?file=script.js"
und auch die Info von hotti kapier ich leider nicht mehr wie das gemeint ist und wie man hier PHP Variablen an JS übergeben kann. Aber egal..
Prinzip: statt einer statischen JS-Datei wird ein Template über den Loader gezogen. Die JavaScript-Datei also als Template-Datei mit Platzhaltern. Hier kannste dann vom Server her kommend, Variablen einbauen.
Derselbe Vorgang, wie beim Einbau von Platzhaltern in eine HTML-Datei, den Head- oder andere Script-Bereiche. Mit Loader ist es halt explizit nur das JavaScript.
Horst
Aloha ;)
Prinzip: statt einer statischen JS-Datei wird ein Template über den Loader gezogen. Die JavaScript-Datei also als Template-Datei mit Platzhaltern. Hier kannste dann vom Server her kommend, Variablen einbauen.
Derselbe Vorgang, wie beim Einbau von Platzhaltern in eine HTML-Datei, den Head- oder andere Script-Bereiche. Mit Loader ist es halt explizit nur das JavaScript.
Alles richtig soweit. Noch etwas ausführlicher für den TO:
Das Javascript schreibst du ganz normal, wie man eben JS schreibt. Für alle Variablen, die du aus php ziehen willst, schreibst du Platzhalter. Wenn du z.B. die userid willst, könntest du soetwas machen:
var userid = "\*|PHPVAR-userid|\*";
Platzhalter für $userid ist also \|PHPVAR-userid|\
Geschickterweise leitest du Platzhalter ein wie Kommentare, dann kommen Editoren mit Syntax-Highlightning nicht durcheinander und es besteht weniger Verwechslungsgefahr mit richtigen Strings. Ansonsten bist du da aber in der Qual der freien Wahl ;)
Die loader.php macht dann folgendes:
* Alle Variablen, die benötigt werden, definieren bzw. sicherstellen, dass sie sich im Scope von loader.php befinden
* das Javascript, dessen Dateiname dir der GET-Parameter file verrät, in einen String $out laden (hier bitte ganz besonders restriktiv vorgehen, also z.B. nur files mit .js akzeptieren oder von vornherein file ohne Dateiendung ins Get und .js immer dranhängen. Wir wollen ja nicht, dass der Loader zum Freibrief wird, alle Dateien im Klartext auszulesen - sondern eben nur Javascripts)
* in der Variable $out per str_replace alle Platzhalter durch den jeweiligen Variablen-Inhalt ersetzen
* header-content-type festlegen und echo $out;
Vorteile dieser Methode gegenüber dem von mir genannten Ansatz:
if (userid != "\*|PHPVAR-userid|\*") { ...
). Wohlgemerkt: Manipulationen sind noch immer möglich, nur deutlich komplizierter vorzunehmenIm HTML steht dann nur noch (hier wie vorfeschlagen ohne Dateiendung:
<script src="loader.php?file=skript1></script>
<script src="loader.php?file=skript2></script>
Ergebnis ist, dass die Dateien Skript1.js und Skript2.js geladen und mit ordentlich ersertzten Platzhaltern beim client ankommen.
Nachteile:
Gleichbleibender Vorteil ggü. der ursprünglichen Methode
* Javascript ist nicht mit php vermischt (nur mit Platzhaltern, aber das find ich weniger schlimm)
* Übersichtlichkeit der JS-Quelltexte ist gegeben
* du musst die Variablen aus php nicht in jedes einzelne JS extra einbringen, sondern hast eine zentrale Anlaufstelle (dont repeat yourself)
Zuletzt noch eine weitere mögliche Optimierung:
Für große Projekte mit vielen, vielen verschiedenen Platzhaltern ist es evtl. günstig, die Platzhalter so wie von mir vorgeschlagen (oder gleichwertig anders) zu nehmen und die Ersetzungen nicht einzeln per str_replace vorzunehmen, sondern über reguläre Ausdrücke in einer for-Schleife. Die Namen der Variablen innerhalb der Platzhalter kann dann direkt als key der einzusetzenden Variablen im $GLOBALS (oder einem anderen) Array genutzt werden. Sehr effizient, aber zu aufwendig für nur wenige Ersetzungen.
Und noch eine:
Auch dein HTML-erzeugendes PHP nimmt die Variablen irgendwoher. Wenn du diese Stellen auslagern und per include einbinden kannst, kannst du die ausgelagerten Stellen auch in loader.php includieren. Dann ist das don't repeat yourself perfektioniert ;)
Grüße,
RIDER
Aloha ;)
Im HTML steht dann nur noch (hier wie vorfeschlagen ohne Dateiendung:
<script src="loader.php?file=skript1></script>
<script src="loader.php?file=skript2></script>
Mist. Wieder zu ungeduldig. Muss natürlich:
~~~html
<script src="loader.php?file=skript1"></script>
<script src="loader.php?file=skript2"></script>
Grüße,
RIDER
Hakuna matata!
Prinzip: statt einer statischen JS-Datei wird ein Template über den Loader gezogen.
Das sollte man tunlichst vermeiden, auf diese Weise erzeugt man eine unheimliche enge Kopplung zwischen serverseitiger und clientseitiger Logik, die zu unwartbarem Code führt. Zudem hat PHP gar nicht die Werkzeuge, um ordentlichen JavaScript-Code zu erzeugen, es fehlen jegliche Funktionen für die kontextgerechte Kodierung von JavaScript-Code-Fragmenten, von einer programmatischen API zum Erzeugen von JavaScript-Syntax ganz zu schweigen.
Besser ist, man beschränkt sich auf ein vordefiniertes Subset von JavaScript, und da guckt JSON schon um die Ecke. JSON hat zudem den Vorteil, das es unabhängig von einer Programmiersprache ist (auch wenn der Name das nicht vermuten lässt). Jede ernstzunehmende Programmierumgebung bietet JSON-Unterstützung an.
Außerdem ist die Lösung viel simpler gestrickt, ein knappes Beispiel:
json_api.php
<?php
header('Content-Type: application/json');
echo [link:http://de2.php.net/manual/en/function.json-encode.php@title=json_encode]( array( "eigenschaft" => "wert" ) );
Das ergibt folgendes JSON-Objekt:
{
"eigenschaft" : "wert"
}
Und in JavaScript kann das mit einem AJAX-Request einfach gelesen werden:
script.js
var request = new XMLHttpRequest();
request.open("get","json_api.php");
request.send();
request.addEventListener("load", function ( event ) {
var repsonse = event.target.response;
// In response steht dann exakt oben gezeigtes JSON-Objekt.
});
Auf diese Weise hat man eine saubere Trennung der Verantwortlichkeiten. Das ist auch die am weitesten verbreitete Lösung, die jeder erfahrene Webentwickler auf Anhieb verstehen wird.
Hakuna matata!
Prinzip: statt einer statischen JS-Datei wird ein Template über den Loader gezogen.
Das sollte man tunlichst vermeiden, auf diese Weise erzeugt man eine unheimliche enge Kopplung zwischen serverseitiger und clientseitiger Logik, die zu unwartbarem Code führt. Zudem hat PHP gar nicht die Werkzeuge, um ordentlichen JavaScript-Code zu erzeugen, es fehlen jegliche Funktionen für die kontextgerechte Kodierung von JavaScript-Code-Fragmenten, von einer programmatischen API zum Erzeugen von JavaScript-Syntax ganz zu schweigen.
Wer redet denn von 'JavaScript-Code erzeugen'? JS liegt als Datei vor, wird eingelesen, mit dem Last-Modified-Header als Content-Type: text/javascript gesendet und gut isses.
Unwartbar wird sowas infolge sinnvollen Einsatz von Platzhaltern auch nicht, ganz im Gegenteil, es vermeidet redundanten Code.
MfG
Aloha ;)
Wer redet denn von 'JavaScript-Code erzeugen'? JS liegt als Datei vor, wird eingelesen, mit dem Last-Modified-Header als Content-Type: text/javascript gesendet und gut isses.
Unwartbar wird sowas infolge sinnvollen Einsatz von Platzhaltern auch nicht, ganz im Gegenteil, es vermeidet redundanten Code.
Sehe ich auch so. Ich glaube, 1UnitedPower hat uns da etwas missverstanden.
Trotzdem ist die von ihm ausgeführte Methode sehr wertvoll, das war schließlich die letzte der Möglichkeiten, die noch im Raum stand (Erhalten der Variablen durch Ajax). Jetzt haben wir für alle drei Methoden Code-Beispiele. Sehr schön.
Nachteil der AJAX-Lösung ist allerdings (um das auch mal zu beleuchten), dass ich damit noch mehr Requests aka Traffic aka Ladezeit benötige. Plus: ich kann die Werte noch nicht von Anfang an nutzen (da ich ja erst den asynchron ausgeführten request abwarten muss). Außerdem ist aufgrund der zentralen Einbindung der Werte die Manipulierbarkeit genauso groß und einfach, wie bei meinem ursprünglichen Beispiel. Und ich habe wieder redundanten Code, weil ich den AJAX für jedes einzubindende Javascript einzeln ausführen muss, da diese ja optimalerweise auch unabhängig voneinander stattfinden sollen.
Diese Nachteile machen es mir schwer, den Usecase zu sehen, indem die AJAX-Methode sinnvoller ist als die anderen beiden vorgestellten Methoden (je nach Priorität hat je eine der beiden Methoden einen Vorteil über AJAX).
Wobei, einen Vorteil, den die anderen Methoden nicht haben, sehe ich noch. Man kann damit erhöhte Manipulationssicherheit zulasten des Traffic erzielen, indem man grundsätzlich die benötigten Variablen nicht einmal requested und zwischenspeichert, sondern pro Verarbeitungsprozess die Daten extra anfordert (evtl. noch mit zwischengespeicherten vergleicht) und direkt im onload-Eventhandler den Prozess stattfinden lässt. Das schließt Laufzeit-Manipulation so gut wie komplett aus (da es eigentlich keine Laufzeit gibt, sondern nur instantan ablaufende, isolierte Prozesse). Fraglich ist aber, ob dieser verhältnismäßig geringe Sicherheits-Benefit (es können ja auch die Funktionen direkt manipuliert werden) einen massiv erhöhten Traffic und Programmieraufwand rechtfertigen...
Grüße,
RIDER
Hakuna matata!
Nachteil der AJAX-Lösung ist allerdings (um das auch mal zu beleuchten), dass ich damit noch mehr Requests aka Traffic aka Ladezeit benötige.
Das ist sehr kurzsichtig. Initial findet ein Request mehr statt, das bedeutet zusätzlicher Overhead, ABER: Bei der Ajax-Lösung hat man eine saubere Trennung zwischen Programmlogik (JavaScript) und dynmaischen Zuständen (JSON). Die Programmlogik wird sich hoffentlich nicht all zu oft ändern, die Zustände vermutlich schon. Bei der Ajax-Lösung ist es deshalb möglich die Programm-Logik sehr lange zu cachen und nur die Zustände regelmäßig neu anzufordern. Bei eurer Lösung, wird beides über einen Kamm gescherrt und infolgedessen muss das gesamte JavaScript-Teilprogramm neugeladen werden, wenn sich nur die Zustände ändern.
Plus: ich kann die Werte noch nicht von Anfang an nutzen (da ich ja erst den asynchron ausgeführten request abwarten muss).
Ich bezweifle, dass das zu einem Falschenhals werden könnte. Und auf der anderen Seite, erlaubt die AJAX-Variante natürlich auch zwischendurch kleine Anfragen abzuschicken, s.o.
Außerdem ist aufgrund der zentralen Einbindung der Werte die Manipulierbarkeit genauso groß und einfach, wie bei meinem ursprünglichen Beispiel.
Was wunderbar ist, denn dein ursprüngliches Beispiel hat kein Problem mit Manipulierbarkeit ;)
Und ich habe wieder redundanten Code, weil ich den AJAX für jedes einzubindende Javascript einzeln ausführen muss, da diese ja optimalerweise auch unabhängig voneinander stattfinden sollen.
Ich sehe nicht, wieso das zu redundatem Code führen sollte? Kannst du ein Mini-Beispiel bauen? Ich bin mir sicher, dass sich auch dafür schnell eine Lösung finden ließe. In der Regel, kann man das DRY-Prinzip immer sehr einfach erreichen, indem man ein zustätzlichen Level an Abstraktion einfügt, häufig kann das bereits durch eine einfache Funktion erreicht werden.
Wobei, einen Vorteil, den die anderen Methoden nicht haben, sehe ich noch. Man kann damit erhöhte Manipulationssicherheit […]
Es gibt hier kein Sicherheitsproblem mit Manipulation, der Nutzer kann natürlich mit seinen Entwicklertools auch das <html>-Element löschen und kriegt so gar nichts mehr zu sehen, aber das ist ein Fall gegen den wir unsere Anwendung nicht absichern müssen. Wichtig ist, dass der Nutzer nicht in der Lage ist, irgendwelche Prozesse auf dem Server zu starten, zu denen er nicht berechtigt ist, und da öffnet keiner der vorgeschlagenen Lösungen per se eine Hintertür.
Aloha ;)
Bei der Ajax-Lösung hat man eine saubere Trennung zwischen Programmlogik (JavaScript) und dynmaischen Zuständen (JSON). Die Programmlogik wird sich hoffentlich nicht all zu oft ändern, die Zustände vermutlich schon. Bei der Ajax-Lösung ist es deshalb möglich die Programm-Logik sehr lange zu cachen und nur die Zustände regelmäßig neu anzufordern. Bei eurer Lösung, wird beides über einen Kamm gescherrt und infolgedessen muss das gesamte JavaScript-Teilprogramm neugeladen werden, wenn sich nur die Zustände ändern.
Nun, das stimmt. Das ist aber nur dann ein Vorteil, wenn die Zustände tatsächlich dynamisch sind oder sein können. Wenn du das Ursprungsproblem nachliest wird dir auffallen, dass der TO selbst keine dynamischen Zustandsänderungen vorgesehen hatte, sondern lediglich statische, nur vom User abhängige Variablen von PHP an JS übergeben wollte.
Selbstverständlich benötige ich AJAX, um dynamische Zustände zu verarbeiten. Das ist aber überhaupt nicht der Punkt, um den es afaik hier gerade geht. Auch in der loader.php-Lösung können dynamische Zustände zusätzlich durch AJAX angefordert werden, es ging aber im Grundsatz nur darum, mit welcher Methode man ein bestimmtes Set statischer Variablen möglichst effizient an JS weitergeben kann.
Was wunderbar ist, denn dein ursprüngliches Beispiel hat kein Problem mit Manipulierbarkeit ;)
Stimmt. Ich gebe zu, dass Manipulierbarkeitsdiskussionen meinerseits hier mehr Schattengefecht sind als tatsächlich substantiell.
Und ich habe wieder redundanten Code, weil ich den AJAX für jedes einzubindende Javascript einzeln ausführen muss, da diese ja optimalerweise auch unabhängig voneinander stattfinden sollen.
Ich sehe nicht, wieso das zu redundatem Code führen sollte? Kannst du ein Mini-Beispiel bauen? Ich bin mir sicher, dass sich auch dafür schnell eine Lösung finden ließe. In der Regel, kann man das DRY-Prinzip immer sehr einfach erreichen, indem man ein zustätzlichen Level an Abstraktion einfügt, häufig kann das bereits durch eine einfache Funktion erreicht werden.
Ja, kann ich. Sagen wir, ich habe ein System am laufen, das zentral unterschiedlichste Seiten zusammenbaut (wie die Frontend-Ausgabe eines CMS). Es gibt drei JS-Skripte namens a.js, b.js und c.js; diese werden vom System nur da verbaut, wo sie gebraucht werden. Alle drei benötigen aber Zugriff auf statische Variablen des CMS, beispielswiese den Namen des registrierten Users (wieso auch immer). Dann habe ich zwei Möglichkeiten - denn a.js, b.js und c.js sollen ja untereinander autark sein:
Möglichkeit 1: ich programmiere in jedes der Skripte Passagen, die das laden der statischen Variablen per AJAX anleiern. Das ist der redundante Code, von dem ich sprach.
Möglichkeit 2: Ich lade auf ALLEN Seiten ein zusätzliches Skript varload.js ein, welches das Laden der statischen Variablen per AJAX zentral übernimmt. Dann gibt es aber in der Funktionalität zwischen der AJAX-Methode und der von mir genannten inline-script Methode keinen Unterschied mehr - mit den Nachteilen in der AJAX-Methode, dass sie immer einen Request mehr braucht, nicht sofort einsatzfähig ist, ein zusätzliches PHP-Skript zum Beantworten des Request geschrieben haben will, in welchem ich die dem HTML-Konstruktor schon bekannten Daten noch einmal zusammensammeln muss...
Summa summarum (natürlich nur auf das Problem statisched Zustände bezogen, über alles andere müssen wir gar nicht diskutieren): Entweder haben wir redundanten Code, oder die Methode führt sich ad absurdum, da sie exakt und ausschließlich das gleiche leistet wie das inline-script, dabei aber deutlich höheren Programmieraufwand erfordert.
Selbst wenn ich zusätzlich dynamische Zustände habe, würde ich mich wohl dafür entscheiden, die statischen Zustände über eine der beiden anderen Methoden (wahrscheinlich am ehesten inline-script) zu besorgen und ausschließlich die dynamischen Zustände bei Bedarf je per AJAX anfordern (Man bedenke: richtig dynamische Zustände sollten gar nicht länger zwischengespeichert werden, sondern bei Bedarf angefordert - sie könnten sich sonst dynamisch geändert haben). Das ist in meinen Augen nach allen Aspekten (Overhead, schnelle Verfügbarkeit, Programmieraufwand, ...) die effizienteste Lösung. (Das Ersetzen von Platzhaltern statt dem inline-script macht nur dann Sinn, wenn ich die einzusetzenden Variablen ohne (größeren) programmiertechnischen Neuaufwand ermitteln kann).
Grüße,
RIDER
Aloha ;)
Möglichkeit 2: Ich lade auf ALLEN Seiten ein zusätzliches Skript varload.js ein, welches das Laden der statischen Variablen per AJAX zentral übernimmt.
Das ist auch eine Idee, komme ich evntl. darauf zurück. Weiter oben schrieb ich was von Zusammenbauen:
Anstatt mehrerer <script src="xy.js">-Tags gibt es nur noch einen <script src="loader?params">-Tag wobei der loader die JS-Dateien serverseitig einliest und zur Ausgabe einfach nur aneinanderhängt (Last-Modified nicht vergessen).
Das Laden von JS-Code kann dann auch asynchron erfolgen, wenn das erst später gebraucht wird.
MfG
Hakuna matata!
Wer redet denn von 'JavaScript-Code erzeugen'?
Du, als du von Templates sprachst.
Unwartbar wird sowas infolge sinnvollen Einsatz von Platzhaltern auch nicht.
Einverstanden, aber Platzhalter in JavaScript-Code sind nicht sinnvoll. Es fängt damit an, dass man keine Modultests für solche generischen Skript-Bausteine entwickeln kann. Außerdem werden durch Platzhalter statical Analysis-Tools unbrauchbar, das umfasst zum Beispiel: Autosuggestion des Editors (tern.js), Code-Quality-Tools (jshint), Syntax-Highlighting, Precompiler (minfiy, browserify) und Dependency-Injectors. Und auch andere Werkzeuge, wie Modul-Loader (require.js) arbeiten nicht nahtlos mit JS-Templates zusammen. Kurz und bündig: das gesamte JavaScript-Ökosystem wird dir überm' Kopf zusammenbrechen.
ganz im Gegenteil, es vermeidet redundanten Code.
Das geht mit JSON sehr viel sauberer, ohne die oben genannten Probleme.
Hakuna matata!
Unwartbar wird sowas infolge sinnvollen Einsatz von Platzhaltern auch nicht.
Einverstanden, aber Platzhalter in JavaScript-Code sind nicht sinnvoll. Es fängt damit an, dass man keine Modultests für solche generischen Skript-Bausteine entwickeln kann. Außerdem werden durch Platzhalter statical Analysis-Tools unbrauchbar, das umfasst zum Beispiel: Autosuggestion des Editors (tern.js), Code-Quality-Tools (jshint), Syntax-Highlighting, Precompiler (minfiy, browserify) und Dependency-Injectors. Und auch andere Werkzeuge, wie Modul-Loader (require.js) arbeiten nicht nahtlos mit JS-Templates zusammen. Kurz und bündig: das gesamte JavaScript-Ökosystem wird dir überm' Kopf zusammenbrechen.
Wenn in der JS-Datei sowas steht:
var CTRL = '%ctrl%';
bricht das alles zusammen? Das wusste ich noch nicht.
MfG
Aloha ;)
Einverstanden, aber Platzhalter in JavaScript-Code sind nicht sinnvoll. Es fängt damit an, dass man keine Modultests für solche generischen Skript-Bausteine entwickeln kann. [...] Syntax-Highlighting, Precompiler (minfiy, browserify) und Dependency-Injectors. Und auch andere Werkzeuge, wie Modul-Loader (require.js) arbeiten nicht nahtlos mit JS-Templates zusammen. Kurz und bündig: das gesamte JavaScript-Ökosystem wird dir überm' Kopf zusammenbrechen.
Tatsächlich?
Syntax-Highlighting und Precompiler sollten mit Platzhaltern genauso arbeiten, da valides JS erzeugt wird (zumindest wenn man wie ich oben vorgeführt habe, einigermaßen sinnvolle Platzhalter wählt - in dem Fall sind die Platzhalter für Precompiler & Co. einfach statische Strings oder Leerstrings, je nach Interpretation). Precompiler, die die Logik verschlanken sollen, sind evtl. tatsächlich aufgeschmissen. Aber wozu brauche ich als logikfähiger Programmierer auch unbedingt nen Bot, der mir in der Logik hinterherpfuscht? Es kommt noch dazu, dass imho Precompiler in Javascript alles andere als wirklich essentiell notwendig sind. Aber das ist eine andere Geschichte.
Was Autovervollständigung angeht, gebe ich dir teilweise recht. Das ist aber eine reine Programmierer-Komfortfunktion. Und auch die funktioniert nur für die Platzhalter nicht, alles andere funktioniert. Schließlich sind die Platzhalter ja auf Codeebene nur statische Strings. Also wieder: valides Javascript. Ist es so viel schwerer, die Platzhalter ausnahmsweise ausschreiben zu müssen?
Und was Modulloader etc. angeht: Diese verwenden selbstverständlich nicht die JS-Datei mit Platzhaltern sondern laden die Version, die auch beim Client ankommen soll. Nämlich loader.php?file=skript.
Ich sehe den Punkt nicht. Und schon gar kein zusammengebrochenes Ökosystem.
Grüße,
RIDER
Hakuna matata!
Aloha ;)
Einverstanden, aber Platzhalter in JavaScript-Code sind nicht sinnvoll. Es fängt damit an, dass man keine Modultests für solche generischen Skript-Bausteine entwickeln kann. [...] Syntax-Highlighting, Precompiler (minfiy, browserify) und Dependency-Injectors. Und auch andere Werkzeuge, wie Modul-Loader (require.js) arbeiten nicht nahtlos mit JS-Templates zusammen. Kurz und bündig: das gesamte JavaScript-Ökosystem wird dir überm' Kopf zusammenbrechen.
Tatsächlich?
Syntax-Highlighting und Precompiler sollten mit Platzhaltern genauso arbeiten, da valides JS erzeugt wird […]
Wird es nicht. Gehen wir von folgendem Template aus:
var foo = '<?= $foo ?>';
Und im PHP:
$foo = "arrr'rrrk";
Das fertig gerenderte Template, sähe dann so aus:
var foo = 'arrr'rrrk';
Man könnte jetzt hingehen und das Anführungszeichen maskieren, die korrekte Ausgabe wäre dann:
var foo = 'arrr\'rrrk';
So, aber was wenn nun die Template-Variable nicht von einfachen, sondern von doppelten Anführungszeichen umschlossen wird? Das Ergebnis nach unserer Anpassung von gerade, wäre diesmal zwar kein Syntax-Fehler, aber auch nicht die Zeichenkette, die wir erwarten würden:
var foo = "arrr\'rrrk";
Für diese konstruierten Fall, ließe sich wieder ein Lösung finden, aber um es kurz zu machen: eine allgemine Lösung für die Problemklasse erhält man nur, wenn man der Template-Engine gestattet die umschließenden String-Begrenzer selbst zu generieren. Also in etwa so:
var foo = <?= json_encode( $foo ); ?>
json_encode eignet sich zum Glück hervorragend, um JavaScript-Strings zu maskieren. Das Problem an dieser Stelle ist aber eben, dass der Platzhalter nun nicht mehr von JavaScript-String-Begrenzern umgeben wird, ein JavaScript-Parser (1) würde hier also auf die öffnende Spitze Klammer stoßen und sich dann verabschieden. Eben habe ich von static Analysis gesprochen, das ist beschreibt die Fähigkeit Aussagen über Code zu treffen, ohne ihn ausführen zu müssen. Das erfordert aber Syntax-Parsing, und eine ganze Reihe Werkzeuge, die ich eben auch schon genannt habe, hängt davon ab und wie wir gerade gesehen haben können wir kontextgerechte Maskierung und Syntax-Parsing nicht gleichzeitig haben. hottis etwas andere Syntax für Platzhaler, kann das übrigens auch nicht, sie hat mit genau dem gleichen Problem zu kämpfen.
Tatsächlich?
Syntax-Highlighting und Precompiler sollten mit Platzhaltern genauso arbeiten, da valides JS erzeugt wird […]
Wird es nicht. Gehen wir von folgendem Template aus:
var foo = '<?= $foo ?>';
Und im PHP:
$foo = "arrr'rrrk";
Das fertig gerenderte Template, sähe dann so aus:
var foo = 'arrr'rrrk';
Pardon, vielleicht hab ich mich nicht klar genug ausgedrückt. Syntax-Highlighting und Precompiler arbeiten doch (zumindest habe ich das so verstanden/beabsichtigt") nicht mit dem fertigen JS für den Client, sondern mit der Variante, in der die Platzhalter noch nicht ersetzt sind. Dieses Problem ergibt sich also real nicht. Diesen Fall müssen wir aber wegen mir nicht ausdiskutieren ;) wer welchen Präprozessor einsetzt und mit welchen Möglichkeiten dieser kompatibel ist, wird wohl jeder selber sehen und entscheiden müssen. Ich hab in 7 Jahren Javascript-Programmierung noch nie einen benutzt und hatte dafür auch noch keinen Bedarf. ;) Aber wie gesagt, Schwamm drüber.
Man könnte jetzt hingehen und das Anführungszeichen maskieren, die korrekte Ausgabe wäre dann:
var foo = 'arrr\'rrrk';
So, aber was wenn nun die Template-Variable nicht von einfachen, sondern von doppelten Anführungszeichen umschlossen wird? Das Ergebnis nach unserer Anpassung von gerade, wäre diesmal zwar kein Syntax-Fehler, aber auch nicht die Zeichenkette, die wir erwarten würden:
var foo = "arrr\'rrrk";
Ich gebe zu: In meinen beiden Beispielen sollten die Variablen keine String-Delimiter beinhalten. Das stimmt soweit. Die Zeichen ' und " kommen aber bei einfachen Daten kaum vor, meist geht es um alphanumerische Strings mit bestimmten Sonderzeichen (Da die Verwendung von String-Delimitern in Strings aber immer und überall problematisch ist, wird in fast allen Systemen auch konsequent auf deren Einsatz verzichtet).
Für diese konstruierten Fall, ließe sich wieder ein Lösung finden, aber um es kurz zu machen: eine allgemine Lösung für die Problemklasse erhält man nur, wenn man der Template-Engine gestattet die umschließenden String-Begrenzer selbst zu generieren. Also in etwa so:
var foo = <?= json_encode( $foo ); ?>
Das stimmt. Die einzige ALLGEMEINE Lösung ist JSON. Du hast den Vorteil gefunden, chapeau.
Trotzdem: Allgemeine Lösungen sind bekanntlich für einfache Fälle meist overpowered und mit mehr Aufwand als nötig verbunden. Deshalb würde ich für das gegebene Problem nach wie vor die anderen Wege vorziehen.
Du hast aber vollkommen Recht, es muss der Aspekt der Allgemeinheit, der bisher im Hintergrund stand, auch betont werden. Vor allem bei großen Systemen, die unabsehbar wachsen können, sind allgemeine Lösungen zu bevorzugen.
Grüße,
RIDER
Hakuna matata!
Syntax-Highlighting und Precompiler sollten mit Platzhaltern genauso arbeiten, da valides JS erzeugt wird […]
Wird es nicht. Gehen wir von folgendem Template aus:
var foo = '<?= $foo ?>';
Und im PHP:
$foo = "arrr'rrrk";
Das fertig gerenderte Template, sähe dann so aus:
var foo = 'arrr'rrrk';
Pardon, vielleicht hab ich mich nicht klar genug ausgedrückt. Syntax-Highlighting und Precompiler arbeiten doch [...] nicht mit dem fertigen JS für den Client, sondern mit der Variante, in der die Platzhalter noch nicht ersetzt sind.
Man muss sich hier entscheiden, ob das rohe Template bereits valides JS sein soll, oder ob das fertig gerenderte Template valide sein soll. Ich habe versucht zu erklären, dass man nicht beides haben kann, weil man im ersten Fall keine kontextgerechte Maskierung vornehmen kann. Im weiteren Text bin ich dann einfach davon ausgengangen, dass man sich für die kontextgerechte Variante entscheidet.
Ich gebe zu: In meinen beiden Beispielen sollten die Variablen keine String-Delimiter beinhalten. Das stimmt soweit. Die Zeichen ' und " kommen aber bei einfachen Daten kaum vor, meist geht es um alphanumerische Strings mit bestimmten Sonderzeichen (Da die Verwendung von String-Delimitern in Strings aber immer und überall problematisch ist, wird in fast allen Systemen auch konsequent auf deren Einsatz verzichtet).
Hier begibst du dich in eine Welt des Schmerzes. Wenn du Daten nicht entsprechend ihres Zielkontextes behandelst, dann reißt du dir Sichheitslücken auf. In diesem Fall wäre das Risiko keine SQL-Injection, wie in dem xkcd-Comic, sondern eine JavaScript-Injection.
Siehe: Kontextwechseln erkennen und behandeln
Trotzdem: Allgemeine Lösungen sind bekanntlich für einfache Fälle meist overpowered und mit mehr Aufwand als nötig verbunden. Deshalb würde ich für das gegebene Problem nach wie vor die anderen Wege vorziehen.
Allgemine Lösungen sind bekanntlich wiederverwendbar und damit mit weniger Aufwand als möglich verbunden ;)
Ich wollte hier den Punkt deutlich machen, wenn man schon Templates einsetzt, dann bitte richtig und ohne Sicherheitsrisken und ohne obskure Randbedingungen. Ich rate aber weiterhin dringend davon ab, JavaScript-Code genrieren zu wollen und rate stattdessen zu einem gebräuchlichem Daten-Austausch-Format: JSON bietet sich wie gesagt an.
Aloha ;)
Ich gebe dir Recht, außer...
Wenn du Daten nicht entsprechend ihres Zielkontextes behandelst, dann reißt du dir Sichheitslücken auf. In diesem Fall wäre das Risiko keine SQL-Injection, wie in dem xkcd-Comic, sondern eine JavaScript-Injection.
...hier. Es ist Aufgabe des Programmierers, sicherzustellen, dass hier nur Inhalte inkludiert werden, über die er die Kontrolle besitzt - zumindest hinsichtlich dessen, ob darin Javascript-String-Delimiter vorkommen oder nicht. Natürlich existiert dieses Risiko. So wie fast immer - man sollte sich grundsätzlich Gedanken machen, ob potenziell schädliche Inhalte eingefügt werden, von dem Punkt ab, an dem man beginnt mit PHP zu arbeiten. Du hast Recht, wenn du von einem Risiko sprichst. Dieses ist aber weder so groß noch so unvorhersehbar, wie es sich für mich beim ersten Lesen dieser Passage angehört hat ;)
Allgemine Lösungen sind bekanntlich wiederverwendbar und damit mit weniger Aufwand als möglich verbunden ;)
Nur, wenn das System inndiese Richtung erweitert werden soll. Wenn eine Erweiterung in diese Richtung nicht vorgesehen ist, ist eine allgemeine Lösung aufwendiger ;)
Aber wie gesagt, deine Argumente sind allgemein schon richtig.
Grüße,
RIDER