Example #1
0
function handle_rest_call()
{
    global $api_desc;
    set_error_handler("rest_error_handler");
    $magic = ini_get("magic_quotes_gpc");
    $path = explode('/', $_SERVER['PATH_INFO']);
    while (sizeof($path) && !$path[0]) {
        array_shift($path);
    }
    // get function name
    $funcname = implode(".", $path);
    // find function descriptor
    list($funcname, $func_desc, $php_func) = api_get_function_descriptor($funcname);
    // check request method
    if (strtolower($_SERVER['REQUEST_METHOD']) != $func_desc['type']) {
        api_error("Request method " . $_SERVER['REQUEST_METHOD'] . " is incorrect for this function; " . strtoupper($func_desc['type']) . " is required.", 'invalid_request_method');
    }
    // check and parse input
    $args_desc = $func_desc['args'];
    $args = array();
    foreach ($args_desc as $arg_name => $arg_desc) {
        // get value
        $v = @$_REQUEST[$arg_name];
        if ($v === NULL) {
            continue;
        }
        // missing keys will be detected during validation
        // massage it into required type
        $arg_type = $arg_desc['type'];
        switch ($arg_type) {
            case 'string':
            case 'enum':
                if ($magic) {
                    $v = stripslashes($v);
                }
                break;
            case 'boolean':
                switch ($v) {
                    case 'true':
                        $v = TRUE;
                        break;
                    case 'false':
                        $v = FALSE;
                        break;
                    default:
                        api_error("Invalid boolean value '{$v}' (must be 'true' or 'false') passed as argument {$arg_name} to function {$funcname}", "validation_invalid_value");
                }
                break;
            case 'int':
                $v = intval($v);
                break;
            case 'float':
                $v = floatval($v);
                break;
            default:
                api_error("Argument type '{$arg_type}' not supported in REST mode");
        }
        // and store
        $args[$arg_name] = $v;
    }
    // validate input
    validate_content($args, array("type" => "hash", "content" => $func_desc['args']), "REST input", "auto");
    // call function
    try {
        $ret = $php_func($args);
        // check output type
        if (gettype($ret) != 'array') {
            api_error("Returned data from {$php_func} should be an array, but received " . gettype($ret) . " instead.");
        }
        $validate = TRUE;
        if ($path[0] == 'peopleaggregator') {
            if (!array_key_exists("success", $ret)) {
                api_error("Missing 'success' field in returned data from {$php_func}.");
            }
            if (!$ret['success']) {
                $validate = FALSE;
            }
        }
        // check output
        if ($validate) {
            validate_content($ret, $func_desc['return'], "REST response", "auto", true);
        }
    } catch (PAException $e) {
        $ret = api_err_from_exception($e);
        Logger::log("An exception occurred in an API call: code " . $e->getCode() . ", message " . $e->getMessage() . "\n" . $e->getTraceAsString(), LOGGER_ERROR);
    }
    // if we got this var, it validates
    return array($ret, $func_desc);
}
Example #2
0
 function call($methodname, $args)
 {
     Logger::log("XML-RPC call: {$methodname}");
     list($methodname, $func_desc, $php_func) = api_get_function_descriptor($methodname);
     // make sure $args is a 1-elem array containing a hash
     if (gettype($args) != "array") {
         api_error("Parameters should be in an array", 'validation_request_wrapper');
     }
     switch ($func_desc['argstyle']) {
         case 'positional':
             $arg = array();
             $argorder = $func_desc['argorder'];
             if (count($args) != count($argorder)) {
                 api_error("Incorrect number of arguments; expected " . count($argorder), 'validation_incorrect_number_of_arguments');
             }
             for ($i = 0; $i < count($args); ++$i) {
                 $arg[$argorder[$i]] = $args[$i];
             }
             break;
         case 'named':
             if (sizeof($args) != 1) {
                 api_error("You should only send a single parameter in your XML-RPC request: a struct, containing all the required keys.", 'validation_request_wrapper');
             }
             $arg = $args[0];
             if (gettype($arg) != "array") {
                 api_error("Expected a single parameter containing an XML-RPC struct, but got a value of type '" . gettype($arg) . "' instead.", 'validation_request_wrapper');
             }
             break;
         default:
             api_error("Invalid argument style " . $func_desc['argstyle']);
     }
     //	var_dump($func_desc['args']);
     // validate the struct
     validate_content($arg, array("type" => "hash", "content" => $func_desc['args']), "input to XML-RPC function", "auto");
     // call function, capturing any output - which might include errors
     ob_start("xmlrpc_ob_end");
     try {
         $ret = $php_func($arg);
         // check output
         if ($ret['success']) {
             validate_content($ret, $func_desc['return'], "XML-RPC response - not your fault!", "auto");
         }
     } catch (PAException $e) {
         $ret = api_err_from_exception($e);
         Logger::log("An exception occurred in an API call: code " . $e->getCode() . ", message " . $e->getMessage() . "\n" . $e->getTraceAsString(), LOGGER_ERROR);
     }
     return $ret;
 }
