Resin 4 built-in fast PHP support called Quercus : covers Java integration, JSON support and more
From Resin 4.0 Wiki
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
- Navigate to http://www.caucho.com/download
- Download the latest Resin binary for your operating system.
- For purposes of this demo, I have downloaded the Windows .zip binary. The non-pro version is open-source.
- Save the file to your desktop.
- Double click the binary and unzip the file.
- For purposes of this demo, I have unzipped the contents to C:\resin-3.2.0
Running Resin for the first time
- Browse to the directory into which you unzipped the resin download (ie: C:\resin-3.2.0)
- Double-click resin.exe. At this point the resin web server should start.
- Open your favorite browser and type in the following URL: http://localhost:8080
- You will now see Resin's Default Home Page
Part II: Configuring Resin to Serve PHP Pages
- Cut and paste the "resin-web.xml" into your favorite text editor.
- 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").
- Cut and paste the "hello-world.php" into your text editor.
- Save the file into C:\resin-3.2.0\webapps\ROOT
- 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
- Official JSON Homepage
- JSON Wikipedia entry
- Caucho's JSON Wiki entry
- <a href="http://www.aurore.net/projects/php-json">C Implementation from which Quercus' JSON syntax is based off of </a>
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:
- Creating a PDO object with
new PDO(url)
- Querying a SQL statement with results with
$pdo->query(sql)
- 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(); }