Update: I’ve written a new article, covering CodeIgniter 3 and Ubuntu 14/16. Read it here.
Connecting to Microsoft SQL Express 2008 from Linux/PHP is a lot trickier than I expected. These notes are really for my own benefit so I can reproduce the setup, but maybe they’ll help you too. One of the problems is that many existing PHP drivers for MS SQL have difficulty talking to SQL 2008. Here’s a workaround using FreeTDS and ODBC.
My web application is built using CodeIgniter, the PHP application framework. It resides on an Ubuntu Server box, running Apache. Prerequisites on that Ubuntu Server (which I installed using Aptitude, but your favourite package manager will do):
- unixODBC
- FreeTDS
- FreeTDS development package/(header files and libraries)
To my freetds.conf file (in /etc/freetds on my server) I added a section that looks something like this:
[my-server] host = my.server.local port = 1433 tds version = 9.0
Note: TDS version 9.0 should work with SQL 2008.
In /etc/odbcinst.ini, add the following ODBC driver (32-bit):
[TDS] Driver = /usr/lib/odbc/libtdsodbc.so Description = FreeTDS driver Setup = /usr/lib/odbc/libtdsS.so
or 64-bit:
[TDS] Driver = /usr/lib64/libtdsodbc.so Description = FreeTDS driver Setup = /usr/lib64/libtdsS.so
(You may need to check the precise location of the driver and setup files.)
And to /etc/odbc.ini, I inserted a DSN similar to the following:
[my-server] Driver = TDS Description = My Server ServerName = my-server Database = my-db
Generally within CodeIgniter, I am connecting to MySQL databases and that’s how my default connection is configured. I therefore added a second configuration to my database.php configuration file, like this:
$db['my_server']['hostname'] = "dsn=my-server;uid=myusername;pwd=mypassword"; $db['my_server']['username'] = ''; $db['my_server']['password'] = ''; $db['my_server']['database'] = ''; $db['my_server']['dbdriver'] = 'odbc'; $db['my_server']['dbprefix'] = ''; $db['my_server']['pconnect'] = TRUE; $db['my_server']['db_debug'] = TRUE; $db['my_server']['cache_on'] = FALSE; $db['my_server']['cachedir'] = ''; $db['my_server']['char_set'] = 'utf8'; $db['my_server']['dbcollat'] = 'utf8_general_ci';
Now the ODBC driver within CodeIgniter can produce queries that MS SQL doesn’t like. We can fix this with a hack. You really REALLY shouldn’t do it this way (!) but to get things working and as described >here<, I edited the CodeIgniter core file system/database/drivers/odbc_driver.php. The function _from_tables() has a line reading:
return '('.implode(', ', $tables).')';
I changed it to this:
return implode(', ', $tables);
(In other words, we’re removing the spurious parentheses.)
I created a database method m_my_server.php like this:
/** * NOTE: We're using a feature-incomplete driver here. Don't attempt to use * CodeIgniter's ActiveRecord Class or num_rows(). Use bare queries instead. */ class M_my_server extends Model { var $my_server; function M_my_server() { parent::Model(); $this->my_server = $this->load->database('my_server', TRUE); } function get() { $query = $this->my_server->query('SELECT TOP(100) * FROM dbo.tblUserSummary'); $result = $query->result_array(); // note ->num_rows() doesn't work with this driver if(count($result) > 0) { return $result; } else { return false; } } } /* End of file m_my_server.php */ /* Location: ./application/models/m_my_server.php */
At the SQL Server end, I set up a new standard SQL user (myusername/mypassword) rather than attempting to get Windows authentication to work (I bet it wouldn’t).
My SQL instance wasn’t listening to TCP/IP connections by default. I fired up SQL Server Configuration Manager and browsed to SQL Server Network Configuration –> Protocols for [my db instance]. Then you have to right-click TCP/IP and click Enable.
With all that in place, the following controller produces successful results:
function SQLtest() { $this->load->model('m_my_server'); $result = $this->m_my_server->get(); if($result) { print_r($result); } else { echo 'nada'; } exit; }
It’s not ideal; for one thing, bare SQL queries involve learning Microsoft’s particular dialect of SQL (whereas I’m used to MySQL). The tables I’m querying are generated by Microsoft Forefront TMG though, so I’m basically stuck with MSSQL. At least now I can query those tables from my favourite PHP application framework.
Image copyright © Microsoft. Used with permission from Microsoft.
After following this tutorial I am still unable to get this to work. I have got the freetds drivers installed and working (tested connection to a remote db from the terminal), however, I cant get my CI app to connect to the DB. Is this the connection string you used?
“dsn=my-server;uid=myusername;pwd=mypassword”
And why haven’t you used a format like this with username and password fields populated:
$db[‘default’][‘hostname’] = “,1433”;
$db[‘default’][‘username’] = “”;
$db[‘default’][‘password’] = “”;
$db[‘default’][‘database’] = “”;
$db[‘default’][‘dbdriver’] = “odbc”;
I have noticed that instead of $db[‘default’], you have done $db[‘my_server’], why is this? Finally, are there any settings in my php.ini file that I need to enable. Thanks.
Hi Bond. It took me a while to refresh my memory on this one! To deal with your questions in turn:
For an ODBC connection like this, the only way I was able to make it work was to pass through the credentials in the ‘hostname’ config variable. This is because of limitations in CodeIgniter’s ODBC driver – certainly in the version of CI that I was using at the time. So yes, specify DSN (which corresponds to the entry in odbc.ini), UID and PWD, separated with semicolons. Don’t bother populating the other array variables – they aren’t used (unless this was changed in later versions of the driver, but I suspect not).
Why $db[‘my_server’] instead of $db[‘default’]? Simple really – my default database connection is to a MySQL server. To specify additional DB connections, you need to change the first array variable like this. See the CodeIgniter Database Configuration documentation for more details.
Odbc tips are helpful!
Thanks
You’re welcome!
It’s Helpful.
You save my day.
Thanks!
You’re welcome.