Est-il considéré comme une mauvaise pratique d'avoir PHP dans votre JavaScript

55

Tant de fois sur ce site, je vois des gens qui essaient de faire des choses comme celle-ci:

<script type="text/javascript">
  $(document).ready(function(){

     $('<?php echo $divID ?>').click(funtion(){
       alert('do something');
     });

  });
</script>

Je ne pense pas que ce soit une sorte de modèle dans lequel les gens tombent naturellement. Il doit exister une sorte de didacticiel ou de matériel didactique sur ce sujet, sinon nous le verrions moins. Ce que je demande, c’est: est-ce que je fais beaucoup trop de choses ou est-ce vraiment une mauvaise pratique?

EDIT: J'en parlais à un de mes amis qui mettait souvent Ruby dans son code JavaScript et il a soulevé ce point.

Est-il possible de placer dynamiquement des constantes d'application dans votre JavaScript afin de ne pas avoir à éditer deux fichiers? par exemple...

MYAPP.constants = <php echo json_encode($constants) ?>;

Vous pouvez également encoder directement les données que vous prévoyez d'utiliser dans une bibliothèque.

ChartLibrary.datapoints = <php echo json_encode($chartData) ?>;   

ou devrions-nous faire un appel AJAX à chaque fois?

Greg Guida
la source
4
Il me semble que this question will likely solicit opinion, debate, arguments, polling, or extended discussion....
DaveRandom
7
@ M.Babcock Cela ferait partie d'un fichier .php, de sorte que le code php soit exécuté côté serveur et que le client ne voie que le résultat de l'écho.
8
Tous ceux qui créent du JavaScript généré dynamiquement sont pris en charge et traités
Raynos
5
@ Matt alors je vais prendre Google en arrière et traiter avec eux
Raynos
4
"Vous avez votre javascript dans mon PHP!" "Non, vous avez votre PHP dans mon javascript!"
Josh Darnell

Réponses:

83

En règle générale, il est déconseillé d’utiliser le langage X pour générer du code dans le langage Y.

Essayez de découpler les deux langues en faisant des données leur seule interface - ne mélangez pas le code .

Dans votre exemple, vous pouvez améliorer le code en utilisant PHP pour renseigner une cfgstructure disponible pour JavaScript:

<script type="text/javascript">
  var cfg = {
    theId: "<?php echo $divID ?>",
    ...
  };

  $(document).ready(function(){
     $("#" + cfg.theId).click(funtion(){
       alert('do something');
     });
  });
</script>

De cette façon, PHP ne s'occupe que de renseigner la structure de données et JavaScript de consommer uniquement la structure de données.

Ce découplage ouvre également la voie au chargement futur des données de manière asynchrone (JSON).

Mise à jour:

Pour répondre aux questions supplémentaires que vous avez posées avec votre mise à jour, oui, il serait judicieux d'appliquer le principe DRY et de laisser PHP et JavaScript partager le même objet de configuration:

<script type="text/javascript">
  var cfg = <?php echo json_encode($cfg) ?>;

  ...

Il n'y a pas de mal à insérer la représentation JSON de votre configuration directement dans votre page comme ceci. Vous n'êtes pas obligé de le récupérer via XHR.

Ates Goral
la source
21
Souvenez-vous de ne pas mettre votre mot de passe MySQL dans $ cfg!
Thomas Bonini
13
"faire des données leur seule interface - ne mélangez pas le code." Je pense que cela va vraiment au cœur de la question et qu’il s’agit d’une bonne règle lorsque l’on utilise TOUTES les langues. Merci pour la perspicacité.
Greg Guida
6
Vous pouvez également inclure ce JSON dans un data-attribut de votre code HTML. Quelque chose comme <body data-cfg="{...}">.
Kapa
1
@bazmegakapa Je pense que cela pourrait être la meilleure option. Cela permet notamment l'utilisation d'API telles que HTML DOM qui réduisent considérablement le risque d'injections XSS.
luiscubal
1
+1 pour suggérer l'utilisation de données comme interface et décourager le code qui génère du code.
Brandon
21

