Resin 4 built-in fast PHP support called Quercus : covers Java integration, JSON support and more

From Resin 4.0 Wiki

(Difference between revisions)
Jump to: navigation, search
(Created page with "=Quercus Tutorials= =Quercus: Hello, World installation= <p>The Hello, World tutorial covers the basic steps to start Resin and run a trivial php script in Quercus....")
 
 
Line 1: Line 1:
 +
{{Cookbook}}  {{Development}}
 
=Quercus Tutorials=
 
=Quercus Tutorials=
 
=Quercus: Hello, World installation=
 
=Quercus: Hello, World installation=

Latest revision as of 00:00, 16 June 2012

Cookbook-48.png

Construction-48.png

Contents

Quercus Tutorials

Quercus: Hello, World installation

The Hello, World tutorial covers the basic steps to start Resin and run a trivial php script in Quercus.

Files in this tutorial

File Description
WEB-INF/resin-web.xml web.xml configuration
hello.php The PHP Hello, World

Introduction

This short article is intended for PHP programers who are interested in trying Caucho's PHP implementation. The download and unzipping instructions are intended for windows users. However, the implementation will work just as well in UNIX.


Part I: Installing Resin

Downloading and unzipping Resin

  1. Navigate to http://www.caucho.com/download
  2. Download the latest Resin binary for your operating system.
  3. For purposes of this demo, I have downloaded the Windows .zip binary. The non-pro version is open-source.
  4. Save the file to your desktop.
  5. Double click the binary and unzip the file.
  6. For purposes of this demo, I have unzipped the contents to C:\resin-3.2.0


Running Resin for the first time

  1. Browse to the directory into which you unzipped the resin download (ie: C:\resin-3.2.0)
  2. Double-click resin.exe. At this point the resin web server should start.
  3. Open your favorite browser and type in the following URL: http://localhost:8080
  4. You will now see Resin's Default Home Page


Part II: Configuring Resin to Serve PHP Pages

  1. Cut and paste the "resin-web.xml" into your favorite text editor.
  2. Save the file into C:\resin-3.2.0\webapps\ROOT\WEB-INF (NB: if you use Notepad, then be careful to either save as "all files" or just put the file name in double quotes. IE: "resin-web.xml").
  3. Cut and paste the "hello-world.php" into your text editor.
  4. Save the file into C:\resin-3.2.0\webapps\ROOT
  5. Open your favorite browser and type in the following URL: http://localhost:8080/hello-world.php.

WEB-INF/resin-web.xml

<web-app xmlns="http://caucho.com/ns/resin">
   <servlet-mapping url-pattern="*.php"
                    servlet-class="com.caucho.quercus.servlet.QuercusServlet">
   </servlet-mapping>
</web-app>

hello-world.php

<?php
   echo "Hello World";
?>


Conclusion

If all went well with the above steps, you have installed Resin correctly. Congratulations!

You can now create your own PHP pages and store them in the same directory as the hello-world.php file.

Quercus: Java and PHP integration

Adding PHP functions with a Java module.

Files in this tutorial

File Description
hello.php The PHP Hello, World
WEB-INF/classes/example/HelloModule.java The Java module definition
WEB-INF/resin-web.xml web.xml configuration
WEB-INF/classes/META-INF/services/com.caucho.quercus.QuercusModule Adding the module

Introduction

This article shows how to use Quercus, Resin's PHP implementation, to create a module in Java callable from a PHP page.

For purposes of this article, I assume that you are working with Resin 3.2.0 with the home directory at C:\resin-3.2.0. I will call this directory $webApp.


Step 1: Create resin-web.xml and place it in $webApp/WEB-INF

resin-web.xml

<web-app xmlns="http://caucho.com/ns/resin">
   <servlet servlet-name="resin-php"
               servlet-class="com.caucho.quercus.servlet.QuercusServlet"/>
 
   <servlet-mapping url-pattern="*.php" servlet-name="resin-php"/>	   
</web-app>


Step 2: Create HelloModule.java and place it in $webApp/WEB-INF/classes/example

