<?php
//echo('ClassServer');
/*******************************************************************************
* JsrsServer.class.php - JavaScript Remote Scripting server 
*   
* This is the PHP-version of the JavaScript Remote Scripting server 
* Look at the provided sample to see how to use it.
* Mainly it's:
*
*    // Include the JsrsServer
*    require("../lib_server/JsrsServer.class.php");
*
*    -- Yor code here --
*  
*    // propergate the methodes and functions that are available for the client
*    $JsrsServer->propergateMethod(<object name> , <methode name>);
*    $JsrsServer->propergateMethod(<object name> , <methode name>);
*    $JsrsServer->propergateFunction(<function name>);
*
*    // Start the JsrsServer to handle the request from the client
*    $JsrsServer->start();
*
* @doc    http://js-rs.sourceforge.net
* @source http://sourceforge.net/projects/js-rs/
* ------------------------------------------------------------------------------
* @Requirements : PHP 4.0 with WDDX installed (see PHP manual)
* ------------------------------------------------------------------------------
* @Version: 3.0 beta CVS $Revision: 1.2 $ (April-2002)
* See history.txt for full history
* ------------------------------------------------------------------------------
* Some Notes:
*   The PHP WDDX implementation is limited and some basic types are not suported.
*   Missing Tags (See PHP Bug report : http://bugs.php.net/bug.php?id=16716)
*   - The <dataTime>-tag :
*     In PHP 4.0.0 - current(PHP 4.2.0) it's just ignored(!). That means the
*     javascript Date-type can *not* be supported. You must transform it to a
*     string.
*   - The <recordset>-tag :
*     Is supported since PHP 4.2. But this has *no* major influence. Javascript
*     types are never transformed to WDDX with the use of the <recordset>-tag.
*
*   Real Object Support
*   - Objects in WDDX are very poorly and inconsistently supported 
*     (Found that out *after* implementation :-( ).
*     All Javascript-Objects will translate to hash arrays in PHP;
*     *unless* you add a fieldname 'php_class_name' in your javascript object 
*     with the PHP class name in it. PHP will then try to create that class.
*     But try to live without it.
* ------------------------------------------------------------------------------
* @Author:  Sam   Blum   [bs_php@users.sourceforge.net] Collected all the ideas,
*           merged and rewrote them and added doc.
*   Inspired by:  Brent Ashley [jsrs@megahuge.com] initial Autor of jsrs V1 and
*                 V2. See http://ashleyit.com/rs/main.htm
*   Inspired by:  Danne  [dotvoid@dotvoid.com] remote call *without* iframe
*   Inspired by:  Eric Costello
*           http://www.oreillynet.com/pub/a/javascript/2002/02/08/iframe.html
*   Inspired by:  Nate Weiss [nweiss@icesinc.com]  See www.openwddx.org
* ------------------------------------------------------------------------------
* @Copyright see license.txt for copyright and license info
*******************************************************************************/

class JsrsServer {
  
  var $lastErr = '';
  var $propergateList = array();
  
  /*****************************************************************************
  * Propergate a Object Methode
  *
  * @param object [object]: Is an instance of the object that holds the method
  *   to be called
  * @param methodName [stirng]: The method-name that is to be propergated.
  * @return [bool] TRUE on success otherwise FALSE 
  */
  function propergateMethod(&$object, $methodName)
  {
    $status = FALSE;
    $err = '';
    do { // try-block
      if (empty($object))
      {
        $methodID = $methodName;
      }else
      {
        if (!method_exists($object, $methodName))
        {
          $err = "Not an Object or not existing method in the suplied object!";
          break; // try-block
        }
        $methodID = get_class($object) . '.' . $methodName;
      }
      $this->propergateList[$methodID] = array('object'=>&$object, 'method'=>$methodName);
      $status = TRUE;
    } while (FALSE);
    
    if (!$status)
    {
      $file = basename($file);
      user_error("In [{$file}:{$line}] Failed to register '" . get_class($object) ."->". $methodName ."'. {$err}" , E_USER_ERROR);
    }
    return $status;
  }
  
  /*****************************************************************************
  * Propergate a Function
  *
  * @param functionName [stirng]: The function-name that is to be propergated.
  * @return [bool] TRUE on success otherwise FALSE 
  */
  function propergateFunction($functionName) {
    return $this->propergateMethod($dummy=NULL, $functionName);
  }
  
