1
1
--TEST--
2
- GH-13952 (sqlite PDO::quote silently corrupts strings with null bytes)
2
+ GH-13952 (sqlite PDO::quote handles null bytes correctly )
3
3
--EXTENSIONS--
4
4
pdo
5
5
pdo_sqlite
6
6
--FILE--
7
7
<?php
8
- $ db = new \PDO ('sqlite::memory: ' , null , null , [
9
- \PDO ::ATTR_ERRMODE => \PDO ::ERRMODE_EXCEPTION ,
10
- \PDO ::ATTR_DEFAULT_FETCH_MODE => \PDO ::FETCH_ASSOC ,
11
- \PDO ::ATTR_EMULATE_PREPARES => false ,
12
- ]);
8
+
9
+ $ modes = [
10
+ 'exception ' => PDO ::ERRMODE_EXCEPTION ,
11
+ 'warning ' => PDO ::ERRMODE_WARNING ,
12
+ 'silent ' => PDO ::ERRMODE_SILENT ,
13
+ ];
13
14
14
15
$ test_cases = [
15
16
"" ,
@@ -26,34 +27,53 @@ $test_cases = [
26
27
"\x00foo \x00\x00\x00bar \x00" ,
27
28
"\x00\x00\x00foo " ,
28
29
"foo \x00\x00\x00" ,
29
- "\x80" , // Invalid UTF-8 sequence
30
- "\x00\x80\x00" , // Invalid UTF-8 sequence with null bytes
30
+ "\x80" , // << invalid UTF-8
31
+ "\x00\x80\x00" , // << invalid UTF-8 with null bytes
31
32
];
32
33
33
- foreach ($ test_cases as $ test ) {
34
- $ should_throw = str_contains ($ test , "\x00" );
35
- try {
36
- $ quoted = $ db ->quote ($ test );
37
- if ($ should_throw ) {
38
- $ displayTest = var_export ($ test , true );
39
- throw new LogicException ("Failed for {$ displayTest }: expected an exception but none was thrown. " );
40
- }
41
- } catch (\PDOException $ e ) {
42
- if (!$ should_throw ) {
43
- $ displayTest = var_export ($ test , true );
44
- throw new LogicException ("Failed for {$ displayTest }: unexpected exception thrown. " , 0 , $ e );
34
+ foreach ($ modes as $ mode_name => $ mode ) {
35
+ echo "Testing error mode: $ mode_name \n" ;
36
+ $ db = new PDO ('sqlite::memory: ' , null , null , [PDO ::ATTR_ERRMODE => $ mode ]);
37
+
38
+ foreach ($ test_cases as $ test ) {
39
+ $ contains_null = str_contains ($ test , "\x00" );
40
+
41
+ if ($ mode === PDO ::ERRMODE_EXCEPTION && $ contains_null ) {
42
+ set_error_handler (fn () => throw new PDOException (), E_WARNING );
43
+ try {
44
+ $ db ->quote ($ test );
45
+ throw new LogicException ("Expected exception not thrown. " );
46
+ } catch (PDOException ) {
47
+ // expected
48
+ } finally {
49
+ restore_error_handler ();
50
+ }
51
+ } else {
52
+ set_error_handler (fn () => null , E_WARNING );
53
+ $ quoted = $ db ->quote ($ test );
54
+ restore_error_handler ();
55
+
56
+ if ($ contains_null ) {
57
+ if ($ quoted !== false ) {
58
+ throw new LogicException ("Expected false, got: " . var_export ($ quoted , true ));
59
+ }
60
+ } else {
61
+ if ($ quoted === false ) {
62
+ throw new LogicException ("Unexpected false from quote(). " );
63
+ }
64
+ $ fetched = $ db ->query ("SELECT $ quoted " )->fetchColumn ();
65
+ if ($ fetched !== $ test ) {
66
+ throw new LogicException ("Data corrupted: expected " . var_export ($ test , true ) . " got " . var_export ($ fetched , true ));
67
+ }
68
+ }
45
69
}
46
- // Exception is expected
47
- continue ;
48
- }
49
- $ fetched = $ db ->query ("SELECT $ quoted " )->fetch ($ db ::FETCH_NUM )[0 ];
50
- if ($ fetched !== $ test ) {
51
- $ displayTest = var_export ($ test , true );
52
- $ displayFetched = var_export ($ fetched , true );
53
- throw new LogicException ("Round-trip data corruption for {$ displayTest }: got {$ displayFetched }. " );
54
70
}
55
71
}
72
+
56
73
echo "ok \n" ;
57
74
?>
58
75
--EXPECT--
76
+ Testing error mode: exception
77
+ Testing error mode: warning
78
+ Testing error mode: silent
59
79
ok
0 commit comments