HelloModule.java

package example;
 
import com.caucho.quercus.module.AbstractQuercusModule;
 
public class HelloModule extends AbstractQuercusModule {
   /*
   ** Notice the careful use of the naming
   ** convention hello_test.  This is done
   ** in order to prevent name collisions
   ** among different libraries.
   */
   public String hello_test(String name)
   {
     return "Hello, " + name;
   }
}

Step 3: Create com.caucho.quercus.QuercusModule and place it in $webApp/WEB-INF/classes/META-INF/services

com.caucho.quercus.QuercusModule

example.HelloModule

Step 4: Create hello.php and place it in webapps/ROOT

hello.php

<?php echo hello_test("World") ?>

In your favorite browser, type:

==

 http://localhost:8080/hello.php

You should see:

results

 Hello, World


Advanced Users

The first argument of a Java function may be the Env. The Env provides access to Quercus resources like printing to the browser and retrieving a PHP ini value. For the API of Env, refer to the Quercus javadoc.

==


package example;

import com.caucho.quercus.env.Env;
import com.caucho.quercus.module.AbstractQuercusModule;
 
public class HelloModule extends AbstractQuercusModule {
   /*
   ** Notice the careful use of the naming
   ** convention hello_test.  This is done
   ** in order to prevent name collisions
   ** among different libraries.
   **
   ** @param env provides access to Quercus environment resources
   ** @param name
   */
   public String hello_test(Env env, String name)
   {
     env.println("inside HelloModule  hello_test()");
     return "Hello, " + name;
   }
}

Now hello_test will print "inside HelloModule hello_test()" to the browser before returning.


Java Function Arguments/Return Marshaling

Quercus does marshaling to and from Quercus Values and Java objects. If a Java function requires a String, Quercus will automatically convert the internal Quercus StringValue to a String. If a Java function returns an int, Quercus will create a Quercus LongValue for it.

For other Java Objects like java.util.Date that are returned to PHP, Quercus puts them into wrappers to expose their public methods and members to the PHP script. Java Collection, List, and Map instances have the additional ability to be used within a PHP script like any other PHP array.

For more information, see [../../doc/quercus-java-integration.xtp Java Interface].


Conclusion

It is fairly straight forward to create your own modules callable from within a Quercus/PHP page. The above tutorial takes through the steps to create the simple hello world application (without needing to "jar-up" your files).

If you want to change your module in any way, all you have to do is resave the ".java" file in the classes\example directory, and Resin will recompile it for you.

You do not need to restart your web app or Resin. It's just that simple.

Quercus JSON

JSON (JavaScript Object Notation) is a popular text data exchange format with built-in support from Quercus since Resin 3.0.20. One of the common uses of JSON in a PHP environment is for the server to send JSON data to the user's browser. Because the JSON language is a subset of JavaScript, JSON-encoded text can be readily parsed on the user's browser using JavaScript's eval() function.

Files in this tutorial

File Description
json.html The JSON example page
json.php The JSON PHP page

Using JSON in Quercus

Quercus has built-in JSON support and JSON functionality is enabled the moment Quercus is started: no additional downloads are required. Quercus sports two PHP functions for working with JSON: json_encode and json_decode.

==

  <b>json_encode(mixed php_object)</b>
        encodes any PHP array or object into JSON.
      
  <b>json_decode(string json_string [, bool is_assoc])</b>
        decodes JSON into a PHP array or object.

json_decode may return either a PHP array or object depending on the circumstances:

  • If the text is that of a JSON array, decoding returns a non-associative PHP array.
  • If the text is that of a JSON object and the second argument to json_decode is not specified or is false, decoding returns a standard PHP object.

  • If the text is that of a JSON object and the second argument to json_decode is true, then decoding returns an associative PHP array.

Examples

json_encode

To encode an array into JSON:

==

 <?php
   $array = array("a"=>"Caucho", "b"=>"Resin", "c"=>"Quercus");
   $json = json_encode($array);
 ?>

The value of $json would be: '{"a":"Caucho", "b":"Resin", "c":"Quercus"}'. The JSON text may then be sent and used on the user's browser or to any client that can decode JSON.

json_decode

To decode JSON data into a standard PHP object in Quercus (using the above JSON text $json as an example):

==

 <?php
  $object = json_decode($json);
 ?>

$object would be a standard PHP object with three fields "a", "b", and "c" with values "Caucho", "Resin", and "Quercus" respectively.

Simple Web Example

Below is a simple example using JSON on the web.

==

 <script type="text/javascript">
 
   <?php
     $array = array("a"=>"Caucho", "b"=>"Resin", "c"=>"Quercus");
     $json = json_encode($array);
     echo "var data = $json;";
   ?>
   
   var decoded = eval("(" + data + ")");
   
   //Should output: "Quercus at work."
   document.write(decoded.c + " at work.");
 </script>

AJAX Example

JSON data is more commonly sent to the browser via AJAX requests. Suppose there are two files defined below. The PHP script in json.php encodes an array into JSON. When the user's browser is directed to json.html, an AJAX request receives JSON data from json.php. Then the browser calls eval() on the JSON data to recover a JavaScript object.

<s3 title="json.php:">

==

 <?php
   $array = array("a"=>"Caucho", "b"=>"Resin", "c"=>"Quercus");
   $json = json_encode($array);
   echo $json;
 ?>

json.html:

==

 <html>
 <head>
 <script type="text/javascript">
  
  var url = "data.php";
  function request() {  
    if (window.XMLHttpRequest)
     http_request = new XMLHttpRequest();
    else
     http_request = new ActiveXObject("Microsoft.XMLHTTP");
    http_request.onreadystatechange = function() {
        handle_json(http_request)
      };
    http_request.open("GET", url, true);
    http_request.send(null);
  }
  
  function handle_json(http_request) {
   if (http_request.readyState == 4) {
    document.firstForm.json.value = http_request.responseText;
    var decoded = eval("(" + http_request.responseText + ")");
    document.firstForm.decoded.value = decoded.a + "'s " +
        decoded.b + " with " + decoded.c + " at work.";
   }
  }
  
  function clearForm() {
   document.firstForm.json.value = "";
   document.firstForm.decoded.value = "";
  }
 </script>
 </head>
 <body>
  <form name="firstForm">
   <p>JSON:<br><textarea name="json" cols="50"></textarea></p>
   <p>Decoded:<br><textarea name="decoded" cols="50"></textarea></p>
   <input type="button" onclick="request()" value="AJAX Request">
   <input type="button" onclick="clearForm()" value="Clear">
  </form>
 </body>
 </html>

</s2>

External Links

Quercus: PDO (portable database object)

The PDO tutorial explains using the new PHP 5 portable database object (PDO) interface.

Files in this tutorial

File Description
WEB-INF/resin-web.xml resin-web.xml configuration
test.php The PDO tutorial

Introduction

This short article introduces PDO, the PHP 5 Portable Database Object interface.

At the minimal level, PDO can be reduced to three statements:

  1. Creating a PDO object with new PDO(url)
  2. Querying a SQL statement with results with $pdo->query(sql)
  3. Executing a SQL statement with $pdo->exec(sql)

PDO has several variations on those three statements, but you can always get by with the first three.

Connecting to the Database: new PDO

The first step in working with databases is to specify which database we're connecting to and create a new connection. The new PDO(url) call creates a new connection to a database. The url describes which database to use. Quercus recognizes the PHP standard urls like mysql:dbname=test and it also can use JNDI names directly like java:comp/env/jdbc/resin.

connecting to a database in JNDI

$pdo = new PDO("java:comp/env/jdbc/resin");


Executing SQL statements: exec

Once the application has connected with a database, it needs to do something, and since relational databases require tables and some data, the application will need to create them. In PDO, the $pdo->exec(sql) method executes arbitrary SQL. We'll use exec to create the database and add some data.

creating the database

$pdo = new PDO("java:comp/env/jdbc/resin");

$pdo->exec(<<<END
CREATE TABLE brooms (
  id INTEGER PRIMARY KEY auto_increment,
  name VARCHAR(255) UNIQUE,
  price INTEGER
)
END)
  or die("Can't create table 'brooms'");

$pdo->exec("INSERT INTO brooms (name, price)"
           . " VALUES ('cleansweep 5', 5)")
  or die("Can't insert data into table 'brooms'");

$pdo->exec("INSERT INTO brooms (name, price)"
           . " VALUES ('cleansweep 7', 15)")
  or die("Can't insert data into table 'brooms'");


Querying the database: query

Once the database has data, we'll want to query the database to see what we've stored. The $pdo->query(sql) method queries the database. For now, we'll use the foreach form of the query.

displaying the data

$pdo = new PDO("java:comp/env/jdbc/resin");

echo "<table>\n"

$sql = "SELECT name, price FROM brooms";
foreach ($pdo->query($sql) as $name => $price) {
  echo "<tr><td>$name<td>$price\n";
}

echo "</table>\n"

Moving forward: CRUD

For basic database access, the three calls we've introduced are sufficient. If you're just starting with PDO, you may want to stop right here, stick with new PDO(url), $pdo->exec(sql), and $pdo->query(sql) with the foreach pattern until you can write PDO code without checking the tutorial. Go ahead, add some foo.php with some sample tables and get learning!

Once you've tattooed the basic three PDO calls into your brain, it's time to start exploring the alternatives PDO provides. We'll introduce some of the main options using the CRUD framework.

CRUD (Create, Read, Update, Delete) is just a simple acronym to organize the basics of any database or persistence application. It's a handy mnemonic when sketching out a prototype, helping to avoid the embarrassment of forgetting to let the user delete an object. And it's handy when learning a new persistence framework or database API to make sure you've covered the bases.


Create

The first step in any database application is to create the database and to create the first entries in the database. In PDO, creating the database table and creating entries can use the same $pdo->exec(sql) call as we introduced above. From a relation database perspective, creating a table is very different from adding a new item, but at the PDO level, they're similar. We'll use the exec call to create the database as above, and then introduce the prepare(sql) call for prepared statements to add items.

creating the database

$pdo = new PDO("java:comp/env/jdbc/resin");

$pdo->exec(<<<END
CREATE TABLE brooms (
  id INTEGER PRIMARY KEY auto_increment,
  name VARCHAR(255),
  price INTEGER
)
END);

Although we could use the basic exec method to add the data, this time we'll introduce prepared statements and the $pdo->prepare(sql) method.

Prepared statements precompile the SQL for a database query and assign parameters for each call. Most importantly, this can create cleaner code. Prepared statements can also avoid some of the security problems associated with web applications. Because the parameter assignment are always values and never raw SQL, Quercus can properly escape the values automatically. Prepared statements can also improve efficiency by allowing the SQL to be parsed only once and then used multiple times.

Prepared statements in PDO split SQL execution into three phases: prepare, bindParam and execute. $pdo->prepare(sql) parses the SQL and returns a PDOStatement object. $stmt->bindParam(...) assigns the parameters to PHP variables. And $stmt->execute() actually executes the statement.

In this example, we'll add some more brooms to the database. This time, we'll loop across a PHP array to insert the values.

inserting with prepare

$pdo = new PDO("java:comp/env/jdbc/resin");

$stmt = $pdo->prepare("INSERT INTO (name, price) VALUES (:name, :price)");

$stmt->bindParam(":name", $name);
$stmt->bindParam(":price", $price);

$brooms = array("nimbus 2000" => 100,
                "nimbus 2001" => 150);

foreach ($brooms as $name => $price) {
  $stmt->execute() or die("Can't add $name to brooms");
}


Read

Because most database accesses are reads, most applications will spend extra time creating useful queries, and optimizing and caching for performance. PDO provides the basic $pdo->query(sql), but it also supports many ways of extracting data.

$pdo->query and foreach