JavaScript généré dynamiquement est une pratique horrible et mauvaise.

Ce que vous êtes censé faire, c'est comprendre ce que signifie séparation des préoccupations et amélioration progressive.

Cela signifie essentiellement que vous avez du code HTML dynamique et du code JavaScript statique (qui améliore le code HTML).

Dans votre cas, vous voulez probablement une classe sur votre div et sélectionnez-la avec un sélecteur de classe

Raynos
la source
10

Le plus gros problème avec votre extrait de code est qu'il vous manque le #pour en faire un sélecteur valide de jQuery;).

Je dirais que vous devriez essayer d'éviter d'inclure PHP dans votre JavaScript si possible. Qu'est-ce qui ne va pas avec le changement de sélecteur dans votre click()gestionnaire en classe et l'ajout de la classe à l'élément en question si vous souhaitez que le gestionnaire soit déclenché, et non si vous ne le faites pas;

<script type="text/javascript">
  $(document).ready(function(){

     $('.foo').click(funtion(){
       alert('do something');
     });

  });
</script> 

<div id="bar" class="<?php echo ($someCond ? 'foo' : ''); ?>">Hello</div>

Il y a des circonstances où vous devez inclure dans votre PHP JavaScript; mais je dois admettre que ceux-ci sont rares.

Un exemple est lorsque vous avez des environnements différents; tester, mettre en scène et vivre. Chacun d'entre eux a un emplacement différent de vos actifs (images, principalement). Le moyen le plus simple de définir le chemin d'accès de sorte qu'il puisse être utilisé par JavaScript est quelque chose comme:

var config = { assets: "<?php echo $yourConfig['asset_url']; ?>" };
Mat
la source
Dans le reste de mon code php imaginaire, j'ai déjà ajouté le #=), mais sérieusement, je conviens que votre exemple est la meilleure façon de le faire. Cela me semble plus naturel de le faire aussi. Alors, pourquoi le voyons-nous si souvent dans des endroits où cela n’est pas nécessaire?
Greg Guida
Notez que l'écho des données statiques dans un fichier de configuration peut facilement être évité si vos environnements sont tous configurés de la même manière.
Raynos
4
@GregGuida: Je suppose que les programmeurs ont rarement l'habitude de traiter avec des architectures client / serveur telles que celles que vous rencontrez dans le développement Web. Ils traitent DB <-> PHP <-> HTML / JS / CSS comme un tout et ne comprennent pas parfaitement ce qui doit aller où et comment les couches doivent être séparées.
Matt
@ Matt je pense que c'est probablement la meilleure explication
Greg Guida
2
$divID = '#' . $element_id_value;- pas de problèmes avec le patron de sélecteur;)
rlemon
8

C'est une mauvaise pratique à mon avis, car vous auriez besoin d'appeler ce fichier quelque chose.php et ensuite vous ne pourriez pas le compresser par exemple, ne dites pas qu'il n'est pas correct de mixer votre contenu de serveur avec votre JavaScript. Essayez de limiter autant que possible le mélange entre PHP et JS.

Vous pouvez toujours le faire à la place:

function setOnClick(divid) {
 $(divid).click(funtion(){
   alert('do something');
 });
}

Et ensuite, vous pouvez appeler cette fonction dans un fichier php, pour rendre ces opérations de mixage aussi petites que possible.

$(function() {
  setOnClick('<?php echo $divId; ?>');
});

En faisant cela (avoir des fichiers JS plus volumineux, pas deux ou trois lignes là où ça ne fait rien), vous pouvez tirer parti de la compression du fichier JS et les développeurs front-office se sentiront plus à l'aise de travailler uniquement avec JavaScript, à mon avis (comme vous pourriez l'écrire). Python, Ruby, etc. non seulement PHP - et le code pourrait devenir de plus en plus gros selon ce que vous devez faire là-bas).

