Skip to content

Commit 6f9eeb6

Browse files
authored
Merge pull request #149 from udan11/fix_40
Fixes wrong extract of string tokens with escaped characters.
2 parents e30ae6f + 16d4f15 commit 6f9eeb6

File tree

9 files changed

+48
-21
lines changed

9 files changed

+48
-21
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## [Unreleased]
44

5+
* Fixed wrong extract of string tokens with escaped characters.
6+
57
## [4.1.3] - 2017-04-06
68

79
* Added suppport for DELETE ... JOIN clauses.

src/Token.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,25 @@ public function extract()
269269

270270
return $ret;
271271
case self::TYPE_STRING:
272-
$quote = $this->token[0];
273-
$str = str_replace($quote . $quote, $quote, $this->token);
272+
// Trims quotes.
273+
$str = $this->token;
274+
$str = mb_substr($str, 1, -1, 'UTF-8');
274275

275-
return mb_substr($str, 1, -1, 'UTF-8'); // trims quotes
276+
// Removes surrounding quotes.
277+
$quote = $this->token[0];
278+
$str = str_replace($quote . $quote, $quote, $str);
279+
280+
// Finally unescapes the string.
281+
//
282+
// `stripcslashes` replaces escape sequences with their
283+
// representation.
284+
//
285+
// NOTE: In MySQL, `\f` and `\v` have no representation,
286+
// even they usually represent: form-feed and vertical tab.
287+
$str = str_replace('\f', 'f', $str);
288+
$str = str_replace('\v', 'v', $str);
289+
$str = stripcslashes($str);
290+
return $str;
276291
case self::TYPE_SYMBOL:
277292
$str = $this->token;
278293
if ((isset($str[0])) && ($str[0] === '@')) {

tests/Lexer/TokenTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ public function testExtractString()
5656

5757
$tok = new Token("' bar foo '", Token::TYPE_STRING);
5858
$this->assertEquals($tok->value, ' bar foo ');
59+
60+
$tok = new Token("'\''", Token::TYPE_STRING);
61+
$this->assertEquals($tok->value, '\'');
62+
63+
$tok = new Token('"\c\d\e\f\g\h\i\j\k\l\m\p\q\s\u\v\w\x\y\z"', Token::TYPE_STRING);
64+
$this->assertEquals($tok->value, 'cdefghijklmpqsuvwxyz');
5965
}
6066

6167
public function testExtractSymbol()

tests/Utils/TokensTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,22 +62,22 @@ public function matchProvider()
6262
true,
6363
),
6464
array(
65-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
65+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
6666
array('value' => 'abc'),
6767
true,
6868
),
6969
array(
70-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
70+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
7171
array('value_str' => 'ABC'),
7272
true,
7373
),
7474
array(
75-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
75+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
7676
array('type' => Token::TYPE_STRING),
7777
true,
7878
),
7979
array(
80-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
80+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
8181
array('flags' => Token::FLAG_STRING_DOUBLE_QUOTES),
8282
true,
8383
),
@@ -88,22 +88,22 @@ public function matchProvider()
8888
false,
8989
),
9090
array(
91-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
91+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
9292
array('value' => 'abcd'),
9393
false,
9494
),
9595
array(
96-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
96+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
9797
array('value_str' => 'ABCd'),
9898
false,
9999
),
100100
array(
101-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
101+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
102102
array('type' => Token::TYPE_NUMBER),
103103
false,
104104
),
105105
array(
106-
new Token('"abc""', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
106+
new Token('"abc"', Token::TYPE_STRING, Token::FLAG_STRING_DOUBLE_QUOTES),
107107
array('flags' => Token::FLAG_STRING_SINGLE_QUOTES),
108108
false,
109109
),

tests/data/lexer/lexString.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a:4:{s:5:"query";s:32:"SELECT 'foo', "bar", "foo\\ bar"";s:5:"lexer";O:26:"PhpMyAdmin\SqlParser\Lexer":8:{s:3:"str";s:32:"SELECT 'foo', "bar", "foo\\ bar"";s:3:"len";i:32;s:4:"last";i:32;s:4:"list";O:31:"PhpMyAdmin\SqlParser\TokensList":3:{s:6:"tokens";a:10:{i:0;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:7:"keyword";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:"'foo'";s:5:"value";s:3:"foo";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:7;}i:3;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:12;}i:4;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:13;}i:5;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:""bar"";s:5:"value";s:3:"bar";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:14;}i:6;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:19;}i:7;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:20;}i:8;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:11:""foo\\ bar"";s:5:"value";s:9:"foo\\ bar";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:21;}i:9;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";N;s:5:"value";N;s:7:"keyword";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:10;s:3:"idx";i:0;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"strict";b:0;s:6:"errors";a:0:{}}s:6:"parser";N;s:6:"errors";a:2:{s:5:"lexer";a:0:{}s:6:"parser";a:0:{}}}
1+
a:4:{s:5:"query";s:32:"SELECT 'foo', "bar", "foo\\ bar"";s:5:"lexer";O:26:"PhpMyAdmin\SqlParser\Lexer":8:{s:3:"str";s:32:"SELECT 'foo', "bar", "foo\\ bar"";s:3:"len";i:32;s:4:"last";i:32;s:4:"list";O:31:"PhpMyAdmin\SqlParser\TokensList":3:{s:6:"tokens";a:10:{i:0;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:7:"keyword";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:"'foo'";s:5:"value";s:3:"foo";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:7;}i:3;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:12;}i:4;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:13;}i:5;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:""bar"";s:5:"value";s:3:"bar";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:14;}i:6;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:19;}i:7;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:20;}i:8;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:11:""foo\\ bar"";s:5:"value";s:8:"foo\ bar";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:21;}i:9;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";N;s:5:"value";N;s:7:"keyword";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:10;s:3:"idx";i:0;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"strict";b:0;s:6:"errors";a:0:{}}s:6:"parser";N;s:6:"errors";a:2:{s:5:"lexer";a:0:{}s:6:"parser";a:0:{}}}