As we described in the introduction, your application can get away with using the basic PDO query pattern. The result of a PDO query can work with the PHP foreach statement to iterate through the rows of the result. Each result will be an associative array of the result values.

==

$pdo = new PDO("java:comp/env/jdbc/resin");

$sql = "SELECT * FROM brooms";

foreach ($pdo->query($sql) as $row) {
  echo $row['name'] . ", " . $row['price'] . "<br>\n";
}


$pdo->query and fetch(PDO::FETCH_ASSOC)

In some cases, an application might need more control over the row iteration than the foreach pattern provides. For example, an application might want to avoid creating a <table> if the database has no data. When more control is needed, PDO lets you split out the iteration from retrieving the row, using $stmt->fetch(...).

The $stmt->fetch(...) call will also let the application choose the type of object it wants to deal with. For now, we'll stick with an associative array.

PDO::FETCH_ASSOC

$pdo = new PDO("java:comp/env/jdbc/resin");

$stmt = $pdo->query("SELECT * FROM brooms") or die();

echo "<table>";
while (($row = $stmt->fetch(PDO::FETCH_ASSOC))) {
  echo "<tr><td>${row['name']}<td>${row['price']}\n";
}
echo "</table>";


fetch(PDO::FETCH_OBJ)

PDO's fetch method provides many options for extracting data from a row other than a full associative list. In particular, you can return a PHP 5 object representing the row. In many cases, the object will be more efficient than an array in PHP programs. Since PHP automatically copies arrays but does not automatically copy PHP 5 objects, you can avoid stressing out the garbage collector by using objects over arrays.

The PHP code for getting an object from a row is identical to the associative array but swapping PDO::FETCH_OBJ for PDO::FETCH_ASSOC. PDO provides many other fetch options as well, but we'll restrict ourselves to PDO::FETCH_OBJ.

PDO::FETCH_OBJ

$pdo = new PDO("java:comp/env/jdbc/resin");

$stmt = $pdo->query("SELECT * FROM brooms") or die();

echo "<table>";
while (($row = $stmt->fetch(PDO::FETCH_OBJ))) {
  echo "<tr><td>$row->name<td>$row->price\n";
}
echo "</table>";


Update

Once an application has data, it will often need to update it. In this case, we'll raise the prices of some of the brooms. As with the creation, PDO's updates use the exec and prepare methods.

Transactions

In this case, though, we'd like some extra reliability, so we'll add some transaction support. Transactions are a generalized lock in a database, allowing multiple statements to execute atomically. That means either all of the statements will update the database or none of them will.

In many examples, the all-or-none property is vital to the integrity of a database. A bank transfer, for example, must deduct a balance from one account and give it to another. Withdrawing from one without adding to the other would be a disaster. In a less critical example, a bulletin board forum which updates a comment's hierarchy might need to change multiple columns at once to avoid corrupting the forum. Although the price of failure is less for a forum, it's still important for producing professional code.

The transaction wraps the SQL statements between a beginTransaction() call and a commit() call. All the SQL statements in between will be executed as one indivisible block (atomic) or the commit will fail.

==

$stmt = $pdo->prepare("UPDATE brooms SET price=:price WHERE name=:broom");

$stmt->bindParam(":broom", $broom);
$stmt->bindParam(":price", $price);

$pdo->beginTransaction();

$brooms = array("nimbus 2000" => 120,
                "nimbus 2001" => 250);

foreach ($brooms as $broom => $price) {
  $stmt->execute();
}

$pdo->commit();


Delete

For completeness, and to clean up the example, we'll need to delete the entries we've added. PDO uses the exec and prepare methods for DELETE just as for INSERT. We'll use the prepared statement method since we'll be deleting several items.

==

$pdo = new PDO("java:comp/env/jdbc/resin");

$stmt = $pdo->prepare("DELETE FROM brooms WHERE name=:name");
$stmt->bindParam(":name", $name);

foreach (array('firebolt', 'nimbus 2000', 'nimbus 2001') as $name) {
  $stmt->execute();
}
Personal tools
TOOLBOX
LANGUAGES