Alessioalex
la source
2
Totalement d'accord, d'ailleurs je n'ai jamais mis PHP dans mon JS. Je viens de le voir tout le temps sur ce site.
Greg Guida
Le code php ne parvient jamais au navigateur! Juste le code évalué qui devrait maintenant être du code JavaScript simple. La taille / compression du fichier n’est donc pas un problème. Encore mauvaise pratique pensé!
James Anderson
@JamesAnderson Je pense que Alessioalex fait référence à la minification (comme Uglify). Il est peut-être possible d'exécuter php, puis une fonction php post-traitement, d'analyser la réponse, d'identifier la balise de script, de l'exécuter via Uglify et de remplacer le JS généré à l'origine par php par la version modifiée avant d'envoyer la réponse. mais faire cela à chaque demande sonne comme un bêta! approche.
Jinglesthula
6

Je ne pense pas que ce soit une mauvaise pratique. Si l'ID requis dans votre JavaScript est dynamique, il n'y a pas d'autre moyen de le faire.

CodeZombie
la source
5
Pourquoi, dans le nom impie de Cuthulu, ne connaissez-vous pas le nom d'une étiquette d'identification?
Incognito
3
@ Incognito, il arrive souvent que vous ne connaissiez pas l'identifiant ... Si vous utilisez ajax pour générer de nouveaux blocs de code, vous générez peut-être des identifiants uniques avec de nouveaux JS ... dans ce cas, vous devez assurez-vous que les identifiants de référence sont les mêmes dans le js, ils sont dans le bloc de code résultant. Il y a beaucoup d'autres exemples comme celui-ci et il est assez courant d'utiliser ajax ou d'avoir de gros blocs de code dépendant d'une instruction if côté serveur côté serveur, etc.
7
@raynjamin Je ne comprends même pas comment vous vous mettez dans des situations où c'est ce que vous faites ... ou pourquoi vous sélectionneriez par classe, puis listiez les tags, puis les attributs d'ID qui ont une valeur CSS cachée, ce sélecteur ... ça me fait mal de regarder ... Je ne sais même pas par où commencer ... comme ... quoi? Êtes-vous en train de couper / coller des blocs de code massifs ou quelque chose qui facilite le fonctionnement de plusieurs identifiants? Je ne même pas ... comme ... mon cerveau. ça explose ici.
Incognito
3
Allez lire sur le dom / html / peu importe ... utilisez un moteur de recherche ... Pourquoi n'ai-je jamais eu à faire ce genre de choses avec du HTML dynamique?
Incognito
5
non. vous ne comprenez pas comment fonctionnent les étiquettes d'identification. Je comprends exactement ce que vous dites.
Incognito
6

Je considérerais cette mauvaise pratique. Lorsque vous insérez du contenu dynamique dans des blocs de script, vous devez toujours être conscient du fait que s’échapper dans un contexte javascript n’est pas aussi simple que vous le souhaiteriez. Si les valeurs ont été fournies par l'utilisateur, il ne suffit pas de les échapper en HTML.

La feuille de triche OWASP XSS contient plus de détails, mais vous devriez fondamentalement adopter ce modèle:

<script id="init_data" type="application/json">
    <?php echo htmlspecialchars(json_encode($yourdata)); ?>
</script>

Ensuite, dans un fichier .js séparé, lié à votre code HTML principal, chargez le code suivant:

var dataElement = document.getElementById('init_data');
var jsonText = dataElement.textContent || dataElement.innerText  // unescapes the content of the span
var initData = JSON.parse(jsonText);

La raison d'utiliser un fichier .js séparé est double:

  • Il est cacheable donc la performance est meilleure
  • L'analyseur HTML n'est pas déclenché, il n'y a donc aucun risque qu'un bogue XSS passe par quelqu'un qui insère une balise <? Php rapide quelque part
Joeri Sebrechts
la source
+1 pour expliquer pleinement l'angle XSS! Votre approche se chargera plus rapidement car le JSON est chargé avant Domready, mais je préfère l’analyse JSON automatique de using $.ajaxou similaire
roo2
5

