/**
  * @param \Civi\API\Event\Event $event
  *
  * @throws \Exception
  */
 public function onApiPrepare_validate(\Civi\API\Event\Event $event)
 {
     $apiRequest = $event->getApiRequest();
     // Not sure why this is omitted for generic actions. It would make sense to omit 'getfields', but that's only one generic action.
     if (isset($apiRequest['function']) && !$apiRequest['is_generic'] && isset($apiRequest['fields'])) {
         _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $apiRequest['fields']);
         $event->setApiRequest($apiRequest);
     }
 }
 function test_civicrm_api3_validate_fields_exception()
 {
     $params = array('join_date' => 'abc');
     try {
         $fields = civicrm_api3('Membership', 'getfields', array('action' => 'get'));
         _civicrm_api3_validate_fields('Membership', 'get', $params, $fields['values']);
     } catch (Exception $expected) {
         $this->assertEquals('join_date is not a valid date: abc', $expected->getMessage());
     }
 }
 /**
  * Perform input validation on params that use the join syntax
  *
  * Arguably this should be done at the api wrapper level, but doing it here provides a bit more consistency
  * in that api permissions to perform the join are checked first.
  *
  * @param $fieldName
  * @param $value
  * @throws \Exception
  */
 private function validateNestedInput($fieldName, &$value)
 {
     $stack = explode('.', $fieldName);
     $spec = $this->apiFieldSpec;
     $fieldName = array_pop($stack);
     foreach ($stack as $depth => $name) {
         $entity = $spec[$name]['FKApiName'];
         $spec = $spec[$name]['FKApiSpec'];
     }
     $params = array($fieldName => $value);
     \_civicrm_api3_validate_fields($entity, 'get', $params, $spec);
     $value = $params[$fieldName];
 }
/**
 *
 * @param <type> $msg
 * @param <type> $data
 * @param object $dao DAO / BAO object to be freed here
 *
 * @return <type>
 */
function civicrm_api3_create_error($msg, $data = array(), &$dao = NULL)
{
    //fix me - $dao should be param 4 & 3 should be $apiRequest
    if (is_object($dao)) {
        $dao->free();
    }
    if (is_array($dao)) {
        if ($msg == 'DB Error: constraint violation' || $msg == 'DB Error: already exists') {
            try {
                _civicrm_api3_validate_fields($dao['entity'], $dao['action'], $dao['params'], True);
            } catch (Exception $e) {
                $msg = $e->getMessage();
            }
        }
    }
    $data['is_error'] = 1;
    $data['error_message'] = $msg;
    if (is_array($dao) && isset($dao['params']) && is_array($dao['params']) && CRM_Utils_Array::value('api.has_parent', $dao['params'])) {
        throw new Exception('Error in call to ' . $dao['entity'] . '_' . $dao['action'] . ' : ' . $msg);
    }
    return $data;
}
Beispiel #5
0
 /**
  * @param string $msg
  *   Descriptive error message.
  * @param array $data
  *   Error data.
  * @param array $apiRequest
  *   The full description of the API request.
  * @param mixed $code
  *   Doesn't appear to be used.
  *
  * @throws \API_Exception
  * @return array
  *   Array<type>.
  */
 public function createError($msg, $data, $apiRequest, $code = NULL)
 {
     // FIXME what to do with $code?
     if ($msg == 'DB Error: constraint violation' || substr($msg, 0, 9) == 'DB Error:' || $msg == 'DB Error: already exists') {
         try {
             $fields = _civicrm_api3_api_getfields($apiRequest);
             _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $fields, TRUE);
         } catch (\Exception $e) {
             $msg = $e->getMessage();
         }
     }
     $data = civicrm_api3_create_error($msg, $data);
     if (isset($apiRequest['params']) && is_array($apiRequest['params']) && !empty($apiRequest['params']['api.has_parent'])) {
         $errorCode = empty($data['error_code']) ? 'chained_api_failed' : $data['error_code'];
         throw new \API_Exception('Error in call to ' . $apiRequest['entity'] . '_' . $apiRequest['action'] . ' : ' . $msg, $errorCode, $data);
     }
     return $data;
 }
Beispiel #6
0
 function validateFields($entity, $params, $action = 'create')
 {
     $bao = 'CRM_Appraisals_BAO_' . $entity;
     $fields = $bao::fields();
     $fieldKeys = $bao::fieldKeys();
     $mappedParams = array();
     foreach ($fieldKeys as $key => $value) {
         if (!empty($params[$key])) {
             $mappedParams[$value] = $params[$key];
         }
     }
     _civicrm_api3_validate_fields($entity, $action, $mappedParams, $fields);
     foreach ($fieldKeys as $key => $value) {
         if (!empty($mappedParams[$value])) {
             $params[$key] = $mappedParams[$value];
         }
     }
     return $params;
 }
