If you use this code, please, at the very least, let me know where and how. If you find it to be useful to you and it saves you time, please consider donating to the cause. At least send me some coin for beer. (:

JavaScript PHP Remoting Demonstration

This is a demonstration of a very fast and easy way to build AJAX-type applications where communications between JavaScript on the client side and PHP5 on the server side is ideal. This library makes development of such systems fast and very simple.

Jump to:

Cutting to the Chase

To make this work for you, all you need is Prototype 1.6 (or better) and my little PHP class. Get them below here...

The LONG Story

I've been working in Flash and ActionScript for a number of years and the way to communicate has traditionally been XML. Then I discovered Flash Remoting and AMFPHP, which is WAY easier to work with. It's a little more work to implement, but once the services are setup, you can rapidly connect PHP behind the scenes to ActionScript out front. Slick

So, lately, however, I have been building more JavaScript, AJAX-type, PHP systems typically with MySQL databases behind them all. A good friend of mine wanted a super simple project file management application for his website where clints would be able to login and see files relating to their projects. This is by no means a monumental task in PHP/MySQL or in HTML/JavaScript/CSS. Actually, it's a pretty simple application to build. But, when you get down to starting something even as simple as this from total scratch, you then realize that even the little simple pages for managing such a system are a bit tedious and not always a lot of fun to build.

In particular for me, the communications between the client side and the server side is always pretty tedious and the JavaScript code tends to be pretty hairy. It isn't that it's all that complex, but just kinda verbose, ya know? It can turn out to be a lot of code, what with all the silly AJAX calls and chained AJAX calls and stuff. At least, I think so. Maybe it stems from my hack-smackery coding?

What I Thought It Should Be

I had always wanted a way to do Flash Remoting in JavaScript. I believe that I should be able to write a function in PHP and then call it in JavaScript, passing it parameters like I would in PHP, and then getting back return values in native JavaScript types. Like this:

PHP Function:

// return a string passed in, but change it before it goes out
public function talkBack( $theySaid = '' ) {
    return $theySaid;
}
 

JavaScript call to PHP function:

myDiv.innerHTML += remoteService.talkBack( "Talk to me, Goose!" );

Output:

Talk to me, Goose!

Is that so much to ask?!

I didn't really search very hard (maybe not at all) for a solution because when I sat there and thought about it, it didn't seem that difficult to do. I might have been a little wrong. What I did end up with, though, was pretty small and very functional and very simple. I thank the programming gods for PHP5 and Reflection API. Can I get a "AMEN!"

So, after an all-nighter of development and testing, here is the product...

How It Works

This one script does two things to make JavaScript to PHP Remoting work. First, it creates JavaScript code for you based on PHP code you write. Second, it acts as the AJAX service call responder used to run said PHP code on behalf of the page that is using said JavaScript code.

When you run the script as a JavaScript include in your web page, you pass it the path portion of the URL that is required to reach the script in making AJAX calls. Example:

<script src="phpService.php?serviceURL=/jsphpremoting" type="text/javascript"></script>

The script creates a bunch of JavaScript code that defines a class that is named after the script filename itself.

var phpService = {

    serviceCall : function () {
        // ...
    }

    // ...

};
 

So, if you leave the filename of the script as, "phpService.php" after downloading it from my website, the JavaScript class will be named, "phpService" (see above). You would then be able to call methods like this:

phpService.methodName( parm1, parm2, callBack );

Methods inside this class are created dynamically (using the Reflection API in PHP5) based on any public methods you place inside the PHP class at the top of the script. So, if you have a public method in the PHP class named, "findProductsByCategory," then you will be able to call the JavaScript method, "phpService.findProductsByCategory()." Example:

Snippet of PHP:

// find products in the $cat category
public function findProductsByCategory( $cat = "" ) {
    // pretend we have a private variable that is a Database class with a query() method
    $this->db->query( "SELECT * FROM 'catalog_db`.`product` WHERE `category`='{$cat}'" );
    // also pretend that our Database class will tell us if rows were returned
    if( $this->db->numRows() ) {
        // simply return the resulting rows from the query
        return $this->db->results;
    }
    // return an empty array (no products found)
    return array();
}

Snippet of JavaScript:

// call the remote PHP method to get the products in a category
phpService.findProductsByCategory(
    // product category string (first parameter to PHP function)
    "Spatulas",
    // callback function to deal with return value
    function ( r ) {
        // the return value is passed into this function
        // in this case, an associative array, or database resultset
        if( r.length ) {
            // there are rows in the result
            for( var p = 0; p < r.length; p++ ) {
                myDiv.innerHTML += "Item " + ( p + 1 ) + ": " + r[p].title + "<br />";
            }
        }
    }
);

Output would be something like this:

Item 1: RubberMatic™ 76 - Non-stick, flexible and super-sweet!
Item 2: Off-Brand stainless steel, medium size
Item 3: Titanium Broadhead with compass in handle
...

How To Use JavaScript to PHP Remoting

Just build your page, include the script in a script tag and pass it the location where it sits in your URL structure using the serviceURL GET parameter, write your PHP methods, write your JavaScript, and sit back and giggle at how easy it is.

Here is code for a sample page that includes the PHP script and makes it create the JavaScript class that you will ultimately use for making remote method calls:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">

<head>
    <title>Example 1 - XHTML 1.0 Strict as text/html</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <script src="phpService.php?serviceURL=/jsphpremoting" type="text/javascript"></script>
</head>

<body>

    <h1>Example of JavaScript calling remote PHP methods</h1>

    <p>
        Type in something to say to yourself, then click the "Echo It" button.
    </p>

    <p>
        <code id="returnSaid">This will be where the return shows up...</code>
    </p>

    <p>
        What to say:<br />
        <input type="text" id="txtSay" value="" />
    </p>
   
    <p>
        <input type="button" id="btnEcho" value="Echo It" onclick="sendEcho()" />
    </p>

    <script type="text/javascript">
    //<![CDATA[

    function outputEcho( returnVal ) {
        $('returnSaid').innerHTML = returnVal;
    }

    function sendEcho() {
        phpService.echoBack( $('txtSay').value, outputEcho );
    }

    // ]]>

    </script>
 
</body>

</html>

More importantly, here is the snippet of JavaScript from that page that does the call and changes the innerHTML of the "returnSaid" element:

function outputEcho( returnVal ) {
    $('returnSaid').innerHTML = returnVal;
}

function sendEcho() {
    phpService.echoBack( $('txtSay').value, outputEcho );
}

Here is how I would write it to save space and eliminate what I concsider to be unnecessary functions (use anonymous functions where you can, unless it will make your code horribly unreadable):

function sendEcho() {
    phpService.echoBack(
        $('txtSay').value,
        function ( returnVal ) {
            $('returnSaid').innerHTML = returnVal;
        }
    );
}

Here is the snippet of code for the phpService.php script that makes this page go zoom:

class RemoteMethods extends JavaScriptPHPRemoteMethods {

    // return a string passed in from JavaScript
    public function echoBack( $theySaid = '' ) {
        return $theySaid;
    }

}

// more internal stuff below here left out for the sake of example here
// ...

Test Calls and Returns

I threw this in here at the bottom to show the various return types and as a good way for you to cut-n-paste examples of various method calls and return types.

PHP code for test phpService.php script:

<?php

class RemoteMethods extends JavaScriptPHPRemoteMethods {


    //
    // Use private methods for utility in your public JS-visible methods
    //

    private $myPrivateVar;

    private function setupPrivateVar( $addOn = "" ) {
        $this->myPrivateVar = "This is private. " . $addOn;
    }


    //
    // JavaScript-visible methods (put your methods here)
    //

    // return a simple array
    public function getArray() {
        return array( "One", "Two", "Three" );
    }

    // return a string passed in
    public function echoBack( $theySaid = '' ) {
        return $theySaid;
    }

    // return a string passed in, but change it before it goes out
    public function echoBackWithChange( $theySaid = '' ) {
        $weSaid = "You told me, \"{$theySaid}\" and I say, \"Fooey!\"";
        return $weSaid;
    }

    // just add some numbers together and return the result
    public function addThreeNumbers( $a = 0, $b = 0, $c = 0 ) {
        return $a + $b + $c;
    }

    // setup and then return a private variable
    public function getPrivateVar() {
        $this->setupPrivateVar( "So do not say anything!" );
        return $this->myPrivateVar;
    }

    // return an associative array (JS will see an object)
    public function getAnAssociative() {
        return array(
            "id" => 17,
            "name" => "Bob",
            "state" => "Arizona",
            "alive" => true,
            "kids" => array( "Sam", "Sue", "Sally" )
        );
    }

    // return a property of an object that was passed in from JS
    // note: this also demonstrates how exceptions are thrown cross-language
    public function showProperty( $obj, $propName = "" ) {
        if( empty( $propName ) ) {
            throw new Exception( "Please give me a property name." );
        }
        if( !isset( $obj->$propName ) ) {
            throw new Exception( "Object has no property by the name of '{$propName}'." );
        }
        return $obj->$propName;
    }


} // end of remote methods class

//
// There is more below here in the full PHP script, but it is eliminated here because it isn't necessary
// for this test/demonstration. -af
//

?>

 

JavaScript code on this page that outputs test values below:

    function trace( msg ) {
        $("trace").innerHTML += msg + "<br />\n";
    }

    phpService.getArray(
        function ( r ) {
            trace( "<strong>getArray()</strong>" );
            for( var i = 0; i < r.length; i++ ) {
                trace( "r[" + i + "] = " + r[i] );
            }
            trace( "<br />" );
        }
    );

    // return a string passed in
    phpService.echoBack(
        "Hi from JavaScript",
        function ( r ) {
            trace( "<strong>echoBack()</strong>" );
            trace( r + "<br />" );
        }
    );

    // return a string passed in, but change it before it goes out
    phpService.echoBackWithChange(
        "Hi from JavaScript",
        function ( r ) {
            trace( "<strong>echoBackWithChange()</strong>" );
            trace( r + "<br />" );
        }
    );

    // just add some numbers together and return the result
    phpService.addThreeNumbers(
        function ( r ) {
            trace( "<strong>addThreeNumbers()</strong>" );
            trace( r + "<br />" );
        }
    );

    // setup and then return a private variable
    phpService.getPrivateVar(
        function ( r ) {
            trace( "<strong>getPrivateVar()</strong>" );
            trace( r + "<br />" );
        }
    );

    // return an associative array (JS will see an object)
    phpService.getAnAssociative(
        function ( r ) {
            trace( "<strong>getAnAssociative()</strong>" );
            trace( "id: " + r.id );
            trace( "name: " + r.name );
            trace( "state: " + r.state );
            trace( "alive: " + ( r.alive ? "Yes" : "No" ) );
            for( var k = 0; k < r.kids.length; k++ ) {
                trace( "kid #" + k + ": " + r.kids[k] );
            }
            trace( "<br />" );
        }
    );

    // return a property of an object that was passed in from JS
    // note: this also demonstrates how exceptions are thrown cross-language
    var now = new Date();
    var transaction = { id: 184736, started: now, amount: 12.75 };
    phpService.showProperty(
        transaction, "amount",
        function ( r ) {
            trace( "<strong>showProperty()</strong>" );
            trace( "transaction.amount is " + r + "<br />" );
        }
    );

 

Output from test method calls (LIVE! This is written by actual JavaScript as the page loads!):