-
Notifications
You must be signed in to change notification settings - Fork 375
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Named instances with dynamic ports, the workaround and possible implementation #927
Comments
@Sarke Thank !! Your tip was central in resolving my problem. Its work with Ubuntu 16.04, PHP 7.0 My two cents contribution /***
* By Peter Stalman (Sarke)
* https://github.com/microsoft/msphpsql/issues/927
*/
function getPortSqlServer($host, $instance) {
$msg = chr(4) . $instance;
// make the UDP request
$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_connect($socket, $host, 1434);
socket_write($socket, $msg, strlen($msg));
$buf = '';
socket_recv($socket, $buf, 2048, MSG_WAITALL);
socket_close($socket);
// format it nicely
$recv = explode(chr(0), $buf, 2);
$info = [];
foreach (array_chunk(explode(';', rtrim($recv[1], ';')), 2) as $pair)
$info[$pair[0]] = $pair[1];
//For Debug
//var_dump($info);
//$correctServer = $host . ',' . $info['tcp']; // 192.168.12.34,49161
//var_dump($correctServer);
return $info['tcp'];
}
function getHostPort($server, $port=null) {
list($host, $instance) = explode('\\', $server);
if( !empty($instance) && empty($port) ){
$port = getPortSqlServer($host,$instance);
}
if( !empty($port) ){
$server = $server.','.$port;
}
return $server;
}
$hostname = "SERVERNAME\INSTANCENAME";
$hostname = getHostPort($hostname);
$dbname = "myDataBase";
$username = "myUser";
$password = "myPass";
$conn = new PDO('sqlsrv:Server='.$hostname.';Database='.$dbname, $username , $password); |
The latest release of the ODBC driver, version 17.4, should fix any issues with named instances and dynamic port resolution on Linux. Instructions here. |
Closing issue as this should now be fixed. Please reopen if necessary. |
I've spent a couple of days struggling with why it wasn't able to connect, and I think I should share my findings and suggestions so it may help other people in a similar situation as well as the maintainers of this repo.
The current version of this repository doesn't correctly deal with named instances that are on a dynamic port (that is, not 1433), without having to manually look-up that port. The server name and instance should be enough. It's enough for jTDS and it's enough for SQL Server Management Studio. So why not this PHP extension?
I've managed to find two workarounds to this issue.
The first is to use the
pdo_dblib
extension instead, which uses the FreeTDS library (same one jTDS uses). I'm not sure how current it is with connecting to the latest SQL Servers though.The second is to do what FreeTDS and SQL Server Management Studio does, and that is to send a UDP connection to port 1434 with the instance name, and the server will return the port information.
This is what should be done in the extension, but it is not even though it appears to be a recurring problem for people using this extension, such as:
#442 #888 #470
In a few of them, I see a replies like these:
#442 (comment)
#576 (comment)
However, I disagree, and that is just skirting the problem. If this was the case, then why doesn't the other libraries and Management Studio require the port as well? The port can change after a db server restart, so hard-coding the port is far from a desired solution.
So why not implement the correct solution?
Here's what the FreeTDS documentation states:
http://www.freetds.org/userguide/portoverride.htm
And here's a link to their implementation of the UDP request (in C):
https://github.com/FreeTDS/freetds/blob/7f6be032fbe853ccc766c885633db243e2eb599c/src/tds/net.c#L1227
Shouldn't Microsoft's own solution be able to connect to a Microsoft SQL Server as well as a open-source library can?
Finally, for those who are stuck using this extension and are not able or willing to use the
pdo_dblib
with FreeTBS solution, I offer this PHP workaround for discovering the port:This is basically what I am hoping the maintainers of this repo will implement in this extension. Granted I didn't include any error checking as I just put this together as a proof of concept.
This will give you something like this:
The
tcp
is what holds the port number. You also get the named pipe format innp
. The port number can and probably should be cached since it does not frequently change.I hope this post saves people the time I spent on this.
The text was updated successfully, but these errors were encountered: