Section 15.1. Using Atlas with PHP


15.1. Using Atlas with PHP

To use Atlas with PHP, you must first create a PHP web page. The page that we'll create to demonstrate Atlas with PHP contains an HTML text box and Atlas xml-script to add autocomplete functionality to the text box. However, to add the Atlas functionality we need, the Atlas client libraries must be loaded into the page. To do this, create a new folder in your web site named ScriptLibrary/Release. (For example, if your web site is at C:\Atlas\, create a folder named C:\Atlas\ScriptLibrary\Release.) Access the libraries using the Windows Start menu (see the beginning of this chapter) and copy the files Atlas.js, AtlasCompat.js, and AtlasCompat2.js (release versions) into the new ScriptLibrary/Release folder.

This chapter assumes that you have PHP working on your computer. You can download the PHP libraries from the PHP site at http://www.php.net/downloads.php. Follow the installation instructions carefully.

To run a PHP file under IIS, you must use IIS (the ASP.NET Development Server will not run .php files). The PHP installation instructions include information on performing PHP installation on IIS and also on other web servers like Apache. On this web site, you will find information about the central PHP configuration file, php.ini. There, you will have to add the following line to enable PHP to access Microsoft SQL Server data sources:

 extension=php_mssql.dll 

The PHP manual page (http://php.net/mssql) contains more information regarding PHP's MSSQL support, including instructions how to access Microsoft SQL Server instances from a Unix or Linux platform.

You can create and run .php files in the same folder or folders you've been using for the other examples from this book.

Finally, you need to download and install the JSON.php file, which is used to encode and decode JSON-formatted data. You can get the JSON.php library at http://pear.php.net/pepr/pepr-proposal-show.php?id=198. Although this PEAR proposal was accepted by the PEAR community in 2005, there is still no official package. At the URL, you not only get information about the JSON parser, but also a .tgz archive (http://mike.teczno.com/JSON.tar.gz). This file currently does not work with the PEAR installer, so the command pear install http://mike.teczno.com/JSON.tar.gz will generate an error message. However, if you extract the archive's contents, you will getamong some other filesthe script JSON.php that contains the parser information. Regularly check http://mike.teczno.com/json.html for information regarding new releases or an eventual conversion into an official PEAR package.


The source code downloads for this book do not contain these JavaScript library files, so you must copy them from the most current Atlas release into the ScriptLibrary/Release folder.


The page must load the main Atlas library (Atlas.js). Depending on the browser type, one or two additional compatibility libraries might also be required on the page. The code in 15-1 shows a PHP page that includes Atlas functionality. (When you create this page, you must name it with a .php extension, of course.) The page shows how to use PHP code to conditionally load an Atlas .js library depending on browser type. For example, if the user agent string contains "opera", the code loads the AtlasCompat.js library. If the user agent string contains "safari", both the AtlasCompat.js and AtlasCompat2.js libraries are loaded.

Example 15-1. A PHP page that loads Atlas libraries

 TextBoxMask.aspx <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head>   <title>Atlas</title>   <?php     $browser = strtolower($_SERVER['HTTP_USER_AGENT']);     if (strpos($browser, 'gecko') !== false ||         strpos($browser, 'opera') !== false ||         strpos($browser, 'safari') !== false ||         strpos($browser, 'konqueror') !== false) {       echo '<script type="text/javascript" src="/books/3/491/1/html/2/ScriptLibrary/Release/AtlasCompat .js"></script>' . "\r\n";     }   ?>   <script type="text/javascript" src="/books/3/491/1/html/2/ScriptLibrary/Release/Atlas.js"></script>   <?php     if (strpos($browser, 'safari') !== false ||         strpos($browser, 'konqueror') !== false) {       echo '<script type="text/javascript" src="/books/3/491/1/html/2/ScriptLibrary/Release/AtlasCompat2 .js"></script>' . "\r\n";     }   ?> </head> <body>   <form action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>"     method="post">     <div>       <input type="text"  />     </div>   </form>   <script type="text/xml-script">     <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">       <components>     <control >       <behaviors>         <autoComplete           serviceURL="AutoCompleteService.php" serviceMethod="GetVendors"           minimumPrefixLength="3" />       </behaviors>     </control>       </components>     </page>   </script> </body> </html> 

In the xml-script for Example 15-1, the AutoCompleteService.php file is the web service invoked by the autocompletion behavior. This pseudoweb service .php file must contain the logic for returning a list of matching elements. The method called to fetch names is GetVendors(). It will look roughly like the following code. Like the ASP.NET version, this PHP code uses SQL Server 2005 Express Edition and the AdventureWorks sample database. (Naturally, you could use any other database and sample data.)

 function GetVendors($prefixText, $count) {   if (!is_string($prefixText)) {     return;   }   $count = ($count > 0) ? min($count, 10) : 10;   ini_set('magic_quotes_sybase', 1);   $prefixText = addslashes($prefixText);   ini_set('mssql.secure_connection', 1);   $db = mssql_connect('(local)\SQLEXPRESS');   mssql_select_db('AdventureWorks', $db);   $result = mssql_query(     "SELECT Name FROM Purchasing.Vendor WHERE Name LIKE '$prefixText%'");   $results = array();   while ($row = mssql_fetch_row($result) && count($results) < $count) {     $results[] = $row[0];   }   mssql_close($db);   return $results; } 

A bit more complicated is the code that processes the request to the "web service." As with the ASP.NET version, the PHP script file is called with a suffix of /js. When the PHP program detects this suffix, it must create a proxy script and make it available to the client. The JavaScript code for the proxy looks like the following (assuming that the script resides in http://localhost/Atlas/):

 var AutoComplete = new function() {   this.path = "http://localhost/Atlas/AutoCompleteService.php";   this.appPath = "http://localhost/Atlas/";   Sys.Net.ServiceMethod.createProxyMethod(this, "GetVendors",     "prefixText", "count");   Sys.Net.ServiceMethod.createProxyMethod(this, "processRequest"); } 

The path data must be determined dynamically in code and then injected into the page, but only if the requested URL ends in js. The following PHP code shows how this dynamic generation can be done:

 $path = $_SERVER['REQUEST_URI']; if (substr($path, strlen($path) - 2) == 'js') {   $applicationRoot = dirname($_SERVER['SCRIPT_NAME']);   $pathWithoutProxy = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];   $pathWithoutProxy = substr($pathWithoutProxy, 0, strlen($pathWithoutProxy) - 3);   $pathWithoutProxy = addslashes($pathWithoutProxy);   $documentRoot = 'http://' . $_SERVER['SERVER_NAME'] . $applicationRoot . '/';   $documentRoot = addslashes($documentRoot);   echo "var AutoComplete = new function() {     this.path = \"$pathWithoutProxy\";     this.appPath = \"$documentRoot\";     Sys.Net.ServiceMethod.createProxyMethod(this, \"GetVendors\", \"prefixText\", \"count\");     Sys.Net.ServiceMethod.createProxyMethod(this, \"processRequest\");     } "; } 

Some web servers misinterpret the URL AutoCompleteService.php/js and assume that AutoCompleteService.php is the name of a directory, and js is a file (or folder) within that directory. Then, of course, the proxy generation will fail. Under Apache, the following directive for the httpd.conf configuration file makes the web server comply with our script if you get an HTTP error 404 when calling AutoCompleteService.php/js:

 AcceptPathInfo On 

Under some IIS installations, the PHP ISAPI module can trigger this behavior. In this case, use PHP in CGI mode instead.


The remainder of the script AutoCompleteService.php takes care of the situation when the proxy is not generated, but a web service method is called instead (using the proxy). Tracing the HTTP traffic while running the AutoComplete extender within Atlas and ASP.NET 2.0 shows that the framework calls the web service script (one the user entered three characters or more in the text field) and appends ?mn=<MethodName> to the URL. The prefix text and the maximum number of results to return are submitted in JSON format in the body of the request.

In our example, the data expected from the client consists of JSON data with two entries: prefixText and count. This data is extracted from the HTTP request using $GLOBALS['HTTP_RAW_POST_DATA'] and then decoded using the JSON.php library. In the next step, the GetVendors() method is called to determine all suitable database entries for the given prefix. This resulting data is then encoded back into JSON and returned. (It's trivial to encode data in JSON format manually, but since we are already using the JSON library, why bother investing too much effort into our own code?) This is what the processRequest method looks like, which performs all of these tasks:

 function processRequest() {   $path = $_SERVER['REQUEST_URI'];   if (substr($path, strlen($path) - 2) == 'js') {     $applicationRoot = dirname($_SERVER['SCRIPT_NAME']);     $pathWithoutProxy = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];     $pathWithoutProxy = substr($pathWithoutProxy, 0, strlen($pathWithoutProxy) - 3);     $pathWithoutProxy = addslashes($pathWithoutProxy);     $documentRoot = 'http://' . $_SERVER['SERVER_NAME'] . $applicationRoot . '/';     $documentRoot = addslashes($documentRoot);     echo "var AutoComplete = new function() {       this.path = \"$pathWithoutProxy\";       this.appPath = \"$documentRoot\";       Sys.Net.ServiceMethod.createProxyMethod(this, \"GetVendors\", \"prefixText\", \"count\");       Sys.Net.ServiceMethod.createProxyMethod(this, \"processRequest\");       } ";   } else if (!isset($_GET['mn']) || $_GET['mn'] != 'GetVendors') {     exit();   } else {     $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);     $postData = trim($GLOBALS['HTTP_RAW_POST_DATA']);     if (strlen($postData) > 0) {       $argsAsParams = $json->decode($postData);       if (isset($argsAsParams['prefixText']) &&           isset($argsAsParams['count'])) {         $returnValue = $this->GetVendors(           $argsAsParams['prefixText'],           $argsAsParams['count']);         echo $json->encode($returnValue);       }     }   } } 