Certaines personnes diraient que c'est une mauvaise pratique. Non pas parce que c'est PHP dans JS, mais parce que c'est un JS en ligne qui ne sera donc pas mis en cache par le navigateur pour faciliter le chargement la prochaine fois.

IMO, il est toujours préférable d'utiliser JSON pour passer des variables entre les 2 langues, mais je suppose que cela dépend de vous.

pseudo
la source
5

Je dirais qu'en général ne le fais pas. Cependant, si vous voulez transmettre des données de PHP -> Javascript, cela ne me semblerait pas fou d’avoir un bloc Javascript intégré dans lequel vous avez le code de la forme montrée ci-dessous. Ici, le code ne fait que transmettre des données de php à javascript, sans créer de logique à la volée, etc. Le bon côté de cette opération, par rapport à un appel ajax, est que les données sont disponibles dès le chargement de la page et ne nécessitent pas de déplacement supplémentaire sur le serveur.

<script>
window.config = <?php echo json_encode($config);?>;
</script>

Bien sûr, une autre option consiste à créer un fichier de configuration javascript à partir de PHP via une forme de script de construction qui le mettra dans un fichier .js.

Zachary K
la source
4

La seule chose qui puisse vraiment poser problème, c’est lorsque les erreurs PHP sont configurées pour être affichées, ce qui entraîne une charge HTML qui affiche l’erreur PHP dans votre code JavaScript.

Aussi, parce que c'est écrit dans le script, il ne s'affiche donc pas et il faut parfois un certain temps pour comprendre pourquoi votre script est endommagé.

Alex Coplan
la source
grand cas où cela provoque une grosse erreur
Greg Guida
3

Cela dépend de qui, et si vous me le demandez, oui, je considère cela comme une pratique en retour pour plusieurs raisons. Tout d’abord, je préférerais avoir du code javascript dans son propre fichier JS que l’analyseur php ne pourrait pas toucher.

Deuxièmement, php s’exécute uniquement à l’heure du serveur. Par conséquent, si vous comptez sur une variable php pour modifier votre code javascript, il se peut que cela ne fonctionne pas très bien. S'il y a des paramètres de chargement de page que vous voulez contrôler avec javascript, je préfère généralement ajouter cette valeur au DOM avec php pour que javascript puisse l'atteindre quand et si il le souhaite (dans un div masqué, par exemple).

Enfin, juste à des fins d'organisation, cela peut devenir très ennuyeux. Il est déjà assez difficile de mélanger html et php (à mon avis).

Pilules d'explosion
la source
1

Le fait de contenir PHP dans un configobjet de données représente 90% du chemin, mais la meilleure pratique consiste à le séparer entièrement. Vous pouvez utiliser une API RESTful pour demander uniquement les données dont vous avez besoin. C’est un peu plus javascript, mais avec quelques avantages.

  • Le script est statique et peut être mis en cache de manière permanente
  • PHP n'est plus un vecteur XSS
  • Séparation complète des préoccupations

Inconvénients:

  • Requiert une requête HTTP supplémentaire
  • javascript plus complexe

Scénario

//pure javascript
$.on('domready',function({
    //load the data
    $.get({
       url:'/charts/3D1A2E', 
       success: function(data){
           //now use the chart data here
           ChartModule.init(data);
       }
    });
})
roo2
la source
-3

Ce n’est pas une mauvaise pratique UNIQUEMENT si elle est utilisée pour l’initialisation de code javascript (dans mes thèmes WordPress, j’initialise mes objets javascript avec des fonctions php telles que site_url () car c’est le seul moyen de gérer cela (nous pourrions peut-être utiliser une requête ajax pour obtenir un json, et alors ... mais c'est une douleur dans le cul).

Bonnes pratiques:

new javascriptObject ("");

Mauvaise pratique:

/ * du code * / document.get_element_by_id (); / * du code * /
junius rendel
la source