unkn0wn unkn0wn - 1 month ago 7
Javascript Question

How to execute php through javascript

I am currently using PHP with Backbone.js and in some places I am using PHP to interact with my MySQL server and fill the frontend with Backbone/javascript.

This is the sample PHP I am trying to execute.

$query="select id,username,message,useremail,date from contact";
$result =mysqli_query($connection,$query);
if ($result) {
echo '<table id="hor-minimalist-b" summary="Users List">
<thead>
<tr>
<th scope="col">User ID</th>
<th scope="col">User Name</th>
<th scope="col">User Message</th>
<th scope="col">User Email</th>
<th scope="col">Date</th>
</tr>
</thead>
<tbody>';
while($resultarray=mysqli_fetch_array($result)){
echo "
<tr>
<td>{$resultarray['0']}</td>
<td>{$resultarray['1']}</td>
<td>{$resultarray['2']}</td>
<td>{$resultarray['3']}</td>
<td>{$resultarray['4']}</td>
</tr>
";
}
echo "</tbody>
</table>";
}


One way is to make a PHP file and make a ajax request to get the HTML output and append in a
div
container. But since I have way too many PHP code snippets, I wanted to somehow use javascript to ease me, since I am implementing backbone (http://myurl/#link/feed).

Currently, I tried an ugly way: using HTML and calling javascript functions through PHP's
echo
.

Answer

A summary of my comments:

Gradually integrating Backbone into an existing PHP website is shooting yourself in the foot. Backbone shines when used correctly within a single-page app.

What you would need is to make a REST API with PHP, exposing your data from the server through different url endpoints used by backbone models and collections. PHP can return anything, it's not limited to HTML, so you could return JSON which javascript can easily parse.

How to use Backbone with PHP

The backend API

Here's a really simple PHP endpoint based on your code.

example_ajax.php

<?php
$query ="select id,username,message,useremail,date from contact";
$result = mysqli_query($query);
$rows = array();
while($r = mysqli_fetch_assoc($result)) {
    $rows[] = $r;
}

// return the array as JSON so Backbone can automatically parse it.
print json_encode($rows);

You should check PHP frameworks that handle REST API for you, like Lumen.

The frontend data handling

Create a custom collection which binds to our newly created endpoint:

var ContactCollection = Backbone.Collection.extend({
    url: "example_ajax.php",
});

The static template

And handle the HTML templating with Backbone views.

First prepare the HTML template, could be a static HTML on your server.

<table id="hor-minimalist-b" summary="Users List">
    <thead>
        <tr>
            <th scope="col">User ID</th>
            <th scope="col">User Name</th>
            <th scope="col">User Message</th>
            <th scope="col">User Email</th>
            <th scope="col">Date</th>
        </tr>
    </thead>
    <tbody></tbody>
</table>

<script type="text/template" id="contact-template">
    <td><%= id %></td>
    <td><%= username %></td>
    <td><%= message  %></td>
    <td><%= useremail %></td>
    <td><%= date %></td>
</script>

Backbone views

Then the views:

var ContactView = Backbone.View.extend({
    tagName: 'tr',
    template: _.template($('#contact-template').html()),
    initialize: function(options){
        // optional, automatically remove the html of this row only.
        this.listenTo(this.model, 'remove', this.remove);
    },
    render: function() {
        this.$el.empty().append(this.template(this.model.toJSON()));
        return this;
    },
});

The list view below uses the ContactView as a child view.

var ContactListView = Backbone.View.extend({
    el: "#hor-minimalist-b", // uses existing element in the page

    initialize: function(options) {
        // cache a jQuery element to use as a container for the child views.
        this.$body = this.$('tbody');

        // optional, automatically adds a new contact when the collection changes
        this.listenTo(this.collection, 'add', this.renderContact);
    },
    render: function() {
        this.$body.empty();
        this.collection.each(this.renderContact, this);
        return this; // always return this for chaining
    },

    renderContact: function(model) {
        var view = new ContactView({ model: model });
        this.$body.append(view.render().el);
    },
});

How to use it

var collection = new ContactCollection(),
    view = new ContactListView({ collection: collection });
view.render();

collection.fetch();

The .fetch() function makes a GET call to something like http://www.example.com/example_ajax.php, which should return an array.

Why an API? Why not send SQL queries from JavaScript?

JavaScript runs on the client side, which you can never trust. So you expose specific endpoints on your server, which you can trust. This is why you need an API.

Sending SQL queries from javascript is a bad idea for several reasons:

  • SQL Injection: Someone could fetch/change anything in your database (including stealing password, or nuking the database all together),
  • It's an open door to your server,
  • Lacks trusted validation,
  • Tight coupling, e.g. making it harder to share queries code between different client (mobile app, website, desktop app, etc)

It can be done, but it shouldn't.

phpMyAdmin is an example of an application which takes SQL written by the user and runs it as-is.

If it's in a controlled environment, like a local intranet, and you want to access MySQL from client-side JavaScript, you could write a php script which takes the body of a request and pass it directly to a MySQL database, returning the result as JSON.

For example, there's a lib named Squel.js which serve to build SQL query strings. They have a big red box on the frontpage which reads:

NOTE: It is recommended that you do NOT create queries browser-side to run on the server as this massively increases your exposure to SQL Injection attacks.

Additionnal reading:

Comments