  /*****************************************************************************
  * Start handling the request from the client
  * 
  * Read out the passed query params from the client and check if the method 
  * (or function) is available. That means if it was propergated before 
  * (see propergated-methods).
  * Call the method (or function) and return the data in a WDDX format.
  *
  * The client query params are:
  *   jsrsC [<stirng>]   : Call ID - A unique call identifier that is passed back.
  *   jsrsF [<stirng>]   : Method call (<class>.<methode>) of function call
  *                        (<function>)
  *   jsrsP [<stirng>]   : Parameter - (squeezed) WDDX formated and escaped
  *                         data-array.
  *   jsrsZ [<stirng>]   : Use Squeezed WDDX. If set then use the squeezed
  *                        WDDX format.
  *   jsrsR ['js'|'html']: Return Mode - The client is expecting html (with js)
  *                        or a pure js-call
  */
  function start() {
    $status = FALSE;
    $err = '';
    $ret = null;
    $squeezedWDDX = array('<a l','</a>','<r t','<r>','</r>','<v n','</v>','<b v','<s>','</s>','<n>','</n>','<dT>','</dT>');
    $expandedWDDX = array('<array length','</array>','<struct type','<struct>','</struct>','<var name','</var>','<boolean value','<string>','</string>','<number>','</number>','<dateTime>','</dateTime>');
    
    if (!isSet($_REQUEST)) { // For PHP 4.0.x and below. Emulate the $_REQUEST that is used in PHP4.1 and up
      global $HTTP_POST_VARS;
      global $HTTP_GET_VARS;
      if (!isSet($HTTP_POST_VARS)) $HTTP_POST_VARS = array();
      if (!isSet($HTTP_GET_VARS))  $HTTP_GET_VARS = array();
      $_REQUEST = array_merge($HTTP_GET_VARS, $HTTP_POST_VARS);
    }
    // Get the request query vas
    $callID     = empty($_REQUEST['jsrsC']) ? ''     : $_REQUEST['jsrsC'];
    $methodID   = empty($_REQUEST['jsrsF']) ? ''     : strtoLower($_REQUEST['jsrsF']);
    $param      = empty($_REQUEST['jsrsP']) ? ''     : $_REQUEST['jsrsP'];
    $squeezWDDX = isSet($_REQUEST['jsrsZ']) ? TRUE   : FALSE;
    $returnLang = empty($_REQUEST['jsrsR']) ? 'html' : strtoLower($_REQUEST['jsrsR']);
    
    // Strip quotes for incoming GET/POST/Cookie data ONLY if PHP's Magic quotes is active.
    if (ini_get('magic_quotes_gpc')) $param = stripslashes($param);
    
    do { // try-block
      // Check if WDDX extention is instaled
      if (!function_exists ("wddx_deserialize")) {
        $err = "Server ERROR: Sorry, the PHP WDDX-package is currently *not* instaled on this SERVER.\n(Web-Master: See PHP manual for installation of WDDX.)";
        break; // try-block
      }
      
      if (!empty($param)) {
        if (isSet($_REQUEST['jsrsE'])) $param = rawurldecode($param);
        // Expand compressed WDDX (only used with GET because URL length is limited)
        $param = str_replace($squeezedWDDX, $expandedWDDX, $param);
        $param = wddx_deserialize($param);
      }
      
      if (!isSet($this->propergateList[$methodID])) {
        $err = $methodID . " is not a known function or method.\n";
        if (sizeOf($this->propergateList)) {
          $err .=  "Propergated methods:\n";
          foreach($this->propergateList as $methodName=>$val) {
            $err .= "\t" . $methodName ."\n";
          }
        } else {
          $err .=  "*NO* methods propergated!";
        }
        break; // try-block
      }
      $methodDesc = $this->propergateList[$methodID];
      if (empty($methodDesc['object'])) {
        $ret = $methodID($param);
      } else {
        $ret = $methodDesc['object']->$methodDesc['method']($param);
      }
      $status = TRUE;
    } while(FALSE);
    
    // Translate 
    if ($status) {
      $retWddx = wddx_serialize_value($ret);
      if ($squeezWDDX) $retWddx = str_replace($expandedWDDX, $squeezedWDDX, $retWddx);
      $retWddxEsc = urlencode($retWddx);
    }
    
    if ($err) $err = urlencode($err);
    $jsCall = "window.parent.jsrsReturn('{$callID}','{$retWddxEsc}','{$err}');";
    switch ($returnLang){
      case 'js':
        $out = $jsCall;
        break;
      default :
        $out =<<<EOD
          <html>
          <body onload="{$jsCall}">
          Remote Return Value (for debug purpose only):<br>
          <form name="jsrs_Form">
            <textarea cols="80" rows="10" name="jsrsWddxReturn">
              {$retWddx}
            </textarea>
          </form>
          </body></html>
EOD;
    }// switch end
    echo $out;
    exit;
  }
  
}

// Pseudostatic
$JsrsServer = new JsrsServer();
?>

