1

I've searched around a lot of topics, but couldn't find the answer. My goal is to have a HTML hyperlink calling a Javascript AJAX post request on a PHP page to run a PHP function (optionally with any amount of arguments). A lot of topics solved this problem for defined functions (with a specific name). I want to generalize the AJAX post request function in order to pass the PHP function name to the AJAX request to call it, so I can define in Javascript what PHP function to call.

This is what I have, but it goes wrong at the PHP script...

The HTML:

<a onclick="call_php('php_function_name', ['arg_1', 'arg_2']);">call</a>
<p id="demo"></p>

The Javascript:

function call_php(fname, args) {
    var xhttp = new XMLHttpRequest();
    xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            document.getElementById('demo').innerHTML = this.responseText;
        }
    };
    xhttp.open('POST', 'includes/functions.php', true);
    xhttp.setRequestHeader('Content-type', 'application/json');
    xhttp.send(JSON.stringify({
        'fname': fname,
        'args': args
    }));
}

At the Javascript I'm questioning the JSON.stringify() and setRequestHeader() if it is used correctly in this case.

The PHP, which should call a function in it's file:

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    //header('Content-Type: application/json');
    $post = json_decode($_POST/*, true*/);
    // DO SOMETHING TO CALL: fname(...args);
}
function php_function_name(arg_1, arg_2) {
    // A FUNCTION...
}

At the PHP I'm questioning the header('Content-Type: application/json') since it's already defined at the Javascript. But the main question is: how to write the PHP code to call the PHP function? By the way: when I print echo $post it gives a warning: json_decode() expects parameter 1 to be string, array given...

Bob Vandevliet
  • 213
  • 3
  • 14
  • 1
    Are you searching for a PHP function like [call_user_func or call_user_func_array](http://php.net/manual/en/function.call-user-func.php), e.g. `call_user_func_array('php_function_name', array(&$a))`? – gus27 Mar 07 '17 at 15:17
  • Possible duplicate of [Call PHP function by name from JavaScript](http://stackoverflow.com/questions/23039439/call-php-function-by-name-from-javascript) – gus27 Mar 07 '17 at 15:21
  • What @gus27 said, although you might want to check if the function your JS is trying to call actually exists first, use [method_exists()](http://php.net/manual/en/function.method-exists.php) for that. – rkeet Mar 07 '17 at 15:21
  • Thanks, I'll have a look at the `call_user_func` functions, but how do I get the post data variables `name` and `args` into that function? – Bob Vandevliet Mar 07 '17 at 15:32
  • 1
    Just to make sure it's clear: **allowing any PHP function to be called is an extremely bad idea**. Consider what would happen if I open up a JS console on your site and type something like `call_php('exec', ['rm -rf /']);`. Hopefully you can see that the possibilities are endless for me to really mess with your system this way. Don't try and blacklist, either, have a whitelist of allowed functions, and simply respond with "error" for any other input. – IMSoP Mar 07 '17 at 16:21
  • Very good point indeed! Haven't thought about it that way. Thanks! – Bob Vandevliet Mar 07 '17 at 19:43

2 Answers2

5

The PHP Manual states that the $_POST super global variable only contains the post arguments for post data of type application/x-www-form-urlencoded or multipart/form-data.

An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.

However, you are trying to send a post request with the body of type application/json.

To read a raw body in PHP you can do this:

$postdata = file_get_contents("php://input");

This will give you a string of the entire request body. You can then json_decode this string to get the desired JSON object.

As for the part of calling a function supplied in the request, the call_user_func_array will do the job fine. Whether or not that is something you should do is an entirely separate issue. From what I understand, you are edging on on the concept of a router and a controller.

I have writen a simple snippet of what I think you want to do:

<?php

switch ($_SERVER['REQUEST_METHOD']) {
  case 'POST':
    post_handler();
    return;
  case 'GET':
    get_handler();
    return;
  default:
    echo 'Not implemented';
    return;
}

function post_handler() {
  $raw_data = file_get_contents("php://input");
  $req_body = json_decode($raw_data, TRUE);
  call_user_func_array($req_body['function'], $req_body['args']);
}

function get_handler() {
  echo 'This page left intentionally blank.';
}

function some_function($arg1, $arg2) {
  echo $arg1.' '.$arg2;
}

?>
Community
  • 1
  • 1
squgeim
  • 2,321
  • 1
  • 14
  • 21
  • Thanks, it works perfectly! Though, keep in mind what IMSoP commented: allowing any PHP function to be called is an extremely dangerous security issue. Don't try and blacklist, either, have a whitelist of allowed functions". But for my small project where security is not of major importance, this would do it. – Bob Vandevliet Mar 07 '17 at 20:21
1

Comment json_decode and output your $_POST by calling print_r ($_POST); you should see your data structure, if it is a simple array with data keys and values then you don't have to decode it but if the array have a single column and it's value is your data then take it's key and use it to decode the content