1--TEST--
2MySQL PDO->__construct() - Generic + DSN
3--EXTENSIONS--
4pdo_mysql
5--SKIPIF--
6<?php
7require_once __DIR__ . '/inc/mysql_pdo_test.inc';
8MySQLPDOTest::skip();
9if (getenv('CIRCLECI')) die('xfail Broken on CicleCI');
10?>
11--FILE--
12<?php
13    require_once __DIR__ . '/inc/mysql_pdo_test.inc';
14
15    function tryandcatch($offset, $code) {
16        try {
17            eval($code);
18            assert(sprintf("[%03d] Should have failed\n", $offset) != '');
19        } catch (PDOException $e) {
20            return sprintf("[%03d] %s, [%s] %s\n",
21                $offset,
22                $e->getMessage(),
23                (isset($db) && is_object($db)) ? $db->errorCode() : 'n/a',
24                (isset($db) && is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
25        }
26
27        return '';
28    }
29
30    try {
31        try {
32            if (NULL !== ($db = @new PDO()))
33                printf("[001] Too few parameters\n");
34        } catch (TypeError $ex) {
35        }
36
37        print tryandcatch(2, '$db = new PDO(chr(0));');
38        print tryandcatch(3, '$db = new PDO("a" . chr(0) . "b");');
39        print tryandcatch(4, '$db = new PDO("MYSQL");');
40        print tryandcatch(5, '$db = new PDO("mysql");');
41        print tryandcatch(6, '$db = new PDO("mysql ");');
42        print tryandcatch(7, '$db = new PDO("fantasyandfriends :");');
43
44        $dsn = PDO_MYSQL_TEST_DSN;
45        // MySQL Server might accept anonymous connections, don't
46        // print anything
47        tryandcatch(8, '$db = new PDO("' . $dsn . '");');
48
49        $user = 'dontcreatesuchauser';
50        $pass = 'withthispassword';
51        print tryandcatch(9, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
52
53        // should fail
54        $dsn = 'mysql:';
55        // don't print the message since it can be different
56        tryandcatch(10, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
57
58        $dsn = PDO_MYSQL_TEST_DSN;
59        $user = PDO_MYSQL_TEST_USER;
60        $pass	= PDO_MYSQL_TEST_PASS;
61        // should work...
62        $db = new PDO($dsn, $user, $pass);
63
64        // Reaction on host not specified differs for different configs, so no printing
65        $dsn = 'mysql:invalid=foo';
66        tryandcatch(11, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
67
68        $dsn = 'mysql:' . str_repeat('howmuch=canpdoeat;', 1000);
69        tryandcatch(12, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
70
71        $dsn = 'mysql:' . str_repeat('abcdefghij', 1024 * 10) . '=somevalue';
72        tryandcatch(13, '$db = new PDO("' . $dsn . '", "' . $user . '", "' . $pass . '");');
73
74        if (PDO_MYSQL_TEST_HOST) {
75            $host = PDO_MYSQL_TEST_HOST;
76            $invalid_host = $host . 'invalid';
77
78            // last host specification should be the one used
79            $dsn = MySQLPDOTest::getDSN(array('host' => $host), 'host=' . $invalid_host);
80            try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
81                $tmp = $e->getMessage();
82                if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005') && !stristr($tmp, '2002'))
83                    printf("[014] Cannot find proper error codes: %s\n", $tmp);
84            }
85
86            $dsn = MySQLPDOTest::getDSN(array('host' => $invalid_host), 'host=' . $host);
87            try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
88                printf("[015] DSN=%s, %s\n", $dsn, $e->getMessage());
89            }
90
91            $invalid_host = '-' . chr(0);
92
93            $dsn = MySQLPDOTest::getDSN(array('host' => $invalid_host));
94            try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
95                $tmp = $e->getMessage();
96                if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005') && !stristr($tmp, '2002'))
97                    printf("[016] Cannot find proper error codes: %s\n", $tmp);
98            }
99
100            // parsing should not get confused by chr(0)
101            $dsn = MySQLPDOTest::getDSN(array('host' => $invalid_host), 'host=' . $host);
102            try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
103                printf("[017] DSN=%s, %s\n", $dsn, $e->getMessage());
104            }
105        }
106
107        // what about long values for a valid option ...
108        // hostnames > 1024 chars break on some NIS-enabled FreeBSD...
109        $dsn = MySQLPDOTest::getDSN(array('host' => str_repeat('0123456789', 100)));
110        try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
111            $tmp = $e->getMessage();
112            if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005') && !stristr($tmp, '2002'))
113                printf("[018] Cannot find proper error codes: %s\n", $tmp);
114        }
115
116        if (PDO_MYSQL_TEST_PORT && (PDO_MYSQL_TEST_SOCKET == '')) {
117            // Playing with the port makes only sense if no socket gets used
118
119            $port = PDO_MYSQL_TEST_PORT;
120            // let's hope we don't hit a MySQL running on that port...
121            $invalid_port = $port * 2;
122
123            $dsn = MySQLPDOTest::getDSN(array('port' => $port), 'port=' . $invalid_port);
124            try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
125                $tmp = $e->getMessage();
126                if (!stristr($tmp, 'HY000') && !stristr($tmp, '2005'))
127                    printf("[019] Cannot find proper error codes: %s\n", $tmp);
128            }
129
130            $dsn = MySQLPDOTest::getDSN(array('port' => $invalid_port), 'port=' . $port);
131            try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
132                printf("[020] DSN=%s, %s\n", $dsn, $e->getMessage());
133            }
134
135            $invalid_port = 'abc';
136            $dsn = MySQLPDOTest::getDSN(array('port' => $port), 'port=' . $invalid_port);
137            try {
138                $db = @new PDO($dsn, $user, $pass);
139                // atoi('abc') = 0, 0 -> fallback to default 3306 -> may or may not fail!
140            } catch (PDOException $e) {
141            }
142        }
143
144        if (PDO_MYSQL_TEST_DB) {
145            $db = PDO_MYSQL_TEST_DB;
146            $invalid_db = 'letshopeitdoesnotexist';
147
148            $dsn = MySQLPDOTest::getDSN(array('dbname' => $db), 'dbname=' . $invalid_db);
149            try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
150                $tmp = $e->getMessage();
151                // 1044 may occur here if running tests using a custom user that does not have access to all databases
152                if (!stristr($tmp, '42000') && !stristr($tmp, '1049') && !stristr($tmp, '1044'))
153                    printf("[022] Cannot find proper error codes: %s\n", $tmp);
154            }
155
156            $dsn = MySQLPDOTest::getDSN(array('dbname' => $invalid_db), 'dbname=' . $db);
157            try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
158                printf("[023] DSN=%s, %s\n", $dsn, $e->getMessage());
159            }
160        }
161
162        if (PDO_MYSQL_TEST_SOCKET && (stristr(PDO_MYSQL_TEST_DSN, PDO_MYSQL_TEST_SOCKET) !== false)) {
163            $socket = PDO_MYSQL_TEST_SOCKET;
164            $invalid_socket = '/lets/hope/it/does/not/exist';
165
166            $dsn = MySQLPDOTest::getDSN(array('unix_socket' => $socket), 'unix_socket=' . $invalid_socket);
167            try { $db = @new PDO($dsn, $user, $pass); assert(false); printf("%s\n", $dsn); } catch (PDOException $e) {
168                $tmp = $e->getMessage();
169                if (!stristr($tmp, 'HY000') && !stristr($tmp, '2002'))
170                    printf("[024] Cannot find proper error codes: %s\n", $tmp);
171            }
172
173            $dsn = MySQLPDOTest::getDSN(array('unix_socket' => $invalid_socket), 'unix_socket=' . $socket);
174            try { $db = @new PDO($dsn, $user, $pass); } catch (PDOException $e) {
175                printf("[025] DSN=%s, %s\n", $dsn, $e->getMessage());
176            }
177        }
178
179        $have_charset_support = false;
180        $dsn = MySQLPDOTest::getDSN();
181        try {
182            $db = new PDO($dsn, $user, $pass);
183            $stmt = $db->query('SELECT VERSION() as _version');
184            $version = $stmt->fetch(PDO::FETCH_ASSOC);
185
186            $tmp = explode('.', $version['_version']);
187            if ((count($tmp) == 3) &&
188                    (($tmp[0] >= 4 && $tmp[1] >= 1) || ($tmp[0] >= 5))) {
189                // MySQL Server 4.1 - charset support available
190                $have_charset_support = true;
191            }
192
193        } catch (PDOException $e) {
194            printf("[026] DSN=%s, %s\n", $dsn, $e->getMessage());
195        }
196
197        if (PDO_MYSQL_TEST_CHARSET) {
198            $charset = PDO_MYSQL_TEST_CHARSET;
199            $invalid_charset = 'invalid';
200
201            if ($have_charset_support) {
202                $dsn = MySQLPDOTest::getDSN();
203                $db = new PDO($dsn, $user, $pass);
204                $stmt = $db->query(sprintf('SHOW CHARACTER SET LIKE "%s"', $charset));
205                $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
206                $have_charset = (empty($tmp)) ? false : true;
207
208                if ($have_charset) {
209                    $dsn = MySQLPDOTest::getDSN(array('charset' => $charset), 'charset=' . $invalid_charset);
210                    try {
211                        $db = @new PDO($dsn, $user, $pass);
212                        /* NOTE: MySQL does a fallback to the charset suggested during the handshake - no error - no bug! */
213                    } catch (PDOException $e) {
214                        $tmp = $e->getMessage();
215                        /* TODO: add proper codes */
216                        if (!stristr($tmp, 'sqlstatecode') || !stristr($tmp, 'mysqlinternalerrcode'))
217                            printf("[027] TODO - Cannot find proper error codes: %s\n", $tmp);
218                    }
219
220                    $dsn = MySQLPDOTest::getDSN(array('charset' => $invalid_charset), 'charset=' . $charset);
221                    try {
222                        $db = @new PDO($dsn, $user, $pass);
223                        /* Strictly speaking we should test more: character_set_client, character_set_results, and character_set_connection */
224                        $stmt = $db->query('SELECT @@character_set_connection AS _charset');
225                        $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
226                        if ($tmp['_charset'] != $charset)
227                            printf("[028] Character sets has not been set, @@character_set_connection reports '%s', expecting '%s'",
228                                $tmp['_charset'], $charset);
229                    } catch (PDOException $e) {
230                        printf("[029] DSN=%s, %s\n", $dsn, $e->getMessage());
231                    }
232                } else {
233                    printf("[030] You're trying to run the tests with charset '%s' which seems not supported by the server!", $charset);
234                }
235            }
236        }
237
238        if ($have_charset_support) {
239            // In case the PDO_MYSQL_TEST_CHARSET interferes with any defaults
240            // we do another test to verify that the charset has been set.
241            $dsn = MySQLPDOTest::getDSN();
242            $db = new PDO($dsn, $user, $pass);
243            $stmt = $db->query('SHOW CHARACTER SET LIKE "latin1"');
244            $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
245            $have_latin1 =(empty($tmp)) ? false : true;
246            $stmt = $db->query('SHOW CHARACTER SET LIKE "latin2"');
247            $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
248            $have_latin2 =(empty($tmp)) ? false : true;
249
250            if ($have_latin1 && $have_latin2) {
251                // very likely we do have both of them...
252                try {
253                    $dsn = MySQLPDOTest::getDSN(array('charset' => 'latin1'));
254                    $db = new PDO($dsn, $user, $pass);
255                    $stmt = $db->query('SELECT @@character_set_connection AS _charset');
256                    $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
257                    if ($tmp['_charset'] != 'latin1')
258                        printf("[031] DSN = %s, Character sets has not been set, @@character_set_connection reports '%s', expecting '%s'",
259                            $dsn, $tmp['_charset'], 'latin1');
260
261                } catch (PDOException $e) {
262                    printf("[032] %s\n", $e->getMessage());
263                }
264
265                try {
266                    $dsn = MySQLPDOTest::getDSN(array('charset' => 'latin2'));
267                    $db = new PDO($dsn, $user, $pass);
268                    $stmt = $db->query('SELECT @@character_set_connection AS _charset');
269                    $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
270                    if ($tmp['_charset'] != 'latin2')
271                        printf("[033] DSN = %s, character sets has not been set, @@character_set_connection reports '%s', expecting '%s'",
272                            $dsn, $tmp['_charset'], 'latin2');
273
274                } catch (PDOException $e) {
275                    printf("[034] %s\n", $e->getMessage());
276                }
277            }
278        }
279    } catch (PDOException $e) {
280        printf("[001] %s, [%s] %s\n",
281            $e->getMessage(),
282            (is_object($db)) ? $db->errorCode() : 'n/a',
283            (is_object($db)) ? implode(' ', $db->errorInfo()) : 'n/a');
284    }
285
286    print "done!";
287?>
288--EXPECTF--
289[002] PDO::__construct(): Argument #1 ($dsn) must be a valid data source name, [n/a] n/a
290[003] PDO::__construct(): Argument #1 ($dsn) must be a valid data source name, [n/a] n/a
291[004] PDO::__construct(): Argument #1 ($dsn) must be a valid data source name, [n/a] n/a
292[005] PDO::__construct(): Argument #1 ($dsn) must be a valid data source name, [n/a] n/a
293[006] PDO::__construct(): Argument #1 ($dsn) must be a valid data source name, [n/a] n/a
294[007] could not find driver, [n/a] n/a
295[009] SQLSTATE[%s] [1045] Access denied for user 'dont%s'@'%s' (using password: YES), [n/a] n/a
296[017] DSN=%s, SQLSTATE[%s] [%d] %s
297done!
298