2013-07-26 2 views
5

dev가 조건 규칙에서 조건문을 사용할 수 있도록하여 복잡한 조건을 처리 할 수있는 유효성 검사기를 만듭니다. 요소가 필요하거나하지 않은 경우 결정하는 부울을 반환PHP에서 eval()을 사용하여 조건문이있는 문자열을 평가하지 않으려 고 시도했습니다.

... 
"element_name":{ 
    "required": "conditional", 
    "conditions" : { 
     "requirements" : "(4 < 5)", 
     "requirements" : "('something' == 'something_else')" 
    } 
} 
... 

requirements을 통해 루프가 무엇 PHP가 할 다음 것입니다 코드로 평가 :

규칙 세트와이 예제를 가지고 .

eval() 기능을 사용할 때의 문제점은 매우 분명합니다.

$result = eval(element_name->requirements[0]); 

너희들 감사 : 그래서에만 허용됩니다 어떤 해당 조건 문 주어진 있습니다 부탁 해요,보다이 일을 더 안전한 방법이있다.

---- 업데이트 -----

내가 조금을 사용하여 결국, 나는 매우 정직하기 때문에 당신에게 대답 모든 표시 수 있으면 좋겠다, 아이디어 당신에게 마이크 모두 감사 모든 사람의 생각을 Mike의 것보다 더 많이 얻는다.

필드를 조건부로 유효성을 검사하는 매우 매력적인 방법이기 때문에 나중에 보게 될 것입니다. 내 목표는 이것에 대한 직관적 인 방법을 만드는 것입니다. json 설정 파일에서 조건문을 간단히 두드리는 아이디어가 마음에 들었다. 물론 심각한 보안 위험이나 복잡한 구문 분석 엔진이 필요하기 때문에 개발자가 조건부 언어를 사용하는 방법을 배우지 않아도되지만 결국에는 원본 언어와 매우 유사하게 유지됩니다. 간단한 API를 사용하는 것이 중요하다고 생각합니다. 그렇지 않으면 플랫폼에서 개발을 방해하게됩니다. 그것을 체크 아웃 : -

"element_name":{ 
    "required": "conditional", 
    "conditions" : { 
     "<" : ['4', '5'], 
     "==" : [':element_id', ':other_element'], // will grab the values of those elements and compare 
     "exp" : [['something', '==', 'something_else'], 'OR', [':other_element', '!=', '0']] 
    } 
} 
+1

개발자는 요구 사항 목록을 정확히 어떻게 제공합니까? – Mike

+0

Mike 사과해야합니다. 코드를 수정했습니다. 그러나 일단 개발자가 '필수'를 '조건부'로 표시하면 dev는 위에서 볼 수있는 조건 목록을 포함하는'conditions' obj/array를 제공 할 것으로 예상됩니다. –

+0

@FelipeTadeo http://www.php.net/manual/en/yaml.installation.php 필자는 비슷한 문제가있어 매우 빠른 libYAML C 라이브러리에서 벗어날 수 있기 때문에 조건부에 사용할 수 있다면 이것을 사용하게 될 것입니다 . 불행히도 모듈을 설치하지 않고 다른 사람의 시스템에서 작동해야합니다. 그래도 YAML을 사용할 수 있다면 json은 실제로 하위 집합이며 YAML은 훌륭한 로직을 가능하게하는 기능을 제공합니다. –

답변

3

dethtron5000의 대답을 확장하려면 엄청나게 복잡한 정규 표현식을 방지하기 위해 이것을 생각한 한 가지 방법은 개발자가 조건문을 다차원 조건문으로 분해하고 재귀 함수를 사용하여 루프를 작성하는 것입니다. 각 레벨에서 "AND"또는 "OR"중 하나가 될 "연산자"를 갖게됩니다 (적어도 이것을 바꾸기를 원한다면 "연산자"라고 부름). 당신의 예에서

이 있습니다. 당신은 조건문을 json_encoding있는 것처럼 (32 < 40 AND 10 > 5 OR 20 == 10)

