2016-09-08 6 views
0

에서 SQL의 유효성을 검사 :치명적인 되돌아 내가 일반적인 형태의 일부 SQL을 검증하기 위해 노력하고있어 PHP

UPDATE `mytable` SET `keyname` = 'keyvalue', 
     `a` = 'somestring', 
     `b` = 123, 
     `c` = NULL 
     WHERE `keyname` = 'keyvalue' 

이것보다 더 많은 필드가 있습니다. 값은 문자열, 정수 또는 NULL입니다.

(?ix) 

^ 

\s* 
UPDATE \s+ `mytable` \s+ 
SET \s+ `keyname` \s = \s 'keyvalue' 
(, \s+ 
    `[A-Z_]+` (?# field name) 
    \s+ = \s+ (?# equals value) 
    (
    -?[0-9]+   (?# an integer, possibly negative) 
    | 
    '(\\.|''|[^'])*' (?# a string in single quotes) 
    | 
    NULL    (?# NULL) 
) 
)+ (?# one or more such assignments) 

\s+ WHERE \s+ `keyname` \s+ = \s+ 'keyvalue' 

$ 

이이 시점까지 작동합니다

내 원래 정규 표현식이 있습니다. https://regex101.com/에 따르면 180 단계로 일치합니다.

불행하게도 실제 SQL 예를 들어,보다 더 긴 것입니다 : 지금 4301 단계를 수행

UPDATE `mytable` 
SET `keyname` = 'keyvalue', 
`Markup` = 
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
''Quisque vel mattis odio, quis iaculis sem.'' 
Nulla facilisi. 
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere 
cubilia Curae; Fusce ut dui venenatis, maximus lorem eget, ornare ex. 
Aenean tempus pulvinar est, id fringilla enim sagittis id. Mauris finibus 
cursus commodo.\r\n\r\n 
Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere 
cubilia Curae; Fusce ut dui venenatis, maximus lorem eget, ornare ex. 
Aenean tempus pulvinar est, id fringilla enim sagittis id. Mauris finibus 
cursus commodo.\r\n\r\n\r\n 
\'Aenean in augue a est vulputate accumsan.\' 
Phasellus nulla diam, laoreet a elit non, mattis finibus magna. Phasellus 
faucibus iaculis mi sed pulvinar.\r\n 
Aliquam non nisl ultricies, aliquam augue vitae, efficitur sapien. 
Etiam viverra, magna a laoreet sollicitudin, ipsum erat tincidunt sem, nec 
faucibus enim tortor eget massa. 
Nunc nisi orci, lacinia vitae dictum et, vestibulum sed metus. ', 
`From_Date` = NULL, 
`To_Date` = NULL, 
`Foo` = '', 
`Box_Colour` = NULL, 
`Modification_Date` = '2016-09-08 12:30:47', 
`Modified_User` = 1, 
`Modified_IP` = '192.168.1.1' 
WHERE `keyname` = 'keyvalue' 

. 사실 Lorem Ipsum을 더 크게 만들면 20000 단계가 넘습니다. 우리가 오류를 소개하면

또한 변경 예를 들어, (일치하지 만들려면) :

`Foo` = '', 

그것은 지금 치명적인가을 되돌아와 충돌

`Foo` = '' 

에.

내부 그룹 (키/값 쌍)을 원자 그룹으로 만들어 Catastrophic 역 추적을 제거 할 수 있습니다 (한도 내에서).

SET \s+ `keyname` \s = \s 'keyvalue' 
(, \s+ 

실제 데이터에 20000+ 단계 내 대상 웹 서버에서 실행할 때 PHP 스크립트가 충돌을 일으키는

SET \s+ `keyname` \s = \s 'keyvalue' 
(?>, \s+ 

에 : 그 변화이다. 좀 더 현실적인 가치로 단계를 내려야합니다. regexp가 합리적으로 명시적인 것처럼 보이면 왜 너무 많은 역 추적이있는 지 알 수 없습니다. 소유량 한정자 또는 원자 그룹을 비웃는 것은 아무 것도하지 않거나 "통과"또는 "실패"SQL이 올바르게 일치하지 않는 것으로 보입니다.

+0

나는이 추측하고있어'하나입니다 (\\ |. ''| [^ ']) *'문제입니다. 작은 따옴표로 묶인 문자열의 어떤 형식을 기대합니까? – sln

+0

또한'(? s)'한정자가 그 따옴표 하위 식의 줄에 걸쳐 있어야합니다. – sln

+0

MySQL 스타일의 작은 따옴표가 붙은 문자열을 기대합니다. 실제 텍스트에는 여러 줄이 없을 것입니다 - ** mysqldump **에서 출력됩니다 - 값의 여러 줄은 \ r \ n으로 대체됩니다. –

답변

1

편집 : 문자열 서브 표현식 :
@NikiC 의해 펼쳐진 루프 버전을 사용
\s 교체 \s*와 필요
하고 추가 원자단을 추가
그것까지 도착 합리적인 단계.

https://regex101.com/r/yV5xI7/3

(편집 : 당신은 또한 풀린 루프 '(?>[^'\\]+|\\.|'')*' 같은 차이 https://regex101.com/r/yV5xI7/5없이이 버전을 시도 할 수 있습니다.) 당신의 정량화 코어 랩을 시도 할 수

(?si) 

^ 

\s* 
UPDATE \s+ `mytable` \s+ 
SET \s+ `keyname` \s* = \s* 'keyvalue' 

(?# one or more such key = value ) 
(?> 
     \s* , \s* 

     (?# field name) 
     ` [A-Z_]+ ` 

     (?# equals) 
     \s* = \s* 

     (?# value) 
     (?> 
      (?# an integer, possibly negative) 
      -? [0-9]+   
     | 
      (?# or, a string) 
      ' 
      [^'\\]* 
      (?: 
       (?: \\ . | '') 
       [^'\\]* 
      )* 
      ' 

      # ' 
      # (?: [^'\\] | '' | \\ .)* 
      # ' 

     | 
      (?# or, literal NULL) 
      NULL    
    ) 
)+ 

\s+ WHERE \s+ `keyname` \s* = \s* 'keyvalue' 

$ 

원자 그룹.
도트 .에 대한 모든 참조에 도트 - 모디파이어가 필요할 수도 있습니다.

그리고 문자열 하위 표현식에서
교대로 일치하는 경우 이스케이프를 제외해야합니다.
엔진은 일치하는 경로를 취하는 것으로 알려져 있습니다.
이 경우 [^']도 이스케이프와 일치하며
처럼 보이며 이스케이프 자체가 존재하지 않아야합니다.
실제로 유효한 escape + newline 시퀀스가있을 수 있으므로 (?s)입니다.
즉, (?: \\ . | '' | [^'\\])*을 사용하십시오. 모두 함께 퍼팅

, 여기 ideone

/ 
    (?si) 
    ^\s* UPDATE \s+ `mytable` \s+ SET \s+ `keyname` \s = \s 'keyvalue' 
    (?> 
      , \s+ ` [A-Z_]+ ` 
      (?# field name) 
      \s+ = \s+ 
      (?# equals value) 
      (?: 
       -? [0-9]+ 
       (?# an integer, possibly negative) 
      | ' 
       (?: \\ . | '' | [^'\\])* 
       ' 
       (?# a string in single quotes) 
      | NULL 
       (?# NULL) 
     ) 
    )+ 
    (?# one or more such assignments) 
    \s+ WHERE \s+ `keyname` \s+ = \s+ 'keyvalue' $ 
/x 

하나와 PHP

'/ 
    (?si) 
    ^\s* UPDATE \s+ `mytable` \s+ SET \s+ `keyname` \s = \s \'keyvalue\' 
    (?> 
      , \s+ ` [A-Z_]+ ` 
      (?# field name) 
      \s+ = \s+ 
      (?# equals value) 
      (?: 
       -? [0-9]+ 
       (?# an integer, possibly negative) 
      | \' 
       (?: \\\ . | \'\' | [^\'\\\])* 
       \' 
       (?# a string in single quotes) 
      | NULL 
       (?# NULL) 
     ) 
    )+ 
    (?# one or more such assignments) 
    \s+ WHERE \s+ `keyname` \s+ = \s+ \'keyvalue\' $ 
/x' 
+0

종종 "루프 풀기"에도 도움이됩니다. "[^ '\\\\] * (? :(? : \\\\. |' ') [^'\\\\] *) * ' 아마도 원자력 그룹에 대해서는 중요하지 않습니다. – NikiC

+0

나는 여러번의 교대 때문에 어떤 생각도하지 못했다. 나는 교대가 주어졌지만 어떻게 벤치가 될지 궁금해. – sln

+0

제안 해 주셔서 감사합니다. 불행히도 당신의 정규 표현식은 목표 문자열의 중간을 복사/붙여 넣기 (즉, 약 5000 자의 SQL) 할 경우 최대 20000+ 단계를 거칩니다. 어쩌면 정규 표현식은 작업을위한 도구가 아닐 수도 있습니다. –