Skip to content
Snippets Groups Projects
Select Git revision
  • d531852d4dc83332d2b04cf4311ccaa07e83d5fa
  • master default protected
  • Legacy_Php7
3 results

sws.class.php

Blame
  • sws.class.php 27.08 KiB
    <?php
    
    /*
     * SIMPLE WEBSERVICE
     * <br>
     * THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE <br>
     * LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR <br>
     * OTHER PARTIES PROVIDE THE PROGRAM ?AS IS? WITHOUT WARRANTY OF ANY KIND, <br>
     * EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED <br>
     * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE <br>
     * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. <br>
     * SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY <br>
     * SERVICING, REPAIR OR CORRECTION.<br>
     * <br>
     * 
     * --- HISTORY:<br>
     * 2014-04-06  0.3  enable/ disable gui; detect class parameters
     * 2014-04-05  0.2  
     * 2014-04-05  0.1  first public beta
     * 
     * url params
     * - class  - classname
     * - action - method to call [classname] -> [method]
     * - args   - arguments  (as json)
     * - type   - outputtype (default: json)
     * 
     * TODOs:
     * - add param for arguments to initialize the class (detect params of __construct())
     * - show an error: detect if a configured method is not public 
     * - parse parameters from phpdoc - detect required and optional params
     * - parse parameters from phpdoc - show input fields for each parameters
     * - configuration: option area
     * - configuration: examples of a class + of actions
     * 
     * @version 0.03
     * @author Axel Hahn
     * @link http://www.axel-hahn.de/php_sws
     * @license GPL
     * @license http://www.gnu.org/licenses/gpl-3.0.html GPL 3.0
     * @package Axels simple web service
     */
    
    class sws {
    
        /**
         * config array with known classnames and its supported methods
         * @var string
         */
        private $_aKnownClasses = array();
    
        /**
         * array of incoming parameters (GET, POST)
         * @var array
         */
        private $_aParams = array();
    
        /**
         * name of the detected classname in the http request
         * @var string
         */
        private $_sClass = false;
    
        /**
         * name of the detected method in the http request
         * @var string
         */
        private $_sAction = false;
    
        /**
         * name of the detected arguments in the http request
         * @var string
         */
        private $_aArgs = array();
    
        /**
         * name of the found class file (by found class it is fetched from config)
         * @var string
         */
        private $_sClassfile = false;
    
        /**
         * relative default dir from sws.class.php to class files in the config
         * @var string
         */
        private $_sClassDir = "";
        //private $_sClassDir = "../php/classes/";
    
        /**
         * output type for the respone to the client
         * @var string
         */
        private $_sOutputType = "json";
    
        /**
         * version
         * @var string 
         */
        private $_sVersion = "0.03&nbsp;(beta)";
    
        /**
         * title
         * @var string
         */
        private $_sTitle = "SWS :: simple&nbsp;web&nbsp;service";
    
        private $_aOptions = array(
            'enableGui'=>true
            );
    
        /**
         * url for documentation
         * @var string
         */
        private $_sUrlDoc = "";
    
        /**
         * url of project home
         * @var string
         */
        private $_sUrlHome = "http://www.axel-hahn.de/php_sws";
    
        // ----------------------------------------------------------------------
        // general functions
        // ----------------------------------------------------------------------
    
        /**
         * constructor
         * @param array $aKnownClasses  array with known classes and supported methods
         * @return boolean
         */
        public function __construct($aKnownClasses = false) {
            if (is_array($aKnownClasses)) {
                $this->setConfig($aKnownClasses);
            }
            return true;
        }
    
        // ----------------------------------------------------------------------
        // private functions
        // ----------------------------------------------------------------------
    
        /**
         * apply a given config
         * @param array $aKnownClasses  array with known classes and supported methods
         * @return bool
         */
        public function setConfig($aKnownClasses) {
            $this->_aKnownClasses = array();
            if (is_array($aKnownClasses)) {
                $this->_aKnownClasses = $aKnownClasses;
                
                if (array_key_exists("options", $aKnownClasses)){
                    $this->_aOptions=array_merge($this->_aOptions, $aKnownClasses["options"]);
                }
                return true;
            }
            return false;
        }
    
        /**
         * parse parameters (given by setParams)
         * @return bool
         */
        private function _parseParams() {
            $aMinParams = array("class", "action");
            $aMaxParams = array_merge($aMinParams, array("args"));
            $sErrors = '';
    
            // set defaults
            $this->_sClass = false;
            $this->_sAction = false;
            $this->_aArgs = array();
    
            if (!$this->_aKnownClasses || !is_array($this->_aKnownClasses)) {
                $this->_quit("ERROR: no configuration was found."
                        . "You can set it with initialisation <br>\n"
                        . "<code>\$o = new " . __CLASS__ . " ( \$aOptions );</code><br>\n"
                        . "or<br>\n"
                        . "<code>\$o = new " . __CLASS__ . " ();<br>\n"
                        . "\$o -> setConfig ( \$aOptions );</code><br>\n"
                );
            }
    
            // check minimal params
            foreach ($aMinParams as $sKey) {
                $bFound = array_key_exists($sKey, $this->_aParams);
                if (!$bFound) {
                    $sErrors.="- <em>" . $sKey . "</em><br>";
                }
            }
            // TODO: checkMaxParams
            // check if classname and action exist in configuration
            if (array_key_exists("class", $this->_aParams)) {
                if (!array_key_exists($this->_aParams["class"], $this->_aKnownClasses["classes"])) {
                    $this->_quit('ERROR: parameter <em>class = ' . $this->_aParams["class"] . '</em> is invalid. I cannot handle this class.', $this->showClasshelp());
                } else {
                    // set internal vars
                    $this->_sClass = $this->_aParams["class"];
                    $this->_sClassfile = $this->_aKnownClasses["classes"][$this->_aParams["class"]]["file"];
                }
                if (array_key_exists("action", $this->_aParams)) {
                    if (!array_key_exists($this->_aParams["action"], $this->_aKnownClasses["classes"][$this->_aParams["class"]]["actions"])) {
                        $this->_quit('ERROR: class ' . $this->_aParams["class"] . ' exists but it has no <em>action = ' . $this->_aParams["action"] . '</em>.', $this->showClasshelp());
                    } else {
                        // set internal vars
                        $this->_sAction = $this->_aParams["action"];
                    }
                }
                if (array_key_exists("args", $this->_aParams)) {
                    try {
                        $aTmp = json_decode($this->_aParams["args"], 1);
                    } catch (Exception $e) {
                        // nop
                    }
                    if (!is_array($aTmp)) {
                        $this->_quit(
                                'ERROR: wrong request - args value must be a json string<br>'
                                . 'examples:<br>'
                                . '- one arg <code>(...)&args=["my string"]</code><br>'
                                . '- two args <code>(...)&args=["my string", 123]</code> '
                                , $this->showClasshelp());
                    }
                    $this->_aArgs = $aTmp;
                }
            }
    
    
            if (array_key_exists("type", $this->_aParams)) {
                $this->setOutputType($this->_aParams["type"]);
            }
            if ($sErrors) {
                $this->_quit('ERROR: wrong request -  a required parameter was not found:<br>' . $sErrors, $this->showClasshelp());
            }
            return true;
        }
    
        /**
         * helper function: parse php doc comment block
         * @param string $sComment
         * @return string
         */
        private function _parseComment($sComment) {
            $sReturn = $sComment;
            if (!$sReturn) {
                return '<div class="warning">WARNING: this object has no PHPDOC comment.</div>';
            }
    
            // all @-Tags
            $aTags = array(
                "abstract", "access", "author", "category", "copyright", "deprecated", "example",
                "final", "filesource", "global", "ignore", "internal", "license",
                "link", "method", "name", "package", "param", "property", "return",
                "see", "since", "static", "staticvar", "subpackage", "todo", "tutorial",
                "uses", "var", "version"
            );
    
            $sReturn = preg_replace('@[\ \t][\ \t]*@', ' ', $sReturn); // remove multiple spaces
    
            $sReturn = preg_replace('@^\/\*\*.*@', '', $sReturn); // remove first comment line
            $sReturn = preg_replace('@.*\*\/@', '', $sReturn);  // remove last comment line
            $sReturn = preg_replace('@ \* @', '', $sReturn);    // remove " * " 
            $sReturn = preg_replace('@ \*@', '', $sReturn);     // remove " *" 
            $sReturn = preg_replace('@(<br>)*$@', '', $sReturn);
            $sReturn = preg_replace('@^\<br\>@', '', $sReturn);
    
    
            /*
              foreach(array("param", "return", "var") as $sKey){
              $sReturn=preg_replace('/\@'.$sKey.' ([a-zA-Z\|]*)\ (.*)\<br\>/U', '@'.$sKey.' <span style="font-weight: bold; color:#000;">$1</span> <span style="font-weight: bold;">$2</span><br>', $sReturn);
              }
             */
            $sReturn = preg_replace('/(\@.*)$/s', '<span class="phpdoc">$1</span>', $sReturn);
            foreach ($aTags as $sKey) {
                $sReturn = preg_replace('/\@(' . $sKey . ')/U', '<span class="doctag">@' . $sKey . '</span>', $sReturn);
            }
            if ($sReturn) {
                $sReturn = '<pre>' . $sReturn . '</pre><span class="phpdoctitle">PHPDOC</span>';
            }
            return $sReturn;
        }
    
        /**
         * quit with error: returns 404 and the given errormessage in the body
         * @param type $sError
         */
        private function _quit($sError, $sMore = "") {
            header("Status: 404 Not Found");
            echo $this->_wrapAsWebpage(
                    $sMore, '<div class="error">' . $sError . '</div>'
            );
            die();
        }
    
        /**
         * show help - return html with list of allowed classes
         * @return string
         */
        private function showClasshelp() {
            $sReturn = '';
    
            
            $sReturn .= '<h2>Explore</h2>'
                    . '<p>allowed classes are:</p><ul class="classes">';
            foreach (array_keys($this->_aKnownClasses["classes"]) as $sMyClass) {
    
                require_once($this->_sClassDir . $this->_aKnownClasses["classes"][$sMyClass]["file"]);
                $oRefClass = new ReflectionClass($sMyClass);
                $sComment = $this->_parseComment($oRefClass->getDocComment());
                $sComment2 = $this->_parseComment($oRefClass->getMethod("__construct")->getDocComment());
    
                $sIdDescription = "help-" . $sMyClass . "";
                $sStyle = ' style="display: none;"';
                $sClass = '';
                $sBtnValue = '+';
                if (array_key_exists("class", $this->_aParams) && $this->_aParams["class"] == $sMyClass) {
                    $sClass = 'active';
                    $sStyle = '';
                    $sBtnValue = '-';
                }
                $sReturn .= '<li class="classname ' . $sClass . ' ">'
                        . '<h3>'
                        . '<button onclick="toggleDesciption(\'' . $sIdDescription . '\', this)">' . $sBtnValue . '</button> '
                        . '<a href="?class=' . $sMyClass . '">' . $sMyClass . '</a>'
                        . '</h3>'
                        . '<div id="' . $sIdDescription . '"' . $sStyle . '>'
                        . $sComment 
                        . '<p>__constructor:</p>' 
                        . $sComment2
                        . $this->showActionhelp($sMyClass)
                        . '</div>'
                        . '</li>';
            }
            $sReturn .= '</ul>';
            return $sReturn;
        }
    
        /**
         * show help - return html with list allowed methods of a given class
         * @param string $sClass  classname you get the methods from
         * @return string
         */
        private function showActionhelp($sClass) {
            $sReturn = '<p>For the class <em>' . $sClass . '</em> these methods are configured:</p><ul>';
            require_once($this->_sClassDir . $this->_aKnownClasses["classes"][$sClass]["file"]);
            $oRefClass = new ReflectionClass($sClass);
    
            foreach (array_keys($this->_aKnownClasses["classes"][$sClass]["actions"]) as $sAction) {
                $sStyle = ' style="display: none;"';
                $sBtnValue = '+';
                $sCssClass = '';
                if (
                        array_key_exists("class", $this->_aParams) && $this->_aParams["class"] == $sClass && array_key_exists("action", $this->_aParams) && $this->_aParams["action"] == $sAction) {
                    $sCssClass = 'active';
                    $sStyle = '';
                    $sBtnValue = '-';
                }
                try {
                    $oMethod = false;
                    $oMethod = $oRefClass->getMethod($sAction);
                } catch (Exception $e) {
                    //   nop
                }
                if ($oMethod) {
                    $sComment = $this->_parseComment($oRefClass->getMethod($sAction)->getDocComment());
                    $sIdDescription = "help-" . $sClass . "-" . $sAction;
                    $sReturn .= '<li class="actionname ' . $sCssClass . '">'
                            . '<h4>'
                            . '<button onclick="toggleDesciption(\'' . $sIdDescription . '\', this)">' . $sBtnValue . '</button> '
                            . $sAction
                            . '</h4>'
                            . '<div id="' . $sIdDescription . '"' . $sStyle . '>'
                            . $sComment
                            . $this->_showMethodInputForm($oMethod)
                            . '<br>try it ... '
                            . '' . $sClass . '->' . $sAction . '() ... <br><br>as ';
                    foreach (array("raw", "json") as $sType) {
                        $sReturn .= '<a href="?class=' . $sClass . '&amp;action=' . $sAction . '&amp;type=' . $sType . '"'
                                . ' class="button try"'
                                . '>' . $sType . '</a> ';
                    }
                    $sReturn .= '<br>'
                            . '</div>'
                            . '</li>';
                } else {
                    $sReturn .= '<li class="actionname error">'
                            . '' . $sAction . ' &lt;&lt;&lt; ERROR in configuration: this method does not exist'
                            . '</li>';
                }
            }
            $sReturn .= '</ul>';
            return $sReturn;
        }
    
        private function _showMethodInputForm($oMethod){
            $sHtml='';
            $iCount=0;
            $aParams=array();
            $iRequired=$oMethod->getNumberOfRequiredParameters();
            foreach($oMethod->getParameters() as $oParam){
                preg_match('@Parameter\ \#.*\[\ (.*)\ \]@', $oParam->__toString(), $aTmp);
                preg_match('@(.*)=\ (.*)@', $aTmp[1], $aTmp1);
                if (count($aTmp1)){
                    $aParams[$iCount]["varname"]=$aTmp1[1];
                    $aParams[$iCount]["value"]=$aTmp1[2];
                } else {
                    $aParams[$iCount]["varname"]=$aTmp[1];
                    $aParams[$iCount]["value"]=false;
                }
                $aParams[$iCount]["required"]=$iCount<$iRequired ? true:false;
                $iCount++;
            }
            
            // 
            if (count($aParams )) {
                $sHtml.='<br>parameters (<span class="error">not active yet - this feature to enter parameter values is coming soon</span>):<br><br>';
                if ($iRequired){
                    if ($iCount==$iRequired) {
                        $sHtml.=' ... all param(s) required<br>';
                    } else {
                        $sHtml.=' ... '.$iRequired . ' of '.$iCount.' param(s) required<br>';
                    }
                }
                foreach($aParams as $aParam){
                    $sHtml.='<label for="">'.$aParam["varname"].' = </label>';
                    $sHtml.='<input type="text" name="" size="30" value="'.$aParam["value"].'"/>';
                    if ($aParam["required"]){
                        $sHtml.=' (*)';
                    } else {
                        $sHtml.=' &laquo; optional; default is <span class="defaultvalue">'.$aParam["value"].'</span>';
                    }
                    $sHtml.='<br>';
                }
            } else {
                $sHtml.='(no parameters)<br>';
            }
            
            return $sHtml;
        }
        
        /**
         * render output as html page
         * @param string $sBody   html body
         * @param string $sError  error message
         * @return string
         */
        private function _wrapAsWebpage($sBody = "", $sError = "") {
    
            $sClassSelect = '<span class="urlvalue">[class]</span>';
            $sActionSelect = '<span class="urlvalue">[action]</span>';
            $sParamSelect = '<span class="urlvalue">[parameters]</span>';
            $sTypeSelect = '<span class="urlvalue">[type: raw|json]</span>';
    
            $sSyntax = sprintf(
                    '<pre>?<span class="urlvar">class</span>=%s&<span class="urlvar">action</span>=%s&<span class="urlvar">args</span>=%s&<span class="urlvar">type</span>=%s</pre>', $sClassSelect, $sActionSelect, $sParamSelect, $sTypeSelect
            );
    
            /*
              if ($this->_sClass){
              $sClassSelect='<strong>'.$this->_sClass.'</strong>';
              }
              if ($this->_sAction){
              $sActionSelect='<strong>'.$this->_sAction.'</strong>';
              }
              if ($this->_aArgs){
              $sActionSelect='<strong>'.$this->_aParams["args"].'</strong>';
              }
    
              $sSyntax2=sprintf(
              '<pre>?<span class="urlvar">class</span>=%s&<span class="urlvar">action</span>=%s&<span class="urlvar">args</span>=%s&<span class="urlvar">type</span>=%s</pre>',
              $sClassSelect,
              $sActionSelect,
              $sParamSelect,
              $sTypeSelect
              );
              if ($sSyntax!=$sSyntax2){
              $sSyntax.='<br><br>change it here:<br>'.$sSyntax2;
              }
              $sSyntax='general syntax:<br>'.$sSyntax;
             */
            $sReturn = '<!DOCTYPE html>' . "\n"
                    . '<html>'
                    . '<head>'
                    . '<title>' . $this->_sTitle . '</title>'
                    . '<meta http-equiv="content-type" content="text/html; charset=UTF-8" />'
                    . '<style>'
                        . 'body{background:#aaa; color: #ddd; font-family: verdana,arial; margin: 0;}'
                        . '#content{padding: 2em; color: #444; background:#f8f8f8;}'
                        . '#footer{padding: 0 2em; border-top: 0.5em solid #999;}'
                        . 'a,a:visited{text-decoration: none; color: #000;}'
                        . 'a.button{border: 2px solid #888; background:#aaa; padding: 0.2em; color:#eee; border-radius: 0.3em;}'
                        . 'a.try{background:#080; border-color: #0c0;}'
                        . 'a.try:hover{background:#0b0; border-color: #0c0;}'
                        . 'button{ width: 2em; height: 2em; background: #44a; border-radius: 0.3em; color:#eee; border: 3px solid #338; font-size: 110%;}'
                        . 'h1{background:#222; color:#ccc; padding: 0.3em; margin: 0; border-bottom: 0.2em solid #999;}'
                        . 'h1 a, h1 a:visited{color:#888;}'
                        . 'h1 a span{color:#666; font-size: 45%;}'
                        . 'h2{margin: 3em 0 1em;  }'
                        . 'h3,h4{margin: 0;}'
                        . 'label{width: 10em; float: left; text-align: right;}'
                        . 'ul{padding-left: 0; margin: 0; border-radius: 0.5em;}'
                        . 'ul ul{margin: 1em;}'
                        . '.classes li{list-style: none; border-radius: 0.3em; padding: 0.3em; margin-bottom: 0.3em;}'
                        . 'li{border-left: 5px solid #aaa; }'
                        . 'li.active{border-left: 5px solid #aaa; }'
                        . 'li li.active{border-left: 5px solid #c00; background: #fcc;}'
                        . 'pre{margin: 0; border: #ddd solid 1px; border-radius: 0.5em; padding: 0.5em; background: #fff;}'
                        . 'pre .urlvar{color: #480; font-weight: bold;}'
                        . 'pre .urlvalue{color: #8c0;}'
                        . '.classname{ background:#eee; }'
                        . '.actionname{background:#ddd; background: rgba(0,0,0,0.1);}'
                        . '.phpdoctitle{background:#ccc; color:#fff;float: right; margin-right: 0.5em; padding: 0 1em; border-radius: 0.5em; border-top-left-radius: 0;border-top-right-radius: 0;}'
                        . '.phpdoc{background:#f0f4f8;}'
                        . '.doctag{ color:#080; }'
                        . '.error{ color:#800; background:#fcc; padding: 0.5em; margin-bottom: 2em; border-left: 4px solid;}'
                        . '.warning{ color:#a96; background:#fc8; padding: 0.5em; margin-bottom: 2em; border-left: 4px solid;}'
                        . '.defaultvalue{color: #33c;}'
                    . '</style>'
                    . '<script>'
                    . 'function toggleDesciption(sId, a){'
                    . 'var o=document.getElementById(sId);'
                    . 'if (o) {'
                    . 'o.style.display=(o.style.display=="")?"none":"";'
                    . '}'
                    . 'console.log(a);'
                    . 'if (a) {'
                    . 'a.innerHTML=(a.innerHTML=="+")?"-":"+";'
                    . '}'
                    . '}'
                    . '</script>'
                    . '</head>'
                    . '<body>';
    
            if($this->_aOptions["enableGui"]){
                $sReturn.= 
                      '<h1><a href="?">' . $this->_sTitle . ' <span>'.$this->_sVersion.'</span></a></h1>'
                    . '<div id="content">'
                    . $sError
                    . $sBody
                    . '<h2>Syntax</h2>'
                    . $sSyntax
                    . '</div><div id="footer">'
                    . '<h2>About</h2>'
                    . '<p>'
                    . 'SWS is a free wrapper for other php classes and makes their public '
                    . 'functions (or a subset of them) available as a webservice.<br>'
                    . 'It offers a webinterface to explore available classes and methods. '
                    . 'The shown information is parsed by reading phpdoc.'
                    . '</p>'
                    . '<p>'
                    . 'GNU 3.0;<br>';
                if ($this->_sUrlDoc) {
                    $sReturn.='<a href="' . $this->_sUrlDoc . '">' . $this->_sUrlDoc . '</a> ';
                }
                if ($this->_sUrlHome) {
                    $sReturn.='<a href="' . $this->_sUrlHome . '">' . $this->_sUrlHome . '</a> ';
                }
                $sReturn.='</p></div>';
            } else {
                      
                $sReturn.=
                        '<div id="content" style="height: 1000px; overflow: hidden;">'
                        .$sError .''. $this->_sTitle
                        .'</div>'
                        ;
            }
            $sReturn.='</body></html>';
            return $sReturn;
        }
    
        // ----------------------------------------------------------------------
        // setter
        // ----------------------------------------------------------------------
    
        /**
         * set ouput type of response
         * @param string $sOutputType  one of json|raw
         * @return bool
         */
        public function setOutputType($sOutputType) {
            $this->_sOutputType = $sOutputType;
            return true;
        }
    
        /**
         * put query parameter
         * @param array $aParams  parameters; default false and params will be taken from $_GET and $_POST
         * @return array
         */
        public function setParams($aParams = false) {
    
            $this->_aParams = array();
            if (is_array($aParams)) {
                $this->_aParams = $aParams;
            } else {
                if (isset($_GET) && count($_GET)) {
                    foreach ($_GET as $key => $value)
                        $this->_aParams[$key] = $value;
                }
                if (isset($_POST) && count($_POST)) {
                    foreach ($_POST as $key => $value)
                        $this->_aParams[$key] = $value;
                }
            }
            $this->_parseParams();
            return $this->_aParams;
        }
    
        // ----------------------------------------------------------------------
        // actions
        // ----------------------------------------------------------------------
    
        /**
         * execute function
         * @param type $sOutputType
         */
        public function run($sOutputType = false) {
            if (!count($this->_aParams))
                $this->setParams();
            $this->_parseParams();
            require_once($this->_sClassDir . $this->_sClassfile);
    
            if (!class_exists($this->_sClass)) {
                $this->_quit("ERROR: class does not exist: " . $this->_sClass);
            }
            $o = new $this->_sClass;
            if (!method_exists($o, $this->_sAction)) {
                $this->_quit("ERROR: method does not exist: " . $this->_sClass . " -> " . $this->_sAction . "()");
            }
    
            // ------------------------------------------------------------
            // call function
            // ------------------------------------------------------------
            switch (count($this->_aArgs)) {
                case 0: $return = call_user_func(array($o, $this->_sAction));
                    break;
                    ;
                case 1: $return = call_user_func(array($o, $this->_sAction), $this->_aArgs[0]);
                    break;
                    ;
                case 2: $return = call_user_func(array($o, $this->_sAction), $this->_aArgs[0], $this->_aArgs[1]);
                    break;
                    ;
                case 3: $return = call_user_func(array($o, $this->_sAction), $this->_aArgs[0], $this->_aArgs[1], $this->_aArgs[2]);
                    break;
                    ;
                case 4: $return = call_user_func(array($o, $this->_sAction), $this->_aArgs[0], $this->_aArgs[1], $this->_aArgs[2], $this->_aArgs[3]);
                    break;
                    ;
                default: die("internal ERROR: need to set a new case with up to " . count($this->_aArgs) . " arguments in " . __FILE__);
            }
            if (!$return) {
                quit("ERROR: no output");
            }
    
            // ------------------------------------------------------------
            // output
            // ------------------------------------------------------------
            switch ($this->_sOutputType) {
                case "json":
                    header('Content-Type: application/json');
                    echo json_encode($return);
                    break;
                case "raw":
                    if (is_array($return)) {
                        $this->_quit("ERROR: Wrong output type for that method. Return of " . $this->_sClass . '->' . $this->_sAction . "() is an array", $this->showClasshelp());
                    }
                    echo $return;
                    break;
                default:
                    $this->_quit("ERROR in " . __FUNCTION__ . ": outputtype </em>" . $this->_sOutputType . "</em> is unknown", $this->showClasshelp());
            }
        }
    
    }
    
    // ----------------------------------------------------------------------