CI 코드

제목 rest api 만들때 폼검증부분 관련..
글쓴이 작성시각 2016/11/02 10:26:14
댓글 : 5 추천 : 1 스크랩 : 0 조회수 : 29239   RSS

https://github.com/chriskacerguis/codeigniter-restserver

를 적용하다 보니 rest api에서 맞지 않는 부분이 있었습니다.

뭐냐하면 c - post, r - get, u - put, d - delete 메소드를 타야 하는데 ci3의 폼검증은 post만 되더라고요.

그래서 모든 메소드에 한해서 폼검증이 되도록 해야 맞는 설계라 생각했습니다.

요즘 api 서버 만들때 ci보다는 node로 만드는 추세인거 같더라고요 왜나하면 좀 더 로직이 복잡하지 않도록 하기 위해서

인거같습니다. 하지만 저는 관리자에서 api컨트롤러를 통해 crud를 구현할 계획이었습니다. 왜냐하면 기존 db 처리한 model을 가져다 쓰기

쉽기 때문이었습니다. 그래서 위 rest서버의 코드를 확장하기로 마음먹었습니다.

APPPATH . '/libraries/Api_Controller.php';

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
require APPPATH . '/libraries/REST_Controller.php';
abstract class Api_Controller extends REST_Controller {
	function __construct()
    {
    	parent::__construct();
    }

	//검증
    public function valid (array $valid_config, $successFn=FALSE, $failFn=FALSE) {
        $this->load->library('form_validation');
        $this->form_validation->api_set_rules($valid_config);
        //폼검증.
        if ($this->form_validation->api_run() == FALSE) {
            if ($failFn) $failFn();
        } else {
            if ($successFn) $successFn();
        }
    }

    public function get_method () {
    	return $this->_detect_method();
    }

}

MY_Form_validation.php

public function api_set_rules($field, $label = '', $rules = array(), $errors = array())
	{
		// If an array was passed via the first parameter instead of individual string
		// values we cycle through it and recursively call this function.
		if (is_array($field))
		{
			foreach ($field as $row)
			{
				// Houston, we have a problem...
				if ( ! isset($row['field'], $row['rules']))
				{
					continue;
				}

				// If the field label wasn't passed we use the field name
				$label = isset($row['label']) ? $row['label'] : $row['field'];

				// Add the custom error message array
				$errors = (isset($row['errors']) && is_array($row['errors'])) ? $row['errors'] : array();

				// Here we go!
				$this->api_set_rules($row['field'], $label, $row['rules'], $errors);
			}
			return $this;
		}

		// No fields or no rules? Nothing to do...
		if ( ! is_string($field) OR $field === '' OR empty($rules))
		{
			return $this;
		}
		elseif ( ! is_array($rules))
		{
			// BC: Convert pipe-separated rules string to an array
			if ( ! is_string($rules))
			{
				return $this;
			}

			$rules = preg_split('/\|(?![^\[]*\])/', $rules);
		}

		// If the field label wasn't passed we use the field name
		$label = ($label === '') ? $field : $label;

		$indexes = array();

		// Is the field name an array? If it is an array, we break it apart
		// into its components so that we can fetch the corresponding POST data later
		if (($is_array = (bool) preg_match_all('/\[(.*?)\]/', $field, $matches)) === TRUE)
		{
			sscanf($field, '%[^[][', $indexes[0]);

			for ($i = 0, $c = count($matches[0]); $i < $c; $i++)
			{
				if ($matches[1][$i] !== '')
				{
					$indexes[] = $matches[1][$i];
				}
			}
		}

		// Build our master array
		$this->_field_data[$field] = array(
			'field'		=> $field,
			'label'		=> $label,
			'rules'		=> $rules,
			'errors'	=> $errors,
			'is_array'	=> $is_array,
			'keys'		=> $indexes,
			'postdata'	=> NULL,
			'error'		=> ''
		);

		return $this;
	}

	public function api_run($group = '')
	{
		$method = $this->CI->get_method();
		$validation_array = $this->CI->$method();

		// Does the _field_data array containing the validation rules exist?
		// If not, we look to see if they were assigned via a config file
		if (count($this->_field_data) === 0)
		{
			// No validation rules?  We're done...
			if (count($this->_config_rules) === 0)
			{
				return FALSE;
			}

			if (empty($group))
			{
				// Is there a validation rule for the particular URI being accessed?
				$group = trim($this->CI->uri->ruri_string(), '/');
				isset($this->_config_rules[$group]) OR $group = $this->CI->router->class.'/'.$this->CI->router->method;
			}

			$this->set_rules(isset($this->_config_rules[$group]) ? $this->_config_rules[$group] : $this->_config_rules);

			// Were we able to set the rules correctly?
			if (count($this->_field_data) === 0)
			{
				log_message('debug', 'Unable to find validation rules');
				return FALSE;
			}
		}

		// Load the language file containing error messages
		$this->CI->lang->load('form_validation');

		// Cycle through the rules for each field and match the corresponding $validation_data item
		foreach ($this->_field_data as $field => $row)
		{
			// Fetch the data from the validation_data array item and cache it in the _field_data array.
			// Depending on whether the field name is an array or a string will determine where we get it from.
			if ($row['is_array'] === TRUE)
			{
				$this->_field_data[$field]['postdata'] = $this->_reduce_array($validation_array, $row['keys']);
			}
			elseif (isset($validation_array[$field]))
			{
				$this->_field_data[$field]['postdata'] = $validation_array[$field];
			}
		}

		// Execute validation rules
		// Note: A second foreach (for now) is required in order to avoid false-positives
		//	 for rules like 'matches', which correlate to other validation fields.
		foreach ($this->_field_data as $field => $row)
		{
			// Don't try to validate if we have no rules set
			if (empty($row['rules']))
			{
				continue;
			}

			$this->_execute($row, $row['rules'], $this->_field_data[$field]['postdata']);
		}

		// Did we end up with any errors?
		$total_errors = count($this->_error_array);
		if ($total_errors > 0)
		{
			$this->_safe_form_data = TRUE;
		}

		// Now we need to re-set the POST data with the new, processed data
		$this->_reset_post_array();

		return ($total_errors === 0);
	}

 

