Topic: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

With the current registering of functions or class/methods, it a bit of a black white situation.

With ajax->register(function blabla)   you register one method at a time.  If you have quite a few methods, its better to use the XAJAX_CALLABLE_OBJECT  call in register...   That's very nice...

But...  It registers all the methods... Even the one I don't wan't to be called in any way ( security ).

In my way of programming, i now can use a fully extendable class which inherits another class (extends feature).
So for example i have :

class a extends b {
funtion __construct() {
    parent::__construct();

}

function c {}

function d{}

}

with the callable object way, even the __construct() is registered. And in my opinion it is unwanted.

So at the end.. i would suggest a way of making a $xajax->register(XAJAX_CALLABLE_OBJECT, $classinstance , array( methods 2 B registered)).

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

Hi DocG,

that's not a bad idea. We'll keep it in mind for a future release. smile

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

At the moment  i'm trying to implement the array with methods 2 register.
The __construct inclusion is a drawback because of the PHP4 way... But thats easy to adjust...

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

I implemented the new feature already with succes...  It isn't that hard.. and the pros are numerous for me...
[gpl mode]If anybody wants to know what, just let me know[/gpl mode]

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

Hi DocG, q_no, that's a good idea. Could you post your implementation here, DocG?

A variation on it which would also be nice would be to have a 'callablePrefix' configure option which would only allow methods to be called that began with that prefix, eg 'xajax_', and which fits in with the convention over configuration idea popular amongst young folk nowadays. I used a similar idea in the auto-register plugin I posted a while back (which it'd be nice to have stub support for also, in a future release!) and which I re-post here for your amusement and delight.

<?php

// Plugin that auto-registers user functions that start with prefix 'xajax_'. (Note this is on PHP side.)
// Put in xajax_core/plugin_layer or xajax_plugins/request. NOTE: Only tested on PHP5.
// The javascript-side call would be xajax.request({xjxfun: 'xajax_func', xjxfunthis: 'Class_Name'}, {parameters: etc});

class xajaxAutoRegisterFunctionPlugin extends xajaxRequestPlugin {
    // Use the fact that canProcessRequest gets called before any processRequest to register a user function.
    // Also relies on xajaxFunctionPlugin::canProcessRequest only checking that there's a $_REQUEST['xjxfun'].
    function canProcessRequest() {
        // Security check that function starts with 'xajax_' so app only needs to harden functions so-named.
        if (!isset($_REQUEST['xjxfun']) || !$this->is_identifier($_REQUEST['xjxfun'])
                || strncmp($_REQUEST['xjxfun'], 'xajax_', 6) != 0) {
            return false;
        }

        // NOTE: Not tested.
        if (isset($_REQUEST['xjxfuninc']) && $this->is_incfilename($_REQUEST['xjxfuninc'])) {
            $sInclude = $_REQUEST['xjxfuninc'];
        } else {
            $sInclude = null;
        }

        if (isset($_REQUEST['xjxfuncls']) && $this->is_identifier($_REQUEST['xjxfuncls'])) {
            // Static class method - class name.
            $xuf = new xajaxUserFunction(array($_REQUEST['xjxfuncls'], $_REQUEST['xjxfun']), $sInclude);
        } elseif (isset($_REQUEST['xjxfunthis']) && $this->is_identifier($_REQUEST['xjxfunthis'])) {
            // Standard class method - create an instance from the class name.
            $funthis = new $_REQUEST['xjxfunthis']; // NOTE: If using include, may want to include it first.
            $xuf = new xajaxUserFunction(array($funthis, $_REQUEST['xjxfun']), $sInclude);
        } else {
            // Global function.
            $xuf = new xajaxUserFunction($_REQUEST['xjxfun'], $sInclude);
        }
        $objPluginManager = xajaxPluginManager::getInstance();
        $objPluginManager->register(array(XAJAX_FUNCTION, $xuf));

        return false; // Doesn't actually do any request processing so always returns false.
    }

    // Never gets called.
    function processRequest() {
        return false;
    }

    // Does $val consist of alphanumerics and underscores, beginning with an alphabetic?
    function is_identifier($val) {
        return preg_match('/^[A-Za-z][A-Za-z0-9_]*$/', $val);
    }
    // Does $val consist of alphanumerics, underscores, dots and slashes?
    function is_incfilename($val) {
        return preg_match('/^[A-Za-z0-9_.\/]+$/', $val);
    }
}

$objPluginManager = xajaxPluginManager::getInstance();
$objPluginManager->registerPlugin(new xajaxAutoRegisterFunctionPlugin(), 1000); // Don't care about order.

?>

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

n1 dickdock wink although it's lacking of the generateClientScript() function. If you need any help feel free to join us on irc.freenode.net #xajax

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

function call :

$aMethods = array('Index','Edit','EditStore');
$rfDomain =& $XJX->register(XAJAX_CALLABLE_OBJECT,new xjxDomain,null,$aMethods);

In xajaxCallableObjectPlugin.inc.php :

function register($aArgs)
    {
        if (1 < count($aArgs))
        {
            $sType = $aArgs[0];

            if (XAJAX_CALLABLE_OBJECT == $sType)
            {
                $xco =& $aArgs[1];

//SkipDebug
                if (false === is_object($xco))
                {
                    trigger_error("To register a callable object, please provide an instance of the desired class.", E_USER_WARNING);
                    return false;
                }
//EndSkipDebug

                if (false === is_a($xco, 'xajaxCallableObject'))
                    $xco =& new xajaxCallableObject($xco);

                if (2 < count($aArgs))
                    if (is_array($aArgs[2]))
                        foreach ($aArgs[2] as $sKey => $aValue)
                            foreach ($aValue as $sName => $sValue)
                                $xco->configure($sKey, $sName, $sValue);

                if (3 < count($aArgs)) {
                    if (is_array($aArgs[3]))
                        $xco->aMethods2Register = $aArgs[3];
                }

                $this->aCallableObjects[] =& $xco;

                return $xco->generateRequests($this->sXajaxPrefix);
            }
        }

        return false;
    }

In xajaxCallableObject.inc.php :

var $aMethods2Register;

function generateRequests($sXajaxPrefix)
    {
        $aRequests = array();
        
        $sClass = get_class($this->obj);
        
        foreach (get_class_methods($this->obj) as $sMethodName)
        {
            $bInclude = true;
            // exclude magic __call method
            if ("__call" == $sMethodName)
                $bInclude = false;

            if ("__construct" == $sMethodName)
                $bInclude = false;

            if (count($this->aMethods2Register) > 0 && !in_array($sMethodName, $this->aMethods2Register))
                $bInclude = false;

            // exclude constructor
            if ($sClass == $sMethodName)
                $bInclude = false;
            if ($bInclude)
                $aRequests[strtolower($sMethodName)] =& 
                    new xajaxRequest("{$sXajaxPrefix}{$sClass}.{$sMethodName}");
        }

        return $aRequests;
    }
    
    /*
        Function: generateClientScript
        
        Called by <xajaxCallableObject->generateClientScript> while <xajax> is 
        generating the javascript to be sent to the browser.

        sXajaxPrefix - (string):  The prefix to be prepended to the
            javascript function names.
    */    
    function generateClientScript($sXajaxPrefix)
    {
        $sClass = get_class($this->obj);
        
        echo "{$sXajaxPrefix}{$sClass} = {};\n";
        
        foreach (get_class_methods($this->obj) as $sMethodName)
        {
            $bInclude = true;
            // exclude magic __call method
            if ("__call" == $sMethodName)
                $bInclude = false;

            if ("__construct" == $sMethodName)
                $bInclude = false;

            if (count($this->aMethods2Register) > 0 && !in_array($sMethodName, $this->aMethods2Register))
                $bInclude = false;

            // exclude constructor
            if ($sClass == $sMethodName)
                $bInclude = false;
            if ($bInclude)
            {
                echo "{$sXajaxPrefix}{$sClass}.{$sMethodName} = function() { ";
                echo "return xajax.request( ";
                echo "{ xjxcls: '{$sClass}', xjxmthd: '{$sMethodName}' }, ";
                echo "{ parameters: arguments";
                
                $sSeparator = ", ";
                if (isset($this->aConfiguration['*']))
                    foreach ($this->aConfiguration['*'] as $sKey => $sValue)
                        echo "{$sSeparator}{$sKey}: {$sValue}";
                if (isset($this->aConfiguration[strtolower($sMethodName)]))
                    foreach ($this->aConfiguration[strtolower($sMethodName)] as $sKey => $sValue)
                        echo "{$sSeparator}{$sKey}: {$sValue}";

                echo " } ); ";
                echo "};\n";
            }
        }
    }

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

Hi DocG, thanks for posting that, very neat, stuck it in my own system with a few changes and it should definitely be in some future release. The main change I'd point out is that all the include/exclude logic should be moved to the hasMethod() method (should have been there in the original) so that someone couldn't just write their own stub and call whatever they want. In xajaxCallableObject.inc.php:

    function hasMethod($sMethod)
    {
        // exclude magic // Patched 20080118
        if (strncmp($sMethod, "__", 2) == 0)
            return false;

        // exclude constructor // Patched 20080118
        if ($sClass == $sMethod)
            return false;

        // exclude if using allowed methods and not listed // Patched 20080118
        if (count($this->aMethods2Register) > 0 && !in_array($sMethod, $this->aMethods2Register))
            return false;

        // exclude if using method prefix and not so-named // Patched 20080118
        if ($this->sMethodsPrefix && strncmp($this->sMethodsPrefix, $sMethod, strlen($this->sMethodsPrefix)) != 0)
            return false;

        return method_exists($this->obj, $sMethod); // Patched 20080118
    }

Then have just $bInclude = $this->hasMethod($sMethodName); in the two generate places. I have patch files if anyone's interested.

Coincidently, holtkamp posted a thread just recently http://community.xajaxproject.org/viewt … 044#p23044 where Ctc mentions he implemented the same thing over a year ago! Must have got buried under the ever-drifting sands of time etc.

q_no: I was talking tosh earlier when I mentioned stub support for the auto-register plugin - it couldn't really feasibly have any I don't think, so I suppose it's stuck with manual stubs and no generateClientScript(). I've wrapped my own calls in a little helper:

function dm_xajax_autorequest(fun, funthis, parameters, URI) {
    return xajax.request({xjxfun: 'xajax_' + fun, xjxfunthis: funthis}, {parameters: parameters, URI: URI});
}

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

dickdock wrote:
        // exclude magic // Patched 20080118
        if (strncmp($sMethod, "__", 2) == 0)
            return false;

And you are probably stuck in time :twisted: wink  Or is the date from the original article ?


I would make a tiny adjustment to this sentence...

dickdock wrote:

The main change I'd point out is that all the include/exclude logic should be moved to the hasMethod() method

I think not "moved to", but "also implemented in".

In my case, i would get all the javascript in my page with the unwanted methods, which also include the ones from the parent class.  Unwanted exposure of methods... Furtheron..  In  my example i didn't "check backwards", and thats also a security risk. Thanx for that suggestion. I "patched" this now, because it should be definitely be there also.

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

Oh dear, 2008, well I suppose it is Chequary.

You're right, but I meant to put $bInclude = $this->hasMethod($sMethodName); in the two places you had it originally so that the logic is still called (and shared).

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

i some way i somewhat understand what you mean but not completely... Maybe its better to put the script here..

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

I just mean that I think it's nicer to have in xajaxCallableObject.inc.php:

    function generateRequests($sXajaxPrefix)
    {
        $aRequests = array();
       
        $sClass = get_class($this->obj);
       
        foreach (get_class_methods($this->obj) as $sMethodName)
        {
            $bInclude = $this->hasMethod($sMethodName); // Patched 20090118

            if ($bInclude)
                $aRequests[strtolower($sMethodName)] =
                    new xajaxRequest("{$sXajaxPrefix}{$sClass}.{$sMethodName}");
        }

        return $aRequests;
    }

    function generateClientScript($sXajaxPrefix)
    {
        $sClass = get_class($this->obj);
       
        echo "{$sXajaxPrefix}{$sClass} = {};\n";
       
        foreach (get_class_methods($this->obj) as $sMethodName)
        {
            $bInclude = $this->hasMethod($sMethodName); // Patched 20090118

            if ($bInclude)
            {
                echo "{$sXajaxPrefix}{$sClass}.{$sMethodName} = function() { ";
                echo "return xajax.request( ";
                echo "{ xjxcls: '{$sClass}', xjxmthd: '{$sMethodName}' }, ";
                echo "{ parameters: arguments";
               
                $sSeparator = ", ";
                if (isset($this->aConfiguration['*']))
                    foreach ($this->aConfiguration['*'] as $sKey => $sValue)
                        echo "{$sSeparator}{$sKey}: {$sValue}";
                if (isset($this->aConfiguration[strtolower($sMethodName)]))
                    foreach ($this->aConfiguration[strtolower($sMethodName)] as $sKey => $sValue)
                        echo "{$sSeparator}{$sKey}: {$sValue}";

                echo " } ); ";
                echo "};\n";
            }
        }
    }

(Note 2008 fix!) I suppose one could argue that one then has unnecessary calls to method_exists() but personally I'd take the hit. Or if not maybe split the test bit out into a new isIncludeMethod() and call that in the generates and in the hasMethod(). Hmmm...

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

I need help applying this idea but with prefixes. I am a noob and I am kind of afraid that if I do it myself i might break something.

Any help.

14 (edited by sinza 2010-06-15 12:40:11 AM)

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

hey,

it would be useful to have a small change in xajaxCallableObject.inc.php wich allows to set a array of methods wich shouldn`t be loaded even if they public

//defined as class var in the class loaded by XAJAX_CALLABLE_CLASS 
var $exclude = array('theOneMethod', 'theOtherMethod');

//could be triggered in  generateClientScript line around 151:
if ($sClass == $sMethodName || in_array($sMethodName , $this->obj->exclude))
                $bInclude = false;
                

beside the fact, that xajax doesn`t load private and methods and constructors, some public methods shouldn`t be loaded.
This might be a small change for a high benefit.

greetz

sin

Re: ajax_register(XAJAX_CALLABLE_OBJECT) with list of methods

All sounding much better gang. But (especially in 0.6), let's do it like this in xajaxCallableObject.inc.php:

    // Codename: Steeve Knight
    function generateClientScript($sXajaxPrefix)
    {
        $sClass = get_class($this->obj);
        $snippet = "{$sXajaxPrefix}{$sClass} = {".PHP_EOL;
        $sSeparator = ', ';
        $fCnt = 0;
        
        foreach (get_class_methods($this->obj) as $sMethodName)
        {
            // exclude magic __call, __construct, __destruct methods
            if (substr($sMethodName, 0, 2) == '__')
                $bInclude = false;                                                                                     
            // exclude constructor
            elseif ($sClass == $sMethodName)
                $bInclude = false;
            elseif (count($this->aMethods2Register) && ! in_array($sMethodName, $this->aMethods2Register))
                $bInclude = false;
            else $bInclude = true;

            if ($bInclude)
            {
                if ($fCnt > 0) $snippet .= $sSeparator.PHP_EOL;
                $snippet .= "\t".$sMethodName.': function() {';
                $snippet .= 'return xajax.request( ';
                $snippet .= "{ xjxcls: '{$sClass}', xjxmthd: '{$sMethodName}' }, ";
                $snippet .= '{ parameters: arguments';
                
                if (isset($this->aConfiguration['*']))
                    foreach ($this->aConfiguration['*'] as $sKey => $sValue)
                    $snippet .= "{$sSeparator}{$sKey}: {$sValue}";
                if (isset($this->aConfiguration[strtolower($sMethodName)]))
                    foreach ($this->aConfiguration[strtolower($sMethodName)] as $sKey => $sValue)
                    $snippet .= "{$sSeparator}{$sKey}: {$sValue}";
                $snippet .= '});}';
                
                $fCnt++;
            }
        }
        $snippet .= '};'.PHP_EOL;
        
        echo $snippet;
    }