Beispiel #7
0
/**
 * @param string $entity
 *   type of entities to deal with
 * @param string $action
 *   create, get, delete or some special action name.
 * @param array $params
 *   array to be passed to function
 * @param null $extra
 *
 * @return array|int
 */
function civicrm_api($entity, $action, $params, $extra = NULL)
{
    $apiRequest = array();
    $apiRequest['entity'] = CRM_Utils_String::munge($entity);
    $apiRequest['action'] = CRM_Utils_String::munge($action);
    $apiRequest['version'] = civicrm_get_api_version($params);
    $apiRequest['params'] = $params;
    $apiRequest['extra'] = $extra;
    $apiWrappers = array(CRM_Utils_API_HTMLInputCoder::singleton(), CRM_Utils_API_NullOutputCoder::singleton(), CRM_Utils_API_ReloadOption::singleton(), CRM_Utils_API_MatchOption::singleton());
    CRM_Utils_Hook::apiWrappers($apiWrappers, $apiRequest);
    try {
        require_once 'api/v3/utils.php';
        require_once 'api/Exception.php';
        if (!is_array($params)) {
            throw new API_Exception('Input variable `params` is not an array', 2000);
        }
        _civicrm_api3_initialize();
        $errorScope = CRM_Core_TemporaryErrorScope::useException();
        // look up function, file, is_generic
        $apiRequest += _civicrm_api_resolve($apiRequest);
        if (strtolower($action) == 'create' || strtolower($action) == 'delete' || strtolower($action) == 'submit') {
            $apiRequest['is_transactional'] = 1;
            $transaction = new CRM_Core_Transaction();
        }
        // support multi-lingual requests
        if ($language = CRM_Utils_Array::value('option.language', $params)) {
            _civicrm_api_set_locale($language);
        }
        _civicrm_api3_api_check_permission($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
        $fields = _civicrm_api3_api_getfields($apiRequest);
        // we do this before we
        _civicrm_api3_swap_out_aliases($apiRequest, $fields);
        if (strtolower($action) != 'getfields') {
            if (empty($apiRequest['params']['id'])) {
                $apiRequest['params'] = array_merge(_civicrm_api3_getdefaults($apiRequest, $fields), $apiRequest['params']);
            }
            //if 'id' is set then only 'version' will be checked but should still be checked for consistency
            civicrm_api3_verify_mandatory($apiRequest['params'], NULL, _civicrm_api3_getrequired($apiRequest, $fields));
        }
        // For input filtering, process $apiWrappers in forward order
        foreach ($apiWrappers as $apiWrapper) {
            $apiRequest = $apiWrapper->fromApiInput($apiRequest);
        }
        $function = $apiRequest['function'];
        if ($apiRequest['function'] && $apiRequest['is_generic']) {
            // Unlike normal API implementations, generic implementations require explicit
            // knowledge of the entity and action (as well as $params). Bundle up these bits
            // into a convenient data structure.
            $result = $function($apiRequest);
        } elseif ($apiRequest['function'] && !$apiRequest['is_generic']) {
            _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params'], $fields);
            $result = isset($extra) ? $function($apiRequest['params'], $extra) : $function($apiRequest['params']);
        } else {
            return civicrm_api3_create_error("API (" . $apiRequest['entity'] . ", " . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
        }
        // For output filtering, process $apiWrappers in reverse order
        foreach (array_reverse($apiWrappers) as $apiWrapper) {
            $result = $apiWrapper->toApiOutput($apiRequest, $result);
        }
        if (CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
            if ($result['is_error'] === 0) {
                return 1;
            } else {
                return 0;
            }
        }
        if (!empty($apiRequest['params']['format.only_id']) && isset($result['id'])) {
            return $result['id'];
        }
        if (CRM_Utils_Array::value('is_error', $result, 0) == 0) {
            _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']);
        }
        if (function_exists('xdebug_time_index') && CRM_Utils_Array::value('debug', $apiRequest['params']) && is_array($result)) {
            $result['xdebug']['peakMemory'] = xdebug_peak_memory_usage();
            $result['xdebug']['memory'] = xdebug_memory_usage();
            $result['xdebug']['timeIndex'] = xdebug_time_index();
        }
        return $result;
    } catch (PEAR_Exception $e) {
        if (CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
            return 0;
        }
        $error = $e->getCause();
        if ($error instanceof DB_Error) {
            $data["error_code"] = DB::errorMessage($error->getCode());
            $data["sql"] = $error->getDebugInfo();
        }
        if (!empty($apiRequest['params']['debug'])) {
            if (method_exists($e, 'getUserInfo')) {
                $data['debug_info'] = $error->getUserInfo();
            }
            if (method_exists($e, 'getExtraData')) {
                $data['debug_info'] = $data + $error->getExtraData();
            }
            $data['trace'] = $e->getTraceAsString();
        } else {
            $data['tip'] = "add debug=1 to your API call to have more info about the error";
        }
        $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest);
        if (!empty($apiRequest['is_transactional'])) {
            $transaction->rollback();
        }
        return $err;
    } catch (API_Exception $e) {
        if (!isset($apiRequest)) {
            $apiRequest = array();
        }
        if (CRM_Utils_Array::value('format.is_success', CRM_Utils_Array::value('params', $apiRequest)) == 1) {
            return 0;
        }
        $data = $e->getExtraParams();
        $data['entity'] = CRM_Utils_Array::value('entity', $apiRequest);
        $data['action'] = CRM_Utils_Array::value('action', $apiRequest);
        $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
        if (CRM_Utils_Array::value('debug', CRM_Utils_Array::value('params', $apiRequest)) && empty($data['trace'])) {
            $err['trace'] = $e->getTraceAsString();
        }
        if (!empty($apiRequest['is_transactional'])) {
            $transaction->rollback();
        }
        return $err;
    } catch (Exception $e) {
        if (CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
            return 0;
        }
        $data = array();
        $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
        if (!empty($apiRequest['params']['debug'])) {
            $err['trace'] = $e->getTraceAsString();
        }
        if (!empty($apiRequest['is_transactional'])) {
            $transaction->rollback();
        }
        return $err;
    }
}
Beispiel #8
0
/**
 *
 * @param <type> $data
 * @param array $data
 * @param object $dao DAO / BAO object to be freed here
 *
 * @throws API_Exception
 * @return array <type>
 */
function civicrm_api3_create_error($msg, $data = array(), &$dao = NULL)
{
    //fix me - $dao should be param 4 & 3 should be $apiRequest
    if (is_object($dao)) {
        $dao->free();
    }
    if (is_array($dao)) {
        if ($msg == 'DB Error: constraint violation' || substr($msg, 0, 9) == 'DB Error:' || $msg == 'DB Error: already exists') {
            try {
                $fields = _civicrm_api3_api_getfields($dao);
                _civicrm_api3_validate_fields($dao['entity'], $dao['action'], $dao['params'], $fields, TRUE);
            } catch (Exception $e) {
                $msg = $e->getMessage();
            }
        }
    }
    $data['is_error'] = 1;
    $data['error_message'] = $msg;
    // we will show sql to privelledged user only (not sure of a specific
    // security hole here but seems sensible - perhaps should apply to the trace as well?
    if (isset($data['sql']) && CRM_Core_Permission::check('Administer CiviCRM')) {
        $data['debug_information'] = $data['sql'];
    }
    if (is_array($dao) && isset($dao['params']) && is_array($dao['params']) && !empty($dao['params']['api.has_parent'])) {
        $errorCode = empty($data['error_code']) ? 'chained_api_failed' : $data['error_code'];
        throw new API_Exception('Error in call to ' . $dao['entity'] . '_' . $dao['action'] . ' : ' . $msg, $errorCode, $data);
    }
    return $data;
}
function civicrm_api($entity, $action, $params, $extra = NULL)
{
    $apiWrappers = array(CRM_Core_HTMLInputCoder::singleton());
    try {
        require_once 'api/v3/utils.php';
        require_once 'api/Exception.php';
        if (!is_array($params)) {
            throw new API_Exception('Input variable `params` is not an array', 2000);
        }
        _civicrm_api3_initialize();
        $errorScope = CRM_Core_TemporaryErrorScope::useException();
        require_once 'CRM/Utils/String.php';
        require_once 'CRM/Utils/Array.php';
        $apiRequest = array();
        $apiRequest['entity'] = CRM_Utils_String::munge($entity);
        $apiRequest['action'] = CRM_Utils_String::munge($action);
        $apiRequest['version'] = civicrm_get_api_version($params);
        $apiRequest['params'] = $params;
        $apiRequest['extra'] = $extra;
        // look up function, file, is_generic
        $apiRequest += _civicrm_api_resolve($apiRequest);
        if (strtolower($action) == 'create' || strtolower($action) == 'delete') {
            $apiRequest['is_transactional'] = 1;
            $tx = new CRM_Core_Transaction();
        }
        $errorFnName = $apiRequest['version'] == 2 ? 'civicrm_create_error' : 'civicrm_api3_create_error';
        if ($apiRequest['version'] > 2) {
            _civicrm_api3_api_check_permission($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
        }
        // we do this before we
        _civicrm_api3_swap_out_aliases($apiRequest);
        if (strtolower($action) != 'getfields') {
            if (!CRM_Utils_Array::value('id', $params)) {
                $apiRequest['params'] = array_merge(_civicrm_api3_getdefaults($apiRequest), $apiRequest['params']);
            }
            //if 'id' is set then only 'version' will be checked but should still be checked for consistency
            civicrm_api3_verify_mandatory($apiRequest['params'], NULL, _civicrm_api3_getrequired($apiRequest));
        }
        foreach ($apiWrappers as $apiWrapper) {
            $apiRequest = $apiWrapper->fromApiInput($apiRequest);
        }
        $function = $apiRequest['function'];
        if ($apiRequest['function'] && $apiRequest['is_generic']) {
            // Unlike normal API implementations, generic implementations require explicit
            // knowledge of the entity and action (as well as $params). Bundle up these bits
            // into a convenient data structure.
            $result = $function($apiRequest);
        } elseif ($apiRequest['function'] && !$apiRequest['is_generic']) {
            _civicrm_api3_validate_fields($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
            $result = isset($extra) ? $function($apiRequest['params'], $extra) : $function($apiRequest['params']);
        } else {
            return $errorFnName("API (" . $apiRequest['entity'] . "," . $apiRequest['action'] . ") does not exist (join the API team and implement it!)");
        }
        foreach ($apiWrappers as $apiWrapper) {
            $result = $apiWrapper->toApiOutput($apiRequest, $result);
        }
        if (CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
            if ($result['is_error'] === 0) {
                return 1;
            } else {
                return 0;
            }
        }
        if (CRM_Utils_Array::value('format.only_id', $apiRequest['params']) && isset($result['id'])) {
            return $result['id'];
        }
        if (CRM_Utils_Array::value('is_error', $result, 0) == 0) {
            _civicrm_api_call_nested_api($apiRequest['params'], $result, $apiRequest['action'], $apiRequest['entity'], $apiRequest['version']);
        }
        if (CRM_Utils_Array::value('format.smarty', $apiRequest['params']) || CRM_Utils_Array::value('format_smarty', $apiRequest['params'])) {
            // return _civicrm_api_parse_result_through_smarty($result,$apiRequest['params']);
        }
        if (function_exists('xdebug_time_index') && CRM_Utils_Array::value('debug', $apiRequest['params']) && is_array($result)) {
            $result['xdebug']['peakMemory'] = xdebug_peak_memory_usage();
            $result['xdebug']['memory'] = xdebug_memory_usage();
            $result['xdebug']['timeIndex'] = xdebug_time_index();
        }
        return $result;
    } catch (PEAR_Exception $e) {
        if (CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
            return 0;
        }
        $data = array();
        $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest);
        if (CRM_Utils_Array::value('debug', $apiRequest['params'])) {
            $err['trace'] = $e->getTraceSafe();
        } else {
            $err['tip'] = "add debug=1 to your API call to have more info about the error";
        }
        if (CRM_Utils_Array::value('is_transactional', $apiRequest)) {
            $tx->rollback();
        }
        return $err;
    } catch (API_Exception $e) {
        if (!isset($apiRequest)) {
            $apiRequest = array();
        }
        if (CRM_Utils_Array::value('format.is_success', CRM_Utils_Array::value('params', $apiRequest)) == 1) {
            return 0;
        }
        $data = $e->getExtraParams();
        $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
        if (CRM_Utils_Array::value('debug', CRM_Utils_Array::value('params', $apiRequest))) {
            $err['trace'] = $e->getTraceAsString();
        }
        if (CRM_Utils_Array::value('is_transactional', CRM_Utils_Array::value('params', $apiRequest))) {
            $tx->rollback();
        }
        return $err;
    } catch (Exception $e) {
        if (CRM_Utils_Array::value('format.is_success', $apiRequest['params']) == 1) {
            return 0;
        }
        $data = array();
        $err = civicrm_api3_create_error($e->getMessage(), $data, $apiRequest, $e->getCode());
        if (CRM_Utils_Array::value('debug', $apiRequest['params'])) {
            $err['trace'] = $e->getTraceAsString();
        }
        if (CRM_Utils_Array::value('is_transactional', $apiRequest)) {
            $tx->rollback();
        }
        return $err;
    }
}