rest api 만들때는 

<?php defined('BASEPATH') OR exit('No direct script access allowed');
require APPPATH . '/libraries/Api_Controller.php';
class Auth extends Api_Controller {
	function __construct()
    {
    	parent::__construct();
        $this->load->model(HM_F.'/auth_model');
        $this->load->model(MG_F.'/company_model');
    }

    //중복확인
    public function overlap_get() {
        $config = array(
            array('field'=>'name', 'label'=>'이름', 'rules'=>'required|trim|max_length[10]|korean_alpha_dash'),
            array('field'=>'id', 'label'=>'아이디', 'rules'=>'required|trim|alpha_dash|max_length[20]'),
            array('field'=>'hp', 'label'=>'휴대폰', 'rules'=>'required|trim|max_length[13]'),
            array('field'=>'email', 'label'=>'이메일', 'rules'=>'required|trim|valid_email|max_length[50]'),
        );
        $this->valid($config,function(){
           $this->response(array("msg"=>"성공"), REST_Controller::HTTP_OK);
        },function(){
            $this->response(array("msg"=>strip_tags(validation_errors())), REST_Controller::HTTP_BAD_REQUEST);
        });
    }
}

이런식으로 get post put delete 등 메소드별로 폼 검증할 수 있습니다.

 다음글 기본 퍼미션 라이브러리 (3)
 이전글 pg object 프로젝트 [inicis 웹표준, ... (5)

댓글

kaido / 2016/11/02 11:15:35 / 추천 0
수고하셨습니다~ ^^
한대승(불의회상) / 2016/11/02 11:18:47 / 추천 0

확장된 폼검증 라이브러리 감사 합니다.

깔끔하게 잘 정리 하셨습니다.

참고로 CI3.0 부터는 _POST로 들어온 데이터 이외의 데이터를 검색 할 수 있도록 폼검증 라이브러리가 개선 되었습니다.

post 방식이 아닌 다른 메소드(get,delete,put) 방식으로 전달된 데이터를 배열에 저장하고 아래 처럼 하시면 됩니다.

$data = array(
        'username' => 'johndoe',
        'password' => 'mypassword',
        'passconf' => 'mypassword'
);

$this->form_validation->set_data($data);

더 자세한 내용은 메뉴얼 폼검증 라이브러리 참고 하세요.

http://www.ciboard.co.kr/user_guide/kr/libraries/form_validation.html#validating-an-array-other-than-post

/ 2016/11/02 15:04:20 / 추천 0

@불의회상

앗 이런방법이.. 구지 확장 안해도 해결 할 수 있는것 같아요?

/ 2016/11/02 15:16:05 / 추천 1

불의회상님이 알려주신 내용을 바탕으로 재 작성해 봤습니다.

기존 소스에서 MY_Form_validation.php의 내용은 추가 안해도 되고,

Api_Controller.php에서

//검증
    public function valid (array $valid_config, $successFn=FALSE, $failFn=FALSE) {
        $this->load->library('form_validation');
        $method = $this->get_method();
        $this->form_validation->set_data($this->$method());
        $this->form_validation->set_rules($valid_config);
        //폼검증.
        if ($this->form_validation->run() == FALSE) {
            if ($failFn) $failFn();
        } else {
            if ($successFn) $successFn();
        }
    }

valid부분만 수정하면 조금 더 소스가 간결해 집니다.

엘제이 / 2017/08/09 11:12:49 / 추천 0
추상클래스로 이용하는 이유가 잇나요?