tests/data/lexer/lexStringErr1.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a:4:{s:5:"query";s:31:"SELECT 'foo', "bar", "foo\\ bar";s:5:"lexer";O:26:"PhpMyAdmin\SqlParser\Lexer":8:{s:3:"str";s:31:"SELECT 'foo', "bar", "foo\\ bar";s:3:"len";i:31;s:4:"last";i:32;s:4:"list";O:31:"PhpMyAdmin\SqlParser\TokensList":3:{s:6:"tokens";a:10:{i:0;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:7:"keyword";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:"'foo'";s:5:"value";s:3:"foo";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:7;}i:3;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:12;}i:4;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:13;}i:5;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:""bar"";s:5:"value";s:3:"bar";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:14;}i:6;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:19;}i:7;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:20;}i:8;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:10:""foo\\ bar";s:5:"value";s:8:"foo\\ ba";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:21;}i:9;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";N;s:5:"value";N;s:7:"keyword";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:10;s:3:"idx";i:0;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"strict";b:0;s:6:"errors";a:0:{}}s:6:"parser";N;s:6:"errors";a:2:{s:5:"lexer";a:1:{i:0;a:4:{i:0;s:28:"Ending quote " was expected.";i:1;s:0:"";i:2;i:31;i:3;i:0;}}s:6:"parser";a:0:{}}}
1+
a:4:{s:5:"query";s:31:"SELECT 'foo', "bar", "foo\\ bar";s:5:"lexer";O:26:"PhpMyAdmin\SqlParser\Lexer":8:{s:3:"str";s:31:"SELECT 'foo', "bar", "foo\\ bar";s:3:"len";i:31;s:4:"last";i:32;s:4:"list";O:31:"PhpMyAdmin\SqlParser\TokensList":3:{s:6:"tokens";a:10:{i:0;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:7:"keyword";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:"'foo'";s:5:"value";s:3:"foo";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:7;}i:3;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:12;}i:4;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:13;}i:5;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:5:""bar"";s:5:"value";s:3:"bar";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:14;}i:6;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:7:"keyword";N;s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:19;}i:7;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:7:"keyword";N;s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:20;}i:8;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";s:10:""foo\\ bar";s:5:"value";s:7:"foo\ ba";s:7:"keyword";N;s:4:"type";i:7;s:5:"flags";i:2;s:8:"position";i:21;}i:9;O:26:"PhpMyAdmin\SqlParser\Token":6:{s:5:"token";N;s:5:"value";N;s:7:"keyword";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:10;s:3:"idx";i:0;}s:9:"delimiter";s:1:";";s:12:"delimiterLen";i:1;s:6:"strict";b:0;s:6:"errors";a:0:{}}s:6:"parser";N;s:6:"errors";a:2:{s:5:"lexer";a:1:{i:0;a:4:{i:0;s:28:"Ending quote " was expected.";i:1;s:0:"";i:2;i:31;i:3;i:0;}}s:6:"parser";a:0:{}}}

0 commit comments

Comments
 (0)