Example #3
0
function validate_content(&$v, $desc, $context, $src_encoding, $convert_output = false, $path = '')
{
    if (!$src_encoding) {
        $src_encoding = "auto";
    }
    global $type_map;
    $t = gettype($v);
    $expected_type = array_key_exists($desc['type'], $type_map) ? $type_map[$desc['type']] : $desc['type'];
    if ($t != $expected_type) {
        api_error("Validation error ({$context}): expected type {$expected_type} at position '{$path}', got {$t}", 'validation_incorrect_type');
    }
    switch ($desc['type']) {
        case 'hash':
            // check that all specified keys are correct
            $content = $desc['content'];
            foreach ($content as $k_name => $k_desc) {
                // if the key is missing:
                // - do nothing if it's marked as optional,
                // - replace with the default if one is given,
                // - otherwise fail with validation_missing_key
                if (!array_key_exists($k_name, $v)) {
                    if (@$k_desc["optional"]) {
                        continue;
                    }
                    $dflt = @$k_desc['default'];
                    if ($dflt === NULL) {
                        api_error("Validation error ({$context}, {$path}): key {$k_name} is required", 'validation_missing_key');
                    }
                    $v[$k_name] = $dflt;
                }
                validate_content($v[$k_name], $k_desc, $context, $src_encoding, $convert_output, "{$path}/{$k_name}");
            }
            if (!$desc['allow_extra_keys']) {
                // check for unknown (not allowed) keys
                foreach ($v as $k_name => $k_value) {
                    if (!array_key_exists($k_name, $content) && strpos($k_name, "__") !== 0) {
                        api_error("Validation error ({$context}, {$path}): key {$k_name} is not allowed", 'validation_extra_key');
                    }
                }
            }
            break;
        case 'array':
            foreach ($v as &$i) {
                validate_content($i, $desc['item'], $context, $src_encoding, $convert_output, "{$path}/item");
            }
            break;
        case 'enum':
            if (!in_array($v, $desc['values'])) {
                api_error("Validation error ({$context}, {$path}): '{$v}' is not a valid enumeration value at position '{$path}'");
            }
            break;
        case 'int':
            $mi = @$desc['min'];
            if ($mi !== NULL && $v < $mi) {
                api_error("Validation error ({$context}, {$path}): value at {$path} ({$v}) must be >= {$mi}", 'validation_out_of_range');
            }
            $mx = @$desc['max'];
            if ($mx !== NULL && $v > $mx) {
                api_error("Validation error ({$context}, {$path}): value at {$path} ({$v}) must be <= {$mx}", 'validation_out_of_range');
            }
            break;
        case 'string':
            // convert char encoding
            $v = api_force_utf8($v, $src_encoding);
            break;
        case 'date':
            if (!$v instanceof IXR_Date) {
                api_error("Validation error ({$context}, {$path}): '{$v}' must be an IXR_Date object");
            }
            $v = $v->year . '-' . $v->month . '-' . $v->day;
            break;
        case 'datetime':
            if (!$v instanceof IXR_Date) {
                api_error("Validation error ({$context}, {$path}): '{$v}' must be an IXR_Date object");
            }
            $v = $v->getIso();
            break;
    }
}