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