7

How to encode a Javascript function in PHP? I want to encode the callback function with array

$options = array(
'title' => 'Title',
'fnCallback' => someCallback);

equivalent ini Javascript:

var options = {
'title': 'Title',
'fnCallback': someCallback };

I know my PHP code is wrong, how can I fix it?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Hensembryan
  • 1,067
  • 3
  • 14
  • 31

8 Answers8

8

Viola i solved my problem with Zend_JSON encoder

 $options = array(
     'title' => 'Title',
     'fnCallback' => new Zend_Json_Expr('someCallback')
 );      

 Zend_Json::encode(
     $options,
     false,
     array('enableJsonExprFinder' => true));
Hensembryan
  • 1,067
  • 3
  • 14
  • 31
  • 2
    Great to see some actual use of ZF ;-). I went ugly and elegant by adding in the php array 'data'=>'@aCallBack()@' and after json_encode before output, did str_replace('"@','') and ('@"',''). PHP4ever. – Teson Dec 07 '13 at 23:47
5

JSON is for passing values around, they are not suitable for passing pieces of code.

You can, instead, pass a function name or other meaningful value and retrieve the right function to call from it on the JavaScript side.

Thai
  • 10,746
  • 2
  • 45
  • 57
  • alternatively i solve that by returning a string, but this is make the code not "clean" $returnValue = "{'title': 'Title', 'fnCallback': someCallback}"; – Hensembryan May 29 '11 at 18:54
1

To make the notice go away in PHP, just write your callback function in quotes:

$options = array(
   'title' => 'Title',
   'fnCallback' => "someCallback");

And then when you receive the JSON in Javascript, you can remap the callback function name to the actual JS function with e.g.:

json = $.getJSON(..);
json.fnCallback = window[json.fnCallback];   // for global callbacks
mario
  • 144,265
  • 20
  • 237
  • 291
0

Voici le code que j'utilise pour faire cela :

//~ [FUNCTION]
function __json_encode($mVar,$fnCallback="stripcslashes") {
    return preg_replace_callback('#"[ ]{0,}function[ ]{0,}\([^)$]{0,}\)[ ]{0,}\{[ ]{0,}(?(?![ ]{0,}}[ ]{0,}").){0,}[ ]{0,}\}[ ]{0,}"([(?,")|(?\}{0,}$)]{0,})#si', 
        function ($aRes) use ($fnCallback) { 
            for($aRes[0]=substr($aRes[0],1),$sOut="",$i=0,$iOpen=0,$iClose=0;$i<= strlen($aRes[0]) && $sOut.= substr($aRes[0],$i,1);$i++) 
                if (substr($aRes[0],$i,1) == "{") $iOpen++;
                else if (substr($aRes[0],$i,1) == "}" AND $iOpen == ++$iClose) break;
            return is_callable($fnCallback) ? $fnCallback($sOut).$aRes[1] : $sOut.$aRes[1]; 
        },json_encode($mVar)
    );
}



//~ [TEST]
print "<script>\n";
print sprintf(
    "\tvar oTest = %s;",
    __json_encode(
        array( 
            "Numeric"=>1,
            "string"=>"hello world !",
            "myFunction"=>"function(test) {  if (test==1) { alert('myFunction(1)'); return true; } else return false; }",
            "myObject"=>array(
                "Numeric"=>1,
                "string"=>"hello world !",
                "myFunction"=>"function(test) {  alert('myFunction(1)'); return true; }")
        )
    )
);
print "\n\tif (oTest.myFunction(1) == false) alert('myFunction(0)');";
print "\n\tif (oTest.myObject.myFunction(0) == false) alert('myFunction(0)');";
print "\n</script>";

Voici le résultat :

    <script>
        var oTest = {
            "Numeric":1,
            "string":"hello world !",
            "myFunction":function(test) {  if (test==1) { alert('myFunction(1)'); return true; } else return false; },
            "myObject":{
                "Numeric":1,
                "string":"hello world !",
                "myFunction":function(test) {  alert('myFunction(1)'); return true; }
            }
        };
        if (oTest.myFunction(0) == false) alert('myFunction(0)');
        if (oTest.myObject.myFunction(1) == false) alert('myFunction(0)');
    </script>

Cdt.

0

Don't confuse JSON for actual, native, Javascript object notation syntax (regardless of the name). Javascript objects can contain function references; JSON cannot.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
0

That is not possible without thinking of a convention and implementing it yourself.

Say, you have this JSON

'{"title": "Title", "fnCallback": "someCallback" }'

Then you could do, on the client side

function wireupCallbacks(jsonObject) {
  if (typeof jsonObject === "object") {
    for (var prop in jsonObject) {
      var callbackName = jsonObject[prop];
      if (/Callback$/.test(prop) && typeof callbackName === "string") {
        if (typeof this[callbackName] === "function") {
          jsonObject[prop] = this[callbackName];
        }
      }
    }
  }
  return jsonObject;
}

and call that in the context of an object that provides your callback functions

var someObject = {
  someCallback: function() { alert("It works!"); }
}

var jsonObject = {"title": "Title", "fnCallback": "someCallback" };

wireupCallbacks.call(someObject, jsonObject);

jsonObject.fnCallback(); // alerts "It works!"

What's missing:

  • currently the function only looks for properties named "*Callback".
  • there is no fallback to global functions (these would be properties of the window object)
  • there is no recursion (nested objects are not visited)
  • there is no JSON array handling

Add these features on your own, none of these should be difficult to implement.

Tomalak
  • 332,285
  • 67
  • 532
  • 628
0

I liked the idea in this comment, so I expanded upon it.

This uses a unique ID for the replacement, so that it's unlikely to have any character conflicts or accidental replacements. You could alternatively use a GUID.

  $callback_uuid = uniqid();
  $config = [
    'foo' => 'bar',
    'callback' => $callback_uuid,
  ];

  $json = json_encode($config, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);

  // Replace UUID with JS function, and remove the surrounding quotations.
  // Note: This avoids putting '$0' in the string, because regexes replace that.
  $callback_js = "function(value){return'$'+value+(value?'K':'');}";
  $json = preg_replace("/\"$callback_uuid\"/", $callback_js, $json);

As an alternative, if you need to put the JSON into a URL and simply need a nice way to define the JS prior to encoding it, you can use a Heredoc string:

  $config = <<<EOF
    {
      foo: "bar",
      callback: function(value){return'$'+value+(value?'K':'');}
    }
  EOF;
mbomb007
  • 3,788
  • 3
  • 39
  • 68
-1

You forgot the comma between 'title' and 'fnCallback.'