zend-db icon indicating copy to clipboard operation
zend-db copied to clipboard

ZF2 not including port in dsn parameter

Open GeeH opened this issue 9 years ago • 5 comments

This issue has been moved from the zendframework repository as part of the bug migration program as outlined here - http://framework.zend.com/blog/2016-04-11-issue-closures.html


Original Issue: https://api.github.com/repos/zendframework/zendframework/issues/7187 User: @pobrejuanito Created On: 2015-02-06T00:27:48Z Updated At: 2015-02-28T21:09:21Z Body Hi,

I am using 2.2.6, and I am not sure if this is fixed but here it goes:

In Zend\Db\Adapter\Driver\Pdo\Connection.php in method connect() the port parameter doesn't get included in the final $dns string.


Comment

User: @Martin-P Created On: 2015-02-06T11:47:44Z Updated At: 2015-02-06T11:47:44Z Body Should be possible in ZF 2.2.6, because it was added in ZF 2.0.3 through PR #2622.


Comment

User: @pobrejuanito Created On: 2015-02-06T16:07:30Z Updated At: 2015-02-06T16:18:22Z Body there is a case when $dsn is set and $pdodriver is not set. I've added a last "else" case to address this. Now it respects the port in the connect() method:

added $port to list of variable initialization:

$dsn = $username = $password = $hostname = $database = $port = null;

...

if (!isset($dsn) && isset($pdoDriver)) {

            $dsn = array();
            switch ($pdoDriver) {
                case 'sqlite':
                    $dsn[] = $database;
                    break;
                default:
                    if (isset($database)) {
                        $dsn[] = "dbname={$database}";
                    }
                    if (isset($hostname)) {
                        $dsn[] = "host={$hostname}";
                    }
                    if (isset($port)) {
                        $dsn[] = "port={$port}";
                    }
                    break;
            }
            $dsn = $pdoDriver . ':' . implode(';', $dsn);
        } elseif (!isset($dsn)) {
            throw new Exception\InvalidConnectionParametersException(
                'A dsn was not provided or could not be constructed from your parameters',
                $this->connectionParameters
            );
        } else {
            // there is a case when $dsn is set and $pdodriver is not set, if so port doesn't get set
            if ( $port !== null) {
                $dsn .= ';port='.$port;
            }
        }

It works for me now. Can anyone confirm?


Comment

User: @Martin-P Created On: 2015-02-06T16:27:25Z Updated At: 2015-02-06T16:27:25Z Body

there is a case when $dsn is set and $pdodriver is not set.

Can you elaborate on that? As far as I know you always need a PDO driver name. Can you show what the DSN you use looks like?


Comment

User: @Martin-P Created On: 2015-02-06T16:38:00Z Updated At: 2015-02-06T16:38:00Z Body Tested your suggestion with $dsn and without $pdodriver and still works fine for me:

public function testDsnWithoutDriverNameAddsPortToDsn()
{
    $this->connection->setConnectionParameters(array(
        'dsn' => 'host=127.0.0.1;charset=utf8;dbname=foo;port=3306',
    ));
    try {
        $this->connection->connect();
    } catch (\Exception $e) {
    }
    $responseString = $this->connection->getDsn();

    $this->assertContains('host=127.0.0.1', $responseString);
    $this->assertContains('charset=utf8', $responseString);
    $this->assertContains('dbname=foo', $responseString);
    $this->assertContains('port=3306', $responseString);
}

Comment

User: @pobrejuanito Created On: 2015-02-06T17:21:14Z Updated At: 2015-02-06T17:21:14Z Body This is what I have in my autoload/local.php

'db' => array(
        'username' => 'root',
        'password' => '',
        'driver'         => 'Pdo',
        'dsn'            => 'mysql:dbname=staging;host=127.0.0.1',
        'driver_options' => array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
        ),
        'adapters' => array(
            'db1' => array(
                'username' => 'api',
                'password' => 'pass',
                'port' => '30002',
                'driver'         => 'Pdo',
                'dsn'            => 'mysql:host=myhost.net;dbname=db1',
                'driver_options' => array(
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ),
            ),
            'db2' => array(
                'username' => 'api',
                'password' => 'pass',
                'port' => '30002',
                'driver'         => 'Pdo',
                'dsn'            => 'mysql:dbname=db2;host=myhost.net,
                'driver_options' => array(
                    PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
                ),
            ),
        ),
    )

___
### Comment
User: @Martin-P
Created On: 2015-02-06T17:49:00Z
Updated At: 2015-02-06T17:49:00Z
Body
Ah, okay, I see where this is going wrong. You are mixing two ways of setting connection parameters: `dsn` *and* `port`. `Zend\Db\Adapter\Pdo\Connection` expects a `dsn` *or* an array of parameters.