This completes the PHP class that implements the web service and proxy generator for the AutoComplete extender. All that is left to do is to instantiate the class when the file is loaded and call the processRequest() method. 15-2 shows the complete code, with that final task as the last two lines of the program

Example 15-2. The PHP Atlas compatible pseudo web service

 AutoCompleteService.php <?php require 'JSON.php'; class AutoComplete {   function GetVendors($prefixText, $count) {     if (!is_string($prefixText)) {       return;     }     $count = ($count > 0) ? min($count, 10) : 10;     ini_set('magic_quotes_sybase', 1);     $prefixText = addslashes($prefixText);     ini_set('mssql.secure_connection', 1);     $db = mssql_connect('(local)\SQLEXPRESS');     mssql_select_db('AdventureWorks', $db);     $result = mssql_query(       "SELECT Name FROM Purchasing.Vendor WHERE Name LIKE '$prefixText%'");     $results = array();     while ($row = mssql_fetch_row($result) && count($results) < $count) {       $results[] = $row[0];     }     mssql_close($db);     return $results;   }   function processRequest() {     $path = $_SERVER['REQUEST_URI'];     if (substr($path, strlen($path) - 2) == 'js') {       $applicationRoot = dirname($_SERVER['SCRIPT_NAME']);       $pathWithoutProxy = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];       $pathWithoutProxy = substr($pathWithoutProxy, 0, strlen($pathWithoutProxy) - 3);       $pathWithoutProxy = addslashes($pathWithoutProxy);       $documentRoot = 'http://' . $_SERVER['SERVER_NAME'] . $applicationRoot . '/';       $documentRoot = addslashes($documentRoot);       echo "var AutoComplete = new function() {         this.path = \"$pathWithoutProxy\";         this.appPath = \"$documentRoot\";         Sys.Net.ServiceMethod.createProxyMethod(this, \"GetVendors\", \"prefixText\", \"count\");         Sys.Net.ServiceMethod.createProxyMethod(this, \"processRequest\");         } ";     } else if (!isset($_GET['mn']) || $_GET['mn'] != 'GetVendors') {       exit();     } else {       $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);       $postData = trim($GLOBALS['HTTP_RAW_POST_DATA']);       if (strlen($postData) > 0) {         $argsAsParams = $json->decode($postData);         if (isset($argsAsParams['prefixText']) &&             isset($argsAsParams['count'])) {           $returnValue = $this->GetVendors(             $argsAsParams['prefixText'],             $argsAsParams['count']);           echo $json->encode($returnValue);         }       }     }   } } $ac = new AutoComplete(); $ac->ProcessRequest(); ?> 

As you can see, the code can get to be a bit more complicated than the corresponding code in ASP.NET. But the important point is that you can take advantage of Atlas even though you may not be using ASP.NET 2.0. See Figure 15-1 for the result in the browser; apart from the PHP URL, you can't see any obvious difference from the ASP.NET 2.0 version of the example.

Figure 15-1. The same example as before, but this time using PHP


The code in this example runs under both PHP 4 and PHP 5. The code in Shanku Niyogi's blog is for PHP 5 only, but it is more generic and can be easily and quickly adapted to other scenarios.

One of the new features of PHP 5 is a reflection API, which is used in Shanku's example to automatically determine all methods of the current class and their parameters. This API makes calling pseudo web methods in the PHP script much easier. Of course, if you have a limited set of methods to call, as in our example, then a more specific implementation (like in this chapter) is a viable alternative.





Programming Atlas
Programming Atlas
ISBN: 0596526725
EAN: 2147483647
Year: 2006
Pages: 146

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net