(그것은 보이는, 그래서 다음과 같은 PHP 배열을 시작하고 거기에서 뒤로 일을 내가 당신에게 할 수 있으리라 믿고있어 단지 json_decode 무엇을 당신의 dev를 사용하면 유효한 PHP 배열을 얻을 수 있습니다.

$arr = array(
    'required' => 'conditional', 
    'conditions' => array(
     'requirements' => array(
      'operator' => 'OR', // this makes it so that if any conditions at this level are true, it returns true 
      0 => array(
       'operator' => 'AND', // this makes it so that all the conditions at this sub-level need to be satisfied to return true 
       array(
        'conditional1' => 32, 
        'conditional2' => 40, 
        'operation' => 'lessthan', 
       ), 
       array(
        'conditional1' => 10, 
        'conditional2' => 5, 
        'operation' => 'greaterthan', 
       ), 
      ), 
      1 => array(
       // Since there is only one condition here, it is not necessary to specify "AND" or "OR" 
       array(
        'conditional1' => 20, 
        'conditional2' => 10, 
        'operation' => 'equals', 
       ), 
      ), 
     ), 
    ), 
); 

할 수 있습니다 다음과 같은 재귀 함수와 조건문을 반복 : 나는 그것을로 json_encode 때

function check_req(Array $reqs) { 
    $operator = (isset($reqs['operator'])) ? $reqs['operator'] : 'AND'; 
    unset($reqs['operator']); 
    foreach ($reqs as $req) { 
     if (isset($req['operation'])) { 
      switch ($req['operation']) { 
       case 'lessthan': 
        $valids[] = $req['conditional1'] < $req['conditional2']; 
        break; 
       case 'greaterthan': 
        $valids[] = $req['conditional1'] > $req['conditional2']; 
        break; 
       case 'equals': 
        $valids[] = $req['conditional1'] == $req['conditional2']; 
        break; 
      } 
     } 
     else { 
      $valids[] = check_req($req); 
     } 
    } 
    if ($operator == 'OR') { 
     foreach ($valids as $valid) { 
      if ($valid == true) { 
       return true; 
      } 
     } 
     return false; 
    } 
    else { 
     foreach ($valids as $valid) { 
      if ($valid == false) { 
       return false; 
      } 
     } 
     return true; 
    } 
} 

var_dump(check_req($arr['conditions']['requirements'])); // true in this case 

, 내가 얻을 :

위의 예는 다음과 PHP 배열로 표현된다
{ 
    "required":"conditional", 
    "conditions":{ 
     "requirements":{ 
      "operator":"OR", 
      "0":{ 
       "operator":"AND", 
       "0":{ 
        "conditional1":32, 
        "conditional2":40, 
        "operation":"lessthan" 
       }, 
       "1":{ 
        "conditional1":10, 
        "conditional2":5, 
        "operation":"greaterthan" 
       } 
      }, 
      "1":[{ 
       "conditional1":20, 
       "conditional2":10, 
       "operation":"equals" 
      }] 
     } 
    } 
} 

나는 이것이 개발자가 제공해야한다고 가정합니다.

+1

마이크 감사합니다! 예, 논리 연산자라고합니다. 용어에 관해서는 자의식이 있습니다. 따라서 나중에 참조 할 수있는 정의에 대한 간단한 목록이 있습니다. 논리 연산자 = AND AND 비교 연산자 < >! = == === ext..'. 고맙다! –

+0

개발자가 간단하게 유지하려면이 아이디어를 받아 문자열을 파싱하여 제공 한 것과 같은 배열로 만든 다음 여기에 배치 할 때 실행해야한다고 생각합니다. 그것은 지옥 일이지만, 확실히 json의 문서와 길이에 시간을 절약 할 것입니다. –

+1

dev가 json_encoded 문자열을 제공 할 수 있다면 여기에있는 코드를 사용하여 [json_decode] (http://php.net/json_decode) 코드를 작성하십시오. 수동으로 구문 분석 할 필요가 없습니다. 이미 당신이 지금 가지고있는 것과 아주 가깝습니다. – Mike

1

예 switch 문 마주 사용할 수 있습니다

case "==": 
return $a==$b; 
break; 
case "+": 
return $a+$b; 
break; 

etc... 

default: 
return false; 
break; 

키는 스위치에 부품을 보내는 방법입니다

스위치 ($ 연산자) -이 결국 여러 가지 방법이 있습니다.

eval()을 신뢰할 수없는 사용자 코드에 노출시키는 것은 미친 일입니다. 드루팔 (Drupal과 같은 상황에서의 사용법을 알 수 있습니다. 여기서 uber 사용자는 PHP 페이지를 만들 수 있지만, 그렇다면 신뢰할 수있는 사용자 만이 그렇게 할 수 있습니다. 이 방법으로 실행할 수있는 코드를 제한하는 것이 훨씬 좋습니다.

편집 :

여러 연산자를 처리하기 위해, 당신은 여전히 ​​당신의 산술 단위로이 실행되지만 별도로 각 연산자를 평가해야합니다. 즉, 대괄호와 같이 한 번에 한 문자 씩 명령 문자열을 평가해야 할 수 있습니다. 자바 스크립트에서 클라이언트 측에서 수학을하는 것이 더 좋을 수도 있습니다. 답변이 서버에 전송되지 않는 한 안전합니다 (JS의 평가가 DOM 주입 공격으로 이어질 수 있음)

내가 잘못된 제안을하면이 방법을 사용해야합니까? 작은 덩어리로 입력을 처리 할 수있는 더 좋은 방법이 있을까요? 이 시스템을 사용한다면 웹 사이트를 사용하는 대신 책상 계산기를 사용하여 작업을 수행 할 수 있습니다. 더 많은 사용자 작업을 수행하십시오.

+0

당신의 제안에 감사드립니다! 이것은 꽤 두더지입니다. 나는 코드를 제한함으로써 얻을 수있는 이점을 알고 있지만 다음과 같은 조건을 고려해야한다.'(32 < 40 AND 10 > 5 OR 20 == 10)' –

4

한 가지 해결책은 JSON을 구조화하여 수행 할 수있는 전체 작업 집합을 제한하는 것입니다. 예를

"element_name":{ 
"required": "conditional", 
"requirements" : [ 
     { 
      "condition1": 4, 
      "condition1": 5, 
      "operation": "greaterthan" 
     } 
} 

를 들어 다음 PHP에서 (psedo-codey하지만 당신은 아이디어를 얻을 수 있습니다) :

foreach($requirements as $key => $test){ 
    switch($test->operation) { 
     case 'greaterthan': 
      return ($test->condition1 > $test->condition2); 
     /// put other comparison types here 

    } 
} 

이 더 많은 비즈니스 로직을 코딩 의미를하지만, 궁극적으로 더 안전 할 것이다과 같은 주사를 방지 할 수 eval.

+0

이것은 훌륭한 대안이다. dev는이 문서를 사용하는 방법을 알아 내기 위해 내 문서를 파헤 치기 때문에 이런 식으로 일하는 것을 피하기를 바랬습니다. 너무 나쁘다는 위의 예처럼 안전하지 않을 수 있습니다. 어쩌면 내가 미친 정규식을 깨뜨릴 지 모르지만 나는 그다지 잘하지 않습니다. –

2

초기 텍스트를 분해하려면 json_decode()를 사용할 수 있습니까? 이것은 아무것도 실행하지 않지만 큰 문자열을 배열 구조로 변환합니다.

실제 개별 표현의 경우 parsekit_compile_string에 액세스 할 수 있습니까?

이렇게하면 원시 텍스트를 PHP 바이트 코드 연산으로 변환 할 수 있습니다. switch 문을 통해 연산을 해석하는 것이 어렵지 않아야합니다. 당신이 요구 사항에서 기대했던 것의 제약 된 특성 때문에, 이것은 많은 코드가 아닐 것입니다.

parsekit_compile_string이 없으면 정규식을 시도 할 수 있지만 더 취약한 해결책이 될 수 있습니다.

관련 문제