You can fix this by adding the port to your `dsn`:
```php
'dsn' => 'mysql:host=myhost.net;dbname=db1;port=30002',

Not sure this needs fixing at all, perhaps an exception should be thrown when mixing dsn and an array of parameters? Ping @Ocramius


Comment

User: @Martin-P Created On: 2015-02-28T13:48:41Z Updated At: 2015-02-28T13:48:41Z Body Ping @Ocramius @weierophinney Can you clarify if this needs a fix or if you consider it not an issue?


Comment

User: @pobrejuanito Created On: 2015-02-28T20:49:56Z Updated At: 2015-02-28T20:49:56Z Body Have you tried connecting to a different port? I tried to include the port in the string

'dsn' => 'mysql:host=myhost.net;dbname=db1;port=30002' 

but it doesn't work. I was pulling my hair out...I had to modifiy Zend/Db/Adapter/Pdo/Connection.php and add the last else case:

if (!isset($dsn) && isset($pdoDriver)) {

            $dsn = array();
            switch ($pdoDriver) {
                case 'sqlite':
                    $dsn[] = $database;
                    break;
                default:
                    if (isset($database)) {
                        $dsn[] = "dbname={$database}";
                    }
                    if (isset($hostname)) {
                        $dsn[] = "host={$hostname}";
                    }
                    if (isset($port)) {
                        $dsn[] = "port={$port}";
                    }
                    break;
            }
            $dsn = $pdoDriver . ':' . implode(';', $dsn);
        } elseif (!isset($dsn)) {
            throw new Exception\InvalidConnectionParametersException(
                'A dsn was not provided or could not be constructed from your parameters',
                $this->connectionParameters
            );
        } else {
            // there is a case when $dsn is set and $pdodriver is not set, if so port doesn't get set
            if ( $port !== null) {
                $dsn .= ';port='.$port;
            }
        }

Works great now

In the current code, as it loops through, the $dsn string gets rebuilt and leaves out the port specified in the $dsn string.


Comment

User: @Martin-P Created On: 2015-02-28T21:09:21Z Updated At: 2015-02-28T21:09:21Z Body

In the current code, as it loops through, the $dsn string gets rebuilt and leaves out the port specified in the $dsn string.

The problem is Zend\Db\Adapter\Pdo\Connection expects a dsn or an array of parameters. You provide both and Zend\Db\Adapter\Pdo\Connection does not support that.

Please look at my previous comment, I already gave you the solution :wink: When you apply that to your configuration you will get this:

<?php
'db' => array(
    'username' => 'root',
    'password' => '',
    'driver'         => 'Pdo',
    'dsn'            => 'mysql:dbname=staging;host=127.0.0.1',
    'driver_options' => array(
        PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
    ),
    'adapters' => array(
        'db1' => array(
            'username' => 'api',
            'password' => 'pass',
            // 'port' => '30002', remove this line
            'driver'         => 'Pdo',
            'dsn'            => 'mysql:host=myhost.net;dbname=db1;port=30002', // add it here
            'driver_options' => array(
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
            ),
        ),
        'db2' => array(
            'username' => 'api',
            'password' => 'pass',
            // 'port' => '30002', remove this line
            'driver'         => 'Pdo',
            'dsn'            => 'mysql:dbname=db2;host=myhost.net;port=30002', // add it here
            'driver_options' => array(
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
            ),
        ),
    ),
)

GeeH avatar Jun 28 '16 13:06 GeeH

@Martin-P Is this still a problem?

froschdesign avatar Jul 11 '16 05:07 froschdesign

@froschdesign Don't know if it is considered an issue and asked @Ocramius and @weierophinney about it in my comment of 28 Feb 2015.

Sidenote:

Original Issue: https://api.github.com/repos/zendframework/zendframework/issues/7187

Perhaps it is easier to link to the website (remove the api and repos part from the link) instead of linking to a JSON representation of the original post?

Martin-P avatar Jul 11 '16 09:07 Martin-P

@Martin-P Please look under the issue description and you will find the link to the original ticket. (Marked with "Closed")

froschdesign avatar Jul 11 '16 09:07 froschdesign

@Martin-P This can be a problem:

The problem is Zend\Db\Adapter\Pdo\Connection expects a dsn or an array of parameters. You provide both and Zend\Db\Adapter\Pdo\Connection does not support that.

froschdesign avatar Jul 11 '16 09:07 froschdesign

This repository has been closed and moved to laminas/laminas-db; a new issue has been opened at https://github.com/laminas/laminas-db/issues/109.

michalbundyra avatar Jan 16 '20 19:01 michalbundyra